From 80e0c443fff2baf812d03c18970f591e4abc15f1 Mon Sep 17 00:00:00 2001 From: Kittnz Date: Tue, 24 Jun 2014 18:23:37 +0200 Subject: Quest: Powering our Defenses fixed Fix by @Discover-, @untaught, @Kittnz --- .../scripts/EasternKingdoms/zone_eversong_woods.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp b/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp index 8c612a11621..bc4fff4da7b 100644 --- a/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp +++ b/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp @@ -190,6 +190,9 @@ enum InfusedCrystal // Quest QUEST_POWERING_OUR_DEFENSES = 8490, + // Quest Credit + QUEST_POD_CREDIT = 16364, + // Says EMOTE = 0, @@ -266,24 +269,17 @@ public: summoned->AI()->AttackStart(me); } - void JustDied(Unit* /*killer*/) override - { - if (PlayerGUID && !Completed) - if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) - player->FailQuest(QUEST_POWERING_OUR_DEFENSES); - } - void UpdateAI(uint32 diff) override { if (EndTimer < diff && Progress) { - Talk(EMOTE); Completed = true; if (PlayerGUID) if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) - player->CompleteQuest(QUEST_POWERING_OUR_DEFENSES); - - me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + { + Talk(EMOTE, player); + player->KilledMonsterCredit(QUEST_POD_CREDIT); + } me->RemoveCorpse(); } else EndTimer -= diff; -- cgit v1.2.3 From 3f21b14bc0cb8425ee2d60e6d4864250d22b1762 Mon Sep 17 00:00:00 2001 From: Sebastian Valle Herrera Date: Tue, 24 Jun 2014 15:21:34 -0500 Subject: Core/Config: Fixed Rate.Corpse.Decay.Looted Looted creatures should now correctly obey the Rate.Corpse.Decay.Looted value. Closes #5358 --- src/server/game/Entities/Creature/Creature.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index c81ba409495..1823c7c96c2 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2274,19 +2274,16 @@ void Creature::AllLootRemovedFromCorpse() if (m_corpseRemoveTime <= now) return; - float decayRate; + float decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED); CreatureTemplate const* cinfo = GetCreatureTemplate(); - decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED); - uint32 diff = uint32((m_corpseRemoveTime - now) * decayRate); - - m_respawnTime -= diff; - // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update if (cinfo && cinfo->SkinLootId) m_corpseRemoveTime = time(NULL); else - m_corpseRemoveTime -= diff; + m_corpseRemoveTime = now + m_corpseDelay * decayRate; + + m_respawnTime = m_corpseRemoveTime + m_respawnTime; } } -- cgit v1.2.3 From cac491bef8c60be0a8b20e6d49480224e50ba0a1 Mon Sep 17 00:00:00 2001 From: Trisjdc Date: Wed, 25 Jun 2014 01:03:24 +0100 Subject: Fix a warning picked by static code analysis (assignment of a temporary variable before destruction) --- src/server/game/Entities/Player/Player.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9733c0f2b52..6548b2dffde 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2920,11 +2920,10 @@ void Player::UninviteFromGroup() void Player::RemoveFromGroup(Group* group, uint64 guid, RemoveMethod method /* = GROUP_REMOVEMETHOD_DEFAULT*/, uint64 kicker /* = 0 */, const char* reason /* = NULL */) { - if (group) - { - group->RemoveMember(guid, method, kicker, reason); - group = NULL; - } + if (!group) + return; + + group->RemoveMember(guid, method, kicker, reason); } void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend, float /*group_rate*/) -- cgit v1.2.3 From a0fedd1d781bd6a4c6f2790e012a0f3ee12ccbf0 Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Jun 2014 20:04:07 -0500 Subject: Core/Skinning: Fixed the creatures becoming non-skinnable even before looting them completely. Closes #5318 --- src/server/game/Entities/Creature/Creature.cpp | 2 +- src/server/game/Entities/Creature/Creature.h | 4 ++++ src/server/game/Entities/Player/Player.cpp | 8 ++++++-- src/server/game/Handlers/LootHandler.cpp | 6 +++++- src/server/game/Spells/Spell.cpp | 6 ++++-- src/server/game/Spells/SpellEffects.cpp | 17 +++++++++++++++-- 6 files changed, 35 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 1823c7c96c2..71143c3c7eb 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -142,7 +142,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) } Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), -lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0), +lootForPickPocketed(false), lootForBody(false), lootForSkinned(false), _skinner(0), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 9cc08e3b71d..069308c9e84 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -553,6 +553,9 @@ class Creature : public Unit, public GridObject, public MapObject Loot loot; bool lootForPickPocketed; bool lootForBody; + bool lootForSkinned; + void SetSkinner(uint64 guid) { _skinner = guid; } + uint64 GetSkinner() const { return _skinner; } // Returns the player who skinned this creature Player* GetLootRecipient() const; Group* GetLootRecipientGroup() const; bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; } @@ -688,6 +691,7 @@ class Creature : public Unit, public GridObject, public MapObject uint64 m_lootRecipient; uint32 m_lootRecipientGroup; + uint64 _skinner; /// Timers time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 6548b2dffde..b28d20c937c 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9020,8 +9020,12 @@ void Player::SendLoot(uint64 guid, LootType loot_type) // possible only if creature->lootForBody && loot->empty() at spell cast check if (loot_type == LOOT_SKINNING) { - loot->clear(); - loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true); + if (!creature->lootForSkinned) + { + creature->lootForSkinned = true; + loot->clear(); + loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true); + } permission = OWNER_PERMISSION; } // set group rights only for loot_type != LOOT_SKINNING diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 61f0b9afce2..2464a5385a4 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -355,11 +355,15 @@ void WorldSession::DoLootRelease(uint64 lguid) loot = &creature->loot; if (loot->isLooted()) { + creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + + if (loot->loot_type == LOOT_SKINNING) + creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); + // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact if (!creature->IsAlive()) creature->AllLootRemovedFromCorpse(); - creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); loot->clear(); } else diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 48c2a76578d..f9a5e742f9f 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5058,11 +5058,13 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_TARGET_UNSKINNABLE; Creature* creature = m_targets.GetUnitTarget()->ToCreature(); - if (creature->GetCreatureType() != CREATURE_TYPE_CRITTER && !creature->loot.isLooted()) + if (creature->GetCreatureType() != CREATURE_TYPE_CRITTER && creature->loot.loot_type != LOOT_SKINNING && !creature->loot.isLooted()) return SPELL_FAILED_TARGET_NOT_LOOTED; uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill(); + bool alreadySkinned = creature->loot.loot_type == LOOT_SKINNING && creature->GetSkinner() == m_caster->GetGUID(); + int32 skillValue = m_caster->ToPlayer()->GetSkillValue(skill); int32 TargetLevel = m_targets.GetUnitTarget()->getLevel(); int32 ReqValue = (skillValue < 100 ? (TargetLevel-10) * 10 : TargetLevel * 5); @@ -5072,7 +5074,7 @@ SpellCastResult Spell::CheckCast(bool strict) // chance for fail at orange skinning attempt if ((m_selfContainer && (*m_selfContainer) == this) && skillValue < sWorld->GetConfigMaxSkillValue() && - (ReqValue < 0 ? 0 : ReqValue) > irand(skillValue - 25, skillValue + 37)) + (ReqValue < 0 ? 0 : ReqValue) > irand(skillValue - 25, skillValue + 37) && !alreadySkinned) return SPELL_FAILED_TRY_AGAIN; break; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9cf0e1ae45c..0a43c5a2c45 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4702,15 +4702,28 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/) uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill(); + bool awardPoints = true; + + // Check if a skinning loot table was already generated for this creature + if (creature->loot.loot_type == LOOT_SKINNING) + { + if (creature->GetSkinner() != m_caster->GetGUID()) + return; + + awardPoints = false; // Do not grant skill points for this loot, they were already granted the first time. + } + else + creature->SetSkinner(m_caster->GetGUID()); + m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING); - creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5; int32 skillValue = m_caster->ToPlayer()->GetPureSkillValue(skill); // Double chances for elites - m_caster->ToPlayer()->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1); + if (awardPoints) + m_caster->ToPlayer()->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1); } void Spell::EffectCharge(SpellEffIndex /*effIndex*/) -- cgit v1.2.3 From 8c944f1456af624ab98672390be63d16cc244a7f Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Jun 2014 22:13:59 -0500 Subject: Core/Loot: Make the pickpocket loot refill every 10 minutes by default on the NPCs after they have been pickpocketed. Configurable by Creature.PickPocketRefillDelay Closes #935 --- src/server/game/Entities/Creature/Creature.cpp | 21 ++++++++++++++++++--- src/server/game/Entities/Creature/Creature.h | 3 +++ src/server/game/Entities/Player/Player.cpp | 1 + src/server/game/Entities/Unit/Unit.cpp | 3 +++ src/server/game/World/World.cpp | 2 ++ src/server/game/World/World.h | 1 + src/server/worldserver/worldserver.conf.dist | 8 ++++++++ 7 files changed, 36 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 71143c3c7eb..84393070c7d 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -142,7 +142,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) } Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(), -lootForPickPocketed(false), lootForBody(false), lootForSkinned(false), _skinner(0), m_groupLootTimer(0), lootingGroupLowGUID(0), +lootForPickPocketed(false), _pickpocketLootRestore(0), lootForBody(false), lootForSkinned(false), _skinner(0), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), @@ -547,6 +547,15 @@ void Creature::Update(uint32 diff) if (!IsAlive()) break; + time_t now = time(NULL); + + // Check if we should refill the pickpocketing loot + if (lootForPickPocketed && _pickpocketLootRestore && _pickpocketLootRestore <= now) + { + lootForPickPocketed = false; + _pickpocketLootRestore = 0; + } + if (m_regenTimer > 0) { if (diff >= m_regenTimer) @@ -1527,9 +1536,10 @@ void Creature::Respawn(bool force) TC_LOG_DEBUG("entities.unit", "Respawning creature %s (GuidLow: %u, Full GUID: " UI64FMTD " Entry: %u)", GetName().c_str(), GetGUIDLow(), GetGUID(), GetEntry()); m_respawnTime = 0; + _pickpocketLootRestore = 0; lootForPickPocketed = false; - lootForBody = false; - + lootForBody = false; + lootForSkinned = false; if (m_originalEntry != GetEntry()) UpdateEntry(m_originalEntry); @@ -2709,3 +2719,8 @@ void Creature::ReleaseFocus(Spell const* focusSpell) ClearUnitState(UNIT_STATE_ROTATING); } +void Creature::StartPickPocketRefillTimer() +{ + _pickpocketLootRestore = time(NULL) + sWorld->getIntConfig(CONFIG_CREATURE_PICKPOCKET_REFILL); +} + diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 069308c9e84..2360d04c459 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -554,6 +554,8 @@ class Creature : public Unit, public GridObject, public MapObject bool lootForPickPocketed; bool lootForBody; bool lootForSkinned; + void StartPickPocketRefillTimer(); + void ResetPickPocketRefillTimer() { _pickpocketLootRestore = 0; } void SetSkinner(uint64 guid) { _skinner = guid; } uint64 GetSkinner() const { return _skinner; } // Returns the player who skinned this creature Player* GetLootRecipient() const; @@ -694,6 +696,7 @@ class Creature : public Unit, public GridObject, public MapObject uint64 _skinner; /// Timers + time_t _pickpocketLootRestore; time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance time_t m_respawnTime; // (secs) time of next respawn uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b28d20c937c..fb4d4c3ddad 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8972,6 +8972,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (!creature->lootForPickPocketed) { creature->lootForPickPocketed = true; + creature->StartPickPocketRefillTimer(); loot->clear(); if (uint32 lootid = creature->GetCreatureTemplate()->pickpocketLootId) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 5e12022312d..d0cc8d771fb 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -15272,7 +15272,10 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) { Loot* loot = &creature->loot; if (creature->lootForPickPocketed) + { + creature->ResetPickPocketRefillTimer(); creature->lootForPickPocketed = false; + } loot->clear(); if (uint32 lootid = creature->GetCreatureTemplate()->lootid) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index b643d127c04..62603cce950 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1044,6 +1044,8 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN] = sConfigMgr->GetBoolDefault("OffhandCheckAtSpellUnlearn", true); + m_int_configs[CONFIG_CREATURE_PICKPOCKET_REFILL] = sConfigMgr->GetIntDefault("Creature.PickPocketRefillDelay", 10 * MINUTE); + if (int32 clientCacheId = sConfigMgr->GetIntDefault("ClientCacheVersion", 0)) { // overwrite DB/old value diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index efd7570992a..61acdc37b07 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -333,6 +333,7 @@ enum WorldIntConfigs CONFIG_BG_REWARD_LOSER_HONOR_FIRST, CONFIG_BG_REWARD_LOSER_HONOR_LAST, CONFIG_BIRTHDAY_TIME, + CONFIG_CREATURE_PICKPOCKET_REFILL, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index f71b7bb8150..5a3ea2bb4e1 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1352,6 +1352,14 @@ Rate.Creature.Elite.RARE.HP = 1 Rate.Creature.Elite.RAREELITE.HP = 1 Rate.Creature.Elite.WORLDBOSS.HP = 1 +# +# Creature.PickPocketRefillDelay +# Description: Time in seconds that the server will wait before refilling the pickpocket loot +# for a creature +# Default: 600 + +Creature.PickPocketRefillDelay = 600 + # # ListenRange.Say # Description: Distance in which players can read say messages from creatures or -- cgit v1.2.3 From 1320c9f8d60d36624c1aa920533622eb84494812 Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Jun 2014 23:00:54 -0500 Subject: Core/SmartAI: Allow the use of SMART_ACTION_SET_EVENT_PHASE with SMART_EVENT_RESPAWN. Closes #9289 --- src/server/game/AI/SmartScripts/SmartAI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index e36433dd8c0..af47b52f500 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -537,9 +537,9 @@ void SmartAI::JustRespawned() me->SetVisible(true); if (me->getFaction() != me->GetCreatureTemplate()->faction) me->RestoreFaction(); - GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN); mJustReset = true; JustReachedHome(); + GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN); mFollowGuid = 0;//do not reset follower on Reset(), we need it after combat evade mFollowDist = 0; mFollowAngle = 0; -- cgit v1.2.3