diff --git a/.gitignore b/.gitignore index cc69717f..dc927cf4 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ local.properties .project .cproject .idea +_codeql_detected_source_root diff --git a/src/ZoneDifficulty.h b/src/ZoneDifficulty.h index d57d772a..9c5368f3 100644 --- a/src/ZoneDifficulty.h +++ b/src/ZoneDifficulty.h @@ -175,14 +175,15 @@ class ZoneDifficulty void MythicmodeEvent(Unit* unit, uint32 entry, uint32 key); bool HasNormalMode(int8 mode) { return (mode & MODE_NORMAL) == MODE_NORMAL; } bool HasMythicmode(int8 mode) { return (mode & MODE_HARD) == MODE_HARD; } + [[nodiscard]] bool IsInstanceMythic(uint32 instanceId) const; bool HasCompletedFullTier(uint32 category, uint32 playerGUID); - bool OverrideModeMatches(uint32 instanceId, uint32 spellId, uint32 mapId); + bool OverrideModeMatches(uint32 instanceId, uint32 modeMask); [[nodiscard]] bool CheckCompletionStatus(Creature* creature, Player* player, uint32 category) const; [[nodiscard]] bool IsValidNerfTarget(Unit* target); - [[nodiscard]] bool VectorContainsUint32(std::vector vec, uint32 element); + [[nodiscard]] bool VectorContainsUint32(const std::vector& vec, uint32 element); [[nodiscard]] bool IsMythicmodeMap(uint32 mapid); [[nodiscard]] bool ShouldNerfInDuels(Unit* target); - [[nodiscard]] bool ShouldNerfMap(uint32 mapId) { return NerfInfo.find(mapId) != NerfInfo.end(); }; + [[nodiscard]] bool ShouldNerfMap(uint32 mapId) { return NerfInfo.count(mapId) > 0; }; [[nodiscard]] int32 GetLowestMatchingPhase(uint32 mapId, uint32 phaseMask); void RewardItem(Player* player, uint8 category, uint8 itemType, uint8 counter, Creature* creature, uint32 itemEntry); void LogAndAnnounceKill(Map* map, bool isMythic); diff --git a/src/mod_zone_difficulty_handler.cpp b/src/mod_zone_difficulty_handler.cpp index c6ded0c4..02266d4b 100644 --- a/src/mod_zone_difficulty_handler.cpp +++ b/src/mod_zone_difficulty_handler.cpp @@ -26,6 +26,12 @@ ZoneDifficulty* ZoneDifficulty::instance() return &instance; } +bool ZoneDifficulty::IsInstanceMythic(uint32 instanceId) const +{ + auto it = MythicmodeInstanceData.find(instanceId); + return it != MythicmodeInstanceData.end() && it->second; +} + void ZoneDifficulty::LoadMapDifficultySettings() { if (!sZoneDifficulty->IsEnabled) @@ -167,12 +173,15 @@ void ZoneDifficulty::LoadMapDifficultySettings() { do { - if ((*result)[3].Get() > 0) + uint8 enabled = (*result)[3].Get(); + if (enabled > 0) { - sZoneDifficulty->SpellNerfOverrides[(*result)[0].Get()][(*result)[1].Get()].NerfPct = (*result)[2].Get(); - sZoneDifficulty->SpellNerfOverrides[(*result)[0].Get()][(*result)[1].Get()].ModeMask = (*result)[3].Get(); + uint32 spellId = (*result)[0].Get(); + uint32 mapId = (*result)[1].Get(); + auto& entry = sZoneDifficulty->SpellNerfOverrides[spellId][mapId]; + entry.NerfPct = (*result)[2].Get(); + entry.ModeMask = (*result)[3].Get(); } - } while (result->NextRow()); } @@ -215,7 +224,6 @@ void ZoneDifficulty::LoadMapDifficultySettings() data.RewardType = (*result)[3].Get(); sZoneDifficulty->MythicmodeLoot[MapID].push_back(data); - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: New creature for map {} with entry: {}", MapID, data.EncounterEntry); Expansion[MapID] = data.RewardType; @@ -231,7 +239,6 @@ void ZoneDifficulty::LoadMapDifficultySettings() do { sZoneDifficulty->DailyHeroicQuests.push_back((*result)[0].Get()); - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Adding daily heroic quest with id {}.", (*result)[0].Get()); } while (result->NextRow()); } else @@ -258,7 +265,6 @@ void ZoneDifficulty::LoadMapDifficultySettings() data.NormalOverride = hpModifierNormal; sZoneDifficulty->CreatureOverrides[creatureEntry] = data; - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: New creature with entry: {} has exception for hp: {}", creatureEntry, hpModifier); } } while (result->NextRow()); } @@ -299,7 +305,6 @@ void ZoneDifficulty::LoadMapDifficultySettings() { LOG_ERROR("module", "MOD-ZONE-DIFFICULTY: Unknown type for `Target`: {} in zone_difficulty_mythicmode_ai", data.Target); } - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: New creature with entry: {} has exception for hp: {}", creatureEntry, hpModifier); } } while (result->NextRow()); } @@ -308,19 +313,10 @@ void ZoneDifficulty::LoadMapDifficultySettings() LOG_ERROR("module", "MOD-ZONE-DIFFICULTY: Query failed: SELECT * FROM zone_difficulty_mythicmode_ai"); } - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Starting load of rewards."); if (QueryResult result = WorldDatabase.Query("SELECT ContentType, ItemType, Entry, Price, Enchant, EnchantSlot, Achievement, Enabled FROM zone_difficulty_mythicmode_rewards")) { - /* debug - * uint32 i = 0; - * end debug - */ do { - /* debug - * ++i; - * end debug - */ ZoneDifficultyRewardData data; uint32 contentType = (*result)[0].Get(); uint32 itemType = (*result)[1].Get(); @@ -334,17 +330,10 @@ void ZoneDifficulty::LoadMapDifficultySettings() if (enabled) { if (data.Achievement >= 0) - { sZoneDifficulty->Rewards[contentType][itemType].push_back(data); - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Loading item with entry {} has enchant {} in slot {}. contentType: {} itemType: {}", data.Entry, data.Enchant, data.EnchantSlot, contentType, itemType); - } else - { sZoneDifficulty->TierRewards[contentType] = data; - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Loading tier reward with entry {} has enchant {} in slot {}. contentType: {} itemType: {}", data.Entry, data.Enchant, data.EnchantSlot, contentType, itemType); - } } - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Total items in Rewards map: {}.", i); } while (result->NextRow()); } else @@ -365,13 +354,6 @@ void ZoneDifficulty::LoadMapDifficultySettings() void ZoneDifficulty::LoadMythicmodeInstanceData() { std::vector instanceIDs = sMapMgr->GetInstanceIDs(); - /* debugging - * for (int i = 0; i < int(instanceIDs.size()); i++) - * { - * LOG_INFO("module", "MOD-ZONE-DIFFICULTY: ZoneDifficulty::LoadMythicmodeInstanceData: id {} exists: {}:", i, instanceIDs[i]); - * } - * end debugging - */ if (QueryResult result = CharacterDatabase.Query("SELECT * FROM zone_difficulty_instance_saves")) { do @@ -388,8 +370,6 @@ void ZoneDifficulty::LoadMythicmodeInstanceData() { CharacterDatabase.Execute("DELETE FROM zone_difficulty_instance_saves WHERE InstanceID = {}", InstanceId); } - - } while (result->NextRow()); } } @@ -422,9 +402,7 @@ void ZoneDifficulty::LoadMythicmodeScoreData() uint8 Type = (*result)[1].Get(); uint32 Score = (*result)[2].Get(); - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Loading from DB for player with GUID {}: Type = {}, Score = {}", GUID, Type, Score); sZoneDifficulty->MythicmodeScore[GUID][Type] = Score; - } while (result->NextRow()); } @@ -433,16 +411,20 @@ void ZoneDifficulty::LoadMythicmodeScoreData() do { uint32 MapId = (*result)[0].Get(); - uint8 BossID = (*result)[1].Get(); + uint8 BossID = static_cast((*result)[1].Get()); uint32 PlayerGuid = (*result)[2].Get(); - // Set all BossID which aren't true to false for that mapID - if (sZoneDifficulty->Logs[PlayerGuid].find(MapId) == sZoneDifficulty->Logs[PlayerGuid].end()) + auto& playerLogs = sZoneDifficulty->Logs[PlayerGuid]; + if (playerLogs.find(MapId) == playerLogs.end()) { - for (int i = 0; i < sZoneDifficulty->EncounterCounter[MapId]; ++i) - sZoneDifficulty->Logs[PlayerGuid][MapId][i] = false; + auto encounterIt = sZoneDifficulty->EncounterCounter.find(MapId); + if (encounterIt != sZoneDifficulty->EncounterCounter.end()) + { + for (int i = 0; i < encounterIt->second; ++i) + playerLogs[MapId][i] = false; + } } - sZoneDifficulty->Logs[PlayerGuid][MapId][BossID] = true; + playerLogs[MapId][BossID] = true; } while (result->NextRow()); } } @@ -661,10 +643,7 @@ bool ZoneDifficulty::IsMythicmodeMap(uint32 mapId) if (!sZoneDifficulty->MythicmodeEnable) return false; - if (sZoneDifficulty->MythicmodeLoot.find(mapId) == sZoneDifficulty->MythicmodeLoot.end()) - return false; - - return true; + return sZoneDifficulty->MythicmodeLoot.count(mapId) > 0; } /** @@ -685,30 +664,24 @@ bool ZoneDifficulty::IsValidNerfTarget(Unit* target) * @param element One element which can potentially be part of the values in the vector * @return The result as bool */ -bool ZoneDifficulty::VectorContainsUint32(std::vector vec, uint32 element) +bool ZoneDifficulty::VectorContainsUint32(const std::vector& vec, uint32 element) { return find(vec.begin(), vec.end(), element) != vec.end(); } /** - * @brief Checks if the instance and spelloverride have matching modes + * @brief Checks if the instance mode matches the override's mode mask * - * @param instanceId - * @param spellId - * @param mapId + * @param instanceId The instance ID to check mythic status + * @param modeMask The mode bitmask from the override entry * @return The result as bool */ - bool ZoneDifficulty::OverrideModeMatches(uint32 instanceId, uint32 spellId, uint32 mapId) + bool ZoneDifficulty::OverrideModeMatches(uint32 instanceId, uint32 modeMask) { - if ((sZoneDifficulty->HasMythicmode(sZoneDifficulty->SpellNerfOverrides[spellId][mapId].ModeMask) && sZoneDifficulty->MythicmodeInstanceData[instanceId]) || - (sZoneDifficulty->HasNormalMode(sZoneDifficulty->SpellNerfOverrides[spellId][mapId].ModeMask) && !sZoneDifficulty->MythicmodeInstanceData[instanceId])) - { - return true; - } - else - { - return false; - } + bool isMythic = sZoneDifficulty->IsInstanceMythic(instanceId); + + return (sZoneDifficulty->HasMythicmode(modeMask) && isMythic) || + (sZoneDifficulty->HasNormalMode(modeMask) && !isMythic); } /** @@ -754,24 +727,22 @@ bool ZoneDifficulty::ShouldNerfInDuels(Unit* target) */ int32 ZoneDifficulty::GetLowestMatchingPhase(uint32 mapId, uint32 phaseMask) { - // Check if there is an entry for the mapId at all - if (sZoneDifficulty->ShouldNerfMap(mapId)) - { + auto mapIt = sZoneDifficulty->NerfInfo.find(mapId); + if (mapIt == sZoneDifficulty->NerfInfo.end()) + return -1; - // Check if 0 is assigned as a phase to cover all phases - if (sZoneDifficulty->NerfInfo[mapId].find(0) != sZoneDifficulty->NerfInfo[mapId].end()) - { - return 0; - } + auto& phaseMap = mapIt->second; - for (auto const& [key, value] : sZoneDifficulty->NerfInfo[mapId]) - { - if (key & phaseMask) - { - return key; - } - } + // Check if 0 is assigned as a phase to cover all phases + if (phaseMap.count(0)) + return 0; + + for (auto const& [key, value] : phaseMap) + { + if (key & phaseMask) + return key; } + return -1; } @@ -783,11 +754,11 @@ int32 ZoneDifficulty::GetLowestMatchingPhase(uint32 mapId, uint32 phaseMask) */ void ZoneDifficulty::SaveMythicmodeInstanceData(uint32 instanceId) { - if (sZoneDifficulty->MythicmodeInstanceData.find(instanceId) == sZoneDifficulty->MythicmodeInstanceData.end()) - { + auto it = sZoneDifficulty->MythicmodeInstanceData.find(instanceId); + if (it == sZoneDifficulty->MythicmodeInstanceData.end()) return; - } - CharacterDatabase.Execute("REPLACE INTO zone_difficulty_instance_saves (InstanceID, MythicmodeOn) VALUES ({}, {})", instanceId, sZoneDifficulty->MythicmodeInstanceData[instanceId]); + + CharacterDatabase.Execute("REPLACE INTO zone_difficulty_instance_saves (InstanceID, MythicmodeOn) VALUES ({}, {})", instanceId, it->second); } void ZoneDifficulty::MythicmodeEvent(Unit* unit, uint32 entry, uint32 key) @@ -974,16 +945,27 @@ bool ZoneDifficulty::HasCompletedFullTier(uint32 category, uint32 playerGuid) break; } + auto playerLogIt = sZoneDifficulty->Logs.find(playerGuid); + if (playerLogIt == sZoneDifficulty->Logs.end()) + return false; + for (uint32 mapId : MapList) { - if (sZoneDifficulty->EncounterCounter.find(mapId) == sZoneDifficulty->EncounterCounter.end()) + auto encounterIt = sZoneDifficulty->EncounterCounter.find(mapId); + if (encounterIt == sZoneDifficulty->EncounterCounter.end()) { LOG_ERROR("module", "MOD-ZONE-DIFFICULTY: Map without data requested in ZoneDifficulty::HasCompletedFullTier {}", mapId); return false; } - for (uint8 i = 0; i < sZoneDifficulty->EncounterCounter[mapId]; ++i) + + auto mapLogIt = playerLogIt->second.find(mapId); + if (mapLogIt == playerLogIt->second.end()) + return false; + + for (uint8 i = 0; i < encounterIt->second; ++i) { - if (!sZoneDifficulty->Logs[playerGuid][mapId][i]) + auto bossIt = mapLogIt->second.find(i); + if (bossIt == mapLogIt->second.end() || !bossIt->second) return false; } } diff --git a/src/mod_zone_difficulty_scripts.cpp b/src/mod_zone_difficulty_scripts.cpp index f711be9d..50b56a8e 100644 --- a/src/mod_zone_difficulty_scripts.cpp +++ b/src/mod_zone_difficulty_scripts.cpp @@ -64,7 +64,7 @@ class mod_zone_difficulty_unitscript : public UnitScript uint32 instanceId = target->GetMap()->GetInstanceId(); uint32 phaseMask = target->GetPhaseMask(); int phase = sZoneDifficulty->GetLowestMatchingPhase(mapId, phaseMask); - bool isMythic = sZoneDifficulty->MythicmodeInstanceData[instanceId]; + bool isMythic = sZoneDifficulty->IsInstanceMythic(instanceId); bool nerfInDuel = sZoneDifficulty->ShouldNerfInDuels(target); auto scaleAbsorb = [](int32 amount, float pct) -> int32 { @@ -96,12 +96,17 @@ class mod_zone_difficulty_unitscript : public UnitScript if (overrideIt != sZoneDifficulty->SpellNerfOverrides.end()) { auto const& overrideMap = overrideIt->second; - if (sZoneDifficulty->OverrideModeMatches(instanceId, spellInfo->Id, mapId)) + + auto mapIt = overrideMap.find(mapId); + if (mapIt != overrideMap.end() && sZoneDifficulty->OverrideModeMatches(instanceId, mapIt->second.ModeMask)) { - if (overrideMap.count(mapId)) - absorb = scaleAbsorb(absorb, overrideMap.at(mapId).NerfPct); - else if (overrideMap.count(0)) - absorb = scaleAbsorb(absorb, overrideMap.at(0).NerfPct); + absorb = scaleAbsorb(absorb, mapIt->second.NerfPct); + } + else + { + auto globalIt = overrideMap.find(0); + if (globalIt != overrideMap.end() && sZoneDifficulty->OverrideModeMatches(instanceId, globalIt->second.ModeMask)) + absorb = scaleAbsorb(absorb, globalIt->second.NerfPct); } } @@ -128,73 +133,74 @@ class mod_zone_difficulty_unitscript : public UnitScript if (!sZoneDifficulty->MythicmodeInNormalDungeons && !target->GetMap()->IsRaidOrHeroicDungeon()) return; - if (sZoneDifficulty->IsValidNerfTarget(target)) + if (!sZoneDifficulty->IsValidNerfTarget(target)) + return; + + if (spellInfo) { - if (spellInfo) + if (spellInfo->HasEffect(SPELL_EFFECT_HEALTH_LEECH)) + return; + + for (auto const& eff : spellInfo->GetEffects()) { - if (spellInfo->HasEffect(SPELL_EFFECT_HEALTH_LEECH)) + if (eff.ApplyAuraName == SPELL_AURA_PERIODIC_LEECH) return; + } - for (auto const& eff : spellInfo->GetEffects()) - { - if (eff.ApplyAuraName == SPELL_AURA_PERIODIC_LEECH) - return; - } + // Skip spells not affected by vulnerability (potions) and bandages + if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || spellInfo->Mechanic == MECHANIC_BANDAGE) + return; + } - // Skip spells not affected by vulnerability (potions) and bandages - if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || spellInfo->Mechanic == MECHANIC_BANDAGE) - return; - } + uint32 mapId = target->GetMapId(); + bool nerfInDuel = sZoneDifficulty->ShouldNerfInDuels(target); - uint32 mapId = target->GetMapId(); - bool nerfInDuel = sZoneDifficulty->ShouldNerfInDuels(target); - //Check if the map of the target is subject of a nerf at all OR if the target is subject of a nerf in a duel - if (sZoneDifficulty->ShouldNerfMap(mapId) || sZoneDifficulty->ShouldNerfInDuels(target)) + if (!sZoneDifficulty->ShouldNerfMap(mapId) && !nerfInDuel) + return; + + // Spell-specific override check - must be first to override everything else. + if (spellInfo) + { + auto spellIt = sZoneDifficulty->SpellNerfOverrides.find(spellInfo->Id); + if (spellIt != sZoneDifficulty->SpellNerfOverrides.end()) { - //This check must be first and skip the rest to override everything else. - if (spellInfo) + uint32 instanceId = target->GetMap()->GetInstanceId(); + auto& overrideMap = spellIt->second; + + auto mapIt = overrideMap.find(mapId); + if (mapIt != overrideMap.end() && sZoneDifficulty->OverrideModeMatches(instanceId, mapIt->second.ModeMask)) { - if (sZoneDifficulty->SpellNerfOverrides.find(spellInfo->Id) != sZoneDifficulty->SpellNerfOverrides.end()) - { - if (sZoneDifficulty->SpellNerfOverrides[spellInfo->Id].find(mapId) != sZoneDifficulty->SpellNerfOverrides[spellInfo->Id].end()) - { - if (sZoneDifficulty->OverrideModeMatches(target->GetMap()->GetInstanceId(), spellInfo->Id, mapId)) - { - heal = heal * sZoneDifficulty->SpellNerfOverrides[spellInfo->Id][mapId].NerfPct; - return; - } - } - if (sZoneDifficulty->SpellNerfOverrides[spellInfo->Id].find(0) != sZoneDifficulty->SpellNerfOverrides[spellInfo->Id].end()) - { - if (sZoneDifficulty->OverrideModeMatches(target->GetMap()->GetInstanceId(), spellInfo->Id, mapId)) - { - heal = heal * sZoneDifficulty->SpellNerfOverrides[spellInfo->Id][0].NerfPct; - return; - } - } - } + heal = heal * mapIt->second.NerfPct; + return; } - uint32 phaseMask = target->GetPhaseMask(); - int matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, phaseMask); - int8 mode = sZoneDifficulty->NerfInfo[mapId][matchingPhase].Enabled; - if (matchingPhase != -1) + auto globalIt = overrideMap.find(0); + if (globalIt != overrideMap.end() && sZoneDifficulty->OverrideModeMatches(instanceId, globalIt->second.ModeMask)) { - Map* map = target->GetMap(); - uint32 instanceId = map->GetInstanceId(); - bool isMythicMode = sZoneDifficulty->MythicmodeInstanceData[instanceId]; - - if (!isMythicMode && sZoneDifficulty->HasNormalMode(mode)) - heal = heal * sZoneDifficulty->NerfInfo[mapId][matchingPhase].HealingNerfPct; - - if (isMythicMode && sZoneDifficulty->HasMythicmode(mode)) - if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) - heal = heal * sZoneDifficulty->NerfInfo[mapId][matchingPhase].HealingNerfPctHard; + heal = heal * globalIt->second.NerfPct; + return; } - else if (sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0 && nerfInDuel) - heal = heal * sZoneDifficulty->NerfInfo[DUEL_INDEX][0].HealingNerfPct; } } + + int matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, target->GetPhaseMask()); + if (matchingPhase != -1) + { + auto const& nerfData = sZoneDifficulty->NerfInfo[mapId][matchingPhase]; + Map* map = target->GetMap(); + bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); + + if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) + heal = heal * nerfData.HealingNerfPct; + + if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) + if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) + heal = heal * nerfData.HealingNerfPctHard; + } + else if (nerfInDuel && sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) + { + heal = heal * sZoneDifficulty->NerfInfo[DUEL_INDEX][0].HealingNerfPct; + } } void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage, SpellInfo const* spellInfo) override @@ -236,17 +242,16 @@ class mod_zone_difficulty_unitscript : public UnitScript if (sZoneDifficulty->ShouldNerfMap(mapId) && matchingPhase != -1) { - int8 mode = sZoneDifficulty->NerfInfo[mapId][matchingPhase].Enabled; + auto const& nerfData = sZoneDifficulty->NerfInfo[mapId][matchingPhase]; Map* map = target->GetMap(); - uint32 instanceId = map->GetInstanceId(); - bool isMythicMode = sZoneDifficulty->MythicmodeInstanceData[instanceId]; + bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); - if (!isMythicMode && sZoneDifficulty->HasNormalMode(mode)) - damage = damage * sZoneDifficulty->NerfInfo[mapId][matchingPhase].SpellDamageBuffPct; + if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) + damage = damage * nerfData.SpellDamageBuffPct; - if (isMythicMode && sZoneDifficulty->HasMythicmode(mode)) + if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) - damage = damage * sZoneDifficulty->NerfInfo[mapId][matchingPhase].SpellDamageBuffPctHard; + damage = damage * nerfData.SpellDamageBuffPctHard; } else if (sZoneDifficulty->ShouldNerfInDuels(target)) if (sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) @@ -274,34 +279,35 @@ class mod_zone_difficulty_unitscript : public UnitScript if (sZoneDifficulty->IsValidNerfTarget(target)) { uint32 mapId = target->GetMapId(); - uint32 phaseMask = target->GetPhaseMask(); - int32 matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, phaseMask); + int32 matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, target->GetPhaseMask()); + + // Spell-specific override check - must be first to override everything else. if (spellInfo) { - //This check must be first and skip the rest to override everything else. - if (sZoneDifficulty->SpellNerfOverrides.find(spellInfo->Id) != sZoneDifficulty->SpellNerfOverrides.end()) + auto spellIt = sZoneDifficulty->SpellNerfOverrides.find(spellInfo->Id); + if (spellIt != sZoneDifficulty->SpellNerfOverrides.end()) { - if (sZoneDifficulty->SpellNerfOverrides[spellInfo->Id].find(mapId) != sZoneDifficulty->SpellNerfOverrides[spellInfo->Id].end()) + uint32 instanceId = target->GetMap()->GetInstanceId(); + auto& overrideMap = spellIt->second; + + auto mapIt = overrideMap.find(mapId); + if (mapIt != overrideMap.end() && sZoneDifficulty->OverrideModeMatches(instanceId, mapIt->second.ModeMask)) { - if (sZoneDifficulty->OverrideModeMatches(target->GetMap()->GetInstanceId(), spellInfo->Id, mapId)) - { - damage = damage * sZoneDifficulty->SpellNerfOverrides[spellInfo->Id][mapId].NerfPct; - return; - } + damage = damage * mapIt->second.NerfPct; + return; } - else if (sZoneDifficulty->SpellNerfOverrides[spellInfo->Id].find(0) != sZoneDifficulty->SpellNerfOverrides[spellInfo->Id].end()) + + auto globalIt = overrideMap.find(0); + if (globalIt != overrideMap.end() && sZoneDifficulty->OverrideModeMatches(instanceId, globalIt->second.ModeMask)) { - if (sZoneDifficulty->OverrideModeMatches(target->GetMap()->GetInstanceId(), spellInfo->Id, mapId)) - { - damage = damage * sZoneDifficulty->SpellNerfOverrides[spellInfo->Id][0].NerfPct; - return; - } + damage = damage * globalIt->second.NerfPct; + return; } } if (sZoneDifficulty->IsDebugInfoEnabled && target) { - if (Player* player = target->ToPlayer()) // Pointless check? Perhaps. + if (Player* player = target->ToPlayer()) { ChatHandler(player->GetSession()).PSendSysMessage("Spell: {} ({}) Before Nerf Value: {} ({} Normal Mode)", spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()], spellInfo->Id, damage, sZoneDifficulty->NerfInfo[mapId][matchingPhase].SpellDamageBuffPct); ChatHandler(player->GetSession()).PSendSysMessage("Spell: {} ({}) Before Nerf Value: {} ({} Mythic Mode)", spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()], spellInfo->Id, damage, sZoneDifficulty->NerfInfo[mapId][matchingPhase].SpellDamageBuffPctHard); @@ -311,24 +317,23 @@ class mod_zone_difficulty_unitscript : public UnitScript if (sZoneDifficulty->ShouldNerfMap(mapId) && matchingPhase != -1) { - int8 mode = sZoneDifficulty->NerfInfo[mapId][matchingPhase].Enabled; + auto const& nerfData = sZoneDifficulty->NerfInfo[mapId][matchingPhase]; Map* map = target->GetMap(); - uint32 instanceId = map->GetInstanceId(); - bool isMythicMode = sZoneDifficulty->MythicmodeInstanceData[instanceId]; + bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); - if (!isMythicMode && sZoneDifficulty->HasNormalMode(mode)) - damage = damage * sZoneDifficulty->NerfInfo[mapId][matchingPhase].SpellDamageBuffPct; + if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) + damage = damage * nerfData.SpellDamageBuffPct; - if (isMythicMode && sZoneDifficulty->HasMythicmode(mode)) + if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) - damage = damage * sZoneDifficulty->NerfInfo[mapId][matchingPhase].SpellDamageBuffPctHard; + damage = damage * nerfData.SpellDamageBuffPctHard; } else if (sZoneDifficulty->ShouldNerfInDuels(target)) if (sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) damage = damage * sZoneDifficulty->NerfInfo[DUEL_INDEX][0].SpellDamageBuffPct; if (sZoneDifficulty->IsDebugInfoEnabled && target) - if (Player* player = target->ToPlayer()) // Pointless check? Perhaps. + if (Player* player = target->ToPlayer()) ChatHandler(player->GetSession()).PSendSysMessage("Spell: {} ({}) Post Nerf Value: {}", spellInfo->SpellName[player->GetSession()->GetSessionDbcLocale()], spellInfo->Id, damage); } } @@ -349,21 +354,19 @@ class mod_zone_difficulty_unitscript : public UnitScript if (sZoneDifficulty->IsValidNerfTarget(target)) { uint32 mapId = target->GetMapId(); - uint32 phaseMask = target->GetPhaseMask(); - int matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, phaseMask); + int matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, target->GetPhaseMask()); if (sZoneDifficulty->ShouldNerfMap(mapId) && matchingPhase != -1) { - int8 mode = sZoneDifficulty->NerfInfo[mapId][matchingPhase].Enabled; + auto const& nerfData = sZoneDifficulty->NerfInfo[mapId][matchingPhase]; Map* map = target->GetMap(); - uint32 instanceId = map->GetInstanceId(); - bool isMythicMode = sZoneDifficulty->MythicmodeInstanceData[instanceId]; + bool isMythicMode = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); - if (!isMythicMode && sZoneDifficulty->HasNormalMode(mode)) - damage = damage * sZoneDifficulty->NerfInfo[mapId][matchingPhase].MeleeDamageBuffPct; + if (!isMythicMode && sZoneDifficulty->HasNormalMode(nerfData.Enabled)) + damage = damage * nerfData.MeleeDamageBuffPct; - if (isMythicMode && sZoneDifficulty->HasMythicmode(mode)) + if (isMythicMode && sZoneDifficulty->HasMythicmode(nerfData.Enabled)) if (map->IsRaid() || (map->IsHeroic() && map->IsDungeon())) - damage = damage * sZoneDifficulty->NerfInfo[mapId][matchingPhase].MeleeDamageBuffPctHard; + damage = damage * nerfData.MeleeDamageBuffPctHard; } else if (sZoneDifficulty->ShouldNerfInDuels(target)) if (sZoneDifficulty->NerfInfo[DUEL_INDEX][0].Enabled > 0) @@ -376,10 +379,7 @@ class mod_zone_difficulty_unitscript : public UnitScript */ void OnUnitEnterCombat(Unit* unit, Unit* /*victim*/) override { - if (sZoneDifficulty->MythicmodeInstanceData.find(unit->GetInstanceId()) == sZoneDifficulty->MythicmodeInstanceData.end()) - return; - - if (!sZoneDifficulty->MythicmodeInstanceData[unit->GetInstanceId()]) + if (!sZoneDifficulty->IsInstanceMythic(unit->GetInstanceId())) return; if (Creature* creature = unit->ToCreature()) @@ -387,13 +387,14 @@ class mod_zone_difficulty_unitscript : public UnitScript return; uint32 entry = unit->GetEntry(); - if (sZoneDifficulty->MythicmodeAI.find(entry) == sZoneDifficulty->MythicmodeAI.end()) + auto aiIt = sZoneDifficulty->MythicmodeAI.find(entry); + if (aiIt == sZoneDifficulty->MythicmodeAI.end()) return; unit->m_Events.CancelEventGroup(EVENT_GROUP); uint32 i = 0; - for (ZoneDifficultyHAI& data : sZoneDifficulty->MythicmodeAI[entry]) + for (ZoneDifficultyHAI& data : aiIt->second) { if (data.Chance == 100 || data.Chance >= urand(1, 100)) { @@ -417,14 +418,14 @@ class mod_zone_difficulty_petscript : public PetScript void OnPetAddToWorld(Pet* pet) override { uint32 mapId = pet->GetMapId(); - if (sZoneDifficulty->DisallowedBuffs.find(mapId) != sZoneDifficulty->DisallowedBuffs.end()) + auto buffIt = sZoneDifficulty->DisallowedBuffs.find(mapId); + if (buffIt != sZoneDifficulty->DisallowedBuffs.end()) { - pet->m_Events.AddEventAtOffset([mapId, pet]() + auto debuffs = buffIt->second; + pet->m_Events.AddEventAtOffset([debuffs, pet]() { - for (uint32 aura : sZoneDifficulty->DisallowedBuffs[mapId]) - { + for (uint32 aura : debuffs) pet->RemoveAurasDueToSpell(aura); - } }, 2s); } } @@ -476,27 +477,22 @@ class mod_zone_difficulty_globalscript : public GlobalScript if (!sZoneDifficulty->MythicmodeEnable) return; - if (sZoneDifficulty->IsDebugInfoEnabled) - { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: OnBeforeSetBossState: bossId = {}, newState = {}, oldState = {}, MapId = {}, InstanceId = {}", id, newState, oldState, instance->GetId(), instance->GetInstanceId()); - } - uint32 instanceId = instance->GetInstanceId(); if (!sZoneDifficulty->IsMythicmodeMap(instance->GetId()) || (!sZoneDifficulty->MythicmodeInNormalDungeons && !instance->IsRaidOrHeroicDungeon())) - { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: OnBeforeSetBossState: Instance not handled because there is no Mythicmode loot data for map id: {}", instance->GetId()); return; - } + + bool isMythic = sZoneDifficulty->IsInstanceMythic(instanceId); + if (oldState != IN_PROGRESS && newState == IN_PROGRESS) { - if (sZoneDifficulty->MythicmodeInstanceData[instanceId]) + if (isMythic) sZoneDifficulty->EncountersInProgress[instanceId] = GameTime::GetGameTime().count(); } else if (oldState == IN_PROGRESS && newState == DONE) { - if (sZoneDifficulty->MythicmodeInstanceData[instanceId]) + if (isMythic) { if ((id == 7 /* Illidari Council*/ || id == 5 /* Reliquary of Souls*/) && instance->GetId() == 564) sZoneDifficulty->AddMythicmodeScore(instance, TYPE_RAID_T6, 1); @@ -504,14 +500,14 @@ class mod_zone_difficulty_globalscript : public GlobalScript if ((id == 0 /* Kalecgos */ || id == 4 /* Twins*/) && instance->GetId() == 580) sZoneDifficulty->AddMythicmodeScore(instance, TYPE_RAID_SWP, 1); - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Mythicmode is on."); - if (sZoneDifficulty->EncountersInProgress.find(instanceId) != sZoneDifficulty->EncountersInProgress.end() && sZoneDifficulty->EncountersInProgress[instanceId] != 0) + auto encounterIt = sZoneDifficulty->EncountersInProgress.find(instanceId); + if (encounterIt != sZoneDifficulty->EncountersInProgress.end() && encounterIt->second != 0) { instance->DoForAllPlayers([&](Player* player) { if (!player->IsGameMaster() && !player->IsDeveloper()) CharacterDatabase.Execute("REPLACE INTO `zone_difficulty_encounter_logs` VALUES({}, {}, {}, {}, {}, {}, {})", - instanceId, sZoneDifficulty->EncountersInProgress[instanceId], GameTime::GetGameTime().count(), instance->GetId(), id, player->GetGUID().GetCounter(), 64); + instanceId, encounterIt->second, GameTime::GetGameTime().count(), instance->GetId(), id, player->GetGUID().GetCounter(), 64); }); } } @@ -520,75 +516,54 @@ class mod_zone_difficulty_globalscript : public GlobalScript void OnInstanceIdRemoved(uint32 instanceId) override { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: OnInstanceIdRemoved: instanceId = {}", instanceId); - if (sZoneDifficulty->MythicmodeInstanceData.find(instanceId) != sZoneDifficulty->MythicmodeInstanceData.end()) - { - sZoneDifficulty->MythicmodeInstanceData.erase(instanceId); - } - + sZoneDifficulty->MythicmodeInstanceData.erase(instanceId); CharacterDatabase.Execute("DELETE FROM zone_difficulty_instance_saves WHERE InstanceID = {};", instanceId); } void OnAfterUpdateEncounterState(Map* map, EncounterCreditType /*type*/, uint32 /*creditEntry*/, Unit* source, Difficulty /*difficulty_fixed*/, DungeonEncounterList const* /*encounters*/, uint32 /*dungeonCompleted*/, bool /*updated*/) override { if (!sZoneDifficulty->MythicmodeEnable) - { return; - } + if (!source) - { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: source is a nullptr in OnAfterUpdateEncounterState"); return; - } - if (sZoneDifficulty->MythicmodeInstanceData.find(map->GetInstanceId()) != sZoneDifficulty->MythicmodeInstanceData.end()) + if (!sZoneDifficulty->IsInstanceMythic(map->GetInstanceId())) + return; + + uint32 mapId = map->GetId(); + if (!sZoneDifficulty->IsMythicmodeMap(mapId) || + (!sZoneDifficulty->MythicmodeInNormalDungeons && !map->IsRaidOrHeroicDungeon())) + return; + + uint32 score = 0; + bool sourceAwardsMythicmodeLoot = false; + auto lootIt = sZoneDifficulty->MythicmodeLoot.find(mapId); + if (lootIt != sZoneDifficulty->MythicmodeLoot.end()) { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Encounter completed. Map relevant. Checking for source: {}", source->GetEntry()); - // Give additional loot, if the encounter was in Mythicmode. - if (sZoneDifficulty->MythicmodeInstanceData[map->GetInstanceId()]) + for (auto const& value : lootIt->second) { - uint32 mapId = map->GetId(); - uint32 score = 0; - if (!sZoneDifficulty->IsMythicmodeMap(mapId) || - (!sZoneDifficulty->MythicmodeInNormalDungeons && !map->IsRaidOrHeroicDungeon())) - { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: No additional loot stored in map with id {}.", map->GetInstanceId()); - return; - } - - bool SourceAwardsMythicmodeLoot = false; - //iterate over all listed creature entries for that map id and see, if the encounter should yield Mythicmode loot and if there is an override to the default behaviour - for (auto value : sZoneDifficulty->MythicmodeLoot[mapId]) + if (value.EncounterEntry == source->GetEntry()) { - if (value.EncounterEntry == source->GetEntry()) - { - SourceAwardsMythicmodeLoot = true; - if (!(value.Override & 1)) - score = 1; - - break; - } + sourceAwardsMythicmodeLoot = true; + if (!(value.Override & 1)) + score = 1; + break; } + } + } - if (!SourceAwardsMythicmodeLoot) - return; + if (!sourceAwardsMythicmodeLoot) + return; - if (map->IsHeroic() && map->IsNonRaidDungeon()) - { - sZoneDifficulty->AddMythicmodeScore(map, sZoneDifficulty->Expansion[mapId], score); - } - else if (map->IsRaid()) - { - sZoneDifficulty->AddMythicmodeScore(map, sZoneDifficulty->Expansion[mapId], score); - sZoneDifficulty->ProcessCreatureDeath(map, source->GetEntry()); - } - /* debug - * else - * { - * LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Map with id {} is not a raid or a dungeon. Mythicmode loot not granted.", map->GetInstanceId()); - * } - */ - } + if (map->IsHeroic() && map->IsNonRaidDungeon()) + { + sZoneDifficulty->AddMythicmodeScore(map, sZoneDifficulty->Expansion[mapId], score); + } + else if (map->IsRaid()) + { + sZoneDifficulty->AddMythicmodeScore(map, sZoneDifficulty->Expansion[mapId], score); + sZoneDifficulty->ProcessCreatureDeath(map, source->GetEntry()); } } }; @@ -600,20 +575,9 @@ class mod_zone_difficulty_rewardnpc : public CreatureScript bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override { - if (sZoneDifficulty->IsDebugInfoEnabled) - { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: OnGossipSelectRewardNpc action: {}", action); - } ClearGossipMenuFor(player); uint32 npcText = 0; - //Safety measure. There's a way for action 0 to happen even though it's not provided in the gossip menu. - if (action == 0) - { - CloseGossipMenuFor(player); - return true; - } - - if (action == 999998) + if (action == 0 || action == 999998) { CloseGossipMenuFor(player); return true; @@ -660,7 +624,6 @@ class mod_zone_difficulty_rewardnpc : public CreatureScript return true; } - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Sending full tier clearance reward for category {}", category); sZoneDifficulty->DeductMythicmodeScore(player, category, sZoneDifficulty->TierRewards[category].Price); sZoneDifficulty->SendItem(player, sZoneDifficulty->TierRewards[category]); @@ -736,7 +699,6 @@ class mod_zone_difficulty_rewardnpc : public CreatureScript ++category; counter = counter - 100; } - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Building gossip with category {} and counter {}", category, counter); if (sZoneDifficulty->UseVendorInterface) { @@ -746,7 +708,6 @@ class mod_zone_difficulty_rewardnpc : public CreatureScript for (size_t i = 0; i < sZoneDifficulty->Rewards[category][counter].size(); ++i) { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Adding gossip option for entry {}", sZoneDifficulty->Rewards[category][counter][i].Entry); ItemTemplate const* proto = sObjectMgr->GetItemTemplate(sZoneDifficulty->Rewards[category][counter][i].Entry); std::string name = proto->Name1; if (ItemLocale const* leftIl = sObjectMgr->GetItemLocale(sZoneDifficulty->Rewards[category][counter][i].Entry)) @@ -770,9 +731,6 @@ class mod_zone_difficulty_rewardnpc : public CreatureScript ++itemType; counter = counter - 100; } - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Handling item with category {}, itemType {}, counter {}", category, itemType, counter); - - // Check if the player has enough score in the respective category. if (!sZoneDifficulty->CheckCompletionStatus(creature, player, category)) { @@ -831,7 +789,6 @@ class mod_zone_difficulty_rewardnpc : public CreatureScript bool OnGossipHello(Player* player, Creature* creature) override { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: OnGossipHelloRewardNpc"); uint32 npcText = NPC_TEXT_OFFER; AddGossipItemFor(player, GOSSIP_ICON_CHAT, "|TInterface\\icons\\inv_misc_questionmark:15|t Can you please remind me of my score?", GOSSIP_SENDER_MAIN, 999999); @@ -962,12 +919,11 @@ class mod_zone_difficulty_dungeonmaster : public CreatureScript uint32 instanceId = player->GetMap()->GetInstanceId(); if (action == 100) { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Try turn on"); bool canTurnOn = true; // Forbid turning Mythicmode on ... // ...if a single encounter was completed on normal mode - if (sZoneDifficulty->MythicmodeInstanceData.find(instanceId) != sZoneDifficulty->MythicmodeInstanceData.end()) + if (sZoneDifficulty->MythicmodeInstanceData.count(instanceId)) { if (player->GetInstanceScript()->GetBossState(0) == DONE) { @@ -988,7 +944,6 @@ class mod_zone_difficulty_dungeonmaster : public CreatureScript if (canTurnOn) { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Turn on Mythicmode for id {}", instanceId); sZoneDifficulty->MythicmodeInstanceData[instanceId] = true; sZoneDifficulty->SaveMythicmodeInstanceData(instanceId); sZoneDifficulty->SendWhisperToRaid("We're switching to the challenging version of the history lesson now. (Mythic Mode)", creature, player); @@ -1000,13 +955,11 @@ class mod_zone_difficulty_dungeonmaster : public CreatureScript { if (player->GetInstanceScript()->IsEncounterInProgress()) { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: IsEncounterInProgress"); creature->Whisper("I am sorry, time-traveler. You can not change the version of the time-line currently. There is already a battle in progress.", LANG_UNIVERSAL, player); CloseGossipMenuFor(player); } if (player->GetInstanceScript()->GetBossState(0) != DONE) { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Turn off Mythicmode for id {}", instanceId); sZoneDifficulty->MythicmodeInstanceData[instanceId] = false; sZoneDifficulty->SaveMythicmodeInstanceData(instanceId); sZoneDifficulty->SendWhisperToRaid("We're switching to the cinematic version of the history lesson now. (Normal mode)", creature, player); @@ -1021,7 +974,6 @@ class mod_zone_difficulty_dungeonmaster : public CreatureScript } else if (action == 102) { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: Turn off Mythicmode for id {}", instanceId); sZoneDifficulty->MythicmodeInstanceData[instanceId] = false; sZoneDifficulty->SaveMythicmodeInstanceData(instanceId); sZoneDifficulty->SendWhisperToRaid("We're switching to the cinematic version of the history lesson now. (Normal mode)", creature, player); @@ -1033,7 +985,6 @@ class mod_zone_difficulty_dungeonmaster : public CreatureScript bool OnGossipHello(Player* player, Creature* creature) override { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: OnGossipHelloChromie"); Group* group = player->GetGroup(); if (group && group->IsLfgRandomInstance() && !player->GetMap()->IsRaid()) { @@ -1046,14 +997,12 @@ class mod_zone_difficulty_dungeonmaster : public CreatureScript return true; } uint32 npcText = NPC_TEXT_OTHER; - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: OnGossipHello Has Group"); if (player->IsGameMaster() || (group && group->IsLeader(player->GetGUID()))) { - //LOG_INFO("module", "MOD-ZONE-DIFFICULTY: OnGossipHello Is Leader"); AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Please Chromie, let us re-experience how all the things really happened back then. (Mythic Mode)", GOSSIP_SENDER_MAIN, 100); AddGossipItemFor(player, GOSSIP_ICON_CHAT, "I think we will be fine with the cinematic version from here. (Normal mode)", GOSSIP_SENDER_MAIN, 101); - npcText = sZoneDifficulty->MythicmodeInstanceData[player->GetMap()->GetInstanceId()] ? + npcText = sZoneDifficulty->IsInstanceMythic(player->GetMap()->GetInstanceId()) ? NPC_TEXT_LEADER_HARD : NPC_TEXT_LEADER_NORMAL; } else @@ -1075,16 +1024,18 @@ class mod_zone_difficulty_allcreaturescript : public AllCreatureScript if (!sZoneDifficulty->MythicmodeEnable) return; - // Heavily inspired by https://github.com/azerothcore/mod-autobalance/blob/1d82080237e62376b9a030502264c90b5b8f272b/src/AutoBalance.cpp + if (!creature) + return; + Map* map = creature->GetMap(); - if (!creature || !map) + if (!map) return; - if (!map->IsRaid() && (!(map->IsHeroic() && map->IsDungeon()))) + if (!map->IsRaid() && !(map->IsHeroic() && map->IsDungeon())) return; uint32 mapId = creature->GetMapId(); - if (sZoneDifficulty->NerfInfo.find(mapId) == sZoneDifficulty->NerfInfo.end()) + if (!sZoneDifficulty->ShouldNerfMap(mapId)) return; if ((creature->IsHunterPet() || creature->IsPet() || creature->IsSummon()) && creature->IsControlledByPlayer()) @@ -1094,60 +1045,52 @@ class mod_zone_difficulty_allcreaturescript : public AllCreatureScript return; CreatureTemplate const* creatureTemplate = creature->GetCreatureTemplate(); - //skip critters and special creatures (spell summons etc.) in instances if (creatureTemplate->maxlevel <= 1) return; + // Check phase match early to skip unnecessary health computation + int matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(mapId, creature->GetPhaseMask()); + if (matchingPhase == -1) + return; + + bool isMythic = sZoneDifficulty->IsInstanceMythic(map->GetInstanceId()); + uint32 entry = creature->GetEntry(); + CreatureBaseStats const* origCreatureStats = sObjectMgr->GetCreatureBaseStats(creature->GetLevel(), creatureTemplate->unit_class); uint32 baseHealth = origCreatureStats->GenerateHealth(creatureTemplate); uint32 scaledBaseHealth = baseHealth; - uint32 entry = creature->GetEntry(); - uint32 phaseMask = creature->GetPhaseMask(); - int matchingPhase = sZoneDifficulty->GetLowestMatchingPhase(creature->GetMapId(), phaseMask); - bool isMythic = sZoneDifficulty->MythicmodeInstanceData[creature->GetMap()->GetInstanceId()]; - - if (sZoneDifficulty->CreatureOverrides.find(entry) == sZoneDifficulty->CreatureOverrides.end()) + auto overrideIt = sZoneDifficulty->CreatureOverrides.find(entry); + if (overrideIt == sZoneDifficulty->CreatureOverrides.end()) { - // TEMPORARY!!! It conflicts with CC normal mode tuning, dont apply trash tuning to hyjal and ssc - if (creature->GetMap()->GetId() == 534 || creature->GetMap()->GetId() == 548) + // TEMPORARY: conflicts with CC normal mode tuning for Hyjal and SSC + if (mapId == 534 || mapId == 548) return; - // Trash mobs. Apply generic tuning. if (!creature->IsDungeonBoss() && isMythic) scaledBaseHealth = round(baseHealth * sZoneDifficulty->MythicmodeHpModifier); } else { - float multiplier = isMythic ? sZoneDifficulty->CreatureOverrides[entry].MythicOverride - : sZoneDifficulty->CreatureOverrides[entry].NormalOverride; + float multiplier = isMythic ? overrideIt->second.MythicOverride + : overrideIt->second.NormalOverride; if (!multiplier) - multiplier = 1.0f; // never 0 + multiplier = 1.0f; scaledBaseHealth = round(baseHealth * multiplier); } - if (matchingPhase != -1) - { - float scaledHealth = scaledBaseHealth; - scaledHealth *= creature->GetPctModifierValue(UNIT_MOD_HEALTH, BASE_PCT); - scaledHealth += creature->GetFlatModifierValue(UNIT_MOD_HEALTH, TOTAL_VALUE); - scaledHealth *= creature->GetPctModifierValue(UNIT_MOD_HEALTH, TOTAL_PCT); - - if (creature->GetMaxHealth() == scaledHealth) - return; + // Quick check: skip if BASE_VALUE is already at the target value + if (creature->GetFlatModifierValue(UNIT_MOD_HEALTH, BASE_VALUE) == (float)scaledBaseHealth) + return; - float percent = creature->GetHealthPct(); - creature->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)scaledBaseHealth); - creature->UpdateMaxHealth(); - if (creature->IsAlive()) - { - uint32 scaledCurHealth = creature->CountPctFromMaxHealth(percent); - creature->SetHealth(scaledCurHealth); - } - creature->ResetPlayerDamageReq(); - } + float percent = creature->GetHealthPct(); + creature->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)scaledBaseHealth); + creature->UpdateMaxHealth(); + if (creature->IsAlive()) + creature->SetHealth(creature->CountPctFromMaxHealth(percent)); + creature->ResetPlayerDamageReq(); } }; @@ -1163,13 +1106,11 @@ class mod_zone_difficulty_playerscript : public PlayerScript void OnPlayerMapChanged(Player* player) override { - uint32 mapId = player->GetMapId(); - if (sZoneDifficulty->DisallowedBuffs.find(mapId) != sZoneDifficulty->DisallowedBuffs.end()) + auto buffIt = sZoneDifficulty->DisallowedBuffs.find(player->GetMapId()); + if (buffIt != sZoneDifficulty->DisallowedBuffs.end()) { - for (auto aura : sZoneDifficulty->DisallowedBuffs[mapId]) - { + for (uint32 aura : buffIt->second) player->RemoveAura(aura); - } } } @@ -1178,20 +1119,22 @@ class mod_zone_difficulty_playerscript : public PlayerScript if (sZoneDifficulty->MythicmodeScore.empty()) return; - if (sZoneDifficulty->MythicmodeScore.find(player->GetGUID().GetCounter()) != sZoneDifficulty->MythicmodeScore.end()) + uint32 guid = player->GetGUID().GetCounter(); + auto scoreIt = sZoneDifficulty->MythicmodeScore.find(guid); + if (scoreIt != sZoneDifficulty->MythicmodeScore.end()) { for (int i = 1; i <= 16; ++i) { uint32 availableScore = 0; - - if (sZoneDifficulty->MythicmodeScore[player->GetGUID().GetCounter()].find(i) != sZoneDifficulty->MythicmodeScore[player->GetGUID().GetCounter()].end()) - availableScore = sZoneDifficulty->MythicmodeScore[player->GetGUID().GetCounter()][i]; + auto typeIt = scoreIt->second.find(i); + if (typeIt != scoreIt->second.end()) + availableScore = typeIt->second; player->UpdatePlayerSetting(ModZoneDifficultyString + "score", i, availableScore); } - sZoneDifficulty->MythicmodeScore.erase(player->GetGUID().GetCounter()); - CharacterDatabase.Execute("DELETE FROM zone_difficulty_mythicmode_score WHERE GUID = {}", player->GetGUID().GetCounter()); + sZoneDifficulty->MythicmodeScore.erase(scoreIt); + CharacterDatabase.Execute("DELETE FROM zone_difficulty_mythicmode_score WHERE GUID = {}", guid); } }