From 7377c96cc816bc698fbe6cb56cea533aa311d4c6 Mon Sep 17 00:00:00 2001 From: Skjalf <47818697+Nyeriah@users.noreply.github.com> Date: Wed, 23 Mar 2022 15:42:34 -0300 Subject: [PATCH 1/4] fix(Scripts/BlackwingLair): Razorgore improvements (#10971) - Rewrite reset events - Use proper healing spell on phase transition - Now uses abilities during phase 1 - Phase transition scripted - mobs now run away --- .../rev_1647530609689243500.sql | 9 ++ src/server/game/AI/CoreAI/UnitAI.h | 3 + .../game/Entities/Creature/Creature.cpp | 5 + src/server/game/Entities/Creature/Creature.h | 3 +- src/server/game/Instances/InstanceScript.cpp | 16 +++ src/server/game/Instances/InstanceScript.h | 6 ++ .../PointMovementGenerator.cpp | 8 ++ .../WaypointMovementGenerator.cpp | 8 ++ .../game/Spells/SpellInfoCorrections.cpp | 6 ++ .../BlackwingLair/blackwing_lair.h | 7 +- .../BlackwingLair/boss_razorgore.cpp | 99 ++++++++++++++++--- .../BlackwingLair/instance_blackwing_lair.cpp | 74 +++++++++++--- 12 files changed, 212 insertions(+), 32 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1647530609689243500.sql diff --git a/data/sql/updates/pending_db_world/rev_1647530609689243500.sql b/data/sql/updates/pending_db_world/rev_1647530609689243500.sql new file mode 100644 index 000000000..fe239252f --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1647530609689243500.sql @@ -0,0 +1,9 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1647530609689243500'); + +DELETE FROM `creature` WHERE `guid` = 84205 AND `id1` = 14459; +INSERT INTO `creature` (`guid`, `id1`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`,`equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES +(84205,14459,469,0,0,1,1,0,-7644.53,-1081.53,408.574,5.2709,10,0,0,42,0,0,0,0,0,'',0); + +DELETE FROM `creature_text` WHERE `CreatureID` = 14459; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration` ,`Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(14459, 0, 0, '%s flee as the controlling power of the orb is drained.', 16, 0, 100, 0, 0, 0, 9592, 3, ''); diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 5e7d98f61..af3caec97 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -334,6 +334,9 @@ public: static AISpellInfoType* AISpellInfo; static void FillAISpellInfo(); + // Called when a summon reaches a waypoint or point movement finished. + virtual void SummonMovementInform(Creature* /*creature*/, uint32 /*motionType*/, uint32 /*point*/) { } + virtual void sGossipHello(Player* /*player*/) {} virtual void sGossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) {} virtual void sGossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, char const* /*code*/) {} diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 6eaac5e8c..0e89b1b73 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -3524,3 +3524,8 @@ void Creature::SetRespawnTime(uint32 respawn) { m_respawnTime = respawn ? GameTime::GetGameTime().count() + respawn : 0; } + +void Creature::SetCorpseRemoveTime(uint32 delay) +{ + m_corpseRemoveTime = GameTime::GetGameTime().count() + delay; +} diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 637fae5cf..aa1b7fa44 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -69,6 +69,7 @@ public: void GetRespawnPosition(float& x, float& y, float& z, float* ori = nullptr, float* dist = nullptr) const; void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } + void SetCorpseRemoveTime(uint32 delay); [[nodiscard]] uint32 GetCorpseDelay() const { return m_corpseDelay; } [[nodiscard]] bool IsRacialLeader() const { return GetCreatureTemplate()->RacialLeader; } [[nodiscard]] bool IsCivilian() const { return GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; } @@ -395,7 +396,7 @@ protected: ObjectGuid::LowType m_lootRecipientGroup; /// Timers - time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance + time_t m_corpseRemoveTime; // (secs) timer for death or corpse disappearance time_t m_respawnTime; // (secs) time of next respawn time_t m_respawnedTime; // (secs) time when creature respawned uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 034f52880..8a2dcfced 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -408,6 +408,22 @@ void InstanceScript::DoRespawnGameObject(ObjectGuid uiGuid, uint32 uiTimeToDespa } } +void InstanceScript::DoRespawnCreature(ObjectGuid guid, bool force) +{ + if (Creature* creature = instance->GetCreature(guid)) + { + creature->Respawn(force); + } +} + +void InstanceScript::DoRespawnCreature(uint32 type, bool force) +{ + if (Creature* creature = instance->GetCreature(GetObjectGuid(type))) + { + creature->Respawn(force); + } +} + void InstanceScript::DoUpdateWorldState(uint32 uiStateId, uint32 uiStateData) { Map::PlayerList const& lPlayers = instance->GetPlayers(); diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 450af2289..f9846f47d 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -194,6 +194,12 @@ public: //Respawns a GO having negative spawntimesecs in gameobject-table void DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn = MINUTE); + // Respawns a creature. + void DoRespawnCreature(ObjectGuid guid, bool force = false); + + // Respawns a creature from the creature object storage. + void DoRespawnCreature(uint32 type, bool force = false); + //sends world state update to all players in instance void DoUpdateWorldState(uint32 worldstateId, uint32 worldstateValue); diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 83ec1a36d..501558066 100644 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -197,6 +197,14 @@ template <> void PointMovementGenerator::MovementInform(Creature* unit { if (unit->AI()) unit->AI()->MovementInform(POINT_MOTION_TYPE, id); + + if (Unit* summoner = unit->GetCharmerOrOwner()) + { + if (UnitAI* AI = summoner->GetAI()) + { + AI->SummonMovementInform(unit, POINT_MOTION_TYPE, id); + } + } } template void PointMovementGenerator::DoInitialize(Player*); diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index b669efa62..9a30e38ca 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -256,6 +256,14 @@ void WaypointMovementGenerator::MovementInform(Creature* creature) { if (creature->AI()) creature->AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); + + if (Unit* owner = creature->GetCharmerOrOwner()) + { + if (UnitAI* AI = owner->GetAI()) + { + AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, i_currentNode); + } + } } //----------------------------------------------------// diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index ea065e9aa..a90200076 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -4243,6 +4243,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].DieSides = 1250; }); + // Explosion - Razorgore + ApplySpellFix({ 20038 }, [](SpellInfo* spellInfo) + { + spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); + }); + for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo* spellInfo = mSpellInfoMap[i]; diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h index fe371cba8..a0adcf52b 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h @@ -39,13 +39,18 @@ enum BWLEncounter // Additional Data DATA_LORD_VICTOR_NEFARIUS = 8, + DATA_GRETHOK = 9, + DATA_NEFARIAN_TROOPS = 10, // Doors - DATA_GO_CHROMAGGUS_DOOR = 9 + DATA_GO_CHROMAGGUS_DOOR = 11 }; enum BWLCreatureIds { + NPC_GRETHOK = 12557, + NPC_BLACKWING_GUARDSMAN = 14456, + NPC_NEFARIAN_TROOPS = 14459, NPC_RAZORGORE = 12435, NPC_BLACKWING_DRAGON = 12422, NPC_BLACKWING_TASKMASTER = 12458, diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp index 6ae689c7c..398fe167f 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp @@ -27,6 +27,8 @@ enum Say SAY_EGGS_BROKEN2 = 1, SAY_EGGS_BROKEN3 = 2, SAY_DEATH = 3, + + EMOTE_TROOPS_RETREAT = 0 }; enum Spells @@ -38,7 +40,12 @@ enum Spells SPELL_CLEAVE = 19632, SPELL_WARSTOMP = 24375, SPELL_FIREBALLVOLLEY = 22425, - SPELL_CONFLAGRATION = 23023 + SPELL_CONFLAGRATION = 23023, + + SPELL_EXPLODE_ORB = 20037, + SPELL_EXPLOSION = 20038, // Instakill everything. + + SPELL_WARMING_FLAMES = 23040, }; enum Summons @@ -72,16 +79,19 @@ public: void Reset() override { _Reset(); - + _died = false; _charmerGUID.Clear(); secondPhase = false; + summons.DespawnAll(); instance->SetData(DATA_EGG_EVENT, NOT_STARTED); } void JustDied(Unit* /*killer*/) override { - _JustDied(); - Talk(SAY_DEATH); + if (secondPhase) + { + _JustDied(); + } } bool CanAIAttack(Unit const* target) const override @@ -93,6 +103,11 @@ public: { _EnterCombat(); + events.ScheduleEvent(EVENT_CLEAVE, 15000); + events.ScheduleEvent(EVENT_STOMP, 35000); + events.ScheduleEvent(EVENT_FIREBALL, 7000); + events.ScheduleEvent(EVENT_CONFLAGRATION, 12000); + instance->SetData(DATA_EGG_EVENT, IN_PROGRESS); } @@ -101,12 +116,26 @@ public: secondPhase = true; _charmerGUID.Clear(); me->RemoveAllAuras(); - me->SetHealth(me->GetMaxHealth()); - events.ScheduleEvent(EVENT_CLEAVE, 15000); - events.ScheduleEvent(EVENT_STOMP, 35000); - events.ScheduleEvent(EVENT_FIREBALL, 7000); - events.ScheduleEvent(EVENT_CONFLAGRATION, 12000); + DoCastSelf(SPELL_WARMING_FLAMES, true); + + if (Creature* troops = instance->GetCreature(DATA_NEFARIAN_TROOPS)) + { + troops->AI()->Talk(EMOTE_TROOPS_RETREAT); + } + + for (ObjectGuid const& guid : _summonGUIDS) + { + if (Creature* creature = ObjectAccessor::GetCreature(*me, guid)) + { + if (creature->IsAlive()) + { + creature->CombatStop(true); + creature->SetReactState(REACT_PASSIVE); + creature->GetMotionMaster()->MovePoint(0, Position(-7560.568848f, -1028.553345f, 408.491211f, 0.523858f)); + } + } + } } void SetGUID(ObjectGuid const guid, int32 /*id*/) override @@ -123,6 +152,13 @@ public: charmer->CastSpell(charmer, SPELL_MIND_EXHAUSTION, true); } } + else + { + if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID)) + { + me->TauntApply(charmer); + } + } } void DoAction(int32 action) override @@ -138,12 +174,41 @@ public: } } + void JustSummoned(Creature* summon) override + { + _summonGUIDS.push_back(summon->GetGUID()); + summon->SetOwnerGUID(me->GetGUID()); + summons.Summon(summon); + } + + void SummonMovementInform(Creature* summon, uint32 movementType, uint32 /*pathId*/) override + { + if (movementType == POINT_MOTION_TYPE) + { + summon->DespawnOrUnsummon(); + } + } + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { - if (!secondPhase && damage >= me->GetHealth()) + if (!secondPhase && damage >= me->GetHealth() && !_died) { - damage = me->GetHealth() - 1; - EnterEvadeMode(); + // This is required because he kills himself with the explosion spell, causing a loop. + _died = true; + + Talk(SAY_DEATH); + DoCastAOE(SPELL_EXPLODE_ORB); + DoCastAOE(SPELL_EXPLOSION); + + // Respawn shorty in case of failure during phase 1. + me->SetCorpseRemoveTime(25); + me->SetRespawnTime(30); + me->SaveRespawnTime(); + + // Might not be required, safe measure. + me->SetLootRecipient(nullptr); + + instance->SetData(DATA_EGG_EVENT, FAIL); } } @@ -152,7 +217,10 @@ public: if (!UpdateVictim()) return; - events.Update(diff); + if (!me->IsCharmed()) + { + events.Update(diff); + } if (me->HasUnitState(UNIT_STATE_CASTING)) return; @@ -176,18 +244,21 @@ public: case EVENT_CONFLAGRATION: DoCastVictim(SPELL_CONFLAGRATION); if (me->GetVictim() && me->GetVictim()->HasAura(SPELL_CONFLAGRATION)) - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true)) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1)) me->TauntApply(target); events.ScheduleEvent(EVENT_CONFLAGRATION, 30000); break; } } + DoMeleeAttackIfReady(); } private: bool secondPhase; + bool _died; ObjectGuid _charmerGUID; + GuidVector _summonGUIDS; }; CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp index d7dfb96ac..679039671 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp @@ -41,6 +41,12 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE} // END }; +ObjectData const creatureData[] = +{ + { NPC_GRETHOK, DATA_GRETHOK }, + { NPC_NEFARIAN_TROOPS, DATA_NEFARIAN_TROOPS } +}; + Position const SummonPosition[8] = { {-7661.207520f, -1043.268188f, 407.199554f, 6.280452f}, @@ -67,7 +73,7 @@ public: //SetHeaders(DataHeader); SetBossNumber(EncounterCount); LoadDoorData(doorData); - //LoadObjectData(creatureData, gameObjectData); + LoadObjectData(creatureData, nullptr); } void Initialize() override @@ -98,6 +104,9 @@ public: if (CreatureAI* razorAI = razor->AI()) razorAI->JustSummoned(creature); break; + case NPC_BLACKWING_GUARDSMAN: + guardList.push_back(creature->GetGUID()); + break; case NPC_NEFARIAN: nefarianGUID = creature->GetGUID(); break; @@ -135,11 +144,14 @@ public: { case GO_BLACK_DRAGON_EGG: if (GetBossState(DATA_FIREMAW) == DONE) + { go->SetPhaseMask(2, true); + } else + { EggList.push_back(go->GetGUID()); + } break; - case GO_PORTCULLIS_RAZORGORE: case GO_PORTCULLIS_VAELASTRASZ: case GO_PORTCULLIS_BROODLORD: @@ -233,10 +245,15 @@ public: if (state == DONE) { for (ObjectGuid const& guid : EggList) + { + // Eggs should be destroyed instead + // @todo: after dynamic spawns if (GameObject* egg = instance->GetGameObject(guid)) + { egg->SetPhaseMask(2, true); + } + } } - SetData(DATA_EGG_EVENT, NOT_STARTED); break; case DATA_CHROMAGGUS: if (state == DONE) @@ -270,7 +287,7 @@ public: switch (data) { case IN_PROGRESS: - _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 45000); + _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 45 * IN_MILLISECONDS); EggEvent = data; EggCount = 0; break; @@ -278,13 +295,19 @@ public: _events.CancelEvent(EVENT_RAZOR_SPAWN); EggEvent = data; EggCount = 0; + for (ObjectGuid const& guid : EggList) { - if (GameObject* egg = instance->GetGameObject(guid)) - { - egg->Respawn(); - } + DoRespawnGameObject(guid, 0); } + + DoRespawnCreature(DATA_GRETHOK); + + for (ObjectGuid const& guid : guardList) + { + DoRespawnCreature(guid); + } + break; case SPECIAL: if (++EggCount >= EggList.size()) @@ -336,12 +359,22 @@ public: void OnUnitDeath(Unit* unit) override { - //! HACK, needed because of buggy CreatureAI after charm - if (unit->GetEntry() == NPC_RAZORGORE && GetBossState(DATA_RAZORGORE_THE_UNTAMED) != DONE) - SetBossState(DATA_RAZORGORE_THE_UNTAMED, DONE); - switch (unit->GetEntry()) { + case NPC_RAZORGORE: + //! HACK, needed because of buggy CreatureAI after charm + if (EggEvent == DONE) + { + if (unit->GetEntry() == NPC_RAZORGORE && GetBossState(DATA_RAZORGORE_THE_UNTAMED) != DONE) + { + SetBossState(DATA_RAZORGORE_THE_UNTAMED, DONE); + } + } + else + { + _events.CancelEvent(EVENT_RAZOR_SPAWN); + } + break; case NPC_BLACK_DRAKONID: case NPC_BLUE_DRAKONID: case NPC_BRONZE_DRAKONID: @@ -379,10 +412,18 @@ public: switch (eventId) { case EVENT_RAZOR_SPAWN: - for (uint8 i = urand(2, 5); i > 0; --i) - if (Creature* summon = instance->SummonCreature(Entry[urand(0, 2)], SummonPosition[urand(0, 7)])) - summon->AI()->DoZoneInCombat(); - _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 12000, 17000); + if (EggEvent == IN_PROGRESS) + { + for (uint8 i = urand(2, 5); i > 0; --i) + { + if (Creature* summon = instance->SummonCreature(Entry[urand(0, 2)], SummonPosition[urand(0, 7)])) + { + summon->AI()->DoZoneInCombat(); + } + } + + _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 12000, 17000); + } break; case EVENT_RAZOR_PHASE_TWO: _events.CancelEvent(EVENT_RAZOR_SPAWN); @@ -462,6 +503,7 @@ public: uint8 EggCount; uint32 EggEvent; GuidList EggList; + GuidList guardList; // Nefarian uint32 NefarianLeftTunnel; From 9ae0b4e425a85b19275760d854b7158e51d6ba51 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Wed, 23 Mar 2022 18:44:25 +0000 Subject: [PATCH 2/4] chore(DB): import pending files Referenced commit(s): 7377c96cc816bc698fbe6cb56cea533aa311d4c6 --- .../2022_03_23_03.sql} | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) rename data/sql/updates/{pending_db_world/rev_1647530609689243500.sql => db_world/2022_03_23_03.sql} (52%) diff --git a/data/sql/updates/pending_db_world/rev_1647530609689243500.sql b/data/sql/updates/db_world/2022_03_23_03.sql similarity index 52% rename from data/sql/updates/pending_db_world/rev_1647530609689243500.sql rename to data/sql/updates/db_world/2022_03_23_03.sql index fe239252f..d7eb02c15 100644 --- a/data/sql/updates/pending_db_world/rev_1647530609689243500.sql +++ b/data/sql/updates/db_world/2022_03_23_03.sql @@ -1,3 +1,19 @@ +-- DB update 2022_03_23_02 -> 2022_03_23_03 +DROP PROCEDURE IF EXISTS `updateDb`; +DELIMITER // +CREATE PROCEDURE updateDb () +proc:BEGIN DECLARE OK VARCHAR(100) DEFAULT 'FALSE'; +SELECT COUNT(*) INTO @COLEXISTS +FROM information_schema.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'version_db_world' AND COLUMN_NAME = '2022_03_23_02'; +IF @COLEXISTS = 0 THEN LEAVE proc; END IF; +START TRANSACTION; +ALTER TABLE version_db_world CHANGE COLUMN 2022_03_23_02 2022_03_23_03 bit; +SELECT sql_rev INTO OK FROM version_db_world WHERE sql_rev = '1647530609689243500'; IF OK <> 'FALSE' THEN LEAVE proc; END IF; +-- +-- START UPDATING QUERIES +-- + INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1647530609689243500'); DELETE FROM `creature` WHERE `guid` = 84205 AND `id1` = 14459; @@ -7,3 +23,13 @@ INSERT INTO `creature` (`guid`, `id1`, `map`, `zoneId`, `areaId`, `spawnMask`, ` DELETE FROM `creature_text` WHERE `CreatureID` = 14459; INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration` ,`Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES (14459, 0, 0, '%s flee as the controlling power of the orb is drained.', 16, 0, 100, 0, 0, 0, 9592, 3, ''); + +-- +-- END UPDATING QUERIES +-- +UPDATE version_db_world SET date = '2022_03_23_03' WHERE sql_rev = '1647530609689243500'; +COMMIT; +END // +DELIMITER ; +CALL updateDb(); +DROP PROCEDURE IF EXISTS `updateDb`; From 44b7a0666c78dc99ab0bbc94045abb6685b3ad86 Mon Sep 17 00:00:00 2001 From: ZhengPeiRu21 <98835050+ZhengPeiRu21@users.noreply.github.com> Date: Thu, 24 Mar 2022 03:27:15 -0600 Subject: [PATCH 3/4] feat(Scripting/Hooks): implement OnQuestComputeXP() hook (#10934) --- doc/changelog/pendings/changes_1647137971165231200.md | 7 +++++++ src/server/game/Entities/Player/PlayerQuest.cpp | 1 + src/server/game/Scripting/ScriptDefines/PlayerScript.cpp | 7 +++++++ src/server/game/Scripting/ScriptMgr.h | 4 ++++ 4 files changed, 19 insertions(+) create mode 100644 doc/changelog/pendings/changes_1647137971165231200.md diff --git a/doc/changelog/pendings/changes_1647137971165231200.md b/doc/changelog/pendings/changes_1647137971165231200.md new file mode 100644 index 000000000..86f51b9af --- /dev/null +++ b/doc/changelog/pendings/changes_1647137971165231200.md @@ -0,0 +1,7 @@ +### Added + +- New hook for OnQuestComputeXP(). The intended use is to change the XP values for certain quests programmatically. The hook is triggered after XP calculation and before rewarding XP or gold to the player. + +### How to upgrade + +- No special changes needed. The new hook is available for use and should not interfere with any existing hooks or logic. diff --git a/src/server/game/Entities/Player/PlayerQuest.cpp b/src/server/game/Entities/Player/PlayerQuest.cpp index 88c640c82..037d4733d 100644 --- a/src/server/game/Entities/Player/PlayerQuest.cpp +++ b/src/server/game/Entities/Player/PlayerQuest.cpp @@ -737,6 +737,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i) AddPct(XP, (*i)->GetAmount()); + sScriptMgr->OnQuestComputeXP(this, quest, XP); int32 moneyRew = 0; if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) || sScriptMgr->ShouldBeRewardedWithMoneyInsteadOfExp(this)) { diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index 1f2bcd9b3..959fc2b35 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -729,6 +729,13 @@ bool ScriptMgr::OnBeforePlayerQuestComplete(Player* player, uint32 quest_id) return true; } +void ScriptMgr::OnQuestComputeXP(Player* player, Quest const* quest, uint32& xpValue) +{ + ExecuteScript([&](PlayerScript* script) + { + script->OnQuestComputeXP(player, quest, xpValue); + }); +} void ScriptMgr::OnBeforeStoreOrEquipNewItem(Player* player, uint32 vendorslot, uint32& item, uint8 count, uint8 bag, uint8 slot, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore) { diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 8400cd7f9..bf874c096 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -1157,6 +1157,9 @@ public: // After completed a quest [[nodiscard]] virtual bool OnBeforeQuestComplete(Player* /*player*/, uint32 /*quest_id*/) { return true; } + // Called after computing the XP reward value for a quest + virtual void OnQuestComputeXP(Player* /*player*/, Quest const* /*quest*/, uint32& /*xpValue*/) { } + // Before durability repair action, you can even modify the discount value virtual void OnBeforeDurabilityRepair(Player* /*player*/, ObjectGuid /*npcGUID*/, ObjectGuid /*itemGUID*/, float&/*discountMod*/, uint8 /*guildBank*/) { } @@ -2221,6 +2224,7 @@ public: /* PlayerScript */ void OnCreateItem(Player* player, Item* item, uint32 count); void OnQuestRewardItem(Player* player, Item* item, uint32 count); bool OnBeforePlayerQuestComplete(Player* player, uint32 quest_id); + void OnQuestComputeXP(Player* player, Quest const* quest, uint32& xpValue); void OnBeforePlayerDurabilityRepair(Player* player, ObjectGuid npcGUID, ObjectGuid itemGUID, float& discountMod, uint8 guildBank); void OnBeforeBuyItemFromVendor(Player* player, ObjectGuid vendorguid, uint32 vendorslot, uint32& item, uint8 count, uint8 bag, uint8 slot); void OnBeforeStoreOrEquipNewItem(Player* player, uint32 vendorslot, uint32& item, uint8 count, uint8 bag, uint8 slot, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore); From 3961e0839c8106d04e6ace425c1160771b1aa558 Mon Sep 17 00:00:00 2001 From: AzerothCoreBot Date: Thu, 24 Mar 2022 09:29:07 +0000 Subject: [PATCH 4/4] chore(DB): import pending files Referenced commit(s): 44b7a0666c78dc99ab0bbc94045abb6685b3ad86 --- acore.json | 2 +- doc/changelog/master.md | 12 ++++++++++++ .../pendings/changes_1647137971165231200.md | 7 ------- 3 files changed, 13 insertions(+), 8 deletions(-) delete mode 100644 doc/changelog/pendings/changes_1647137971165231200.md diff --git a/acore.json b/acore.json index 352813896..b521641cc 100644 --- a/acore.json +++ b/acore.json @@ -1,5 +1,5 @@ { "name": "azerothcore-wotlk", - "version": "6.0.0-dev.2", + "version": "6.0.0-dev.3", "license": "AGPL3" } diff --git a/doc/changelog/master.md b/doc/changelog/master.md index 913877108..bc889f228 100644 --- a/doc/changelog/master.md +++ b/doc/changelog/master.md @@ -1,3 +1,15 @@ +## 6.0.0-dev.3 | Commit: [44b7a0666c78dc99ab0bbc94045abb6685b3ad86 +](https://github.com/azerothcore/azerothcore-wotlk/commit/44b7a0666c78dc99ab0bbc94045abb6685b3ad86 + + +### Added + +- New hook for OnQuestComputeXP(). The intended use is to change the XP values for certain quests programmatically. The hook is triggered after XP calculation and before rewarding XP or gold to the player. + +### How to upgrade + +- No special changes needed. The new hook is available for use and should not interfere with any existing hooks or logic. + ## 6.0.0-dev.2 | Commit: [680e60c68b1864596bf23d427e9f4742c6437b86 ](https://github.com/azerothcore/azerothcore-wotlk/commit/680e60c68b1864596bf23d427e9f4742c6437b86 diff --git a/doc/changelog/pendings/changes_1647137971165231200.md b/doc/changelog/pendings/changes_1647137971165231200.md deleted file mode 100644 index 86f51b9af..000000000 --- a/doc/changelog/pendings/changes_1647137971165231200.md +++ /dev/null @@ -1,7 +0,0 @@ -### Added - -- New hook for OnQuestComputeXP(). The intended use is to change the XP values for certain quests programmatically. The hook is triggered after XP calculation and before rewarding XP or gold to the player. - -### How to upgrade - -- No special changes needed. The new hook is available for use and should not interfere with any existing hooks or logic.