diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-10-22 02:07:59 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-10-22 02:07:59 +0200 |
commit | 1011cb73c92ddb90589452f70a1dd33830689e32 (patch) | |
tree | 02de42791042a43b54069787799e352afe8ec17d /src | |
parent | 29cfbedfb2af9ca6cf76c20b7e5fa17887418e8d (diff) |
Core/GameObjects: Implemented gathering nodes (gameobject type 50)
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 80 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObjectData.h | 118 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Updates/ViewerDependentValues.h | 9 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 26 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
-rw-r--r-- | src/server/game/Handlers/LootHandler.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 6 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 |
10 files changed, 238 insertions, 12 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index f8abc8eba84..9f84d95d17e 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2913,6 +2913,56 @@ void GameObject::Use(Unit* user) player->SendDirectMessage(gameObjectUILink.Write()); return; } + case GAMEOBJECT_TYPE_GATHERING_NODE: //50 + { + Player* player = user->ToPlayer(); + if (!player) + return; + + GameObjectTemplate const* info = GetGOInfo(); + if (!m_personalLoot.count(player->GetGUID())) + { + if (info->gatheringNode.chestLoot) + { + Loot* loot = new Loot(GetMap(), GetGUID(), LOOT_CHEST, nullptr); + m_personalLoot[player->GetGUID()].reset(loot); + + loot->FillLoot(info->gatheringNode.chestLoot, LootTemplates_Gameobject, player, true, false, GetLootMode(), GetMap()->GetDifficultyLootItemContext()); + } + + if (info->gatheringNode.triggeredEvent) + GameEvents::Trigger(info->gatheringNode.triggeredEvent, player, this); + + // triggering linked GO + if (uint32 trapEntry = info->gatheringNode.linkedTrap) + TriggeringLinkedGameObject(trapEntry, player); + + if (info->gatheringNode.xpDifficulty && info->gatheringNode.xpDifficulty < 10) + if (QuestXPEntry const* questXp = sQuestXPStore.LookupEntry(player->GetLevel())) + if (uint32 xp = Quest::RoundXPValue(questXp->Difficulty[info->gatheringNode.xpDifficulty])) + player->GiveXP(xp, nullptr); + + spellId = info->gatheringNode.spell; + } + + if (m_personalLoot.size() >= info->gatheringNode.MaxNumberofLoots) + { + SetGoState(GO_STATE_ACTIVE); + SetDynamicFlag(GO_DYNFLAG_LO_NO_INTERACT); + } + + if (getLootState() != GO_ACTIVATED) + { + SetLootState(GO_ACTIVATED, player); + if (info->gatheringNode.ObjectDespawnDelay) + DespawnOrUnsummon(Seconds(info->gatheringNode.ObjectDespawnDelay)); + } + + // Send loot + if (Loot* loot = GetLootForPlayer(player)) + player->SendLoot(*loot); + break; + } default: if (GetGoType() >= MAX_GAMEOBJECT_TYPE) TC_LOG_ERROR("misc", "GameObject::Use(): unit (%s, name: %s) tries to use object (%s, name: %s) of unknown type (%u)", @@ -3252,6 +3302,21 @@ void GameObject::OnLootRelease(Player* looter) } break; } + case GAMEOBJECT_TYPE_GATHERING_NODE: + { + SetGoStateFor(GO_STATE_ACTIVE, looter); + + UF::ObjectData::Base objMask; + UF::GameObjectData::Base goMask; + objMask.MarkChanged(&UF::ObjectData::DynamicFlags); + + UpdateData udata(GetMapId()); + BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), goMask.GetChangesMask(), looter); + WorldPacket packet; + udata.BuildPacket(&packet); + looter->SendDirectMessage(&packet); + break; + } default: break; } @@ -3541,6 +3606,9 @@ void GameObject::AfterRelocation() float GameObject::GetInteractionDistance() const { + if (GetGOInfo()->GetInteractRadiusOverride()) + return float(GetGOInfo()->GetInteractRadiusOverride()) / 100.0f; + switch (GetGoType()) { case GAMEOBJECT_TYPE_AREADAMAGE: @@ -3780,6 +3848,18 @@ bool GameObject::CanInteractWithCapturePoint(Player const* target) const || m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured; } +bool GameObject::MeetsInteractCondition(Player const* user) const +{ + if (!m_goInfo->GetConditionID1()) + return true; + + if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(m_goInfo->GetConditionID1())) + if (!ConditionMgr::IsPlayerMeetingCondition(user, playerCondition)) + return false; + + return true; +} + std::unordered_map<ObjectGuid, GameObject::PerPlayerState>& GameObject::GetOrCreatePerPlayerStates() { if (!m_perPlayerState) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 6341d9ecaea..8dd027eb207 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -381,6 +381,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> void UpdateCapturePoint(); bool CanInteractWithCapturePoint(Player const* target) const; + bool MeetsInteractCondition(Player const* user) const; + void AIM_Destroy(); bool AIM_Initialize(); diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h index 777b4e815fd..90dd21ad59a 100644 --- a/src/server/game/Entities/GameObject/GameObjectData.h +++ b/src/server/game/Entities/GameObject/GameObjectData.h @@ -839,6 +839,94 @@ struct GameObjectTemplate } } + uint32 GetConditionID1() const + { + switch (type) + { + case GAMEOBJECT_TYPE_DOOR: return door.conditionID1; + case GAMEOBJECT_TYPE_BUTTON: return button.conditionID1; + case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.conditionID1; + case GAMEOBJECT_TYPE_CHEST: return chest.conditionID1; + case GAMEOBJECT_TYPE_GENERIC: return generic.conditionID1; + case GAMEOBJECT_TYPE_TRAP: return trap.conditionID1; + case GAMEOBJECT_TYPE_CHAIR: return chair.conditionID1; + case GAMEOBJECT_TYPE_SPELL_FOCUS: return spellFocus.conditionID1; + case GAMEOBJECT_TYPE_TEXT: return text.conditionID1; + case GAMEOBJECT_TYPE_GOOBER: return goober.conditionID1; + case GAMEOBJECT_TYPE_CAMERA: return camera.conditionID1; + case GAMEOBJECT_TYPE_RITUAL: return ritual.conditionID1; + case GAMEOBJECT_TYPE_MAILBOX: return mailbox.conditionID1; + case GAMEOBJECT_TYPE_SPELLCASTER: return spellCaster.conditionID1; + case GAMEOBJECT_TYPE_FLAGSTAND: return flagStand.conditionID1; + case GAMEOBJECT_TYPE_AURA_GENERATOR: return auraGenerator.conditionID1; + case GAMEOBJECT_TYPE_GUILD_BANK: return guildbank.conditionID1; + case GAMEOBJECT_TYPE_NEW_FLAG: return newflag.conditionID1; + case GAMEOBJECT_TYPE_ITEM_FORGE: return itemForge.conditionID1; + case GAMEOBJECT_TYPE_GATHERING_NODE: return gatheringNode.conditionID1; + default: return 0; + } + } + + uint32 GetInteractRadiusOverride() const + { + switch (type) + { + case GAMEOBJECT_TYPE_DOOR: return door.InteractRadiusOverride; + case GAMEOBJECT_TYPE_BUTTON: return button.InteractRadiusOverride; + case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.InteractRadiusOverride; + case GAMEOBJECT_TYPE_CHEST: return chest.InteractRadiusOverride; + case GAMEOBJECT_TYPE_BINDER: return binder.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GENERIC: return generic.InteractRadiusOverride; + case GAMEOBJECT_TYPE_TRAP: return trap.InteractRadiusOverride; + case GAMEOBJECT_TYPE_CHAIR: return chair.InteractRadiusOverride; + case GAMEOBJECT_TYPE_SPELL_FOCUS: return spellFocus.InteractRadiusOverride; + case GAMEOBJECT_TYPE_TEXT: return text.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GOOBER: return goober.InteractRadiusOverride; + case GAMEOBJECT_TYPE_TRANSPORT: return transport.InteractRadiusOverride; + case GAMEOBJECT_TYPE_AREADAMAGE: return areaDamage.InteractRadiusOverride; + case GAMEOBJECT_TYPE_CAMERA: return camera.InteractRadiusOverride; + case GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT: return moTransport.InteractRadiusOverride; + case GAMEOBJECT_TYPE_DUEL_ARBITER: return duelFlag.InteractRadiusOverride; + case GAMEOBJECT_TYPE_FISHINGNODE: return fishingNode.InteractRadiusOverride; + case GAMEOBJECT_TYPE_RITUAL: return ritual.InteractRadiusOverride; + case GAMEOBJECT_TYPE_MAILBOX: return mailbox.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GUARDPOST: return guardPost.InteractRadiusOverride; + case GAMEOBJECT_TYPE_SPELLCASTER: return spellCaster.InteractRadiusOverride; + case GAMEOBJECT_TYPE_MEETINGSTONE: return meetingStone.InteractRadiusOverride; + case GAMEOBJECT_TYPE_FLAGSTAND: return flagStand.InteractRadiusOverride; + case GAMEOBJECT_TYPE_FISHINGHOLE: return fishingHole.InteractRadiusOverride; + case GAMEOBJECT_TYPE_FLAGDROP: return flagDrop.InteractRadiusOverride; + case GAMEOBJECT_TYPE_CONTROL_ZONE: return controlZone.InteractRadiusOverride; + case GAMEOBJECT_TYPE_AURA_GENERATOR: return auraGenerator.InteractRadiusOverride; + case GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY: return dungeonDifficulty.InteractRadiusOverride; + case GAMEOBJECT_TYPE_BARBER_CHAIR: return barberChair.InteractRadiusOverride; + case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING: return destructibleBuilding.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GUILD_BANK: return guildbank.InteractRadiusOverride; + case GAMEOBJECT_TYPE_TRAPDOOR: return trapdoor.InteractRadiusOverride; + case GAMEOBJECT_TYPE_NEW_FLAG: return newflag.InteractRadiusOverride; + case GAMEOBJECT_TYPE_NEW_FLAG_DROP: return newflagdrop.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GARRISON_BUILDING: return garrisonBuilding.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GARRISON_PLOT: return garrisonPlot.InteractRadiusOverride; + case GAMEOBJECT_TYPE_CAPTURE_POINT: return capturePoint.InteractRadiusOverride; + case GAMEOBJECT_TYPE_PHASEABLE_MO: return phaseableMO.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GARRISON_MONUMENT: return garrisonMonument.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GARRISON_SHIPMENT: return garrisonShipment.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GARRISON_MONUMENT_PLAQUE: return garrisonMonumentPlaque.InteractRadiusOverride; + case GAMEOBJECT_TYPE_ITEM_FORGE: return itemForge.InteractRadiusOverride; + case GAMEOBJECT_TYPE_UI_LINK: return UILink.InteractRadiusOverride; + case GAMEOBJECT_TYPE_KEYSTONE_RECEPTACLE: return KeystoneReceptacle.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GATHERING_NODE: return gatheringNode.InteractRadiusOverride; + case GAMEOBJECT_TYPE_CHALLENGE_MODE_REWARD: return challengeModeReward.InteractRadiusOverride; + case GAMEOBJECT_TYPE_SIEGEABLE_MO: return siegeableMO.InteractRadiusOverride; + case GAMEOBJECT_TYPE_PVP_REWARD: return pvpReward.InteractRadiusOverride; + case GAMEOBJECT_TYPE_PLAYER_CHOICE_CHEST: return playerChoiceChest.InteractRadiusOverride; + case GAMEOBJECT_TYPE_LEGENDARY_FORGE: return legendaryForge.InteractRadiusOverride; + case GAMEOBJECT_TYPE_GARR_TALENT_TREE: return garrTalentTree.InteractRadiusOverride; + case GAMEOBJECT_TYPE_WEEKLY_REWARD_CHEST: return weeklyRewardChest.InteractRadiusOverride; + default: return 0; + } + } + uint32 GetRequireLOS() const { switch (type) @@ -911,6 +999,16 @@ struct GameObjectTemplate } } + uint32 GetNotInCombat() const + { + switch (type) + { + case GAMEOBJECT_TYPE_CHEST: return chest.notInCombat; + case GAMEOBJECT_TYPE_GATHERING_NODE: return gatheringNode.notInCombat; + default: return 0; + } + } + uint32 GetCharges() const // despawn at uses amount { switch (type) @@ -984,6 +1082,26 @@ struct GameObjectTemplate } } + uint32 GetTrivialSkillHigh() const + { + switch (type) + { + case GAMEOBJECT_TYPE_CHEST: return chest.trivialSkillHigh; + case GAMEOBJECT_TYPE_GATHERING_NODE: return gatheringNode.trivialSkillHigh; + default: return 0; + } + } + + uint32 GetTrivialSkillLow() const + { + switch (type) + { + case GAMEOBJECT_TYPE_CHEST: return chest.trivialSkillLow; + case GAMEOBJECT_TYPE_GATHERING_NODE: return gatheringNode.trivialSkillLow; + default: return 0; + } + } + uint32 GetCooldown() const // Cooldown preventing goober and traps to cast spell { switch (type) diff --git a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h index fdcd7a08a15..79aae2b4363 100644 --- a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h +++ b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h @@ -118,10 +118,19 @@ public: else dynFlags &= ~GO_DYNFLAG_LO_NO_INTERACT; break; + case GAMEOBJECT_TYPE_GATHERING_NODE: + if (gameObject->ActivateToQuest(receiver)) + dynFlags |= GO_DYNFLAG_LO_ACTIVATE | GO_DYNFLAG_LO_SPARKLE | GO_DYNFLAG_LO_HIGHLIGHT; + if (gameObject->GetGoStateFor(receiver->GetGUID()) == GO_STATE_ACTIVE) + dynFlags |= GO_DYNFLAG_LO_DEPLETED; + break; default: break; } + if (!gameObject->MeetsInteractCondition(receiver)) + dynFlags |= GO_DYNFLAG_LO_NO_INTERACT; + dynamicFlags = (uint32(pathProgress) << 16) | uint32(dynFlags); } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b581bd07799..53ce1f7c170 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5497,13 +5497,27 @@ bool Player::UpdateCraftSkill(SpellInfo const* spellInfo) return false; } -bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator) +bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator /*= 1*/, WorldObject const* object /*= nullptr*/) { TC_LOG_DEBUG("entities.player.skills", "Player::UpdateGatherSkill: Player '%s' (%s), SkillID: %u, SkillLevel: %u, RedLevel: %u)", GetName().c_str(), GetGUID().ToString().c_str(), SkillId, SkillValue, RedLevel); uint32 gathering_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING); + uint32 grayLevel = RedLevel + 100; + uint32 greenLevel = RedLevel + 50; + uint32 yellowLevel = RedLevel + 25; + if (GameObject const* go = Object::ToGameObject(object)) + { + if (go->GetGOInfo()->GetTrivialSkillLow()) + yellowLevel = go->GetGOInfo()->GetTrivialSkillLow(); + + if (go->GetGOInfo()->GetTrivialSkillHigh()) + grayLevel = go->GetGOInfo()->GetTrivialSkillHigh(); + + greenLevel = (yellowLevel + grayLevel) / 2; + } + // For skinning and Mining chance decrease with level. 1-74 - no decrease, 75-149 - 2 times, 225-299 - 8 times switch (SkillId) { @@ -5518,7 +5532,7 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLeve case SKILL_KUL_TIRAN_HERBALISM: case SKILL_JEWELCRAFTING: case SKILL_INSCRIPTION: - return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator, gathering_skill_gain); + return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * Multiplicator, gathering_skill_gain); case SKILL_SKINNING: case SKILL_SKINNING_2: case SKILL_OUTLAND_SKINNING: @@ -5529,9 +5543,9 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLeve case SKILL_LEGION_SKINNING: case SKILL_KUL_TIRAN_SKINNING: if (sWorld->getIntConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS) == 0) - return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator, gathering_skill_gain); + return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * Multiplicator, gathering_skill_gain); else - return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/sWorld->getIntConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)), gathering_skill_gain); + return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * Multiplicator) >> (SkillValue / sWorld->getIntConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)), gathering_skill_gain); case SKILL_MINING: case SKILL_MINING_2: case SKILL_OUTLAND_MINING: @@ -5542,9 +5556,9 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLeve case SKILL_LEGION_MINING: case SKILL_KUL_TIRAN_MINING: if (sWorld->getIntConfig(CONFIG_SKILL_CHANCE_MINING_STEPS) == 0) - return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator, gathering_skill_gain); + return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * Multiplicator, gathering_skill_gain); else - return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/sWorld->getIntConfig(CONFIG_SKILL_CHANCE_MINING_STEPS)), gathering_skill_gain); + return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, grayLevel, greenLevel, yellowLevel) * Multiplicator) >> (SkillValue / sWorld->getIntConfig(CONFIG_SKILL_CHANCE_MINING_STEPS)), gathering_skill_gain); } return false; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 335da76cb5c..41ba3ef8123 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1947,7 +1947,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool UpdateSkillPro(uint16 skillId, int32 chance, uint32 step); bool UpdateCraftSkill(SpellInfo const* spellInfo); - bool UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator = 1); + bool UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator = 1, WorldObject const* object = nullptr); bool UpdateFishingSkill(); float GetHealthBonusFromStamina() const; diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 40d92fc2a22..f5ece4a1a30 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -295,7 +295,7 @@ void WorldSession::DoLootRelease(Loot* loot) else go->SetLootState(GO_READY); } - else if (go->IsFullyLooted()) + else if (go->GetGoType() != GAMEOBJECT_TYPE_GATHERING_NODE && go->IsFullyLooted()) go->SetLootState(GO_JUST_DEACTIVATED); go->OnLootRelease(player); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 0310dcee50a..ec3d3333119 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -645,6 +645,9 @@ class TC_GAME_API Quest void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const; + // Helpers + static uint32 RoundXPValue(uint32 xp); + std::vector<uint32> DependentPreviousQuests; std::vector<uint32> DependentBreadcrumbQuests; std::array<WorldPacket, TOTAL_LOCALES> QueryData; @@ -742,9 +745,6 @@ class TC_GAME_API Quest uint32 _specialFlags = 0; // custom flags, not sniffed/WDB std::bitset<MAX_QUEST_OBJECTIVE_TYPE> _usedQuestObjectiveTypes; uint32 _scriptId = 0; - - // Helpers - static uint32 RoundXPValue(uint32 xp); }; struct QuestStatusData diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index fe7a1e12e06..b045b6473fd 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -6051,6 +6051,9 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32 lockId = go->GetGOInfo()->GetLockId(); if (!lockId) return SPELL_FAILED_BAD_TARGETS; + + if (go->GetGOInfo()->GetNotInCombat() && m_caster->ToUnit()->IsInCombat()) + return SPELL_FAILED_AFFECTING_COMBAT; } else if (Item* itm = m_targets.GetItemTarget()) lockId = itm->GetTemplate()->GetLockID(); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b09841cac2a..ceb5ed1383a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1612,7 +1612,7 @@ void Spell::EffectOpenLock() { // Allow one skill-up until respawned if (!gameObjTarget->IsInSkillupList(player->GetGUID()) && - player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue)) + player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue, 1, gameObjTarget)) gameObjTarget->AddToSkillupList(player->GetGUID()); } else if (itemTarget) |