diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml new file mode 100644 index 000000000..9221efed1 --- /dev/null +++ b/.github/workflows/add-to-project.yml @@ -0,0 +1,106 @@ +name: Auto Assign to Project(s) + +on: + issues: + types: [opened, labeled] + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + assign_one_project: + runs-on: ubuntu-latest + name: Assign to One Project + steps: + + - name: Assign issues with `ChromieCraft Generic` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, 'ChromieCraft Generic') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/20' + + - name: Assign issues with `1-19` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '1-19') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/14' + + - name: Assign issues with `20-29` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '20-29') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/17' + + - name: Assign issues with `30-39` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '30-39') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/23' + + - name: Assign issues with `40-49` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '40-49') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/24' + + - name: Assign issues with `50-59` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '50-59') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/25' + + - name: Assign issues with `60` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '60') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/22' + + - name: Assign issues with `61-64` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '61-64') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/32' + + - name: Assign issues with `65-69` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '65-69') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/36' + + - name: Assign issues with `70` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '70') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/26' + + - name: Assign issues with `71-74` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '71-74') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/33' + + - name: Assign issues with `75-79` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '75-79') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/37' + + - name: Assign issues with `80` label to their project + uses: srggrs/assign-one-project-github-action@1.2.1 + if: | + contains(github.event.issue.labels.*.name, '80') + with: + project: 'https://github.com/azerothcore/azerothcore-wotlk/projects/38' + diff --git a/data/sql/updates/db_world/2022_10_26_01.sql b/data/sql/updates/db_world/2022_10_26_01.sql new file mode 100644 index 000000000..7f9d3844e --- /dev/null +++ b/data/sql/updates/db_world/2022_10_26_01.sql @@ -0,0 +1,6 @@ +-- DB update 2022_10_26_00 -> 2022_10_26_01 +-- +DELETE FROM `spell_proc_event` WHERE `entry` IN (64349,64350); +INSERT INTO `spell_proc_event` VALUES +(64349,0,0,0,0,0,0,0,0,0,0,60000), +(64350,0,0,0,0,0,0,0,0,0,0,60000); diff --git a/data/sql/updates/db_world/2022_10_28_00.sql b/data/sql/updates/db_world/2022_10_28_00.sql new file mode 100644 index 000000000..4ccf51b87 --- /dev/null +++ b/data/sql/updates/db_world/2022_10_28_00.sql @@ -0,0 +1,8 @@ +-- DB update 2022_10_26_01 -> 2022_10_28_00 +-- + +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|256 WHERE entry IN ( +15517, -- Ouro +15275, -- Emperor Vek'nilash +15276); -- Emperor Vek'lor + diff --git a/data/sql/updates/db_world/2022_10_29_00.sql b/data/sql/updates/db_world/2022_10_29_00.sql new file mode 100644 index 000000000..9d8a2d0d4 --- /dev/null +++ b/data/sql/updates/db_world/2022_10_29_00.sql @@ -0,0 +1,3 @@ +-- DB update 2022_10_28_00 -> 2022_10_29_00 +-- +UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask`|33554432 WHERE `entry` = 15276; diff --git a/data/sql/updates/db_world/2022_10_29_01.sql b/data/sql/updates/db_world/2022_10_29_01.sql new file mode 100644 index 000000000..a2657c85e --- /dev/null +++ b/data/sql/updates/db_world/2022_10_29_01.sql @@ -0,0 +1,127 @@ +-- DB update 2022_10_29_00 -> 2022_10_29_01 +-- +ALTER TABLE `areatrigger_tavern` ADD COLUMN `faction` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `name`; + +SET @FACTION_ALLIANCE := 2; +SET @FACTION_HORDE := 4; +SET @FACTION_BOTH := 6; + +UPDATE `areatrigger_tavern` SET `faction` = @FACTION_ALLIANCE WHERE `id` IN ( +71, +562, +682, +707, +708, +709, +710, +712, +713, +715, +716, +717, +1024, +1042, +2266, +2786, +4090, +4240, +4241, +4337, +4374, +4376, +4377, +4381, +4383, +4499, +4961, +4964, +4965, +4966, +4993, +4528, +4558, +4753, +4756, +4769, +4867, +5182); + +UPDATE `areatrigger_tavern` SET `faction` = @FACTION_HORDE WHERE `id` IN ( +178, +719, +720, +721, +722, +742, +843, +844, +862, +982, +1022, +1025, +1606, +1646, +2267, +2286, +2610, +3547, +3690, +3886, +4108, +4109, +4265, +4336, +4373, +4375, +4378, +4380, +4486, +4494, +4526, +5323, +5360, +4967, +4970, +4979, +4868, +4910, +5045, +4861, +4775, +4755, +4595); + +UPDATE `areatrigger_tavern` SET `faction` = @FACTION_BOTH WHERE `id` IN ( +98, +743, +1023, +2287, +3985, +4058, +4300, +4382, +4498, +4521, +4555, +4577, +5183, +5200, +5204, +5217, +5227, +5314, +5315, +5316, +5317, +5327, +5062, +5164, +5030, +4975, +4976, +4977, +4607, +4608, +4640, +4714, +4847); diff --git a/data/sql/updates/db_world/2022_10_29_02.sql b/data/sql/updates/db_world/2022_10_29_02.sql new file mode 100644 index 000000000..02b6b78a6 --- /dev/null +++ b/data/sql/updates/db_world/2022_10_29_02.sql @@ -0,0 +1,3 @@ +-- DB update 2022_10_29_01 -> 2022_10_29_02 +-- +DELETE FROM `spell_proc_event` WHERE `entry`=46916; diff --git a/data/sql/updates/db_world/2022_10_29_03.sql b/data/sql/updates/db_world/2022_10_29_03.sql new file mode 100644 index 000000000..a6552609f --- /dev/null +++ b/data/sql/updates/db_world/2022_10_29_03.sql @@ -0,0 +1,10 @@ +-- DB update 2022_10_29_02 -> 2022_10_29_03 +-- +-- Lava Spawn (12265) +DELETE FROM `creature_text` WHERE `CreatureID`=12265; +INSERT INTO `creature_text` (`CreatureID`, `Text`, `Type`, `Probability`, `BroadcastTextId`, `comment`) VALUES +(12265, '%s splits into two new Lava Spawns!', 16, 100, 7570, 'Lava Spawn'); + +UPDATE `creature_template` SET `AiName`='', `ScriptName`='npc_lava_spawn' WHERE `entry`=12265; + +DELETE FROM `smart_scripts` WHERE `entryorguid`=12265 AND `source_type`=0; diff --git a/data/sql/updates/db_world/2022_10_29_04.sql b/data/sql/updates/db_world/2022_10_29_04.sql new file mode 100644 index 000000000..9f6732356 --- /dev/null +++ b/data/sql/updates/db_world/2022_10_29_04.sql @@ -0,0 +1,9 @@ +-- DB update 2022_10_29_03 -> 2022_10_29_04 +-- +DELETE FROM `creature` WHERE `guid`=91799; +INSERT INTO `creature` (`guid`, `id1`, `map`, `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 +(91799,15353,0,1,1,1,-4918.64,-983.141,501.538,2.43867,300,0,0,1,0,0,0,0,0,'',0); + +DELETE FROM `game_event_creature` WHERE `guid`=91799; +INSERT INTO `game_event_creature` VALUES +(12,91799); diff --git a/data/sql/updates/db_world/2022_10_30_00.sql b/data/sql/updates/db_world/2022_10_30_00.sql new file mode 100644 index 000000000..eca38e9ac --- /dev/null +++ b/data/sql/updates/db_world/2022_10_30_00.sql @@ -0,0 +1,3 @@ +-- DB update 2022_10_29_04 -> 2022_10_30_00 +-- +UPDATE `creature_loot_template` SET `Chance`=100 WHERE `Entry` IN (20798, 19298) AND `Item` IN (29590, 29588); diff --git a/data/sql/updates/db_world/2022_10_30_01.sql b/data/sql/updates/db_world/2022_10_30_01.sql new file mode 100644 index 000000000..faa0b4d9e --- /dev/null +++ b/data/sql/updates/db_world/2022_10_30_01.sql @@ -0,0 +1,35 @@ +-- DB update 2022_10_30_00 -> 2022_10_30_01 +ALTER TABLE `creature` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `creature_equip_template` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `creature_questitem` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `creature_template` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `creature_template_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `creature_template_resistance` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `creature_template_spell` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `gameobject` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `gameobject_questitem` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `gameobject_template` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `gameobject_template_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `gossip_menu_option` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `item_set_names` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `item_set_names_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `item_template` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `item_template_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `lfg_dungeon_template` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `npc_text` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `npc_vendor` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `page_text` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `page_text_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `points_of_interest_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_details` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_greeting` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_greeting_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_offer_reward` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_offer_reward_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_poi` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_poi_points` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_request_items` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_request_items_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_template` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `quest_template_locale` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; +ALTER TABLE `spell_target_position` CHANGE COLUMN `VerifiedBuild` `VerifiedBuild` MEDIUMINT NULL DEFAULT NULL; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index aaf601eea..2654f5d10 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1139,8 +1139,6 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, u break; } - LoadCreaturesAddon(); - uint32 displayID = GetNativeDisplayId(); if (sObjectMgr->GetCreatureModelRandomGender(&displayID) && !IsTotem()) // Cancel load if no model defined or if totem { @@ -1148,6 +1146,8 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, u SetNativeDisplayId(displayID); } + LoadCreaturesAddon(); + //! Need to be called after LoadCreaturesAddon - MOVEMENTFLAG_HOVER is set there m_positionZ += GetHoverHeight(); @@ -2032,11 +2032,15 @@ void Creature::Respawn(bool force) setDeathState(JUST_RESPAWNED); // MDic - Acidmanifesto - uint32 displayID = GetNativeDisplayId(); - if (sObjectMgr->GetCreatureModelRandomGender(&displayID)) // Cancel load if no model defined + // Do not override transform auras + if (GetAuraEffectsByType(SPELL_AURA_TRANSFORM).empty()) { - SetDisplayId(displayID); - SetNativeDisplayId(displayID); + uint32 displayID = GetNativeDisplayId(); + if (sObjectMgr->GetCreatureModelRandomGender(&displayID)) // Cancel load if no model defined + { + SetDisplayId(displayID); + SetNativeDisplayId(displayID); + } } GetMotionMaster()->InitDefault(); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 7a763cef6..d2cbc7e12 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -370,11 +370,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const // 0x08000000 if (unit->m_movementInfo.GetMovementFlags() & MOVEMENTFLAG_SPLINE_ENABLED) { - const G3D::Vector3* p = &unit->movespline->_Spline().getPoints(true)[0]; - if (unit->movespline->_Spline().getPoints(true).empty() || (!unit->movespline->_Spline().getPoints(true).empty() && !p)) - const_cast(unit)->DisableSpline(); - else - Movement::PacketBuilder::WriteCreate(*unit->movespline, *data); + Movement::PacketBuilder::WriteCreate(*unit->movespline, *data); } } else diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 3c3c5bb8b..99aa55cc3 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1052,7 +1052,14 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) uint32 creature_ID = (petType == HUNTER_PET) ? 1 : cinfo->Entry; - SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); + if (petType == HUNTER_PET) + { + SetMeleeDamageSchool(SPELL_SCHOOL_NORMAL); + } + else + { + SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); + } SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50)); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a5f0345c8..551cde79a 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -13318,14 +13318,21 @@ uint32 Player::CalculateTalentsPoints() const { uint32 base_talent = getLevel() < 10 ? 0 : getLevel() - 9; + uint32 talentPointsForLevel = 0; if (getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609) - return uint32(base_talent * sWorld->getRate(RATE_TALENT)); - - uint32 talentPointsForLevel = getLevel() < 56 ? 0 : getLevel() - 55; - talentPointsForLevel += m_questRewardTalentCount; - - if (talentPointsForLevel > base_talent) + { talentPointsForLevel = base_talent; + } + else + { + talentPointsForLevel = getLevel() < 56 ? 0 : getLevel() - 55; + talentPointsForLevel += m_questRewardTalentCount; + + if (talentPointsForLevel > base_talent) + { + talentPointsForLevel = base_talent; + } + } talentPointsForLevel += m_extraBonusTalentCount; return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT)); @@ -13623,16 +13630,23 @@ void Player::CompletedAchievement(AchievementEntry const* entry) m_achievementMgr->CompletedAchievement(entry); } -void Player::LearnTalent(uint32 talentId, uint32 talentRank) +void Player::LearnTalent(uint32 talentId, uint32 talentRank, bool command /*= false*/) { uint32 CurTalentPoints = GetFreeTalentPoints(); - // xinef: check basic data - if (CurTalentPoints == 0) - return; + if (!command) + { + // xinef: check basic data + if (!CurTalentPoints) + { + return; + } - if (talentRank >= MAX_TALENT_RANK) - return; + if (talentRank >= MAX_TALENT_RANK) + { + return; + } + } TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); if (!talentInfo) @@ -13661,10 +13675,15 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) if (currentTalentRank >= talentRank + 1) return; - // xinef: check if we have enough free talent points uint32 talentPointsChange = (talentRank - currentTalentRank + 1); - if (CurTalentPoints < talentPointsChange) - return; + if (!command) + { + // xinef: check if we have enough free talent points + if (CurTalentPoints < talentPointsChange) + { + return; + } + } // xinef: check if talent deponds on another talent if (talentInfo->DependsOn > 0) @@ -13686,23 +13705,26 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) return; } - // xinef: check amount of points spent in current talent tree - // xinef: be smart and quick - uint32 spentPoints = 0; - if (talentInfo->Row > 0) + if (!command) { - const PlayerTalentMap& talentMap = GetTalentMap(); - for (PlayerTalentMap::const_iterator itr = talentMap.begin(); itr != talentMap.end(); ++itr) - if (TalentSpellPos const* talentPos = GetTalentSpellPos(itr->first)) - if (TalentEntry const* itrTalentInfo = sTalentStore.LookupEntry(talentPos->talent_id)) - if (itrTalentInfo->TalentTab == talentInfo->TalentTab) - if (itr->second->State != PLAYERSPELL_REMOVED && itr->second->IsInSpec(GetActiveSpec())) // pussywizard - spentPoints += talentPos->rank + 1; - } + // xinef: check amount of points spent in current talent tree + // xinef: be smart and quick + uint32 spentPoints = 0; + if (talentInfo->Row > 0) + { + const PlayerTalentMap& talentMap = GetTalentMap(); + for (PlayerTalentMap::const_iterator itr = talentMap.begin(); itr != talentMap.end(); ++itr) + if (TalentSpellPos const* talentPos = GetTalentSpellPos(itr->first)) + if (TalentEntry const* itrTalentInfo = sTalentStore.LookupEntry(talentPos->talent_id)) + if (itrTalentInfo->TalentTab == talentInfo->TalentTab) + if (itr->second->State != PLAYERSPELL_REMOVED && itr->second->IsInSpec(GetActiveSpec())) // pussywizard + spentPoints += talentPos->rank + 1; + } - // xinef: we do not have enough talent points to add talent of this tier - if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK)) - return; + // xinef: we do not have enough talent points to add talent of this tier + if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK)) + return; + } // xinef: hacking attempt, tries to learn unknown rank uint32 spellId = talentInfo->RankID[talentRank]; @@ -13735,7 +13757,11 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) // xinef: update free talent points count m_usedTalentCount += talentPointsChange; - SetFreeTalentPoints(CurTalentPoints - talentPointsChange); + + if (!command) + { + SetFreeTalentPoints(CurTalentPoints - talentPointsChange); + } sScriptMgr->OnPlayerLearnTalents(this, talentId, talentRank, spellId); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 45ea2ed5e..9cedd098d 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1677,7 +1677,7 @@ public: void BuildPlayerTalentsInfoData(WorldPacket* data); void BuildPetTalentsInfoData(WorldPacket* data); void SendTalentsInfoData(bool pet); - void LearnTalent(uint32 talentId, uint32 talentRank); + void LearnTalent(uint32 talentId, uint32 talentRank, bool command = false); void LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank); bool addTalent(uint32 spellId, uint8 addSpecMask, uint8 oldTalentRank); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 4ee9b0e90..3176865b0 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -124,7 +124,8 @@ DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo) : DamageInfo(DamageInfo(dm DamageInfo::DamageInfo(DamageInfo const& dmg1, DamageInfo const& dmg2) : m_attacker(dmg1.m_attacker), m_victim(dmg1.m_victim), m_damage(dmg1.m_damage + dmg2.m_damage), m_spellInfo(dmg1.m_spellInfo), m_schoolMask(SpellSchoolMask(dmg1.m_schoolMask | dmg2.m_schoolMask)), - m_damageType(dmg1.m_damageType), m_attackType(dmg1.m_attackType), m_absorb(dmg1.m_absorb + dmg2.m_absorb), m_resist(dmg1.m_resist + dmg2.m_resist), m_block(dmg1.m_block) + m_damageType(dmg1.m_damageType), m_attackType(dmg1.m_attackType), m_absorb(dmg1.m_absorb + dmg2.m_absorb), m_resist(dmg1.m_resist + dmg2.m_resist), m_block(dmg1.m_block), + m_cleanDamage(dmg1.m_cleanDamage + dmg1.m_cleanDamage) { } @@ -915,7 +916,9 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage } if (attacker && shareDamageTarget->GetTypeId() == TYPEID_PLAYER) - attacker->SendSpellNonMeleeDamageLog(shareDamageTarget, spell, shareDamage, damageSchoolMask, shareAbsorb, shareResist, damagetype == DIRECT_DAMAGE, 0, false); + { + attacker->SendSpellNonMeleeDamageLog(shareDamageTarget, spell, shareDamage, damageSchoolMask, shareAbsorb, shareResist, damagetype == DIRECT_DAMAGE, 0, false, true); + } Unit::DealDamage(attacker, shareDamageTarget, shareDamage, cleanDamage, NODAMAGE, damageSchoolMask, spellProto, false, false, damageSpell); } @@ -2359,7 +2362,9 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted, nullptr, -1, nullptr, &splittedDmgInfo); if (attacker) - attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo(), splitted, schoolMask, splitted_absorb, splitted_resist, false, 0, false); + { + attacker->SendSpellNonMeleeDamageLog(caster, (*itr)->GetSpellInfo(), splitted, schoolMask, splitted_absorb, splitted_resist, false, 0, false, true); + } CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); Unit::DealDamage(attacker, caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*itr)->GetSpellInfo(), false); @@ -2430,7 +2435,9 @@ void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited) caster->ProcDamageAndSpellFor(true, attacker, procVictim, procEx, BASE_ATTACK, spellInfo, splitted); if (attacker) - attacker->SendSpellNonMeleeDamageLog(caster, splitSpellInfo, splitted, splitSchoolMask, splitted_absorb, splitted_resist, false, 0, false); + { + attacker->SendSpellNonMeleeDamageLog(caster, splitSpellInfo, splitted, splitSchoolMask, splitted_absorb, splitted_resist, false, 0, false, true); + } CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); Unit::DealDamage(attacker, caster, splitted, &cleanDamage, DIRECT_DAMAGE, splitSchoolMask, splitSpellInfo, false); @@ -3148,20 +3155,18 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo // xinef: if from behind or spell requires cast from behind if (!victim->HasInArc(M_PI, this)) { - if (!victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)) + if (!victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION) || spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET)) { // Can`t dodge from behind in PvP (but its possible in PvE) if (victim->GetTypeId() == TYPEID_PLAYER) + { canDodge = false; + } + // Can`t parry or block canParry = false; canBlock = false; } - else // Only deterrence as of 3.3.5 - { - if (spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET)) - canParry = false; - } } // Check creatures flags_extra for disable parry @@ -6219,11 +6224,31 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log) data << uint8 (log->unused); // unused data << uint32(log->blocked); // blocked data << uint32(log->HitInfo); - data << uint8 (0); // flag to use extend data + data << uint32(log->HitInfo); + data << uint8(log->HitInfo & (SPELL_HIT_TYPE_CRIT_DEBUG | SPELL_HIT_TYPE_HIT_DEBUG | SPELL_HIT_TYPE_ATTACK_TABLE_DEBUG)); + //if (log->HitInfo & SPELL_HIT_TYPE_CRIT_DEBUG) + //{ + // data << float(log->CritRoll); + // data << float(log->CritNeeded); + //} + //if (log->HitInfo & SPELL_HIT_TYPE_HIT_DEBUG) + //{ + // data << float(log->HitRoll); + // data << float(log->HitNeeded); + //} + //if (log->HitInfo & SPELL_HIT_TYPE_ATTACK_TABLE_DEBUG) + //{ + // data << float(log->MissChance); + // data << float(log->DodgeChance); + // data << float(log->ParryChance); + // data << float(log->BlockChance); + // data << float(log->GlanceChance); + // data << float(log->CrushChance); + //} SendMessageToSet(&data, true); } -void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit) +void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit /*= false*/, bool Split /*= false*/) { SpellNonMeleeDamage log(this, target, spellInfo, damageSchoolMask); log.damage = Damage; @@ -6231,9 +6256,15 @@ void Unit::SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, log.resist = Resist; log.physicalLog = PhysicalDamage; log.blocked = Blocked; - log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6; + log.HitInfo = 0; if (CriticalHit) + { log.HitInfo |= SPELL_HIT_TYPE_CRIT; + } + if (Split) + { + log.HitInfo |= SPELL_HIT_TYPE_SPLIT; + } SendSpellNonMeleeDamageLog(&log); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 036d70f1c..639f6727f 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1746,7 +1746,7 @@ public: void SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount); void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage* log); void SendSpellNonMeleeReflectLog(SpellNonMeleeDamage* log, Unit* attacker); - void SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false); + void SendSpellNonMeleeDamageLog(Unit* target, SpellInfo const* spellInfo, uint32 Damage, SpellSchoolMask damageSchoolMask, uint32 AbsorbedDamage, uint32 Resist, bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false, bool Split = false); void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo); void SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo); void SendSpellDamageResist(Unit* target, uint32 spellId); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 20fab220f..13aa9f489 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -6320,7 +6320,7 @@ void ObjectMgr::LoadTavernAreaTriggers() _tavernAreaTriggerStore.clear(); // need for reload case - QueryResult result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern"); + QueryResult result = WorldDatabase.Query("SELECT id, faction FROM areatrigger_tavern"); if (!result) { @@ -6346,7 +6346,9 @@ void ObjectMgr::LoadTavernAreaTriggers() continue; } - _tavernAreaTriggerStore.insert(Trigger_ID); + uint32 faction = fields[1].Get(); + + _tavernAreaTriggerStore.emplace(Trigger_ID, faction); } while (result->NextRow()); LOG_INFO("server.loading", ">> Loaded {} Tavern Triggers in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index a5e36b690..c592fecbb 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -840,9 +840,15 @@ public: return 0; } - [[nodiscard]] bool IsTavernAreaTrigger(uint32 Trigger_ID) const + [[nodiscard]] bool IsTavernAreaTrigger(uint32 triggerID, uint32 faction) const { - return _tavernAreaTriggerStore.find(Trigger_ID) != _tavernAreaTriggerStore.end(); + auto itr = _tavernAreaTriggerStore.find(triggerID); + if (itr != _tavernAreaTriggerStore.end()) + { + return (itr->second & faction) != 0; + } + + return false; } [[nodiscard]] GossipText const* GetGossipText(uint32 Text_ID) const; @@ -1449,7 +1455,7 @@ private: typedef std::unordered_map GossipTextContainer; typedef std::unordered_map QuestAreaTriggerContainer; - typedef std::set TavernAreaTriggerContainer; + typedef std::unordered_map TavernAreaTriggerContainer; QuestAreaTriggerContainer _questAreaTriggerStore; TavernAreaTriggerContainer _tavernAreaTriggerStore; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 35d9dc542..33d6a5b85 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -747,7 +747,8 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data) return; } - bool isTavernAreatrigger = sObjectMgr->IsTavernAreaTrigger(triggerId); + uint32 teamFaction = player->GetTeamId(true) == TEAM_ALLIANCE ? FACTION_MASK_ALLIANCE : FACTION_MASK_HORDE; + bool isTavernAreatrigger = sObjectMgr->IsTavernAreaTrigger(triggerId, teamFaction); if (!player->IsInAreaTriggerRadius(atEntry, isTavernAreatrigger ? 5.f : 0.f)) { LOG_DEBUG("network", "HandleAreaTriggerOpcode: Player {} ({}) too far (trigger map: {} player map: {}), ignore Area Trigger ID: {}", diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index 30b5c8dcf..591970330 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -93,7 +93,7 @@ bool ChaseMovementGenerator::DoUpdate(T* owner, uint32 time_diff) { if (Creature* cOwner2 = owner->ToCreature()) { - cOwner2->SetCannotReachTarget(i_path && i_path->GetPathType() & PATHFIND_INCOMPLETE ? target->GetGUID() : ObjectGuid::Empty); + cOwner2->SetCannotReachTarget(); } i_recalculateTravel = false; diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp index 65ad59ad1..27fb52288 100644 --- a/src/server/game/Movement/Spline/MoveSpline.cpp +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -80,7 +80,7 @@ namespace Movement void MoveSpline::computeFallElevation(float& el) const { - float z_now = spline.getPoint(spline.first(), false).z - Movement::computeFallElevation(MSToSec(time_passed), false); + float z_now = spline.getPoint(spline.first()).z - Movement::computeFallElevation(MSToSec(time_passed), false); float final_z = FinalDestination().z; el = std::max(z_now, final_z); } @@ -96,7 +96,7 @@ namespace Movement float start_elevation; inline int32 operator()(Spline& s, int32 i) { - return Movement::computeFallTime(start_elevation - s.getPoint(i + 1, false).z, false) * 1000.f; + return Movement::computeFallTime(start_elevation - s.getPoint(i + 1).z, false) * 1000.f; } }; @@ -138,7 +138,7 @@ namespace Movement // init spline timestamps if (splineflags.falling) { - FallInitializer init(spline.getPoint(spline.first(), false).z); + FallInitializer init(spline.getPoint(spline.first()).z); spline.initLengths(init); } else diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h index 1c0931abf..d713ba9f3 100644 --- a/src/server/game/Movement/Spline/MoveSpline.h +++ b/src/server/game/Movement/Spline/MoveSpline.h @@ -71,7 +71,7 @@ namespace Movement void init_spline(const MoveSplineInitArgs& args); protected: - [[nodiscard]] const MySpline::ControlArray& getPath(bool visual) const { return spline.getPoints(visual); } + [[nodiscard]] const MySpline::ControlArray& getPath() const { return spline.getPoints(); } void computeParabolicElevation(float& el) const; void computeFallElevation(float& el) const; @@ -117,8 +117,8 @@ namespace Movement [[nodiscard]] bool isCyclic() const { return splineflags.cyclic; } [[nodiscard]] bool isFalling() const { return splineflags.falling; } [[nodiscard]] bool isWalking() const { return splineflags.walkmode; } - [[nodiscard]] Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last(), false) : Vector3(); } - [[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1, false) : Vector3(); } + [[nodiscard]] Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3(); } + [[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1) : Vector3(); } [[nodiscard]] int32 currentPathIdx() const; [[nodiscard]] bool HasAnimation() const { return splineflags.animation; } diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp index 3a6084e21..faf6cd203 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.cpp +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -135,11 +135,6 @@ namespace Movement data << int8(unit->GetTransSeat()); } - Movement::SplineBase::ControlArray* visualPoints = const_cast(move_spline._Spline().allocateVisualPoints()); - visualPoints->resize(move_spline._Spline().getPointCount()); - // Xinef: Apply hover in creature movement packet - std::copy(move_spline._Spline().getPoints(false).begin(), move_spline._Spline().getPoints(false).end(), visualPoints->begin()); - PacketBuilder::WriteMonsterMove(move_spline, data); unit->SendMessageToSet(&data, true); diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp index a624b0766..b7ccda009 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -45,7 +45,7 @@ namespace Movement MoveSplineFlag splineflags = move_spline.splineflags; data << uint8(0); // sets/unsets MOVEMENTFLAG2_UNK7 (0x40) - data << move_spline.spline.getPoint(move_spline.spline.first(), true); + data << move_spline.spline.getPoint(move_spline.spline.first()); data << move_spline.GetId(); switch (splineflags & MoveSplineFlag::Mask_Final_Facing) @@ -99,7 +99,7 @@ namespace Movement void WriteLinearPath(const Spline& spline, ByteBuffer& data) { uint32 last_idx = spline.getPointCount() - 3; - const Vector3* real_path = &spline.getPoint(1, true); + const Vector3* real_path = &spline.getPoint(1); data << last_idx; data << real_path[last_idx]; // destination @@ -120,7 +120,7 @@ namespace Movement { uint32 count = spline.getPointCount() - 3; data << count; - data.append(&spline.getPoint(2, true), count); + data.append(&spline.getPoint(2), count); } void WriteCatmullRomCyclicPath(const Spline& spline, ByteBuffer& data, bool flying) @@ -129,12 +129,12 @@ namespace Movement data << uint32(count + 1); if (flying) { - data << spline.getPoint(1, true); // fake point, client will erase it from the spline after first cycle done - data.append(&spline.getPoint(2, true), count); + data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done + data.append(&spline.getPoint(2), count); } else { - data.append(&spline.getPoint(2, true), count); + data.append(&spline.getPoint(2), count); data << Vector3::zero(); //Xinef: fake point } } @@ -189,9 +189,9 @@ namespace Movement data << move_spline.vertical_acceleration; // added in 3.1 data << move_spline.effect_start_time; // added in 3.1 - uint32 nodes = move_spline.getPath(true).size(); + uint32 nodes = move_spline.getPath().size(); data << nodes; - data.append(&move_spline.getPath(true)[0], nodes); + data.append(&move_spline.getPath()[0], nodes); data << uint8(move_spline.spline.mode()); // added in 3.1 data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination()); } diff --git a/src/server/game/Movement/Spline/Spline.cpp b/src/server/game/Movement/Spline/Spline.cpp index 15169f63c..601951a20 100644 --- a/src/server/game/Movement/Spline/Spline.cpp +++ b/src/server/game/Movement/Spline/Spline.cpp @@ -286,7 +286,6 @@ namespace Movement index_lo = 0; index_hi = 0; points.clear(); - pointsVisual.clear(); } std::string SplineBase::ToString() const diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h index c0ea4899c..98896d931 100644 --- a/src/server/game/Movement/Spline/Spline.h +++ b/src/server/game/Movement/Spline/Spline.h @@ -42,7 +42,6 @@ namespace Movement protected: ControlArray points; - ControlArray pointsVisual; index_type index_lo{0}; index_type index_hi{0}; @@ -112,10 +111,9 @@ namespace Movement [[nodiscard]] bool isCyclic() const { return cyclic;} // Xinef: DO NOT USE EXCEPT FOR SPLINE INITIALIZATION!!!!!! - [[nodiscard]] const ControlArray* allocateVisualPoints() const { return &pointsVisual; } - [[nodiscard]] const ControlArray& getPoints(bool visual) const { return visual ? pointsVisual : points;} + [[nodiscard]] const ControlArray& getPoints() const { return points;} [[nodiscard]] index_type getPointCount() const { return points.size();} - [[nodiscard]] const Vector3& getPoint(index_type i, bool visual) const { return visual ? pointsVisual[i] : points[i];} + [[nodiscard]] const Vector3& getPoint(index_type i) const { return points[i];} /** Initializes spline. Don't call other methods while spline not initialized. */ void init_spline(const Vector3* controls, index_type count, EvaluationMode m); diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index e28a7c437..d14ddb3c3 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -131,6 +131,16 @@ Quest::Quest(Field* questRecord) } _eventIdForQuest = 0; + + if (sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT)) + { + Flags &= ~QUEST_FLAGS_AUTO_ACCEPT; + } + + if (sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE)) + { + Flags &= ~QUEST_FLAGS_AUTOCOMPLETE; + } } void Quest::LoadQuestDetails(Field* fields) @@ -180,8 +190,10 @@ void Quest::LoadQuestTemplateAddon(Field* fields) RewardMailSenderEntry = fields[16].Get(); SpecialFlags = fields[17].Get(); - if (SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) + if ((SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) && !sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT)) + { Flags |= QUEST_FLAGS_AUTO_ACCEPT; + } } uint32 Quest::XPValue(uint8 playerLevel) const @@ -253,12 +265,12 @@ uint32 Quest::GetRewMoneyMaxLevel() const bool Quest::IsAutoAccept() const { - return sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT) ? false : (Flags & QUEST_FLAGS_AUTO_ACCEPT); + return HasFlag(QUEST_FLAGS_AUTO_ACCEPT); } bool Quest::IsAutoComplete() const { - return sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_COMPLETE) ? false : HasFlag(QUEST_FLAGS_AUTOCOMPLETE); + return HasFlag(QUEST_FLAGS_AUTOCOMPLETE); } bool Quest::IsRaidQuest(Difficulty difficulty) const diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index e13872796..f2c4a25e8 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -2923,15 +2923,18 @@ void DynObjAura::FillTargetMap(std::map& targets, Unit* /*caster*/ for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) { - // xinef: check z level and los dependence Unit* target = *itr; - float zLevel = GetDynobjOwner()->GetPositionZ(); - if (target->GetPositionZ() + 3.0f < zLevel || target->GetPositionZ() - 5.0f > zLevel) + + Optional collisionHeight = { }; + if (Unit* dynObjCaster = GetDynobjOwner()->GetCaster()) { - if (!spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !target->IsWithinLOSInMap(GetDynobjOwner())) - { - continue; - } + collisionHeight = dynObjCaster->GetCollisionHeight(); + } + + if (!spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && + !target->IsWithinLOSInMap(GetDynobjOwner(), VMAP::ModelIgnoreFlags::Nothing, LINEOFSIGHT_ALL_CHECKS, collisionHeight)) + { + continue; } std::map::iterator existing = targets.find(*itr); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 5accfd393..d8a2b4c8d 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3974,6 +3974,20 @@ void Spell::_cast(bool skipCheck) if (modOwner) modOwner->SetSpellModTakingSpell(this, true); + bool resetAttackTimers = IsAutoActionResetSpell() && !m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS); + if (resetAttackTimers) + { + Unit::AuraEffectList const& vIgnoreReset = m_caster->GetAuraEffectsByType(SPELL_AURA_IGNORE_MELEE_RESET); + for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i) + { + if ((*i)->IsAffectedOnSpell(m_spellInfo)) + { + resetAttackTimers = false; + break; + } + } + } + // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells if ((m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled())/* xinef: we dont need this || m_spellInfo->Id == 14157*/) { @@ -4006,38 +4020,23 @@ void Spell::_cast(bool skipCheck) handle_immediate(); } - if (IsAutoActionResetSpell()) + if (resetAttackTimers) { - bool found = false; - Unit::AuraEffectList const& vIgnoreReset = m_caster->GetAuraEffectsByType(SPELL_AURA_IGNORE_MELEE_RESET); - for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i) + if (m_casttime == 0 && m_spellInfo->CalcCastTime()) { - if ((*i)->IsAffectedOnSpell(m_spellInfo)) - { - found = true; - break; - } + resetAttackTimers = false; } - if (!found && !m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)) + if (resetAttackTimers) { - bool allow = true; - if (m_casttime == 0 && m_spellInfo->CalcCastTime()) + m_caster->resetAttackTimer(BASE_ATTACK); + + if (m_caster->haveOffhandWeapon()) { - allow = false; + m_caster->resetAttackTimer(OFF_ATTACK); } - if (allow) - { - m_caster->resetAttackTimer(BASE_ATTACK); - - if (m_caster->haveOffhandWeapon()) - { - m_caster->resetAttackTimer(OFF_ATTACK); - } - - m_caster->resetAttackTimer(RANGED_ATTACK); - } + m_caster->resetAttackTimer(RANGED_ATTACK); } } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 8281ec106..5ae18f79c 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -319,7 +319,7 @@ void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/) Unit::DealDamageMods(unitTarget, envDamage, &absorb); damage = envDamage; - m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false); + m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0); } } diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index f5058dac5..a0c37d441 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -4421,6 +4421,12 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].MiscValueB = 64; }); + // Uppercut + ApplySpellFix({ 26007 }, [](SpellInfo* spellInfo) + { + spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS; + }); + for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { SpellInfo* spellInfo = mSpellInfoMap[i]; diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index 6ea772dd4..c997afab6 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -195,9 +195,12 @@ public: if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo)) continue; - player->LearnTalent(talentInfo->TalentID, rankId); + player->LearnTalent(talentInfo->TalentID, rankId, true); } + player->SetFreeTalentPoints(0); + player->SendTalentsInfoData(false); + handler->SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); return true; } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.cpp index 7e215ad55..ea6eb193e 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.cpp @@ -19,6 +19,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" +#include "TaskScheduler.h" enum Texts { @@ -34,6 +35,13 @@ enum Spells SPELL_FULL_HEALTH = 17683, SPELL_FIRE_NOVA_VISUAL = 19823, SPELL_PLAY_DEAD_PACIFY = 19951, // Server side spell + + // Lava Spawn + SPELL_FIREBALL = 19391, + SPELL_SPLIT_1 = 19569, + SPELL_SPLIT_2 = 19570, + + TALK_0 = 0 }; // Serrated Bites timer may be wrong @@ -207,10 +215,60 @@ public: } }; +struct npc_lava_spawn : public ScriptedAI +{ + npc_lava_spawn(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() override + { + _scheduler.CancelAll(); + } + + void EnterCombat(Unit* /*who*/) override + { + _scheduler.Schedule(15s, [this](TaskContext context) + { + std::list lavaSpawns; + me->GetCreatureListWithEntryInGrid(lavaSpawns, me->GetEntry(), 100.f); + if (lavaSpawns.size() < 16) + { + Talk(TALK_0); + + DoCastSelf(SPELL_SPLIT_1, true); + DoCastSelf(SPELL_SPLIT_2, true); + + me->DespawnOrUnsummon(); + } + else + { + context.Repeat(15s); + } + }); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + return; + } + + _scheduler.Update(diff); + + DoSpellAttackIfReady(SPELL_FIREBALL); + } + +private: + TaskScheduler _scheduler; +}; + void AddSC_molten_core() { // Creatures new npc_mc_core_hound(); + RegisterCreatureAI(npc_lava_spawn); // Spells new spell_mc_play_dead(); diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index c5541a403..e5e6fab05 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp @@ -452,10 +452,9 @@ struct boss_cthun : public BossAI target->m_Events.AddEventAtOffset([target, this]() { + DoCast(target, SPELL_DIGESTIVE_ACID, true); DoTeleportPlayer(target, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O); target->RemoveAurasDueToSpell(SPELL_MIND_FLAY); - //Cast digestive acid on them - DoCast(target, SPELL_DIGESTIVE_ACID, true); }, 3800ms); } @@ -546,6 +545,8 @@ struct boss_cthun : public BossAI { eye->DespawnOrUnsummon(); } + + instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_DONE); } void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override @@ -747,6 +748,8 @@ struct npc_giant_claw_tentacle : public ScriptedAI } } } + + _canAttack = false; } void JustDied(Unit* /*killer*/) override @@ -770,14 +773,17 @@ struct npc_giant_claw_tentacle : public ScriptedAI DoZoneInCombat(); _scheduler.Schedule(2s, [this](TaskContext context) - { + { DoCastVictim(SPELL_HAMSTRING); context.Repeat(10s); - }).Schedule(5s, [this](TaskContext context) - { - DoCastSelf(SPELL_THRASH); - context.Repeat(10s); - }); + }).Schedule(5s, [this](TaskContext context) + { + DoCastSelf(SPELL_THRASH); + context.Repeat(10s); + }).Schedule(3s, [this](TaskContext /*context*/) + { + _canAttack = true; + }); ScheduleMeleeCheck(); } @@ -825,6 +831,7 @@ struct npc_giant_claw_tentacle : public ScriptedAI me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); _scheduler.CancelAll(); + _canAttack = false; _scheduler.Schedule(5s, [this](TaskContext /*task*/) { @@ -851,6 +858,11 @@ struct npc_giant_claw_tentacle : public ScriptedAI ScheduleMeleeCheck(); } + + _scheduler.Schedule(3s, [this](TaskContext /*context*/) + { + _canAttack = true; + }); } void UpdateAI(uint32 diff) override @@ -861,12 +873,16 @@ struct npc_giant_claw_tentacle : public ScriptedAI _scheduler.Update(diff); - DoMeleeAttackIfReady(); + if (_canAttack) + { + DoMeleeAttackIfReady(); + } } private: TaskScheduler _scheduler; ObjectGuid _portalGUID; + bool _canAttack; }; struct npc_giant_eye_tentacle : public ScriptedAI diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp index 1355b52d1..6b8d086ac 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp @@ -112,6 +112,11 @@ struct boss_ouro : public BossAI _scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); }); } + bool CanAIAttack(Unit const* victim) const override + { + return me->IsWithinMeleeRange(victim); + } + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override { if (me->HealthBelowPctDamaged(20, damage) && !_enraged) @@ -190,7 +195,9 @@ struct boss_ouro : public BossAI void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override { if (spellInfo->Id == SPELL_SAND_BLAST && target) - me->GetThreatMgr().ModifyThreatByPercent(target, 100); + { + me->GetThreatMgr().ModifyThreatByPercent(target, -100); + } } void Emerge() @@ -202,7 +209,21 @@ struct boss_ouro : public BossAI _scheduler .Schedule(20s, GROUP_EMERGED, [this](TaskContext context) { - DoCastVictim(SPELL_SAND_BLAST); + if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, 0.0f, true)) + { + me->SetTarget(target->GetGUID()); + } + + DoCastAOE(SPELL_SAND_BLAST); + + me->m_Events.AddEventAtOffset([this]() + { + if (Unit* victim = me->GetVictim()) + { + me->SetTarget(victim->GetGUID()); + } + }, 3s); + context.Repeat(); }) .Schedule(22s, GROUP_EMERGED, [this](TaskContext context) @@ -252,11 +273,14 @@ struct boss_ouro : public BossAI void EnterEvadeMode(EvadeReason /*why*/) override { - DoCastSelf(SPELL_OURO_SUBMERGE_VISUAL); - me->DespawnOrUnsummon(1000); - instance->SetBossState(DATA_OURO, FAIL); - if (GameObject* base = me->FindNearestGameObject(GO_SANDWORM_BASE, 200.f)) - base->DespawnOrUnsummon(); + if (me->GetThreatMgr().GetThreatList().empty()) + { + DoCastSelf(SPELL_OURO_SUBMERGE_VISUAL); + me->DespawnOrUnsummon(1000); + instance->SetBossState(DATA_OURO, FAIL); + if (GameObject* base = me->FindNearestGameObject(GO_SANDWORM_BASE, 200.f)) + base->DespawnOrUnsummon(); + } } void EnterCombat(Unit* who) override diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp index f12d58ff7..75f1126b8 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp @@ -138,7 +138,7 @@ struct boss_sartura : public BossAI case EVENT_SPELL_BERSERK: if (!berserked) { - DoCastSelf(SPELL_BERSERK); + DoCastSelf(SPELL_BERSERK, true); berserked = true; } break; diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp index 324cb884c..ccc02dfbf 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp @@ -309,7 +309,7 @@ struct boss_veknilash : public boss_twinemperorsAI _scheduler .Schedule(14s, [this](TaskContext context) { - DoCastRandomTarget(SPELL_UPPERCUT, 0, me->GetMeleeReach(), true, true); + DoCastRandomTarget(SPELL_UPPERCUT, 0, me->GetMeleeReach(), true); context.Repeat(4s, 15s); }) .Schedule(12s, [this](TaskContext context) diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.cpp index f3ea97e89..b30d52c6a 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.cpp @@ -402,7 +402,8 @@ struct npc_obsidian_nullifier : public ScriptedAI for (Unit* target : _targets) { - DoCast(target, SPELL_DRAIN_MANA_NULLIFIER, true); + if (target) + DoCast(target, SPELL_DRAIN_MANA_NULLIFIER, true); } if (me->GetPowerPct(POWER_MANA) >= 100.f) diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index cddeabf53..bb6b8b9e2 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -122,7 +122,7 @@ class spell_rog_blade_flurry : public AuraScript DamageInfo* damageInfo = eventInfo.GetDamageInfo(); if (procTarget && damageInfo) { - int32 damage = damageInfo->GetDamage(); + int32 damage = damageInfo->GetUnmitigatedDamage(); CustomSpellValues values; values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage); diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index d5f253ffe..35aec6db2 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -668,7 +668,7 @@ class spell_warr_sweeping_strikes : public AuraScript } else { - int32 damage = damageInfo->GetDamage(); + int32 damage = damageInfo->GetUnmitigatedDamage(); GetTarget()->CastCustomSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK_1, &damage, 0, 0, true, nullptr, aurEff); } } diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index f8e2071b1..a5bbf57ba 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -1504,12 +1504,12 @@ enum SpellMissInfo enum SpellHitType { - SPELL_HIT_TYPE_UNK1 = 0x00001, - SPELL_HIT_TYPE_CRIT = 0x00002, - SPELL_HIT_TYPE_UNK3 = 0x00004, - SPELL_HIT_TYPE_UNK4 = 0x00008, - SPELL_HIT_TYPE_UNK5 = 0x00010, // replace caster? - SPELL_HIT_TYPE_UNK6 = 0x00020 + SPELL_HIT_TYPE_CRIT_DEBUG = 0x01, + SPELL_HIT_TYPE_CRIT = 0x02, + SPELL_HIT_TYPE_HIT_DEBUG = 0x04, + SPELL_HIT_TYPE_SPLIT = 0x08, + SPELL_HIT_TYPE_VICTIM_IS_ATTACKER = 0x10, + SPELL_HIT_TYPE_ATTACK_TABLE_DEBUG = 0x20 }; enum SpellDmgClass