Merge branch 'master' of github.com:azerothcore/azerothcore-wotlk into Playerbot
This commit is contained in:
@@ -432,7 +432,7 @@ int main(int argc, char** argv)
|
||||
|
||||
// 0 - normal shutdown
|
||||
// 1 - shutdown at error
|
||||
// 2 - restart command used, this code can be used by restarter for restart Warheadd
|
||||
// 2 - restart command used, this code can be used by restarter for restart AzerothCore
|
||||
|
||||
return World::GetExitCode();
|
||||
}
|
||||
|
||||
@@ -939,6 +939,13 @@ ClientCacheVersion = 0
|
||||
|
||||
SessionAddDelay = 10000
|
||||
|
||||
#
|
||||
# GridCleanUpDelay
|
||||
# Description: Time (in milliseconds) grid clean up delay.
|
||||
# Default: 300000 - (5 minutes)
|
||||
|
||||
GridCleanUpDelay = 300000
|
||||
|
||||
#
|
||||
# CloseIdleConnections
|
||||
# Description: Automatically close idle connections.
|
||||
@@ -1244,17 +1251,17 @@ Visibility.GroupMode = 1
|
||||
# Visibility.Distance.Instances
|
||||
# Visibility.Distance.BGArenas
|
||||
# Description: Visibility distance to see other players or gameobjects.
|
||||
# Visibility on continents on retail ~90 yards. In BG/Arenas ~180.
|
||||
# For instances default ~120.
|
||||
# Max limited by active player zone: ~ 333
|
||||
# Visibility on continents on retail ~100 yards. In BG/Arenas ~533.
|
||||
# For instances default ~170.
|
||||
# Max limited by grid size: 533.33333
|
||||
# Min limit is max aggro radius (45) * Rate.Creature.Aggro
|
||||
# Default: 90 - (Visibility.Distance.Continents)
|
||||
# 120 - (Visibility.Distance.Instances)
|
||||
# 180 - (Visibility.Distance.BGArenas)
|
||||
# Default: 100 - (Visibility.Distance.Continents)
|
||||
# 170 - (Visibility.Distance.Instances)
|
||||
# 533 - (Visibility.Distance.BGArenas)
|
||||
|
||||
Visibility.Distance.Continents = 90
|
||||
Visibility.Distance.Instances = 120
|
||||
Visibility.Distance.BGArenas = 180
|
||||
Visibility.Distance.Continents = 100
|
||||
Visibility.Distance.Instances = 170
|
||||
Visibility.Distance.BGArenas = 533
|
||||
|
||||
#
|
||||
# Visibility.Notify.Period.OnContinents
|
||||
@@ -1365,17 +1372,6 @@ DetectPosCollision = 1
|
||||
|
||||
CheckGameObjectLoS = 1
|
||||
|
||||
#
|
||||
# TargetPosRecalculateRange
|
||||
# Description: Max distance from movement target point (+moving unit size) and targeted
|
||||
# object (+size) after that new target movement point calculated.
|
||||
# Range: 0.5-5.0
|
||||
# Default: 1.5
|
||||
# 0.5 - (Minimum, Contact Range, More sensitive reaction to target movement)
|
||||
# 5.0 - (Maximum, Melee attack range, Less CPU usage)
|
||||
|
||||
TargetPosRecalculateRange = 1.5
|
||||
|
||||
#
|
||||
# PreloadAllNonInstancedMapGrids
|
||||
# Description: Preload all grids on all non-instanced maps. This will take a great amount
|
||||
|
||||
@@ -200,7 +200,6 @@ void npc_escortAI::ReturnToLastPoint()
|
||||
|
||||
void npc_escortAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->GetThreatMgr().ClearAllThreat();
|
||||
me->CombatStop(true);
|
||||
me->SetLootRecipient(nullptr);
|
||||
|
||||
@@ -1041,7 +1041,7 @@ const WintergraspTowerCannonData TowerCannon[WG_MAX_TOWER_CANNON] =
|
||||
2,
|
||||
{
|
||||
{ 4448.138184f, 1974.998779f, 441.995911f, 1.967238f },
|
||||
{ 4448.713379f, 1955.148682f, 441.995178f, 0.380733f },
|
||||
{ 4486.3257f, 1954.6545f, 442.0783f, 0.349065840244293212f },
|
||||
{ 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0 },
|
||||
|
||||
@@ -242,6 +242,7 @@ void Arena::EndBattleground(TeamId winnerTeamId)
|
||||
uint8 memberId = 0;
|
||||
for (auto const& [playerGuid, arenaLogEntryData] : ArenaLogEntries)
|
||||
{
|
||||
auto const& score = PlayerScores.find(playerGuid.GetCounter());
|
||||
stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_LOG_MEMBERSTATS);
|
||||
stmt2->SetData(0, fightId);
|
||||
stmt2->SetData(1, ++memberId);
|
||||
@@ -250,9 +251,18 @@ void Arena::EndBattleground(TeamId winnerTeamId)
|
||||
stmt2->SetData(4, arenaLogEntryData.ArenaTeamId);
|
||||
stmt2->SetData(5, arenaLogEntryData.Acc);
|
||||
stmt2->SetData(6, arenaLogEntryData.IP);
|
||||
stmt2->SetData(7, arenaLogEntryData.DamageDone);
|
||||
stmt2->SetData(8, arenaLogEntryData.HealingDone);
|
||||
stmt2->SetData(9, arenaLogEntryData.KillingBlows);
|
||||
if (score != PlayerScores.end())
|
||||
{
|
||||
stmt2->SetData(7, score->second->GetDamageDone());
|
||||
stmt2->SetData(8, score->second->GetHealingDone());
|
||||
stmt2->SetData(9, score->second->GetKillingBlows());
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt2->SetData(7, 0);
|
||||
stmt2->SetData(8, 0);
|
||||
stmt2->SetData(9, 0);
|
||||
}
|
||||
trans->Append(stmt2);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,4 +63,4 @@ private:
|
||||
void EndBattleground(TeamId winnerTeamId) override;
|
||||
};
|
||||
|
||||
#endif // WARHEAD_ARENA_H
|
||||
#endif // ACORE_ARENA_H
|
||||
|
||||
@@ -72,4 +72,4 @@ protected:
|
||||
std::string TeamName{};
|
||||
};
|
||||
|
||||
#endif // WARHEAD_ARENA_SCORE_H
|
||||
#endif // ACORE_ARENA_SCORE_H
|
||||
|
||||
@@ -268,9 +268,6 @@ public:
|
||||
uint32 Acc{0};
|
||||
uint32 ArenaTeamId{0};
|
||||
std::string IP{};
|
||||
uint32 DamageDone{0};
|
||||
uint32 HealingDone{0};
|
||||
uint32 KillingBlows{0};
|
||||
};
|
||||
|
||||
enum BGHonorMode
|
||||
|
||||
@@ -551,6 +551,6 @@ void BattlegroundAB::ApplyPhaseMask()
|
||||
for (auto const& itr : bgPlayerMap)
|
||||
{
|
||||
itr.second->SetPhaseMask(phaseMask, false);
|
||||
itr.second->UpdateObjectVisibility(true, false);
|
||||
itr.second->UpdateObjectVisibility(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,8 +289,22 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
|
||||
}
|
||||
case CONDITION_NEAR_GAMEOBJECT:
|
||||
{
|
||||
condMeets = static_cast<bool>(GetClosestGameObjectWithEntry(object, ConditionValue1, static_cast<float>(ConditionValue2)));
|
||||
break;
|
||||
if (!ConditionValue3)
|
||||
{
|
||||
condMeets = static_cast<bool>(GetClosestGameObjectWithEntry(object, ConditionValue1, static_cast<float>(ConditionValue2)));
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameObject* go = GetClosestGameObjectWithEntry(object, ConditionValue1, static_cast<float>(ConditionValue2)))
|
||||
{
|
||||
if ((go->GetGoState() == GO_STATE_READY && ConditionValue3 == 1) || (go->GetGoState() != GO_STATE_READY && ConditionValue3 == 2))
|
||||
condMeets = true;
|
||||
else
|
||||
condMeets = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
case CONDITION_OBJECT_ENTRY_GUID:
|
||||
{
|
||||
@@ -2124,8 +2138,8 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
|
||||
LOG_ERROR("sql.sql", "NearGameObject condition has non existing gameobject template entry ({}), skipped", cond->ConditionValue1);
|
||||
return false;
|
||||
}
|
||||
if (cond->ConditionValue3)
|
||||
LOG_ERROR("sql.sql", "NearGameObject condition has useless data in value3 ({})!", cond->ConditionValue3);
|
||||
if (cond->ConditionValue3 > 2)
|
||||
LOG_ERROR("sql.sql", "NearGameObject condition for gameobject ID ({}) has data over 2 for value3 ({})!", cond->ConditionValue1, cond->ConditionValue3);
|
||||
break;
|
||||
}
|
||||
case CONDITION_OBJECT_ENTRY_GUID:
|
||||
|
||||
@@ -62,7 +62,7 @@ enum ConditionTypes
|
||||
CONDITION_LEVEL = 27, // level ComparisonType 0 true if unit's level is equal to param1 (param2 can modify the statement)
|
||||
CONDITION_QUEST_COMPLETE = 28, // quest_id 0 0 true if player has quest_id with all objectives complete, but not yet rewarded
|
||||
CONDITION_NEAR_CREATURE = 29, // creature entry distance dead true if there is a creature of entry in range
|
||||
CONDITION_NEAR_GAMEOBJECT = 30, // gameobject entry distance 0 true if there is a gameobject of entry in range
|
||||
CONDITION_NEAR_GAMEOBJECT = 30, // gameobject entry distance GoState true if there is a gameobject of entry in range (param3 can check for GoState, 0 = dont't check, 1 = Ready , 2 = Not Ready)
|
||||
CONDITION_OBJECT_ENTRY_GUID = 31, // TypeID entry guid/Attackable true if object is type TypeID and the entry is 0 or matches entry of the object or matches guid of the object
|
||||
CONDITION_TYPE_MASK = 32, // TypeMask 0 0 true if object is type object's TypeMask matches provided TypeMask
|
||||
CONDITION_RELATION_TO = 33, // ConditionTarget RelationType 0 true if object is in given relation with object specified by ConditionTarget
|
||||
|
||||
@@ -365,17 +365,15 @@ void Creature::RemoveCorpse(bool setSpawnTime, bool skipVisibility)
|
||||
//SaveRespawnTime();
|
||||
}
|
||||
|
||||
float x, y, z, o;
|
||||
GetRespawnPosition(x, y, z, &o);
|
||||
SetHomePosition(x, y, z, o);
|
||||
SetPosition(x, y, z, o);
|
||||
|
||||
// xinef: relocate notifier
|
||||
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
||||
|
||||
// pussywizard: if corpse was removed during falling then the falling will continue after respawn, so stop falling is such case
|
||||
if (IsFalling())
|
||||
StopMoving();
|
||||
|
||||
float x, y, z, o;
|
||||
GetRespawnPosition(x, y, z, &o);
|
||||
UpdateAllowedPositionZ(x, y, z);
|
||||
SetHomePosition(x, y, z, o);
|
||||
GetMap()->CreatureRelocation(this, x, y, z, o);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -537,7 +535,7 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
||||
|
||||
SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool));
|
||||
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(GetLevel(), cInfo->unit_class);
|
||||
float armor = (float)stats->GenerateArmor(cInfo); /// @todo: Why is this treated as uint32 when it's a float?
|
||||
float armor = stats->GenerateArmor(cInfo);
|
||||
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
|
||||
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY]));
|
||||
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE]));
|
||||
@@ -580,13 +578,13 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
||||
ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
|
||||
}
|
||||
|
||||
if (GetMovementTemplate().IsRooted())
|
||||
{
|
||||
SetControlled(true, UNIT_STATE_ROOT);
|
||||
}
|
||||
|
||||
SetDetectionDistance(cInfo->detection_range);
|
||||
|
||||
// Update movement
|
||||
if (IsRooted())
|
||||
SetControlled(true, UNIT_STATE_ROOT);
|
||||
UpdateMovementFlags();
|
||||
|
||||
LoadSpellTemplateImmunity();
|
||||
|
||||
if (updateAI)
|
||||
@@ -1489,6 +1487,9 @@ void Creature::SelectLevel(bool changelevel)
|
||||
uint8 minlevel = std::min(cInfo->maxlevel, cInfo->minlevel);
|
||||
uint8 maxlevel = std::max(cInfo->maxlevel, cInfo->minlevel);
|
||||
uint8 level = minlevel == maxlevel ? minlevel : urand(minlevel, maxlevel);
|
||||
|
||||
sScriptMgr->OnBeforeCreatureSelectLevel(cInfo, this, level);
|
||||
|
||||
if (changelevel)
|
||||
SetLevel(level);
|
||||
|
||||
@@ -2078,9 +2079,7 @@ void Creature::Respawn(bool force)
|
||||
m_respawnedTime = GameTime::GetGameTime().count();
|
||||
}
|
||||
m_respawnedTime = GameTime::GetGameTime().count();
|
||||
// xinef: relocate notifier, fixes npc appearing in corpse position after forced respawn (instead of spawn)
|
||||
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
||||
UpdateObjectVisibility(false);
|
||||
UpdateObjectVisibility();
|
||||
}
|
||||
|
||||
void Creature::ForcedDespawn(uint32 timeMSToDespawn, Seconds forceRespawnTimer)
|
||||
@@ -2753,6 +2752,14 @@ bool Creature::IsSpellProhibited(SpellSchoolMask idSchoolMask) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Creature::ClearProhibitedSpellTimers()
|
||||
{
|
||||
for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
|
||||
{
|
||||
m_ProhibitSchoolTime[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::_AddCreatureSpellCooldown(uint32 spell_id, uint16 categoryId, uint32 end_time)
|
||||
{
|
||||
CreatureSpellCooldown spellCooldown;
|
||||
@@ -3110,7 +3117,7 @@ bool Creature::SetDisableGravity(bool disable, bool packetOnly /*= false*/, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !GetMovementTemplate().IsRooted())
|
||||
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !IsRooted())
|
||||
{
|
||||
if (IsLevitating())
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_FLY);
|
||||
@@ -3259,7 +3266,7 @@ bool Creature::SetHover(bool enable, bool packetOnly /*= false*/, bool updateAni
|
||||
if (!packetOnly && !Unit::SetHover(enable))
|
||||
return false;
|
||||
|
||||
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !GetMovementTemplate().IsRooted())
|
||||
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !IsRooted())
|
||||
{
|
||||
if (IsLevitating())
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_FLY);
|
||||
|
||||
@@ -82,6 +82,7 @@ public:
|
||||
[[nodiscard]] bool CanEnterWater() const override;
|
||||
[[nodiscard]] bool CanFly() const override { return GetMovementTemplate().IsFlightAllowed() || IsFlying(); }
|
||||
[[nodiscard]] bool CanHover() const { return GetMovementTemplate().Ground == CreatureGroundMovementType::Hover || IsHovering(); }
|
||||
[[nodiscard]] bool IsRooted() const { return GetMovementTemplate().IsRooted(); }
|
||||
|
||||
MovementGeneratorType GetDefaultMovementType() const override { return m_defaultMovementType; }
|
||||
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
|
||||
@@ -165,6 +166,7 @@ public:
|
||||
[[nodiscard]] uint32 GetSpellCooldown(uint32 spell_id) const;
|
||||
void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs) override;
|
||||
[[nodiscard]] bool IsSpellProhibited(SpellSchoolMask idSchoolMask) const;
|
||||
void ClearProhibitedSpellTimers();
|
||||
|
||||
[[nodiscard]] bool HasSpell(uint32 spellID) const override;
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ struct CreatureBaseStats
|
||||
{
|
||||
uint32 BaseHealth[MAX_EXPANSIONS];
|
||||
uint32 BaseMana;
|
||||
uint32 BaseArmor;
|
||||
float BaseArmor;
|
||||
uint32 AttackPower;
|
||||
uint32 RangedAttackPower;
|
||||
float BaseDamage[MAX_EXPANSIONS];
|
||||
@@ -313,9 +313,9 @@ struct CreatureBaseStats
|
||||
return uint32(std::ceil(BaseMana * info->ModMana));
|
||||
}
|
||||
|
||||
uint32 GenerateArmor(CreatureTemplate const* info) const
|
||||
float GenerateArmor(CreatureTemplate const* info) const
|
||||
{
|
||||
return uint32(std::ceil(BaseArmor * info->ModArmor));
|
||||
return std::ceil(BaseArmor * info->ModArmor);
|
||||
}
|
||||
|
||||
float GenerateBaseDamage(CreatureTemplate const* info) const
|
||||
|
||||
@@ -2280,7 +2280,14 @@ void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/
|
||||
if (!IsDestructibleBuilding())
|
||||
return;
|
||||
|
||||
if (!m_goValue.Building.MaxHealth || !change)
|
||||
// if this building doesn't have health, return
|
||||
if (!m_goValue.Building.MaxHealth)
|
||||
return;
|
||||
|
||||
sScriptMgr->OnGameObjectModifyHealth(this, attackerOrHealer, change, sSpellMgr->GetSpellInfo(spellId));
|
||||
|
||||
// if the health isn't being changed, return
|
||||
if (!change)
|
||||
return;
|
||||
|
||||
if (!m_allowModifyDestructibleBuilding)
|
||||
|
||||
@@ -65,7 +65,7 @@ constexpr float VisibilityDistances[AsUnderlyingType(VisibilityDistanceType::Max
|
||||
VISIBILITY_DISTANCE_SMALL,
|
||||
VISIBILITY_DISTANCE_LARGE,
|
||||
VISIBILITY_DISTANCE_GIGANTIC,
|
||||
VISIBILITY_DISTANCE_INFINITE
|
||||
MAX_VISIBILITY_DISTANCE
|
||||
};
|
||||
|
||||
Object::Object() : m_PackGUID(sizeof(uint64) + 1)
|
||||
@@ -2922,7 +2922,7 @@ void WorldObject::DestroyForNearbyPlayers()
|
||||
}
|
||||
}
|
||||
|
||||
void WorldObject::UpdateObjectVisibility(bool /*forced*/, bool /*fromUpdate*/)
|
||||
void WorldObject::UpdateObjectVisibility(bool /*forced*/)
|
||||
{
|
||||
//updates object's visibility for nearby players
|
||||
Acore::VisibleChangesNotifier notifier(*this);
|
||||
@@ -2931,28 +2931,7 @@ void WorldObject::UpdateObjectVisibility(bool /*forced*/, bool /*fromUpdate*/)
|
||||
|
||||
void WorldObject::AddToNotify(uint16 f)
|
||||
{
|
||||
if (!(m_notifyflags & f))
|
||||
if (Unit* u = ToUnit())
|
||||
{
|
||||
if (f & NOTIFY_VISIBILITY_CHANGED)
|
||||
{
|
||||
uint32 EVENT_VISIBILITY_DELAY = u->FindMap() ? DynamicVisibilityMgr::GetVisibilityNotifyDelay(u->FindMap()->GetEntry()->map_type) : 1000;
|
||||
|
||||
uint32 diff = getMSTimeDiff(u->m_last_notify_mstime, GameTime::GetGameTimeMS().count());
|
||||
if (diff >= EVENT_VISIBILITY_DELAY / 2)
|
||||
EVENT_VISIBILITY_DELAY /= 2;
|
||||
else
|
||||
EVENT_VISIBILITY_DELAY -= diff;
|
||||
u->m_delayed_unit_relocation_timer = EVENT_VISIBILITY_DELAY;
|
||||
u->m_last_notify_mstime = GameTime::GetGameTimeMS().count() + EVENT_VISIBILITY_DELAY - 1;
|
||||
}
|
||||
else if (f & NOTIFY_AI_RELOCATION)
|
||||
{
|
||||
u->m_delayed_unit_ai_notify_timer = u->FindMap() ? DynamicVisibilityMgr::GetAINotifyDelay(u->FindMap()->GetEntry()->map_type) : 500;
|
||||
}
|
||||
|
||||
m_notifyflags |= f;
|
||||
}
|
||||
m_notifyflags |= f;
|
||||
}
|
||||
|
||||
struct WorldObjectChangeAccumulator
|
||||
|
||||
@@ -379,14 +379,23 @@ class MovableMapObject
|
||||
template<class T> friend class RandomMovementGenerator;
|
||||
|
||||
protected:
|
||||
MovableMapObject() = default;
|
||||
MovableMapObject() : _moveState(MAP_OBJECT_CELL_MOVE_NONE)
|
||||
{
|
||||
_newPosition.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
private:
|
||||
Cell _currentCell;
|
||||
[[nodiscard]] Cell const& GetCurrentCell() const { return _currentCell; }
|
||||
void SetCurrentCell(Cell const& cell) { _currentCell = cell; }
|
||||
|
||||
Cell _currentCell;
|
||||
MapObjectCellMoveState _moveState{MAP_OBJECT_CELL_MOVE_NONE};
|
||||
MapObjectCellMoveState _moveState;
|
||||
Position _newPosition;
|
||||
void SetNewCellPosition(float x, float y, float z, float o)
|
||||
{
|
||||
_moveState = MAP_OBJECT_CELL_MOVE_ACTIVE;
|
||||
_newPosition.Relocate(x, y, z, o);
|
||||
}
|
||||
};
|
||||
|
||||
class WorldObject : public Object, public WorldLocation
|
||||
@@ -538,7 +547,7 @@ public:
|
||||
void GetDeadCreatureListInGrid(std::list<Creature*>& lList, float maxSearchRange, bool alive = false) const;
|
||||
|
||||
void DestroyForNearbyPlayers();
|
||||
virtual void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false);
|
||||
virtual void UpdateObjectVisibility(bool forced = true);
|
||||
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& player_set) override;
|
||||
void GetCreaturesWithEntryInRange(std::list<Creature*>& creatureList, float radius, uint32 entry);
|
||||
|
||||
|
||||
@@ -28,16 +28,15 @@
|
||||
#define VISIBILITY_INC_FOR_GOBJECTS 30.0f // pussywizard
|
||||
#define SPELL_SEARCHER_COMPENSATION 30.0f // increase searchers size in case we have large npc near cell border
|
||||
#define TRADE_DISTANCE 11.11f
|
||||
#define MAX_VISIBILITY_DISTANCE 250.0f // max distance for visible objects, experimental
|
||||
#define MAX_VISIBILITY_DISTANCE SIZE_OF_GRIDS // max distance for visible objects, experimental
|
||||
#define SIGHT_RANGE_UNIT 50.0f
|
||||
#define MAX_SEARCHER_DISTANCE 150.0f // pussywizard: replace the use of MAX_VISIBILITY_DISTANCE in searchers, because MAX_VISIBILITY_DISTANCE is quite too big for this purpose
|
||||
#define VISIBILITY_DISTANCE_INFINITE 533.0f
|
||||
#define VISIBILITY_DISTANCE_GIGANTIC 400.0f
|
||||
#define VISIBILITY_DISTANCE_LARGE 200.0f
|
||||
#define VISIBILITY_DISTANCE_NORMAL 100.0f
|
||||
#define VISIBILITY_DISTANCE_SMALL 50.0f
|
||||
#define VISIBILITY_DISTANCE_TINY 25.0f
|
||||
#define DEFAULT_VISIBILITY_DISTANCE 100.0f // default visible distance, 100 yards on continents
|
||||
#define DEFAULT_VISIBILITY_DISTANCE VISIBILITY_DISTANCE_NORMAL // default visible distance, 100 yards on continents
|
||||
#define DEFAULT_VISIBILITY_INSTANCE 170.0f // default visible distance in instances, 170 yards
|
||||
#define VISIBILITY_DIST_WINTERGRASP 175.0f
|
||||
#define DEFAULT_VISIBILITY_BGARENAS 533.0f // default visible distance in BG/Arenas, roughly 533 yards
|
||||
|
||||
@@ -1294,6 +1294,8 @@ uint8 Player::GetChatTag() const
|
||||
tag |= CHAT_TAG_DND;
|
||||
if (isAFK())
|
||||
tag |= CHAT_TAG_AFK;
|
||||
if (IsCommentator())
|
||||
tag |= CHAT_TAG_COM;
|
||||
if (IsDeveloper())
|
||||
tag |= CHAT_TAG_DEV;
|
||||
|
||||
@@ -4653,7 +4655,7 @@ void Player::DurabilityLossAll(double percent, bool inventory)
|
||||
|
||||
void Player::DurabilityLoss(Item* item, double percent)
|
||||
{
|
||||
if(!item)
|
||||
if(!item || percent == 0.0)
|
||||
return;
|
||||
|
||||
uint32 pMaxDurability = item ->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
|
||||
|
||||
@@ -839,7 +839,7 @@ enum PlayerChatTag
|
||||
CHAT_TAG_AFK = 0x01,
|
||||
CHAT_TAG_DND = 0x02,
|
||||
CHAT_TAG_GM = 0x04,
|
||||
CHAT_TAG_COM = 0x08, // Commentator
|
||||
CHAT_TAG_COM = 0x08, // Commentator tag. Do not exist in clean client
|
||||
CHAT_TAG_DEV = 0x10,
|
||||
};
|
||||
|
||||
@@ -1139,6 +1139,8 @@ public:
|
||||
void SendTaxiNodeStatusMultiple();
|
||||
// mount_id can be used in scripting calls
|
||||
|
||||
[[nodiscard]] bool IsCommentator() const { return HasPlayerFlag(PLAYER_FLAGS_COMMENTATOR2); }
|
||||
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); }
|
||||
[[nodiscard]] bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; }
|
||||
@@ -1553,6 +1555,7 @@ public:
|
||||
void SaveToDB(CharacterDatabaseTransaction trans, bool create, bool logout);
|
||||
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction trans); // fast save function for item/money cheating preventing
|
||||
void SaveGoldToDB(CharacterDatabaseTransaction trans);
|
||||
void _SaveSkills(CharacterDatabaseTransaction trans);
|
||||
|
||||
static void Customize(CharacterCustomizeInfo const* customizeInfo, CharacterDatabaseTransaction trans);
|
||||
static void SavePositionInDB(uint32 mapid, float x, float y, float z, float o, uint32 zone, ObjectGuid guid);
|
||||
@@ -2349,7 +2352,7 @@ public:
|
||||
bool IsVisibleGloballyFor(Player const* player) const;
|
||||
|
||||
void GetInitialVisiblePackets(Unit* target);
|
||||
void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false) override;
|
||||
void UpdateObjectVisibility(bool forced = true) override;
|
||||
void UpdateVisibilityForPlayer(bool mapChange = false);
|
||||
void UpdateVisibilityOf(WorldObject* target);
|
||||
void UpdateTriggerVisibility();
|
||||
@@ -2696,7 +2699,6 @@ public:
|
||||
void _SaveWeeklyQuestStatus(CharacterDatabaseTransaction trans);
|
||||
void _SaveMonthlyQuestStatus(CharacterDatabaseTransaction trans);
|
||||
void _SaveSeasonalQuestStatus(CharacterDatabaseTransaction trans);
|
||||
void _SaveSkills(CharacterDatabaseTransaction trans);
|
||||
void _SaveSpells(CharacterDatabaseTransaction trans);
|
||||
void _SaveEquipmentSets(CharacterDatabaseTransaction trans);
|
||||
void _SaveEntryPoint(CharacterDatabaseTransaction trans);
|
||||
|
||||
@@ -413,14 +413,6 @@ void Player::Update(uint32 p_time)
|
||||
TeleportTo(teleportStore_dest, teleportStore_options);
|
||||
}
|
||||
|
||||
if (!IsBeingTeleported() && bRequestForcedVisibilityUpdate)
|
||||
{
|
||||
bRequestForcedVisibilityUpdate = false;
|
||||
UpdateObjectVisibility(true, true);
|
||||
m_delayed_unit_relocation_timer = 0;
|
||||
RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED);
|
||||
}
|
||||
|
||||
sScriptMgr->OnAfterPlayerUpdate(this, p_time);
|
||||
}
|
||||
|
||||
@@ -1552,23 +1544,13 @@ void Player::UpdateVisibilityForPlayer(bool mapChange)
|
||||
m_seer = this;
|
||||
}
|
||||
|
||||
Acore::VisibleNotifier notifierNoLarge(
|
||||
*this, mapChange,
|
||||
false); // visit only objects which are not large; default distance
|
||||
Cell::VisitAllObjects(m_seer, notifierNoLarge,
|
||||
GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
||||
notifierNoLarge.SendToSelf();
|
||||
|
||||
Acore::VisibleNotifier notifierLarge(
|
||||
*this, mapChange, true); // visit only large objects; maximum distance
|
||||
Cell::VisitAllObjects(m_seer, notifierLarge, GetSightRange());
|
||||
notifierLarge.SendToSelf();
|
||||
|
||||
if (mapChange)
|
||||
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
||||
// updates visibility of all objects around point of view for current player
|
||||
Acore::VisibleNotifier notifier(*this, mapChange);
|
||||
Cell::VisitAllObjects(m_seer, notifier, GetSightRange());
|
||||
notifier.SendToSelf(); // send gathered data
|
||||
}
|
||||
|
||||
void Player::UpdateObjectVisibility(bool forced, bool fromUpdate)
|
||||
void Player::UpdateObjectVisibility(bool forced)
|
||||
{
|
||||
// Prevent updating visibility if player is not in world (example: LoadFromDB sets drunkstate which updates invisibility while player is not in map)
|
||||
if (!IsInWorld())
|
||||
@@ -1578,11 +1560,6 @@ void Player::UpdateObjectVisibility(bool forced, bool fromUpdate)
|
||||
AddToNotify(NOTIFY_VISIBILITY_CHANGED);
|
||||
else if (!isBeingLoaded())
|
||||
{
|
||||
if (!fromUpdate) // pussywizard:
|
||||
{
|
||||
bRequestForcedVisibilityUpdate = true;
|
||||
return;
|
||||
}
|
||||
Unit::UpdateObjectVisibility(true);
|
||||
UpdateVisibilityForPlayer();
|
||||
}
|
||||
|
||||
@@ -317,12 +317,6 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject),
|
||||
|
||||
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
|
||||
|
||||
m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
||||
m_last_notify_mstime = 0;
|
||||
m_delayed_unit_relocation_timer = 0;
|
||||
m_delayed_unit_ai_notify_timer = 0;
|
||||
bRequestForcedVisibilityUpdate = false;
|
||||
|
||||
m_applyResilience = false;
|
||||
_instantCast = false;
|
||||
|
||||
@@ -411,32 +405,6 @@ void Unit::Update(uint32 p_time)
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
// pussywizard:
|
||||
if (GetTypeId() != TYPEID_PLAYER || (!ToPlayer()->IsBeingTeleported() && !bRequestForcedVisibilityUpdate))
|
||||
{
|
||||
if (m_delayed_unit_relocation_timer)
|
||||
{
|
||||
if (m_delayed_unit_relocation_timer <= p_time)
|
||||
{
|
||||
m_delayed_unit_relocation_timer = 0;
|
||||
//ExecuteDelayedUnitRelocationEvent();
|
||||
FindMap()->i_objectsForDelayedVisibility.insert(this);
|
||||
}
|
||||
else
|
||||
m_delayed_unit_relocation_timer -= p_time;
|
||||
}
|
||||
if (m_delayed_unit_ai_notify_timer)
|
||||
{
|
||||
if (m_delayed_unit_ai_notify_timer <= p_time)
|
||||
{
|
||||
m_delayed_unit_ai_notify_timer = 0;
|
||||
ExecuteDelayedUnitAINotifyEvent();
|
||||
}
|
||||
else
|
||||
m_delayed_unit_ai_notify_timer -= p_time;
|
||||
}
|
||||
}
|
||||
|
||||
_UpdateSpells( p_time );
|
||||
|
||||
if (CanHaveThreatList() && GetThreatMgr().isNeedUpdateToClient(p_time))
|
||||
@@ -8191,13 +8159,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
CastCustomSpell(this, triggered_spell_id, &basepoints0, nullptr, nullptr, true, castItem, triggeredByAura, originalCaster);
|
||||
break;
|
||||
}
|
||||
// Shaman T8 Elemental 4P Bonus
|
||||
case 64928:
|
||||
{
|
||||
basepoints0 = CalculatePct(int32(damage), triggerAmount);
|
||||
triggered_spell_id = 64930; // Electrified
|
||||
break;
|
||||
}
|
||||
// Shaman T9 Elemental 4P Bonus
|
||||
case 67228:
|
||||
{
|
||||
@@ -17541,13 +17502,17 @@ void Unit::SetContestedPvP(Player* attackedPlayer, bool lookForNearContestedGuar
|
||||
player->AddUnitState(UNIT_STATE_ATTACK_PLAYER);
|
||||
player->SetPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP);
|
||||
// call MoveInLineOfSight for nearby contested guards
|
||||
AddToNotify(NOTIFY_AI_RELOCATION);
|
||||
Acore::AIRelocationNotifier notifier(*this);
|
||||
Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
|
||||
}
|
||||
if (!HasUnitState(UNIT_STATE_ATTACK_PLAYER))
|
||||
for (Unit* unit : m_Controlled)
|
||||
{
|
||||
AddUnitState(UNIT_STATE_ATTACK_PLAYER);
|
||||
// call MoveInLineOfSight for nearby contested guards
|
||||
AddToNotify(NOTIFY_AI_RELOCATION);
|
||||
if (!unit->HasUnitState(UNIT_STATE_ATTACK_PLAYER))
|
||||
{
|
||||
unit->AddUnitState(UNIT_STATE_ATTACK_PLAYER);
|
||||
Acore::AIRelocationNotifier notifier(*unit);
|
||||
Cell::VisitWorldObjects(this, notifier, GetVisibilityRange());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19408,7 +19373,7 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::UpdateObjectVisibility(bool forced, bool /*fromUpdate*/)
|
||||
void Unit::UpdateObjectVisibility(bool forced)
|
||||
{
|
||||
if (!forced)
|
||||
AddToNotify(NOTIFY_VISIBILITY_CHANGED);
|
||||
@@ -19416,8 +19381,7 @@ void Unit::UpdateObjectVisibility(bool forced, bool /*fromUpdate*/)
|
||||
{
|
||||
WorldObject::UpdateObjectVisibility(true);
|
||||
Acore::AIRelocationNotifier notifier(*this);
|
||||
float radius = 60.0f;
|
||||
Cell::VisitAllObjects(this, notifier, radius);
|
||||
Cell::VisitAllObjects(this, notifier, GetVisibilityRange());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20774,124 +20738,6 @@ bool ConflagrateAuraStateDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time
|
||||
return true;
|
||||
}
|
||||
|
||||
void Unit::ExecuteDelayedUnitRelocationEvent()
|
||||
{
|
||||
this->RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED);
|
||||
if (!this->IsInWorld() || this->IsDuringRemoveFromWorld())
|
||||
return;
|
||||
|
||||
if (this->HasSharedVision())
|
||||
for (SharedVisionList::const_iterator itr = this->GetSharedVisionList().begin(); itr != this->GetSharedVisionList().end(); ++itr)
|
||||
if (Player* player = (*itr))
|
||||
{
|
||||
if (player->IsOnVehicle(this) || !player->IsInWorld() || player->IsDuringRemoveFromWorld()) // players on vehicles have their own event executed (due to passenger relocation)
|
||||
continue;
|
||||
WorldObject* viewPoint = player;
|
||||
if (player->m_seer && player->m_seer->IsInWorld())
|
||||
viewPoint = player->m_seer;
|
||||
if (!viewPoint->IsPositionValid() || !player->IsPositionValid())
|
||||
continue;
|
||||
|
||||
if (Unit* active = viewPoint->ToUnit())
|
||||
{
|
||||
//if (active->IsVehicle()) // always check original unit here, last notify position is not relocated
|
||||
// active = player;
|
||||
|
||||
float dx = active->m_last_notify_position.GetPositionX() - active->GetPositionX();
|
||||
float dy = active->m_last_notify_position.GetPositionY() - active->GetPositionY();
|
||||
float dz = active->m_last_notify_position.GetPositionZ() - active->GetPositionZ();
|
||||
float distsq = dx * dx + dy * dy + dz * dz;
|
||||
float mindistsq = DynamicVisibilityMgr::GetReqMoveDistSq(active->FindMap()->GetEntry()->map_type);
|
||||
if (distsq < mindistsq)
|
||||
continue;
|
||||
|
||||
// this will be relocated below sharedvision!
|
||||
//active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ());
|
||||
}
|
||||
|
||||
Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
|
||||
Cell::VisitAllObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
||||
relocateNoLarge.SendToSelf();
|
||||
Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance
|
||||
Cell::VisitAllObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE);
|
||||
relocateLarge.SendToSelf();
|
||||
}
|
||||
|
||||
if (Player* player = this->ToPlayer())
|
||||
{
|
||||
WorldObject* viewPoint = player;
|
||||
if (player->m_seer && player->m_seer->IsInWorld())
|
||||
viewPoint = player->m_seer;
|
||||
|
||||
if (viewPoint->GetMapId() != player->GetMapId() || !viewPoint->IsPositionValid() || !player->IsPositionValid())
|
||||
return;
|
||||
|
||||
if (Unit* active = viewPoint->ToUnit())
|
||||
{
|
||||
if (active->IsVehicle())
|
||||
active = player;
|
||||
|
||||
if (!player->GetFarSightDistance())
|
||||
{
|
||||
float dx = active->m_last_notify_position.GetPositionX() - active->GetPositionX();
|
||||
float dy = active->m_last_notify_position.GetPositionY() - active->GetPositionY();
|
||||
float dz = active->m_last_notify_position.GetPositionZ() - active->GetPositionZ();
|
||||
float distsq = dx * dx + dy * dy + dz * dz;
|
||||
|
||||
float mindistsq = DynamicVisibilityMgr::GetReqMoveDistSq(active->FindMap()->GetEntry()->map_type);
|
||||
if (distsq < mindistsq)
|
||||
return;
|
||||
|
||||
active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ());
|
||||
}
|
||||
}
|
||||
|
||||
Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
|
||||
Cell::VisitAllObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
|
||||
relocateNoLarge.SendToSelf();
|
||||
|
||||
if (!player->GetFarSightDistance())
|
||||
{
|
||||
Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance
|
||||
Cell::VisitAllObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE);
|
||||
relocateLarge.SendToSelf();
|
||||
}
|
||||
|
||||
this->AddToNotify(NOTIFY_AI_RELOCATION);
|
||||
}
|
||||
else if (Creature* unit = this->ToCreature())
|
||||
{
|
||||
if (!unit->IsPositionValid())
|
||||
return;
|
||||
|
||||
float dx = unit->m_last_notify_position.GetPositionX() - unit->GetPositionX();
|
||||
float dy = unit->m_last_notify_position.GetPositionY() - unit->GetPositionY();
|
||||
float dz = unit->m_last_notify_position.GetPositionZ() - unit->GetPositionZ();
|
||||
float distsq = dx * dx + dy * dy + dz * dz;
|
||||
float mindistsq = DynamicVisibilityMgr::GetReqMoveDistSq(unit->FindMap()->GetEntry()->map_type);
|
||||
if (distsq < mindistsq)
|
||||
return;
|
||||
|
||||
unit->m_last_notify_position.Relocate(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ());
|
||||
|
||||
Acore::CreatureRelocationNotifier relocate(*unit);
|
||||
Cell::VisitAllObjects(unit, relocate, unit->GetVisibilityRange() + VISIBILITY_COMPENSATION);
|
||||
|
||||
this->AddToNotify(NOTIFY_AI_RELOCATION);
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::ExecuteDelayedUnitAINotifyEvent()
|
||||
{
|
||||
this->RemoveFromNotify(NOTIFY_AI_RELOCATION);
|
||||
if (!this->IsInWorld() || this->IsDuringRemoveFromWorld())
|
||||
return;
|
||||
|
||||
Acore::AIRelocationNotifier notifier(*this);
|
||||
float radius = 60.0f;
|
||||
Cell::VisitAllObjects(this, notifier, radius);
|
||||
}
|
||||
|
||||
void Unit::SetInFront(WorldObject const* target)
|
||||
{
|
||||
if (!HasUnitState(UNIT_STATE_CANNOT_TURN))
|
||||
|
||||
@@ -2145,7 +2145,7 @@ public:
|
||||
// common function for visibility checks for player/creatures with detection code
|
||||
[[nodiscard]] uint32 GetPhaseByAuras() const;
|
||||
void SetPhaseMask(uint32 newPhaseMask, bool update) override;// overwrite WorldObject::SetPhaseMask
|
||||
void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false) override;
|
||||
void UpdateObjectVisibility(bool forced = true) override;
|
||||
|
||||
SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY];
|
||||
uint32 m_lastSanctuaryTime;
|
||||
@@ -2419,14 +2419,6 @@ public:
|
||||
void AddPointedBy(SafeUnitPointer* sup) { SafeUnitPointerSet.insert(sup); }
|
||||
void RemovePointedBy(SafeUnitPointer* sup) { SafeUnitPointerSet.erase(sup); }
|
||||
static void HandleSafeUnitPointersOnDelete(Unit* thisUnit);
|
||||
// Relocation Nofier optimization
|
||||
Position m_last_notify_position;
|
||||
uint32 m_last_notify_mstime;
|
||||
uint16 m_delayed_unit_relocation_timer;
|
||||
uint16 m_delayed_unit_ai_notify_timer;
|
||||
bool bRequestForcedVisibilityUpdate;
|
||||
void ExecuteDelayedUnitRelocationEvent();
|
||||
void ExecuteDelayedUnitAINotifyEvent();
|
||||
|
||||
// cooldowns
|
||||
[[nodiscard]] virtual bool HasSpellCooldown(uint32 /*spell_id*/) const { return false; }
|
||||
|
||||
@@ -7676,8 +7676,8 @@ void ObjectMgr::LoadReputationSpilloverTemplate()
|
||||
|
||||
_repSpilloverTemplateStore.clear(); // for reload case
|
||||
|
||||
uint32 count = 0; // 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
QueryResult result = WorldDatabase.Query("SELECT faction, faction1, rate_1, rank_1, faction2, rate_2, rank_2, faction3, rate_3, rank_3, faction4, rate_4, rank_4 FROM reputation_spillover_template");
|
||||
uint32 count = 0; // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
||||
QueryResult result = WorldDatabase.Query("SELECT faction, faction1, rate_1, rank_1, faction2, rate_2, rank_2, faction3, rate_3, rank_3, faction4, rate_4, rank_4, faction5, rate_5, rank_5, faction6, rate_6, rank_6 FROM reputation_spillover_template");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -7706,6 +7706,12 @@ void ObjectMgr::LoadReputationSpilloverTemplate()
|
||||
repTemplate.faction[3] = fields[10].Get<uint16>();
|
||||
repTemplate.faction_rate[3] = fields[11].Get<float>();
|
||||
repTemplate.faction_rank[3] = fields[12].Get<uint8>();
|
||||
repTemplate.faction[4] = fields[13].Get<uint16>();
|
||||
repTemplate.faction_rate[4] = fields[14].Get<float>();
|
||||
repTemplate.faction_rank[4] = fields[15].Get<uint8>();
|
||||
repTemplate.faction[5] = fields[16].Get<uint16>();
|
||||
repTemplate.faction_rate[5] = fields[17].Get<float>();
|
||||
repTemplate.faction_rank[5] = fields[18].Get<uint8>();
|
||||
|
||||
FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId);
|
||||
|
||||
|
||||
@@ -96,6 +96,12 @@ public:
|
||||
visitor.Visit(i_objects);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
uint32 GetWorldObjectCountInGrid() const
|
||||
{
|
||||
return i_objects.template Count<T>();
|
||||
}
|
||||
|
||||
/** Inserts a container type object into the grid.
|
||||
*/
|
||||
template<class SPECIFIC_OBJECT> void AddGridObject(SPECIFIC_OBJECT* obj)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 "GridStates.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "Log.h"
|
||||
#include "Map.h"
|
||||
#include "ObjectGridLoader.h"
|
||||
|
||||
void InvalidState::Update(Map&, NGridType&, GridInfo&, uint32) const
|
||||
{
|
||||
}
|
||||
|
||||
void ActiveState::Update(Map& map, NGridType& grid, GridInfo& info, uint32 diff) const
|
||||
{
|
||||
// Only check grid activity every (grid_expiry/10) ms, because it's really useless to do it every cycle
|
||||
info.UpdateTimeTracker(diff);
|
||||
if (info.getTimeTracker().Passed())
|
||||
{
|
||||
if (!grid.GetWorldObjectCountInNGrid<Player>() && !map.ActiveObjectsNearGrid(grid))
|
||||
{
|
||||
ObjectGridStoper worker;
|
||||
TypeContainerVisitor<ObjectGridStoper, GridTypeMapContainer> visitor(worker);
|
||||
grid.VisitAllGrids(visitor);
|
||||
grid.SetGridState(GRID_STATE_IDLE);
|
||||
LOG_DEBUG("maps", "Grid[{}, {}] on map {} moved to IDLE state", grid.getX(), grid.getY(), map.GetId());
|
||||
}
|
||||
else
|
||||
map.ResetGridExpiry(grid, 0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
void IdleState::Update(Map& map, NGridType& grid, GridInfo&, uint32) const
|
||||
{
|
||||
map.ResetGridExpiry(grid);
|
||||
grid.SetGridState(GRID_STATE_REMOVAL);
|
||||
LOG_DEBUG("maps", "Grid[{}, {}] on map {} moved to REMOVAL state", grid.getX(), grid.getY(), map.GetId());
|
||||
}
|
||||
|
||||
void RemovalState::Update(Map& map, NGridType& grid, GridInfo& info, uint32 diff) const
|
||||
{
|
||||
if (!info.getUnloadLock())
|
||||
{
|
||||
info.UpdateTimeTracker(diff);
|
||||
if (info.getTimeTracker().Passed() && !map.UnloadGrid(grid, false))
|
||||
{
|
||||
LOG_DEBUG("maps", "Grid[{}, {}] for map {} differed unloading due to players or active objects nearby", grid.getX(), grid.getY(), map.GetId());
|
||||
map.ResetGridExpiry(grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef ACORE_GRIDSTATES_H
|
||||
#define ACORE_GRIDSTATES_H
|
||||
|
||||
#include "GridDefines.h"
|
||||
#include "NGrid.h"
|
||||
|
||||
class Map;
|
||||
|
||||
class AC_GAME_API GridState
|
||||
{
|
||||
public:
|
||||
virtual ~GridState() { };
|
||||
virtual void Update(Map &, NGridType&, GridInfo &, uint32 t_diff) const = 0;
|
||||
};
|
||||
|
||||
class AC_GAME_API InvalidState : public GridState
|
||||
{
|
||||
public:
|
||||
void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override;
|
||||
};
|
||||
|
||||
class AC_GAME_API ActiveState : public GridState
|
||||
{
|
||||
public:
|
||||
void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override;
|
||||
};
|
||||
|
||||
class AC_GAME_API IdleState : public GridState
|
||||
{
|
||||
public:
|
||||
void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override;
|
||||
};
|
||||
|
||||
class AC_GAME_API RemovalState : public GridState
|
||||
{
|
||||
public:
|
||||
void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 "NGrid.h"
|
||||
#include "Random.h"
|
||||
|
||||
GridInfo::GridInfo() : i_timer(0), vis_Update(0, irand(0, DEFAULT_VISIBILITY_NOTIFY_PERIOD)),
|
||||
i_unloadActiveLockCount(0), i_unloadExplicitLock(false), i_unloadReferenceLock(false)
|
||||
{
|
||||
}
|
||||
|
||||
GridInfo::GridInfo(std::chrono::seconds expiry, bool unload /*= true */) : i_timer(expiry.count()), vis_Update(0, irand(0, DEFAULT_VISIBILITY_NOTIFY_PERIOD)),
|
||||
i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload), i_unloadReferenceLock(false)
|
||||
{
|
||||
}
|
||||
@@ -26,6 +26,42 @@
|
||||
#include "Timer.h"
|
||||
#include "Util.h"
|
||||
|
||||
#define DEFAULT_VISIBILITY_NOTIFY_PERIOD 1000
|
||||
|
||||
class AC_GAME_API GridInfo
|
||||
{
|
||||
public:
|
||||
GridInfo();
|
||||
GridInfo(std::chrono::seconds expiry, bool unload = true);
|
||||
TimeTracker const& getTimeTracker() const { return i_timer; }
|
||||
bool getUnloadLock() const { return i_unloadActiveLockCount || i_unloadExplicitLock || i_unloadReferenceLock; }
|
||||
void setUnloadExplicitLock(bool on) { i_unloadExplicitLock = on; }
|
||||
void setUnloadReferenceLock(bool on) { i_unloadReferenceLock = on; }
|
||||
void incUnloadActiveLock() { ++i_unloadActiveLockCount; }
|
||||
void decUnloadActiveLock() { if (i_unloadActiveLockCount) --i_unloadActiveLockCount; }
|
||||
|
||||
void setTimer(TimeTracker const& pTimer) { i_timer = pTimer; }
|
||||
void ResetTimeTracker(time_t interval) { i_timer.Reset(interval); }
|
||||
void UpdateTimeTracker(time_t diff) { i_timer.Update(diff); }
|
||||
PeriodicTimer& getRelocationTimer() { return vis_Update; }
|
||||
private:
|
||||
TimeTracker i_timer;
|
||||
PeriodicTimer vis_Update;
|
||||
|
||||
uint16 i_unloadActiveLockCount : 16; // lock from active object spawn points (prevent clone loading)
|
||||
bool i_unloadExplicitLock : 1; // explicit manual lock or config setting
|
||||
bool i_unloadReferenceLock : 1; // lock from instance map copy
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GRID_STATE_INVALID = 0,
|
||||
GRID_STATE_ACTIVE = 1,
|
||||
GRID_STATE_IDLE = 2,
|
||||
GRID_STATE_REMOVAL = 3,
|
||||
MAX_GRID_STATE = 4
|
||||
} grid_state_t;
|
||||
|
||||
template
|
||||
<
|
||||
uint32 N,
|
||||
@@ -37,10 +73,10 @@ class NGrid
|
||||
{
|
||||
public:
|
||||
typedef Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> GridType;
|
||||
NGrid(uint32 id, int32 x, int32 y)
|
||||
: i_gridId(id), i_x(x), i_y(y), i_GridObjectDataLoaded(false)
|
||||
{
|
||||
}
|
||||
NGrid(uint32 id, int32 x, int32 y, std::chrono::seconds expiry, bool unload = true) :
|
||||
i_gridId(id), i_GridInfo(GridInfo(expiry, unload)), i_x(x), i_y(y),
|
||||
i_cellstate(GRID_STATE_INVALID), i_GridObjectDataLoaded(false)
|
||||
{ }
|
||||
|
||||
GridType& GetGridType(const uint32 x, const uint32 y)
|
||||
{
|
||||
@@ -55,6 +91,9 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32 GetGridId() const { return i_gridId; }
|
||||
void SetGridId(uint32 id) { i_gridId = id; }
|
||||
[[nodiscard]] grid_state_t GetGridState() const { return i_cellstate; }
|
||||
void SetGridState(grid_state_t s) { i_cellstate = s; }
|
||||
[[nodiscard]] int32 getX() const { return i_x; }
|
||||
[[nodiscard]] int32 getY() const { return i_y; }
|
||||
|
||||
@@ -65,6 +104,16 @@ public:
|
||||
[[nodiscard]] bool isGridObjectDataLoaded() const { return i_GridObjectDataLoaded; }
|
||||
void setGridObjectDataLoaded(bool pLoaded) { i_GridObjectDataLoaded = pLoaded; }
|
||||
|
||||
GridInfo* getGridInfoRef() { return &i_GridInfo; }
|
||||
TimeTracker const& getTimeTracker() const { return i_GridInfo.getTimeTracker(); }
|
||||
bool getUnloadLock() const { return i_GridInfo.getUnloadLock(); }
|
||||
void setUnloadExplicitLock(bool on) { i_GridInfo.setUnloadExplicitLock(on); }
|
||||
void setUnloadReferenceLock(bool on) { i_GridInfo.setUnloadReferenceLock(on); }
|
||||
void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); }
|
||||
void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); }
|
||||
void ResetTimeTracker(std::chrono::seconds interval) { i_GridInfo.ResetTimeTracker(interval.count()); }
|
||||
void UpdateTimeTracker(std::chrono::seconds diff) { i_GridInfo.UpdateTimeTracker(diff.count()); }
|
||||
|
||||
/*
|
||||
template<class SPECIFIC_OBJECT> void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
|
||||
{
|
||||
@@ -103,11 +152,23 @@ public:
|
||||
GetGridType(x, y).Visit(visitor);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
uint32 GetWorldObjectCountInNGrid() const
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (uint32 x = 0; x < N; ++x)
|
||||
for (uint32 y = 0; y < N; ++y)
|
||||
count += i_cells[x][y].template GetWorldObjectCountInGrid<T>();
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 i_gridId;
|
||||
GridInfo i_GridInfo;
|
||||
GridReference<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> > i_Reference;
|
||||
int32 i_x;
|
||||
int32 i_y;
|
||||
grid_state_t i_cellstate;
|
||||
GridType i_cells[N][N];
|
||||
bool i_GridObjectDataLoaded;
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Map.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "SpellInfo.h"
|
||||
@@ -23,22 +24,10 @@
|
||||
#include "Transport.h"
|
||||
#include "UpdateData.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "CellImpl.h"
|
||||
|
||||
using namespace Acore;
|
||||
|
||||
void VisibleNotifier::Visit(GameObjectMapType& m)
|
||||
{
|
||||
for (GameObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
GameObject* go = iter->GetSource();
|
||||
if (i_largeOnly != go->IsVisibilityOverridden())
|
||||
continue;
|
||||
|
||||
vis_guids.erase(go->GetGUID());
|
||||
i_player.UpdateVisibilityOf(go, i_data, i_visibleNow);
|
||||
}
|
||||
}
|
||||
|
||||
void VisibleNotifier::SendToSelf()
|
||||
{
|
||||
// at this moment i_clientGUIDs have guids that not iterate at grid level checks
|
||||
@@ -46,9 +35,6 @@ void VisibleNotifier::SendToSelf()
|
||||
if (Transport* transport = i_player.GetTransport())
|
||||
for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
|
||||
{
|
||||
if (i_largeOnly != (*itr)->IsVisibilityOverridden())
|
||||
continue;
|
||||
|
||||
if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end())
|
||||
{
|
||||
vis_guids.erase((*itr)->GetGUID());
|
||||
@@ -65,6 +51,9 @@ void VisibleNotifier::SendToSelf()
|
||||
case TYPEID_UNIT:
|
||||
i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow);
|
||||
break;
|
||||
case TYPEID_DYNAMICOBJECT:
|
||||
i_player.UpdateVisibilityOf((*itr)->ToDynObject(), i_data, i_visibleNow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -73,12 +62,6 @@ void VisibleNotifier::SendToSelf()
|
||||
|
||||
for (GuidUnorderedSet::const_iterator it = vis_guids.begin(); it != vis_guids.end(); ++it)
|
||||
{
|
||||
if (WorldObject* obj = ObjectAccessor::GetWorldObject(i_player, *it))
|
||||
{
|
||||
if (i_largeOnly != obj->IsVisibilityOverridden())
|
||||
continue;
|
||||
}
|
||||
|
||||
// pussywizard: static transports are removed only in RemovePlayerFromMap and here if can no longer detect (eg. phase changed)
|
||||
if ((*it).IsTransport())
|
||||
if (GameObject* staticTrans = i_player.GetMap()->GetGameObject(*it))
|
||||
@@ -105,9 +88,6 @@ void VisibleNotifier::SendToSelf()
|
||||
|
||||
for (std::vector<Unit*>::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it)
|
||||
{
|
||||
if (i_largeOnly != (*it)->IsVisibilityOverridden())
|
||||
continue;
|
||||
|
||||
i_player.GetInitialVisiblePackets(*it);
|
||||
}
|
||||
}
|
||||
@@ -178,6 +158,23 @@ void PlayerRelocationNotifier::Visit(PlayerMapType& m)
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerRelocationNotifier::Visit(CreatureMapType& m)
|
||||
{
|
||||
bool relocated_for_ai = (&i_player == i_player.m_seer);
|
||||
|
||||
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
Creature* c = iter->GetSource();
|
||||
|
||||
vis_guids.erase(c->GetGUID());
|
||||
|
||||
i_player.UpdateVisibilityOf(c, i_data, i_visibleNow);
|
||||
|
||||
if (relocated_for_ai && !c->isNeedNotify(NOTIFY_VISIBILITY_CHANGED))
|
||||
CreatureUnitRelocationWorker(c, &i_player);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureRelocationNotifier::Visit(PlayerMapType& m)
|
||||
{
|
||||
for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
@@ -194,6 +191,58 @@ void CreatureRelocationNotifier::Visit(PlayerMapType& m)
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureRelocationNotifier::Visit(CreatureMapType& m)
|
||||
{
|
||||
if (!i_creature.IsAlive())
|
||||
return;
|
||||
|
||||
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
Creature* c = iter->GetSource();
|
||||
CreatureUnitRelocationWorker(&i_creature, c);
|
||||
|
||||
if (!c->isNeedNotify(NOTIFY_VISIBILITY_CHANGED))
|
||||
CreatureUnitRelocationWorker(c, &i_creature);
|
||||
}
|
||||
}
|
||||
|
||||
void DelayedUnitRelocation::Visit(CreatureMapType& m)
|
||||
{
|
||||
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
Creature* unit = iter->GetSource();
|
||||
if (!unit->isNeedNotify(NOTIFY_VISIBILITY_CHANGED))
|
||||
continue;
|
||||
|
||||
CreatureRelocationNotifier relocate(*unit);
|
||||
|
||||
TypeContainerVisitor<CreatureRelocationNotifier, WorldTypeMapContainer > c2world_relocation(relocate);
|
||||
TypeContainerVisitor<CreatureRelocationNotifier, GridTypeMapContainer > c2grid_relocation(relocate);
|
||||
|
||||
cell.Visit(p, c2world_relocation, i_map, *unit, i_radius);
|
||||
cell.Visit(p, c2grid_relocation, i_map, *unit, i_radius);
|
||||
}
|
||||
}
|
||||
|
||||
void DelayedUnitRelocation::Visit(PlayerMapType& m)
|
||||
{
|
||||
for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
Player* player = iter->GetSource();
|
||||
WorldObject const* viewPoint = player->m_seer;
|
||||
|
||||
if (!viewPoint->isNeedNotify(NOTIFY_VISIBILITY_CHANGED))
|
||||
continue;
|
||||
|
||||
if (player != viewPoint && !viewPoint->IsPositionValid())
|
||||
continue;
|
||||
|
||||
PlayerRelocationNotifier relocate(*player);
|
||||
Cell::VisitAllObjects(viewPoint, relocate, i_radius, false);
|
||||
relocate.SendToSelf();
|
||||
}
|
||||
}
|
||||
|
||||
void AIRelocationNotifier::Visit(CreatureMapType& m)
|
||||
{
|
||||
bool self = isCreature && !((Creature*)(&i_unit))->IsMoveInLineOfSightStrictlyDisabled();
|
||||
@@ -341,14 +390,9 @@ void MessageDistDelivererToHostile::Visit(DynamicObjectMapType& m)
|
||||
template<class T>
|
||||
void ObjectUpdater::Visit(GridRefMgr<T>& m)
|
||||
{
|
||||
T* obj;
|
||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); )
|
||||
{
|
||||
obj = iter->GetSource();
|
||||
++iter;
|
||||
if (obj->IsInWorld() && (i_largeOnly == obj->IsVisibilityOverridden()))
|
||||
obj->Update(i_timeDiff);
|
||||
}
|
||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
if (iter->GetSource()->IsInWorld())
|
||||
iter->GetSource()->Update(i_timeDiff);
|
||||
}
|
||||
|
||||
bool AnyDeadUnitObjectInRangeCheck::operator()(Player* u)
|
||||
|
||||
@@ -44,16 +44,14 @@ namespace Acore
|
||||
GuidUnorderedSet vis_guids;
|
||||
std::vector<Unit*>& i_visibleNow;
|
||||
bool i_gobjOnly;
|
||||
bool i_largeOnly;
|
||||
UpdateData i_data;
|
||||
|
||||
VisibleNotifier(Player& player, bool gobjOnly, bool largeOnly) :
|
||||
i_player(player), vis_guids(player.m_clientGUIDs), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly), i_largeOnly(largeOnly)
|
||||
VisibleNotifier(Player& player, bool gobjOnly) :
|
||||
i_player(player), vis_guids(player.m_clientGUIDs), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly)
|
||||
{
|
||||
i_visibleNow.clear();
|
||||
}
|
||||
|
||||
void Visit(GameObjectMapType&);
|
||||
template<class T> void Visit(GridRefMgr<T>& m);
|
||||
void SendToSelf(void);
|
||||
};
|
||||
@@ -71,9 +69,10 @@ namespace Acore
|
||||
|
||||
struct PlayerRelocationNotifier : public VisibleNotifier
|
||||
{
|
||||
PlayerRelocationNotifier(Player& player, bool largeOnly): VisibleNotifier(player, false, largeOnly) { }
|
||||
PlayerRelocationNotifier(Player& player) : VisibleNotifier(player, false) { }
|
||||
|
||||
template<class T> void Visit(GridRefMgr<T>& m) { VisibleNotifier::Visit(m); }
|
||||
void Visit(CreatureMapType&);
|
||||
void Visit(PlayerMapType&);
|
||||
};
|
||||
|
||||
@@ -82,6 +81,20 @@ namespace Acore
|
||||
Creature& i_creature;
|
||||
CreatureRelocationNotifier(Creature& c) : i_creature(c) {}
|
||||
template<class T> void Visit(GridRefMgr<T>&) {}
|
||||
void Visit(CreatureMapType&);
|
||||
void Visit(PlayerMapType&);
|
||||
};
|
||||
|
||||
struct DelayedUnitRelocation
|
||||
{
|
||||
Map& i_map;
|
||||
Cell& cell;
|
||||
CellCoord& p;
|
||||
const float i_radius;
|
||||
DelayedUnitRelocation(Cell& c, CellCoord& pair, Map& map, float radius) :
|
||||
i_map(map), cell(c), p(pair), i_radius(radius) { }
|
||||
template<class T> void Visit(GridRefMgr<T>&) { }
|
||||
void Visit(CreatureMapType&);
|
||||
void Visit(PlayerMapType&);
|
||||
};
|
||||
|
||||
@@ -94,6 +107,25 @@ namespace Acore
|
||||
void Visit(CreatureMapType&);
|
||||
};
|
||||
|
||||
struct GridUpdater
|
||||
{
|
||||
GridType& i_grid;
|
||||
uint32 i_timeDiff;
|
||||
GridUpdater(GridType& grid, uint32 diff) : i_grid(grid), i_timeDiff(diff) { }
|
||||
|
||||
template<class T> void updateObjects(GridRefMgr<T>& m)
|
||||
{
|
||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
iter->GetSource()->Update(i_timeDiff);
|
||||
}
|
||||
|
||||
void Visit(PlayerMapType& m) { updateObjects<Player>(m); }
|
||||
void Visit(CreatureMapType& m) { updateObjects<Creature>(m); }
|
||||
void Visit(GameObjectMapType& m) { updateObjects<GameObject>(m); }
|
||||
void Visit(DynamicObjectMapType& m) { updateObjects<DynamicObject>(m); }
|
||||
void Visit(CorpseMapType& m) { updateObjects<Corpse>(m); }
|
||||
};
|
||||
|
||||
struct MessageDistDeliverer
|
||||
{
|
||||
WorldObject const* i_source;
|
||||
@@ -154,8 +186,7 @@ namespace Acore
|
||||
struct ObjectUpdater
|
||||
{
|
||||
uint32 i_timeDiff;
|
||||
bool i_largeOnly;
|
||||
explicit ObjectUpdater(const uint32 diff, bool largeOnly) : i_timeDiff(diff), i_largeOnly(largeOnly) {}
|
||||
explicit ObjectUpdater(const uint32 diff) : i_timeDiff(diff) {}
|
||||
template<class T> void Visit(GridRefMgr<T>& m);
|
||||
void Visit(PlayerMapType&) {}
|
||||
void Visit(CorpseMapType&) {}
|
||||
|
||||
@@ -38,9 +38,6 @@ inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
|
||||
|
||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
if (i_largeOnly != iter->GetSource()->IsVisibilityOverridden())
|
||||
continue;
|
||||
|
||||
vis_guids.erase(iter->GetSource()->GetGUID());
|
||||
i_player.UpdateVisibilityOf(iter->GetSource(), i_data, i_visibleNow);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,35 @@
|
||||
#include "Transport.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
void ObjectGridEvacuator::Visit(CreatureMapType& m)
|
||||
{
|
||||
// creature in unloading grid can have respawn point in another grid
|
||||
// if it will be unloaded then it will not respawn in original grid until unload/load original grid
|
||||
// move to respawn point to prevent this case. For player view in respawn grid this will be normal respawn.
|
||||
for (CreatureMapType::iterator iter = m.begin(); iter != m.end();)
|
||||
{
|
||||
Creature* c = iter->GetSource();
|
||||
++iter;
|
||||
|
||||
ASSERT(!c->IsPet() && "ObjectGridRespawnMover must not be called for pets");
|
||||
c->GetMap()->CreatureRespawnRelocation(c, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGridEvacuator::Visit(GameObjectMapType& m)
|
||||
{
|
||||
// gameobject in unloading grid can have respawn point in another grid
|
||||
// if it will be unloaded then it will not respawn in original grid until unload/load original grid
|
||||
// move to respawn point to prevent this case. For player view in respawn grid this will be normal respawn.
|
||||
for (GameObjectMapType::iterator iter = m.begin(); iter != m.end();)
|
||||
{
|
||||
GameObject* go = iter->GetSource();
|
||||
++iter;
|
||||
|
||||
go->GetMap()->GameObjectRespawnRelocation(go, true);
|
||||
}
|
||||
}
|
||||
|
||||
// for loading world object at grid loading (Corpses)
|
||||
//TODO: to implement npc on transport, also need to load npcs at grid loading
|
||||
class ObjectWorldLoader
|
||||
@@ -229,6 +258,17 @@ void ObjectGridUnloader::Visit(GridRefMgr<T>& m)
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGridStoper::Visit(CreatureMapType& m)
|
||||
{
|
||||
// stop any fights at grid de-activation and remove dynobjects created at cast by creatures
|
||||
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
iter->GetSource()->RemoveAllDynObjects();
|
||||
if (iter->GetSource()->IsInCombat())
|
||||
iter->GetSource()->CombatStop();
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ObjectGridCleaner::Visit(GridRefMgr<T>& m)
|
||||
{
|
||||
|
||||
@@ -53,6 +53,23 @@ private:
|
||||
uint32 i_corpses;
|
||||
};
|
||||
|
||||
//Stop the creatures before unloading the NGrid
|
||||
class AC_GAME_API ObjectGridStoper
|
||||
{
|
||||
public:
|
||||
void Visit(CreatureMapType& m);
|
||||
template<class T> void Visit(GridRefMgr<T>&) { }
|
||||
};
|
||||
|
||||
//Move the foreign creatures back to respawn positions before unloading the NGrid
|
||||
class AC_GAME_API ObjectGridEvacuator
|
||||
{
|
||||
public:
|
||||
void Visit(CreatureMapType& m);
|
||||
void Visit(GameObjectMapType& m);
|
||||
template<class T> void Visit(GridRefMgr<T>&) { }
|
||||
};
|
||||
|
||||
//Clean up and remove from world
|
||||
class ObjectGridCleaner
|
||||
{
|
||||
|
||||
@@ -225,9 +225,9 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
|
||||
// Overwritten by SPELL_AURA_MOD_LANGUAGE auras (Affects only Say and Yell)
|
||||
Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE);
|
||||
if (!ModLangAuras.empty())
|
||||
if (!ModLangAuras.empty() && (type == CHAT_MSG_SAY || type == CHAT_MSG_YELL))
|
||||
lang = ModLangAuras.front()->GetMiscValue();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Config.h"
|
||||
#include "GameTime.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridStates.h"
|
||||
#include "Group.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "Log.h"
|
||||
|
||||
@@ -1738,7 +1738,9 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
|
||||
// Rate.Drop.Item.GroupAmount is only in effect for the top loot template level
|
||||
if (isTopLevel)
|
||||
{
|
||||
group->Process(loot, player, store, lootMode, sWorld->getRate(RATE_DROP_ITEM_GROUP_AMOUNT));
|
||||
uint32 groupAmount = sWorld->getRate(RATE_DROP_ITEM_GROUP_AMOUNT);
|
||||
sScriptMgr->OnAfterCalculateLootGroupAmount(player, loot, lootMode, groupAmount, store);
|
||||
group->Process(loot, player, store, lootMode, groupAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+686
-178
File diff suppressed because it is too large
Load Diff
+47
-20
@@ -71,7 +71,6 @@ namespace VMAP
|
||||
namespace Acore
|
||||
{
|
||||
struct ObjectUpdater;
|
||||
struct LargeObjectUpdater;
|
||||
}
|
||||
|
||||
struct ScriptAction
|
||||
@@ -312,7 +311,7 @@ class Map : public GridRefMgr<NGridType>
|
||||
{
|
||||
friend class MapReference;
|
||||
public:
|
||||
Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr);
|
||||
Map(uint32 id, std::chrono::seconds, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr);
|
||||
~Map() override;
|
||||
|
||||
[[nodiscard]] MapEntry const* GetEntry() const { return i_mapEntry; }
|
||||
@@ -337,13 +336,7 @@ public:
|
||||
template<class T> void RemoveFromMap(T*, bool);
|
||||
|
||||
void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
|
||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
|
||||
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
|
||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor);
|
||||
void VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
|
||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
|
||||
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
|
||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor);
|
||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor);
|
||||
|
||||
virtual void Update(const uint32, const uint32, bool thread = true);
|
||||
|
||||
@@ -362,7 +355,7 @@ public:
|
||||
[[nodiscard]] bool IsRemovalGrid(float x, float y) const
|
||||
{
|
||||
GridCoord p = Acore::ComputeGridCoord(x, y);
|
||||
return !getNGrid(p.x_coord, p.y_coord);
|
||||
return !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsGridLoaded(float x, float y) const
|
||||
@@ -370,13 +363,26 @@ public:
|
||||
return IsGridLoaded(Acore::ComputeGridCoord(x, y));
|
||||
}
|
||||
|
||||
bool GetUnloadLock(GridCoord const& p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); }
|
||||
void SetUnloadLock(GridCoord const& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); }
|
||||
void LoadGrid(float x, float y);
|
||||
void LoadAllCells();
|
||||
bool UnloadGrid(NGridType& ngrid);
|
||||
bool UnloadGrid(NGridType& ngrid, bool pForce);
|
||||
void GridMarkNoUnload(uint32 x, uint32 y);
|
||||
void GridUnmarkNoUnload(uint32 x, uint32 y);
|
||||
virtual void UnloadAll();
|
||||
|
||||
void ResetGridExpiry(NGridType& grid, float factor = 1) const
|
||||
{
|
||||
grid.ResetTimeTracker(std::chrono::duration_cast<std::chrono::seconds>(i_gridExpiry * factor));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::chrono::seconds GetGridExpiry(void) const { return i_gridExpiry; }
|
||||
[[nodiscard]] uint32 GetId() const { return i_mapEntry->MapID; }
|
||||
|
||||
static void InitStateMachine();
|
||||
static void DeleteStateMachine();
|
||||
|
||||
static bool ExistMap(uint32 mapid, int gx, int gy);
|
||||
static bool ExistVMap(uint32 mapid, int gx, int gy);
|
||||
|
||||
@@ -415,6 +421,10 @@ public:
|
||||
void RemoveAllObjectsInRemoveList();
|
||||
virtual void RemoveAllPlayers();
|
||||
|
||||
// used only in MoveAllCreaturesInMoveList and ObjectGridUnloader
|
||||
bool CreatureRespawnRelocation(Creature* c, bool diffGridOnly);
|
||||
bool GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly);
|
||||
|
||||
[[nodiscard]] uint32 GetInstanceId() const { return i_InstanceId; }
|
||||
[[nodiscard]] uint8 GetSpawnMode() const { return (i_spawnMode); }
|
||||
|
||||
@@ -468,12 +478,10 @@ public:
|
||||
void resetMarkedCells() { marked_cells.reset(); }
|
||||
bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); }
|
||||
void markCell(uint32 pCellId) { marked_cells.set(pCellId); }
|
||||
void resetMarkedCellsLarge() { marked_cells_large.reset(); }
|
||||
bool isCellMarkedLarge(uint32 pCellId) { return marked_cells_large.test(pCellId); }
|
||||
void markCellLarge(uint32 pCellId) { marked_cells_large.set(pCellId); }
|
||||
|
||||
[[nodiscard]] bool HavePlayers() const { return !m_mapRefMgr.IsEmpty(); }
|
||||
[[nodiscard]] uint32 GetPlayersCountExceptGMs() const;
|
||||
[[nodiscard]] bool ActiveObjectsNearGrid(NGridType const& ngrid) const;
|
||||
|
||||
void AddWorldObject(WorldObject* obj) { i_worldObjects.insert(obj); }
|
||||
void RemoveWorldObject(WorldObject* obj) { i_worldObjects.erase(obj); }
|
||||
@@ -660,20 +668,30 @@ private:
|
||||
// Load MMap Data
|
||||
void LoadMMap(int gx, int gy);
|
||||
|
||||
bool CreatureCellRelocation(Creature* creature, Cell new_cell);
|
||||
bool GameObjectCellRelocation(GameObject* go, Cell new_cell);
|
||||
bool DynamicObjectCellRelocation(DynamicObject* go, Cell new_cell);
|
||||
|
||||
template<class T> void InitializeObject(T* obj);
|
||||
void AddCreatureToMoveList(Creature* c);
|
||||
void AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang);
|
||||
void RemoveCreatureFromMoveList(Creature* c);
|
||||
void AddGameObjectToMoveList(GameObject* go);
|
||||
void AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang);
|
||||
void RemoveGameObjectFromMoveList(GameObject* go);
|
||||
void AddDynamicObjectToMoveList(DynamicObject* go);
|
||||
void AddDynamicObjectToMoveList(DynamicObject* go, float x, float y, float z, float ang);
|
||||
void RemoveDynamicObjectFromMoveList(DynamicObject* go);
|
||||
|
||||
bool _creatureToMoveLock;
|
||||
std::vector<Creature*> _creaturesToMove;
|
||||
|
||||
bool _gameObjectsToMoveLock;
|
||||
std::vector<GameObject*> _gameObjectsToMove;
|
||||
|
||||
bool _dynamicObjectsToMoveLock;
|
||||
std::vector<DynamicObject*> _dynamicObjectsToMove;
|
||||
|
||||
[[nodiscard]] bool IsGridLoaded(const GridCoord&) const;
|
||||
void EnsureGridCreated_i(const GridCoord&);
|
||||
void EnsureGridLoadedForActiveObject(Cell const&, WorldObject* object);
|
||||
|
||||
void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); }
|
||||
|
||||
@@ -695,6 +713,8 @@ private:
|
||||
void SendObjectUpdates();
|
||||
|
||||
protected:
|
||||
void SetUnloadReferenceLock(GridCoord const& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); }
|
||||
|
||||
std::mutex Lock;
|
||||
std::mutex GridLock;
|
||||
std::shared_mutex MMapLock;
|
||||
@@ -710,6 +730,8 @@ protected:
|
||||
MapRefMgr m_mapRefMgr;
|
||||
MapRefMgr::iterator m_mapRefIter;
|
||||
|
||||
int32 m_VisibilityNotifyPeriod;
|
||||
|
||||
typedef std::set<WorldObject*> ActiveNonPlayers;
|
||||
ActiveNonPlayers m_activeNonPlayers;
|
||||
ActiveNonPlayers::iterator m_activeNonPlayersIter;
|
||||
@@ -728,6 +750,8 @@ private:
|
||||
void _ScriptProcessDoor(Object* source, Object* target, const ScriptInfo* scriptInfo) const;
|
||||
GameObject* _FindGameObject(WorldObject* pWorldObject, ObjectGuid::LowType guid) const;
|
||||
|
||||
std::chrono::seconds i_gridExpiry;
|
||||
|
||||
//used for fast base_map (e.g. MapInstanced class object) search for
|
||||
//InstanceMaps and BattlegroundMaps...
|
||||
Map* m_parentMap;
|
||||
@@ -735,7 +759,10 @@ private:
|
||||
NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
|
||||
GridMap* GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
|
||||
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP* TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
|
||||
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP* TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells_large;
|
||||
|
||||
//these functions used to process player/mob aggro reactions and
|
||||
//visibility calculations. Highly optimized for massive calculations
|
||||
void ProcessRelocationNotifies(uint32 diff);
|
||||
|
||||
bool i_scriptLock;
|
||||
std::unordered_set<WorldObject*> i_objectsToRemove;
|
||||
@@ -812,7 +839,7 @@ enum InstanceResetMethod
|
||||
class InstanceMap : public Map
|
||||
{
|
||||
public:
|
||||
InstanceMap(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent);
|
||||
InstanceMap(uint32 id, std::chrono::seconds, uint32 InstanceId, uint8 SpawnMode, Map* _parent);
|
||||
~InstanceMap() override;
|
||||
bool AddPlayerToMap(Player*) override;
|
||||
void RemovePlayerFromMap(Player*, bool) override;
|
||||
@@ -846,7 +873,7 @@ private:
|
||||
class BattlegroundMap : public Map
|
||||
{
|
||||
public:
|
||||
BattlegroundMap(uint32 id, uint32 InstanceId, Map* _parent, uint8 spawnMode);
|
||||
BattlegroundMap(uint32 id, std::chrono::seconds, uint32 InstanceId, Map* _parent, uint8 spawnMode);
|
||||
~BattlegroundMap() override;
|
||||
|
||||
bool AddPlayerToMap(Player*) override;
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "VMapFactory.h"
|
||||
|
||||
MapInstanced::MapInstanced(uint32 id) : Map(id, 0, DUNGEON_DIFFICULTY_NORMAL)
|
||||
MapInstanced::MapInstanced(uint32 id, std::chrono::seconds expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL)
|
||||
{
|
||||
// initialize instanced maps list
|
||||
m_InstancedMaps.clear();
|
||||
// fill with zero
|
||||
memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS * sizeof(uint16));
|
||||
}
|
||||
|
||||
void MapInstanced::InitVisibilityDistance()
|
||||
@@ -203,7 +203,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save,
|
||||
|
||||
LOG_DEBUG("maps", "MapInstanced::CreateInstance: {} map instance {} for {} created with difficulty {}", save ? "" : "new ", InstanceId, GetId(), difficulty ? "heroic" : "normal");
|
||||
|
||||
InstanceMap* map = new InstanceMap(GetId(), InstanceId, difficulty, this);
|
||||
InstanceMap* map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this);
|
||||
ASSERT(map->IsDungeon());
|
||||
|
||||
map->LoadRespawnTimes();
|
||||
@@ -237,7 +237,7 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun
|
||||
else
|
||||
spawnMode = REGULAR_DIFFICULTY;
|
||||
|
||||
BattlegroundMap* map = new BattlegroundMap(GetId(), InstanceId, this, spawnMode);
|
||||
BattlegroundMap* map = new BattlegroundMap(GetId(), GetGridExpiry(), InstanceId, this, spawnMode);
|
||||
ASSERT(map->IsBattlegroundOrArena());
|
||||
map->SetBG(bg);
|
||||
bg->SetBgMap(map);
|
||||
|
||||
@@ -28,7 +28,7 @@ class MapInstanced : public Map
|
||||
public:
|
||||
using InstancedMaps = std::unordered_map<uint32, Map*>;
|
||||
|
||||
MapInstanced(uint32 id);
|
||||
MapInstanced(uint32 id, std::chrono::seconds expiry);
|
||||
~MapInstanced() override {}
|
||||
|
||||
// functions overwrite Map versions
|
||||
@@ -46,6 +46,19 @@ public:
|
||||
}
|
||||
bool DestroyInstance(InstancedMaps::iterator& itr);
|
||||
|
||||
void AddGridMapReference(GridCoord const& p)
|
||||
{
|
||||
++GridMapReference[p.x_coord][p.y_coord];
|
||||
SetUnloadReferenceLock(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - p.x_coord, (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord), true);
|
||||
}
|
||||
|
||||
void RemoveGridMapReference(GridCoord const& p)
|
||||
{
|
||||
--GridMapReference[p.x_coord][p.y_coord];
|
||||
if (!GridMapReference[p.x_coord][p.y_coord])
|
||||
SetUnloadReferenceLock(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - p.x_coord, (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord), false);
|
||||
}
|
||||
|
||||
InstancedMaps& GetInstancedMaps() { return m_InstancedMaps; }
|
||||
void InitVisibilityDistance() override;
|
||||
|
||||
@@ -54,5 +67,7 @@ private:
|
||||
BattlegroundMap* CreateBattleground(uint32 InstanceId, Battleground* bg);
|
||||
|
||||
InstancedMaps m_InstancedMaps;
|
||||
|
||||
uint16 GridMapReference[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
MapMgr::MapMgr()
|
||||
{
|
||||
i_gridCleanUpDelay = sWorld->getIntConfig(CONFIG_INTERVAL_GRIDCLEAN);
|
||||
i_timer[3].SetInterval(sWorld->getIntConfig(CONFIG_INTERVAL_MAPUPDATE));
|
||||
mapUpdateStep = 0;
|
||||
_nextInstanceId = 0;
|
||||
@@ -53,6 +54,8 @@ MapMgr* MapMgr::instance()
|
||||
|
||||
void MapMgr::Initialize()
|
||||
{
|
||||
Map::InitStateMachine();
|
||||
|
||||
int num_threads(sWorld->getIntConfig(CONFIG_NUMTHREADS));
|
||||
|
||||
// Start mtmaps if needed
|
||||
@@ -81,10 +84,10 @@ Map* MapMgr::CreateBaseMap(uint32 id)
|
||||
ASSERT(entry);
|
||||
|
||||
if (entry->Instanceable())
|
||||
map = new MapInstanced(id);
|
||||
map = new MapInstanced(id, std::chrono::seconds(i_gridCleanUpDelay));
|
||||
else
|
||||
{
|
||||
map = new Map(id, 0, REGULAR_DIFFICULTY);
|
||||
map = new Map(id, std::chrono::seconds(i_gridCleanUpDelay), 0, REGULAR_DIFFICULTY);
|
||||
map->LoadRespawnTimes();
|
||||
map->LoadCorpseData();
|
||||
}
|
||||
@@ -333,6 +336,8 @@ void MapMgr::UnloadAll()
|
||||
|
||||
if (m_updater.activated())
|
||||
m_updater.deactivate();
|
||||
|
||||
Map::DeleteStateMachine();
|
||||
}
|
||||
|
||||
void MapMgr::GetNumInstances(uint32& dungeons, uint32& battlegrounds, uint32& arenas)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "MapInstanced.h"
|
||||
#include "MapUpdater.h"
|
||||
#include "Object.h"
|
||||
#include "GridStates.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
@@ -73,6 +74,14 @@ public:
|
||||
void Initialize(void);
|
||||
void Update(uint32);
|
||||
|
||||
void SetGridCleanUpDelay(uint32 t)
|
||||
{
|
||||
if (t < MIN_GRID_DELAY)
|
||||
i_gridCleanUpDelay = MIN_GRID_DELAY;
|
||||
else
|
||||
i_gridCleanUpDelay = t;
|
||||
}
|
||||
|
||||
void SetMapUpdateInterval(uint32 t)
|
||||
{
|
||||
if (t < MIN_MAP_UPDATE_DELAY)
|
||||
@@ -170,6 +179,7 @@ private:
|
||||
MapMgr& operator=(const MapMgr&);
|
||||
|
||||
std::mutex Lock;
|
||||
uint32 i_gridCleanUpDelay;
|
||||
MapMapType i_maps;
|
||||
IntervalTimer i_timer[4]; // continents, bgs/arenas, instances, total from the beginning
|
||||
uint8 mapUpdateStep;
|
||||
|
||||
@@ -38,7 +38,7 @@ Quest::Quest(Field* questRecord)
|
||||
Type = questRecord[5].Get<uint16>();
|
||||
SuggestedPlayers = questRecord[6].Get<uint8>();
|
||||
TimeAllowed = questRecord[7].Get<uint32>();
|
||||
AllowableRaces = questRecord[8].Get<uint16>();
|
||||
AllowableRaces = questRecord[8].Get<uint32>();
|
||||
RequiredFactionId1 = questRecord[9].Get<uint16>();
|
||||
RequiredFactionId2 = questRecord[10].Get<uint16>();
|
||||
RequiredFactionValue1 = questRecord[11].Get<int32>();
|
||||
|
||||
@@ -48,6 +48,15 @@ void ScriptMgr::OnCreatureSaveToDB(Creature* creature)
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::OnBeforeCreatureSelectLevel(const CreatureTemplate* cinfo, Creature* creature, uint8& level)
|
||||
{
|
||||
ExecuteScript<AllCreatureScript>([&](AllCreatureScript* script)
|
||||
{
|
||||
script->OnBeforeCreatureSelectLevel(cinfo, creature, level);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void ScriptMgr::Creature_SelectLevel(const CreatureTemplate* cinfo, Creature* creature)
|
||||
{
|
||||
ExecuteScript<AllCreatureScript>([&](AllCreatureScript* script)
|
||||
|
||||
@@ -160,6 +160,21 @@ void ScriptMgr::OnGameObjectDamaged(GameObject* go, Player* player)
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptMgr::OnGameObjectModifyHealth(GameObject* go, Unit* attackerOrHealer, int32& change, SpellInfo const* spellInfo)
|
||||
{
|
||||
ASSERT(go);
|
||||
|
||||
ExecuteScript<AllGameObjectScript>([&](AllGameObjectScript* script)
|
||||
{
|
||||
script->OnGameObjectModifyHealth(go, attackerOrHealer, change, spellInfo);
|
||||
});
|
||||
|
||||
if (auto tempScript = ScriptRegistry<GameObjectScript>::GetScriptById(go->GetScriptId()))
|
||||
{
|
||||
tempScript->OnModifyHealth(go, attackerOrHealer, change, spellInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptMgr::OnGameObjectLootStateChanged(GameObject* go, uint32 state, Unit* unit)
|
||||
{
|
||||
ASSERT(go);
|
||||
|
||||
@@ -55,6 +55,14 @@ void ScriptMgr::OnAfterRefCount(Player const* player, Loot& loot, bool canRate,
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::OnAfterCalculateLootGroupAmount(Player const* player, Loot& loot, uint16 lootMode, uint32& groupAmount, LootStore const& store)
|
||||
{
|
||||
ExecuteScript<GlobalScript>([&](GlobalScript* script)
|
||||
{
|
||||
script->OnAfterCalculateLootGroupAmount(player, loot, lootMode, groupAmount, store);
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store)
|
||||
{
|
||||
ExecuteScript<GlobalScript>([&](GlobalScript* script)
|
||||
|
||||
@@ -556,6 +556,9 @@ public:
|
||||
// Called from End of Creature Update.
|
||||
virtual void OnAllCreatureUpdate(Creature* /*creature*/, uint32 /*diff*/) { }
|
||||
|
||||
// Called just before the level of the creature is set.
|
||||
virtual void OnBeforeCreatureSelectLevel(const CreatureTemplate* /*cinfo*/, Creature* /*creature*/, uint8& /*level*/) { }
|
||||
|
||||
// Called from End of Creature SelectLevel.
|
||||
virtual void Creature_SelectLevel(const CreatureTemplate* /*cinfo*/, Creature* /*creature*/) { }
|
||||
|
||||
@@ -706,6 +709,9 @@ public:
|
||||
// Called when the game object is damaged (destructible buildings only).
|
||||
virtual void OnGameObjectDamaged(GameObject* /*go*/, Player* /*player*/) { }
|
||||
|
||||
// Called when the health of a game object is modified (destructible buildings only).
|
||||
virtual void OnGameObjectModifyHealth(GameObject* /*go*/, Unit* /*attackerOrHealer*/, int32& /*change*/, SpellInfo const* /*spellInfo*/) { }
|
||||
|
||||
// Called when the game object loot state is changed.
|
||||
virtual void OnGameObjectLootStateChanged(GameObject* /*go*/, uint32 /*state*/, Unit* /*unit*/) { }
|
||||
|
||||
@@ -788,6 +794,9 @@ public:
|
||||
// Called when the game object is damaged (destructible buildings only).
|
||||
virtual void OnDamaged(GameObject* /*go*/, Player* /*player*/) { }
|
||||
|
||||
// Called when the health of a game object is modified (destructible buildings only).
|
||||
virtual void OnModifyHealth(GameObject* /*go*/, Unit* /*attackerOrHealer*/, int32& /*change*/, SpellInfo const* /*spellInfo*/) { }
|
||||
|
||||
// Called when the game object loot state is changed.
|
||||
virtual void OnLootStateChanged(GameObject* /*go*/, uint32 /*state*/, Unit* /*unit*/) { }
|
||||
|
||||
@@ -1634,6 +1643,7 @@ public:
|
||||
|
||||
// loot
|
||||
virtual void OnAfterRefCount(Player const* /*player*/, LootStoreItem* /*LootStoreItem*/, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, uint32& /*maxcount*/, LootStore const& /*store*/) { }
|
||||
virtual void OnAfterCalculateLootGroupAmount(Player const* /*player*/, Loot& /*loot*/, uint16 /*lootMode*/, uint32& /*groupAmount*/, LootStore const& /*store*/) { }
|
||||
virtual void OnBeforeDropAddItem(Player const* /*player*/, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, LootStoreItem* /*LootStoreItem*/, LootStore const& /*store*/) { }
|
||||
virtual bool OnItemRoll(Player const* /*player*/, LootStoreItem const* /*LootStoreItem*/, float& /*chance*/, Loot& /*loot*/, LootStore const& /*store*/) { return true; };
|
||||
virtual bool OnBeforeLootEqualChanced(Player const* /*player*/, LootStoreItemList /*EqualChanced*/, Loot& /*loot*/, LootStore const& /*store*/) { return true; }
|
||||
@@ -2268,6 +2278,7 @@ public: /* GameObjectScript */
|
||||
uint32 GetDialogStatus(Player* player, GameObject* go);
|
||||
void OnGameObjectDestroyed(GameObject* go, Player* player);
|
||||
void OnGameObjectDamaged(GameObject* go, Player* player);
|
||||
void OnGameObjectModifyHealth(GameObject* go, Unit* attackerOrHealer, int32& change, SpellInfo const* spellInfo);
|
||||
void OnGameObjectLootStateChanged(GameObject* go, uint32 state, Unit* unit);
|
||||
void OnGameObjectStateChanged(GameObject* go, uint32 state);
|
||||
void OnGameObjectUpdate(GameObject* go, uint32 diff);
|
||||
@@ -2538,6 +2549,7 @@ public: /* GlobalScript */
|
||||
void OnGlobalMirrorImageDisplayItem(Item const* item, uint32& display);
|
||||
void OnBeforeUpdateArenaPoints(ArenaTeam* at, std::map<ObjectGuid, uint32>& ap);
|
||||
void OnAfterRefCount(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, uint32& maxcount, LootStore const& store);
|
||||
void OnAfterCalculateLootGroupAmount(Player const* player, Loot& loot, uint16 lootMode, uint32& groupAmount, LootStore const& store);
|
||||
void OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store);
|
||||
bool OnItemRoll(Player const* player, LootStoreItem const* LootStoreItem, float& chance, Loot& loot, LootStore const& store);
|
||||
bool OnBeforeLootEqualChanced(Player const* player, LootStoreItemList EqualChanced, Loot& loot, LootStore const& store);
|
||||
@@ -2589,6 +2601,7 @@ public: /* MovementHandlerScript */
|
||||
public: /* AllCreatureScript */
|
||||
//listener function (OnAllCreatureUpdate) is called by OnCreatureUpdate
|
||||
//void OnAllCreatureUpdate(Creature* creature, uint32 diff);
|
||||
void OnBeforeCreatureSelectLevel(const CreatureTemplate* cinfo, Creature* creature, uint8& level);
|
||||
void Creature_SelectLevel(const CreatureTemplate* cinfo, Creature* creature);
|
||||
void OnCreatureSaveToDB(Creature* creature);
|
||||
|
||||
|
||||
@@ -381,8 +381,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
|
||||
|
||||
AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32* baseAmount, Unit* caster):
|
||||
m_base(base), m_spellInfo(base->GetSpellInfo()),
|
||||
m_baseAmount(baseAmount ? * baseAmount : m_spellInfo->Effects[effIndex].BasePoints), m_critChance(0),
|
||||
m_oldAmount(0), m_isAuraEnabled(true), m_channelData(nullptr), m_spellmod(nullptr), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex),
|
||||
m_baseAmount(baseAmount ? * baseAmount : m_spellInfo->Effects[effIndex].BasePoints), m_dieSides(m_spellInfo->Effects[effIndex].DieSides),
|
||||
m_critChance(0), m_oldAmount(0), m_isAuraEnabled(true), m_channelData(nullptr), m_spellmod(nullptr), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex),
|
||||
m_canBeRecalculated(true), m_isPeriodic(false)
|
||||
{
|
||||
CalculatePeriodic(caster, true, false);
|
||||
@@ -1602,8 +1602,8 @@ void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode
|
||||
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
|
||||
}
|
||||
|
||||
target->UpdateObjectVisibility(target->GetTypeId() == TYPEID_PLAYER || target->GetOwnerGUID().IsPlayer() || target->GetMap()->Instanceable(), true);
|
||||
target->bRequestForcedVisibilityUpdate = false;
|
||||
if (target->IsInWorld())
|
||||
target->UpdateObjectVisibility();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModStealthDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -1676,8 +1676,8 @@ void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, boo
|
||||
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
|
||||
}
|
||||
|
||||
target->UpdateObjectVisibility(target->GetTypeId() == TYPEID_PLAYER || target->GetOwnerGUID().IsPlayer() || target->GetMap()->Instanceable(), true);
|
||||
target->bRequestForcedVisibilityUpdate = false;
|
||||
if (target->IsInWorld())
|
||||
target->UpdateObjectVisibility();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModStealthLevel(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -1841,7 +1841,6 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
|
||||
if (!target->GetMap()->Instanceable())
|
||||
{
|
||||
target->UpdateObjectVisibility(false);
|
||||
target->m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f);
|
||||
}
|
||||
else
|
||||
target->UpdateObjectVisibility();
|
||||
@@ -6299,6 +6298,13 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
|
||||
// ignore non positive values (can be result apply spellmods to aura damage
|
||||
uint32 damage = std::max(GetAmount(), 0);
|
||||
|
||||
// If the damage is percent-max-health based, calculate damage before the Modify hook
|
||||
if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
|
||||
{
|
||||
// xinef: ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner
|
||||
damage = uint32(std::ceil(CalculatePct<float, float>(target->GetMaxHealth(), damage)));
|
||||
}
|
||||
|
||||
// Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
|
||||
sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage, GetSpellInfo());
|
||||
|
||||
@@ -6330,8 +6336,6 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
|
||||
// 5..8 ticks have normal tick damage
|
||||
}
|
||||
}
|
||||
else // xinef: ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner
|
||||
damage = uint32(std::ceil(CalculatePct<float, float>(target->GetMaxHealth(), damage)));
|
||||
|
||||
// calculate crit chance
|
||||
bool crit = false;
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
uint32 GetId() const;
|
||||
uint32 GetEffIndex() const { return m_effIndex; }
|
||||
int32 GetBaseAmount() const { return m_baseAmount; }
|
||||
int32 GetDieSides() const { return m_dieSides; }
|
||||
int32 GetAmplitude() const { return m_amplitude; }
|
||||
|
||||
int32 GetMiscValueB() const;
|
||||
@@ -121,6 +122,7 @@ private:
|
||||
|
||||
SpellInfo const* const m_spellInfo;
|
||||
int32 const m_baseAmount;
|
||||
int32 const m_dieSides;
|
||||
|
||||
bool m_applyResilience;
|
||||
uint8 m_casterLevel;
|
||||
|
||||
@@ -6637,8 +6637,8 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
}
|
||||
case SPELL_AURA_MOUNTED:
|
||||
{
|
||||
// Xinef: disallow casting in water for mounts not increasing water movement Speed
|
||||
if (m_caster->IsInWater() && !m_spellInfo->HasAura(SPELL_AURA_MOD_INCREASE_SWIM_SPEED))
|
||||
// Disallow casting flying mounts in water
|
||||
if (m_caster->IsInWater() && m_spellInfo->HasAura(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED))
|
||||
return SPELL_FAILED_ONLY_ABOVEWATER;
|
||||
|
||||
// Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells
|
||||
|
||||
@@ -6057,8 +6057,11 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
|
||||
Position pos;
|
||||
|
||||
// xinef: do not use precalculated position for effect summon pet in this function
|
||||
// it means it was cast by NPC and should have its position overridden
|
||||
if (totalNumGuardians == 1 && GetSpellInfo()->Effects[i].Effect != SPELL_EFFECT_SUMMON_PET)
|
||||
// it means it was cast by NPC and should have its position overridden unless the
|
||||
// target position is specified in the DB AND the effect has no or zero radius
|
||||
if ((totalNumGuardians == 1 && GetSpellInfo()->Effects[i].Effect != SPELL_EFFECT_SUMMON_PET) ||
|
||||
(GetSpellInfo()->Effects[i].TargetA.GetTarget() == TARGET_DEST_DB &&
|
||||
(!GetSpellInfo()->Effects[i].HasRadius() || GetSpellInfo()->Effects[i].RadiusEntry->RadiusMax == 0)))
|
||||
{
|
||||
pos = *destTarget;
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
// Marked for Death
|
||||
ApplySpellFix({ 53241, 53243, 53244, 53245, 53246 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(423937, 276955137, 2049);
|
||||
spellInfo->Effects[EFFECT_0].SpellClassMask = flag96(399361, 276955137, 1);
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
@@ -4572,6 +4572,18 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
|
||||
});
|
||||
|
||||
// Instill Lord Valthalak's Spirit DND
|
||||
ApplySpellFix({ 27360 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->ChannelInterruptFlags |= AURA_INTERRUPT_FLAG_MOVE;
|
||||
});
|
||||
|
||||
// Holiday - Midsummer, Ribbon Pole Periodic Visual
|
||||
ApplySpellFix({ 45406 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AuraInterruptFlags |= ( AURA_INTERRUPT_FLAG_MOUNT | AURA_INTERRUPT_FLAG_CAST );
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -208,6 +208,7 @@ enum WorldFloatConfigs
|
||||
enum WorldIntConfigs
|
||||
{
|
||||
CONFIG_COMPRESSION = 0,
|
||||
CONFIG_INTERVAL_GRIDCLEAN,
|
||||
CONFIG_INTERVAL_MAPUPDATE,
|
||||
CONFIG_INTERVAL_CHANGEWEATHER,
|
||||
CONFIG_INTERVAL_DISCONNECT_TOLERANCE,
|
||||
@@ -505,7 +506,6 @@ enum Rates
|
||||
RATE_TALENT,
|
||||
RATE_CORPSE_DECAY_LOOTED,
|
||||
RATE_INSTANCE_RESET_TIME,
|
||||
RATE_TARGET_POS_RECALCULATION_RANGE,
|
||||
RATE_DURABILITY_LOSS_ON_DEATH,
|
||||
RATE_DURABILITY_LOSS_DAMAGE,
|
||||
RATE_DURABILITY_LOSS_PARRY,
|
||||
|
||||
@@ -110,6 +110,10 @@ float World::_maxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE;
|
||||
float World::_maxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE;
|
||||
float World::_maxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS;
|
||||
|
||||
int32 World::m_visibility_notify_periodOnContinents = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
|
||||
int32 World::m_visibility_notify_periodInInstances = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
|
||||
int32 World::m_visibility_notify_periodInBGArenas = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
|
||||
|
||||
Realm realm;
|
||||
|
||||
/// World constructor
|
||||
@@ -583,18 +587,6 @@ void World::LoadConfigSettings(bool reload)
|
||||
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) playerBaseMoveSpeed[i] = baseMoveSpeed[i] * _rate_values[RATE_MOVESPEED];
|
||||
_rate_values[RATE_CORPSE_DECAY_LOOTED] = sConfigMgr->GetOption<float>("Rate.Corpse.Decay.Looted", 0.5f);
|
||||
|
||||
_rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = sConfigMgr->GetOption<float>("TargetPosRecalculateRange", 1.5f);
|
||||
if (_rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] < CONTACT_DISTANCE)
|
||||
{
|
||||
LOG_ERROR("server.loading", "TargetPosRecalculateRange ({}) must be >= {}. Using {} instead.", _rate_values[RATE_TARGET_POS_RECALCULATION_RANGE], CONTACT_DISTANCE, CONTACT_DISTANCE);
|
||||
_rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = CONTACT_DISTANCE;
|
||||
}
|
||||
else if (_rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] > NOMINAL_MELEE_RANGE)
|
||||
{
|
||||
LOG_ERROR("server.loading", "TargetPosRecalculateRange ({}) must be <= {}. Using {} instead.", _rate_values[RATE_TARGET_POS_RECALCULATION_RANGE], NOMINAL_MELEE_RANGE, NOMINAL_MELEE_RANGE);
|
||||
_rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = NOMINAL_MELEE_RANGE;
|
||||
}
|
||||
|
||||
_rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = sConfigMgr->GetOption<float>("DurabilityLoss.OnDeath", 10.0f);
|
||||
if (_rate_values[RATE_DURABILITY_LOSS_ON_DEATH] < 0.0f)
|
||||
{
|
||||
@@ -667,6 +659,14 @@ void World::LoadConfigSettings(bool reload)
|
||||
LOG_ERROR("server.loading", "PlayerSave.Stats.MinLevel ({}) must be in range 0..80. Using default, do not save character stats (0).", _int_configs[CONFIG_MIN_LEVEL_STAT_SAVE]);
|
||||
_int_configs[CONFIG_MIN_LEVEL_STAT_SAVE] = 0;
|
||||
}
|
||||
_int_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfigMgr->GetOption("GridCleanUpDelay", 5 * MINUTE * IN_MILLISECONDS);
|
||||
if (_int_configs[CONFIG_INTERVAL_GRIDCLEAN] < MIN_GRID_DELAY)
|
||||
{
|
||||
LOG_ERROR("server.loading", "GridCleanUpDelay ({}) must be greater {}. Use this minimal value.", _int_configs[CONFIG_INTERVAL_GRIDCLEAN], MIN_GRID_DELAY);
|
||||
_int_configs[CONFIG_INTERVAL_GRIDCLEAN] = MIN_GRID_DELAY;
|
||||
}
|
||||
if (reload)
|
||||
sMapMgr->SetGridCleanUpDelay(_int_configs[CONFIG_INTERVAL_GRIDCLEAN]);
|
||||
|
||||
_int_configs[CONFIG_INTERVAL_MAPUPDATE] = sConfigMgr->GetOption<int32>("MapUpdateInterval", 10);
|
||||
if (_int_configs[CONFIG_INTERVAL_MAPUPDATE] < MIN_MAP_UPDATE_DELAY)
|
||||
@@ -1261,6 +1261,10 @@ void World::LoadConfigSettings(bool reload)
|
||||
_maxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE;
|
||||
}
|
||||
|
||||
m_visibility_notify_periodOnContinents = sConfigMgr->GetOption<int32>("Visibility.Notify.Period.OnContinents", DEFAULT_VISIBILITY_NOTIFY_PERIOD);
|
||||
m_visibility_notify_periodInInstances = sConfigMgr->GetOption<int32>("Visibility.Notify.Period.InInstances", DEFAULT_VISIBILITY_NOTIFY_PERIOD);
|
||||
m_visibility_notify_periodInBGArenas = sConfigMgr->GetOption<int32>("Visibility.Notify.Period.InBGArenas", DEFAULT_VISIBILITY_NOTIFY_PERIOD);
|
||||
|
||||
///- Load the CharDelete related config options
|
||||
_int_configs[CONFIG_CHARDELETE_METHOD] = sConfigMgr->GetOption<int32>("CharDelete.Method", 0);
|
||||
_int_configs[CONFIG_CHARDELETE_MIN_LEVEL] = sConfigMgr->GetOption<int32>("CharDelete.MinLevel", 0);
|
||||
|
||||
@@ -322,6 +322,10 @@ public:
|
||||
static float GetMaxVisibleDistanceInInstances() { return _maxVisibleDistanceInInstances; }
|
||||
static float GetMaxVisibleDistanceInBGArenas() { return _maxVisibleDistanceInBGArenas; }
|
||||
|
||||
static int32 GetVisibilityNotifyPeriodOnContinents() { return m_visibility_notify_periodOnContinents; }
|
||||
static int32 GetVisibilityNotifyPeriodInInstances() { return m_visibility_notify_periodInInstances; }
|
||||
static int32 GetVisibilityNotifyPeriodInBGArenas() { return m_visibility_notify_periodInBGArenas; }
|
||||
|
||||
// our: needed for arena spectator subscriptions
|
||||
uint32 GetNextWhoListUpdateDelaySecs() override;
|
||||
|
||||
@@ -415,6 +419,10 @@ private:
|
||||
static float _maxVisibleDistanceInInstances;
|
||||
static float _maxVisibleDistanceInBGArenas;
|
||||
|
||||
static int32 m_visibility_notify_periodOnContinents;
|
||||
static int32 m_visibility_notify_periodInInstances;
|
||||
static int32 m_visibility_notify_periodInBGArenas;
|
||||
|
||||
std::string _realmName;
|
||||
|
||||
// CLI command holder to be thread safe
|
||||
|
||||
@@ -25,13 +25,8 @@ EndScriptData */
|
||||
#include "Chat.h"
|
||||
#include "Guild.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "Language.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
#if AC_COMPILER == AC_COMPILER_GNU
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
|
||||
class guild_commandscript : public CommandScript
|
||||
@@ -43,50 +38,38 @@ public:
|
||||
{
|
||||
static ChatCommandTable guildCommandTable =
|
||||
{
|
||||
{ "create", SEC_GAMEMASTER, true, &HandleGuildCreateCommand, "" },
|
||||
{ "delete", SEC_GAMEMASTER, true, &HandleGuildDeleteCommand, "" },
|
||||
{ "invite", SEC_GAMEMASTER, true, &HandleGuildInviteCommand, "" },
|
||||
{ "uninvite", SEC_GAMEMASTER, true, &HandleGuildUninviteCommand, "" },
|
||||
{ "rank", SEC_GAMEMASTER, true, &HandleGuildRankCommand, "" },
|
||||
{ "rename", SEC_GAMEMASTER, true, &HandleGuildRenameCommand, "" },
|
||||
{ "info", SEC_GAMEMASTER, true, &HandleGuildInfoCommand, "" }
|
||||
{ "create", HandleGuildCreateCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "delete", HandleGuildDeleteCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "invite", HandleGuildInviteCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "uninvite", HandleGuildUninviteCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "rank", HandleGuildRankCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "rename", HandleGuildRenameCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "info", HandleGuildInfoCommand, SEC_GAMEMASTER, Console::Yes }
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
{ "guild", SEC_GAMEMASTER, true, nullptr, "", guildCommandTable }
|
||||
{ "guild", guildCommandTable }
|
||||
};
|
||||
return commandTable;
|
||||
}
|
||||
|
||||
/** \brief GM command level 3 - Create a guild.
|
||||
*
|
||||
* This command allows a GM (level 3) to create a guild.
|
||||
*
|
||||
* The "args" parameter contains the name of the guild leader
|
||||
* and then the name of the guild.
|
||||
*
|
||||
*/
|
||||
static bool HandleGuildCreateCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGuildCreateCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, std::string_view guildName)
|
||||
{
|
||||
if (!*args)
|
||||
if (!target)
|
||||
{
|
||||
target = PlayerIdentifier::FromTargetOrSelf(handler);
|
||||
}
|
||||
|
||||
if (!target || !target->IsConnected())
|
||||
{
|
||||
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
// if not guild name only (in "") then player name
|
||||
Player* target;
|
||||
if (!handler->extractPlayerTarget(*args != '"' ? (char*)args : nullptr, &target))
|
||||
return false;
|
||||
Player* playerTarget = target->GetConnectedPlayer();
|
||||
|
||||
char* tailStr = *args != '"' ? strtok(nullptr, "") : (char*)args;
|
||||
if (!tailStr)
|
||||
return false;
|
||||
|
||||
char* guildStr = handler->extractQuotedArg(tailStr);
|
||||
if (!guildStr)
|
||||
return false;
|
||||
|
||||
std::string guildName = guildStr;
|
||||
|
||||
if (target->GetGuildId())
|
||||
if (playerTarget->GetGuildId())
|
||||
{
|
||||
handler->SendSysMessage(LANG_PLAYER_IN_GUILD);
|
||||
handler->SetSentErrorMessage(true);
|
||||
@@ -108,7 +91,7 @@ public:
|
||||
}
|
||||
|
||||
Guild* guild = new Guild;
|
||||
if (!guild->Create(target, guildName))
|
||||
if (!guild->Create(playerTarget, guildName))
|
||||
{
|
||||
delete guild;
|
||||
handler->SendSysMessage(LANG_GUILD_NOT_CREATED);
|
||||
@@ -121,16 +104,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGuildDeleteCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGuildDeleteCommand(ChatHandler*, std::string_view guildName)
|
||||
{
|
||||
if (!*args)
|
||||
if (guildName.empty())
|
||||
{
|
||||
return false;
|
||||
|
||||
char* guildStr = handler->extractQuotedArg((char*)args);
|
||||
if (!guildStr)
|
||||
return false;
|
||||
|
||||
std::string guildName = guildStr;
|
||||
}
|
||||
|
||||
Guild* targetGuild = sGuildMgr->GetGuildByName(guildName);
|
||||
if (!targetGuild)
|
||||
@@ -142,41 +121,41 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGuildInviteCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGuildInviteCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, std::string_view guildName)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
if (!target)
|
||||
{
|
||||
target = PlayerIdentifier::FromTargetOrSelf(handler);
|
||||
}
|
||||
|
||||
// if not guild name only (in "") then player name
|
||||
ObjectGuid targetGuid;
|
||||
if (!handler->extractPlayerTarget(*args != '"' ? (char*)args : nullptr, nullptr, &targetGuid))
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char* tailStr = *args != '"' ? strtok(nullptr, "") : (char*)args;
|
||||
if (!tailStr)
|
||||
return false;
|
||||
|
||||
char* guildStr = handler->extractQuotedArg(tailStr);
|
||||
if (!guildStr)
|
||||
return false;
|
||||
|
||||
std::string guildName = guildStr;
|
||||
Guild* targetGuild = sGuildMgr->GetGuildByName(guildName);
|
||||
if (!targetGuild)
|
||||
return false;
|
||||
|
||||
// player's guild membership checked in AddMember before add
|
||||
return targetGuild->AddMember(targetGuid);
|
||||
return targetGuild->AddMember(target->GetGUID());
|
||||
}
|
||||
|
||||
static bool HandleGuildUninviteCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGuildUninviteCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
Player* target;
|
||||
ObjectGuid targetGuid;
|
||||
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid))
|
||||
return false;
|
||||
if (!target)
|
||||
{
|
||||
target = PlayerIdentifier::FromTargetOrSelf(handler);
|
||||
}
|
||||
|
||||
uint32 guildId = target ? target->GetGuildId() : sCharacterCache->GetCharacterGuildIdByGuid(targetGuid);
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* playerTarget = target->GetConnectedPlayer();
|
||||
|
||||
uint32 guildId = playerTarget ? playerTarget->GetGuildId() : sCharacterCache->GetCharacterGuildIdByGuid(target->GetGUID());
|
||||
if (!guildId)
|
||||
return false;
|
||||
|
||||
@@ -184,7 +163,7 @@ public:
|
||||
if (!targetGuild)
|
||||
return false;
|
||||
|
||||
targetGuild->DeleteMember(targetGuid, false, true, true);
|
||||
targetGuild->DeleteMember(target->GetGUID(), false, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -207,26 +186,15 @@ public:
|
||||
return targetGuild->ChangeMemberRank(player->GetGUID(), rank);
|
||||
}
|
||||
|
||||
static bool HandleGuildRenameCommand(ChatHandler* handler, char const* _args)
|
||||
static bool HandleGuildRenameCommand(ChatHandler* handler, std::string_view oldGuildStr, std::string_view newGuildStr)
|
||||
{
|
||||
if (!*_args)
|
||||
return false;
|
||||
|
||||
char *args = (char *)_args;
|
||||
|
||||
char const* oldGuildStr = handler->extractQuotedArg(args);
|
||||
if (!oldGuildStr)
|
||||
if (!oldGuildStr.empty())
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
char const* newGuildStr = handler->extractQuotedArg(strtok(nullptr, ""));
|
||||
if (!newGuildStr)
|
||||
if (newGuildStr.empty())
|
||||
{
|
||||
handler->SendSysMessage(LANG_INSERT_GUILD_NAME);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -256,35 +224,40 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGuildInfoCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGuildInfoCommand(ChatHandler* handler, Optional<Variant<ObjectGuid::LowType, std::string_view>> const& guildIdentifier)
|
||||
{
|
||||
Guild* guild = nullptr;
|
||||
|
||||
if (args && args[0] != '\0')
|
||||
if (guildIdentifier)
|
||||
{
|
||||
if (isNumeric(args))
|
||||
guild = sGuildMgr->GetGuildById(strtoull(args, nullptr, 10));
|
||||
if (ObjectGuid::LowType const* guid = std::get_if<ObjectGuid::LowType>(&*guildIdentifier))
|
||||
guild = sGuildMgr->GetGuildById(*guid);
|
||||
else
|
||||
guild = sGuildMgr->GetGuildByName(args);
|
||||
guild = sGuildMgr->GetGuildByName(guildIdentifier->get<std::string_view>());
|
||||
}
|
||||
else if (Player* target = handler->getSelectedPlayerOrSelf())
|
||||
guild = target->GetGuild();
|
||||
else if (Optional<PlayerIdentifier> target = PlayerIdentifier::FromTargetOrSelf(handler); target && target->IsConnected())
|
||||
guild = target->GetConnectedPlayer()->GetGuild();
|
||||
|
||||
if (!guild)
|
||||
return false;
|
||||
|
||||
// Display Guild Information
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_NAME, guild->GetName().c_str(), guild->GetId()); // Guild Id + Name
|
||||
|
||||
std::string guildMasterName;
|
||||
if (sCharacterCache->GetCharacterNameByGuid(guild->GetLeaderGUID(), guildMasterName))
|
||||
{
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_GUILD_MASTER, guildMasterName.c_str(), guild->GetLeaderGUID().GetCounter()); // Guild Master
|
||||
}
|
||||
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_CREATION_DATE, Acore::Time::TimeToHumanReadable(Seconds(guild->GetCreatedDate())).c_str()); // Creation Date
|
||||
// Format creation date
|
||||
char createdDateStr[20];
|
||||
time_t createdDate = guild->GetCreatedDate();
|
||||
tm localTm;
|
||||
strftime(createdDateStr, 20, "%Y-%m-%d %H:%M:%S", localtime_r(&createdDate, &localTm));
|
||||
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_CREATION_DATE, createdDateStr); // Creation Date
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_MEMBER_COUNT, guild->GetMemberCount()); // Number of Members
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_BANK_GOLD, guild->GetTotalBankMoney() / 100 / 100); // Bank Gold (in gold coins)
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_MOTD, guild->GetMOTD().c_str()); // Message of the day
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_MOTD, guild->GetMOTD().c_str()); // Message of the Day
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_EXTRA_INFO, guild->GetInfo().c_str()); // Extra Information
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
{
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
{ "commentator", HandleCommentatorCommand, SEC_MODERATOR, Console::No },
|
||||
{ "dev", HandleDevCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "gps", HandleGPSCommand, SEC_MODERATOR, Console::No },
|
||||
{ "aura", HandleAuraCommand, SEC_GAMEMASTER, Console::No },
|
||||
@@ -451,6 +452,51 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleCommentatorCommand(ChatHandler* handler, Optional<bool> enableArg)
|
||||
{
|
||||
WorldSession* session = handler->GetSession();
|
||||
|
||||
if (!session)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto SetCommentatorMod = [&](bool enable)
|
||||
{
|
||||
session->SendNotification(enable ? "Commentator mode on" : "Commentator mode off");
|
||||
session->GetPlayer()->SetCommentator(enable);
|
||||
};
|
||||
|
||||
if (!enableArg)
|
||||
{
|
||||
if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->IsCommentator())
|
||||
{
|
||||
SetCommentatorMod(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCommentatorMod(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*enableArg)
|
||||
{
|
||||
SetCommentatorMod(true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCommentatorMod(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->SendSysMessage(LANG_USE_BOL);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HandleDevCommand(ChatHandler* handler, Optional<bool> enableArg)
|
||||
{
|
||||
WorldSession* session = handler->GetSession();
|
||||
@@ -467,32 +513,29 @@ public:
|
||||
sScriptMgr->OnHandleDevCommand(handler->GetSession()->GetPlayer(), enable);
|
||||
};
|
||||
|
||||
if (WorldSession* session = handler->GetSession())
|
||||
if (!enableArg)
|
||||
{
|
||||
if (!enableArg)
|
||||
{
|
||||
if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->IsDeveloper())
|
||||
{
|
||||
SetDevMod(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDevMod(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*enableArg)
|
||||
if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->IsDeveloper())
|
||||
{
|
||||
SetDevMod(true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDevMod(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*enableArg)
|
||||
{
|
||||
SetDevMod(true);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDevMod(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->SendSysMessage(LANG_USE_BOL);
|
||||
|
||||
@@ -30,10 +30,6 @@ EndScriptData */
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
#if AC_COMPILER == AC_COMPILER_GNU
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
|
||||
class reset_commandscript : public CommandScript
|
||||
@@ -45,48 +41,53 @@ public:
|
||||
{
|
||||
static ChatCommandTable resetCommandTable =
|
||||
{
|
||||
{ "achievements", SEC_CONSOLE, true, &HandleResetAchievementsCommand, "" },
|
||||
{ "honor", SEC_ADMINISTRATOR, true, &HandleResetHonorCommand, "" },
|
||||
{ "level", SEC_ADMINISTRATOR, true, &HandleResetLevelCommand, "" },
|
||||
{ "spells", SEC_ADMINISTRATOR, true, &HandleResetSpellsCommand, "" },
|
||||
{ "stats", SEC_ADMINISTRATOR, true, &HandleResetStatsCommand, "" },
|
||||
{ "talents", SEC_ADMINISTRATOR, true, &HandleResetTalentsCommand, "" },
|
||||
{ "all", SEC_CONSOLE, true, &HandleResetAllCommand, "" }
|
||||
{ "achievements", HandleResetAchievementsCommand, SEC_CONSOLE, Console::Yes },
|
||||
{ "honor", HandleResetHonorCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "level", HandleResetLevelCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "spells", HandleResetSpellsCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "stats", HandleResetStatsCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "talents", HandleResetTalentsCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "all", HandleResetAllCommand, SEC_CONSOLE, Console::Yes }
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
{ "reset", SEC_ADMINISTRATOR, true, nullptr, "", resetCommandTable }
|
||||
{ "reset", resetCommandTable }
|
||||
};
|
||||
return commandTable;
|
||||
}
|
||||
|
||||
static bool HandleResetAchievementsCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleResetAchievementsCommand(ChatHandler*, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
Player* target;
|
||||
ObjectGuid targetGuid;
|
||||
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid))
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target)
|
||||
target->ResetAchievements();
|
||||
Player* playerTarget = target->GetConnectedPlayer();
|
||||
|
||||
if (playerTarget)
|
||||
playerTarget->ResetAchievements();
|
||||
else
|
||||
AchievementMgr::DeleteFromDB(targetGuid.GetCounter());
|
||||
AchievementMgr::DeleteFromDB(target->GetGUID().GetCounter());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleResetHonorCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleResetHonorCommand(ChatHandler*, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
Player* target;
|
||||
if (!handler->extractPlayerTarget((char*)args, &target))
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
target->SetHonorPoints(0);
|
||||
target->SetUInt32Value(PLAYER_FIELD_KILLS, 0);
|
||||
target->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0);
|
||||
target->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0);
|
||||
target->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
|
||||
target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL);
|
||||
Player* playerTarget = target->GetConnectedPlayer();
|
||||
|
||||
playerTarget->SetHonorPoints(0);
|
||||
playerTarget->SetUInt32Value(PLAYER_FIELD_KILLS, 0);
|
||||
playerTarget->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0);
|
||||
playerTarget->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0);
|
||||
playerTarget->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
|
||||
playerTarget->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -123,156 +124,145 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleResetLevelCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleResetLevelCommand(ChatHandler*, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
Player* target;
|
||||
if (!handler->extractPlayerTarget((char*)args, &target))
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* playerTarget = target->GetConnectedPlayer();
|
||||
|
||||
if (!HandleResetStatsOrLevelHelper(playerTarget))
|
||||
return false;
|
||||
|
||||
if (!HandleResetStatsOrLevelHelper(target))
|
||||
return false;
|
||||
|
||||
uint8 oldLevel = target->GetLevel();
|
||||
uint8 oldLevel = playerTarget->GetLevel();
|
||||
|
||||
// set starting level
|
||||
uint32 startLevel = target->getClass() != CLASS_DEATH_KNIGHT
|
||||
uint32 startLevel = playerTarget->getClass() != CLASS_DEATH_KNIGHT
|
||||
? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)
|
||||
: sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
|
||||
|
||||
target->_ApplyAllLevelScaleItemMods(false);
|
||||
target->SetLevel(startLevel);
|
||||
target->InitRunes();
|
||||
target->InitStatsForLevel(true);
|
||||
target->InitTaxiNodesForLevel();
|
||||
target->InitGlyphsForLevel();
|
||||
target->InitTalentForLevel();
|
||||
target->SetUInt32Value(PLAYER_XP, 0);
|
||||
playerTarget->_ApplyAllLevelScaleItemMods(false);
|
||||
playerTarget->SetLevel(startLevel);
|
||||
playerTarget->InitRunes();
|
||||
playerTarget->InitStatsForLevel(true);
|
||||
playerTarget->InitTaxiNodesForLevel();
|
||||
playerTarget->InitGlyphsForLevel();
|
||||
playerTarget->InitTalentForLevel();
|
||||
playerTarget->SetUInt32Value(PLAYER_XP, 0);
|
||||
|
||||
target->_ApplyAllLevelScaleItemMods(true);
|
||||
playerTarget->_ApplyAllLevelScaleItemMods(true);
|
||||
|
||||
// reset level for pet
|
||||
if (Pet* pet = target->GetPet())
|
||||
if (Pet* pet = playerTarget->GetPet())
|
||||
pet->SynchronizeLevelWithOwner();
|
||||
|
||||
sScriptMgr->OnPlayerLevelChanged(target, oldLevel);
|
||||
sScriptMgr->OnPlayerLevelChanged(playerTarget, oldLevel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleResetSpellsCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleResetSpellsCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
Player* target;
|
||||
ObjectGuid targetGuid;
|
||||
std::string targetName;
|
||||
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName))
|
||||
if (!target)
|
||||
{
|
||||
target = PlayerIdentifier::FromTargetOrSelf(handler);
|
||||
}
|
||||
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* playerTarget = target->GetConnectedPlayer();
|
||||
|
||||
if (target)
|
||||
{
|
||||
target->resetSpells(/* bool myClassOnly */);
|
||||
playerTarget->resetSpells(/* bool myClassOnly */);
|
||||
|
||||
ChatHandler(target->GetSession()).SendSysMessage(LANG_RESET_SPELLS);
|
||||
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != target)
|
||||
handler->PSendSysMessage(LANG_RESET_SPELLS_ONLINE, handler->GetNameLink(target).c_str());
|
||||
ChatHandler(playerTarget->GetSession()).SendSysMessage(LANG_RESET_SPELLS);
|
||||
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != playerTarget)
|
||||
handler->PSendSysMessage(LANG_RESET_SPELLS_ONLINE, handler->GetNameLink(playerTarget).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt->SetData(0, uint16(AT_LOGIN_RESET_SPELLS));
|
||||
stmt->SetData(1, targetGuid.GetCounter());
|
||||
stmt->SetData(1, playerTarget->GetGUID().GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
handler->PSendSysMessage(LANG_RESET_SPELLS_OFFLINE, targetName.c_str());
|
||||
handler->PSendSysMessage(LANG_RESET_SPELLS_OFFLINE, target->GetName());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleResetStatsCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleResetStatsCommand(ChatHandler*, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
Player* target;
|
||||
if (!handler->extractPlayerTarget((char*)args, &target))
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* playerTarget = target->GetConnectedPlayer();
|
||||
|
||||
if (!HandleResetStatsOrLevelHelper(playerTarget))
|
||||
return false;
|
||||
|
||||
if (!HandleResetStatsOrLevelHelper(target))
|
||||
return false;
|
||||
|
||||
target->InitRunes();
|
||||
target->InitStatsForLevel(true);
|
||||
target->InitTaxiNodesForLevel();
|
||||
target->InitGlyphsForLevel();
|
||||
target->InitTalentForLevel();
|
||||
playerTarget->InitRunes();
|
||||
playerTarget->InitStatsForLevel(true);
|
||||
playerTarget->InitTaxiNodesForLevel();
|
||||
playerTarget->InitGlyphsForLevel();
|
||||
playerTarget->InitTalentForLevel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleResetTalentsCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleResetTalentsCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
|
||||
{
|
||||
Player* target;
|
||||
ObjectGuid targetGuid;
|
||||
std::string targetName;
|
||||
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName))
|
||||
Player* targetPlayer = nullptr;
|
||||
|
||||
if (target)
|
||||
{
|
||||
targetPlayer = target->GetConnectedPlayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try reset talents as Hunter Pet
|
||||
Creature* creature = handler->getSelectedCreature();
|
||||
if (!*args && creature && creature->IsPet())
|
||||
{
|
||||
Unit* owner = creature->GetOwner();
|
||||
if (owner && owner->GetTypeId() == TYPEID_PLAYER && creature->ToPet()->IsPermanentPetFor(owner->ToPlayer()))
|
||||
{
|
||||
creature->ToPet()->resetTalents();
|
||||
owner->ToPlayer()->SendTalentsInfoData(true);
|
||||
|
||||
ChatHandler(owner->ToPlayer()->GetSession()).SendSysMessage(LANG_RESET_PET_TALENTS);
|
||||
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != owner->ToPlayer())
|
||||
handler->PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE, handler->GetNameLink(owner->ToPlayer()).c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target)
|
||||
if (targetPlayer)
|
||||
{
|
||||
target->resetTalents(true);
|
||||
target->SendTalentsInfoData(false);
|
||||
ChatHandler(target->GetSession()).SendSysMessage(LANG_RESET_TALENTS);
|
||||
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != target)
|
||||
handler->PSendSysMessage(LANG_RESET_TALENTS_ONLINE, handler->GetNameLink(target).c_str());
|
||||
targetPlayer->resetTalents(true);
|
||||
targetPlayer->SendTalentsInfoData(false);
|
||||
ChatHandler(targetPlayer->GetSession()).SendSysMessage(LANG_RESET_TALENTS);
|
||||
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != targetPlayer)
|
||||
handler->PSendSysMessage(LANG_RESET_TALENTS_ONLINE, handler->GetNameLink(targetPlayer).c_str());
|
||||
|
||||
Pet* pet = target->GetPet();
|
||||
Pet::resetTalentsForAllPetsOf(target, pet);
|
||||
Pet* pet = targetPlayer->GetPet();
|
||||
Pet::resetTalentsForAllPetsOf(targetPlayer, pet);
|
||||
if (pet)
|
||||
target->SendTalentsInfoData(true);
|
||||
targetPlayer->SendTalentsInfoData(true);
|
||||
return true;
|
||||
}
|
||||
else if (targetGuid)
|
||||
else
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt->SetData(0, uint16(AT_LOGIN_RESET_TALENTS | AT_LOGIN_RESET_PET_TALENTS));
|
||||
stmt->SetData(1, targetGuid.GetCounter());
|
||||
stmt->SetData(1, target->GetGUID().GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
std::string nameLink = handler->playerLink(targetName);
|
||||
std::string nameLink = handler->playerLink(target->GetName());
|
||||
handler->PSendSysMessage(LANG_RESET_TALENTS_OFFLINE, nameLink.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HandleResetAllCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleResetAllCommand(ChatHandler* handler, std::string_view caseName)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
std::string caseName = args;
|
||||
|
||||
AtLoginFlags atLogin;
|
||||
|
||||
// Command specially created as single command to prevent using short case names
|
||||
@@ -292,7 +282,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
handler->PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE, args);
|
||||
handler->PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE, caseName);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
@@ -303,7 +293,7 @@ public:
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock(*HashMapHolder<Player>::GetLock());
|
||||
HashMapHolder<Player>::MapType const& plist = ObjectAccessor::GetPlayers();
|
||||
for (HashMapHolder<Player>::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr)
|
||||
for (auto itr = plist.begin(); itr != plist.end(); ++itr)
|
||||
itr->second->SetAtLoginFlag(atLogin);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -24,7 +24,6 @@ EndScriptData */
|
||||
|
||||
#include "AccountMgr.h"
|
||||
#include "Chat.h"
|
||||
#include "Language.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
@@ -32,10 +31,6 @@ EndScriptData */
|
||||
#include "ScriptMgr.h"
|
||||
#include "TicketMgr.h"
|
||||
|
||||
#if AC_COMPILER == AC_COMPILER_GNU
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
|
||||
class ticket_commandscript : public CommandScript
|
||||
@@ -47,48 +42,38 @@ public:
|
||||
{
|
||||
static ChatCommandTable ticketResponseCommandTable =
|
||||
{
|
||||
{ "append", SEC_GAMEMASTER, true, &HandleGMTicketResponseAppendCommand, "" },
|
||||
{ "appendln", SEC_GAMEMASTER, true, &HandleGMTicketResponseAppendLnCommand, "" }
|
||||
{ "append", HandleGMTicketResponseAppendCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "appendln", HandleGMTicketResponseAppendLnCommand, SEC_GAMEMASTER, Console::Yes }
|
||||
};
|
||||
static ChatCommandTable ticketCommandTable =
|
||||
{
|
||||
{ "assign", SEC_GAMEMASTER, true, &HandleGMTicketAssignToCommand, "" },
|
||||
{ "close", SEC_GAMEMASTER, true, &HandleGMTicketCloseByIdCommand, "" },
|
||||
{ "closedlist", SEC_GAMEMASTER, true, &HandleGMTicketListClosedCommand, "" },
|
||||
{ "comment", SEC_GAMEMASTER, true, &HandleGMTicketCommentCommand, "" },
|
||||
{ "complete", SEC_GAMEMASTER, true, &HandleGMTicketCompleteCommand, "" },
|
||||
{ "delete", SEC_ADMINISTRATOR, true, &HandleGMTicketDeleteByIdCommand, "" },
|
||||
{ "escalate", SEC_GAMEMASTER, true, &HandleGMTicketEscalateCommand, "" },
|
||||
{ "escalatedlist", SEC_GAMEMASTER, true, &HandleGMTicketListEscalatedCommand, "" },
|
||||
{ "list", SEC_GAMEMASTER, true, &HandleGMTicketListCommand, "" },
|
||||
{ "onlinelist", SEC_GAMEMASTER, true, &HandleGMTicketListOnlineCommand, "" },
|
||||
{ "reset", SEC_CONSOLE, true, &HandleGMTicketResetCommand, "" },
|
||||
{ "response", SEC_GAMEMASTER, true, nullptr, "", ticketResponseCommandTable },
|
||||
{ "togglesystem", SEC_ADMINISTRATOR, true, &HandleToggleGMTicketSystem, "" },
|
||||
{ "unassign", SEC_GAMEMASTER, true, &HandleGMTicketUnAssignCommand, "" },
|
||||
{ "viewid", SEC_GAMEMASTER, true, &HandleGMTicketGetByIdCommand, "" },
|
||||
{ "viewname", SEC_GAMEMASTER, true, &HandleGMTicketGetByNameCommand, "" }
|
||||
{ "assign", HandleGMTicketAssignToCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "close", HandleGMTicketCloseByIdCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "closedlist", HandleGMTicketListClosedCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "comment", HandleGMTicketCommentCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "complete", HandleGMTicketCompleteCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "delete", HandleGMTicketDeleteByIdCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "escalate", HandleGMTicketEscalateCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "escalatedlist", HandleGMTicketListEscalatedCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "list", HandleGMTicketListCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "onlinelist", HandleGMTicketListOnlineCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "reset", HandleGMTicketResetCommand, SEC_CONSOLE, Console::Yes },
|
||||
|
||||
{ "response", ticketResponseCommandTable },
|
||||
{ "togglesystem", HandleToggleGMTicketSystem, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "unassign", HandleGMTicketUnAssignCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "viewid", HandleGMTicketGetByIdCommand, SEC_GAMEMASTER, Console::Yes },
|
||||
{ "viewname", HandleGMTicketGetByNameCommand, SEC_GAMEMASTER, Console::Yes }
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
{ "ticket", SEC_GAMEMASTER, false, nullptr, "", ticketCommandTable }
|
||||
{ "ticket", ticketCommandTable }
|
||||
};
|
||||
return commandTable;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketAssignToCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketAssignToCommand(ChatHandler* handler, uint32 ticketId, std::string target)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
char* ticketIdStr = strtok((char*)args, " ");
|
||||
uint32 ticketId = atoi(ticketIdStr);
|
||||
|
||||
char* targetStr = strtok(nullptr, " ");
|
||||
if (!targetStr)
|
||||
return false;
|
||||
|
||||
std::string target(targetStr);
|
||||
if (!normalizePlayerName(target))
|
||||
return false;
|
||||
|
||||
@@ -138,12 +123,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketCloseByIdCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketCloseByIdCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
uint32 ticketId = atoi(args);
|
||||
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
|
||||
if (!ticket || ticket->IsClosed() || ticket->IsCompleted())
|
||||
{
|
||||
@@ -177,14 +158,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketCommentCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketCommentCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
char* ticketIdStr = strtok((char*)args, " ");
|
||||
uint32 ticketId = atoi(ticketIdStr);
|
||||
|
||||
char* comment = strtok(nullptr, "\n");
|
||||
if (!comment)
|
||||
return false;
|
||||
@@ -218,20 +193,14 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketListClosedCommand(ChatHandler* handler, char const* /*args*/)
|
||||
static bool HandleGMTicketListClosedCommand(ChatHandler* handler)
|
||||
{
|
||||
sTicketMgr->ShowClosedList(*handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketCompleteCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketCompleteCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
char* ticketIdStr = strtok((char*)args, " ");
|
||||
uint32 ticketId = atoi(ticketIdStr);
|
||||
|
||||
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
|
||||
if (!ticket || ticket->IsClosed() || ticket->IsCompleted())
|
||||
{
|
||||
@@ -272,12 +241,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketDeleteByIdCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketDeleteByIdCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
uint32 ticketId = atoi(args);
|
||||
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
|
||||
if (!ticket)
|
||||
{
|
||||
@@ -308,12 +273,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketEscalateCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketEscalateCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
uint32 ticketId = atoi(args);
|
||||
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
|
||||
if (!ticket || ticket->IsClosed() || ticket->IsCompleted() || ticket->GetEscalatedStatus() != TICKET_UNASSIGNED)
|
||||
{
|
||||
@@ -330,25 +291,25 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketListEscalatedCommand(ChatHandler* handler, char const* /*args*/)
|
||||
static bool HandleGMTicketListEscalatedCommand(ChatHandler* handler)
|
||||
{
|
||||
sTicketMgr->ShowEscalatedList(*handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketListCommand(ChatHandler* handler, char const* /*args*/)
|
||||
static bool HandleGMTicketListCommand(ChatHandler* handler)
|
||||
{
|
||||
sTicketMgr->ShowList(*handler, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketListOnlineCommand(ChatHandler* handler, char const* /*args*/)
|
||||
static bool HandleGMTicketListOnlineCommand(ChatHandler* handler)
|
||||
{
|
||||
sTicketMgr->ShowList(*handler, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketResetCommand(ChatHandler* handler, char const* /*args*/)
|
||||
static bool HandleGMTicketResetCommand(ChatHandler* handler)
|
||||
{
|
||||
if (sTicketMgr->GetOpenTicketCount())
|
||||
{
|
||||
@@ -364,7 +325,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleToggleGMTicketSystem(ChatHandler* handler, char const* /*args*/)
|
||||
static bool HandleToggleGMTicketSystem(ChatHandler* handler)
|
||||
{
|
||||
bool status = !sTicketMgr->GetStatus();
|
||||
sTicketMgr->SetStatus(status);
|
||||
@@ -372,12 +333,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketUnAssignCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketUnAssignCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
uint32 ticketId = atoi(args);
|
||||
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
|
||||
if (!ticket || ticket->IsClosed())
|
||||
{
|
||||
@@ -425,12 +382,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketGetByIdCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketGetByIdCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
uint32 ticketId = atoi(args);
|
||||
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
|
||||
if (!ticket || ticket->IsClosed() || ticket->IsCompleted())
|
||||
{
|
||||
@@ -442,16 +395,12 @@ public:
|
||||
ticket->SetViewed();
|
||||
ticket->SaveToDB(trans);
|
||||
|
||||
handler->SendSysMessage(ticket->FormatMessageString(*handler, true).c_str());
|
||||
handler->SendSysMessage(ticket->FormatMessageString(*handler, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketGetByNameCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketGetByNameCommand(ChatHandler* handler, std::string name)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
std::string name(args);
|
||||
if (!normalizePlayerName(name))
|
||||
return false;
|
||||
|
||||
@@ -485,18 +434,12 @@ public:
|
||||
ticket->SetViewed();
|
||||
ticket->SaveToDB(trans);
|
||||
|
||||
handler->SendSysMessage(ticket->FormatMessageString(*handler, true).c_str());
|
||||
handler->SendSysMessage(ticket->FormatMessageString(*handler, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _HandleGMTicketResponseAppendCommand(char const* args, bool newLine, ChatHandler* handler)
|
||||
static bool _HandleGMTicketResponseAppendCommand(uint32 ticketId, bool newLine, ChatHandler* handler)
|
||||
{
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
char* ticketIdStr = strtok((char*)args, " ");
|
||||
uint32 ticketId = atoi(ticketIdStr);
|
||||
|
||||
char* response = strtok(nullptr, "\n");
|
||||
if (!response)
|
||||
return false;
|
||||
@@ -526,14 +469,14 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMTicketResponseAppendCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketResponseAppendCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
return _HandleGMTicketResponseAppendCommand(args, false, handler);
|
||||
return _HandleGMTicketResponseAppendCommand(ticketId, false, handler);
|
||||
}
|
||||
|
||||
static bool HandleGMTicketResponseAppendLnCommand(ChatHandler* handler, char const* args)
|
||||
static bool HandleGMTicketResponseAppendLnCommand(ChatHandler* handler, uint32 ticketId)
|
||||
{
|
||||
return _HandleGMTicketResponseAppendCommand(args, true, handler);
|
||||
return _HandleGMTicketResponseAppendCommand(ticketId, true, handler);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -44,12 +44,18 @@ enum Spells
|
||||
|
||||
struct boss_curator : public BossAI
|
||||
{
|
||||
boss_curator(Creature* creature) : BossAI(creature, DATA_CURATOR) { }
|
||||
boss_curator(Creature* creature) : BossAI(creature, DATA_CURATOR)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_MANA_LEECH, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_POWER_BURN, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_BURN, true);
|
||||
@@ -132,18 +138,6 @@ struct boss_curator : public BossAI
|
||||
}
|
||||
summon->SetInCombatWithZone();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_curator()
|
||||
|
||||
@@ -101,6 +101,7 @@ struct boss_netherspite : public BossAI
|
||||
BossAI::Reset();
|
||||
berserk = false;
|
||||
HandleDoors(true);
|
||||
DestroyPortals();
|
||||
}
|
||||
|
||||
void SummonPortals()
|
||||
@@ -219,6 +220,24 @@ struct boss_netherspite : public BossAI
|
||||
});
|
||||
}
|
||||
|
||||
void DestroyPortals()
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[i]))
|
||||
{
|
||||
portal->DisappearAndDie();
|
||||
}
|
||||
if (Creature* portal = ObjectAccessor::GetCreature(*me, BeamerGUID[i]))
|
||||
{
|
||||
portal->DisappearAndDie();
|
||||
}
|
||||
|
||||
PortalGUID[i].Clear();
|
||||
BeamTarget[i].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchToBanishPhase()
|
||||
{
|
||||
Talk(EMOTE_PHASE_BANISH);
|
||||
@@ -228,10 +247,7 @@ struct boss_netherspite : public BossAI
|
||||
DoCastSelf(SPELL_BANISH_VISUAL, true);
|
||||
DoCastSelf(SPELL_BANISH_ROOT, true);
|
||||
|
||||
for (uint32 id : PortalID)
|
||||
{
|
||||
summons.DespawnEntry(id);
|
||||
}
|
||||
DestroyPortals();
|
||||
|
||||
scheduler.Schedule(30s, [this](TaskContext)
|
||||
{
|
||||
|
||||
@@ -87,9 +87,19 @@ struct boss_nightbane : public BossAI
|
||||
{
|
||||
BossAI::Reset();
|
||||
_skeletonscheduler.CancelAll();
|
||||
Phase = 1;
|
||||
MovePhase = 0;
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
if (!_intro)
|
||||
{
|
||||
//when boss is reset and we're past the intro
|
||||
//cannot despawn, but have to move to a location where he normally is
|
||||
//me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
|
||||
Position preSpawnPosis = me->GetHomePosition();
|
||||
EnterEvadeMode();
|
||||
me->NearTeleportTo(preSpawnPosis);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
_intro = true;
|
||||
Phase = 1;
|
||||
MovePhase = 0;
|
||||
}
|
||||
|
||||
me->SetSpeed(MOVE_RUN, 2.0f);
|
||||
me->SetDisableGravity(_intro);
|
||||
@@ -109,19 +119,6 @@ struct boss_nightbane : public BossAI
|
||||
_flying = false;
|
||||
_movement = false;
|
||||
|
||||
if (!_intro)
|
||||
{
|
||||
//when boss is reset and we're past the intro
|
||||
//cannot despawn, but have to move to a location where he normally is
|
||||
//me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
|
||||
Position preSpawnPosis = me->GetHomePosition();
|
||||
me->NearTeleportTo(preSpawnPosis);
|
||||
instance->SetData(DATA_NIGHTBANE, NOT_STARTED);
|
||||
_intro = true;
|
||||
Phase = 1;
|
||||
MovePhase = 0;
|
||||
}
|
||||
|
||||
ScheduleHealthCheckEvent({ 75, 50, 25 }, [&]{
|
||||
TakeOff();
|
||||
});
|
||||
@@ -136,11 +133,10 @@ struct boss_nightbane : public BossAI
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
if (instance)
|
||||
instance->SetData(DATA_NIGHTBANE, IN_PROGRESS);
|
||||
BossAI::JustEngagedWith(who);
|
||||
_intro = false;
|
||||
|
||||
HandleTerraceDoors(false);
|
||||
Talk(YELL_AGGRO);
|
||||
@@ -238,7 +234,6 @@ struct boss_nightbane : public BossAI
|
||||
{
|
||||
if (id >= 8)
|
||||
{
|
||||
_intro = false;
|
||||
//me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
|
||||
//doesn't need home position because we have to "despawn" boss on reset
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
@@ -18,51 +18,58 @@
|
||||
#include "GameObject.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
#include "karazhan.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
enum Texts
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_FLAMEWREATH = 1,
|
||||
SAY_BLIZZARD = 2,
|
||||
SAY_EXPLOSION = 3,
|
||||
SAY_DRINK = 4,
|
||||
SAY_ELEMENTALS = 5,
|
||||
SAY_KILL = 6,
|
||||
SAY_TIMEOVER = 7,
|
||||
SAY_DEATH = 8
|
||||
SAY_AGGRO = 0,
|
||||
SAY_FLAMEWREATH = 1,
|
||||
SAY_BLIZZARD = 2,
|
||||
SAY_EXPLOSION = 3,
|
||||
SAY_DRINK = 4,
|
||||
SAY_ELEMENTALS = 5,
|
||||
SAY_KILL = 6,
|
||||
SAY_TIMEOVER = 7,
|
||||
SAY_DEATH = 8,
|
||||
SAY_ATIESH = 9,
|
||||
EMOTE_ARCANE_EXPLOSION = 10
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
//Spells
|
||||
SPELL_FROSTBOLT = 29954,
|
||||
SPELL_FIREBALL = 29953,
|
||||
SPELL_ARCMISSLE = 29955,
|
||||
SPELL_CHAINSOFICE = 29991,
|
||||
SPELL_DRAGONSBREATH = 29964,
|
||||
SPELL_MASSSLOW = 30035,
|
||||
SPELL_FLAME_WREATH = 29946,
|
||||
SPELL_AOE_CS = 29961,
|
||||
SPELL_PLAYERPULL = 32265,
|
||||
SPELL_AEXPLOSION = 29973,
|
||||
SPELL_MASS_POLY = 29963,
|
||||
SPELL_BLINK_CENTER = 29967,
|
||||
SPELL_CONJURE = 29975,
|
||||
SPELL_DRINK = 30024,
|
||||
SPELL_POTION = 32453,
|
||||
SPELL_AOE_PYROBLAST = 29978,
|
||||
SPELL_FROSTBOLT = 29954,
|
||||
SPELL_FIREBALL = 29953,
|
||||
SPELL_ARCMISSLE = 29955,
|
||||
SPELL_CHAINSOFICE = 29991,
|
||||
SPELL_DRAGONSBREATH = 29964,
|
||||
SPELL_MASSSLOW = 30035,
|
||||
SPELL_FLAME_WREATH = 30004,
|
||||
SPELL_FLAME_WREATH_RING = 29946,
|
||||
SPELL_FLAME_WREATH_RAN_THRU = 29947, // You ran through the flames!
|
||||
SPELL_FLAME_WREATH_EXPLOSION = 29949,
|
||||
SPELL_AOE_CS = 29961,
|
||||
SPELL_PLAYERPULL = 32265,
|
||||
SPELL_AEXPLOSION = 29973,
|
||||
SPELL_MASS_POLY = 29963,
|
||||
SPELL_BLINK_CENTER = 29967,
|
||||
SPELL_CONJURE = 29975,
|
||||
SPELL_DRINK = 30024,
|
||||
SPELL_POTION = 32453,
|
||||
SPELL_AOE_PYROBLAST = 29978,
|
||||
|
||||
SPELL_SUMMON_WELEMENTAL_1 = 29962,
|
||||
SPELL_SUMMON_WELEMENTAL_2 = 37051,
|
||||
SPELL_SUMMON_WELEMENTAL_3 = 37052,
|
||||
SPELL_SUMMON_WELEMENTAL_4 = 37053,
|
||||
SPELL_SUMMON_WELEMENTAL_1 = 29962,
|
||||
SPELL_SUMMON_WELEMENTAL_2 = 37051,
|
||||
SPELL_SUMMON_WELEMENTAL_3 = 37052,
|
||||
SPELL_SUMMON_WELEMENTAL_4 = 37053,
|
||||
|
||||
SPELL_SUMMON_BLIZZARD = 29969, // Activates the Blizzard NPC
|
||||
SPELL_SUMMON_BLIZZARD = 29969, // Activates the Blizzard NPC
|
||||
|
||||
SPELL_SHADOW_PYRO = 29978
|
||||
SPELL_SHADOW_PYRO = 29978
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
@@ -79,20 +86,11 @@ enum SuperSpell
|
||||
|
||||
enum Groups
|
||||
{
|
||||
GROUP_FLAMEWREATH = 0,
|
||||
GROUP_DRINKING = 1
|
||||
GROUP_DRINKING = 0
|
||||
};
|
||||
|
||||
Position const roomCenter = {-11158.f, -1920.f};
|
||||
|
||||
Position const elementalPos[4] =
|
||||
{
|
||||
{-11168.1f, -1939.29f, 232.092f, 1.46f},
|
||||
{-11138.2f, -1915.38f, 232.092f, 3.00f},
|
||||
{-11161.7f, -1885.36f, 232.092f, 4.59f},
|
||||
{-11192.4f, -1909.36f, 232.092f, 6.19f}
|
||||
};
|
||||
|
||||
struct boss_shade_of_aran : public BossAI
|
||||
{
|
||||
boss_shade_of_aran(Creature* creature) : BossAI(creature, DATA_ARAN)
|
||||
@@ -103,22 +101,11 @@ struct boss_shade_of_aran : public BossAI
|
||||
});
|
||||
}
|
||||
|
||||
uint8 LastSuperSpell;
|
||||
|
||||
ObjectGuid FlameWreathTarget[3];
|
||||
float FWTargPosX[3];
|
||||
float FWTargPosY[3];
|
||||
|
||||
uint32 CurrentNormalSpell;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
_drinkScheduler.CancelAll();
|
||||
LastSuperSpell = rand() % 3;
|
||||
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
FlameWreathTarget[i].Clear();
|
||||
_lastSuperSpell = rand() % 3;
|
||||
|
||||
CurrentNormalSpell = 0;
|
||||
|
||||
@@ -127,9 +114,7 @@ struct boss_shade_of_aran : public BossAI
|
||||
_frostCooledDown = true;
|
||||
|
||||
_drinking = false;
|
||||
|
||||
// Not in progress
|
||||
instance->SetData(DATA_ARAN, NOT_STARTED);
|
||||
_hasDrunk = false;
|
||||
|
||||
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
|
||||
{
|
||||
@@ -198,8 +183,7 @@ struct boss_shade_of_aran : public BossAI
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->SetData(DATA_ARAN, DONE);
|
||||
_JustDied();
|
||||
|
||||
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
|
||||
{
|
||||
@@ -208,14 +192,30 @@ struct boss_shade_of_aran : public BossAI
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* doneBy, uint32& damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask) override
|
||||
{
|
||||
BossAI::DamageTaken(doneBy, damage, damagetype, damageSchoolMask);
|
||||
|
||||
if ((damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE) && _drinking && me->GetReactState() == REACT_PASSIVE)
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_DRINK);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||
_drinkScheduler.CancelGroup(GROUP_DRINKING);
|
||||
_drinkScheduler.Schedule(1s, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_AOE_PYROBLAST, false);
|
||||
_drinking = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
instance->SetData(DATA_ARAN, IN_PROGRESS);
|
||||
|
||||
DoZoneInCombat();
|
||||
|
||||
//handle timed closing door
|
||||
scheduler.Schedule(15s, [this](TaskContext)
|
||||
{
|
||||
@@ -226,11 +226,14 @@ struct boss_shade_of_aran : public BossAI
|
||||
}
|
||||
}).Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
if (!me->IsNonMeleeSpellCast(false) && !_drinking)
|
||||
context.Repeat(2s);
|
||||
|
||||
if (!_drinking)
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
|
||||
if (!target)
|
||||
if (me->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 Spells[3];
|
||||
uint8 AvailableSpells = 0;
|
||||
@@ -252,49 +255,87 @@ struct boss_shade_of_aran : public BossAI
|
||||
++AvailableSpells;
|
||||
}
|
||||
|
||||
// Should drink at 10%, need 10% mana for mass polymorph
|
||||
if (!_hasDrunk && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 13)
|
||||
{
|
||||
_drinking = true;
|
||||
_hasDrunk = true;
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
Talk(SAY_DRINK);
|
||||
DoCastAOE(SPELL_MASS_POLY);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
|
||||
// Start drinking after conjuring drinks
|
||||
_drinkScheduler.Schedule(2s, GROUP_DRINKING, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_CONJURE);
|
||||
}).Schedule(4s, GROUP_DRINKING, [this](TaskContext)
|
||||
{
|
||||
me->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
DoCastSelf(SPELL_DRINK);
|
||||
});
|
||||
|
||||
_drinkScheduler.Schedule(10s, GROUP_DRINKING, [this](TaskContext)
|
||||
{
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||
DoCastSelf(SPELL_AOE_PYROBLAST);
|
||||
_drinkScheduler.CancelGroup(GROUP_DRINKING);
|
||||
_drinking = false;
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//If no available spells wait 1 second and try again
|
||||
if (AvailableSpells)
|
||||
{
|
||||
CurrentNormalSpell = Spells[rand() % AvailableSpells];
|
||||
|
||||
if (!me->CanCastSpell(CurrentNormalSpell))
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(CurrentNormalSpell))
|
||||
{
|
||||
me->SetWalk(false);
|
||||
me->ResumeChasingVictim();
|
||||
}
|
||||
else
|
||||
{
|
||||
DoCast(target, CurrentNormalSpell);
|
||||
if (me->GetVictim())
|
||||
if (int32(me->GetPower(POWER_MANA)) < spellInfo->CalcPowerCost(me, (SpellSchoolMask)spellInfo->SchoolMask))
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), 45.0f);
|
||||
DoCastSelf(SPELL_POTION);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!me->CanCastSpell(CurrentNormalSpell))
|
||||
{
|
||||
me->SetWalk(false);
|
||||
me->ResumeChasingVictim();
|
||||
}
|
||||
else
|
||||
{
|
||||
DoCastRandomTarget(CurrentNormalSpell, 0, 100.0f);
|
||||
if (me->GetVictim())
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), 45.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
context.Repeat(2s);
|
||||
}).Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
if (!_drinking)
|
||||
{
|
||||
switch (urand(0, 1))
|
||||
{
|
||||
case 0:
|
||||
DoCastSelf(SPELL_AOE_CS);
|
||||
break;
|
||||
case 1:
|
||||
DoCastRandomTarget(SPELL_CHAINSOFICE);
|
||||
break;
|
||||
}
|
||||
urand(0, 1) ? DoCastSelf(SPELL_AOE_CS) : DoCastRandomTarget(SPELL_CHAINSOFICE);
|
||||
}
|
||||
context.Repeat(5s, 20s);
|
||||
}).Schedule(35s, [this](TaskContext context)
|
||||
}).Schedule(6s, [this](TaskContext context)
|
||||
{
|
||||
if (!_drinking)
|
||||
{
|
||||
me->ClearProhibitedSpellTimers();
|
||||
|
||||
DoCastSelf(SPELL_BLINK_CENTER, true);
|
||||
|
||||
uint8 Available[2];
|
||||
|
||||
switch (LastSuperSpell)
|
||||
switch (_lastSuperSpell)
|
||||
{
|
||||
case SUPER_AE:
|
||||
Available[0] = SUPER_FLAME;
|
||||
@@ -310,49 +351,21 @@ struct boss_shade_of_aran : public BossAI
|
||||
break;
|
||||
}
|
||||
|
||||
LastSuperSpell = Available[urand(0, 1)];
|
||||
_lastSuperSpell = Available[urand(0, 1)];
|
||||
|
||||
switch (LastSuperSpell)
|
||||
switch (_lastSuperSpell)
|
||||
{
|
||||
case SUPER_AE:
|
||||
Talk(SAY_EXPLOSION);
|
||||
|
||||
DoCastSelf(SPELL_BLINK_CENTER, true);
|
||||
Talk(EMOTE_ARCANE_EXPLOSION);
|
||||
DoCastSelf(SPELL_PLAYERPULL, true);
|
||||
DoCastSelf(SPELL_MASSSLOW, true);
|
||||
DoCastSelf(SPELL_AEXPLOSION, false);
|
||||
break;
|
||||
|
||||
case SUPER_FLAME:
|
||||
Talk(SAY_FLAMEWREATH);
|
||||
|
||||
scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext)
|
||||
{
|
||||
scheduler.CancelGroup(GROUP_FLAMEWREATH);
|
||||
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
|
||||
{
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
{
|
||||
if (!FlameWreathTarget[i])
|
||||
continue;
|
||||
|
||||
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
|
||||
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
|
||||
{
|
||||
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
|
||||
FlameWreathTarget[i].Clear();
|
||||
}
|
||||
}
|
||||
context.Repeat(500ms);
|
||||
});
|
||||
|
||||
FlameWreathTarget[0].Clear();
|
||||
FlameWreathTarget[1].Clear();
|
||||
FlameWreathTarget[2].Clear();
|
||||
|
||||
FlameWreathEffect();
|
||||
DoCastAOE(SPELL_FLAME_WREATH);
|
||||
break;
|
||||
|
||||
case SUPER_BLIZZARD:
|
||||
Talk(SAY_BLIZZARD);
|
||||
DoCastAOE(SPELL_SUMMON_BLIZZARD);
|
||||
@@ -360,51 +373,6 @@ struct boss_shade_of_aran : public BossAI
|
||||
}
|
||||
}
|
||||
context.Repeat(35s, 40s);
|
||||
}).Schedule(1s, [this](TaskContext context){
|
||||
if (me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
|
||||
{
|
||||
_drinking = true;
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
Talk(SAY_DRINK);
|
||||
DoCastSelf(SPELL_MASS_POLY, true);
|
||||
DoCastSelf(SPELL_CONJURE, false);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
DoCastSelf(SPELL_DRINK, true);
|
||||
_currentHealth = me->GetHealth();
|
||||
_drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context)
|
||||
{
|
||||
//check for damage to interrupt
|
||||
if (me->GetHealth() < _currentHealth)
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_DRINK);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||
DoCastSelf(SPELL_POTION, false);
|
||||
DoCastSelf(SPELL_AOE_PYROBLAST, false);
|
||||
_drinkScheduler.CancelGroup(GROUP_DRINKING);
|
||||
_drinking = false;
|
||||
} else
|
||||
{
|
||||
context.Repeat(500ms);
|
||||
}
|
||||
}).Schedule(10s, GROUP_DRINKING, [this](TaskContext)
|
||||
{
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||
DoCastSelf(SPELL_POTION, true);
|
||||
DoCastSelf(SPELL_AOE_PYROBLAST, false);
|
||||
_drinkScheduler.CancelGroup(GROUP_DRINKING);
|
||||
_drinking = false;
|
||||
});
|
||||
context.Repeat(12s); //semi-arbitrary duration to envelop drinking duration
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Repeat(1s);
|
||||
}
|
||||
}).Schedule(12min, [this](TaskContext context)
|
||||
{
|
||||
for (uint32 i = 0; i < 5; ++i)
|
||||
@@ -422,41 +390,6 @@ struct boss_shade_of_aran : public BossAI
|
||||
});
|
||||
}
|
||||
|
||||
void FlameWreathEffect()
|
||||
{
|
||||
std::vector<Unit*> targets;
|
||||
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
|
||||
|
||||
if (t_list.empty())
|
||||
return;
|
||||
|
||||
//store the threat list in a different container
|
||||
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
|
||||
{
|
||||
Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
|
||||
//only on alive players
|
||||
if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
|
||||
targets.push_back(target);
|
||||
}
|
||||
|
||||
//cut down to size if we have more than 3 targets
|
||||
while (targets.size() > 3)
|
||||
targets.erase(targets.begin() + rand() % targets.size());
|
||||
|
||||
uint32 i = 0;
|
||||
for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
|
||||
{
|
||||
if (*itr)
|
||||
{
|
||||
FlameWreathTarget[i] = (*itr)->GetGUID();
|
||||
FWTargPosX[i] = (*itr)->GetPositionX();
|
||||
FWTargPosY[i] = (*itr)->GetPositionY();
|
||||
DoCast((*itr), SPELL_FLAME_WREATH, true);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
@@ -483,9 +416,6 @@ struct boss_shade_of_aran : public BossAI
|
||||
Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCast(false))
|
||||
return;
|
||||
|
||||
//Interrupt effect
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
|
||||
//Normally we would set the cooldown equal to the spell duration
|
||||
//but we do not have access to the DurationStore
|
||||
|
||||
@@ -505,14 +435,95 @@ struct boss_shade_of_aran : public BossAI
|
||||
private:
|
||||
TaskScheduler _drinkScheduler;
|
||||
|
||||
uint32 _lastSuperSpell;
|
||||
|
||||
uint32 CurrentNormalSpell;
|
||||
|
||||
bool _arcaneCooledDown;
|
||||
bool _fireCooledDown;
|
||||
bool _frostCooledDown;
|
||||
bool _drinking;
|
||||
uint32 _currentHealth;
|
||||
bool _hasDrunk;
|
||||
};
|
||||
|
||||
// 30004 - Flame Wreath
|
||||
class spell_flamewreath : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_flamewreath);
|
||||
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_FLAME_WREATH_RING });
|
||||
}
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
uint8 maxSize = 3;
|
||||
|
||||
if (targets.size() > maxSize)
|
||||
{
|
||||
Acore::Containers::RandomResize(targets, maxSize);
|
||||
}
|
||||
|
||||
_targets = targets;
|
||||
}
|
||||
|
||||
void HandleFinish()
|
||||
{
|
||||
for (auto const& target : _targets)
|
||||
{
|
||||
if (Unit* targetUnit = target->ToUnit())
|
||||
{
|
||||
GetCaster()->CastSpell(targetUnit, SPELL_FLAME_WREATH_RING, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<WorldObject*> _targets;
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_flamewreath::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
AfterCast += SpellCastFn(spell_flamewreath::HandleFinish);
|
||||
}
|
||||
};
|
||||
|
||||
// 29946 - Flame Wreath (visual effect)
|
||||
class spell_flamewreath_aura : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_flamewreath_aura);
|
||||
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_FLAME_WREATH_RAN_THRU, SPELL_FLAME_WREATH_EXPLOSION });
|
||||
}
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEFAULT && GetDuration())
|
||||
{
|
||||
if (Unit* target = GetTarget())
|
||||
{
|
||||
target->CastSpell(target, SPELL_FLAME_WREATH_RAN_THRU, true);
|
||||
|
||||
target->m_Events.AddEventAtOffset([target] {
|
||||
target->RemoveAurasDueToSpell(SPELL_FLAME_WREATH_RAN_THRU);
|
||||
target->CastSpell(target, SPELL_FLAME_WREATH_EXPLOSION, true);
|
||||
}, 1s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_flamewreath_aura::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_shade_of_aran()
|
||||
{
|
||||
RegisterKarazhanCreatureAI(boss_shade_of_aran);
|
||||
RegisterSpellScript(spell_flamewreath);
|
||||
RegisterSpellScript(spell_flamewreath_aura);
|
||||
}
|
||||
|
||||
@@ -231,20 +231,12 @@ struct boss_dorothee : public ScriptedAI
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override
|
||||
{
|
||||
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
return;
|
||||
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
return;
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
if (creature->GetEntry() == NPC_TITO)
|
||||
{
|
||||
Talk(SAY_DOROTHEE_TITO_DEATH);
|
||||
}
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason reason) override
|
||||
@@ -288,8 +280,6 @@ struct npc_tito : public ScriptedAI
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
void Reset() override { }
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(10s, [this](TaskContext context)
|
||||
@@ -299,18 +289,6 @@ struct npc_tito : public ScriptedAI
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* Dorothee = instance->GetCreature(DATA_DOROTHEE))
|
||||
{
|
||||
if (Dorothee->IsAlive())
|
||||
{
|
||||
Talk(SAY_DOROTHEE_TITO_DEATH, Dorothee);
|
||||
}
|
||||
}
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
@@ -351,17 +329,6 @@ struct boss_roar : public ScriptedAI
|
||||
}
|
||||
}
|
||||
|
||||
void Reset() override { }
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
{
|
||||
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
return;
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason reason) override
|
||||
{
|
||||
ScriptedAI::EnterEvadeMode(reason);
|
||||
@@ -373,14 +340,6 @@ struct boss_roar : public ScriptedAI
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
return;
|
||||
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_ROAR_AGGRO);
|
||||
@@ -458,24 +417,6 @@ struct boss_strawman : public ScriptedAI
|
||||
}
|
||||
}
|
||||
|
||||
void Reset() override { }
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
return;
|
||||
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
return;
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason reason) override
|
||||
{
|
||||
ScriptedAI::EnterEvadeMode(reason);
|
||||
@@ -601,22 +542,6 @@ struct boss_tinhead : public ScriptedAI
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
return;
|
||||
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
|
||||
return;
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason reason) override
|
||||
{
|
||||
ScriptedAI::EnterEvadeMode(reason);
|
||||
@@ -763,6 +688,7 @@ enum RedRidingHood
|
||||
SPELL_LITTLE_RED_RIDING_HOOD = 30768,
|
||||
SPELL_TERRIFYING_HOWL = 30752,
|
||||
SPELL_WIDE_SWIPE = 30761,
|
||||
SPELL_PICNIC_BASKET_SMELL = 30755,
|
||||
|
||||
CREATURE_BIG_BAD_WOLF = 17521,
|
||||
|
||||
@@ -826,16 +752,6 @@ struct boss_bigbadwolf : public ScriptedAI
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
ObjectGuid HoodGUID;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
HoodGUID.Clear();
|
||||
_tempThreat = 0;
|
||||
|
||||
_isChasing = false;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
instance->DoUseDoorOrButton(instance->GetGuidData(DATA_GO_STAGEDOORLEFT));
|
||||
@@ -844,40 +760,14 @@ struct boss_bigbadwolf : public ScriptedAI
|
||||
|
||||
_scheduler.Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
if (!_isChasing)
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
|
||||
{
|
||||
Talk(SAY_WOLF_HOOD);
|
||||
DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true);
|
||||
_tempThreat = DoGetThreat(target);
|
||||
if (_tempThreat)
|
||||
{
|
||||
DoModifyThreatByPercent(target, -100);
|
||||
}
|
||||
HoodGUID = target->GetGUID();
|
||||
me->AddThreat(target, 1000000.0f);
|
||||
_isChasing = true;
|
||||
context.Repeat(20s);
|
||||
}
|
||||
Talk(SAY_WOLF_HOOD);
|
||||
DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true);
|
||||
target->CastSpell(me, SPELL_PICNIC_BASKET_SMELL, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isChasing = false;
|
||||
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, HoodGUID))
|
||||
{
|
||||
HoodGUID.Clear();
|
||||
if (DoGetThreat(target))
|
||||
{
|
||||
DoModifyThreatByPercent(target, -100);
|
||||
}
|
||||
me->AddThreat(target, _tempThreat);
|
||||
_tempThreat = 0;
|
||||
}
|
||||
|
||||
context.Repeat(40s);
|
||||
}
|
||||
context.Repeat(40s);
|
||||
}).Schedule(25s, 35s, [this](TaskContext context)
|
||||
{
|
||||
DoCastAOE(SPELL_TERRIFYING_HOWL);
|
||||
@@ -920,15 +810,10 @@ struct boss_bigbadwolf : public ScriptedAI
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
|
||||
if (_isChasing)
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
bool _isChasing;
|
||||
float _tempThreat;
|
||||
};
|
||||
|
||||
/**********************************************/
|
||||
|
||||
@@ -48,6 +48,12 @@ ObjectData const creatureData[] =
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
ObjectData const gameObjectData[] =
|
||||
{
|
||||
{ GO_SIDE_ENTRANCE_DOOR, DATA_GO_SIDE_ENTRANCE_DOOR },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
class instance_karazhan : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -64,7 +70,7 @@ public:
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
LoadObjectData(creatureData, gameObjectData);
|
||||
|
||||
// 1 - OZ, 2 - HOOD, 3 - RAJ, this never gets altered.
|
||||
OperaEvent = urand(EVENT_OZ, EVENT_RAJ);
|
||||
@@ -300,13 +306,11 @@ public:
|
||||
{
|
||||
HandleGameObject(m_uiStageDoorLeftGUID, true);
|
||||
HandleGameObject(m_uiStageDoorRightGUID, true);
|
||||
if (GameObject* sideEntrance = instance->GetGameObject(m_uiSideEntranceDoor))
|
||||
sideEntrance->RemoveGameObjectFlag(GO_FLAG_LOCKED);
|
||||
instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, 16812, nullptr);
|
||||
}
|
||||
else if (state == FAIL)
|
||||
{
|
||||
HandleGameObject(m_uiStageDoorLeftGUID, false);
|
||||
HandleGameObject(m_uiStageDoorLeftGUID, true);
|
||||
HandleGameObject(m_uiStageDoorRightGUID, false);
|
||||
HandleGameObject(m_uiCurtainGUID, false);
|
||||
DoRespawnCreature(_barnesGUID, true);
|
||||
@@ -372,11 +376,10 @@ public:
|
||||
MastersTerraceDoor[1] = go->GetGUID();
|
||||
break;
|
||||
case GO_SIDE_ENTRANCE_DOOR:
|
||||
m_uiSideEntranceDoor = go->GetGUID();
|
||||
if (GetBossState(DATA_OPERA_PERFORMANCE) == DONE)
|
||||
go->SetGameObjectFlag(GO_FLAG_LOCKED);
|
||||
else
|
||||
go->RemoveGameObjectFlag(GO_FLAG_LOCKED);
|
||||
else
|
||||
go->SetGameObjectFlag(GO_FLAG_LOCKED);
|
||||
break;
|
||||
case GO_DUST_COVERED_CHEST:
|
||||
DustCoveredChest = go->GetGUID();
|
||||
@@ -477,8 +480,6 @@ public:
|
||||
return m_uiLibraryDoor;
|
||||
case DATA_GO_MASSIVE_DOOR:
|
||||
return m_uiMassiveDoor;
|
||||
case DATA_GO_SIDE_ENTRANCE_DOOR:
|
||||
return m_uiSideEntranceDoor;
|
||||
case DATA_GO_GAME_DOOR:
|
||||
return m_uiGamesmansDoor;
|
||||
case DATA_GO_GAME_EXIT_DOOR:
|
||||
@@ -519,7 +520,6 @@ public:
|
||||
ObjectGuid m_uiNightBaneGUID;
|
||||
ObjectGuid m_uiLibraryDoor; // Door at Shade of Aran
|
||||
ObjectGuid m_uiMassiveDoor; // Door at Netherspite
|
||||
ObjectGuid m_uiSideEntranceDoor; // Side Entrance
|
||||
ObjectGuid m_uiGamesmansDoor; // Door before Chess
|
||||
ObjectGuid m_uiGamesmansExitDoor; // Door after Chess
|
||||
ObjectGuid m_uiNetherspaceDoor; // Door at Malchezaar
|
||||
|
||||
@@ -135,7 +135,6 @@ public:
|
||||
{
|
||||
npc_barnesAI(Creature* creature) : npc_escortAI(creature)
|
||||
{
|
||||
RaidWiped = false;
|
||||
m_uiEventId = 0;
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
@@ -146,11 +145,9 @@ public:
|
||||
|
||||
uint32 TalkCount;
|
||||
uint32 TalkTimer;
|
||||
uint32 WipeTimer;
|
||||
uint32 m_uiEventId;
|
||||
|
||||
bool PerformanceReady;
|
||||
bool RaidWiped;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
@@ -158,7 +155,6 @@ public:
|
||||
|
||||
TalkCount = 0;
|
||||
TalkTimer = 2000;
|
||||
WipeTimer = 5000;
|
||||
|
||||
PerformanceReady = false;
|
||||
|
||||
@@ -183,8 +179,8 @@ public:
|
||||
switch (waypointId)
|
||||
{
|
||||
case 0:
|
||||
DoCast(me, SPELL_TUXEDO, false);
|
||||
instance->DoUseDoorOrButton(instance->GetGuidData(DATA_GO_STAGEDOORLEFT));
|
||||
DoCastSelf(SPELL_TUXEDO);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true);
|
||||
break;
|
||||
case 4:
|
||||
TalkCount = 0;
|
||||
@@ -276,8 +272,6 @@ public:
|
||||
creature->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
}
|
||||
|
||||
RaidWiped = false;
|
||||
|
||||
instance->SetData(DATA_SPAWN_OPERA_DECORATIONS, m_uiEventId);
|
||||
}
|
||||
|
||||
@@ -303,43 +297,6 @@ public:
|
||||
}
|
||||
else TalkTimer -= diff;
|
||||
}
|
||||
|
||||
if (PerformanceReady)
|
||||
{
|
||||
if (!RaidWiped)
|
||||
{
|
||||
if (WipeTimer <= diff)
|
||||
{
|
||||
Map* map = me->GetMap();
|
||||
if (!map->IsDungeon())
|
||||
return;
|
||||
|
||||
Map::PlayerList const& PlayerList = map->GetPlayers();
|
||||
if (PlayerList.IsEmpty())
|
||||
return;
|
||||
|
||||
RaidWiped = true;
|
||||
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
|
||||
{
|
||||
if (i->GetSource()->IsAlive() && !i->GetSource()->IsGameMaster())
|
||||
{
|
||||
RaidWiped = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (RaidWiped)
|
||||
{
|
||||
RaidWiped = true;
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
|
||||
WipeTimer = 15000;
|
||||
}
|
||||
else WipeTimer -= diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -391,15 +348,16 @@ public:
|
||||
AddGossipItemFor(player, GOSSIP_ICON_DOT, OZ_GM_GOSSIP3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5);
|
||||
}
|
||||
|
||||
if (npc_barnesAI* pBarnesAI = CAST_AI(npc_barnes::npc_barnesAI, creature->AI()))
|
||||
if (instance->GetBossState(DATA_OPERA_PERFORMANCE) != FAIL)
|
||||
{
|
||||
if (!pBarnesAI->RaidWiped)
|
||||
SendGossipMenuFor(player, BARNES_TEXT_IS_READY, creature->GetGUID());
|
||||
else
|
||||
SendGossipMenuFor(player, BARNES_TEXT_WIPED, creature->GetGUID());
|
||||
|
||||
return true;
|
||||
SendGossipMenuFor(player, BARNES_TEXT_IS_READY, creature->GetGUID());
|
||||
}
|
||||
else
|
||||
{
|
||||
SendGossipMenuFor(player, BARNES_TEXT_WIPED, creature->GetGUID());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,8 +562,32 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
class at_karazhan_side_entrance : public OnlyOnceAreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_karazhan_side_entrance() : OnlyOnceAreaTriggerScript("at_karazhan_side_entrance") { }
|
||||
|
||||
bool _OnTrigger(Player* player, AreaTrigger const* /*at*/) override
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
if (instance->GetBossState(DATA_OPERA_PERFORMANCE) == DONE)
|
||||
{
|
||||
if (GameObject* door = instance->GetGameObject(DATA_GO_SIDE_ENTRANCE_DOOR))
|
||||
{
|
||||
instance->HandleGameObject(ObjectGuid::Empty, true, door);
|
||||
door->RemoveGameObjectFlag(GO_FLAG_LOCKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_karazhan()
|
||||
{
|
||||
new npc_barnes();
|
||||
new npc_image_of_medivh();
|
||||
new at_karazhan_side_entrance();
|
||||
}
|
||||
|
||||
@@ -203,52 +203,6 @@ enum ScarletMonasteryTrashMisc
|
||||
SPELL_FORGIVENESS = 28697,
|
||||
};
|
||||
|
||||
class npc_scarlet_guard : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_scarlet_guard() : CreatureScript("npc_scarlet_guard") { }
|
||||
|
||||
struct npc_scarlet_guardAI : public SmartAI
|
||||
{
|
||||
npc_scarlet_guardAI(Creature* creature) : SmartAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
SayAshbringer = false;
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (who && who->GetDistance2d(me) < 12.0f)
|
||||
{
|
||||
if (Player* player = who->ToPlayer())
|
||||
{
|
||||
if (player->HasAura(AURA_ASHBRINGER) && !SayAshbringer)
|
||||
{
|
||||
Talk(SAY_WELCOME);
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
me->SetSheath(SHEATH_STATE_UNARMED);
|
||||
me->SetFacingToObject(player);
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
me->AddAura(SPELL_AURA_MOD_ROOT, me);
|
||||
me->CastSpell(me, SPELL_AURA_MOD_ROOT, true);
|
||||
SayAshbringer = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmartAI::MoveInLineOfSight(who);
|
||||
}
|
||||
private:
|
||||
bool SayAshbringer = false;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetScarletMonasteryAI<npc_scarlet_guardAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
enum MograineEvents
|
||||
{
|
||||
EVENT_SPELL_CRUSADER_STRIKE = 1,
|
||||
@@ -733,7 +687,6 @@ public:
|
||||
void AddSC_instance_scarlet_monastery()
|
||||
{
|
||||
new instance_scarlet_monastery();
|
||||
new npc_scarlet_guard();
|
||||
new npc_fairbanks();
|
||||
new npc_mograine();
|
||||
new boss_high_inquisitor_whitemane();
|
||||
|
||||
@@ -289,9 +289,6 @@ public:
|
||||
ResetTimer = 5000;
|
||||
|
||||
SpawnAdds();
|
||||
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, 46916);
|
||||
me->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
|
||||
@@ -1367,13 +1367,15 @@ enum BrewfestRevelerEnum
|
||||
FACTION_ALLIANCE = 1934,
|
||||
FACTION_HORDE = 1935,
|
||||
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE = 44003,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_FEMALE = 44004,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_BE = 43907,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_ORC = 43914,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_TAUREN = 43915,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_TROLL = 43916,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_UNDEAD = 43917
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE = 44003,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_FEMALE = 44004,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_BE = 43907,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_ORC = 43914,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_TAUREN = 43915,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_TROLL = 43916,
|
||||
SPELL_BREWFEST_REVELER_TRANSFORM_UNDEAD = 43917,
|
||||
|
||||
SPELL_DRUNKEN_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE = 44096
|
||||
};
|
||||
|
||||
class spell_brewfest_reveler_transform : public AuraScript
|
||||
@@ -1394,6 +1396,7 @@ class spell_brewfest_reveler_transform : public AuraScript
|
||||
break;
|
||||
case SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE:
|
||||
case SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_FEMALE:
|
||||
case SPELL_DRUNKEN_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE:
|
||||
factionId = FACTION_FRIENDLY;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Spell.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellScript.h"
|
||||
#include <random>
|
||||
|
||||
enum eBonfire
|
||||
{
|
||||
@@ -46,6 +47,19 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum torchToss
|
||||
{
|
||||
GO_TORCH_TARGET_BRAZIER = 187708,
|
||||
NPC_TORCH_TOSS_TARGET_BUNNY = 25535,
|
||||
|
||||
SPELL_TARGET_INDICATOR_RANK_1 = 43313,
|
||||
SPELL_TORCH_TOSS_LAND = 46054,
|
||||
SPELL_BRAZIERS_HIT_VISUAL = 45724,
|
||||
SPELL_TORCH_TOSS_SUCCESS_A = 45719,
|
||||
SPELL_TORCH_TOSS_SUCCESS_H = 46651,
|
||||
SPELL_TORCH_TOSS_TRAINING = 45716,
|
||||
};
|
||||
|
||||
struct npc_midsummer_torch_target : public ScriptedAI
|
||||
{
|
||||
npc_midsummer_torch_target(Creature* creature) : ScriptedAI(creature)
|
||||
@@ -54,7 +68,7 @@ struct npc_midsummer_torch_target : public ScriptedAI
|
||||
startTimer = 1;
|
||||
posVec.clear();
|
||||
playerGUID.Clear();
|
||||
me->CastSpell(me, 43313, true);
|
||||
me->CastSpell(me, SPELL_TARGET_INDICATOR_RANK_1, true);
|
||||
counter = 0;
|
||||
maxCount = 0;
|
||||
}
|
||||
@@ -82,12 +96,12 @@ struct npc_midsummer_torch_target : public ScriptedAI
|
||||
if (posVec.empty())
|
||||
return;
|
||||
// Triggered spell from torch
|
||||
if (spellInfo->Id == 46054 && caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if (spellInfo->Id == SPELL_TORCH_TOSS_LAND && caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
me->CastSpell(me, 45724, true); // hit visual anim
|
||||
me->CastSpell(me, SPELL_BRAZIERS_HIT_VISUAL, true); // hit visual anim
|
||||
if (++counter >= maxCount)
|
||||
{
|
||||
caster->CastSpell(caster, (caster->ToPlayer()->GetTeamId() ? 46651 : 45719), true); // quest complete spell
|
||||
caster->CastSpell(caster, (caster->ToPlayer()->GetTeamId() ? SPELL_TORCH_TOSS_SUCCESS_H : SPELL_TORCH_TOSS_SUCCESS_A), true); // quest complete spell
|
||||
me->DespawnOrUnsummon(1);
|
||||
return;
|
||||
}
|
||||
@@ -129,7 +143,7 @@ struct npc_midsummer_torch_target : public ScriptedAI
|
||||
void FillPositions()
|
||||
{
|
||||
std::list<GameObject*> gobjList;
|
||||
me->GetGameObjectListWithEntryInGrid(gobjList, 187708 /*TORCH_GO*/, 30.0f);
|
||||
me->GetGameObjectListWithEntryInGrid(gobjList, GO_TORCH_TARGET_BRAZIER, 30.0f);
|
||||
for (std::list<GameObject*>::const_iterator itr = gobjList.begin(); itr != gobjList.end(); ++itr)
|
||||
{
|
||||
Position pos;
|
||||
@@ -145,8 +159,6 @@ struct npc_midsummer_torch_target : public ScriptedAI
|
||||
int8 num = urand(0, posVec.size() - 1);
|
||||
Position pos;
|
||||
pos.Relocate(posVec.at(num));
|
||||
me->m_last_notify_position.Relocate(0.0f, 0.0f, 0.0f);
|
||||
me->m_last_notify_mstime = GameTime::GetGameTimeMS().count() + 10000;
|
||||
|
||||
me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
|
||||
}
|
||||
@@ -169,7 +181,7 @@ class spell_gen_crab_disguise : public AuraScript
|
||||
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_CRAB_DISGUISE });
|
||||
return ValidateSpellInfo({ SPELL_APPLY_DIGUISE, SPELL_FADE_DIGUISE });
|
||||
}
|
||||
|
||||
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
@@ -199,17 +211,293 @@ class spell_gen_crab_disguise : public AuraScript
|
||||
|
||||
enum RibbonPole
|
||||
{
|
||||
GO_RIBBON_POLE = 181605,
|
||||
|
||||
SPELL_RIBBON_POLE_CHANNEL_VISUAL = 29172,
|
||||
SPELL_RIBBON_POLE_CHANNEL_VISUAL_2 = 29531,
|
||||
SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE = 29705,
|
||||
SPELL_TEST_RIBBON_POLE_CHANNEL_RED = 29726,
|
||||
SPELL_TEST_RIBBON_POLE_CHANNEL_PINK = 29727,
|
||||
// player spinning/rorating around himself
|
||||
SPELL_RIBBON_POLE_PERIODIC_VISUAL = 45406,
|
||||
// spew lava trails
|
||||
SPELL_RIBBON_POLE_FIRE_SPIRAL_VISUAL= 45421,
|
||||
// blue fire ring, duration 5s
|
||||
SPELL_FLAME_RING = 46842,
|
||||
// red fire ring, duration 5s
|
||||
SPELL_FLAME_PATCH = 46836,
|
||||
// single firework explosion
|
||||
SPELL_RIBBON_POLE_FIREWORK = 46847,
|
||||
SPELL_RIBBON_POLE_GROUND_FLOWER = 46969,
|
||||
SPELL_RIBBON_POLE_XP = 29175,
|
||||
SPELL_RIBBON_POLE_FIREWORKS = 46971,
|
||||
|
||||
NPC_RIBBON_POLE_DEBUG_TARGET = 17066,
|
||||
NPC_GROUND_FLOWER = 25518,
|
||||
NPC_BIG_DANCING_FLAMES = 26267,
|
||||
NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY = 25303,
|
||||
|
||||
// dancing players count
|
||||
THRESHOLD_FLAME_CIRCLE = 1,
|
||||
THRESHOLD_FIREWORK = 2,
|
||||
THRESHOLD_FIREWORK_3 = 3,
|
||||
THRESHOLD_FIREWORK_5 = 5,
|
||||
THRESHOLD_GROUND_FLOWERS = 3,
|
||||
THRESHOLD_SPEW_LAVA = 6,
|
||||
THRESHOLD_DANCING_FLAMES = 7,
|
||||
|
||||
MAX_COUNT_GROUND_FLOWERS = 3,
|
||||
MAX_COUNT_SPEW_LAVA_TARGETS = 2,
|
||||
MAX_COUNT_DANCING_FLAMES = 4,
|
||||
};
|
||||
|
||||
struct npc_midsummer_ribbon_pole_target : public ScriptedAI
|
||||
{
|
||||
npc_midsummer_ribbon_pole_target(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
// ribbonPole trap also spawns this NPC (currently unwanted)
|
||||
if (me->ToTempSummon())
|
||||
me->DespawnOrUnsummon();
|
||||
|
||||
_ribbonPole = nullptr;
|
||||
_bunny = nullptr;
|
||||
_dancerList.clear();
|
||||
|
||||
LocateRibbonPole();
|
||||
SpawnFireSpiralBunny();
|
||||
|
||||
_scheduler.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
DoCleanupChecks();
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
DoFlameCircleChecks();
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(15s, [this](TaskContext context)
|
||||
{
|
||||
DoFireworkChecks();
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(10s, [this](TaskContext context)
|
||||
{
|
||||
DoGroundFlowerChecks();
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(10s, [this](TaskContext context)
|
||||
{
|
||||
DoSpewLavaChecks();
|
||||
context.Repeat();
|
||||
})
|
||||
.Schedule(15s, [this](TaskContext context)
|
||||
{
|
||||
DoDancingFLameChecks();
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
void SpellHit(Unit* caster, SpellInfo const* spell) override
|
||||
{
|
||||
Player* dancer = caster->ToPlayer();
|
||||
if (!dancer)
|
||||
return;
|
||||
|
||||
switch (spell->Id)
|
||||
{
|
||||
case SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE:
|
||||
case SPELL_TEST_RIBBON_POLE_CHANNEL_RED:
|
||||
case SPELL_TEST_RIBBON_POLE_CHANNEL_PINK:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent duplicates
|
||||
if (std::find(_dancerList.begin(), _dancerList.end(), dancer) != _dancerList.end())
|
||||
return;
|
||||
|
||||
_dancerList.push_back(dancer);
|
||||
}
|
||||
|
||||
void LocateRibbonPole()
|
||||
{
|
||||
_scheduler.Schedule(420ms, [this](TaskContext context)
|
||||
{
|
||||
_ribbonPole = me->FindNearestGameObject(GO_RIBBON_POLE, 10.0f);
|
||||
|
||||
if (!_ribbonPole)
|
||||
context.Repeat(420ms);
|
||||
});
|
||||
}
|
||||
|
||||
void SpawnFireSpiralBunny()
|
||||
{
|
||||
_bunny = me->FindNearestCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, 10.0f);
|
||||
|
||||
if (!_bunny)
|
||||
_bunny = DoSpawnCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, 0, 0, 0, 0, TEMPSUMMON_MANUAL_DESPAWN, 0);
|
||||
}
|
||||
|
||||
void DoCleanupChecks()
|
||||
{
|
||||
if (_dancerList.empty())
|
||||
return;
|
||||
|
||||
// remove non-dancing players from list
|
||||
std::erase_if(_dancerList, [](Player* dancer)
|
||||
{
|
||||
return !dancer->HasAura(SPELL_RIBBON_POLE_PERIODIC_VISUAL);
|
||||
});
|
||||
}
|
||||
|
||||
void DoFlameCircleChecks()
|
||||
{
|
||||
if (!_ribbonPole)
|
||||
return;
|
||||
if (_dancerList.size() >= THRESHOLD_FLAME_CIRCLE)
|
||||
{
|
||||
// random blue / red circle
|
||||
if (urand(0, 1))
|
||||
_ribbonPole->CastSpell(me, SPELL_FLAME_RING);
|
||||
else
|
||||
_ribbonPole->CastSpell(me, SPELL_FLAME_PATCH);
|
||||
}
|
||||
}
|
||||
|
||||
void DoFireworkChecks()
|
||||
{
|
||||
if (!_bunny)
|
||||
return;
|
||||
|
||||
if (_dancerList.size() >= THRESHOLD_FIREWORK)
|
||||
{
|
||||
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
|
||||
}
|
||||
if (_dancerList.size() >= THRESHOLD_FIREWORK_3)
|
||||
{
|
||||
_scheduler.Schedule(500ms, [this](TaskContext /*context*/)
|
||||
{
|
||||
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
|
||||
})
|
||||
.Schedule(1s, [this](TaskContext /*context*/)
|
||||
{
|
||||
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
|
||||
});
|
||||
}
|
||||
if (_dancerList.size() >= THRESHOLD_FIREWORK_5)
|
||||
{
|
||||
_scheduler.Schedule(1500ms, [this](TaskContext /*context*/)
|
||||
{
|
||||
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
|
||||
})
|
||||
.Schedule(2s, [this](TaskContext /*context*/)
|
||||
{
|
||||
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DoGroundFlowerChecks()
|
||||
{
|
||||
if (!_bunny)
|
||||
return;
|
||||
|
||||
if (_dancerList.size() >= THRESHOLD_GROUND_FLOWERS)
|
||||
{
|
||||
std::list<Creature*> crList;
|
||||
me->GetCreaturesWithEntryInRange(crList, 20.0f, NPC_GROUND_FLOWER);
|
||||
|
||||
if (crList.size() < MAX_COUNT_GROUND_FLOWERS)
|
||||
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_GROUND_FLOWER);
|
||||
}
|
||||
}
|
||||
|
||||
void DoSpewLavaChecks()
|
||||
{
|
||||
if (!_bunny)
|
||||
return;
|
||||
|
||||
if (_dancerList.size() >= THRESHOLD_SPEW_LAVA)
|
||||
{
|
||||
if (!_dancerList.empty())
|
||||
{
|
||||
Acore::Containers::RandomShuffle(_dancerList);
|
||||
|
||||
for (uint8 i = 0; (i < MAX_COUNT_SPEW_LAVA_TARGETS) && (i < _dancerList.size()); i++)
|
||||
{
|
||||
Player* dancerTarget = _dancerList[i];
|
||||
|
||||
if (dancerTarget)
|
||||
{
|
||||
Creature* fireSpiralBunny = dancerTarget->SummonCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, dancerTarget->GetPositionX(), dancerTarget->GetPositionY(), dancerTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
|
||||
if (fireSpiralBunny)
|
||||
fireSpiralBunny->CastSpell(_bunny, SPELL_RIBBON_POLE_FIRE_SPIRAL_VISUAL, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoDancingFLameChecks()
|
||||
{
|
||||
if (_dancerList.size() >= THRESHOLD_DANCING_FLAMES)
|
||||
{
|
||||
std::list<Creature*> crList;
|
||||
me->GetCreaturesWithEntryInRange(crList, 20.0f, NPC_BIG_DANCING_FLAMES);
|
||||
|
||||
if (crList.size() < MAX_COUNT_DANCING_FLAMES)
|
||||
{
|
||||
float spawnDist = 12.0f;
|
||||
float angle = rand_norm() * 2 * M_PI;
|
||||
DoSpawnCreature(NPC_BIG_DANCING_FLAMES, spawnDist * cos(angle), spawnDist * std::sin(angle), 0, angle + M_PI, TEMPSUMMON_TIMED_DESPAWN, 60000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
std::vector<Player*> _dancerList;
|
||||
GameObject* _ribbonPole;
|
||||
Creature* _bunny;
|
||||
};
|
||||
|
||||
class spell_midsummer_ribbon_pole_firework : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_midsummer_ribbon_pole_firework)
|
||||
|
||||
void ModDestHeight(SpellDestination& dest)
|
||||
{
|
||||
Position const offset = { 0.0f, 0.0f, 20.0f , 0.0f };
|
||||
dest.RelocateOffset(offset);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_midsummer_ribbon_pole_firework::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_RANDOM);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_midsummer_ribbon_pole : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_midsummer_ribbon_pole)
|
||||
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
return ValidateSpellInfo(
|
||||
{
|
||||
SPELL_RIBBON_POLE_XP,
|
||||
SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE,
|
||||
SPELL_TEST_RIBBON_POLE_CHANNEL_RED,
|
||||
SPELL_TEST_RIBBON_POLE_CHANNEL_PINK
|
||||
});
|
||||
}
|
||||
|
||||
void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
@@ -218,7 +506,9 @@ class spell_midsummer_ribbon_pole : public AuraScript
|
||||
Creature* cr = target->FindNearestCreature(NPC_RIBBON_POLE_DEBUG_TARGET, 10.0f);
|
||||
if (!cr)
|
||||
{
|
||||
target->RemoveAura(SPELL_RIBBON_POLE_CHANNEL_VISUAL);
|
||||
target->RemoveAura(SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE);
|
||||
target->RemoveAura(SPELL_TEST_RIBBON_POLE_CHANNEL_RED);
|
||||
target->RemoveAura(SPELL_TEST_RIBBON_POLE_CHANNEL_PINK);
|
||||
SetDuration(1);
|
||||
return;
|
||||
}
|
||||
@@ -243,7 +533,19 @@ class spell_midsummer_ribbon_pole : public AuraScript
|
||||
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* ar = GetTarget();
|
||||
ar->CastSpell(ar, SPELL_RIBBON_POLE_CHANNEL_VISUAL, true);
|
||||
switch (urand(0, 2))
|
||||
{
|
||||
case 0:
|
||||
ar->CastSpell(ar, SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE, true);
|
||||
break;
|
||||
case 1:
|
||||
ar->CastSpell(ar, SPELL_TEST_RIBBON_POLE_CHANNEL_RED, true);
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
ar->CastSpell(ar, SPELL_TEST_RIBBON_POLE_CHANNEL_PINK, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
@@ -301,10 +603,10 @@ class spell_midsummer_torch_quest : public AuraScript
|
||||
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* ar = GetTarget();
|
||||
if (Creature* cr = ar->SummonCreature(25535, ar->GetPositionX(), ar->GetPositionY(), ar->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 90000))
|
||||
if (Creature* cr = ar->SummonCreature(NPC_TORCH_TOSS_TARGET_BUNNY, ar->GetPositionX(), ar->GetPositionY(), ar->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 90000))
|
||||
{
|
||||
torchGUID = cr->GetGUID();
|
||||
CAST_AI(npc_midsummer_torch_target, cr->AI())->SetPlayerGUID(ar->GetGUID(), (GetId() == 45716 ? 8 : 20));
|
||||
CAST_AI(npc_midsummer_torch_target, cr->AI())->SetPlayerGUID(ar->GetGUID(), (GetId() == SPELL_TORCH_TOSS_TRAINING ? 8 : 20));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,13 +631,32 @@ enum flingTorch
|
||||
SPELL_FLING_TORCH_DUMMY = 46747,
|
||||
SPELL_MISSED_TORCH = 45676,
|
||||
SPELL_TORCH_COUNTER = 45693,
|
||||
SPELL_TORCH_SHADOW = 46105
|
||||
SPELL_TORCH_SHADOW = 46105,
|
||||
SPELL_TORCH_CATCH_SUCCESS_A = 46081,
|
||||
SPELL_TORCH_CATCH_SUCCESS_H = 46654,
|
||||
SPELL_JUGGLE_TORCH = 45671,
|
||||
|
||||
QUEST_MORE_TORCH_TOSS_A = 11924,
|
||||
QUEST_MORE_TORCH_TOSS_H = 11925,
|
||||
};
|
||||
|
||||
class spell_midsummer_fling_torch : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_midsummer_fling_torch);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo(
|
||||
{
|
||||
SPELL_FLING_TORCH,
|
||||
SPELL_TORCH_SHADOW,
|
||||
SPELL_MISSED_TORCH,
|
||||
SPELL_TORCH_CATCH_SUCCESS_A,
|
||||
SPELL_TORCH_CATCH_SUCCESS_H,
|
||||
SPELL_TORCH_COUNTER
|
||||
});
|
||||
}
|
||||
|
||||
bool handled;
|
||||
bool Load() override { handled = false; return true; }
|
||||
|
||||
@@ -412,13 +733,13 @@ class spell_midsummer_fling_torch : public SpellScript
|
||||
{
|
||||
aur->ModStackAmount(1);
|
||||
uint8 count = 4;
|
||||
if (target->GetQuestStatus(target->GetTeamId() ? 11925 : 11924) == QUEST_STATUS_INCOMPLETE) // More Torch Catching quests
|
||||
if (target->GetQuestStatus(target->GetTeamId() ? QUEST_MORE_TORCH_TOSS_H : QUEST_MORE_TORCH_TOSS_A) == QUEST_STATUS_INCOMPLETE) // More Torch Catching quests
|
||||
count = 10;
|
||||
|
||||
if (aur->GetStackAmount() >= count)
|
||||
{
|
||||
//target->CastSpell(target, 46711, true); // Set Flag: all torch returning quests are complete
|
||||
target->CastSpell(target, (target->GetTeamId() ? 46654 : 46081), true); // Quest completion
|
||||
target->CastSpell(target, (target->GetTeamId() ? SPELL_TORCH_CATCH_SUCCESS_H : SPELL_TORCH_CATCH_SUCCESS_A), true); // Quest completion
|
||||
aur->SetDuration(1);
|
||||
return;
|
||||
}
|
||||
@@ -433,7 +754,7 @@ class spell_midsummer_fling_torch : public SpellScript
|
||||
void Register() override
|
||||
{
|
||||
AfterCast += SpellCastFn(spell_midsummer_fling_torch::HandleFinish);
|
||||
if (m_scriptSpellId == 45671)
|
||||
if (m_scriptSpellId == SPELL_JUGGLE_TORCH)
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_midsummer_fling_torch::CheckCast);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_midsummer_fling_torch::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
@@ -466,6 +787,21 @@ class spell_midsummer_juggling_torch : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_midsummer_juggling_torch);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo(
|
||||
{
|
||||
SPELL_JUGGLE_SELF,
|
||||
SPELL_JUGGLE_SLOW,
|
||||
SPELL_JUGGLE_MED,
|
||||
SPELL_JUGGLE_FAST,
|
||||
SPELL_TORCH_SHADOW_SELF,
|
||||
SPELL_TORCH_SHADOW_SLOW,
|
||||
SPELL_TORCH_SHADOW_MED,
|
||||
SPELL_TORCH_SHADOW_FAST
|
||||
});
|
||||
}
|
||||
|
||||
void HandleFinish()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
@@ -543,9 +879,11 @@ void AddSC_event_midsummer_scripts()
|
||||
// NPCs
|
||||
new go_midsummer_bonfire();
|
||||
RegisterCreatureAI(npc_midsummer_torch_target);
|
||||
RegisterCreatureAI(npc_midsummer_ribbon_pole_target);
|
||||
|
||||
// Spells
|
||||
RegisterSpellScript(spell_gen_crab_disguise);
|
||||
RegisterSpellScript(spell_midsummer_ribbon_pole_firework);
|
||||
RegisterSpellScript(spell_midsummer_ribbon_pole);
|
||||
RegisterSpellScript(spell_midsummer_ribbon_pole_visual);
|
||||
RegisterSpellScript(spell_midsummer_torch_quest);
|
||||
|
||||
@@ -15,99 +15,12 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Dustwallow_Marsh
|
||||
SD%Complete: 95
|
||||
SDComment: Quest support: 11180, 11126, 11174
|
||||
SDCategory: Dustwallow Marsh
|
||||
EndScriptData */
|
||||
|
||||
/* ContentData
|
||||
npc_cassa_crimsonwing - handled by npc_taxi
|
||||
EndContentData */
|
||||
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "SpellScript.h"
|
||||
|
||||
/*######
|
||||
## npc_zelfrax
|
||||
######*/
|
||||
|
||||
Position const MovePosition = {-2967.030f, -3872.1799f, 35.620f, 0.0f};
|
||||
|
||||
enum Zelfrax
|
||||
{
|
||||
SAY_ZELFRAX1 = 0,
|
||||
SAY_ZELFRAX2 = 1
|
||||
};
|
||||
|
||||
class npc_zelfrax : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_zelfrax() : CreatureScript("npc_zelfrax") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_zelfraxAI(creature);
|
||||
}
|
||||
|
||||
struct npc_zelfraxAI : public ScriptedAI
|
||||
{
|
||||
npc_zelfraxAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
MoveToDock();
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
{
|
||||
me->SetInCombatWith(who);
|
||||
who->SetInCombatWith(me);
|
||||
|
||||
if (IsCombatMovementAllowed())
|
||||
me->GetMotionMaster()->MoveChase(who);
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 Type, uint32 /*Id*/) override
|
||||
{
|
||||
if (Type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||
me->SetImmuneToPC(false);
|
||||
SetCombatMovement(true);
|
||||
|
||||
if (me->IsInCombat())
|
||||
if (Unit* unit = me->GetVictim())
|
||||
me->GetMotionMaster()->MoveChase(unit);
|
||||
}
|
||||
|
||||
void MoveToDock()
|
||||
{
|
||||
SetCombatMovement(false);
|
||||
me->GetMotionMaster()->MovePoint(0, MovePosition);
|
||||
Talk(SAY_ZELFRAX1);
|
||||
Talk(SAY_ZELFRAX2);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*Diff*/) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
enum SpellScripts
|
||||
{
|
||||
SPELL_OOZE_ZAP = 42489,
|
||||
@@ -243,7 +156,6 @@ public:
|
||||
|
||||
void AddSC_dustwallow_marsh()
|
||||
{
|
||||
new npc_zelfrax();
|
||||
new spell_ooze_zap();
|
||||
new spell_ooze_zap_channel_end();
|
||||
new spell_energize_aoe();
|
||||
|
||||
@@ -157,7 +157,6 @@ enum ThrallWarchief : uint32
|
||||
QUEST_WHAT_THE_WIND_CARRIES = 6566,
|
||||
GOSSIP_MENU_THRALL = 3664,
|
||||
GOSSIP_RESPONSE_THRALL_FIRST = 5733,
|
||||
GOSSIP_OPTION_DEFAULT = 0
|
||||
};
|
||||
|
||||
const Position heraldOfThrallPos = { -462.404f, -2637.68f, 96.0656f, 5.8606f };
|
||||
@@ -179,7 +178,7 @@ public:
|
||||
uint32 NextAction = GOSSIP_ACTION_INFO_DEF + DiscussionOrder + 1;
|
||||
uint32 GossipResponse = GOSSIP_RESPONSE_THRALL_FIRST + DiscussionOrder - 1;
|
||||
|
||||
AddGossipItemFor(player, GOSSIP_MENU_THRALL + DiscussionOrder, GOSSIP_OPTION_DEFAULT, GOSSIP_SENDER_MAIN, NextAction);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_THRALL + DiscussionOrder, 0, GOSSIP_SENDER_MAIN, NextAction);
|
||||
SendGossipMenuFor(player, GossipResponse, creature->GetGUID());
|
||||
}
|
||||
else if (DiscussionOrder == 7)
|
||||
@@ -200,7 +199,7 @@ public:
|
||||
|
||||
if (player->GetQuestStatus(QUEST_WHAT_THE_WIND_CARRIES) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_MENU_THRALL, GOSSIP_OPTION_DEFAULT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_THRALL, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
}
|
||||
|
||||
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
|
||||
|
||||
@@ -918,7 +918,8 @@ public:
|
||||
player->AddAura(SPELL_WARTS, player);
|
||||
else
|
||||
{
|
||||
DoCast(player, SPELL_FROG_KISS); // Removes SPELL_WARTSBGONE_LIP_BALM
|
||||
// Removes SPELL_WARTSBGONE_LIP_BALM
|
||||
player->CastSpell(player, SPELL_FROG_KISS, true);
|
||||
|
||||
if (me->GetEntry() == NPC_LAKE_FROG)
|
||||
{
|
||||
@@ -1298,6 +1299,30 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// 62536 - Frog Kiss
|
||||
class spell_frog_kiss : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_frog_kiss);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_WARTSBGONE_LIP_BALM });
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Player* target = GetHitPlayer())
|
||||
{
|
||||
target->RemoveAurasDueToSpell(SPELL_WARTSBGONE_LIP_BALM);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_frog_kiss::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_grizzly_hills()
|
||||
{
|
||||
// Theirs
|
||||
@@ -1319,4 +1344,5 @@ void AddSC_grizzly_hills()
|
||||
new spell_warhead_fuse();
|
||||
RegisterSpellScript(spell_q12227_outhouse_groans);
|
||||
RegisterSpellScript(spell_q12227_camera_shake);
|
||||
RegisterSpellScript(spell_frog_kiss);
|
||||
}
|
||||
|
||||
+31
-28
@@ -65,16 +65,13 @@ enum Spells
|
||||
|
||||
enum Misc
|
||||
{
|
||||
MAX_ADVISORS = 3,
|
||||
MAX_ADVISORS = 2,
|
||||
NPC_SEER_OLUM = 22820,
|
||||
GO_CAGE = 185952,
|
||||
};
|
||||
|
||||
const Position advisorsPosition[MAX_ADVISORS + 2] =
|
||||
const Position advisorsPosition[MAX_ADVISORS] =
|
||||
{
|
||||
{459.61f, -534.81f, -7.54f, 3.82f},
|
||||
{463.83f, -540.23f, -7.54f, 3.15f},
|
||||
{459.94f, -547.28f, -7.54f, 2.42f},
|
||||
{448.37f, -544.71f, -7.54f, 0.00f},
|
||||
{457.37f, -544.71f, -7.54f, 0.00f}
|
||||
};
|
||||
@@ -94,21 +91,13 @@ struct boss_fathomlord_karathress : public BossAI
|
||||
BossAI::Reset();
|
||||
_recentlySpoken = false;
|
||||
|
||||
me->SummonCreature(NPC_FATHOM_GUARD_TIDALVESS, advisorsPosition[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 600000);
|
||||
me->SummonCreature(NPC_FATHOM_GUARD_SHARKKIS, advisorsPosition[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 600000);
|
||||
me->SummonCreature(NPC_FATHOM_GUARD_CARIBDIS, advisorsPosition[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 600000);
|
||||
|
||||
ScheduleHealthCheckEvent(75, [&]{
|
||||
for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
|
||||
{
|
||||
if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr))
|
||||
instance->DoForAllMinions(DATA_FATHOM_LORD_KARATHRESS, [&](Creature* fathomguard) {
|
||||
if (fathomguard->IsAlive())
|
||||
{
|
||||
if (summon->GetMaxHealth() > 500000)
|
||||
{
|
||||
summon->CastSpell(me, SPELL_BLESSING_OF_THE_TIDES, true);
|
||||
}
|
||||
fathomguard->CastSpell(me, SPELL_BLESSING_OF_THE_TIDES, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (me->HasAura(SPELL_BLESSING_OF_THE_TIDES))
|
||||
{
|
||||
Talk(SAY_GAIN_BLESSING);
|
||||
@@ -122,19 +111,22 @@ struct boss_fathomlord_karathress : public BossAI
|
||||
if (summon->GetEntry() == NPC_SEER_OLUM)
|
||||
{
|
||||
summon->SetWalk(true);
|
||||
summon->GetMotionMaster()->MovePoint(0, advisorsPosition[MAX_ADVISORS + 1], false);
|
||||
summon->GetMotionMaster()->MovePoint(0, advisorsPosition[MAX_ADVISORS - 1], false);
|
||||
}
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit*) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
if (summon->GetEntry() == NPC_FATHOM_GUARD_TIDALVESS)
|
||||
Talk(SAY_GAIN_ABILITY1);
|
||||
if (summon->GetEntry() == NPC_FATHOM_GUARD_SHARKKIS)
|
||||
Talk(SAY_GAIN_ABILITY2);
|
||||
if (summon->GetEntry() == NPC_FATHOM_GUARD_CARIBDIS)
|
||||
Talk(SAY_GAIN_ABILITY3);
|
||||
scheduler.Schedule(1s, [this, summon](TaskContext)
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
@@ -154,7 +146,7 @@ struct boss_fathomlord_karathress : public BossAI
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
me->SummonCreature(NPC_SEER_OLUM, advisorsPosition[MAX_ADVISORS], TEMPSUMMON_TIMED_DESPAWN, 3600000);
|
||||
me->SummonCreature(NPC_SEER_OLUM, advisorsPosition[MAX_ADVISORS-2], TEMPSUMMON_TIMED_DESPAWN, 3600000);
|
||||
if (GameObject* gobject = me->FindNearestGameObject(GO_CAGE, 100.0f))
|
||||
{
|
||||
gobject->SetGoState(GO_STATE_ACTIVE);
|
||||
@@ -207,8 +199,6 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
|
||||
{
|
||||
boss_fathomguard_sharkkis(Creature* creature) : ScriptedAI(creature), summons(creature)
|
||||
{
|
||||
summons.clear();
|
||||
|
||||
_instance = creature->GetInstanceScript();
|
||||
|
||||
_scheduler.SetValidator([this]
|
||||
@@ -224,6 +214,7 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
|
||||
_scheduler.CancelAll();
|
||||
|
||||
summons.DespawnAll();
|
||||
summons.clear();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
@@ -232,8 +223,12 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
|
||||
{
|
||||
karathress->Attack(who, false);
|
||||
}
|
||||
_scheduler.Schedule(2500ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_HURL_TRIDENT);
|
||||
@@ -268,7 +263,7 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
|
||||
{
|
||||
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
|
||||
{
|
||||
me->CastSpell(karathress, SPELL_POWER_OF_SHARKKIS);
|
||||
me->CastSpell(karathress, SPELL_POWER_OF_SHARKKIS, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,8 +411,12 @@ struct boss_fathomguard_tidalvess : public ScriptedAI
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
|
||||
{
|
||||
karathress->Attack(who, false);
|
||||
}
|
||||
_scheduler.Schedule(10900ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_FROST_SHOCK);
|
||||
@@ -439,7 +438,7 @@ struct boss_fathomguard_tidalvess : public ScriptedAI
|
||||
{
|
||||
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
|
||||
{
|
||||
me->CastSpell(karathress, SPELL_POWER_OF_TIDALVESS);
|
||||
me->CastSpell(karathress, SPELL_POWER_OF_TIDALVESS, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,8 +488,12 @@ struct boss_fathomguard_caribdis : public ScriptedAI
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
|
||||
{
|
||||
karathress->Attack(who, false);
|
||||
}
|
||||
_scheduler.Schedule(27900ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_WATER_BOLT_VOLLEY);
|
||||
@@ -517,7 +520,7 @@ struct boss_fathomguard_caribdis : public ScriptedAI
|
||||
{
|
||||
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
|
||||
{
|
||||
me->CastSpell(karathress, SPELL_POWER_OF_CARIBDIS);
|
||||
me->CastSpell(karathress, SPELL_POWER_OF_CARIBDIS, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+210
-251
@@ -19,6 +19,7 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "serpent_shrine.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
enum Talk
|
||||
{
|
||||
@@ -59,18 +60,12 @@ enum Misc
|
||||
|
||||
NPC_GREYHEART_SPELLBINDER = 21806,
|
||||
NPC_SHADOW_OF_LEOTHERAS = 21875,
|
||||
};
|
||||
|
||||
EVENT_SPELL_BERSERK = 1,
|
||||
EVENT_HEALTH_CHECK = 2,
|
||||
EVENT_SWITCH_TO_DEMON = 3,
|
||||
EVENT_SPELL_WHIRLWIND = 4,
|
||||
EVENT_KILL_TALK = 5,
|
||||
EVENT_SWITCH_TO_ELF = 6,
|
||||
EVENT_SPELL_INSIDIOUS_WHISPER = 7,
|
||||
EVENT_SUMMON_DEMON = 8,
|
||||
EVENT_RESTORE_FIGHT = 9,
|
||||
|
||||
EVENT_SPELL_SHADOW_BOLT = 20
|
||||
enum Groups
|
||||
{
|
||||
GROUP_COMBAT = 1,
|
||||
GROUP_DEMON = 2
|
||||
};
|
||||
|
||||
const Position channelersPos[MAX_CHANNELERS] =
|
||||
@@ -80,267 +75,231 @@ const Position channelersPos[MAX_CHANNELERS] =
|
||||
{362.11f, -437.48f, 29.52f, 0.9f}
|
||||
};
|
||||
|
||||
class boss_leotheras_the_blind : public CreatureScript
|
||||
struct boss_leotheras_the_blind : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_leotheras_the_blind() : CreatureScript("boss_leotheras_the_blind") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_leotheras_the_blind(Creature* creature) : BossAI(creature, DATA_LEOTHERAS_THE_BLIND)
|
||||
{
|
||||
return GetSerpentShrineAI<boss_leotheras_the_blindAI>(creature);
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_leotheras_the_blindAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_leotheras_the_blindAI(Creature* creature) : BossAI(creature, DATA_LEOTHERAS_THE_BLIND)
|
||||
{
|
||||
}
|
||||
BossAI::Reset();
|
||||
DoCastSelf(SPELL_CLEAR_CONSUMING_MADNESS, true);
|
||||
DoCastSelf(SPELL_DUAL_WIELD, true);
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
me->LoadEquipment(0, true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
_recentlySpoken = false;
|
||||
SummonChannelers();
|
||||
|
||||
ScheduleHealthCheckEvent(15, [&]{
|
||||
if (me->GetDisplayId() != me->GetNativeDisplayId())
|
||||
{
|
||||
//is currently in metamorphosis
|
||||
DoResetThreatList();
|
||||
me->LoadEquipment();
|
||||
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
|
||||
|
||||
scheduler.RescheduleGroup(GROUP_COMBAT, 10s);
|
||||
}
|
||||
scheduler.CancelGroup(GROUP_DEMON);
|
||||
scheduler.DelayAll(10s);
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->CastSpell(me, SPELL_CLEAR_CONSUMING_MADNESS, true);
|
||||
me->CastSpell(me, SPELL_DUAL_WIELD, true);
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
me->LoadEquipment(0, true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->StopMoving();
|
||||
Talk(SAY_FINAL_FORM);
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
BossAI::InitializeAI();
|
||||
SummonChannelers();
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
{
|
||||
BossAI::JustReachedHome();
|
||||
SummonChannelers();
|
||||
}
|
||||
|
||||
void SummonChannelers()
|
||||
{
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, false);
|
||||
me->CastSpell(me, SPELL_BANISH, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true);
|
||||
|
||||
summons.DespawnAll();
|
||||
for (uint8 i = 0; i < MAX_CHANNELERS; ++i)
|
||||
me->SummonCreature(NPC_GREYHEART_SPELLBINDER, channelersPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* /*who*/) override { }
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit*) override
|
||||
{
|
||||
me->SetInCombatWithZone();
|
||||
summons.Despawn(summon);
|
||||
if (summon->GetEntry() == NPC_GREYHEART_SPELLBINDER)
|
||||
if (!summons.HasEntry(NPC_GREYHEART_SPELLBINDER))
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->LoadEquipment();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000);
|
||||
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
|
||||
events.ScheduleEvent(EVENT_SWITCH_TO_DEMON, 55000);
|
||||
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
scheduler.Schedule(4s, [this](TaskContext)
|
||||
{
|
||||
Talk(me->GetDisplayId() != me->GetNativeDisplayId() ? SAY_DEMON_SLAY : SAY_NIGHTELF_SLAY);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
me->CastSpell(me, SPELL_CLEAR_CONSUMING_MADNESS, true);
|
||||
Talk(SAY_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (who && me->Attack(who, true))
|
||||
me->GetMotionMaster()->MoveChase(who, me->GetDisplayId() == me->GetNativeDisplayId() ? 0.0f : 25.0f);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
DoCastSelf(SPELL_SUMMON_SHADOW_OF_LEOTHERAS);
|
||||
}).Schedule(6s, [this](TaskContext)
|
||||
{
|
||||
case EVENT_SPELL_BERSERK:
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
break;
|
||||
case EVENT_HEALTH_CHECK:
|
||||
if (me->HealthBelowPct(15))
|
||||
{
|
||||
if (me->GetDisplayId() != me->GetNativeDisplayId())
|
||||
{
|
||||
DoResetThreatList();
|
||||
me->LoadEquipment();
|
||||
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
|
||||
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000);
|
||||
}
|
||||
events.CancelEvent(EVENT_SWITCH_TO_DEMON);
|
||||
events.CancelEvent(EVENT_SPELL_INSIDIOUS_WHISPER);
|
||||
events.DelayEvents(10000);
|
||||
events.ScheduleEvent(EVENT_SUMMON_DEMON, 4000);
|
||||
events.ScheduleEvent(EVENT_RESTORE_FIGHT, 6000);
|
||||
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->StopMoving();
|
||||
Talk(SAY_FINAL_FORM);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
|
||||
break;
|
||||
case EVENT_SWITCH_TO_DEMON:
|
||||
DoResetThreatList();
|
||||
Talk(SAY_SWITCH_TO_DEMON);
|
||||
me->LoadEquipment(0, true);
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), 25.0f);
|
||||
me->CastSpell(me, SPELL_METAMORPHOSIS, true);
|
||||
|
||||
events.CancelEvent(EVENT_SPELL_WHIRLWIND);
|
||||
events.ScheduleEvent(EVENT_SPELL_INSIDIOUS_WHISPER, 25000);
|
||||
events.ScheduleEvent(EVENT_SWITCH_TO_ELF, 60000);
|
||||
break;
|
||||
case EVENT_SWITCH_TO_ELF:
|
||||
DoResetThreatList();
|
||||
me->LoadEquipment();
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), 0.0f);
|
||||
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
|
||||
events.ScheduleEvent(EVENT_SWITCH_TO_DEMON, 55000);
|
||||
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_WHIRLWIND:
|
||||
me->CastSpell(me, SPELL_WHIRLWIND, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 27000);
|
||||
break;
|
||||
case EVENT_SPELL_INSIDIOUS_WHISPER:
|
||||
Talk(SAY_INNER_DEMONS);
|
||||
me->CastCustomSpell(SPELL_INSIDIOUS_WHISPER, SPELLVALUE_MAX_TARGETS, 5, me, false);
|
||||
break;
|
||||
case EVENT_SUMMON_DEMON:
|
||||
me->CastSpell(me, SPELL_SUMMON_SHADOW_OF_LEOTHERAS, true);
|
||||
break;
|
||||
case EVENT_RESTORE_FIGHT:
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->GetDisplayId() == me->GetNativeDisplayId())
|
||||
DoMeleeAttackIfReady();
|
||||
else if (me->isAttackReady(BASE_ATTACK))
|
||||
{
|
||||
me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, false);
|
||||
me->setAttackTimer(BASE_ATTACK, 2000);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class npc_inner_demon : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_inner_demon() : CreatureScript("npc_inner_demon") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetSerpentShrineAI<npc_inner_demonAI>(creature);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
struct npc_inner_demonAI : public ScriptedAI
|
||||
void SummonChannelers()
|
||||
{
|
||||
npc_inner_demonAI(Creature* creature) : ScriptedAI(creature)
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, false);
|
||||
DoCastSelf(SPELL_BANISH);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true);
|
||||
|
||||
//probably needs a spell instead
|
||||
summons.DespawnAll();
|
||||
for (uint8 i = 0; i < MAX_CHANNELERS; ++i)
|
||||
{
|
||||
me->SummonCreature(NPC_GREYHEART_SPELLBINDER, channelersPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectGuid ownerGUID;
|
||||
EventMap events;
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
void SummonedCreatureDies(Creature* summon, Unit*) override
|
||||
{
|
||||
me->SetInCombatWithZone();
|
||||
summons.Despawn(summon);
|
||||
if (summon->GetEntry() == NPC_GREYHEART_SPELLBINDER)
|
||||
{
|
||||
me->DespawnOrUnsummon(1);
|
||||
}
|
||||
|
||||
void IsSummonedBy(WorldObject* summoner) override
|
||||
{
|
||||
if (!summoner)
|
||||
return;
|
||||
|
||||
ownerGUID = summoner->GetGUID();
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, 4000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Unit* unit = ObjectAccessor::GetUnit(*me, ownerGUID))
|
||||
unit->RemoveAurasDueToSpell(SPELL_INSIDIOUS_WHISPER);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (!who || who->GetGUID() != ownerGUID)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
bool CanAIAttack(Unit const* who) const override
|
||||
{
|
||||
return who->GetGUID() == ownerGUID;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
if (!summons.HasEntry(NPC_GREYHEART_SPELLBINDER))
|
||||
{
|
||||
case EVENT_SPELL_SHADOW_BOLT:
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, 6000);
|
||||
break;
|
||||
}
|
||||
me->RemoveAllAuras();
|
||||
me->LoadEquipment();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
scheduler.Schedule(10min, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_BERSERK);
|
||||
});
|
||||
|
||||
ElfTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ElfTime()
|
||||
{
|
||||
scheduler.Schedule(25050ms, 32550ms, GROUP_COMBAT, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_WHIRLWIND);
|
||||
context.Repeat(30250ms, 34900ms);
|
||||
}).Schedule(60350ms, GROUP_DEMON, [this](TaskContext)
|
||||
{
|
||||
DoResetThreatList();
|
||||
Talk(SAY_SWITCH_TO_DEMON);
|
||||
DemonTime();
|
||||
});
|
||||
}
|
||||
|
||||
void DemonTime()
|
||||
{
|
||||
me->LoadEquipment(0, true);
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), 25.0f);
|
||||
DoCastSelf(SPELL_METAMORPHOSIS, true);
|
||||
|
||||
scheduler.CancelGroup(GROUP_COMBAT);
|
||||
scheduler.Schedule(24250ms, GROUP_DEMON, [this](TaskContext)
|
||||
{
|
||||
Talk(SAY_INNER_DEMONS);
|
||||
me->CastCustomSpell(SPELL_INSIDIOUS_WHISPER, SPELLVALUE_MAX_TARGETS, 5, me, false);
|
||||
}).Schedule(60s, [this](TaskContext)
|
||||
{
|
||||
DoResetThreatList();
|
||||
me->LoadEquipment();
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), 0.0f);
|
||||
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
|
||||
ElfTime();
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
if (me->GetDisplayId() == me->GetNativeDisplayId())
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
else if (me->isAttackReady(BASE_ATTACK))
|
||||
{
|
||||
me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, false);
|
||||
me->setAttackTimer(BASE_ATTACK, 2000);
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool _recentlySpoken;
|
||||
};
|
||||
|
||||
struct npc_inner_demon : public ScriptedAI
|
||||
{
|
||||
npc_inner_demon(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
|
||||
_instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
me->DespawnOrUnsummon(1);
|
||||
}
|
||||
|
||||
void IsSummonedBy(WorldObject* summoner) override
|
||||
{
|
||||
if (!summoner)
|
||||
return;
|
||||
|
||||
_scheduler.CancelAll();
|
||||
_scheduler.Schedule(4s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOW_BOLT);
|
||||
context.Repeat(6s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
|
||||
{
|
||||
leotheras->RemoveAurasDueToSpell(SPELL_INSIDIOUS_WHISPER);
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
|
||||
{
|
||||
if (!who || who->GetGUID() != leotheras->GetGUID())
|
||||
{
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CanAIAttack(Unit const* who) const override
|
||||
{
|
||||
if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
|
||||
{
|
||||
return who->GetGUID() == leotheras->GetGUID();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_scheduler.Update(diff);
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
class spell_leotheras_whirlwind : public SpellScriptLoader
|
||||
@@ -516,8 +475,8 @@ public:
|
||||
|
||||
void AddSC_boss_leotheras_the_blind()
|
||||
{
|
||||
new boss_leotheras_the_blind();
|
||||
new npc_inner_demon();
|
||||
RegisterSerpentShrineAI(boss_leotheras_the_blind);
|
||||
RegisterSerpentShrineAI(npc_inner_demon);
|
||||
new spell_leotheras_whirlwind();
|
||||
new spell_leotheras_chaos_blast();
|
||||
new spell_leotheras_insidious_whisper();
|
||||
|
||||
+136
-137
@@ -26,7 +26,10 @@ enum Spells
|
||||
SPELL_GEYSER = 37478,
|
||||
SPELL_SPOUT_VISUAL = 37431,
|
||||
SPELL_SPOUT_PERIODIC = 37430,
|
||||
SPELL_LURKER_SPAWN_TRIGGER = 54587 // Needed for achievement
|
||||
SPELL_LURKER_SPAWN_TRIGGER = 54587, // Needed for achievement
|
||||
|
||||
SPELL_CLEAR_ALL_DEBUFFS = 34098,
|
||||
SPELL_SUBMERGE_VISUAL = 28819,
|
||||
};
|
||||
|
||||
enum Misc
|
||||
@@ -37,13 +40,12 @@ enum Misc
|
||||
|
||||
NPC_COILFANG_GUARDIAN = 21873,
|
||||
NPC_COILFANG_AMBUSHER = 21865,
|
||||
};
|
||||
|
||||
EVENT_PHASE_1 = 1,
|
||||
EVENT_PHASE_2 = 2,
|
||||
EVENT_SPELL_WHIRL = 3,
|
||||
EVENT_SPELL_SPOUT = 4,
|
||||
EVENT_SPELL_GEYSER = 5,
|
||||
EVENT_SPELL_SPOUT_PERIODIC = 6
|
||||
enum Groups
|
||||
{
|
||||
GROUP_WHIRL = 1,
|
||||
GROUP_GEYSER = 2
|
||||
};
|
||||
|
||||
const Position positions[MAX_SUMMONS] =
|
||||
@@ -59,152 +61,149 @@ const Position positions[MAX_SUMMONS] =
|
||||
{42.471519f, -445.115295f, -19.769423f, 0.0f}
|
||||
};
|
||||
|
||||
class boss_the_lurker_below : public CreatureScript
|
||||
struct boss_the_lurker_below : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_the_lurker_below() : CreatureScript("boss_the_lurker_below") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_the_lurker_below(Creature* creature) : BossAI(creature, DATA_THE_LURKER_BELOW)
|
||||
{
|
||||
return GetSerpentShrineAI<boss_the_lurker_belowAI>(creature);
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_the_lurker_belowAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_the_lurker_belowAI(Creature* creature) : BossAI(creature, DATA_THE_LURKER_BELOW) { }
|
||||
BossAI::Reset();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
|
||||
me->SetVisible(false);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_START_EVENT)
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->setAttackTimer(BASE_ATTACK, 6000);
|
||||
me->SetVisible(true);
|
||||
me->UpdateObjectVisibility(true);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetInCombatWithZone();
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (who && me->GetReactState() == REACT_AGGRESSIVE)
|
||||
{
|
||||
me->Attack(who, true);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
SchedulerPhaseOne(38800ms, 91000ms);
|
||||
}
|
||||
|
||||
void SchedulerPhaseOne(std::chrono::milliseconds spoutTimer, std::chrono::milliseconds p2Timer)
|
||||
{
|
||||
scheduler.Schedule(10900ms, GROUP_GEYSER, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_GEYSER);
|
||||
context.Repeat(10200ms, 54900ms);
|
||||
}).Schedule(18150ms, GROUP_WHIRL, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_WHIRL);
|
||||
context.Repeat(34150ms, 68550ms);
|
||||
}).Schedule(spoutTimer, [this](TaskContext context)
|
||||
{
|
||||
Talk(EMOTE_TAKE_BREATH);
|
||||
me->CastSpell(me, SPELL_SPOUT_VISUAL, TRIGGERED_IGNORE_SET_FACING);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetFacingToObject(me->GetVictim());
|
||||
me->SetTarget();
|
||||
scheduler.RescheduleGroup(GROUP_GEYSER, 25s);
|
||||
scheduler.RescheduleGroup(GROUP_WHIRL, 18s);
|
||||
scheduler.Schedule(3s, [this](TaskContext)
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
DoCastSelf(SPELL_SPOUT_PERIODIC, true);
|
||||
});
|
||||
context.Repeat(60s);
|
||||
}).Schedule(p2Timer, [this](TaskContext)
|
||||
{
|
||||
//phase2
|
||||
scheduler.CancelAll();
|
||||
DoCastSelf(SPELL_SUBMERGE_VISUAL, true);
|
||||
DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS, true);
|
||||
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
|
||||
me->SetVisible(false);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
// Reset summons
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summon->SetInCombatWithZone();
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_START_EVENT)
|
||||
for (uint8 i = 0; i < MAX_SUMMONS; ++i)
|
||||
{
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->setAttackTimer(BASE_ATTACK, 6000);
|
||||
me->SetVisible(true);
|
||||
me->UpdateObjectVisibility(true);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetInCombatWithZone();
|
||||
//needs sniffed spell probably
|
||||
me->SummonCreature(i < 6 ? NPC_COILFANG_AMBUSHER : NPC_COILFANG_GUARDIAN, positions[i].GetPositionX(), positions[i].GetPositionY(), positions[i].GetPositionZ(), positions[i].GetAngle(me), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
|
||||
}
|
||||
SchedulerPhaseTwo();
|
||||
});
|
||||
}
|
||||
|
||||
void SchedulerPhaseTwo()
|
||||
{
|
||||
scheduler.Schedule(60s, [this](TaskContext)
|
||||
{
|
||||
me->setAttackTimer(BASE_ATTACK, 6000);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
scheduler.CancelAll();
|
||||
SchedulerPhaseOne(10000ms, 90750ms);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
|
||||
if (me->getStandState() != UNIT_STAND_STATE_STAND || !me->isAttackReady() || me->GetReactState() != REACT_AGGRESSIVE)
|
||||
return;
|
||||
|
||||
Unit* target = nullptr;
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
target = me->GetVictim();
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
|
||||
for (ThreatReference const* ref : t_list)
|
||||
{
|
||||
if (Unit* threatTarget = ObjectAccessor::GetUnit(*me, ref->getUnitGuid()))
|
||||
{
|
||||
if (me->IsWithinMeleeRange(threatTarget))
|
||||
{
|
||||
target = threatTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
if (target)
|
||||
{
|
||||
BossAI::JustDied(killer);
|
||||
me->AttackerStateUpdate(target);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
else if ((target = SelectTarget(SelectTargetMethod::Random, 0)))
|
||||
{
|
||||
if (who && me->GetReactState() == REACT_AGGRESSIVE)
|
||||
me->Attack(who, true);
|
||||
me->CastSpell(target, SPELL_WATER_BOLT, false);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_SPELL_WHIRL, 18000);
|
||||
events.ScheduleEvent(EVENT_SPELL_SPOUT, 45000);
|
||||
events.ScheduleEvent(EVENT_SPELL_GEYSER, 10000);
|
||||
events.ScheduleEvent(EVENT_PHASE_2, 125000);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_WHIRL:
|
||||
me->CastSpell(me, SPELL_WHIRL, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_WHIRL, 18000);
|
||||
break;
|
||||
case EVENT_SPELL_GEYSER:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, SPELL_GEYSER, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_GEYSER, 10000);
|
||||
break;
|
||||
case EVENT_SPELL_SPOUT:
|
||||
Talk(EMOTE_TAKE_BREATH);
|
||||
me->CastSpell(me, SPELL_SPOUT_VISUAL, TRIGGERED_IGNORE_SET_FACING);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetFacingToObject(me->GetVictim());
|
||||
me->SetTarget();
|
||||
events.ScheduleEvent(EVENT_SPELL_SPOUT, 60000);
|
||||
events.RescheduleEvent(EVENT_SPELL_WHIRL, 18000);
|
||||
events.RescheduleEvent(EVENT_SPELL_GEYSER, 25000);
|
||||
events.ScheduleEvent(EVENT_SPELL_SPOUT_PERIODIC, 3000);
|
||||
break;
|
||||
case EVENT_SPELL_SPOUT_PERIODIC:
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
me->CastSpell(me, SPELL_SPOUT_PERIODIC, true);
|
||||
break;
|
||||
case EVENT_PHASE_2:
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_PHASE_1, 60000);
|
||||
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
for (uint8 i = 0; i < MAX_SUMMONS; ++i)
|
||||
me->SummonCreature(i < 6 ? NPC_COILFANG_AMBUSHER : NPC_COILFANG_GUARDIAN, positions[i].GetPositionX(), positions[i].GetPositionY(), positions[i].GetPositionZ(), positions[i].GetAngle(me), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
|
||||
break;
|
||||
case EVENT_PHASE_1:
|
||||
me->setAttackTimer(BASE_ATTACK, 6000);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_SPELL_SPOUT, 10000);
|
||||
events.ScheduleEvent(EVENT_PHASE_2, 120000);
|
||||
break;
|
||||
}
|
||||
|
||||
if (me->getStandState() != UNIT_STAND_STATE_STAND || !me->isAttackReady() || me->GetReactState() != REACT_AGGRESSIVE)
|
||||
return;
|
||||
|
||||
Unit* target = nullptr;
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
target = me->GetVictim();
|
||||
else
|
||||
{
|
||||
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
|
||||
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
|
||||
if (Unit* threatTarget = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
|
||||
if (me->IsWithinMeleeRange(threatTarget))
|
||||
{
|
||||
target = threatTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target)
|
||||
me->AttackerStateUpdate(target);
|
||||
else if ((target = SelectTarget(SelectTargetMethod::Random, 0)))
|
||||
me->CastSpell(target, SPELL_WATER_BOLT, false);
|
||||
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
};
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
};
|
||||
|
||||
class go_strange_pool : public GameObjectScript
|
||||
@@ -315,7 +314,7 @@ public:
|
||||
|
||||
void AddSC_boss_the_lurker_below()
|
||||
{
|
||||
new boss_the_lurker_below();
|
||||
RegisterSerpentShrineAI(boss_the_lurker_below);
|
||||
new go_strange_pool();
|
||||
new spell_lurker_below_spout();
|
||||
new spell_lurker_below_spout_cone();
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ struct boss_morogrim_tidewalker : public BossAI
|
||||
else
|
||||
{
|
||||
Talk(EMOTE_WATERY_GLOBULES);
|
||||
for (uint8 waterGlobuleId : waterGlobuleIds)
|
||||
for (uint32 waterGlobuleId : waterGlobuleIds)
|
||||
{
|
||||
DoCastSelf(waterGlobuleId, true);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,10 @@ public:
|
||||
if (Creature* vashj = instance->GetCreature(LadyVashjGUID))
|
||||
vashj->AI()->JustSummoned(creature);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
}
|
||||
|
||||
ObjectGuid GetGuidData(uint32 identifier) const override
|
||||
|
||||
@@ -166,7 +166,7 @@ struct boss_magtheridon : public BossAI
|
||||
{
|
||||
me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1);
|
||||
context.Repeat(11s, 39s);
|
||||
}).Schedule(40s, [this](TaskContext context)
|
||||
}).Schedule(28300ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_QUAKE);
|
||||
_castingQuake = true;
|
||||
@@ -175,29 +175,33 @@ struct boss_magtheridon : public BossAI
|
||||
me->SetOrientation(me->GetAngle(me->GetVictim()));
|
||||
me->SetTarget(ObjectGuid::Empty);
|
||||
scheduler.DelayAll(6999ms);
|
||||
scheduler.Schedule(7s, [this](TaskContext /*context*/)
|
||||
scheduler.Schedule(7s, [this](TaskContext)
|
||||
{
|
||||
_castingQuake = false;
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
DoCastSelf(SPELL_BLAST_NOVA);
|
||||
|
||||
_interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context)
|
||||
{
|
||||
if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
|
||||
{
|
||||
Talk(SAY_BANISH);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
scheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
|
||||
}
|
||||
else
|
||||
context.Repeat(50ms);
|
||||
}).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/)
|
||||
{
|
||||
_interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
|
||||
});
|
||||
});
|
||||
context.Repeat(53s, 56s);
|
||||
context.Repeat(56300ms, 64300ms);
|
||||
}).Schedule(55650ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_BLAST_NOVA);
|
||||
scheduler.DelayAll(10s);
|
||||
|
||||
_interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context)
|
||||
{
|
||||
if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
|
||||
{
|
||||
Talk(SAY_BANISH);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
scheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
|
||||
}
|
||||
else
|
||||
context.Repeat(50ms);
|
||||
}).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/)
|
||||
{
|
||||
_interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
|
||||
});
|
||||
context.Repeat(54350ms, 55400ms);
|
||||
}).Schedule(22min, [this](TaskContext /*context*/)
|
||||
{
|
||||
DoCastSelf(SPELL_BERSERK, true);
|
||||
|
||||
@@ -443,8 +443,6 @@ public:
|
||||
|
||||
GetUnitOwner()->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
GetUnitOwner()->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
GetUnitOwner()->m_last_notify_position.Relocate(0.0f, 0.0f, 0.0f);
|
||||
GetUnitOwner()->m_delayed_unit_relocation_timer = 1000;
|
||||
}
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
|
||||
@@ -208,7 +208,11 @@ class spell_capacitus_polarity_shift : public SpellScript
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
target->RemoveAurasDueToSpell(SPELL_POSITIVE_CHARGE_STACK);
|
||||
target->RemoveAurasDueToSpell(SPELL_NEGATIVE_CHARGE_STACK);
|
||||
target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, nullptr, nullptr, GetCaster()->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -731,8 +731,19 @@ public:
|
||||
## npc_flanis_swiftwing_and_kagrosh
|
||||
######*/
|
||||
|
||||
#define GOSSIP_HSK1 "Take Flanis's Pack"
|
||||
#define GOSSIP_HSK2 "Take Kagrosh's Pack"
|
||||
enum Flanis : uint32
|
||||
{
|
||||
QUEST_THE_FATE_OF_FLANIS = 10583,
|
||||
ITEM_FLAUNISS_PACK = 30658,
|
||||
GOSSIP_MENU_FLANIS = 8356,
|
||||
};
|
||||
|
||||
enum Kagrosh : uint32
|
||||
{
|
||||
QUEST_THE_FATE_OF_KAGROSH = 10601,
|
||||
ITEM_KAGROSHS_PACK = 30659,
|
||||
GOSSIP_MENU_KAGROSH = 8371,
|
||||
};
|
||||
|
||||
class npcs_flanis_swiftwing_and_kagrosh : public CreatureScript
|
||||
{
|
||||
@@ -745,32 +756,33 @@ public:
|
||||
if (action == GOSSIP_ACTION_INFO_DEF + 1)
|
||||
{
|
||||
ItemPosCountVec dest;
|
||||
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 30658, 1, nullptr);
|
||||
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_FLAUNISS_PACK, 1, nullptr);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
player->StoreNewItem(dest, 30658, true);
|
||||
ClearGossipMenuFor(player);
|
||||
player->StoreNewItem(dest, ITEM_FLAUNISS_PACK, true);
|
||||
}
|
||||
}
|
||||
if (action == GOSSIP_ACTION_INFO_DEF + 2)
|
||||
{
|
||||
ItemPosCountVec dest;
|
||||
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 30659, 1, nullptr);
|
||||
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_KAGROSHS_PACK, 1, nullptr);
|
||||
if (msg == EQUIP_ERR_OK)
|
||||
{
|
||||
player->StoreNewItem(dest, 30659, true);
|
||||
ClearGossipMenuFor(player);
|
||||
player->StoreNewItem(dest, ITEM_KAGROSHS_PACK, true);
|
||||
}
|
||||
}
|
||||
|
||||
CloseGossipMenuFor(player);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
if (player->GetQuestStatus(10583) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(30658, 1, true))
|
||||
AddGossipItemFor(player, 0, GOSSIP_HSK1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
if (player->GetQuestStatus(10601) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(30659, 1, true))
|
||||
AddGossipItemFor(player, 0, GOSSIP_HSK2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
if (player->GetQuestStatus(QUEST_THE_FATE_OF_FLANIS) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(ITEM_FLAUNISS_PACK, 1, true))
|
||||
AddGossipItemFor(player, GOSSIP_MENU_FLANIS, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
if (player->GetQuestStatus(QUEST_THE_FATE_OF_KAGROSH) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(ITEM_KAGROSHS_PACK, 1, true))
|
||||
AddGossipItemFor(player, GOSSIP_MENU_KAGROSH, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
|
||||
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
|
||||
|
||||
@@ -1734,6 +1746,97 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum KorWild
|
||||
{
|
||||
SAY_LAND = 0,
|
||||
POINT_LAND = 1
|
||||
};
|
||||
|
||||
class npc_korkron_or_wildhammer : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_korkron_or_wildhammer(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
creature->SetDisableGravity(true);
|
||||
creature->SetHover(true);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
me->DespawnOrUnsummon(3s, 0s);
|
||||
}
|
||||
|
||||
void IsSummonedBy(WorldObject* summoner) override
|
||||
{
|
||||
_playerGUID = summoner->GetGUID();
|
||||
me->SetFacingToObject(summoner);
|
||||
Position pos = summoner->GetPosition();
|
||||
me->GetMotionMaster()->MovePoint(POINT_LAND, pos);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_LAND)
|
||||
{
|
||||
if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID))
|
||||
Talk(SAY_LAND, player);
|
||||
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
}
|
||||
private:
|
||||
ObjectGuid _playerGUID;
|
||||
};
|
||||
|
||||
class spell_calling_korkron_or_wildhammer : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_calling_korkron_or_wildhammer);
|
||||
|
||||
void SetDest(SpellDestination& dest)
|
||||
{
|
||||
// Adjust effect summon position
|
||||
Position const offset = { -14.0f, -14.0f, 16.0f, 0.0f };
|
||||
dest.RelocateOffset(offset);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_calling_korkron_or_wildhammer::SetDest, EFFECT_0, TARGET_DEST_CASTER);
|
||||
}
|
||||
};
|
||||
|
||||
enum InfernalOversoul
|
||||
{
|
||||
NPC_INFERNAL_OVERSOUL = 21735,
|
||||
SPELL_DISRUPT_SUMMONING_RITUAL = 37285
|
||||
};
|
||||
|
||||
class spell_disrupt_summoning_ritual : public SpellScript
|
||||
{
|
||||
public:
|
||||
PrepareSpellScript(spell_disrupt_summoning_ritual);
|
||||
|
||||
SpellCastResult CheckRequirement()
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (Creature* infernal = caster->FindNearestCreature(NPC_INFERNAL_OVERSOUL, 100.0f))
|
||||
if (!infernal->HasAura(SPELL_DISRUPT_SUMMONING_RITUAL))
|
||||
return SPELL_FAILED_CASTER_AURASTATE;
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_disrupt_summoning_ritual::CheckRequirement);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_shadowmoon_valley()
|
||||
{
|
||||
// Ours
|
||||
@@ -1755,4 +1858,7 @@ void AddSC_shadowmoon_valley()
|
||||
new npc_torloth_the_magnificent();
|
||||
new npc_enraged_spirit();
|
||||
new npc_shadowmoon_tuber_node();
|
||||
RegisterCreatureAI(npc_korkron_or_wildhammer);
|
||||
RegisterSpellScript(spell_calling_korkron_or_wildhammer);
|
||||
RegisterSpellScript(spell_disrupt_summoning_ritual);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,11 @@ public:
|
||||
# npc_zephyr
|
||||
######*/
|
||||
|
||||
#define GOSSIP_HZ "Take me to the Caverns of Time."
|
||||
enum Zephyr : int32
|
||||
{
|
||||
GOSSIP_MENU_ZEPHYR = 9205,
|
||||
SPELL_TELEPORT_CAVERNS_OF_TIME = 37778,
|
||||
};
|
||||
|
||||
class npc_zephyr : public CreatureScript
|
||||
{
|
||||
@@ -96,7 +100,7 @@ public:
|
||||
{
|
||||
ClearGossipMenuFor(player);
|
||||
if (action == GOSSIP_ACTION_INFO_DEF + 1)
|
||||
player->CastSpell(player, 37778, false);
|
||||
player->CastSpell(player, SPELL_TELEPORT_CAVERNS_OF_TIME, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -104,7 +108,7 @@ public:
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
if (player->GetReputationRank(989) >= REP_REVERED)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HZ, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_ZEPHYR, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
|
||||
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
|
||||
|
||||
|
||||
@@ -575,10 +575,25 @@ public:
|
||||
/*######
|
||||
## go_skull_pile
|
||||
######*/
|
||||
#define GOSSIP_S_DARKSCREECHER_AKKARAI "Summon Darkscreecher Akkarai"
|
||||
#define GOSSIP_S_KARROG "Summon Karrog"
|
||||
#define GOSSIP_S_GEZZARAK_THE_HUNTRESS "Summon Gezzarak the Huntress"
|
||||
#define GOSSIP_S_VAKKIZ_THE_WINDRAGER "Summon Vakkiz the Windrager"
|
||||
|
||||
enum SkullPile : uint32
|
||||
{
|
||||
QUEST_ADVERSARIAL_BLOOD = 11885,
|
||||
|
||||
GOSSIP_MENU_SKULL_PILE = 8660,
|
||||
GOSSIP_MENU_TEXT_SKULL_PILE = 10888,
|
||||
GOSSIP_MENU_TEXT_SKULL_PILE_QUEST = 11057,
|
||||
|
||||
GOSSIP_OPTION_SUMMON_GEZZARAK_THE_HUNTRESS = 0,
|
||||
GOSSIP_OPTION_SUMMON_DARKSCREECHER_AKKARAI = 1,
|
||||
GOSSIP_OPTION_SUMMON_KARROG = 2,
|
||||
GOSSIP_OPTION_SUMMON_VAKKIZ_THE_WINDRAGER = 3,
|
||||
|
||||
SPELL_SUMMON_GEZZARAK_THE_HUNTRESS = 40632,
|
||||
SPELL_SUMMON_DARKSCREECHER_AKKARAI = 40642,
|
||||
SPELL_SUMMON_KARROG = 40640,
|
||||
SPELL_SUMMON_VAKKIZ_THE_WINDRAGER = 40644,
|
||||
};
|
||||
|
||||
class go_skull_pile : public GameObjectScript
|
||||
{
|
||||
@@ -588,26 +603,29 @@ public:
|
||||
bool OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action) override
|
||||
{
|
||||
ClearGossipMenuFor(player);
|
||||
switch (sender)
|
||||
|
||||
if (sender == GOSSIP_SENDER_MAIN)
|
||||
{
|
||||
case GOSSIP_SENDER_MAIN:
|
||||
SendActionMenu(player, go, action);
|
||||
break;
|
||||
SendActionMenu(player, go, action);
|
||||
CloseGossipMenuFor(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, GameObject* go) override
|
||||
{
|
||||
if ((player->GetQuestStatus(11885) == QUEST_STATUS_INCOMPLETE) || player->GetQuestRewardStatus(11885))
|
||||
if ((player->GetQuestStatus(QUEST_ADVERSARIAL_BLOOD) == QUEST_STATUS_INCOMPLETE) || player->GetQuestRewardStatus(QUEST_ADVERSARIAL_BLOOD))
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_S_DARKSCREECHER_AKKARAI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_S_KARROG, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_S_GEZZARAK_THE_HUNTRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_S_VAKKIZ_THE_WINDRAGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
|
||||
}
|
||||
AddGossipItemFor(player, GOSSIP_MENU_SKULL_PILE, GOSSIP_OPTION_SUMMON_GEZZARAK_THE_HUNTRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_SKULL_PILE, GOSSIP_OPTION_SUMMON_DARKSCREECHER_AKKARAI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_SKULL_PILE, GOSSIP_OPTION_SUMMON_KARROG, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
|
||||
AddGossipItemFor(player, GOSSIP_MENU_SKULL_PILE, GOSSIP_OPTION_SUMMON_VAKKIZ_THE_WINDRAGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
|
||||
|
||||
SendGossipMenuFor(player, GOSSIP_MENU_TEXT_SKULL_PILE_QUEST, go->GetGUID());
|
||||
}
|
||||
else
|
||||
SendGossipMenuFor(player, GOSSIP_MENU_TEXT_SKULL_PILE, go->GetGUID());
|
||||
|
||||
SendGossipMenuFor(player, go->GetGOInfo()->questgiver.gossipID, go->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -616,16 +634,16 @@ public:
|
||||
switch (action)
|
||||
{
|
||||
case GOSSIP_ACTION_INFO_DEF + 1:
|
||||
player->CastSpell(player, 40642, false);
|
||||
player->CastSpell(player, SPELL_SUMMON_GEZZARAK_THE_HUNTRESS, false);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF + 2:
|
||||
player->CastSpell(player, 40640, false);
|
||||
player->CastSpell(player, SPELL_SUMMON_DARKSCREECHER_AKKARAI, false);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF + 3:
|
||||
player->CastSpell(player, 40632, false);
|
||||
player->CastSpell(player, SPELL_SUMMON_KARROG, false);
|
||||
break;
|
||||
case GOSSIP_ACTION_INFO_DEF + 4:
|
||||
player->CastSpell(player, 40644, false);
|
||||
player->CastSpell(player, SPELL_SUMMON_VAKKIZ_THE_WINDRAGER, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,6 +410,26 @@ class spell_dru_dash : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// -1850 - Dash
|
||||
class spell_dru_dash_aura : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_dru_dash_aura);
|
||||
|
||||
void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
// do not set speed if not in cat form
|
||||
if (GetUnitOwner()->GetShapeshiftForm() != FORM_CAT)
|
||||
{
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_dash_aura::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_INCREASE_SPEED);
|
||||
}
|
||||
};
|
||||
|
||||
// 5229 - Enrage
|
||||
class spell_dru_enrage : public AuraScript
|
||||
{
|
||||
@@ -1185,7 +1205,7 @@ void AddSC_druid_spell_scripts()
|
||||
RegisterSpellScript(spell_dru_barkskin);
|
||||
RegisterSpellScript(spell_dru_treant_scaling);
|
||||
RegisterSpellScript(spell_dru_berserk);
|
||||
RegisterSpellScript(spell_dru_dash);
|
||||
RegisterSpellAndAuraScriptPair(spell_dru_dash, spell_dru_dash_aura);
|
||||
RegisterSpellScript(spell_dru_enrage);
|
||||
RegisterSpellScript(spell_dru_glyph_of_starfire);
|
||||
RegisterSpellScript(spell_dru_idol_lifebloom);
|
||||
|
||||
@@ -4997,6 +4997,111 @@ class spell_gen_spirit_of_competition_winner : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 27360 - Lord Valthalak's Amulet
|
||||
enum Valthalak
|
||||
{
|
||||
SPELL_INSTILL_LORD_VALTHALAK_SPIRIT = 27360,
|
||||
NPC_LORD_VALTHALAK = 16042
|
||||
};
|
||||
|
||||
class spell_gen_valthalak_amulet : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_valthalak_amulet)
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
if (Unit* target = GetExplTargetUnit())
|
||||
if (target->GetEntry() == NPC_LORD_VALTHALAK && target->isDead())
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_gen_valthalak_amulet::CheckCast);
|
||||
}
|
||||
};
|
||||
|
||||
enum ScourgeBanner
|
||||
{
|
||||
GO_COMMAND_TENT = 176210,
|
||||
};
|
||||
|
||||
class spell_gen_planting_scourge_banner : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_planting_scourge_banner)
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
if (GameObject* tent = GetCaster()->FindNearestGameObject(GO_COMMAND_TENT, 20.0f))
|
||||
if (tent->GetGoState() != GO_STATE_READY) // If tent is burned down
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_gen_planting_scourge_banner::CheckCast);
|
||||
}
|
||||
};
|
||||
|
||||
enum Jubling
|
||||
{
|
||||
SPELL_JUBLING_COOLDOWN_1_WEEK = 23852
|
||||
};
|
||||
|
||||
// 23853 - Jubling Cooldown
|
||||
class spell_gen_jubling_cooldown : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_jubling_cooldown);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_JUBLING_COOLDOWN_1_WEEK });
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Player* target = GetHitPlayer())
|
||||
{
|
||||
target->CastSpell(target, SPELL_JUBLING_COOLDOWN_1_WEEK); // 1 week
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_gen_jubling_cooldown::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
// 12699 - Yeh'kinya's Bramble
|
||||
enum YehkinyaBramble
|
||||
{
|
||||
NPC_VALE_SCREECHER = 5307,
|
||||
NPC_ROGUE_VALE_SCREECHER = 5308
|
||||
};
|
||||
|
||||
class spell_gen_yehkinya_bramble : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_yehkinya_bramble)
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
if (Unit* target = GetExplTargetUnit())
|
||||
if ((target->GetEntry() == NPC_VALE_SCREECHER || target->GetEntry() == NPC_ROGUE_VALE_SCREECHER) && target->isDead())
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_gen_yehkinya_bramble::CheckCast);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_generic_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_silithyst);
|
||||
@@ -5145,4 +5250,8 @@ void AddSC_generic_spell_scripts()
|
||||
RegisterSpellScript(spell_gen_curse_of_pain);
|
||||
RegisterSpellScript(spell_gen_spirit_of_competition_participant);
|
||||
RegisterSpellScript(spell_gen_spirit_of_competition_winner);
|
||||
RegisterSpellScript(spell_gen_valthalak_amulet);
|
||||
RegisterSpellScript(spell_gen_planting_scourge_banner);
|
||||
RegisterSpellScript(spell_gen_jubling_cooldown);
|
||||
RegisterSpellScript(spell_gen_yehkinya_bramble);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,8 @@ enum HunterSpells
|
||||
SPELL_DRAENEI_GIFT_OF_THE_NAARU = 59543,
|
||||
SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT = 61389,
|
||||
SPELL_LOCK_AND_LOAD_TRIGGER = 56453,
|
||||
SPELL_LOCK_AND_LOAD_MARKER = 67544
|
||||
SPELL_LOCK_AND_LOAD_MARKER = 67544,
|
||||
SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY = 38297, // Leggings of Beast Mastery
|
||||
};
|
||||
|
||||
class spell_hun_check_pet_los : public SpellScript
|
||||
@@ -165,6 +166,10 @@ class spell_hun_generic_scaling : public AuraScript
|
||||
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
|
||||
int32 modifier = schoolMask == SPELL_SCHOOL_MASK_NORMAL ? 35 : 40;
|
||||
amount = CalculatePct(std::max<int32>(0, owner->GetResistance(schoolMask)), modifier);
|
||||
if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY) && schoolMask == SPELL_SCHOOL_MASK_NORMAL)
|
||||
{
|
||||
amount += 490;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,6 +185,10 @@ class spell_hun_generic_scaling : public AuraScript
|
||||
AddPct(modifier, wildHuntEff->GetAmount());
|
||||
|
||||
amount = CalculatePct(std::max<int32>(0, owner->GetStat(Stats(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue))), modifier);
|
||||
if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY))
|
||||
{
|
||||
amount += 52;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +210,10 @@ class spell_hun_generic_scaling : public AuraScript
|
||||
ownerAP += CalculatePct(owner->GetStat(STAT_STAMINA), HvWEff->GetAmount());
|
||||
|
||||
amount = CalculatePct(std::max<int32>(0, ownerAP), modifier);
|
||||
if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY))
|
||||
{
|
||||
amount += 70;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1308,9 +1321,11 @@ class spell_hun_bestial_wrath : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_hun_furious_howl : public SpellScript
|
||||
// -24604 - Furious Howl
|
||||
// 53434 - Call of the Wild
|
||||
class spell_hun_target_self_and_pet : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_hun_furious_howl);
|
||||
PrepareSpellScript(spell_hun_target_self_and_pet);
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
@@ -1327,7 +1342,7 @@ class spell_hun_furious_howl : public SpellScript
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_furious_howl::FilterTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_PARTY);
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_target_self_and_pet::FilterTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_PARTY);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1361,5 +1376,5 @@ void AddSC_hunter_spell_scripts()
|
||||
RegisterSpellScript(spell_hun_lock_and_load);
|
||||
RegisterSpellScript(spell_hun_intimidation);
|
||||
RegisterSpellScript(spell_hun_bestial_wrath);
|
||||
RegisterSpellScript(spell_hun_furious_howl);
|
||||
RegisterSpellScript(spell_hun_target_self_and_pet);
|
||||
}
|
||||
|
||||
@@ -3883,6 +3883,64 @@ class spell_item_worn_troll_dice : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
enum VenomhideHatchling
|
||||
{
|
||||
NPC_VENOMHIDE_HATCHLING = 34320
|
||||
};
|
||||
|
||||
class spell_item_venomhide_feed : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_item_venomhide_feed)
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
if (Player* player = GetCaster()->ToPlayer())
|
||||
{
|
||||
std::list<Creature*> hatchling;
|
||||
player->GetAllMinionsByEntry(hatchling, NPC_VENOMHIDE_HATCHLING);
|
||||
if (!hatchling.empty())
|
||||
{
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
void UpdateTarget(WorldObject*& target)
|
||||
{
|
||||
if (!target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Player* player = GetCaster()->ToPlayer())
|
||||
{
|
||||
std::list<Creature*> hatchling;
|
||||
player->GetAllMinionsByEntry(hatchling, NPC_VENOMHIDE_HATCHLING);
|
||||
if (hatchling.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (Creature* creature : hatchling)
|
||||
{
|
||||
if (creature)
|
||||
{
|
||||
target = creature;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_item_venomhide_feed::CheckCast);
|
||||
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_item_venomhide_feed::UpdateTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_item_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_item_massive_seaforium_charge);
|
||||
@@ -4003,4 +4061,5 @@ void AddSC_item_spell_scripts()
|
||||
RegisterSpellScript(spell_item_green_whelp_armor);
|
||||
RegisterSpellScript(spell_item_elixir_of_shadows);
|
||||
RegisterSpellScript(spell_item_worn_troll_dice);
|
||||
RegisterSpellScript(spell_item_venomhide_feed);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,12 @@ enum PaladinSpells
|
||||
SPELL_PALADIN_SANCTIFIED_RETRIBUTION_AURA = 63531,
|
||||
SPELL_PALADIN_AURA_MASTERY_IMMUNE = 64364,
|
||||
|
||||
SPELL_JUDGEMENTS_OF_THE_JUST = 68055,
|
||||
SPELL_JUDGEMENT_OF_VENGEANCE_EFFECT = 31804,
|
||||
SPELL_HOLY_VENGEANCE = 31803,
|
||||
SPELL_JUDGEMENT_OF_CORRUPTION_EFFECT = 53733,
|
||||
SPELL_BLOOD_CORRUPTION = 53742,
|
||||
|
||||
SPELL_GENERIC_ARENA_DAMPENING = 74410,
|
||||
SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411
|
||||
};
|
||||
@@ -874,7 +880,26 @@ public:
|
||||
|
||||
// Judgement of the Just
|
||||
if (GetCaster()->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_PALADIN, 3015, 0))
|
||||
GetCaster()->CastSpell(GetHitUnit(), 68055, true);
|
||||
{
|
||||
if (GetCaster()->CastSpell(GetHitUnit(), SPELL_JUDGEMENTS_OF_THE_JUST, true) && (spellId2 == SPELL_JUDGEMENT_OF_VENGEANCE_EFFECT || spellId2 == SPELL_JUDGEMENT_OF_CORRUPTION_EFFECT))
|
||||
{
|
||||
//hidden effect only cast when spellcast of judgements of the just is succesful
|
||||
GetCaster()->CastSpell(GetHitUnit(), SealApplication(spellId2), true); //add hidden seal apply effect for vengeance and corruption
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 SealApplication(uint32 correspondingSpellId)
|
||||
{
|
||||
switch (correspondingSpellId)
|
||||
{
|
||||
case SPELL_JUDGEMENT_OF_VENGEANCE_EFFECT:
|
||||
return SPELL_HOLY_VENGEANCE;
|
||||
case SPELL_JUDGEMENT_OF_CORRUPTION_EFFECT:
|
||||
return SPELL_BLOOD_CORRUPTION;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -48,6 +48,7 @@ enum PriestSpells
|
||||
SPELL_PRIEST_SHADOW_WORD_DEATH = 32409,
|
||||
SPELL_PRIEST_T9_HEALING_2P = 67201,
|
||||
SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL = 64085,
|
||||
SPELL_PRIEST_T4_4P_FLEXIBILITY = 37565,
|
||||
|
||||
SPELL_GENERIC_ARENA_DAMPENING = 74410,
|
||||
SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411,
|
||||
@@ -926,6 +927,28 @@ class spell_pri_mind_control : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 37565 - Flexibility | Item - Priest T4 Holy/Discipline 4P Bonus
|
||||
class spell_pri_t4_4p_bonus : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_pri_t4_4p_bonus);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_PRIEST_T4_4P_FLEXIBILITY });
|
||||
}
|
||||
|
||||
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
GetTarget()->RemoveAurasDueToSpell(SPELL_PRIEST_T4_4P_FLEXIBILITY);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectProc += AuraEffectProcFn(spell_pri_t4_4p_bonus::HandleProc, EFFECT_ALL, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_priest_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_pri_shadowfiend_scaling);
|
||||
@@ -949,4 +972,5 @@ void AddSC_priest_spell_scripts()
|
||||
RegisterSpellScript(spell_pri_shadow_word_death);
|
||||
RegisterSpellScript(spell_pri_vampiric_touch);
|
||||
RegisterSpellScript(spell_pri_mind_control);
|
||||
RegisterSpellScript(spell_pri_t4_4p_bonus);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ enum ShamanSpells
|
||||
SPELL_SHAMAN_CLEANSING_TOTEM_EFFECT = 52025,
|
||||
SPELL_SHAMAN_EARTH_SHIELD_HEAL = 379,
|
||||
SPELL_SHAMAN_ELEMENTAL_MASTERY = 16166,
|
||||
SPELL_SHAMAN_ELECTRIFIED = 64930,
|
||||
SPELL_SHAMAN_EXHAUSTION = 57723,
|
||||
SPELL_SHAMAN_FIRE_NOVA_R1 = 1535,
|
||||
SPELL_SHAMAN_FIRE_NOVA_TRIGGERED_R1 = 8349,
|
||||
@@ -59,7 +60,8 @@ enum ShamanSpells
|
||||
SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL = 52042,
|
||||
SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1 = 51554,
|
||||
SPELL_SHAMAN_STORMSTRIKE = 17364,
|
||||
SPELL_SHAMAN_LAVA_LASH = 60103
|
||||
SPELL_SHAMAN_LAVA_LASH = 60103,
|
||||
SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD = 45284,
|
||||
};
|
||||
|
||||
enum ShamanSpellIcons
|
||||
@@ -1104,6 +1106,45 @@ class spell_sha_flurry_proc : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 64928 - Item - Shaman T8 Elemental 4P Bonus
|
||||
class spell_sha_t8_electrified : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_sha_t8_electrified);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_SHAMAN_ELECTRIFIED });
|
||||
}
|
||||
|
||||
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
|
||||
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
|
||||
if (!damageInfo || !damageInfo->GetDamage())
|
||||
return;
|
||||
|
||||
// Do not proc from Lightning Overload (patch 3.1~)
|
||||
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
|
||||
{
|
||||
if (spellInfo->Id == SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SpellInfo const* electrifiedDot = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_ELECTRIFIED);
|
||||
int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()) / electrifiedDot->GetMaxTicks());
|
||||
|
||||
eventInfo.GetProcTarget()->CastDelayedSpellWithPeriodicAmount(eventInfo.GetActor(), SPELL_SHAMAN_ELECTRIFIED, SPELL_AURA_PERIODIC_DAMAGE, amount);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectProc += AuraEffectProcFn(spell_sha_t8_electrified::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_shaman_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_sha_totem_of_wrath);
|
||||
@@ -1135,4 +1176,5 @@ void AddSC_shaman_spell_scripts()
|
||||
RegisterSpellScript(spell_sha_sentry_totem);
|
||||
RegisterSpellScript(spell_sha_thunderstorm);
|
||||
RegisterSpellScript(spell_sha_flurry_proc);
|
||||
RegisterSpellScript(spell_sha_t8_electrified);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ enum WarlockSpells
|
||||
SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117,
|
||||
SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1 = 18213,
|
||||
SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371,
|
||||
SPELL_WARLOCK_EYE_OF_KILROGG_FLY = 58083
|
||||
SPELL_WARLOCK_EYE_OF_KILROGG_FLY = 58083,
|
||||
SPELL_WARLOCK_PET_VOID_STAR_TALISMAN = 37386, // Void Star Talisman
|
||||
};
|
||||
|
||||
enum WarlockSpellIcons
|
||||
@@ -242,6 +243,7 @@ class spell_warl_demonic_aegis : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// -35696 - Demonic Knowledge
|
||||
class spell_warl_demonic_knowledge : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_warl_demonic_knowledge);
|
||||
@@ -249,7 +251,10 @@ class spell_warl_demonic_knowledge : public AuraScript
|
||||
void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
amount = CalculatePct(caster->GetStat(STAT_STAMINA) + caster->GetStat(STAT_INTELLECT), aurEff->GetBaseAmount());
|
||||
{
|
||||
uint8 pct = aurEff->GetBaseAmount() + aurEff->GetDieSides();
|
||||
amount = CalculatePct(caster->GetStat(STAT_STAMINA) + caster->GetStat(STAT_INTELLECT), pct);
|
||||
}
|
||||
}
|
||||
|
||||
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude)
|
||||
@@ -284,6 +289,11 @@ class spell_warl_generic_scaling : public AuraScript
|
||||
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
|
||||
int32 modifier = schoolMask == SPELL_SCHOOL_MASK_NORMAL ? 35 : 40;
|
||||
amount = CalculatePct(std::max<int32>(0, owner->GetResistance(schoolMask)), modifier);
|
||||
if (owner->HasAura(SPELL_WARLOCK_PET_VOID_STAR_TALISMAN) && schoolMask != SPELL_SCHOOL_MASK_NORMAL)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_WARLOCK_PET_VOID_STAR_TALISMAN);
|
||||
amount += spellInfo->Effects[EFFECT_0].CalcValue(); // 130
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,6 +400,11 @@ class spell_warl_infernal_scaling : public AuraScript
|
||||
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
|
||||
int32 modifier = schoolMask == SPELL_SCHOOL_MASK_NORMAL ? 35 : 40;
|
||||
amount = CalculatePct(std::max<int32>(0, owner->GetResistance(schoolMask)), modifier);
|
||||
if (owner->HasAura(SPELL_WARLOCK_PET_VOID_STAR_TALISMAN) && schoolMask != SPELL_SCHOOL_MASK_NORMAL)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_WARLOCK_PET_VOID_STAR_TALISMAN);
|
||||
amount += spellInfo->Effects[EFFECT_0].CalcValue(); // 130
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,34 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ContentData
|
||||
go_cat_figurine (the "trap" version of GO, two different exist)
|
||||
go_barov_journal
|
||||
go_ethereum_prison
|
||||
go_ethereum_stasis
|
||||
go_sacred_fire_of_life
|
||||
go_shrine_of_the_birds
|
||||
go_southfury_moonstone
|
||||
go_resonite_cask
|
||||
go_tablet_of_the_seven
|
||||
go_tele_to_dalaran_crystal
|
||||
go_tele_to_violet_stand
|
||||
go_scourge_cage
|
||||
go_jotunheim_cage
|
||||
go_table_theka
|
||||
go_soulwell
|
||||
go_bashir_crystalforge
|
||||
go_soulwell
|
||||
go_dragonflayer_cage
|
||||
go_tadpole_cage
|
||||
go_amberpine_outhouse
|
||||
go_hive_pod
|
||||
go_veil_skith_cage
|
||||
EndContentData */
|
||||
|
||||
#include "CellImpl.h"
|
||||
#include "GameObjectAI.h"
|
||||
#include "GameTime.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
@@ -1385,41 +1359,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## go_inconspicuous_landmark
|
||||
######*/
|
||||
|
||||
enum InconspicuousLandmark
|
||||
{
|
||||
SPELL_SUMMON_PIRATES_TREASURE_AND_TRIGGER_MOB = 11462,
|
||||
ITEM_CUERGOS_KEY = 9275,
|
||||
};
|
||||
|
||||
class go_inconspicuous_landmark : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
go_inconspicuous_landmark() : GameObjectScript("go_inconspicuous_landmark")
|
||||
{
|
||||
_lastUsedTime = GameTime::GetGameTime().count();
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, GameObject* /*go*/) override
|
||||
{
|
||||
if (player->HasItemCount(ITEM_CUERGOS_KEY))
|
||||
return true;
|
||||
|
||||
if (_lastUsedTime > GameTime::GetGameTime().count())
|
||||
return true;
|
||||
|
||||
_lastUsedTime = GameTime::GetGameTime().count() + MINUTE;
|
||||
player->CastSpell(player, SPELL_SUMMON_PIRATES_TREASURE_AND_TRIGGER_MOB, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _lastUsedTime;
|
||||
};
|
||||
|
||||
/*######
|
||||
## go_soulwell
|
||||
######*/
|
||||
@@ -1989,7 +1928,6 @@ void AddSC_go_scripts()
|
||||
new go_arcane_prison();
|
||||
new go_jotunheim_cage();
|
||||
new go_table_theka();
|
||||
new go_inconspicuous_landmark();
|
||||
new go_soulwell();
|
||||
new go_dragonflayer_cage();
|
||||
new go_amberpine_outhouse();
|
||||
|
||||
@@ -2506,9 +2506,9 @@ enum VenomhideHatchlingMisc
|
||||
ITEM_VENOMHIDE_BABY_TOOTH = 47196,
|
||||
|
||||
MODEL_BABY_RAPTOR = 29251,
|
||||
MODEL_BABY_RAPTOR_REPTILE_EYES = 29809,
|
||||
MODEL_ADOLESCENT_RAPTOR = 29103,
|
||||
MODEL_FULL_RAPTOR = 5291,
|
||||
MODEL_BABY_RAPTOR_REPTILE_EYES = 29274,
|
||||
MODEL_ADOLESCENT_RAPTOR = 29275,
|
||||
MODEL_FULL_RAPTOR = 29276,
|
||||
};
|
||||
|
||||
enum VenomhideHatchlingTexts
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __WARHEAD_SECRETMGR_H__
|
||||
#define __WARHEAD_SECRETMGR_H__
|
||||
#ifndef __ACORE_SECRETMGR_H__
|
||||
#define __ACORE_SECRETMGR_H__
|
||||
|
||||
#include "BigNumber.h"
|
||||
#include "Common.h"
|
||||
|
||||
@@ -216,7 +216,7 @@ enum FactionTemplates
|
||||
#define MIN_REPUTATION_RANK (REP_HATED)
|
||||
#define MAX_REPUTATION_RANK 8
|
||||
|
||||
#define MAX_SPILLOVER_FACTIONS 4
|
||||
#define MAX_SPILLOVER_FACTIONS 6
|
||||
|
||||
enum MoneyConstants
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user