summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/apps/worldserver/worldserver.conf.dist12
-rw-r--r--src/server/database/Updater/DBUpdater.cpp6
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp3
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAB.h1
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp69
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundAV.h1
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp6
-rw-r--r--src/server/game/Battlegrounds/Zones/BattlegroundWS.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp91
-rw-r--r--src/server/game/Entities/Player/Player.h8
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp103
-rw-r--r--src/server/game/Entities/Unit/Unit.h3
-rw-r--r--src/server/game/Entities/Unit/UnitDefines.h4
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp18
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp5
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp4
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp81
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rw-r--r--src/server/game/Server/WorldSession.h1
-rw-r--r--src/server/game/World/WorldConfig.cpp3
-rw-r--r--src/server/game/World/WorldConfig.h3
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp53
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/boss_tenris_mirkblood.cpp8
-rw-r--r--src/server/scripts/Kalimdor/kalimdor_script_loader.cpp2
-rw-r--r--src/server/scripts/Kalimdor/zone_azshara.cpp361
-rw-r--r--src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp2
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp12
-rw-r--r--src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp34
-rw-r--r--src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp78
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp150
-rw-r--r--src/server/scripts/Spells/spell_item.cpp12
-rw-r--r--src/server/scripts/Spells/spell_quest.cpp3
-rw-r--r--src/server/scripts/World/go_scripts.cpp3
34 files changed, 539 insertions, 607 deletions
diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist
index 89863ac4f9..07945f07f3 100644
--- a/src/server/apps/worldserver/worldserver.conf.dist
+++ b/src/server/apps/worldserver/worldserver.conf.dist
@@ -2351,6 +2351,18 @@ Rate.Reputation.LowLevel.Quest = 1
Rate.Reputation.RecruitAFriendBonus = 0.1
#
+# Rate.Reputation.Gain.WSG
+# Rate.Reputation.Gain.AB
+# Rate.Reputation.Gain.AV
+# Description: Reputation bonus rate for WSG, AB and AV battlegrounds.
+# This is applied IN ADDITION to the global Rate.Reputation.Gain.
+# Default: 1
+
+Rate.Reputation.Gain.WSG = 1
+Rate.Reputation.Gain.AB = 1
+Rate.Reputation.Gain.AV = 1
+
+#
###################################################################################################
###################################################################################################
diff --git a/src/server/database/Updater/DBUpdater.cpp b/src/server/database/Updater/DBUpdater.cpp
index 442b48bcb8..d32fddd8c1 100644
--- a/src/server/database/Updater/DBUpdater.cpp
+++ b/src/server/database/Updater/DBUpdater.cpp
@@ -496,17 +496,13 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
if (ssl == "ssl")
args.emplace_back("--ssl-mode=REQUIRED");
- // Execute sql file
- args.emplace_back("-e");
- args.emplace_back(Acore::StringFormat("BEGIN; SOURCE {}; COMMIT;", path.generic_string()));
-
// Database
if (!database.empty())
args.emplace_back(database);
// Invokes a mysql process which doesn't leak credentials to logs
int const ret = Acore::StartProcess(DBUpdaterUtil::GetCorrectedMySQLExecutable(), args,
- "sql.updates", "", true);
+ "sql.updates", path.generic_string(), true);
if (ret != EXIT_SUCCESS)
{
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
index 10c0956e5d..d1aa246ab0 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
@@ -115,7 +115,7 @@ void BattlegroundAB::PostUpdateImpl(uint32 diff)
if (honorRewards < uint8(m_TeamScores[teamId] / _honorTics))
RewardHonorToTeam(GetBonusHonorFromKill(1), teamId);
if (reputationRewards < uint8(m_TeamScores[teamId] / _reputationTics))
- RewardReputationToTeam(teamId == TEAM_ALLIANCE ? 509 : 510, 10, teamId);
+ RewardReputationToTeam(teamId == TEAM_ALLIANCE ? 509 : 510, uint32(10 * _abReputationRate), teamId);
if (information < uint8(m_TeamScores[teamId] / BG_AB_WARNING_NEAR_VICTORY_SCORE))
{
if (teamId == TEAM_ALLIANCE)
@@ -421,6 +421,7 @@ bool BattlegroundAB::SetupBattleground()
{
_honorTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)) ? BG_AB_HONOR_TICK_WEEKEND : BG_AB_HONOR_TICK_NORMAL;
_reputationTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)) ? BG_AB_REP_TICK_WEEKEND : BG_AB_REP_TICK_NORMAL;
+ _abReputationRate = sWorld->getRate(RATE_REPUTATION_GAIN_AB);
for (uint32 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
{
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
index a250c9f16e..61aee582d7 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h
@@ -299,6 +299,7 @@ private:
EventMap _bgEvents;
uint32 _honorTics;
uint32 _reputationTics;
+ float _abReputationRate;
uint8 _controlledPoints[PVP_TEAMS_COUNT] {};
bool _teamScores500Disadvantage[PVP_TEAMS_COUNT] {};
uint32 _configurableMaxTeamScore;
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
index 5b6a8b335f..b65daf5d9e 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
@@ -194,21 +194,21 @@ void BattlegroundAV::HandleQuestComplete(uint32 questid, Player* player)
case AV_QUEST_A_COMMANDER1:
case AV_QUEST_H_COMMANDER1:
m_Team_QuestStatus[teamId][1]++;
- RewardReputationToTeam(teamId, 1, teamId);
+ RewardReputationToTeam(teamId, uint32(1 * _avReputationRate), teamId);
if (m_Team_QuestStatus[teamId][1] == 30)
LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
break;
case AV_QUEST_A_COMMANDER2:
case AV_QUEST_H_COMMANDER2:
m_Team_QuestStatus[teamId][2]++;
- RewardReputationToTeam(teamId, 1, teamId);
+ RewardReputationToTeam(teamId, uint32(1 * _avReputationRate), teamId);
if (m_Team_QuestStatus[teamId][2] == 60)
LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
break;
case AV_QUEST_A_COMMANDER3:
case AV_QUEST_H_COMMANDER3:
m_Team_QuestStatus[teamId][3]++;
- RewardReputationToTeam(teamId, 1, teamId);
+ RewardReputationToTeam(teamId, uint32(1 * _avReputationRate), teamId);
if (m_Team_QuestStatus[teamId][3] == 120)
LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
break;
@@ -316,21 +316,21 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type)
type -= AV_CPLACE_MAX;
cinfoid = uint16(BG_AV_StaticCreaturePos[type][4]);
creature = AddCreature(BG_AV_StaticCreatureInfo[cinfoid],
- type + AV_CPLACE_MAX,
- BG_AV_StaticCreaturePos[type][0],
- BG_AV_StaticCreaturePos[type][1],
- BG_AV_StaticCreaturePos[type][2],
- BG_AV_StaticCreaturePos[type][3]);
+ type + AV_CPLACE_MAX,
+ BG_AV_StaticCreaturePos[type][0],
+ BG_AV_StaticCreaturePos[type][1],
+ BG_AV_StaticCreaturePos[type][2],
+ BG_AV_StaticCreaturePos[type][3]);
isStatic = true;
}
else
{
creature = AddCreature(BG_AV_CreatureInfo[cinfoid],
- type,
- BG_AV_CreaturePos[type][0],
- BG_AV_CreaturePos[type][1],
- BG_AV_CreaturePos[type][2],
- BG_AV_CreaturePos[type][3]);
+ type,
+ BG_AV_CreaturePos[type][0],
+ BG_AV_CreaturePos[type][1],
+ BG_AV_CreaturePos[type][2],
+ BG_AV_CreaturePos[type][3]);
}
if (!creature)
return nullptr;
@@ -344,7 +344,7 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type)
(cinfoid >= AV_NPC_H_GRAVEDEFENSE0 && cinfoid <= AV_NPC_H_GRAVEDEFENSE3))))
{
if (!isStatic && ((cinfoid >= AV_NPC_A_GRAVEDEFENSE0 && cinfoid <= AV_NPC_A_GRAVEDEFENSE3)
- || (cinfoid >= AV_NPC_H_GRAVEDEFENSE0 && cinfoid <= AV_NPC_H_GRAVEDEFENSE3)))
+ || (cinfoid >= AV_NPC_H_GRAVEDEFENSE0 && cinfoid <= AV_NPC_H_GRAVEDEFENSE3)))
{
CreatureData& data = sObjectMgr->NewOrExistCreatureData(creature->GetSpawnId());
data.wander_distance = 5;
@@ -814,11 +814,11 @@ void BattlegroundAV::PopulateNode(BG_AV_Nodes node)
if (!trigger)
{
trigger = AddCreature(WORLD_TRIGGER,
- node + 302,
- BG_AV_CreaturePos[node + 302][0],
- BG_AV_CreaturePos[node + 302][1],
- BG_AV_CreaturePos[node + 302][2],
- BG_AV_CreaturePos[node + 302][3]);
+ node + 302,
+ BG_AV_CreaturePos[node + 302][0],
+ BG_AV_CreaturePos[node + 302][1],
+ BG_AV_CreaturePos[node + 302][2],
+ BG_AV_CreaturePos[node + 302][3]);
}
//add bonus honor aura trigger creature when node is accupied
@@ -1240,25 +1240,28 @@ GraveyardStruct const* BattlegroundAV::GetClosestGraveyard(Player* player)
bool BattlegroundAV::SetupBattleground()
{
+ _avReputationRate = sWorld->getRate(RATE_REPUTATION_GAIN_AV);
+
if (sBattlegroundMgr->IsBGWeekend(GetBgTypeID(true)))
{
- _reputationTower = 18;
- _reputationCaptain = 185;
- _reputationBoss = 525;
- _reputationPerOwnedGraveyard = 18;
- _reputationSurvivingCaptain = 175;
- _reputationSurvivingTower = 18;
- _reputationPerOwnedMine = 36;
+ _reputationTower = uint32(18 * _avReputationRate);
+ _reputationCaptain = uint32(185 * _avReputationRate);
+ _reputationBoss = uint32(525 * _avReputationRate);
+ _reputationPerOwnedGraveyard = uint32(18 * _avReputationRate);
+ _reputationSurvivingCaptain = uint32(175 * _avReputationRate);
+ _reputationSurvivingTower = uint32(18 * _avReputationRate);
+ _reputationPerOwnedMine = uint32(36 * _avReputationRate);
}
else
{
- _reputationTower = 12;
- _reputationCaptain = 125;
- _reputationBoss = sWorld->getIntConfig(CONFIG_BATTLEGROUND_ALTERAC_REP_ONBOSSDEATH);
- _reputationPerOwnedGraveyard = 12;
- _reputationSurvivingCaptain = 125;
- _reputationSurvivingTower = 12;
- _reputationPerOwnedMine = 24;
+ _reputationTower = uint32(12 * _avReputationRate);
+ _reputationCaptain = uint32(125 * _avReputationRate);
+ // Special case: This value comes from another config setting, but we still apply our multiplier
+ _reputationBoss = uint32(sWorld->getIntConfig(CONFIG_BATTLEGROUND_ALTERAC_REP_ONBOSSDEATH) * _avReputationRate);
+ _reputationPerOwnedGraveyard = uint32(12 * _avReputationRate);
+ _reputationSurvivingCaptain = uint32(125 * _avReputationRate);
+ _reputationSurvivingTower = uint32(12 * _avReputationRate);
+ _reputationPerOwnedMine = uint32(24 * _avReputationRate);
}
// Create starting objects
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
index a058f1d98c..c8a0fd8cd2 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h
@@ -1846,6 +1846,7 @@ private:
uint32 _reputationSurvivingCaptain = 0; // 125, 175
uint32 _reputationSurvivingTower = 0; // 12, 18
uint32 _reputationPerOwnedMine = 0; // 24, 36
+ float _avReputationRate;
bool m_IsInformedNearVictory[2] {};
};
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
index 272f07fbad..974e1d67ae 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp
@@ -426,15 +426,17 @@ void BattlegroundWS::HandleAreaTrigger(Player* player, uint32 trigger)
bool BattlegroundWS::SetupBattleground()
{
+ _wsReputationRate = sWorld->getRate(RATE_REPUTATION_GAIN_WSG);
+
if (sBattlegroundMgr->IsBGWeekend(GetBgTypeID(true)))
{
- _reputationCapture = 45;
+ _reputationCapture = uint32(45 * _wsReputationRate);
_honorWinKills = 3;
_honorEndKills = 4;
}
else
{
- _reputationCapture = 35;
+ _reputationCapture = uint32(35 * _wsReputationRate);
_honorWinKills = 1;
_honorEndKills = 2;
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h
index 61fa2516ed..7aa8975003 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h
@@ -258,6 +258,7 @@ private:
ObjectGuid _droppedFlagGUID[2];
uint8 _flagState[2];
TeamId _lastFlagCaptureTeam;
+ float _wsReputationRate;
uint32 _reputationCapture;
uint32 _honorWinKills;
uint32 _honorEndKills;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 05c93ca7e1..a82d55eb8e 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -90,6 +90,7 @@
#include "WorldStateDefines.h"
#include "WorldStatePackets.h"
#include <cmath>
+#include <queue>
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
// however, for some reasons removing it would cause a damn linking issue
@@ -2500,6 +2501,7 @@ void Player::GiveLevel(uint8 level)
m_Played_time[PLAYED_TIME_LEVEL] = 0; // Level Played Time reset
_ApplyAllLevelScaleItemMods(false);
+ _RemoveAllAuraStatMods();
SetLevel(level);
@@ -2522,6 +2524,7 @@ void Player::GiveLevel(uint8 level)
UpdateSkillsToMaxSkillsForLevel();
_ApplyAllLevelScaleItemMods(true);
+ _ApplyAllAuraStatMods();
if (!isDead())
{
@@ -4429,12 +4432,6 @@ void Player::SetMovement(PlayerMovementType pType)
const PackedGuid& guid = GetPackGUID();
switch (pType)
{
- case MOVE_ROOT:
- data.Initialize(SMSG_FORCE_MOVE_ROOT, guid.size() + 4);
- break;
- case MOVE_UNROOT:
- data.Initialize(SMSG_FORCE_MOVE_UNROOT, guid.size() + 4);
- break;
case MOVE_WATER_WALK:
data.Initialize(SMSG_MOVE_WATER_WALK, guid.size() + 4);
break;
@@ -4488,10 +4485,10 @@ void Player::BuildPlayerRepop()
SetHealth(1); // convert player body to ghost
SetMovement(MOVE_WATER_WALK);
SetWaterWalking(true);
- if (!GetSession()->isLogingOut())
- {
- SetMovement(MOVE_UNROOT);
- }
+
+ if (!IsImmobilizedState())
+ SendMoveRoot(false);
+
RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // BG - remove insignia related
int32 corpseReclaimDelay = CalculateCorpseReclaimDelay();
if (corpseReclaimDelay >= 0)
@@ -4528,7 +4525,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
setDeathState(DeathState::Alive);
SetMovement(MOVE_LAND_WALK);
- SetMovement(MOVE_UNROOT);
+ SendMoveRoot(false);
SetWaterWalking(false);
m_deathTimer = 0;
@@ -4592,7 +4589,7 @@ void Player::KillPlayer()
if (IsFlying() && !GetTransport())
GetMotionMaster()->MoveFall();
- SetMovement(MOVE_ROOT);
+ SendMoveRoot(true);
StopMirrorTimers(); //disable timers(bars)
@@ -11701,9 +11698,6 @@ void Player::SendInitialPacketsAfterAddToMap()
GetZoneAndAreaId(newzone, newarea);
UpdateZone(newzone, newarea); // also call SendInitWorldStates();
- if (HasStunAura())
- SetMovement(MOVE_ROOT);
-
WorldPacket setCompoundState(SMSG_MULTIPLE_MOVES, 100);
setCompoundState << uint32(0); // size placeholder
@@ -14371,6 +14365,67 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const
return false;
}
+/**
+ * @brief Checks if any vendor option is available in the gossip menu tree for a given creature.
+ *
+ * @param menuId The starting gossip menu ID to check.
+ * @param creature Pointer to the creature whose gossip menus are being checked.
+ * @return true if a vendor option is available in any accessible menu; false otherwise.
+ */
+bool Player::AnyVendorOptionAvailable(uint32 menuId, Creature const* creature) const
+{
+ std::set<uint32> visitedMenus;
+ std::queue<uint32> menusToCheck;
+ menusToCheck.push(menuId);
+
+ while (!menusToCheck.empty())
+ {
+ uint32 const currentMenuId = menusToCheck.front();
+ menusToCheck.pop();
+
+ if (visitedMenus.find(currentMenuId) != visitedMenus.end())
+ continue;
+
+ visitedMenus.insert(currentMenuId);
+
+ GossipMenuItemsMapBounds menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(currentMenuId);
+
+ if (menuItemBounds.first == menuItemBounds.second && currentMenuId != 0)
+ continue;
+
+ for (auto itr = menuItemBounds.first; itr != menuItemBounds.second; ++itr)
+ {
+ if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(this), const_cast<Creature*>(creature), itr->second.Conditions))
+ continue;
+
+ if (itr->second.OptionType == GOSSIP_OPTION_VENDOR)
+ return true;
+ else if (itr->second.ActionMenuID)
+ {
+ GossipMenusMapBounds menuBounds = sObjectMgr->GetGossipMenusMapBounds(itr->second.ActionMenuID);
+ bool menuAccessible = false;
+
+ if (menuBounds.first == menuBounds.second)
+ menuAccessible = true;
+ else
+ {
+ for (auto menuItr = menuBounds.first; menuItr != menuBounds.second; ++menuItr)
+ if (sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(this), const_cast<Creature*>(creature), menuItr->second.Conditions))
+ {
+ menuAccessible = true;
+ break;
+ }
+ }
+
+ if (menuAccessible)
+ menusToCheck.push(itr->second.ActionMenuID);
+ }
+ }
+ }
+
+ return false;
+}
+
bool Player::CanSeeVendor(Creature const* creature) const
{
if (!creature->HasNpcFlag(UNIT_NPC_FLAG_VENDOR))
@@ -14378,9 +14433,11 @@ bool Player::CanSeeVendor(Creature const* creature) const
ConditionList conditions = sConditionMgr->GetConditionsForNpcVendorEvent(creature->GetEntry(), 0);
if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(this), const_cast<Creature*>(creature), conditions))
- {
return false;
- }
+
+ uint32 const menuId = creature->GetCreatureTemplate()->GossipMenuId;
+ if (!AnyVendorOptionAvailable(menuId, creature))
+ return false;
return true;
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 74c89cc96d..ea2cd277a5 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -41,6 +41,7 @@
#include "TradeData.h"
#include "Unit.h"
#include "WorldSession.h"
+#include <set>
#include <string>
#include <vector>
@@ -448,8 +449,6 @@ typedef std::list<Item*> ItemDurationList;
enum PlayerMovementType
{
- MOVE_ROOT = 1,
- MOVE_UNROOT = 2,
MOVE_WATER_WALK = 3,
MOVE_LAND_WALK = 4
};
@@ -1156,6 +1155,7 @@ public:
void SetCommentator(bool on) { ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_COMMENTATOR2, on); }
[[nodiscard]] bool IsDeveloper() const { return HasPlayerFlag(PLAYER_FLAGS_DEVELOPER); }
void SetDeveloper(bool on) { ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_DEVELOPER, on); }
+ void SetBeastMaster(bool on) { if (on) SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); else RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); }
[[nodiscard]] bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; }
void SetAcceptWhispers(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; }
[[nodiscard]] bool IsGameMaster() const { return m_ExtraFlags & PLAYER_EXTRA_GM_ON; }
@@ -2549,7 +2549,9 @@ public:
//bool isActiveObject() const { return true; }
bool CanSeeSpellClickOn(Creature const* creature) const;
[[nodiscard]] bool CanSeeVendor(Creature const* creature) const;
-
+private:
+ [[nodiscard]] bool AnyVendorOptionAvailable(uint32 menuId, Creature const* creature) const;
+public:
[[nodiscard]] uint32 GetChampioningFaction() const { return m_ChampioningFaction; }
void SetChampioningFaction(uint32 faction) { m_ChampioningFaction = faction; }
Spell* m_spellModTakingSpell;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 4a26367b53..1fbbf0d9c7 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -18293,73 +18293,65 @@ void Unit::SetStunned(bool apply)
}
}
-void Unit::SetRooted(bool apply, bool isStun)
+void Unit::SetRooted(bool apply, bool stun, bool logout)
{
+ const uint32 state = (stun ? (logout ? UNIT_STATE_LOGOUT_TIMER : UNIT_STATE_STUNNED) : UNIT_STATE_ROOT);
+
if (apply)
{
- // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a)
- // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before
- // setting MOVEMENTFLAG_ROOT
- RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING);
+ AddUnitState(state);
- if (IsFalling())
- {
- AddUnitMovementFlag(MOVEMENTFLAG_PENDING_ROOT);
- }
- else
- {
- AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
- }
+ SendMoveRoot(true);
+ }
+ else
+ {
+ ClearUnitState(state);
- // Creature specific
- if (!IsPlayer())
- {
- if (isStun && movespline->Finalized())
- {
- StopMovingOnCurrentPos();
- }
- else
- {
- StopMoving();
- }
- }
+ // Prevent giving ability to move if more immobilizers are active
+ if (!IsImmobilizedState())
+ SendMoveRoot(false);
+ }
+}
- if (m_movedByPlayer)
+void Unit::SendMoveRoot(bool apply)
+{
+ const Player* client = GetClientControlling();
+
+ // Apply flags in-place when unit currently is not controlled by a player
+ if (!client)
+ {
+ if (apply)
{
- WorldPacket data(SMSG_FORCE_MOVE_ROOT, GetPackGUID().size() + 4);
- data << GetPackGUID();
- data << m_movedByPlayer->ToPlayer()->GetSession()->GetOrderCounter(); // movement counter
- m_movedByPlayer->ToPlayer()->SendDirectMessage(&data);
- m_movedByPlayer->ToPlayer()->GetSession()->IncrementOrderCounter();
+ m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_MASK_MOVING_FLY);
+ m_movementInfo.AddMovementFlag(MOVEMENTFLAG_ROOT);
+ if (!client)
+ StopMoving();
}
else
- {
- WorldPacket data(SMSG_SPLINE_MOVE_ROOT, GetPackGUID().size());
- data << GetPackGUID();
- SendMessageToSet(&data, true);
- }
+ m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ROOT);
+ }
+
+ if (!IsInWorld())
+ return;
+
+ const PackedGuid& guid = GetPackGUID();
+ // Wrath+ spline root: when unit is currently not controlled by a player
+ if (!client)
+ {
+ WorldPacket data(apply ? SMSG_SPLINE_MOVE_ROOT : SMSG_SPLINE_MOVE_UNROOT, guid.size());
+ data << guid;
+ SendMessageToSet(&data, true);
}
+ // Wrath+ force root: when unit is controlled by a player
else
{
- RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT | MOVEMENTFLAG_PENDING_ROOT);
+ auto const counter = client->GetSession()->GetOrderCounter();
- if (!HasUnitState(UNIT_STATE_STUNNED)) // prevent moving if it also has stun effect
- {
- if (m_movedByPlayer)
- {
- WorldPacket data(SMSG_FORCE_MOVE_UNROOT, GetPackGUID().size() + 4);
- data << GetPackGUID();
- data << m_movedByPlayer->ToPlayer()->GetSession()->GetOrderCounter(); // movement counter
- m_movedByPlayer->ToPlayer()->SendDirectMessage(&data);
- m_movedByPlayer->ToPlayer()->GetSession()->IncrementOrderCounter();
- }
- else
- {
- WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, GetPackGUID().size());
- data << GetPackGUID();
- SendMessageToSet(&data, true);
- }
- }
+ WorldPacket data(apply ? SMSG_FORCE_MOVE_ROOT : SMSG_FORCE_MOVE_UNROOT, guid.size() + 4);
+ data << guid;
+ data << counter;
+ client->GetSession()->SendPacket(&data);
+ client->GetSession()->IncrementOrderCounter();
}
}
@@ -20799,7 +20791,10 @@ void Unit::PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPoi
appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
if (!target->CanSeeVendor(creature))
+ {
+ appendValue &= ~UNIT_NPC_FLAG_REPAIR;
appendValue &= ~UNIT_NPC_FLAG_VENDOR_MASK;
+ }
if (!creature->IsValidTrainerForPlayer(target, &appendValue))
appendValue &= ~UNIT_NPC_FLAG_TRAINER;
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 726addd949..2902825105 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -2066,7 +2066,8 @@ protected:
void SetFeared(bool apply, Unit* fearedBy = nullptr, bool isFear = false);
void SetConfused(bool apply);
void SetStunned(bool apply);
- void SetRooted(bool apply, bool isStun = false);
+ void SetRooted(bool apply, bool stun = false, bool logout = false);
+ void SendMoveRoot(bool state);
//----------- Protected variables ----------//
UnitAI* i_AI;
diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h
index 1875a96aae..72d19e7ebb 100644
--- a/src/server/game/Entities/Unit/UnitDefines.h
+++ b/src/server/game/Entities/Unit/UnitDefines.h
@@ -197,7 +197,9 @@ enum UnitState
UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator
UNIT_STATE_NO_ENVIRONMENT_UPD = 0x20000000,
- UNIT_STATE_NO_COMBAT_MOVEMENT = 0x40000000, // serverside only - should not be changed outside the core and should be placed at the end
+ // serverside region
+ UNIT_STATE_NO_COMBAT_MOVEMENT = 0x40000000, // should not be changed outside the core and should be placed at the end
+ UNIT_STATE_LOGOUT_TIMER = 0x80000000, // Unit is logging out
UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE
| UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | UNIT_STATE_FOLLOW | UNIT_STATE_ROOT | UNIT_STATE_CONFUSED
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index c532f5fe7e..ff904bb177 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1122,8 +1122,22 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
if (!cInfo->Models.size())
LOG_ERROR("sql.sql", "Creature (Entry: {}) does not have any existing display id in creature_template_model.", cInfo->Entry);
- else if (std::accumulate(cInfo->Models.begin(), cInfo->Models.end(), 0.0f, [](float sum, CreatureModel const& model) { return sum + model.Probability; }) <= 0.0f)
- LOG_ERROR("sql.sql", "Creature (Entry: {}) has zero total chance for all models in creature_template_model.", cInfo->Entry);
+ else
+ {
+ float const totalProbability = std::accumulate(cInfo->Models.begin(), cInfo->Models.end(), 0.0f, [](float sum, CreatureModel const& model) { return sum + model.Probability; });
+
+ if (totalProbability <= 0.0f)
+ { // There are many cases in official data of all models having a probability of 0. Believe to be treated equivalent to equal chance ONLY if all are zeroed
+ if (totalProbability == 0.0f)
+ LOG_DEBUG("sql.sql", "Creature (Entry: {}) has zero total chance for all models in creature_template_model. Setting all to 1.0.", cInfo->Entry);
+ else // Custom, likely bad data
+ LOG_ERROR("sql.sql", "Creature (Entry: {}) has less than zero total chance for all models in creature_template_model. Setting all to 1.0.", cInfo->Entry);
+
+ auto& models = const_cast<CreatureTemplate*>(cInfo)->Models;
+ for (auto& model : models)
+ model.Probability = 1.0f;
+ }
+ }
if (!cInfo->unit_class || ((1 << (cInfo->unit_class - 1)) & CLASSMASK_ALL_CREATURES) == 0)
{
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index e18b7365ef..ac7ab27834 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -1164,8 +1164,11 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar)
SendPacket(&data);
// Xinef: fix possible problem with flag UNIT_FLAG_STUNNED added during logout
- if (!pCurrChar->HasUnitState(UNIT_STATE_STUNNED))
+ if (pCurrChar->HasUnitState(UNIT_STATE_LOGOUT_TIMER))
+ {
+ pCurrChar->SetRooted(false, true, true);
pCurrChar->RemoveUnitFlag(UNIT_FLAG_STUNNED);
+ }
pCurrChar->SendInitialPacketsBeforeAddToMap();
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index bb2651c028..03c91c298c 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -468,7 +468,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPackets::Character::LogoutRequ
GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT);
}
- GetPlayer()->SetRooted(true);
+ GetPlayer()->SetRooted(true, true, true);
GetPlayer()->SetUnitFlag(UNIT_FLAG_STUNNED);
}
@@ -492,7 +492,7 @@ void WorldSession::HandleLogoutCancelOpcode(WorldPackets::Character::LogoutCance
// not remove flags if can't free move - its not set in Logout request code.
if (GetPlayer()->CanFreeMove())
{
- GetPlayer()->SetRooted(false);
+ GetPlayer()->SetRooted(false, true, true);
GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND);
GetPlayer()->RemoveUnitFlag(UNIT_FLAG_STUNNED);
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index c738365b53..6bf1b899b2 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -967,79 +967,36 @@ void WorldSession::ComputeNewClockDelta()
void WorldSession::HandleMoveRootAck(WorldPacket& recvData)
{
- ObjectGuid guid;
- recvData >> guid.ReadAsPacked();
-
- Unit* mover = _player->m_mover;
- if (!mover || guid != mover->GetGUID())
- {
- recvData.rfinish(); // prevent warnings spam
- return;
- }
-
- uint32 movementCounter;
- recvData >> movementCounter;
-
- MovementInfo movementInfo;
- movementInfo.guid = guid;
- ReadMovementInfo(recvData, &movementInfo);
-
- /* process position-change */
- int64 movementTime = (int64) movementInfo.time + _timeSyncClockDelta;
- if (_timeSyncClockDelta == 0 || movementTime < 0 || movementTime > 0xFFFFFFFF)
- {
- LOG_INFO("misc", "The computed movement time using clockDelta is erronous. Using fallback instead");
- movementInfo.time = getMSTime();
- }
- else
- {
- movementInfo.time = (uint32)movementTime;
- }
-
- movementInfo.guid = mover->GetGUID();
- mover->m_movementInfo = movementInfo;
- mover->UpdatePosition(movementInfo.pos);
-
-}
+ LOG_DEBUG("network", "WORLD: {}", GetOpcodeNameForLogging((Opcodes)recvData.GetOpcode()));
-void WorldSession::HandleMoveUnRootAck(WorldPacket& recvData)
-{
ObjectGuid guid;
+ uint32 counter;
+ MovementInfo movementInfo;
recvData >> guid.ReadAsPacked();
+ recvData >> counter;
+ ReadMovementInfo(recvData, &movementInfo);
Unit* mover = _player->m_mover;
- if (!mover || guid != mover->GetGUID())
- {
- recvData.rfinish(); // prevent warnings spam
- return;
- }
-
- uint32 movementCounter;
- recvData >> movementCounter;
- MovementInfo movementInfo;
- movementInfo.guid = guid;
- ReadMovementInfo(recvData, &movementInfo);
+ if (mover->GetGUID() != guid)
+ return;
- /* process position-change */
- int64 movementTime = (int64) movementInfo.time + _timeSyncClockDelta;
- if (_timeSyncClockDelta == 0 || movementTime < 0 || movementTime > 0xFFFFFFFF)
+ if (recvData.GetOpcode() == CMSG_FORCE_MOVE_UNROOT_ACK) // unroot case
{
- LOG_INFO("misc", "The computed movement time using clockDelta is erronous. Using fallback instead");
- movementInfo.time = getMSTime();
- }
- else
- {
- movementInfo.time = (uint32)movementTime;
+ if (!mover->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_ROOT))
+ return;
}
-
- if (G3D::fuzzyEq(movementInfo.fallTime, 0.f))
+ else // root case
{
- movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FALLING);
+ if (mover->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_ROOT))
+ return;
}
- movementInfo.guid = mover->GetGUID();
- mover->m_movementInfo = movementInfo;
- mover->UpdatePosition(movementInfo.pos);
+ if (!ProcessMovementInfo(movementInfo, mover, _player, recvData))
+ return;
+ WorldPacket data(recvData.GetOpcode() == CMSG_FORCE_MOVE_UNROOT_ACK ? MSG_MOVE_UNROOT : MSG_MOVE_ROOT);
+ data << guid.WriteAsPacked();
+ WriteMovementInfo(&data, &movementInfo);
+ mover->SendMessageToSet(&data, _player);
}
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 5658e4147d..5061f873ce 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -978,7 +978,8 @@ enum AcoreStrings
LANG_GUILD_INFO_EXTRA_INFO = 1183,
LANG_GUILD_INFO_RANKS = 1184,
LANG_GUILD_INFO_RANKS_LIST = 1185,
- // Room for more level 3 1186-1198 not used
+ LANG_COMMAND_BEASTMASTER_MODE = 1186,
+ // Room for more level 3 1187-1198 not used
// Debug commands
LANG_DO_NOT_USE_6X_DEBUG_AREATRIGGER_LEFT = 1999,
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 11b0a90057..cbb576580f 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -363,7 +363,7 @@ void OpcodeTable::Initialize()
/*0x0E8*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_MOVE_ROOT, STATUS_NEVER);
/*0x0E9*/ DEFINE_HANDLER(CMSG_FORCE_MOVE_ROOT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveRootAck );
/*0x0EA*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_MOVE_UNROOT, STATUS_NEVER);
- /*0x0EB*/ DEFINE_HANDLER(CMSG_FORCE_MOVE_UNROOT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveUnRootAck );
+ /*0x0EB*/ DEFINE_HANDLER(CMSG_FORCE_MOVE_UNROOT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveRootAck );
/*0x0EC*/ DEFINE_HANDLER(MSG_MOVE_ROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x0ED*/ DEFINE_HANDLER(MSG_MOVE_UNROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x0EE*/ DEFINE_HANDLER(MSG_MOVE_HEARTBEAT, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes );
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 33ccaaa4f2..c4f9ce9fe8 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -628,7 +628,6 @@ public: // opcodes handlers
void HandlePlayedTime(WorldPackets::Character::PlayedTimeClient& packet);
// new
- void HandleMoveUnRootAck(WorldPacket& recvPacket);
void HandleMoveRootAck(WorldPacket& recvPacket);
// new inspect
diff --git a/src/server/game/World/WorldConfig.cpp b/src/server/game/World/WorldConfig.cpp
index eedd61eaf4..7ee1b6f6d7 100644
--- a/src/server/game/World/WorldConfig.cpp
+++ b/src/server/game/World/WorldConfig.cpp
@@ -85,6 +85,9 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<float>(RATE_BUYVALUE_ITEM_HEIRLOOM, "Rate.BuyValue.Item.Heirloom", 1.0f);
SetConfigValue<float>(RATE_REPUTATION_GAIN, "Rate.Reputation.Gain", 1.0f);
+ SetConfigValue<float>(RATE_REPUTATION_GAIN_AB, "Rate.Reputation.Gain.AB", 1.0f);
+ SetConfigValue<float>(RATE_REPUTATION_GAIN_AV, "Rate.Reputation.Gain.AV", 1.0f);
+ SetConfigValue<float>(RATE_REPUTATION_GAIN_WSG, "Rate.Reputation.Gain.WSG", 1.0f);
SetConfigValue<float>(RATE_REPUTATION_LOWLEVEL_KILL, "Rate.Reputation.LowLevel.Kill", 1.0f);
SetConfigValue<float>(RATE_REPUTATION_LOWLEVEL_QUEST, "Rate.Reputation.LowLevel.Quest", 1.0f);
SetConfigValue<float>(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS, "Rate.Reputation.RecruitAFriendBonus", 0.1f);
diff --git a/src/server/game/World/WorldConfig.h b/src/server/game/World/WorldConfig.h
index ce089b65a3..f076d0b293 100644
--- a/src/server/game/World/WorldConfig.h
+++ b/src/server/game/World/WorldConfig.h
@@ -437,6 +437,9 @@ enum ServerConfigs
RATE_XP_PET_NEXT_LEVEL,
RATE_REPAIRCOST,
RATE_REPUTATION_GAIN,
+ RATE_REPUTATION_GAIN_AB,
+ RATE_REPUTATION_GAIN_AV,
+ RATE_REPUTATION_GAIN_WSG,
RATE_REPUTATION_LOWLEVEL_KILL,
RATE_REPUTATION_LOWLEVEL_QUEST,
RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS,
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 4ca8b5b37f..fe14104922 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -193,7 +193,8 @@ public:
{ "skirmish", HandleSkirmishCommand, SEC_ADMINISTRATOR, Console::No },
{ "mailbox", HandleMailBoxCommand, SEC_MODERATOR, Console::No },
{ "string", HandleStringCommand, SEC_GAMEMASTER, Console::No },
- { "opendoor", HandleOpenDoorCommand, SEC_GAMEMASTER, Console::No }
+ { "opendoor", HandleOpenDoorCommand, SEC_GAMEMASTER, Console::No },
+ { "bm", HandleBMCommand, SEC_GAMEMASTER, Console::No }
};
return commandTable;
@@ -504,6 +505,7 @@ public:
if (!session)
{
+ handler->SendErrorMessage(LANG_USE_BOL);
return false;
}
@@ -537,9 +539,6 @@ public:
SetCommentatorMod(false);
return true;
}
-
- handler->SendErrorMessage(LANG_USE_BOL);
- return false;
}
static bool HandleDevCommand(ChatHandler* handler, Optional<bool> enableArg)
@@ -548,6 +547,7 @@ public:
if (!session)
{
+ handler->SendErrorMessage(LANG_USE_BOL);
return false;
}
@@ -582,9 +582,6 @@ public:
SetDevMod(false);
return true;
}
-
- handler->SendErrorMessage(LANG_USE_BOL);
- return false;
}
static bool HandleGPSCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
@@ -3069,6 +3066,48 @@ public:
handler->SendErrorMessage(LANG_CMD_NO_DOOR_FOUND, range ? *range : 5.0f);
return false;
}
+
+ static bool HandleBMCommand(ChatHandler* handler, Optional<bool> enableArg)
+ {
+ WorldSession* session = handler->GetSession();
+
+ if (!session)
+ return false;
+
+ auto SetBMMod = [&](bool enable)
+ {
+ char const* enabled = "ON";
+ char const* disabled = "OFF";
+ handler->SendNotification(LANG_COMMAND_BEASTMASTER_MODE, enable ? enabled : disabled);
+
+ session->GetPlayer()->SetBeastMaster(enable);
+ };
+
+ if (!enableArg)
+ {
+ if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->IsDeveloper())
+ SetBMMod(true);
+ else
+ SetBMMod(false);
+
+ return true;
+ }
+
+ if (*enableArg)
+ {
+ SetBMMod(true);
+ return true;
+ }
+ else
+ {
+ SetBMMod(false);
+ return true;
+ }
+
+ handler->SendErrorMessage(LANG_USE_BOL);
+ return false;
+ }
+
};
void AddSC_misc_commandscript()
diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_tenris_mirkblood.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_tenris_mirkblood.cpp
index 8784c79914..07eb7da114 100644
--- a/src/server/scripts/EasternKingdoms/Karazhan/boss_tenris_mirkblood.cpp
+++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_tenris_mirkblood.cpp
@@ -290,8 +290,8 @@ public:
bool OnTrigger(Player* player, AreaTrigger const* /*trigger*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
- if (instance->GetBossState(DATA_MIRKBLOOD) != DONE)
- if (Creature* mirkblood = instance->GetCreature(DATA_MIRKBLOOD))
+ if (Creature* mirkblood = instance->GetCreature(DATA_MIRKBLOOD))
+ if (mirkblood->IsAlive() && !mirkblood->IsInCombat())
mirkblood->AI()->Talk(SAY_APPROACH, player);
return false;
@@ -306,8 +306,8 @@ public:
bool OnTrigger(Player* player, AreaTrigger const* /*trigger*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
- if (instance->GetBossState(DATA_MIRKBLOOD) != DONE)
- if (Creature* mirkblood = instance->GetCreature(DATA_MIRKBLOOD))
+ if (Creature* mirkblood = instance->GetCreature(DATA_MIRKBLOOD))
+ if (mirkblood->IsAlive() && mirkblood->IsImmuneToPC())
mirkblood->SetImmuneToPC(false);
return false;
diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
index 1e80e0982f..8186c7f364 100644
--- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
+++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp
@@ -74,7 +74,6 @@ void AddSC_instance_wailing_caverns(); //Wailing caverns
void AddSC_zulfarrak();
void AddSC_instance_zulfarrak(); //Zul'Farrak instance script
void AddSC_ashenvale();
-void AddSC_azshara();
void AddSC_azuremyst_isle();
void AddSC_bloodmyst_isle();
void AddSC_boss_azuregos();
@@ -157,7 +156,6 @@ void AddKalimdorScripts()
AddSC_zulfarrak();
AddSC_instance_zulfarrak(); //Zul'Farrak instance script
AddSC_ashenvale();
- AddSC_azshara();
AddSC_azuremyst_isle();
AddSC_bloodmyst_isle();
AddSC_boss_azuregos();
diff --git a/src/server/scripts/Kalimdor/zone_azshara.cpp b/src/server/scripts/Kalimdor/zone_azshara.cpp
deleted file mode 100644
index 1a10cec1db..0000000000
--- a/src/server/scripts/Kalimdor/zone_azshara.cpp
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by the
- * Free Software Foundation; either version 3 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "CreatureScript.h"
-#include "Player.h"
-#include "ScriptedCreature.h"
-#include "ScriptedGossip.h"
-
-/*####
-# npc_rizzle_sprysprocket
-####*/
-
-enum RizzleSprysprocketData
-{
- QUEST_CHASING_THE_MOONSTONE = 10994,
-
- NPC_DEPTH_CHARGE = 23025,
-
- SPELL_RIZZLE_BLACKJACK = 39865,
- SPELL_RIZZLE_ESCAPE = 39871,
- SPELL_RIZZLE_FROST_GRENADE = 40525,
- SPELL_DEPTH_CHARGE_TRAP = 38576,
- SPELL_PERIODIC_DEPTH_CHARGE = 39912,
- SPELL_GIVE_SOUTHFURY_MOONSTONE = 39886,
-
- SAY_RIZZLE_START = 0,
- SAY_RIZZLE_GRENADE = 1,
- SAY_RIZZLE_FINAL = 2,
- MSG_ESCAPE_NOTICE = 3,
- GOSSIP_GET_MOONSTONE = 21893
-
-};
-
-Position const WPs[58] =
-{
- {3691.97f, -3962.41f, 35.9118f, 3.67f},
- {3675.02f, -3960.49f, 35.9118f, 3.67f},
- {3653.19f, -3958.33f, 33.9118f, 3.59f},
- {3621.12f, -3958.51f, 29.9118f, 3.48f},
- {3604.86f, -3963, 29.9118f, 3.48f},
- {3569.94f, -3970.25f, 29.9118f, 3.44f},
- {3541.03f, -3975.64f, 29.9118f, 3.41f},
- {3510.84f, -3978.71f, 29.9118f, 3.41f},
- {3472.7f, -3997.07f, 29.9118f, 3.35f},
- {3439.15f, -4014.55f, 29.9118f, 3.29f},
- {3412.8f, -4025.87f, 29.9118f, 3.25f},
- {3384.95f, -4038.04f, 29.9118f, 3.24f},
- {3346.77f, -4052.93f, 29.9118f, 3.22f},
- {3299.56f, -4071.59f, 29.9118f, 3.20f},
- {3261.22f, -4080.38f, 30.9118f, 3.19f},
- {3220.68f, -4083.09f, 31.9118f, 3.18f},
- {3187.11f, -4070.45f, 33.9118f, 3.16f},
- {3162.78f, -4062.75f, 33.9118f, 3.15f},
- {3136.09f, -4050.32f, 33.9118f, 3.07f},
- {3119.47f, -4044.51f, 36.0363f, 3.07f},
- {3098.95f, -4019.8f, 33.9118f, 3.07f},
- {3073.07f, -4011.42f, 33.9118f, 3.07f},
- {3051.71f, -3993.37f, 33.9118f, 3.02f},
- {3027.52f, -3978.6f, 33.9118f, 3.00f},
- {3003.78f, -3960.14f, 33.9118f, 2.98f},
- {2977.99f, -3941.98f, 31.9118f, 2.96f},
- {2964.57f, -3932.07f, 30.9118f, 2.96f},
- {2947.9f, -3921.31f, 29.9118f, 2.96f},
- {2924.91f, -3910.8f, 29.9118f, 2.94f},
- {2903.04f, -3896.42f, 29.9118f, 2.93f},
- {2884.75f, -3874.03f, 29.9118f, 2.90f},
- {2868.19f, -3851.48f, 29.9118f, 2.82f},
- {2854.62f, -3819.72f, 29.9118f, 2.80f},
- {2825.53f, -3790.4f, 29.9118f, 2.744f},
- {2804.31f, -3773.05f, 29.9118f, 2.71f},
- {2769.78f, -3763.57f, 29.9118f, 2.70f},
- {2727.23f, -3745.92f, 30.9118f, 2.69f},
- {2680.12f, -3737.49f, 30.9118f, 2.67f},
- {2647.62f, -3739.94f, 30.9118f, 2.66f},
- {2616.6f, -3745.75f, 30.9118f, 2.64f},
- {2589.38f, -3731.97f, 30.9118f, 2.61f},
- {2562.94f, -3722.35f, 31.9118f, 2.56f},
- {2521.05f, -3716.6f, 31.9118f, 2.55f},
- {2485.26f, -3706.67f, 31.9118f, 2.51f},
- {2458.93f, -3696.67f, 31.9118f, 2.51f},
- {2432, -3692.03f, 31.9118f, 2.46f},
- {2399.59f, -3681.97f, 31.9118f, 2.45f},
- {2357.75f, -3666.6f, 31.9118f, 2.44f},
- {2311.99f, -3656.88f, 31.9118f, 2.94f},
- {2263.41f, -3649.55f, 31.9118f, 3.02f},
- {2209.05f, -3641.76f, 31.9118f, 2.99f},
- {2164.83f, -3637.64f, 31.9118f, 3.15f},
- {2122.42f, -3639, 31.9118f, 3.21f},
- {2075.73f, -3643.59f, 31.9118f, 3.22f},
- {2033.59f, -3649.52f, 31.9118f, 3.42f},
- {1985.22f, -3662.99f, 31.9118f, 3.42f},
- {1927.09f, -3679.56f, 33.9118f, 3.42f},
- {1873.57f, -3695.32f, 33.9118f, 3.44f}
-};
-
-class npc_rizzle_sprysprocket : public CreatureScript
-{
-public:
- npc_rizzle_sprysprocket() : CreatureScript("npc_rizzle_sprysprocket") { }
-
- struct npc_rizzle_sprysprocketAI : public ScriptedAI
- {
- npc_rizzle_sprysprocketAI(Creature* creature) : ScriptedAI(creature) { }
-
- void Reset() override
- {
- SpellEscapeTimer = 1300;
- TeleportTimer = 3500;
- CheckTimer = 10000;
- GrenadeTimer = 30000;
- MustDieTimer = 3000;
- CurrWP = 0;
-
- PlayerGUID.Clear();
-
- MustDie = false;
- Escape = false;
- ContinueWP = false;
- Reached = false;
- }
-
- void JustEngagedWith(Unit* /*who*/) override { }
-
- void AttackStart(Unit* who) override
- {
- if (!who || PlayerGUID)
- return;
-
- Player* player = who->ToPlayer();
-
- if (player && player->GetQuestStatus(QUEST_CHASING_THE_MOONSTONE) == QUEST_STATUS_INCOMPLETE)
- {
- PlayerGUID = who->GetGUID();
- Talk(SAY_RIZZLE_START);
- DoCast(who, SPELL_RIZZLE_BLACKJACK, false);
- return;
- }
- }
-
- void sGossipSelect(Player* player, uint32 /*sender*/, uint32 /*action*/) override
- {
- CloseGossipMenuFor(player);
- me->CastSpell(player, SPELL_GIVE_SOUTHFURY_MOONSTONE, true);
- MustDieTimer = 3000;
- MustDie = true;
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type != POINT_MOTION_TYPE)
- return;
-
- if (id == 57)
- {
- me->DespawnOrUnsummon();
- return;
- }
-
- ++CurrWP;
- ContinueWP = true;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (MustDie)
- {
- if (MustDieTimer <= diff)
- {
- me->DespawnOrUnsummon();
- return;
- }
- else MustDieTimer -= diff;
- }
-
- if (!Escape)
- {
- if (!PlayerGUID)
- return;
-
- if (SpellEscapeTimer <= diff)
- {
- DoCast(me, SPELL_RIZZLE_ESCAPE, false);
- SpellEscapeTimer = 10000;
- }
- else SpellEscapeTimer -= diff;
-
- if (TeleportTimer <= diff)
- {
- // temp solution - unit can't be teleported by core using spelleffect 5, only players
- me->NearTeleportTo(3706.39f, -3969.15f, 35.9118f, me->GetOrientation());
-
- //begin swimming and summon depth charges
- Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);
- if (!player)
- return;
-
- Talk(MSG_ESCAPE_NOTICE, player);
- DoCast(me, SPELL_PERIODIC_DEPTH_CHARGE);
- me->SetHover(true);
- me->SetSwim(true);
- me->SetSpeed(MOVE_RUN, 0.85f, true);
- me->GetMotionMaster()->MovementExpired();
- me->GetMotionMaster()->MovePoint(CurrWP, WPs[CurrWP]);
- Escape = true;
- }
- else TeleportTimer -= diff;
-
- return;
- }
-
- if (ContinueWP)
- {
- me->GetMotionMaster()->MovePoint(CurrWP, WPs[CurrWP]);
- ContinueWP = false;
- }
-
- if (GrenadeTimer <= diff)
- {
- if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID))
- {
- Talk(SAY_RIZZLE_GRENADE, player);
- DoCast(player, SPELL_RIZZLE_FROST_GRENADE, true);
- }
- GrenadeTimer = 30000;
- }
- else GrenadeTimer -= diff;
-
- if (CheckTimer <= diff)
- {
- Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);
- if (!player)
- {
- me->DespawnOrUnsummon();
- return;
- }
-
- if (me->IsWithinDist(player, 10) && me->GetPositionX() > player->GetPositionX() && !Reached)
- {
- Talk(SAY_RIZZLE_FINAL);
- me->ReplaceAllNpcFlags(NPCFlags(1));
- me->SetFaction(FACTION_FRIENDLY);
- me->GetMotionMaster()->MoveIdle();
- me->RemoveAurasDueToSpell(SPELL_PERIODIC_DEPTH_CHARGE);
- Reached = true;
- }
-
- CheckTimer = 1000;
- }
- else CheckTimer -= diff;
- }
-
- private:
- ObjectGuid PlayerGUID;
- uint32 SpellEscapeTimer;
- uint32 TeleportTimer;
- uint32 CheckTimer;
- uint32 GrenadeTimer;
- uint32 MustDieTimer;
- uint32 CurrWP;
- bool MustDie;
- bool Escape;
- bool ContinueWP;
- bool Reached;
- };
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (player->GetQuestStatus(QUEST_CHASING_THE_MOONSTONE) != QUEST_STATUS_INCOMPLETE)
- return true;
-
- AddGossipItemFor(player, GOSSIP_GET_MOONSTONE, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
- SendGossipMenuFor(player, 10811, creature->GetGUID());
-
- return true;
- }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_rizzle_sprysprocketAI(creature);
- }
-};
-
-/*####
-# npc_depth_charge
-####*/
-class npc_depth_charge : public CreatureScript
-{
-public:
- npc_depth_charge() : CreatureScript("npc_depth_charge") { }
-
- struct npc_depth_chargeAI : public ScriptedAI
- {
- npc_depth_chargeAI(Creature* creature) : ScriptedAI(creature) { }
-
- bool WeMustDie;
- uint32 WeMustDieTimer;
-
- void Reset() override
- {
- me->SetHover(true);
- me->SetSwim(true);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- WeMustDie = false;
- WeMustDieTimer = 1000;
- }
-
- void JustEngagedWith(Unit* /*who*/) override { }
-
- void AttackStart(Unit* /*who*/) override { }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (!who)
- return;
-
- if (who->IsPlayer() && me->IsWithinDistInMap(who, 5))
- {
- DoCast(who, SPELL_DEPTH_CHARGE_TRAP);
- WeMustDie = true;
- return;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (WeMustDie)
- {
- if (WeMustDieTimer <= diff)
- me->DespawnOrUnsummon();
- else
- WeMustDieTimer -= diff;
- }
- return;
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_depth_chargeAI(creature);
- }
-};
-
-void AddSC_azshara()
-{
- new npc_rizzle_sprysprocket();
- new npc_depth_charge();
-}
diff --git a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
index 359a18c575..01761599ec 100644
--- a/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/zone_bloodmyst_isle.cpp
@@ -24,7 +24,7 @@
######*/
//possible creatures to be spawned
-uint32 const possibleSpawns[32] = {17322, 17661, 17496, 17522, 17340, 17352, 17333, 17524, 17654, 17348, 17339, 17345, 17359, 17353, 17336, 17550, 17330, 17701, 17321, 17325, 17320, 17683, 17342, 17715, 17334, 17341, 17338, 17337, 17346, 17344, 17327};
+uint32 const possibleSpawns[32] = {17322, 17661, 17496, 17522, 17340, 17352, 17333, 17524, 17654, 17348, 17339, 17345, 17353, 17336, 17550, 17330, 17701, 17321, 17325, 17320, 17683, 17342, 17715, 17334, 17341, 17338, 17337, 17346, 17344, 17327};
enum WebbedCreature
{
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp
index 649a60c6f2..3ed2a5f79a 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp
@@ -246,6 +246,12 @@ public:
events.Reset();
}
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (pInstance && pInstance->GetData(DATA_INSTANCE_PROGRESS) >= INSTANCE_PROGRESS_GRAND_CHAMPIONS_REACHED_DEST)
+ ScriptedAI::MoveInLineOfSight(who);
+ }
+
void JustEngagedWith(Unit* /*who*/) override
{
events.Reset();
@@ -410,6 +416,12 @@ public:
}
}
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (pInstance && pInstance->GetData(DATA_INSTANCE_PROGRESS) >= INSTANCE_PROGRESS_GRAND_CHAMPIONS_REACHED_DEST)
+ npc_escortAI::MoveInLineOfSight(who);
+ }
+
void JustEngagedWith(Unit* /*who*/) override
{
if (pInstance && pInstance->GetData(DATA_INSTANCE_PROGRESS) == INSTANCE_PROGRESS_CHAMPIONS_UNMOUNTED )
diff --git a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp
index 18a30b7dbc..e4260080f8 100644
--- a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp
+++ b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp
@@ -125,17 +125,18 @@ public:
void Reset() override
{
BossAI::Reset();
- for (uint8 i = 0; i < 5; i++)
- me->SummonCreature(NPC_LIVING_MOJO, mojoPosition[i].GetPositionX(), mojoPosition[i].GetPositionY(), mojoPosition[i].GetPositionZ(), 0, TEMPSUMMON_MANUAL_DESPAWN, 0);
-
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- }
-
- void InitializeAI() override
- {
- BossAI::InitializeAI();
- me->CastSpell(me, SPELL_FREEZE_ANIM, true);
+ if (!me->IsInEvadeMode())
+ {
+ me->CastSpell(me, SPELL_FREEZE_ANIM, true);
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ for (const auto & i : mojoPosition)
+ me->SummonCreature(NPC_LIVING_MOJO, i.GetPositionX(), i.GetPositionY(), i.GetPositionZ(), 0, TEMPSUMMON_MANUAL_DESPAWN, 0);
+ }
+ else
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ }
}
void JustReachedHome() override
@@ -144,9 +145,9 @@ public:
me->CastSpell(me, SPELL_FREEZE_ANIM, true);
}
- void JustEngagedWith(Unit* who) override
+ void ScheduleTasks() override
{
- BossAI::JustEngagedWith(who);
+ events.ScheduleEvent(EVENT_COLOSSUS_START_FIGHT, 1s);
events.ScheduleEvent(EVENT_COLOSSUS_MIGHTY_BLOW, 10s);
events.ScheduleEvent(EVENT_COLOSSUS_MORTAL_STRIKE, 7s);
events.ScheduleEvent(EVENT_COLOSSUS_HEALTH_1, 1s);
@@ -183,6 +184,7 @@ public:
summons.Despawn(summon);
if (summon->GetEntry() == NPC_DRAKKARI_ELEMENTAL)
{
+ me->SetHealth(me->GetMaxHealth() / 2);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM);
if (me->GetVictim())
@@ -231,7 +233,7 @@ public:
events.ScheduleEvent(EVENT_COLOSSUS_HEALTH_1, 1s);
break;
case EVENT_COLOSSUS_HEALTH_2:
- if (me->HealthBelowPct(21))
+ if (me->HealthBelowPct(2))
{
me->CastSpell(me, SPELL_EMERGE, false);
me->CastSpell(me, SPELL_EMERGE_SUMMON, true);
@@ -301,7 +303,7 @@ public:
switch (events.ExecuteEvent())
{
case EVENT_ELEMENTAL_HEALTH:
- if (me->HealthBelowPct(51))
+ if (me->HealthBelowPct(56))
{
me->CastSpell(me, SPELL_FACE_ME, true);
me->CastSpell(me, SPELL_SURGE_VISUAL, true);
@@ -315,7 +317,7 @@ public:
case EVENT_ELEMENTAL_SURGE:
Talk(SAY_SURGE);
me->CastSpell(me, SPELL_SURGE_VISUAL, true);
- me->CastSpell(me->GetVictim(), SPELL_SURGE, false);
+ DoCastRandomTarget(SPELL_SURGE, 0, 40, true, false, true);
events.ScheduleEvent(EVENT_ELEMENTAL_SURGE, 15s);
break;
case EVENT_ELEMENTAL_VOLLEY:
diff --git a/src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp b/src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp
index e0be1dd9d9..5e6fd02aa4 100644
--- a/src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp
+++ b/src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp
@@ -92,12 +92,18 @@ public:
BossAI::JustEngagedWith(who);
me->CastSpell(me, SPELL_MOJO_FRENZY, true);
- events.ScheduleEvent(EVENT_GROUND_TREMOR, 18s);
- events.ScheduleEvent(EVENT_NUMBLING_SHOUT, 10s);
+ events.ScheduleEvent(EVENT_GROUND_TREMOR, 13s, 30s);
+ events.ScheduleEvent(EVENT_NUMBLING_SHOUT, 8s, 38s);
events.ScheduleEvent(EVENT_DETERMINED_STAB, 20s);
events.ScheduleEvent(EVENT_TRANSFORMATION, 12s);
}
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ summons.DespawnAll();
+ BossAI::EnterEvadeMode(why);
+ }
+
void SpellHitTarget(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Id == SPELL_TRANSFORMATION)
@@ -113,6 +119,7 @@ public:
{
Talk(SAY_DEATH);
Talk(EMOTE_ALTAR);
+
BossAI::JustDied(killer);
}
@@ -144,29 +151,52 @@ public:
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- switch (events.ExecuteEvent())
+ while (uint32 eventId = events.ExecuteEvent())
{
- case EVENT_GROUND_TREMOR:
- if (roll_chance_i(50))
- Talk(SAY_QUAKE);
- me->CastSpell(me, me->GetDisplayId() != me->GetNativeDisplayId() ? SPELL_QUAKE : SPELL_GROUND_TREMOR, false);
- events.ScheduleEvent(EVENT_GROUND_TREMOR, 10s);
- break;
- case EVENT_NUMBLING_SHOUT:
- me->CastSpell(me, me->GetDisplayId() != me->GetNativeDisplayId() ? SPELL_NUMBING_ROAR : SPELL_NUMBING_SHOUT, false);
- events.ScheduleEvent(EVENT_NUMBLING_SHOUT, 10s);
- break;
- case EVENT_DETERMINED_STAB:
- me->CastSpell(me->GetVictim(), me->GetDisplayId() != me->GetNativeDisplayId() ? SPELL_DETERMINED_GORE : SPELL_DETERMINED_STAB, false);
- events.ScheduleEvent(EVENT_DETERMINED_STAB, 8s);
- break;
- case EVENT_TRANSFORMATION:
- Talk(EMOTE_TRANSFORM);
- Talk(SAY_TRANSFORM);
- me->CastSpell(me, SPELL_TRANSFORMATION, false);
- me->CastSpell(me, SPELL_SUMMON_PHANTOM_TRANSFORM, true);
- events.ScheduleEvent(EVENT_TRANSFORMATION, 10s);
- break;
+ switch (eventId)
+ {
+ case EVENT_GROUND_TREMOR:
+ if (roll_chance_i(50))
+ Talk(SAY_QUAKE);
+
+ if (me->GetDisplayId() != me->GetNativeDisplayId())
+ {
+ me->CastSpell(me, SPELL_QUAKE, false);
+ events.ScheduleEvent(EVENT_GROUND_TREMOR, 16s, 63s);
+ }
+ else
+ {
+ me->CastSpell(me, SPELL_GROUND_TREMOR, false);
+ events.ScheduleEvent(EVENT_GROUND_TREMOR, 13s, 27s);
+ }
+ return;
+
+ case EVENT_NUMBLING_SHOUT:
+ if (me->GetDisplayId() != me->GetNativeDisplayId())
+ {
+ me->CastSpell(me, SPELL_NUMBING_ROAR, false);
+ events.ScheduleEvent(EVENT_NUMBLING_SHOUT, 8s, 54s);
+ }
+ else
+ {
+ me->CastSpell(me, SPELL_NUMBING_SHOUT, false);
+ events.ScheduleEvent(EVENT_NUMBLING_SHOUT, 6s, 27s);
+ }
+ return;
+
+ case EVENT_DETERMINED_STAB:
+ me->CastSpell(me->GetVictim(), me->GetDisplayId() != me->GetNativeDisplayId() ? SPELL_DETERMINED_GORE : SPELL_DETERMINED_STAB, false);
+ events.ScheduleEvent(EVENT_DETERMINED_STAB, 8s);
+ return;
+
+ case EVENT_TRANSFORMATION:
+ Talk(EMOTE_TRANSFORM);
+ Talk(SAY_TRANSFORM);
+ me->CastSpell(me, SPELL_TRANSFORMATION, false);
+ me->CastSpell(me, SPELL_SUMMON_PHANTOM_TRANSFORM, true);
+ events.ScheduleEvent(EVENT_TRANSFORMATION, 10s);
+ return;
+ }
}
DoMeleeAttackIfReady();
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 5b1d646acc..fcd58e2f79 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -5528,6 +5528,148 @@ class spell_gen_food_heart_emote : public AuraScript
}
};
+// 456 - SHOWLABEL Only OFF
+class spell_gen_showlabel_off : public SpellScript
+{
+ PrepareSpellScript(spell_gen_showlabel_off)
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Player* player = GetCaster()->ToPlayer())
+ player->SetGMChat(false);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_showlabel_off::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 2765 - SHOWLABEL Only ON
+class spell_gen_showlabel_on : public SpellScript
+{
+ PrepareSpellScript(spell_gen_showlabel_on)
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Player* player = GetCaster()->ToPlayer())
+ player->SetGMChat(true);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_showlabel_on::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 1509 - GM Only OFF
+class spell_gen_gm_off : public SpellScript
+{
+ PrepareSpellScript(spell_gen_gm_off)
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Player* player = GetCaster()->ToPlayer())
+ {
+ player->SetGameMaster(false);
+ player->UpdateTriggerVisibility();
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_gm_off::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 18139 - GM Only ON
+class spell_gen_gm_on : public SpellScript
+{
+ PrepareSpellScript(spell_gen_gm_on)
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Player* player = GetCaster()->ToPlayer())
+ {
+ player->SetGameMaster(true);
+ player->UpdateTriggerVisibility();
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_gm_on::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 6147 - INVIS Only OFF
+class spell_gen_invis_off : public SpellScript
+{
+ PrepareSpellScript(spell_gen_invis_off)
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Player* player = GetCaster()->ToPlayer())
+ player->SetGMVisible(true);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_invis_off::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 2763 - INVIS Only ON
+class spell_gen_invis_on : public SpellScript
+{
+ PrepareSpellScript(spell_gen_invis_on)
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Player* player = GetCaster()->ToPlayer())
+ player->SetGMVisible(false);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_invis_on::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 20114, 24675 - BM Only OFF
+class spell_gen_bm_off : public SpellScript
+{
+ PrepareSpellScript(spell_gen_bm_off)
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Player* player = GetCaster()->ToPlayer())
+ player->SetBeastMaster(false);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_bm_off::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 20115, 24676 - BM Only ON
+class spell_gen_bm_on : public SpellScript
+{
+ PrepareSpellScript(spell_gen_bm_on)
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ if (Player* player = GetCaster()->ToPlayer())
+ player->SetBeastMaster(true);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_gen_bm_on::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_silithyst);
@@ -5693,4 +5835,12 @@ void AddSC_generic_spell_scripts()
RegisterSpellScriptWithArgs(spell_gen_translocate, "spell_gen_translocate_up", SPELL_TRANSLOCATION_UP);
RegisterSpellScript(spell_gen_cooldown_all);
RegisterSpellScript(spell_gen_food_heart_emote);
+ RegisterSpellScript(spell_gen_showlabel_off);
+ RegisterSpellScript(spell_gen_showlabel_on);
+ RegisterSpellScript(spell_gen_gm_off);
+ RegisterSpellScript(spell_gen_gm_on);
+ RegisterSpellScript(spell_gen_invis_off);
+ RegisterSpellScript(spell_gen_invis_on);
+ RegisterSpellScript(spell_gen_bm_on);
+ RegisterSpellScript(spell_gen_bm_off);
}
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 44d52f0e7d..5b458f44c7 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -1503,16 +1503,20 @@ class spell_item_blessing_of_ancient_kings : public AuraScript
HealInfo* healInfo = eventInfo.GetHealInfo();
if (!healInfo)
- {
return;
- }
int32 absorb = int32(CalculatePct(healInfo->GetHeal(), 15.0f));
// xinef: all heals contribute to one bubble
if (AuraEffect* protEff = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_PROTECTION_OF_ANCIENT_KINGS, 0/*, eventInfo.GetActor()->GetGUID()*/))
{
- // The shield can grow to a maximum size of 20,000 damage absorbtion
- protEff->SetAmount(std::min<int32>(protEff->GetAmount() + absorb, 20000));
+ // The shield is supposed to cap out at 20,000 absorption...
+ absorb += protEff->GetAmount();
+
+ // ...but Blizz wrote this instead. See #23152 for details
+ if (absorb > 20000)
+ absorb = 200000;
+
+ protEff->SetAmount(absorb);
// Refresh and return to prevent replacing the aura
protEff->GetBase()->RefreshDuration();
diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp
index 127bd957aa..704a354248 100644
--- a/src/server/scripts/Spells/spell_quest.cpp
+++ b/src/server/scripts/Spells/spell_quest.cpp
@@ -1364,6 +1364,9 @@ class spell_q12937_relief_for_the_fallen : public AuraScript
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
+ if (!GetCaster() || !GetCaster()->IsPlayer())
+ return;
+
Player* caster = GetCaster()->ToPlayer();
Unit* target = GetUnitOwner();
if (target && target->ToCreature())
diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp
index ff9adc9635..a190384b2d 100644
--- a/src/server/scripts/World/go_scripts.cpp
+++ b/src/server/scripts/World/go_scripts.cpp
@@ -1066,7 +1066,7 @@ class go_southfury_moonstone : public GameObjectScript
public:
go_southfury_moonstone() : GameObjectScript("go_southfury_moonstone") { }
- bool OnGossipHello(Player* player, GameObject* /*go*/) override
+ bool OnGossipHello(Player* player, GameObject* go) override
{
//implicitTarget=48 not implemented as of writing this code, and manual summon may be just ok for our purpose
//player->CastSpell(player, SPELL_SUMMON_RIZZLE, false);
@@ -1076,6 +1076,7 @@ public:
// no need casting spell blackjack, it's casted by script npc_rizzle_sprysprocket.
//creature->CastSpell(player, SPELL_BLACKJACK, false);
creature->AI()->AttackStart(player);
+ go->DespawnOrUnsummon(8000ms);
}
return false;