diff options
Diffstat (limited to 'src')
26 files changed, 361 insertions, 108 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 0de13280376..680c0815c6b 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -692,6 +692,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u return; me->DoFleeToGetAssistance(); + if (e.action.flee.withEmote) + sCreatureTextMgr->SendChatString(me, sObjectMgr->GetTrinityStringForDBCLocale(LANG_FLEE), CHAT_MSG_MONSTER_EMOTE); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: Creature %u DoFleeToGetAssistance", me->GetGUIDLow()); break; } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index d6235b05667..de60737f3b6 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -383,7 +383,7 @@ enum SMART_ACTION SMART_ACTION_SET_EVENT_PHASE = 22, // Phase SMART_ACTION_INC_EVENT_PHASE = 23, // Value (may be negative to decrement phase, should not be 0) SMART_ACTION_EVADE = 24, // No Params - SMART_ACTION_FLEE_FOR_ASSIST = 25, // No Params + SMART_ACTION_FLEE_FOR_ASSIST = 25, // With Emote SMART_ACTION_CALL_GROUPEVENTHAPPENS = 26, // QuestID SMART_ACTION_CALL_CASTEDCREATUREORGO = 27, // CreatureId, SpellId SMART_ACTION_REMOVEAURASFROMSPELL = 28, // Spellid @@ -854,6 +854,11 @@ struct SmartAction struct { + uint32 withEmote; + } flee; + + struct + { uint32 param1; uint32 param2; uint32 param3; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index b01385e6536..d5dbdca976f 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -1491,3 +1491,62 @@ void BattlegroundAV::ResetBGSubclass() DelCreature(i); } + +bool BattlegroundAV::IsBothMinesControlledByTeam(uint32 team) const +{ + for (uint8 mine = 0; mine < 2; mine++) + if (m_Mine_Owner[mine] != team) + return false; + + return true; +} + +bool BattlegroundAV::IsAllTowersControlledAndCaptainAlive(uint32 team) const +{ + if (team == ALLIANCE) + { + for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) // alliance towers controlled + { + if (m_Nodes[i].State == POINT_CONTROLED) + { + if (m_Nodes[i].Owner != ALLIANCE) + return false; + } + else + return false; + } + + for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) // horde towers destroyed + if (m_Nodes[i].State != POINT_DESTROYED) + return false; + + if (!m_CaptainAlive[0]) + return false; + + return true; + } + else if (team == HORDE) + { + for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) // horde towers controlled + { + if (m_Nodes[i].State == POINT_CONTROLED) + { + if (m_Nodes[i].Owner != HORDE) + return false; + } + else + return false; + } + + for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) // alliance towers destroyed + if (m_Nodes[i].State != POINT_DESTROYED) + return false; + + if (!m_CaptainAlive[1]) + return false; + + return true; + } + + return false; +}
\ No newline at end of file diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 5832a0f87c5..83fd559fdd4 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -1563,6 +1563,10 @@ class BattlegroundAV : public Battleground virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); + /* achievement req. */ + bool IsBothMinesControlledByTeam(uint32 team) const; + bool IsAllTowersControlledAndCaptainAlive(uint32 team) const; + private: virtual void PostUpdateImpl(uint32 diff); diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h index 12f26022f59..c5466d65d3f 100755 --- a/src/server/game/Chat/Channels/Channel.h +++ b/src/server/game/Chat/Channels/Channel.h @@ -95,12 +95,13 @@ enum ChannelDBCFlags CHANNEL_DBC_FLAG_INITIAL = 0x00001, // General, Trade, LocalDefense, LFG CHANNEL_DBC_FLAG_ZONE_DEP = 0x00002, // General, Trade, LocalDefense, GuildRecruitment CHANNEL_DBC_FLAG_GLOBAL = 0x00004, // WorldDefense - CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade - CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment - CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment + CHANNEL_DBC_FLAG_TRADE = 0x00008, // Trade, LFG + CHANNEL_DBC_FLAG_CITY_ONLY = 0x00010, // Trade, GuildRecruitment, LFG + CHANNEL_DBC_FLAG_CITY_ONLY2 = 0x00020, // Trade, GuildRecruitment, LFG CHANNEL_DBC_FLAG_DEFENSE = 0x10000, // LocalDefense, WorldDefense CHANNEL_DBC_FLAG_GUILD_REQ = 0x20000, // GuildRecruitment - CHANNEL_DBC_FLAG_LFG = 0x40000 // LookingForGroup + CHANNEL_DBC_FLAG_LFG = 0x40000, // LFG + CHANNEL_DBC_FLAG_UNK1 = 0x80000, // General }; enum ChannelMemberFlags diff --git a/src/server/game/Combat/HostileRefManager.cpp b/src/server/game/Combat/HostileRefManager.cpp index 5d9e7d671c8..47e9a1d2508 100755 --- a/src/server/game/Combat/HostileRefManager.cpp +++ b/src/server/game/Combat/HostileRefManager.cpp @@ -40,10 +40,9 @@ void HostileRefManager::threatAssist(Unit* victim, float baseThreat, SpellInfo c threat /= getSize(); while (ref) { - if (victim == getOwner()) - ref->addThreat(threat); // It is faster to modify the threat durectly if possible - else - ref->getSource()->addThreat(victim, threat); + if (ThreatCalcHelper::isValidProcess(victim, ref->getSource()->getOwner(), threatSpell)) + ref->getSource()->doAddThreat(victim, threat); + ref = ref->next(); } } diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index bf3650f611e..858ef057baf 100755 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -36,8 +36,14 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float { if (threatSpell) { - if (threatSpell->AttributesEx & SPELL_ATTR1_NO_THREAT) - return 0.0f; + if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(threatSpell->Id)) + if (threatEntry->pctMod != 1.0f) + threat *= threatEntry->pctMod; + + // Energize is not affected by Mods + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) + if (threatSpell->Effects[i].Effect == SPELL_EFFECT_ENERGIZE || threatSpell->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_ENERGIZE) + return threat; if (Player* modOwner = hatedUnit->GetSpellModOwner()) modOwner->ApplySpellMod(threatSpell->Id, SPELLMOD_THREAT, threat); @@ -46,7 +52,7 @@ float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float return hatedUnit->ApplyTotalThreatModifier(threat, schoolMask); } -bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* /*threatSpell*/) +bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell) { //function deals with adding threat and adding players and pets into ThreatList //mobs, NPCs, guards have ThreatList and HateOfflineList @@ -68,6 +74,10 @@ bool ThreatCalcHelper::isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellIn if (!hatedUnit->isAlive() || !hatingUnit->isAlive()) return false; + // spell not causing threat + if (threatSpell && threatSpell->AttributesEx & SPELL_ATTR1_NO_THREAT) + return false; + ASSERT(hatingUnit->GetTypeId() == TYPEID_UNIT); return true; diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 8f7ce9d8df3..0728a2f838e 100755 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -99,7 +99,7 @@ const std::string CustomSpellDifficultyfmt="ppppp"; const std::string CustomSpellDifficultyIndex="id"; const char SpellDurationfmt[]="niii"; const char SpellEntryfmt[]="niiiiiiiiiiiixixiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiixfffxxxiiiiixxfffxx"; -const std::string CustomSpellEntryfmt="pappppppppaapapapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaaaaaa"; +const std::string CustomSpellEntryfmt="papppppppppppapapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaaaaaa"; const std::string CustomSpellEntryIndex = "Id"; const char SpellFocusObjectfmt[]="nxxxxxxxxxxxxxxxxx"; const char SpellItemEnchantmentfmt[]="nxiiiiiixxxiiissssssssssssssssxiiiiiii"; diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index e17f8163bff..0d91b476fdd 100755 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -441,7 +441,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << uint32(quest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective data << uint32(quest->GetRepObjectiveValue()); // shown in quest log as part of quest objective - data << uint32(quest->GetRepObjectiveFaction2()); // shown in quest log as part of quest objective OPOSITE faction + data << uint32(quest->GetRepObjectiveFaction2()); // shown in quest log as part of quest objective OPPOSITE faction data << uint32(quest->GetRepObjectiveValue2()); // shown in quest log as part of quest objective OPPOSITE faction data << uint32(quest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0 diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8742deb2eb5..e0adb99bc37 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5522,14 +5522,14 @@ void Player::RepopAtGraveyard() bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) { - if (channel->flags & CHANNEL_DBC_FLAG_ZONE_DEP) - { - if (zone->flags & AREA_FLAG_ARENA_INSTANCE) - return false; + if (channel->flags & CHANNEL_DBC_FLAG_ZONE_DEP && zone->flags & AREA_FLAG_ARENA_INSTANCE) + return false; - if ((channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY) && !(zone->flags & AREA_FLAG_CAPITAL)) - return false; - } + if ((channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY) && (!(zone->flags & AREA_FLAG_SLAVE_CAPITAL))) + return false; + + if ((channel->flags & CHANNEL_DBC_FLAG_GUILD_REQ) && GetGuildId()) + return false; return true; } @@ -5577,12 +5577,6 @@ void Player::UpdateLocalChannels(uint32 newZone) { if (ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i)) { - if (!(channel->flags & CHANNEL_DBC_FLAG_ZONE_DEP)) - continue; // Not zone dependent, don't handle it here - - if ((channel->flags & CHANNEL_DBC_FLAG_GUILD_REQ) && GetGuildId()) - continue; // Should not join to these channels automatically - Channel* usedChannel = NULL; for (JoinedChannelsList::iterator itr = m_channels.begin(); itr != m_channels.end(); ++itr) @@ -14636,10 +14630,6 @@ bool Player::CanCompleteQuest(uint32 quest_id) if (repFacId && GetReputationMgr().GetReputation(repFacId) < qInfo->GetRepObjectiveValue()) return false; - uint32 repFacId2 = qInfo->GetRepObjectiveFaction2(); - if (repFacId2 && GetReputationMgr().GetReputation(repFacId2) < qInfo->GetRepObjectiveValue2()) - return false; - return true; } } @@ -15272,6 +15262,16 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); return false; } + + // ReputationObjective2 does not seem to be an objective requirement but a requirement + // to be able to accept the quest + uint32 fIdObj = qInfo->GetRepObjectiveFaction2(); + if (fIdObj && GetReputationMgr().GetReputation(fIdObj) >= qInfo->GetRepObjectiveValue2()) + { + if (msg) + SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); + return false; + } return true; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 4cea8f56005..be46e9b1ffb 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -791,12 +791,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0); if (victim->GetTypeId() != TYPEID_PLAYER) - { - if (spellProto && IsDamageToThreatSpell(spellProto)) - victim->AddThreat(this, damage * 2.0f, damageSchoolMask, spellProto); - else victim->AddThreat(this, (float)damage, damageSchoolMask, spellProto); - } else // victim is a player { // random durability for items (HIT TAKEN) @@ -6603,6 +6598,13 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return true; } } + // Misdirection + if (dummySpell->Id == 34477) + { + triggered_spell_id = 35079; // 4 sec buff on self + target = this; + break; + } break; } case SPELLFAMILY_PALADIN: @@ -10334,6 +10336,9 @@ void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers p SendEnergizeSpellLog(victim, spellID, damage, powerType); // needs to be called after sending spell log victim->ModifyPower(powerType, damage); + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); + victim->getHostileRefManager().threatAssist(this, float(damage) * 0.5f, spellInfo); } uint32 Unit::SpellDamageBonus(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) @@ -11622,30 +11627,6 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons return false; } -bool Unit::IsDamageToThreatSpell(SpellInfo const* spellInfo) const -{ - if (!spellInfo) - return false; - - switch(spellInfo->SpellFamilyName) - { - case SPELLFAMILY_WARLOCK: - if (spellInfo->SpellFamilyFlags[0] == 0x100) // Searing Pain - return true; - break; - case SPELLFAMILY_SHAMAN: - if (spellInfo->SpellFamilyFlags[0] == SPELLFAMILYFLAG_SHAMAN_FROST_SHOCK) - return true; - break; - case SPELLFAMILY_DEATHKNIGHT: - if (spellInfo->SpellFamilyFlags[1] == 0x20000000) // Rune Strike - return true; - break; - } - - return false; -} - void Unit::MeleeDamageBonus(Unit* victim, uint32 *pdamage, WeaponAttackType attType, SpellInfo const* spellProto) { if (!victim) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index e777f16b99a..fb41914d6f7 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1572,8 +1572,6 @@ class Unit : public WorldObject void SendPlaySpellVisual(uint32 id); void SendPlaySpellImpact(uint64 guid, uint32 id); - bool IsDamageToThreatSpell(SpellInfo const* spellInfo) const; - void DeMorph(); void SendAttackStateUpdate(CalcDamageInfo *damageInfo); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index e1b37c121a7..62b2ce0c440 100755 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -3931,28 +3931,28 @@ void ObjectMgr::LoadQuests() // no changes, quest can't be done for this requirement } - if (!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0) + if (!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue != 0) { sLog->outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect", qinfo->GetQuestId(), qinfo->RepObjectiveValue); // warning } - if (!qinfo->RepObjectiveFaction2 && qinfo->RepObjectiveValue2 > 0) + if (!qinfo->RepObjectiveFaction2 && qinfo->RepObjectiveValue2 != 0) { sLog->outErrorDb("Quest %u has `RepObjectiveValue2` = %d but `RepObjectiveFaction2` is 0, value has no effect", qinfo->GetQuestId(), qinfo->RepObjectiveValue2); // warning } - if (!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0) + if (!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue != 0) { sLog->outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect", qinfo->GetQuestId(), qinfo->RequiredMinRepValue); // warning } - if (!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0) + if (!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue != 0) { sLog->outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect", qinfo->GetQuestId(), qinfo->RequiredMaxRepValue); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index e824a3cf5da..9e8a4b17f84 100755 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -943,6 +943,7 @@ enum TrinityStrings LANG_GOINFO_LOOTID = 5028, LANG_COMMAND_LOOKUP_MAX_RESULTS = 5029, // Room for more Trinity strings 5030-9999 + LANG_FLEE = 5030, // Level requirement notifications LANG_SAY_REQ = 6604, diff --git a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp b/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp index 0ccfce64045..3f9609bc0e0 100755 --- a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp @@ -26,21 +26,15 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) uint32 channel_id; uint8 unknown1, unknown2; std::string channelname, pass; + ChatChannelsEntry const* channel; recvPacket >> channel_id; if (channel_id) { - ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(channel_id); + channel = sChatChannelsStore.LookupEntry(channel_id); if (!channel) return; - - AreaTableEntry const* current_zone = GetAreaEntryByAreaID(_player->GetZoneId()); - if (!current_zone) - return; - - if (!_player->CanJoinConstantChannelInZone(channel, current_zone)) - return; } recvPacket >> unknown1 >> unknown2; @@ -50,6 +44,14 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) return; recvPacket >> pass; + + AreaTableEntry const* current_zone = GetAreaEntryByAreaID(_player->GetZoneId()); + if (!current_zone) + return; + + if (!_player->CanJoinConstantChannelInZone(channel, current_zone)) + return; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) { cMgr->team = _player->GetTeam(); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 8b68bff0a56..0fe54f2f2e8 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -4927,22 +4927,18 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool case SPELLFAMILY_PRIEST: // Vampiric Touch if (m_spellInfo->SpellFamilyFlags[1] & 0x0400 && aurApp->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && GetEffIndex() == 0) - { if (AuraEffect const* aurEff = GetBase()->GetEffect(1)) { int32 damage = aurEff->GetAmount() * 8; // backfire damage target->CastCustomSpell(target, 64085, &damage, NULL, NULL, true, NULL, NULL, GetCasterGUID()); } - } break; case SPELLFAMILY_WARLOCK: // Haunt if (m_spellInfo->SpellFamilyFlags[1] & 0x40000) - { if (caster) target->CastCustomSpell(caster, 48210, &m_amount, 0, 0, true, NULL, this, GetCasterGUID()); - } break; case SPELLFAMILY_DRUID: // Lifebloom @@ -4965,9 +4961,16 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool } break; case SPELLFAMILY_HUNTER: - // Misdirection - if (GetId() == 34477) - target->SetReducedThreatPercent(0, 0); + switch (GetId()) + { + case 34477: // Misdirection + if (aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) + target->SetReducedThreatPercent(0, 0); + break; + case 35079: // Misdirection proc + target->SetReducedThreatPercent(0, 0); + break; + } break; case SPELLFAMILY_DEATHKNIGHT: // Summon Gargoyle (Dismiss Gargoyle at remove) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index ed36a4ae208..5642df13d8a 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2335,7 +2335,7 @@ void Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur) } else { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id); + sLog->outError("SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id); Unit* target = NULL; if (uint64 guid = m_caster->GetUInt64Value(UNIT_FIELD_TARGET)) target = ObjectAccessor::GetUnit(*m_caster, guid); @@ -4536,20 +4536,53 @@ void Spell::TakeReagents() void Spell::HandleThreatSpells() { - if (!m_targets.GetUnitTarget()) + if (m_UniqueTargetInfo.empty()) return; - if (!m_targets.GetUnitTarget()->CanHaveThreatList()) + if ((m_spellInfo->AttributesEx & SPELL_ATTR1_NO_THREAT) || + (m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO)) return; - uint16 threat = sSpellMgr->GetSpellThreat(m_spellInfo->Id); + float threat = 0.0f; + if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id)) + { + if (threatEntry->apPctMod != 0.0f) + threat += threatEntry->apPctMod * m_caster->GetTotalAttackPowerValue(BASE_ATTACK); + + threat += threatEntry->flatMod; + } + else if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_NO_INITIAL_THREAT) == 0) + threat += m_spellInfo->SpellLevel; - if (!threat) + // past this point only multiplicative effects occur + if (threat == 0.0f) return; - m_targets.GetUnitTarget()->AddThreat(m_caster, float(threat)); + // since 2.0.1 threat from positive effects also is distributed among all targets, so the overall caused threat is at most the defined bonus + threat /= m_UniqueTargetInfo.size(); + + for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + { + if (ihit->missCondition != SPELL_MISS_NONE) + continue; + + Unit* target = ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); + if (!target) + continue; + + // positive spells distribute threat among all units that are in combat with target, like healing + if (m_spellInfo->_IsPositiveSpell()) + target->getHostileRefManager().threatAssist(m_caster, threat, m_spellInfo); + // for negative spells threat gets distributed among affected targets + else + { + if (!target->CanHaveThreatList()) + continue; - sLog->outStaticDebug("Spell %u, rank %u, added an additional %i threat", m_spellInfo->Id, m_spellInfo->GetRank(), threat); + target->AddThreat(m_caster, threat, m_spellInfo->GetSchoolMask(), m_spellInfo); + } + } + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell %u, added an additional %f threat for %s %u target(s)", m_spellInfo->Id, threat, m_spellInfo->_IsPositiveSpell() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size())); } void Spell::HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGOTarget, uint32 i) @@ -4723,7 +4756,8 @@ SpellCastResult Spell::CheckCast(bool strict) } { - SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(m_caster, m_targets.GetObjectTarget()); + // Check explicit target for m_originalCaster - todo: get rid of such workarounds + SpellCastResult castResult = m_spellInfo->CheckExplicitTarget(m_originalCaster ? m_originalCaster : m_caster, m_targets.GetObjectTarget(), m_targets.GetItemTarget()); if (castResult != SPELL_CAST_OK) return castResult; } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 93f9640b92a..8dd1cc0242d 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3275,6 +3275,7 @@ void Spell::EffectDistract(SpellEffIndex /*effIndex*/) unitTarget->SetOrientation(angle); unitTarget->StopMoving(); unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS); + unitTarget->SendMovementFlagUpdate(); } } diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 04e90d2083b..3e374b62cd1 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1721,13 +1721,14 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, Unit const* target, b return SPELL_CAST_OK; } -SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject const* target) const +SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget) const { uint32 neededTargets = GetExplicitTargetMask(); if (!target) { if (neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT_MASK | TARGET_FLAG_CORPSE_MASK)) - return SPELL_FAILED_BAD_TARGETS; + if (!(neededTargets & TARGET_FLAG_GAMEOBJECT_ITEM) || !itemTarget) + return SPELL_FAILED_BAD_TARGETS; return SPELL_CAST_OK; } diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 69f160cbb0f..b79e50db001 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -24,6 +24,7 @@ class Unit; class Player; +class Item; class Spell; class SpellInfo; struct SpellChainNode; @@ -186,7 +187,7 @@ enum SpellCustomAttributes SPELL_ATTR0_CU_CONE_BACK = 0x00000002, SPELL_ATTR0_CU_CONE_LINE = 0x00000004, SPELL_ATTR0_CU_SHARE_DAMAGE = 0x00000008, - SPELL_ATTR0_CU_NONE1 = 0x00000010, // UNUSED + SPELL_ATTR0_CU_NO_INITIAL_THREAT = 0x00000010, SPELL_ATTR0_CU_NONE2 = 0x00000020, // UNUSED SPELL_ATTR0_CU_AURA_CC = 0x00000040, SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100, @@ -442,7 +443,7 @@ public: SpellCastResult CheckShapeshift(uint32 form) const; SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const; SpellCastResult CheckTarget(Unit const* caster, Unit const* target, bool implicit = true) const; - SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target) const; + SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const; bool CheckTargetCreatureType(Unit const* target) const; SpellSchoolMask GetSchoolMask() const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 3b546a94bfa..85139061303 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -965,13 +965,19 @@ SpellBonusEntry const* SpellMgr::GetSpellBonusData(uint32 spellId) const return NULL; } -uint16 SpellMgr::GetSpellThreat(uint32 spellid) const +SpellThreatEntry const* SpellMgr::GetSpellThreatEntry(uint32 spellID) const { - SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellid); - if (itr == mSpellThreatMap.end()) - return 0; - - return itr->second; + SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellID); + if (itr != mSpellThreatMap.end()) + return &itr->second; + else + { + uint32 firstSpell = GetFirstSpellInChain(spellID); + SpellThreatMap::const_iterator itr = mSpellThreatMap.find(firstSpell); + if (itr != mSpellThreatMap.end()) + return &itr->second; + } + return NULL; } SkillLineAbilityMapBounds SpellMgr::GetSkillLineAbilityMapBounds(uint32 spell_id) const @@ -1940,8 +1946,8 @@ void SpellMgr::LoadSpellThreats() uint32 count = 0; - // 0 1 - QueryResult result = WorldDatabase.Query("SELECT entry, Threat FROM spell_threat"); + // 0 1 2 3 + QueryResult result = WorldDatabase.Query("SELECT entry, flatMod, pctMod, apPctMod FROM spell_threat"); if (!result) { sLog->outString(">> Loaded 0 aggro generating spells"); @@ -1954,7 +1960,6 @@ void SpellMgr::LoadSpellThreats() Field *fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); - uint16 Threat = fields[1].GetUInt16(); if (!GetSpellInfo(entry)) { @@ -1962,12 +1967,16 @@ void SpellMgr::LoadSpellThreats() continue; } - mSpellThreatMap[entry] = Threat; + SpellThreatEntry ste; + ste.flatMod = fields[1].GetInt16(); + ste.pctMod = fields[2].GetFloat(); + ste.apPctMod = fields[3].GetFloat(); - ++count; + mSpellThreatMap[entry] = ste; + count++; } while (result->NextRow()); - sLog->outString(">> Loaded %u aggro generating spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + sLog->outString(">> Loaded %u SpellThreatEntries in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); sLog->outString(); } @@ -2634,6 +2643,18 @@ void SpellMgr::LoadSpellCustomAttr() case SPELL_AURA_MOD_STUN: spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC; break; + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: + case SPELL_AURA_PERIODIC_LEECH: + case SPELL_AURA_PERIODIC_MANA_LEECH: + case SPELL_AURA_PERIODIC_HEALTH_FUNNEL: + case SPELL_AURA_PERIODIC_ENERGIZE: + case SPELL_AURA_OBS_MOD_HEALTH: + case SPELL_AURA_OBS_MOD_POWER: + case SPELL_AURA_POWER_BURN: + spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT; + break; } switch (spellInfo->Effects[j].Effect) @@ -2646,6 +2667,16 @@ void SpellMgr::LoadSpellCustomAttr() case SPELL_EFFECT_HEAL: spellInfo->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE; break; + case SPELL_EFFECT_POWER_DRAIN: + case SPELL_EFFECT_POWER_BURN: + case SPELL_EFFECT_HEAL_MAX_HEALTH: + case SPELL_EFFECT_HEALTH_LEECH: + case SPELL_EFFECT_HEAL_PCT: + case SPELL_EFFECT_ENERGIZE_PCT: + case SPELL_EFFECT_ENERGIZE: + case SPELL_EFFECT_HEAL_MECHANICAL: + spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT; + break; case SPELL_EFFECT_CHARGE: case SPELL_EFFECT_CHARGE_DEST: case SPELL_EFFECT_JUMP: @@ -3032,6 +3063,7 @@ void SpellMgr::LoadDbcDataCorrections() case 57761: // Fireball! case 39805: // Lightning Overload case 64823: // Item - Druid T8 Balance 4P Bonus + case 34477: // Misdirection case 44401: // Missile Barrage spellInfo->procCharges = 1; break; diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index e8ac3ce9862..64d21b7c3a5 100755 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -349,7 +349,14 @@ enum SpellGroupStackRule typedef std::map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap; -typedef std::map<uint32, uint16> SpellThreatMap; +struct SpellThreatEntry +{ + int32 flatMod; // flat threat-value for this Spell - default: 0 + float pctMod; // threat-multiplier for this Spell - default: 1.0f + float apPctMod; // Pct of AP that is added as Threat - default: 0.0f +}; + +typedef std::map<uint32, SpellThreatEntry> SpellThreatMap; // Spell script target related declarations (accessed using SpellMgr functions) enum SpellScriptTargetType @@ -603,7 +610,7 @@ class SpellMgr SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const; // Spell threat table - uint16 GetSpellThreat(uint32 spellid) const; + SpellThreatEntry const* GetSpellThreatEntry(uint32 spellID) const; SkillLineAbilityMapBounds GetSkillLineAbilityMapBounds(uint32 spell_id) const; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp index 91cd8dee55c..7566d9bc410 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp @@ -85,7 +85,6 @@ class instance_trial_of_the_crusader : public InstanceMapScript EventStage = 0; TributeChestGUID = 0; - DataDamageTwin = 0; MainGateDoorGUID = 0; EastPortcullisGUID = 0; diff --git a/src/server/scripts/Northrend/VaultOfArchavon/instance_vault_of_archavon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/instance_vault_of_archavon.cpp index 904566e13a4..8d668011f9a 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/instance_vault_of_archavon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/instance_vault_of_archavon.cpp @@ -41,6 +41,9 @@ class instance_archavon : public InstanceMapScript { EmalonGUID = 0; ToravonGUID = 0; + ArchavonDeath = 0; + EmalonDeath = 0; + KoralonDeath = 0; } void OnCreatureCreate(Creature* creature) @@ -73,9 +76,63 @@ class instance_archavon : public InstanceMapScript return 0; } + bool SetBossState(uint32 type, EncounterState state) + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + if (state != DONE) + return true; + + switch (type) + { + case DATA_ARCHAVON: + ArchavonDeath = time(NULL); + break; + case DATA_EMALON: + EmalonDeath = time(NULL); + break; + case DATA_KORALON: + KoralonDeath = time(NULL); + break; + default: + return true; + } + + // on every death of Archavon, Emalon and Koralon check our achievement + DoCastSpellOnPlayers(SPELL_EARTH_WIND_FIRE_ACHIEVEMENT_CHECK); + + return true; + } + + bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) + { + switch (criteria_id) + { + case CRITERIA_EARTH_WIND_FIRE_10: + case CRITERIA_EARTH_WIND_FIRE_25: + if (ArchavonDeath && EmalonDeath && KoralonDeath) + { + // instance difficulty check is already done in db (achievement_criteria_data) + // int() for Visual Studio, compile errors with abs(time_t) + return (abs(int(ArchavonDeath-EmalonDeath)) < MINUTE && \ + abs(int(EmalonDeath-KoralonDeath)) < MINUTE && \ + abs(int(KoralonDeath-ArchavonDeath)) < MINUTE); + } + break; + default: + break; + } + + return false; + } + private: uint64 EmalonGUID; uint64 ToravonGUID; + time_t ArchavonDeath; + time_t EmalonDeath; + time_t KoralonDeath; }; InstanceScript* GetInstanceScript(InstanceMap* map) const diff --git a/src/server/scripts/Northrend/VaultOfArchavon/vault_of_archavon.h b/src/server/scripts/Northrend/VaultOfArchavon/vault_of_archavon.h index 4aa01e58f5f..04f50d3adeb 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/vault_of_archavon.h +++ b/src/server/scripts/Northrend/VaultOfArchavon/vault_of_archavon.h @@ -36,4 +36,15 @@ enum Data #define MAX_ENCOUNTER 4 +enum AchievementCriteriaIds +{ + CRITERIA_EARTH_WIND_FIRE_10 = 12018, + CRITERIA_EARTH_WIND_FIRE_25 = 12019, +}; + +enum AchievementSpells +{ + SPELL_EARTH_WIND_FIRE_ACHIEVEMENT_CHECK = 68308, +}; + #endif diff --git a/src/server/scripts/World/achievement_scripts.cpp b/src/server/scripts/World/achievement_scripts.cpp index db09c12da0b..af966e3e22e 100755 --- a/src/server/scripts/World/achievement_scripts.cpp +++ b/src/server/scripts/World/achievement_scripts.cpp @@ -21,6 +21,7 @@ #include "BattlegroundWS.h" #include "BattlegroundIC.h" #include "BattlegroundSA.h" +#include "BattlegroundAV.h" #include "Vehicle.h" class achievement_storm_glory : public AchievementCriteriaScript @@ -207,6 +208,48 @@ public: } }; +class achievement_everything_counts : public AchievementCriteriaScript +{ + public: + achievement_everything_counts() : AchievementCriteriaScript("achievement_everything_counts") { } + + bool OnCheck(Player* source, Unit* /*target*/) + { + Battleground* bg = source->GetBattleground(); + if (!bg) + return false; + + if (source->GetBattlegroundTypeId() != BATTLEGROUND_AV) + return false; + + if (static_cast<BattlegroundAV*>(bg)->IsBothMinesControlledByTeam(source->GetTeam())) + return true; + + return false; + } +}; + +class achievement_bg_av_perfection : public AchievementCriteriaScript +{ + public: + achievement_bg_av_perfection() : AchievementCriteriaScript("achievement_bg_av_perfection") { } + + bool OnCheck(Player* source, Unit* /*target*/) + { + Battleground* bg = source->GetBattleground(); + if (!bg) + return false; + + if (source->GetBattlegroundTypeId() != BATTLEGROUND_AV) + return false; + + if (static_cast<BattlegroundAV*>(bg)->IsAllTowersControlledAndCaptainAlive(source->GetTeam())) + return true; + + return false; + } +}; + class achievement_wg_didnt_stand_a_chance : public AchievementCriteriaScript { public: @@ -269,6 +312,8 @@ void AddSC_achievement_scripts() new achievement_bg_sa_artillery(); new achievement_sickly_gazelle(); new achievement_wg_didnt_stand_a_chance(); + new achievement_everything_counts(); + new achievement_bg_av_perfection(); new achievement_arena_kills("achievement_arena_2v2_kills", ARENA_TYPE_2v2); new achievement_arena_kills("achievement_arena_3v3_kills", ARENA_TYPE_3v3); new achievement_arena_kills("achievement_arena_5v5_kills", ARENA_TYPE_5v5); |