aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2022-10-22 02:07:59 +0200
committerShauren <shauren.trinity@gmail.com>2022-10-22 02:07:59 +0200
commit1011cb73c92ddb90589452f70a1dd33830689e32 (patch)
tree02de42791042a43b54069787799e352afe8ec17d /src
parent29cfbedfb2af9ca6cf76c20b7e5fa17887418e8d (diff)
Core/GameObjects: Implemented gathering nodes (gameobject type 50)
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp80
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h2
-rw-r--r--src/server/game/Entities/GameObject/GameObjectData.h118
-rw-r--r--src/server/game/Entities/Object/Updates/ViewerDependentValues.h9
-rw-r--r--src/server/game/Entities/Player/Player.cpp26
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Handlers/LootHandler.cpp2
-rw-r--r--src/server/game/Quests/QuestDef.h6
-rw-r--r--src/server/game/Spells/Spell.cpp3
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
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)