diff options
Diffstat (limited to 'src')
32 files changed, 400 insertions, 176 deletions
diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index b9d385ba675..f4555649210 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -33,21 +33,24 @@ class GameObjectAI explicit GameObjectAI(GameObject* g) : go(g) {} virtual ~GameObjectAI() {} - virtual void UpdateAI(const uint32 /*diff*/) {} + virtual void UpdateAI(uint32 /*diff*/) {} virtual void InitializeAI() { Reset(); } virtual void Reset() {}; - static int Permissible(const GameObject* go); + static int Permissible(GameObject const* go); - virtual bool GossipHello(Player* /*player*/) {return false;} - virtual bool GossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) {return false;} - virtual bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) {return false;} - virtual bool QuestAccept(Player* /*player*/, Quest const* /*quest*/) {return false;} - virtual bool QuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) {return false;} - virtual uint32 GetDialogStatus(Player* /*player*/) {return 100;} + virtual bool GossipHello(Player* /*player*/) { return false; } + virtual bool GossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) { return false; } + virtual bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, char const* /*code*/) { return false; } + virtual bool QuestAccept(Player* /*player*/, Quest const* /*quest*/) { return false; } + virtual bool QuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) { return false; } + virtual uint32 GetDialogStatus(Player* /*player*/) { return 100; } virtual void Destroyed(Player* /*player*/, uint32 /*eventId*/) {} + virtual uint32 GetData(uint32 /*id*/) { return 0; } + virtual void SetData64(uint32 /*id*/, uint64 /*value*/) {} + virtual uint64 GetData64(uint32 /*id*/) { return 0; } virtual void SetData(uint32 /*id*/, uint32 /*value*/) {} virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) {} virtual void OnStateChanged(uint32 /*state*/, Unit* /*unit*/) { } @@ -58,8 +61,8 @@ class NullGameObjectAI : public GameObjectAI public: explicit NullGameObjectAI(GameObject* g); - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} - static int Permissible(const GameObject* /*go*/) { return PERMIT_BASE_IDLE; } + static int Permissible(GameObject const* /*go*/) { return PERMIT_BASE_IDLE; } }; #endif diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index ebe14c0d7d0..1a0c6652e74 100755 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -133,6 +133,9 @@ namespace FactorySelector const GameObjectAICreator* ai_factory = NULL; GameObjectAIRegistry& ai_registry(*GameObjectAIRepository::instance()); + if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) + return scriptedAI; + ai_factory = ai_registry.GetRegistryItem(go->GetAIName()); //future goAI types go here diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 4eb7f8a7f50..2a412bffb22 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -854,7 +854,7 @@ int SmartGameObjectAI::Permissible(const GameObject* g) return PERMIT_BASE_NO; } -void SmartGameObjectAI::UpdateAI(const uint32 diff) +void SmartGameObjectAI::UpdateAI(uint32 diff) { GetScript()->OnUpdate(diff); } diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 94e5e65cf8b..bfd1c7b9d41 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -239,7 +239,7 @@ public: SmartGameObjectAI(GameObject* g) : GameObjectAI(g), go(g) {} ~SmartGameObjectAI() {} - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); void InitializeAI(); void Reset(); SmartScript* GetScript() { return &mScript; } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index d6bfde021e7..44192a74123 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -144,6 +144,7 @@ Battleground::Battleground() m_Winner = 2; m_StartTime = 0; m_ResetStatTimer = 0; + m_ValidStartPositionTimer = 0; m_Events = 0; m_IsRated = false; m_BuffChange = false; @@ -177,6 +178,8 @@ Battleground::Battleground() m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0; m_ArenaTeamIds[BG_TEAM_HORDE] = 0; + m_StartMaxDist = 0.0f; + m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0; m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0; @@ -291,6 +294,7 @@ void Battleground::Update(uint32 diff) // Update start time and reset stats timer m_StartTime += diff; m_ResetStatTimer += diff; + m_ValidStartPositionTimer += diff; PostUpdateImpl(diff); } @@ -422,7 +426,7 @@ inline void Battleground::_ProcessJoin(uint32 diff) // ********************************************************* ModifyStartDelayTime(diff); - if (m_ResetStatTimer <= 5000) + if (m_ResetStatTimer > 5000) { m_ResetStatTimer = 0; for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) @@ -453,19 +457,19 @@ inline void Battleground::_ProcessJoin(uint32 diff) // First start warning - 2 or 1 minute SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL); } - // After 1 minute or 30 seconds, warning is signalled + // After 1 minute or 30 seconds, warning is signaled else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2)) { m_Events |= BG_STARTING_EVENT_2; SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL); } - // After 30 or 15 seconds, warning is signalled + // After 30 or 15 seconds, warning is signaled else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3)) { m_Events |= BG_STARTING_EVENT_3; SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL); } - // Delay expired (atfer 2 or 1 minute) + // Delay expired (after 2 or 1 minute) else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4)) { m_Events |= BG_STARTING_EVENT_4; @@ -526,6 +530,33 @@ inline void Battleground::_ProcessJoin(uint32 diff) sWorld->SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel()); } } + + // Find if the player left our start zone; if so, teleport it back + if (m_ValidStartPositionTimer > 1000) + { + m_ValidStartPositionTimer = 0; + float maxDist = GetStartMaxDist(); + if (maxDist > 0.0f) + { + for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) + { + if (Player *plr = ObjectAccessor::FindPlayer(itr->first)) + { + float x, y, z, o; + uint32 team = plr->GetBGTeam(); + GetTeamStartLoc(team, x, y, z, o); + + float dist = plr->GetDistance(x, y, z); + + if (dist >= maxDist) + { + sLog->outError("BATTLEGROUND: Sending %s back to start location (possible exploit)", plr->GetName()); + plr->TeleportTo(GetMapId(), x, y, z, o); + } + } + } + } + } } inline void Battleground::_ProcessLeave(uint32 diff) diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 32f6ebc92de..01dfbb23033 100755 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -443,6 +443,8 @@ class Battleground Z = m_TeamStartLocZ[idx]; O = m_TeamStartLocO[idx]; } + void SetStartMaxDist(float startMaxDist) { m_StartMaxDist = startMaxDist; } + float GetStartMaxDist() const { return m_StartMaxDist; } // Packet Transfer // method that should fill worldpacket with actual world states (not yet implemented for all battlegrounds!) @@ -617,6 +619,7 @@ class Battleground uint32 m_ClientInstanceID; // the instance-id which is sent to the client and without any other internal use uint32 m_StartTime; uint32 m_ResetStatTimer; + uint32 m_ValidStartPositionTimer; int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself uint32 m_LastResurrectTime; BattlegroundBracketId m_BracketId; @@ -698,6 +701,7 @@ class Battleground float m_TeamStartLocY[BG_TEAMS_COUNT]; float m_TeamStartLocZ[BG_TEAMS_COUNT]; float m_TeamStartLocO[BG_TEAMS_COUNT]; + float m_StartMaxDist; uint32 ScriptId; }; #endif diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index e1b99cbdcb9..a106f11ae82 100755 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -660,6 +660,7 @@ uint32 BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data) bg->SetName(data.BattlegroundName); bg->SetTeamStartLoc(ALLIANCE, data.Team1StartLocX, data.Team1StartLocY, data.Team1StartLocZ, data.Team1StartLocO); bg->SetTeamStartLoc(HORDE, data.Team2StartLocX, data.Team2StartLocY, data.Team2StartLocZ, data.Team2StartLocO); + bg->SetStartMaxDist(data.StartMaxDist); bg->SetLevelRange(data.LevelMin, data.LevelMax); bg->SetScriptId(data.scriptId); @@ -677,8 +678,8 @@ void BattlegroundMgr::CreateInitialBattlegrounds() uint8 selectionWeight; BattlemasterListEntry const* bl; - // 0 1 2 3 4 5 6 7 8 9 10 - QueryResult result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, AllianceStartO, HordeStartLoc, HordeStartO, Weight, ScriptName FROM battleground_template"); + // 0 1 2 3 4 5 6 7 8 9 10 11 + QueryResult result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, AllianceStartO, HordeStartLoc, HordeStartO, StartMaxDist, Weight, ScriptName FROM battleground_template"); if (!result) { @@ -712,17 +713,20 @@ void BattlegroundMgr::CreateInitialBattlegrounds() data.MaxPlayersPerTeam = fields[2].GetUInt16(); data.LevelMin = fields[3].GetUInt8(); data.LevelMax = fields[4].GetUInt8(); - //check values from DB - if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam) + + // check values from DB + if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam) { - data.MinPlayersPerTeam = 0; // by default now expected strong full bg requirement - data.MaxPlayersPerTeam = 40; + sLog->outErrorDb("Table `battleground_template` for id %u has bad values for MinPlayersPerTeam (%u) and MaxPlayersPerTeam(%u)", + data.bgTypeId, data.MinPlayersPerTeam, data.MaxPlayersPerTeam); + continue; } + if (data.LevelMin == 0 || data.LevelMax == 0 || data.LevelMin > data.LevelMax) { - //TO-DO: FIX ME - data.LevelMin = 0;//bl->minlvl; - data.LevelMax = 80;//bl->maxlvl; + sLog->outErrorDb("Table `battleground_template` for id %u has bad values for LevelMin (%u) and LevelMax(%u)", + data.bgTypeId, data.LevelMin, data.LevelMax); + continue; } startId = fields[5].GetUInt32(); @@ -767,8 +771,10 @@ void BattlegroundMgr::CreateInitialBattlegrounds() continue; } - selectionWeight = fields[9].GetUInt8(); - data.scriptId = sObjectMgr->GetScriptId(fields[10].GetCString()); + data.StartMaxDist = fields[9].GetFloat(); + + selectionWeight = fields[10].GetUInt8(); + data.scriptId = sObjectMgr->GetScriptId(fields[11].GetCString()); data.BattlegroundName = bl->name[sWorld->GetDefaultDbcLocale()]; data.MapID = bl->mapid[0]; diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 88559d07993..7afb83da0a6 100755 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -50,6 +50,7 @@ struct CreateBattlegroundData float Team2StartLocY; float Team2StartLocZ; float Team2StartLocO; + float StartMaxDist; uint32 scriptId; }; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index fcb89e33dc1..586f09bd79c 100755 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1041,6 +1041,13 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4))); break; } + case 28017: // Bloodworms + { + SetCreateHealth(4 * petlevel); + SetBonusDamage(int32(m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.006f)); + SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - 30 - (petlevel / 4))); + SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel - 30 + (petlevel / 4))); + } } break; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 26ea7c110d2..31bd17ffc8f 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -6830,11 +6830,6 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation, bool t if (GetGroup()) SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION); - // code block for underwater state update - // Unit::UpdatePosition() checks for validity and updates our coordinates - // so we re-fetch them instead of using "raw" coordinates from function params - UpdateUnderwaterState(GetMap(), GetPositionX(), GetPositionY(), GetPositionZ()); - if (GetTrader() && !IsWithinDistInMap(GetTrader(), INTERACTION_DISTANCE)) GetSession()->SendCancelTrade(); @@ -17657,7 +17652,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) ItemPosCountVec dest; err = CanStoreItem(itr->second->GetSlot(), slot, dest, item); if (err == EQUIP_ERR_OK) - itr->second->StoreItem(slot, item, true); + item = StoreItem(dest, item, true); } } @@ -18318,10 +18313,10 @@ void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficu CharacterDatabase.Execute(stmt); } - itr->second.save->RemovePlayer(this); // save can become invalid if (itr->second.perm) GetSession()->SendCalendarRaidLockout(itr->second.save, false); + itr->second.save->RemovePlayer(this); // save can become invalid m_boundInstances[difficulty].erase(itr++); } } diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 69771129ac9..2da1c1b88cb 100755 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -1068,6 +1068,7 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType) #define ENTRY_TREANT 1964 #define ENTRY_FIRE_ELEMENTAL 15438 #define ENTRY_GHOUL 26125 +#define ENTRY_BLOODWORM 28017 bool Guardian::UpdateStats(Stats stat) { @@ -1229,6 +1230,7 @@ void Guardian::UpdateMaxHealth() case ENTRY_SUCCUBUS: multiplicator = 9.1f; break; case ENTRY_FELHUNTER: multiplicator = 9.5f; break; case ENTRY_FELGUARD: multiplicator = 11.0f; break; + case ENTRY_BLOODWORM: multiplicator = 1.0f; break; default: multiplicator = 10.0f; break; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index eebfd25e3d4..da23a7ba010 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -252,6 +252,7 @@ m_HostileRefManager(this) _focusSpell = NULL; _targetLocked = false; + _lastLiquid = NULL; } //////////////////////////////////////////////////////////// @@ -1542,7 +1543,7 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe // Magic damage, check for resists // Ignore spells that cant be resisted - if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0 && (spellInfo && (spellInfo->AttributesEx4 & SPELL_ATTR4_IGNORE_RESISTANCES) == 0)) + if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0 && (!spellInfo || (spellInfo->AttributesEx4 & SPELL_ATTR4_IGNORE_RESISTANCES) == 0)) { float victimResistance = float(victim->GetResistance(schoolMask)); victimResistance += float(GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask)); @@ -3089,6 +3090,48 @@ bool Unit::IsUnderWater() const return GetBaseMap()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ()); } +void Unit::UpdateUnderwaterState(Map* m, float x, float y, float z) +{ + if (!isPet() && !IsVehicle()) + return; + + LiquidData liquid_status; + ZLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status); + if (!res) + { + if (_lastLiquid && _lastLiquid->SpellId) + RemoveAurasDueToSpell(_lastLiquid->SpellId); + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER); + _lastLiquid = NULL; + return; + } + + if (uint32 liqEntry = liquid_status.entry) + { + LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry); + if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid->Id != liqEntry) + RemoveAurasDueToSpell(_lastLiquid->SpellId); + + if (liquid && liquid->SpellId) + { + if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER)) + CastSpell(this, liquid->SpellId, true); + else + RemoveAurasDueToSpell(liquid->SpellId); + } + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER); + _lastLiquid = liquid; + } + else if (_lastLiquid && _lastLiquid->SpellId) + { + RemoveAurasDueToSpell(_lastLiquid->SpellId); + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER); + _lastLiquid = NULL; + } +} + void Unit::DeMorph() { SetDisplayId(GetNativeDisplayId()); @@ -6000,6 +6043,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Siphon Life case 63108: { + if (!damage) + break; // Glyph of Siphon Life if (HasAura(56216)) triggerAmount += triggerAmount / 4; @@ -7354,20 +7399,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 63685; break; } - // Storm, Earth and Fire - if (dummySpell->SpellIconID == 3063) - { - // Earthbind Totem summon only - if (procSpell->Id != 2484) - return false; - - float chance = (float)triggerAmount; - if (!roll_chance_f(chance)) - return false; - - triggered_spell_id = 64695; - break; - } // Ancestral Awakening if (dummySpell->SpellIconID == 3065) { @@ -7396,8 +7427,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (GetTypeId() != TYPEID_PLAYER || !victim || !victim->isAlive() || !castItem || !castItem->IsEquipped()) return false; - Player* player = ToPlayer(); - WeaponAttackType attType = WeaponAttackType(player->GetAttackBySlot(castItem->GetSlot())); + WeaponAttackType attType = WeaponAttackType(Player::GetAttackBySlot(castItem->GetSlot())); if ((attType != BASE_ATTACK && attType != OFF_ATTACK) || (attType == BASE_ATTACK && procFlag & PROC_FLAG_DONE_OFFHAND_ATTACK) || (attType == OFF_ATTACK && procFlag & PROC_FLAG_DONE_MAINHAND_ATTACK)) @@ -7985,11 +8015,7 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp for (uint8 i = 1; i < stack; ++i) dmg += mod * stack; if (Unit* caster = triggeredByAura->GetCaster()) - { caster->CastCustomSpell(70701, SPELLVALUE_BASE_POINT0, dmg); - if (Creature* creature = caster->ToCreature()) - creature->DespawnOrUnsummon(1); - } break; } // Ball of Flames Proc @@ -8200,6 +8226,16 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp CastCustomSpell(this, 70845, &basepoints0, NULL, NULL, true); break; } + // Recklessness + case 1719: + { + //! Possible hack alert + //! Don't drop charges on proc, they will be dropped on SpellMod removal + //! Before this change, it was dropping two charges per attack, one in ProcDamageAndSpellFor, and one in RemoveSpellMods. + //! The reason of this behaviour is Recklessness having three auras, 2 of them can not proc (isTriggeredAura array) but the other one can, making the whole spell proc. + *handled = true; + break; + } default: break; } @@ -17262,6 +17298,9 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel else if (turn) UpdateOrientation(orientation); + // code block for underwater state update + UpdateUnderwaterState(GetMap(), x, y, z); + return (relocated || turn); } @@ -17566,7 +17605,7 @@ bool Unit::SetWalk(bool enable) return true; } -bool Unit::SetDisableGravity(bool disable, bool packetOnly /*= false*/) +bool Unit::SetDisableGravity(bool disable, bool /*packetOnly = false*/) { if (disable == IsLevitating()) return false; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 00d66518d3f..828d87216df 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1580,6 +1580,7 @@ class Unit : public WorldObject virtual bool IsInWater() const; virtual bool IsUnderWater() const; + virtual void UpdateUnderwaterState(Map* m, float x, float y, float z); bool isInAccessiblePlaceFor(Creature const* c) const; void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false); @@ -2353,6 +2354,7 @@ class Unit : public WorldObject uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; uint32 m_lastManaUse; // msecs + LiquidTypeEntry const* _lastLiquid; TimeTrackerSmall m_movesplineTimer; Diminishing m_Diminishing; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 22f0ea35413..0386e6b4214 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -3294,20 +3294,20 @@ enum BanReturn // indexes of BattlemasterList.dbc enum BattlegroundTypeId { - BATTLEGROUND_TYPE_NONE = 0, - BATTLEGROUND_AV = 1, - BATTLEGROUND_WS = 2, - BATTLEGROUND_AB = 3, - BATTLEGROUND_NA = 4, - BATTLEGROUND_BE = 5, - BATTLEGROUND_AA = 6, - BATTLEGROUND_EY = 7, - BATTLEGROUND_RL = 8, - BATTLEGROUND_SA = 9, - BATTLEGROUND_DS = 10, - BATTLEGROUND_RV = 11, - BATTLEGROUND_IC = 30, - BATTLEGROUND_RB = 32 + BATTLEGROUND_TYPE_NONE = 0, // None + BATTLEGROUND_AV = 1, // Alterac Valley + BATTLEGROUND_WS = 2, // Warsong Gulch + BATTLEGROUND_AB = 3, // Arathi Basin + BATTLEGROUND_NA = 4, // Nagrand Arena + BATTLEGROUND_BE = 5, // Blade's Edge Arena + BATTLEGROUND_AA = 6, // All Arenas + BATTLEGROUND_EY = 7, // Eye of the Storm + BATTLEGROUND_RL = 8, // Ruins of Lordaernon + BATTLEGROUND_SA = 9, // Strand of the Ancients + BATTLEGROUND_DS = 10, // Dalaran Sewers + BATTLEGROUND_RV = 11, // Ring of Valor + BATTLEGROUND_IC = 30, // Isle of Conquest + BATTLEGROUND_RB = 32 // Random Battleground }; #define MAX_BATTLEGROUND_TYPE_ID 33 diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index b0ac0b710c1..c0e1eb842ae 100755 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -114,6 +114,9 @@ void MotionMaster::UpdateMotion(uint32 diff) _cleanFlag &= ~MMCF_RESET; } + + // probably not the best place to pu this but im not really sure where else to put it. + _owner->UpdateUnderwaterState(_owner->GetMap(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); } void MotionMaster::DirectClean(bool reset) diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index eb61db8b4ba..fdff5a92564 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -135,7 +135,7 @@ bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_ } // prevent movement while casting spells with cast time or channel time - if (owner.IsNonMeleeSpellCasted(false, false, true)) + if (owner.HasUnitState(UNIT_STATE_CASTING)) { if (!owner.IsStopped()) owner.StopMoving(); diff --git a/src/server/game/Reputation/ReputationMgr.h b/src/server/game/Reputation/ReputationMgr.h index 401503783b9..a073845ea73 100755 --- a/src/server/game/Reputation/ReputationMgr.h +++ b/src/server/game/Reputation/ReputationMgr.h @@ -132,6 +132,9 @@ class ReputationMgr void ApplyForceReaction(uint32 faction_id, ReputationRank rank, bool apply); + //! Public for chat command needs + bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental); + public: // senders void SendInitialReputations(); void SendForceReactions(); @@ -142,7 +145,6 @@ class ReputationMgr void Initialize(); uint32 GetDefaultStateFlags(FactionEntry const* factionEntry) const; bool SetReputation(FactionEntry const* factionEntry, int32 standing, bool incremental); - bool SetOneFactionReputation(FactionEntry const* factionEntry, int32 standing, bool incremental); void SetVisible(FactionState* faction); void SetAtWar(FactionState* faction, bool atWar) const; void SetInactive(FactionState* faction, bool inactive) const; diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index aac615180c8..01d56cf8060 100755 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -954,6 +954,14 @@ bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effInd return tmpscript->OnDummyEffect(caster, spellId, effIndex, target); } +GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* go) +{ + ASSERT(go); + + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, NULL); + return tmpscript->GetAI(go); +} + bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger) { ASSERT(player); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 3b65a5cf256..6fe058d336a 100755 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -39,6 +39,7 @@ class Creature; class CreatureAI; class DynamicObject; class GameObject; +class GameObjectAI; class Guild; class GridMap; class Group; @@ -471,6 +472,9 @@ class GameObjectScript : public ScriptObject, public UpdatableScript<GameObject> // Called when the game object is damaged (destructible buildings only). virtual void OnDamaged(GameObject* /*go*/, Player* /*player*/) { } + + // Called when a GameObjectAI object is needed for the gameobject. + virtual GameObjectAI* GetAI(GameObject* /*go*/) const { return NULL; } }; class AreaTriggerScript : public ScriptObject @@ -911,6 +915,7 @@ class ScriptMgr void OnGameObjectDestroyed(GameObject* go, Player* player); void OnGameObjectDamaged(GameObject* go, Player* player); void OnGameObjectUpdate(GameObject* go, uint32 diff); + GameObjectAI* GetGameObjectAI(GameObject* go); public: /* AreaTriggerScript */ diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 1ad6fe557f9..dbbd89c7533 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1474,6 +1474,23 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const if (spellInfo->Stances & (1<<(GetMiscValue()-1))) target->CastSpell(target, itr->first, true, NULL, this); } + + // Also do it for Glyphs + for (uint32 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) + { + if (uint32 glyphId = target->ToPlayer()->GetGlyph(i)) + { + if (GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId)) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(glyph->SpellId); + if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE))) + continue; + if (spellInfo->Stances & (1<<(GetMiscValue()-1))) + target->CastSpell(target, glyph->SpellId, true, NULL, this); + } + } + } + // Leader of the Pack if (target->ToPlayer()->HasSpell(17007)) { @@ -1583,10 +1600,25 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const } } + const Unit::AuraEffectList& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); + AuraEffect* newAura = NULL; + // Iterate through all the shapeshift auras that the target has, if there is another aura with SPELL_AURA_MOD_SHAPESHIFT, then this aura is being removed due to that one being applied + for (Unit::AuraEffectList::const_iterator itr = shapeshifts.begin(); itr != shapeshifts.end(); ++itr) + { + if ((*itr) != this) + { + newAura = *itr; + break; + } + } Unit::AuraApplicationMap& tAuras = target->GetAppliedAuras(); for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();) { - if (itr->second->GetBase()->IsRemovedOnShapeLost(target)) + // Use the new aura to see on what stance the target will be + uint32 newStance = (1<<((newAura ? newAura->GetMiscValue() : 0)-1)); + + // If the stances are not compatible with the spell, remove it + if (itr->second->GetBase()->IsRemovedOnShapeLost(target) && !(itr->second->GetBase()->GetSpellInfo()->Stances & newStance)) target->RemoveAura(itr); else ++itr; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index af3f53e2369..df2b9c35320 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3427,36 +3427,6 @@ void Spell::_handle_immediate_phase() // process items for (std::list<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); - - if (!m_originalCaster) - return; - // Handle procs on cast - // TODO: finish new proc system:P - if (m_UniqueTargetInfo.empty()) - { - uint32 procAttacker = m_procAttacker; - if (!procAttacker) - { - bool positive = m_spellInfo->IsPositive(); - switch (m_spellInfo->DmgClass) - { - case SPELL_DAMAGE_CLASS_MAGIC: - if (positive) - procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS; - else - procAttacker |= PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG; - break; - case SPELL_DAMAGE_CLASS_NONE: - if (positive) - procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS; - else - procAttacker |= PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG; - break; - } - } - // Proc damage for spells which have only dest targets (2484 should proc 51486 for example) - m_originalCaster->ProcDamageAndSpell(NULL, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell); - } } void Spell::_handle_finish_phase() diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 80ed1972a5d..05431ef0a16 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3347,9 +3347,9 @@ void SpellMgr::LoadDbcDataCorrections() case 70460: // Coldflame Jets (Traps after Saurfang) spellInfo->DurationIndex = 1; // 10 seconds break; - case 71413: // Green Ooze Summon (Professor Putricide) - case 71414: // Orange Ooze Summon (Professor Putricide) - spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; + case 71412: // Green Ooze Summon (Professor Putricide) + case 71415: // Orange Ooze Summon (Professor Putricide) + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; break; case 71159: // Awaken Plagued Zombies spellInfo->DurationIndex = 21; diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp index fa30adde72a..0734e0a0f63 100644 --- a/src/server/game/Warden/Warden.cpp +++ b/src/server/game/Warden/Warden.cpp @@ -187,7 +187,9 @@ std::string Warden::Penalty(WardenCheck* check /*= NULL*/) duration << sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_BAN_DURATION) << "s"; std::string accountName; AccountMgr::GetName(_session->GetAccountId(), accountName); - sWorld->BanAccount(BAN_ACCOUNT, accountName, duration.str(), "Warden Anticheat violation","Server"); + std::stringstream banReason; + banReason << "Warden Anticheat Violation: " << check->Comment << " (CheckId: " << check->CheckId << ")"; + sWorld->BanAccount(BAN_ACCOUNT, accountName, duration.str(), banReason.str(),"Server"); return "Ban"; break; diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp index 90d1cfc0140..f4c7a5069cf 100644 --- a/src/server/game/Warden/WardenCheckMgr.cpp +++ b/src/server/game/Warden/WardenCheckMgr.cpp @@ -63,8 +63,8 @@ void WardenCheckMgr::LoadWardenChecks() CheckStore.resize(maxCheckId + 1); - // 0 1 2 3 4 5 6 - result = WorldDatabase.Query("SELECT id, type, data, result, address, length, str FROM warden_checks ORDER BY id ASC"); + // 0 1 2 3 4 5 6 7 + result = WorldDatabase.Query("SELECT id, type, data, result, address, length, str, comment FROM warden_checks ORDER BY id ASC"); uint32 count = 0; do @@ -78,9 +78,11 @@ void WardenCheckMgr::LoadWardenChecks() uint32 address = fields[4].GetUInt32(); uint8 length = fields[5].GetUInt8(); std::string str = fields[6].GetString(); + std::string comment = fields[7].GetString(); WardenCheck* wardenCheck = new WardenCheck(); wardenCheck->Type = checkType; + wardenCheck->CheckId = id; // Initialize action with default action from config wardenCheck->Action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION)); @@ -134,6 +136,11 @@ void WardenCheckMgr::LoadWardenChecks() CheckResultStore[id] = wr; } + if (comment.empty()) + wardenCheck->Comment = "Undocumented Check"; + else + wardenCheck->Comment = comment; + ++count; } while (result->NextRow()); diff --git a/src/server/game/Warden/WardenCheckMgr.h b/src/server/game/Warden/WardenCheckMgr.h index 45de18081c2..7a83d8f0c6d 100644 --- a/src/server/game/Warden/WardenCheckMgr.h +++ b/src/server/game/Warden/WardenCheckMgr.h @@ -36,6 +36,8 @@ struct WardenCheck uint32 Address; // PROC_CHECK, MEM_CHECK, PAGE_CHECK uint8 Length; // PROC_CHECK, MEM_CHECK, PAGE_CHECK std::string Str; // LUA, MPQ, DRIVER + std::string Comment; + uint16 CheckId; enum WardenActions Action; }; diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 32ee96dacfe..bb3a4d65b76 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1234,7 +1234,7 @@ public: return false; } - target->GetReputationMgr().SetReputation(factionEntry, amount); + target->GetReputationMgr().SetOneFactionReputation(factionEntry, amount, false); handler->PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[handler->GetSessionDbcLocale()], factionId, handler->GetNameLink(target).c_str(), target->GetReputationMgr().GetReputation(factionEntry)); return true; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 541e52fb922..273f2a20b4b 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -64,6 +64,9 @@ enum Spells SPELL_MALLEABLE_GOO = 70852, SPELL_UNSTABLE_EXPERIMENT = 70351, SPELL_TEAR_GAS = 71617, // phase transition + SPELL_TEAR_GAS_CREATURE = 71618, + SPELL_TEAR_GAS_CANCEL = 71620, + SPELL_TEAR_GAS_PERIODIC_TRIGGER = 73170, SPELL_CREATE_CONCOCTION = 71621, SPELL_GUZZLE_POTIONS = 71893, SPELL_OOZE_TANK_PROTECTION = 71770, // protects the tank @@ -86,6 +89,7 @@ enum Spells SPELL_GASEOUS_BLOAT_PROC = 70215, SPELL_GASEOUS_BLOAT = 70672, SPELL_GASEOUS_BLOAT_PROTECTION = 70812, + SPELL_EXPUNGED_GAS = 70701, // Volatile Ooze SPELL_OOZE_ERUPTION = 70492, @@ -595,13 +599,15 @@ class boss_professor_putricide : public CreatureScript break; case EVENT_TEAR_GAS: me->GetMotionMaster()->MovePoint(POINT_TABLE, tablePos); + DoCast(me, SPELL_TEAR_GAS_PERIODIC_TRIGGER, true); break; case EVENT_RESUME_ATTACK: me->SetReactState(REACT_DEFENSIVE); AttackStart(me->getVictim()); // remove Tear Gas + me->RemoveAurasDueToSpell(SPELL_TEAR_GAS_PERIODIC_TRIGGER); instance->DoRemoveAurasDueToSpellOnPlayers(71615); - instance->DoRemoveAurasDueToSpellOnPlayers(71618); + DoCastAOE(SPELL_TEAR_GAS_CANCEL); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAS_VARIABLE); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_OOZE_VARIABLE); break; @@ -699,27 +705,36 @@ class npc_volatile_ooze : public CreatureScript public: npc_volatile_ooze() : CreatureScript("npc_volatile_ooze") { } - struct npc_volatile_oozeAI : public ScriptedAI + struct npc_putricide_oozeAI : public ScriptedAI { - npc_volatile_oozeAI(Creature* creature) : ScriptedAI(creature) + npc_putricide_oozeAI(Creature* creature) : ScriptedAI(creature) { _newTargetSelectTimer = 0; } void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) { - if (!_newTargetSelectTimer && sSpellMgr->GetSpellDifficultyId(spell->Id) == sSpellMgr->GetSpellDifficultyId(SPELL_OOZE_ERUPTION)) + if (!_newTargetSelectTimer && spell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_OOZE_ERUPTION, me)) + _newTargetSelectTimer = 1000; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_TEAR_GAS_CREATURE) _newTargetSelectTimer = 1000; } void UpdateAI(uint32 const diff) { - if (!UpdateVictim()) + if (!UpdateVictim() && !_newTargetSelectTimer) return; if (!_newTargetSelectTimer) return; + if (me->HasAura(SPELL_TEAR_GAS_CREATURE)) + return; + if (_newTargetSelectTimer <= diff) { _newTargetSelectTimer = 0; @@ -730,13 +745,68 @@ class npc_volatile_ooze : public CreatureScript } private: - // no need to use EventMap for just one event uint32 _newTargetSelectTimer; }; CreatureAI* GetAI(Creature* creature) const { - return GetIcecrownCitadelAI<npc_volatile_oozeAI>(creature); + return GetIcecrownCitadelAI<npc_putricide_oozeAI>(creature); + } +}; + +class npc_gas_cloud : public CreatureScript +{ + public: + npc_gas_cloud() : CreatureScript("npc_gas_cloud") { } + + struct npc_gas_cloudAI : public ScriptedAI + { + npc_gas_cloudAI(Creature* creature) : ScriptedAI(creature) + { + _newTargetSelectTimer = 0; + } + + void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) + { + if (!_newTargetSelectTimer && spell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_EXPUNGED_GAS, me)) + _newTargetSelectTimer = 1000; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_TEAR_GAS_CREATURE) + _newTargetSelectTimer = 1000; + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() && !_newTargetSelectTimer) + return; + + DoMeleeAttackIfReady(); + + if (!_newTargetSelectTimer) + return; + + if (me->HasAura(SPELL_TEAR_GAS_CREATURE)) + return; + + if (_newTargetSelectTimer <= diff) + { + _newTargetSelectTimer = 0; + me->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, me, false); + } + else + _newTargetSelectTimer -= diff; + } + + private: + uint32 _newTargetSelectTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_gas_cloudAI>(creature); } }; @@ -755,8 +825,8 @@ class spell_putricide_gaseous_bloat : public SpellScriptLoader if (Unit* caster = GetCaster()) { target->RemoveAuraFromStack(GetSpellInfo()->Id, GetCasterGUID()); - if (!target->HasAura(GetId())&& caster->GetTypeId() == TYPEID_UNIT) - caster->ToCreature()->DespawnOrUnsummon(); + if (!target->HasAura(GetId())) + caster->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, caster, false); } } @@ -823,7 +893,19 @@ class spell_putricide_ooze_channel : public SpellScriptLoader void StartAttack() { GetCaster()->ClearUnitState(UNIT_STATE_CASTING); + GetCaster()->DeleteThreatList(); GetCaster()->ToCreature()->AI()->AttackStart(GetHitUnit()); + GetCaster()->AddThreat(GetHitUnit(), 500000000.0f); // value seen in sniff + } + + // temporary, until SelectTarget are not called on empty lists + void CheckTarget() + { + if (_target) + return; + + FinishCast(SPELL_FAILED_NO_VALID_TARGETS); + GetCaster()->ToCreature()->DespawnOrUnsummon(1); // despawn next update } void Register() @@ -832,6 +914,7 @@ class spell_putricide_ooze_channel : public SpellScriptLoader OnUnitTargetSelect += SpellUnitTargetFn(spell_putricide_ooze_channel_SpellScript::SetTarget, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); OnUnitTargetSelect += SpellUnitTargetFn(spell_putricide_ooze_channel_SpellScript::SetTarget, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY); AfterHit += SpellHitFn(spell_putricide_ooze_channel_SpellScript::StartAttack); + OnCast += SpellCastFn(spell_putricide_ooze_channel_SpellScript::CheckTarget); } Unit* _target; @@ -931,13 +1014,13 @@ class spell_putricide_unstable_experiment : public SpellScriptLoader uint32 stage = GetCaster()->ToCreature()->AI()->GetData(DATA_EXPERIMENT_STAGE); Creature* target = NULL; std::list<Creature*> creList; - GetCreatureListWithEntryInGrid(creList, GetCaster(), NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 100.0f); + GetCreatureListWithEntryInGrid(creList, GetCaster(), NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 200.0f); // 2 of them are spawned at green place - weird trick blizz for (std::list<Creature*>::iterator itr = creList.begin(); itr != creList.end(); ++itr) { target = *itr; std::list<Creature*> tmp; - GetCreatureListWithEntryInGrid(tmp, target, NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 1.0f); + GetCreatureListWithEntryInGrid(tmp, target, NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER, 10.0f); if ((!stage && tmp.size() > 1) || (stage && tmp.size() == 1)) break; } @@ -957,42 +1040,6 @@ class spell_putricide_unstable_experiment : public SpellScriptLoader } }; -class spell_putricide_ooze_summon : public SpellScriptLoader -{ - public: - spell_putricide_ooze_summon() : SpellScriptLoader("spell_putricide_ooze_summon") { } - - class spell_putricide_ooze_summon_AuraScript : public AuraScript - { - PrepareAuraScript(spell_putricide_ooze_summon_AuraScript); - - void HandleTriggerSpell(AuraEffect const* aurEff) - { - PreventDefaultAction(); - if (Unit* caster = GetCaster()) - { - uint32 triggerSpellId = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - float x, y, z; - GetTarget()->GetPosition(x, y, z); - z = GetTarget()->GetMap()->GetHeight(GetTarget()->GetPhaseMask(), x, y, z, true, 25.0f); - x += 10.0f * cosf(caster->GetOrientation()); - y += 10.0f * sinf(caster->GetOrientation()); - caster->CastSpell(x, y, z, triggerSpellId, true, NULL, NULL, GetCasterGUID()); - } - } - - void Register() - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_putricide_ooze_summon_AuraScript::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_putricide_ooze_summon_AuraScript(); - } -}; - class spell_putricide_ooze_eruption_searcher : public SpellScriptLoader { public: @@ -1455,14 +1502,15 @@ class spell_putricide_regurgitated_ooze : public SpellScriptLoader } }; -class spell_putricide_clear_mutated_plague : public SpellScriptLoader +// Removes aura with id stored in effect value +class spell_putricide_clear_aura_effect_value : public SpellScriptLoader { public: - spell_putricide_clear_mutated_plague() : SpellScriptLoader("spell_putricide_clear_mutated_plague") { } + spell_putricide_clear_aura_effect_value() : SpellScriptLoader("spell_putricide_clear_aura_effect_value") { } - class spell_putricide_clear_mutated_plague_SpellScript : public SpellScript + class spell_putricide_clear_aura_effect_value_SpellScript : public SpellScript { - PrepareSpellScript(spell_putricide_clear_mutated_plague_SpellScript); + PrepareSpellScript(spell_putricide_clear_aura_effect_value_SpellScript); void HandleScript(SpellEffIndex effIndex) { @@ -1473,13 +1521,13 @@ class spell_putricide_clear_mutated_plague : public SpellScriptLoader void Register() { - OnEffectHitTarget += SpellEffectFn(spell_putricide_clear_mutated_plague_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + OnEffectHitTarget += SpellEffectFn(spell_putricide_clear_aura_effect_value_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; SpellScript* GetSpellScript() const { - return new spell_putricide_clear_mutated_plague_SpellScript(); + return new spell_putricide_clear_aura_effect_value_SpellScript(); } }; @@ -1518,12 +1566,12 @@ void AddSC_boss_professor_putricide() { new boss_professor_putricide(); new npc_volatile_ooze(); + new npc_gas_cloud(); new spell_putricide_gaseous_bloat(); new spell_putricide_ooze_channel(); new spell_putricide_slime_puddle(); new spell_putricide_slime_puddle_aura(); new spell_putricide_unstable_experiment(); - new spell_putricide_ooze_summon(); new spell_putricide_ooze_eruption_searcher(); new spell_putricide_choking_gas_bomb(); new spell_putricide_unbound_plague(); @@ -1534,6 +1582,6 @@ void AddSC_boss_professor_putricide() new spell_putricide_mutated_transformation(); new spell_putricide_mutated_transformation_dmg(); new spell_putricide_regurgitated_ooze(); - new spell_putricide_clear_mutated_plague(); + new spell_putricide_clear_aura_effect_value(); new spell_stinky_precious_decimate(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index e12393f047f..22858cf69e5 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -234,7 +234,6 @@ class instance_ulduar : public InstanceMapScript case NPC_ALGALON: AlgalonGUID = creature->GetGUID(); break; - // Hodir's Helper NPCs case NPC_EIVI_NIGHTFEATHER: if (TeamInInstance == HORDE) diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 1a0f4576fea..84e3bd8d604 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -35,6 +35,9 @@ enum ShamanSpells SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1 = 8349, SHAMAN_SPELL_SATED = 57724, SHAMAN_SPELL_EXHAUSTION = 57723, + + SHAMAN_SPELL_STORM_EARTH_AND_FIRE = 51483, + EARTHBIND_TOTEM_SPELL_EARTHGRAB = 64695, // For Earthen Power SHAMAN_TOTEM_SPELL_EARTHBIND_TOTEM = 6474, @@ -221,9 +224,25 @@ class spell_sha_earthbind_totem : public SpellScriptLoader caster->CastSpell(caster, SHAMAN_TOTEM_SPELL_EARTHEN_POWER, true, NULL, aurEff); } + void Apply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (!GetCaster()) + return; + Player* owner = GetCaster()->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!owner) + return; + // Storm, Earth and Fire + if (AuraEffect* aurEff = owner->GetAuraEffectOfRankedSpell(SHAMAN_SPELL_STORM_EARTH_AND_FIRE, EFFECT_1)) + { + if (roll_chance_i(aurEff->GetAmount())) + GetCaster()->CastSpell(GetCaster(), EARTHBIND_TOTEM_SPELL_EARTHGRAB, false); + } + } + void Register() { OnEffectPeriodic += AuraEffectPeriodicFn(spell_sha_earthbind_totem_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + OnEffectApply += AuraEffectApplyFn(spell_sha_earthbind_totem_AuraScript::Apply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); } }; diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 66e44112b8a..3e4c043ae47 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -365,7 +365,7 @@ class spell_warr_concussion_blow : public SpellScriptLoader void HandleDummy(SpellEffIndex /* effIndex */) { - SetHitDamage(GetHitDamage() + CalculatePctF(GetHitDamage(),GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK))); + SetHitDamage(CalculatePctN(GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK), GetEffectValue())); } void Register() diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 6858827ed8e..61b997bba35 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -2400,6 +2400,9 @@ enum eLockSmith QUEST_HOTTER_THAN_HELL_H = 10764, QUEST_RETURN_TO_KHAGDAR = 9837, QUEST_CONTAINMENT = 13159, + QUEST_ETERNAL_VIGILANCE = 11011, + QUEST_KEY_TO_THE_FOCUSING_IRIS = 13372, + QUEST_HC_KEY_TO_THE_FOCUSING_IRIS = 13375, ITEM_ARCATRAZ_KEY = 31084, ITEM_SHADOWFORGE_KEY = 11000, @@ -2407,21 +2410,28 @@ enum eLockSmith ITEM_SHATTERED_HALLS_KEY = 28395, ITEM_THE_MASTERS_KEY = 24490, ITEM_VIOLET_HOLD_KEY = 42482, + ITEM_ESSENCE_INFUSED_MOONSTONE = 32449, + ITEM_KEY_TO_THE_FOCUSING_IRIS = 44582, + ITEM_HC_KEY_TO_THE_FOCUSING_IRIS = 44581, SPELL_ARCATRAZ_KEY = 54881, SPELL_SHADOWFORGE_KEY = 54882, SPELL_SKELETON_KEY = 54883, SPELL_SHATTERED_HALLS_KEY = 54884, SPELL_THE_MASTERS_KEY = 54885, - SPELL_VIOLET_HOLD_KEY = 67253 + SPELL_VIOLET_HOLD_KEY = 67253, + SPELL_ESSENCE_INFUSED_MOONSTONE = 40173, }; -#define GOSSIP_LOST_ARCATRAZ_KEY "I've lost my key to the Arcatraz." -#define GOSSIP_LOST_SHADOWFORGE_KEY "I've lost my key to the Blackrock Depths." -#define GOSSIP_LOST_SKELETON_KEY "I've lost my key to the Scholomance." -#define GOSSIP_LOST_SHATTERED_HALLS_KEY "I've lost my key to the Shattered Halls." -#define GOSSIP_LOST_THE_MASTERS_KEY "I've lost my key to the Karazhan." -#define GOSSIP_LOST_VIOLET_HOLD_KEY "I've lost my key to the Violet Hold." +#define GOSSIP_LOST_ARCATRAZ_KEY "I've lost my key to the Arcatraz." +#define GOSSIP_LOST_SHADOWFORGE_KEY "I've lost my key to the Blackrock Depths." +#define GOSSIP_LOST_SKELETON_KEY "I've lost my key to the Scholomance." +#define GOSSIP_LOST_SHATTERED_HALLS_KEY "I've lost my key to the Shattered Halls." +#define GOSSIP_LOST_THE_MASTERS_KEY "I've lost my key to the Karazhan." +#define GOSSIP_LOST_VIOLET_HOLD_KEY "I've lost my key to the Violet Hold." +#define GOSSIP_LOST_ESSENCE_INFUSED_MOONSTONE "I've lost my Essence-Infused Moonstone." +#define GOSSIP_LOST_KEY_TO_THE_FOCUSING_IRIS "I've lost my Key to the Focusing Iris." +#define GOSSIP_LOST_HC_KEY_TO_THE_FOCUSING_IRIS "I've lost my Heroic Key to the Focusing Iris." class npc_locksmith : public CreatureScript { @@ -2456,6 +2466,18 @@ public: if (player->GetQuestRewardStatus(QUEST_CONTAINMENT) && !player->HasItemCount(ITEM_VIOLET_HOLD_KEY, 1, true)) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_VIOLET_HOLD_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + // Essence-Infused Moonstone + if (player->GetQuestRewardStatus(QUEST_ETERNAL_VIGILANCE) && !player->HasItemCount(ITEM_ESSENCE_INFUSED_MOONSTONE, 1, true)) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_ESSENCE_INFUSED_MOONSTONE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + + // Key to the Focusing Iris + if (player->GetQuestRewardStatus(QUEST_KEY_TO_THE_FOCUSING_IRIS) && !player->HasItemCount(ITEM_KEY_TO_THE_FOCUSING_IRIS, 1, true)) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_KEY_TO_THE_FOCUSING_IRIS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + + // Heroic Key to the Focusing Iris + if (player->GetQuestRewardStatus(QUEST_HC_KEY_TO_THE_FOCUSING_IRIS) && !player->HasItemCount(ITEM_HC_KEY_TO_THE_FOCUSING_IRIS, 1, true)) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_HC_KEY_TO_THE_FOCUSING_IRIS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); + player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); return true; @@ -2490,6 +2512,18 @@ public: player->CLOSE_GOSSIP_MENU(); player->CastSpell(player, SPELL_VIOLET_HOLD_KEY, false); break; + case GOSSIP_ACTION_INFO_DEF + 7: + player->CLOSE_GOSSIP_MENU(); + player->CastSpell(player, SPELL_ESSENCE_INFUSED_MOONSTONE, false); + break; + case GOSSIP_ACTION_INFO_DEF + 8: + player->CLOSE_GOSSIP_MENU(); + player->AddItem(ITEM_KEY_TO_THE_FOCUSING_IRIS,1); + break; + case GOSSIP_ACTION_INFO_DEF + 9: + player->CLOSE_GOSSIP_MENU(); + player->AddItem(ITEM_HC_KEY_TO_THE_FOCUSING_IRIS,1); + break; } return true; } diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index 8b69accfc23..314d196cc06 100755 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -102,7 +102,7 @@ class DatabaseWorkerPool //! Shuts down delaythreads for this connection pool by underlying deactivate(). //! The next dequeue attempt in the worker thread tasks will result in an error, - //! ultimately ending the worker thread task. + //! ultimately ending the worker thread task. _queue->queue()->close(); for (uint8 i = 0; i < _connectionCount[IDX_ASYNC]; ++i) @@ -114,7 +114,7 @@ class DatabaseWorkerPool t->Close(); //! Closes the actualy MySQL connection. } - sLog->outSQLDriver("Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.", + sLog->outSQLDriver("Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.", GetDatabaseName()); //! Shut down the synchronous connections |