aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp237
-rw-r--r--src/server/game/AI/CoreAI/PetAI.h14
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h11
-rw-r--r--src/server/game/AI/CreatureAI.h4
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp76
-rw-r--r--src/server/game/Entities/Creature/Creature.h2
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp1
-rw-r--r--src/server/game/Entities/Player/Player.cpp144
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp108
-rw-r--r--src/server/game/Entities/Unit/Unit.h42
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h29
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp16
-rw-r--r--src/server/game/Handlers/PetHandler.cpp4
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp6
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp4
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp108
-rw-r--r--src/server/game/Scripting/ScriptMgr.h31
-rw-r--r--src/server/game/Scripting/ScriptSystem.cpp122
-rw-r--r--src/server/game/Scripting/ScriptSystem.h24
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp19
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp49
-rw-r--r--src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp2
-rw-r--r--src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp2
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp4
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp2
-rw-r--r--src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp2
-rw-r--r--src/server/scripts/Kalimdor/azuremyst_isle.cpp28
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp30
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp6
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp12
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.h8
-rw-r--r--src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp117
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp2
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp4
-rw-r--r--src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp6
-rw-r--r--src/server/scripts/Northrend/borean_tundra.cpp2
-rw-r--r--src/server/scripts/Northrend/sholazar_basin.cpp52
-rw-r--r--src/server/scripts/Outland/BlackTemple/illidari_council.cpp2
-rw-r--r--src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp2
-rw-r--r--src/server/scripts/Outland/netherstorm.cpp6
-rw-r--r--src/server/scripts/Outland/shadowmoon_valley.cpp4
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp177
-rw-r--r--src/server/scripts/Spells/spell_holiday.cpp169
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp16
-rw-r--r--src/server/scripts/World/npc_professions.cpp4
-rw-r--r--src/server/scripts/World/npcs_special.cpp2
-rw-r--r--src/tools/vmap4_extractor/vmapexport.cpp2
49 files changed, 950 insertions, 768 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index 2fdb3cd39c6..3d9e0486838 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -44,10 +44,6 @@ PetAI::PetAI(Creature* c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK)
UpdateAllies();
}
-void PetAI::EnterEvadeMode()
-{
-}
-
bool PetAI::_needToStop()
{
// This is needed for charmed creatures, as once their target was reset other effects can trigger threat
@@ -74,12 +70,13 @@ void PetAI::_stopAttack()
me->InterruptNonMeleeSpells(false);
me->SendMeleeAttackStop(); // Should stop pet's attack button from flashing
me->GetCharmInfo()->SetIsCommandAttack(false);
+ ClearCharmInfoFlags();
HandleReturnMovement();
}
void PetAI::UpdateAI(const uint32 diff)
{
- if (!me->isAlive())
+ if (!me->isAlive() || !me->GetCharmInfo())
return;
Unit* owner = me->GetCharmerOrOwner();
@@ -107,39 +104,33 @@ void PetAI::UpdateAI(const uint32 diff)
}
// Check before attacking to prevent pets from leaving stay position
- if (CanAttack(me->getVictim()))
+ if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
+ {
+ if (me->GetCharmInfo()->IsCommandAttack() || (me->GetCharmInfo()->IsAtStay() && me->IsWithinMeleeRange(me->getVictim())))
+ DoMeleeAttackIfReady();
+ }
+ else
DoMeleeAttackIfReady();
}
- else if (owner && me->GetCharmInfo()) //no victim
+ else
{
- // Only aggressive pets do target search every update.
- // Defensive pets do target search only in these cases:
- // * Owner attacks something - handled by OwnerAttacked()
- // * Owner receives damage - handled by OwnerDamagedBy()
- // * Pet is in combat and current target dies - handled by KilledUnit()
- if (me->HasReactState(REACT_AGGRESSIVE))
+ if (me->HasReactState(REACT_AGGRESSIVE) || me->GetCharmInfo()->IsAtStay())
{
- Unit* nextTarget = SelectNextTarget();
+ // Every update we need to check targets only in certain cases
+ // Aggressive - Allow auto select if owner or pet don't have a target
+ // Stay - Only pick from pet or owner targets / attackers so targets won't run by
+ // while chasing our owner. Don't do auto select.
+ // All other cases (ie: defensive) - Targets are assigned by AttackedBy(), OwnerAttackedBy(), OwnerAttacked(), etc.
+ Unit* nextTarget = SelectNextTarget(me->HasReactState(REACT_AGGRESSIVE));
if (nextTarget)
AttackStart(nextTarget);
else
- {
- me->GetCharmInfo()->SetIsCommandAttack(false);
HandleReturnMovement();
- }
}
else
- {
- me->GetCharmInfo()->SetIsCommandAttack(false);
HandleReturnMovement();
- }
}
- else if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) // no charm info and no victim
- me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle());
-
- if (!me->GetCharmInfo())
- return;
// Autocast (casted only in combat or persistent spells in any state)
if (!me->HasUnitState(UNIT_STATE_CASTING))
@@ -190,7 +181,8 @@ void PetAI::UpdateAI(const uint32 diff)
spellUsed = true;
}
}
-
+ if (spellInfo->HasEffect(SPELL_EFFECT_JUMP_DEST))
+ continue; //pets must jump only to target
// No enemy, check friendly
if (!spellUsed)
{
@@ -313,15 +305,11 @@ void PetAI::KilledUnit(Unit* victim)
me->InterruptNonMeleeSpells(false);
me->SendMeleeAttackStop(); // Stops the pet's 'Attack' button from flashing
- Unit* nextTarget = SelectNextTarget();
-
- if (nextTarget)
+ // Before returning to owner, see if there are more things to attack
+ if (Unit* nextTarget = SelectNextTarget(false))
AttackStart(nextTarget);
else
- {
- me->GetCharmInfo()->SetIsCommandAttack(false);
HandleReturnMovement(); // Return
- }
}
void PetAI::AttackStart(Unit* target)
@@ -332,17 +320,14 @@ void PetAI::AttackStart(Unit* target)
if (!CanAttack(target))
return;
- if (Unit* owner = me->GetOwner())
- owner->SetInCombatWith(target);
-
// Only chase if not commanded to stay or if stay but commanded to attack
DoAttack(target, (!me->GetCharmInfo()->HasCommandState(COMMAND_STAY) || me->GetCharmInfo()->IsCommandAttack()));
}
-void PetAI::OwnerDamagedBy(Unit* attacker)
+void PetAI::OwnerAttackedBy(Unit* attacker)
{
- // Called when owner takes damage. Allows defensive pets to know
- // that their owner might need help
+ // Called when owner takes damage. This function helps keep pets from running off
+ // simply due to owner gaining aggro.
if (!attacker)
return;
@@ -380,10 +365,12 @@ void PetAI::OwnerAttacked(Unit* target)
AttackStart(target);
}
-Unit* PetAI::SelectNextTarget()
+Unit* PetAI::SelectNextTarget(bool allowAutoSelect) const
{
- // Provides next target selection after current target death
- // Targets are not evaluated here for being valid attack targets
+ // Provides next target selection after current target death.
+ // This function should only be called internally by the AI
+ // Targets are not evaluated here for being valid targets, that is done in _CanAttack()
+ // The parameter: allowAutoSelect lets us disable aggressive pet auto targeting for certain situations
// Passive pets don't do next target selection
if (me->HasReactState(REACT_PASSIVE))
@@ -406,17 +393,17 @@ Unit* PetAI::SelectNextTarget()
// Check owner victim
// 3.0.2 - Pets now start attacking their owners victim in defensive mode as soon as the hunter does
if (Unit* ownerVictim = me->GetCharmerOrOwner()->getVictim())
- if (!ownerVictim->HasBreakableByDamageCrowdControlAura())
return ownerVictim;
// Neither pet or owner had a target and aggressive pets can pick any target
- // Note: Creature::SelectNearestTarget() If no distance is supplied it uses MAX_VISIBILITY_DISTANCE
- // We also want to lock this to LOS so pet doesn't go running through walls and stuff
- if (me->HasReactState(REACT_AGGRESSIVE))
- if (Unit* nearTarget = me->ToCreature()->SelectNearestTarget())
- if (nearTarget->IsHostileTo(me) && !nearTarget->HasBreakableByDamageCrowdControlAura())
- if (nearTarget->IsWithinLOS(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()))
- return nearTarget;
+ // To prevent aggressive pets from chain selecting targets and running off, we
+ // only select a random target if certain conditions are met.
+ if (me->HasReactState(REACT_AGGRESSIVE) && allowAutoSelect)
+ {
+ if (!me->GetCharmInfo()->IsReturning() || me->GetCharmInfo()->IsFollowing() || me->GetCharmInfo()->IsAtStay())
+ if (Unit* nearTarget = me->ToCreature()->SelectNearestHostileUnitInAggroRange(true))
+ return nearTarget;
+ }
// Default - no valid targets
return NULL;
@@ -426,6 +413,11 @@ void PetAI::HandleReturnMovement()
{
// Handles moving the pet back to stay or owner
+ // Prevent activating movement when under control of spells
+ // such as "Eyes of the Beast"
+ if (me->isCharmed())
+ return;
+
if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
{
if (!me->GetCharmInfo()->IsAtStay() && !me->GetCharmInfo()->IsReturning())
@@ -436,6 +428,7 @@ void PetAI::HandleReturnMovement()
float x, y, z;
me->GetCharmInfo()->GetStayPosition(x, y, z);
+ ClearCharmInfoFlags();
me->GetCharmInfo()->SetIsReturning(true);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MovePoint(me->GetGUIDLow(), x, y, z);
@@ -448,6 +441,7 @@ void PetAI::HandleReturnMovement()
{
if (!me->GetCharmInfo()->IsCommandAttack())
{
+ ClearCharmInfoFlags();
me->GetCharmInfo()->SetIsReturning(true);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle());
@@ -458,33 +452,33 @@ void PetAI::HandleReturnMovement()
void PetAI::DoAttack(Unit* target, bool chase)
{
- // Handles attack with or without chase and also resets all
- // PetAI flags for next update / creature kill
+ // Handles attack with or without chase and also resets flags
+ // for next update / creature kill
- // me->GetCharmInfo()->SetIsCommandAttack(false);
+ if (me->Attack(target, true))
+ {
+ if (Unit* owner = me->GetOwner())
+ owner->SetInCombatWith(target);
- // The following conditions are true if chase == true
- // (Follow && (Aggressive || Defensive))
- // ((Stay || Follow) && (Passive && player clicked attack))
+ // Play sound to let the player know the pet is attacking something it picked on its own
+ if (me->HasReactState(REACT_AGGRESSIVE) && !me->GetCharmInfo()->IsCommandAttack())
+ me->SendPetAIReaction(me->GetGUID());
- if (chase)
- {
- if (me->Attack(target, true))
+
+ if (chase)
+ {
+ ClearCharmInfoFlags();
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveChase(target);
+ }
+ else // (Stay && ((Aggressive || Defensive) && In Melee Range)))
{
- me->GetCharmInfo()->SetIsAtStay(false);
- me->GetCharmInfo()->SetIsFollowing(false);
- me->GetCharmInfo()->SetIsReturning(false);
+ ClearCharmInfoFlags();
+ me->GetCharmInfo()->SetIsAtStay(true);
me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveChase(target);
+ me->GetMotionMaster()->MoveIdle();
}
}
- else // (Stay && ((Aggressive || Defensive) && In Melee Range)))
- {
- me->GetCharmInfo()->SetIsAtStay(true);
- me->GetCharmInfo()->SetIsFollowing(false);
- me->GetCharmInfo()->SetIsReturning(false);
- me->Attack(target, true);
- }
}
void PetAI::MovementInform(uint32 moveType, uint32 data)
@@ -498,10 +492,8 @@ void PetAI::MovementInform(uint32 moveType, uint32 data)
// pet's GUIDLow since we set that as the waypoint ID
if (data == me->GetGUIDLow() && me->GetCharmInfo()->IsReturning())
{
+ ClearCharmInfoFlags();
me->GetCharmInfo()->SetIsAtStay(true);
- me->GetCharmInfo()->SetIsReturning(false);
- me->GetCharmInfo()->SetIsFollowing(false);
- me->GetCharmInfo()->SetIsCommandAttack(false);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
}
@@ -513,10 +505,8 @@ void PetAI::MovementInform(uint32 moveType, uint32 data)
// otherwise we're probably chasing a creature
if (me->GetCharmerOrOwner() && me->GetCharmInfo() && data == me->GetCharmerOrOwner()->GetGUIDLow() && me->GetCharmInfo()->IsReturning())
{
- me->GetCharmInfo()->SetIsAtStay(false);
- me->GetCharmInfo()->SetIsReturning(false);
+ ClearCharmInfoFlags();
me->GetCharmInfo()->SetIsFollowing(true);
- me->GetCharmInfo()->SetIsCommandAttack(false);
}
break;
}
@@ -527,32 +517,55 @@ void PetAI::MovementInform(uint32 moveType, uint32 data)
bool PetAI::CanAttack(Unit* target)
{
- // Evaluates wether a pet can attack a specific
- // target based on CommandState, ReactState and other flags
+ // Evaluates wether a pet can attack a specific target based on CommandState, ReactState and other flags
+ // IMPORTANT: The order in which things are checked is important, be careful if you add or remove checks
- // Can't attack dead targets...
- if (!target->isAlive())
+ // Hmmm...
+ if (!target)
return false;
- // Returning - check first since pets returning ignore attacks
- if (me->GetCharmInfo()->IsReturning())
+ if (!target->isAlive())
+ {
+ // Clear target to prevent getting stuck on dead targets
+ me->AttackStop();
+ me->InterruptNonMeleeSpells(false);
+ me->SendMeleeAttackStop();
return false;
+ }
- // Passive - check now so we don't have to worry about passive in later checks
+ // Passive - passive pets can attack if told to
if (me->HasReactState(REACT_PASSIVE))
return me->GetCharmInfo()->IsCommandAttack();
- // Follow
- if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
- return true;
+ // CC - mobs under crowd control can be attacked if owner commanded
+ if (target->HasBreakableByDamageCrowdControlAura())
+ return me->GetCharmInfo()->IsCommandAttack();
+
+ // Returning - pets ignore attacks only if owner clicked follow
+ if (me->GetCharmInfo()->IsReturning())
+ return !me->GetCharmInfo()->IsCommandFollow();
// Stay - can attack if target is within range or commanded to
if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
return (me->IsWithinMeleeRange(target) || me->GetCharmInfo()->IsCommandAttack());
- // Pets commanded to attack should not stop their approach if attacked by another creature
- if (me->getVictim() && (me->getVictim() != target))
- return !me->GetCharmInfo()->IsCommandAttack();
+ // Pets attacking something (or chasing) should only switch targets if owner tells them to
+ if (me->getVictim() && me->getVictim() != target)
+ {
+ // Check if our owner selected this target and clicked "attack"
+ Unit* ownerTarget = NULL;
+ if (Player* owner = me->GetCharmerOrOwner()->ToPlayer())
+ ownerTarget = owner->GetSelectedUnit();
+ else
+ ownerTarget = me->GetCharmerOrOwner()->getVictim();
+
+ if (ownerTarget && me->GetCharmInfo()->IsCommandAttack())
+ return (target->GetGUID() == ownerTarget->GetGUID());
+ }
+
+ // Follow
+ if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
+ return !me->GetCharmInfo()->IsReturning();
// default, though we shouldn't ever get here
return false;
@@ -565,11 +578,55 @@ void PetAI::ReceiveEmote(Player* player, uint32 emote)
{
case TEXT_EMOTE_COWER:
if (me->isPet() && me->ToPet()->IsPetGhoul())
- me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
+ me->HandleEmoteCommand(/*EMOTE_ONESHOT_ROAR*/EMOTE_ONESHOT_OMNICAST_GHOUL);
break;
case TEXT_EMOTE_ANGRY:
if (me->isPet() && me->ToPet()->IsPetGhoul())
- me->HandleEmoteCommand(EMOTE_ONESHOT_COWER);
+ me->HandleEmoteCommand(/*EMOTE_ONESHOT_COWER*/EMOTE_STATE_STUN);
+ break;
+ case TEXT_EMOTE_GLARE:
+ if (me->isPet() && me->ToPet()->IsPetGhoul())
+ me->HandleEmoteCommand(EMOTE_STATE_STUN);
+ break;
+ case TEXT_EMOTE_SOOTHE:
+ if (me->isPet() && me->ToPet()->IsPetGhoul())
+ me->HandleEmoteCommand(EMOTE_ONESHOT_OMNICAST_GHOUL);
break;
}
}
+
+void PetAI::ClearCharmInfoFlags()
+{
+ // Quick access to set all flags to FALSE
+
+ CharmInfo* ci = me->GetCharmInfo();
+
+ if (ci)
+ {
+ ci->SetIsAtStay(false);
+ ci->SetIsCommandAttack(false);
+ ci->SetIsCommandFollow(false);
+ ci->SetIsFollowing(false);
+ ci->SetIsReturning(false);
+ }
+}
+
+void PetAI::AttackedBy(Unit* attacker)
+{
+ // Called when pet takes damage. This function helps keep pets from running off
+ // simply due to gaining aggro.
+
+ if (!attacker)
+ return;
+
+ // Passive pets don't do anything
+ if (me->HasReactState(REACT_PASSIVE))
+ return;
+
+ // Prevent pet from disengaging from current target
+ if (me->getVictim() && me->getVictim()->isAlive())
+ return;
+
+ // Continue to evaluate and attack if necessary
+ AttackStart(attacker);
+}
diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h
index d7f1dca3fbf..8a8853b19b5 100644
--- a/src/server/game/AI/CoreAI/PetAI.h
+++ b/src/server/game/AI/CoreAI/PetAI.h
@@ -31,17 +31,24 @@ class PetAI : public CreatureAI
explicit PetAI(Creature* c);
- void EnterEvadeMode();
void UpdateAI(const uint32);
static int Permissible(const Creature*);
void KilledUnit(Unit* /*victim*/);
void AttackStart(Unit* target);
void MovementInform(uint32 moveType, uint32 data);
- void OwnerDamagedBy(Unit* attacker);
+ void OwnerAttackedBy(Unit* attacker);
void OwnerAttacked(Unit* target);
+ void AttackedBy(Unit* attacker);
void ReceiveEmote(Player* player, uint32 textEmote);
+ // The following aren't used by the PetAI but need to be defined to override
+ // default CreatureAI functions which interfere with the PetAI
+ //
+ void MoveInLineOfSight(Unit* /*who*/) {} // CreatureAI interferes with returning pets
+ void MoveInLineOfSight_Safe(Unit* /*who*/) {} // CreatureAI interferes with returning pets
+ void EnterEvadeMode() {} // For fleeing, pets don't use this type of Evade mechanic
+
private:
bool _isVisible(Unit*) const;
bool _needToStop(void);
@@ -54,10 +61,11 @@ class PetAI : public CreatureAI
std::set<uint64> m_AllySet;
uint32 m_updateAlliesTimer;
- Unit* SelectNextTarget();
+ Unit* SelectNextTarget(bool allowAutoSelect) const;
void HandleReturnMovement();
void DoAttack(Unit* target, bool chase);
bool CanAttack(Unit* target);
+ void ClearCharmInfoFlags();
};
#endif
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 2eab0e89fcd..8b31bb5c54d 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -29,17 +29,6 @@ class Quest;
class Unit;
struct AISpellInfoType;
-// Default script texts
-enum GeneralScriptTexts
-{
- DEFAULT_TEXT = -1000000,
- EMOTE_GENERIC_FRENZY_KILL = -1000001,
- EMOTE_GENERIC_FRENZY = -1000002,
- EMOTE_GENERIC_ENRAGED = -1000003,
- EMOTE_GENERIC_BERSERK = -1000004,
- EMOTE_GENERIC_BERSERK_RAID = -1000005 // RaidBossEmote version of the previous one
-};
-
//Selection method used by SelectTarget
enum SelectAggroTarget
{
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index d3ad27935ca..4f61e168a87 100644
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -117,7 +117,7 @@ class CreatureAI : public UnitAI
virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spell*/) {}
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
- //virtual void AttackedBy(Unit* attacker);
+ virtual void AttackedBy(Unit* /*attacker*/) {}
virtual bool IsEscorted() { return false; }
// Called when creature is spawned or respawned (for reseting variables)
@@ -137,7 +137,7 @@ class CreatureAI : public UnitAI
virtual void ReceiveEmote(Player* /*player*/, uint32 /*emoteId*/) {}
// Called when owner takes damage
- virtual void OwnerDamagedBy(Unit* /*attacker*/) {}
+ virtual void OwnerAttackedBy(Unit* /*attacker*/) {}
// Called when owner attacks something
virtual void OwnerAttacked(Unit* /*target*/) {}
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 41d48cbfc02..02026a5a5a7 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -412,6 +412,16 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData* data)
SetPvP(false);
}
+ // updates spell bars for vehicles and set player's faction - should be called here, to overwrite faction that is set from the new template
+ if (IsVehicle())
+ {
+ if (Player* owner = Creature::GetCharmerOrOwnerPlayerOrPlayerItself()) // this check comes in case we don't have a player
+ {
+ setFaction(owner->getFaction()); // vehicles should have same as owner faction
+ owner->VehicleSpellInitialize();
+ }
+ }
+
// trigger creature is always not selectable and can not be attacked
if (isTrigger())
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
@@ -2651,3 +2661,69 @@ bool Creature::SetHover(bool enable)
SendMessageToSet(&data, false);
return true;
}
+
+float Creature::GetAggroRange(Unit const* target) const
+{
+ // Determines the aggro range for creatures (usually pets), used mainly for aggressive pet target selection.
+ // Based on data from wowwiki due to lack of 3.3.5a data
+
+ if (target && this->isPet())
+ {
+ uint32 targetLevel = 0;
+
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ targetLevel = target->getLevelForTarget(this);
+ else if (target->GetTypeId() == TYPEID_UNIT)
+ targetLevel = target->ToCreature()->getLevelForTarget(this);
+
+ uint32 myLevel = getLevelForTarget(target);
+ int32 levelDiff = int32(targetLevel) - int32(myLevel);
+
+ // The maximum Aggro Radius is capped at 45 yards (25 level difference)
+ if (levelDiff < -25)
+ levelDiff = -25;
+
+ // The base aggro radius for mob of same level
+ float aggroRadius = 20;
+
+ // Aggro Radius varies with level difference at a rate of roughly 1 yard/level
+ aggroRadius -= (float)levelDiff;
+
+ // detect range auras
+ aggroRadius += GetTotalAuraModifier(SPELL_AURA_MOD_DETECT_RANGE);
+
+ // detected range auras
+ aggroRadius += target->GetTotalAuraModifier(SPELL_AURA_MOD_DETECTED_RANGE);
+
+ // Just in case, we don't want pets running all over the map
+ if (aggroRadius > MAX_AGGRO_RADIUS)
+ aggroRadius = MAX_AGGRO_RADIUS;
+
+ // Minimum Aggro Radius for a mob seems to be combat range (5 yards)
+ // hunter pets seem to ignore minimum aggro radius so we'll default it a little higher
+ if (aggroRadius < 10)
+ aggroRadius = 10;
+
+ return (aggroRadius);
+ }
+
+ // Default
+ return 0.0f;
+}
+
+Unit* Creature::SelectNearestHostileUnitInAggroRange(bool useLOS) const
+{
+ // Selects nearest hostile target within creature's aggro range. Used primarily by
+ // pets set to aggressive. Will not return neutral or friendly targets.
+
+ Unit* target = NULL;
+
+ {
+ Trinity::NearestHostileUnitInAggroRangeCheck u_check(this, useLOS);
+ Trinity::UnitSearcher<Trinity::NearestHostileUnitInAggroRangeCheck> searcher(this, target, u_check);
+
+ VisitNearbyGridObject(MAX_AGGRO_RADIUS, searcher);
+ }
+
+ return target;
+}
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 4651adb7006..25042fb5b3f 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -616,12 +616,14 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
bool canStartAttack(Unit const* u, bool force) const;
float GetAttackDistance(Unit const* player) const;
+ float GetAggroRange(Unit const* target) const;
void SendAIReaction(AiReaction reactionType);
Unit* SelectNearestTarget(float dist = 0) const;
Unit* SelectNearestTargetInAttackDistance(float dist = 0) const;
Player* SelectNearestPlayer(float distance = 0) const;
+ Unit* SelectNearestHostileUnitInAggroRange(bool useLOS = false) const;
void DoFleeToGetAssistance();
void CallForHelp(float fRadius);
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index 9337add8ba3..5dcc0246651 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -75,6 +75,7 @@ void Pet::AddToWorld()
if (GetCharmInfo() && GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
{
GetCharmInfo()->SetIsCommandAttack(false);
+ GetCharmInfo()->SetIsCommandFollow(false);
GetCharmInfo()->SetIsAtStay(false);
GetCharmInfo()->SetIsFollowing(false);
GetCharmInfo()->SetIsReturning(false);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index bb5659eeb25..606bcc6cfec 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -7023,7 +7023,7 @@ void Player::RewardReputation(Unit* victim, float rate)
if (Rep->RepFaction1 && (!Rep->TeamDependent || team == ALLIANCE))
{
- int32 donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue1, ChampioningFaction ? ChampioningFaction : Rep->RepFaction1, false);
+ int32 donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue1, ChampioningFaction ? ChampioningFaction : Rep->RepFaction1);
donerep1 = int32(donerep1*(rate + favored_rep_mult));
if (recruitAFriend)
@@ -7037,7 +7037,7 @@ void Player::RewardReputation(Unit* victim, float rate)
if (Rep->RepFaction2 && (!Rep->TeamDependent || team == HORDE))
{
- int32 donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue2, ChampioningFaction ? ChampioningFaction : Rep->RepFaction2, false);
+ int32 donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue2, ChampioningFaction ? ChampioningFaction : Rep->RepFaction2);
donerep2 = int32(donerep2*(rate + favored_rep_mult));
if (recruitAFriend)
@@ -7084,25 +7084,25 @@ void Player::RewardReputation(Quest const* quest)
uint32 row = ((quest->RewardFactionValueId[i] < 0) ? 1 : 0) + 1;
uint32 field = abs(quest->RewardFactionValueId[i]);
- if (const QuestFactionRewEntry* pRow = sQuestFactionRewardStore.LookupEntry(row))
+ if (QuestFactionRewEntry const* pRow = sQuestFactionRewardStore.LookupEntry(row))
{
int32 repPoints = pRow->QuestRewFactionValue[field];
if (!repPoints)
continue;
if (quest->IsDaily())
- repPoints = CalculateReputationGain(REPUTATION_SOURCE_DAILY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i], true);
+ repPoints = CalculateReputationGain(REPUTATION_SOURCE_DAILY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i]);
else if (quest->IsWeekly())
- repPoints = CalculateReputationGain(REPUTATION_SOURCE_WEEKLY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i], true);
+ repPoints = CalculateReputationGain(REPUTATION_SOURCE_WEEKLY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i]);
else if (quest->IsMonthly())
- repPoints = CalculateReputationGain(REPUTATION_SOURCE_MONTHLY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i], true);
+ repPoints = CalculateReputationGain(REPUTATION_SOURCE_MONTHLY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i]);
else
- repPoints = CalculateReputationGain(REPUTATION_SOURCE_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i], true);
+ repPoints = CalculateReputationGain(REPUTATION_SOURCE_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i]);
if (recruitAFriend)
repPoints = int32(repPoints * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
- if (const FactionEntry* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i]))
+ if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i]))
GetReputationMgr().ModifyReputation(factionEntry, repPoints);
}
}
@@ -12528,22 +12528,22 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
}
}
-void Player::DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check)
+void Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, bool unequip_check)
{
- sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: DestroyItemCount item = %u, count = %u", item, count);
+ sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: DestroyItemCount item = %u, count = %u", itemEntry, count);
uint32 remcount = 0;
// in inventory
for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
{
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
- if (pItem->GetEntry() == item && !pItem->IsInTrade())
+ if (item->GetEntry() == itemEntry && !item->IsInTrade())
{
- if (pItem->GetCount() + remcount <= count)
+ if (item->GetCount() + remcount <= count)
{
// all items in inventory can unequipped
- remcount += pItem->GetCount();
+ remcount += item->GetCount();
DestroyItem(INVENTORY_SLOT_BAG_0, i, update);
if (remcount >= count)
@@ -12551,11 +12551,11 @@ void Player::DestroyItemCount(uint32 item, uint32 count, bool update, bool unequ
}
else
{
- ItemRemovedQuestCheck(pItem->GetEntry(), count - remcount);
- pItem->SetCount(pItem->GetCount() - count + remcount);
+ ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
+ item->SetCount(item->GetCount() - count + remcount);
if (IsInWorld() && update)
- pItem->SendUpdateToPlayer(this);
- pItem->SetState(ITEM_CHANGED, this);
+ item->SendUpdateToPlayer(this);
+ item->SetState(ITEM_CHANGED, this);
return;
}
}
@@ -12565,18 +12565,18 @@ void Player::DestroyItemCount(uint32 item, uint32 count, bool update, bool unequ
// in inventory bags
for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
{
- if (Bag* pBag = GetBagByPos(i))
+ if (Bag* bag = GetBagByPos(i))
{
- for (uint32 j = 0; j < pBag->GetBagSize(); j++)
+ for (uint32 j = 0; j < bag->GetBagSize(); j++)
{
- if (Item* pItem = pBag->GetItemByPos(j))
+ if (Item* item = bag->GetItemByPos(j))
{
- if (pItem->GetEntry() == item && !pItem->IsInTrade())
+ if (item->GetEntry() == itemEntry && !item->IsInTrade())
{
// all items in bags can be unequipped
- if (pItem->GetCount() + remcount <= count)
+ if (item->GetCount() + remcount <= count)
{
- remcount += pItem->GetCount();
+ remcount += item->GetCount();
DestroyItem(i, j, update);
if (remcount >= count)
@@ -12584,11 +12584,11 @@ void Player::DestroyItemCount(uint32 item, uint32 count, bool update, bool unequ
}
else
{
- ItemRemovedQuestCheck(pItem->GetEntry(), count - remcount);
- pItem->SetCount(pItem->GetCount() - count + remcount);
+ ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
+ item->SetCount(item->GetCount() - count + remcount);
if (IsInWorld() && update)
- pItem->SendUpdateToPlayer(this);
- pItem->SetState(ITEM_CHANGED, this);
+ item->SendUpdateToPlayer(this);
+ item->SetState(ITEM_CHANGED, this);
return;
}
}
@@ -12600,15 +12600,15 @@ void Player::DestroyItemCount(uint32 item, uint32 count, bool update, bool unequ
// in equipment and bag list
for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)
{
- if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
- if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
+ if (item && item->GetEntry() == itemEntry && !item->IsInTrade())
{
- if (pItem->GetCount() + remcount <= count)
+ if (item->GetCount() + remcount <= count)
{
if (!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false) == EQUIP_ERR_OK)
{
- remcount += pItem->GetCount();
+ remcount += item->GetCount();
DestroyItem(INVENTORY_SLOT_BAG_0, i, update);
if (remcount >= count)
@@ -12617,16 +12617,78 @@ void Player::DestroyItemCount(uint32 item, uint32 count, bool update, bool unequ
}
else
{
- ItemRemovedQuestCheck(pItem->GetEntry(), count - remcount);
- pItem->SetCount(pItem->GetCount() - count + remcount);
+ ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
+ item->SetCount(item->GetCount() - count + remcount);
+ if (IsInWorld() && update)
+ item->SendUpdateToPlayer(this);
+ item->SetState(ITEM_CHANGED, this);
+ return;
+ }
+ }
+ }
+ }
+
+ // in bank
+ for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
+ {
+ if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ {
+ if (item->GetEntry() == itemEntry && !item->IsInTrade())
+ {
+ if (item->GetCount() + remcount <= count)
+ {
+ remcount += item->GetCount();
+ DestroyItem(INVENTORY_SLOT_BAG_0, i, update);
+ if (remcount >= count)
+ return;
+ }
+ else
+ {
+ ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
+ item->SetCount(item->GetCount() - count + remcount);
if (IsInWorld() && update)
- pItem->SendUpdateToPlayer(this);
- pItem->SetState(ITEM_CHANGED, this);
+ item->SendUpdateToPlayer(this);
+ item->SetState(ITEM_CHANGED, this);
return;
}
}
}
}
+
+ // in bank bags
+ for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
+ {
+ if (Bag* bag = GetBagByPos(i))
+ {
+ for (uint32 j = 0; j < bag->GetBagSize(); j++)
+ {
+ if (Item* item = bag->GetItemByPos(j))
+ {
+ if (item->GetEntry() == itemEntry && !item->IsInTrade())
+ {
+ // all items in bags can be unequipped
+ if (item->GetCount() + remcount <= count)
+ {
+ remcount += item->GetCount();
+ DestroyItem(i, j, update);
+
+ if (remcount >= count)
+ return;
+ }
+ else
+ {
+ ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
+ item->SetCount(item->GetCount() - count + remcount);
+ if (IsInWorld() && update)
+ item->SendUpdateToPlayer(this);
+ item->SetState(ITEM_CHANGED, this);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
}
void Player::DestroyZoneLimitedItem(bool update, uint32 new_zone)
@@ -16764,13 +16826,11 @@ bool Player::LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, flo
return true;
}
-void Player::SetHomebind(WorldLocation const& /*loc*/, uint32 /*area_id*/)
+void Player::SetHomebind(WorldLocation const& loc, uint32 areaId)
{
- m_homebindMapId = GetMapId();
- m_homebindAreaId = GetAreaId();
- m_homebindX = GetPositionX();
- m_homebindY = GetPositionY();
- m_homebindZ = GetPositionZ();
+ loc.GetPosition(m_homebindX, m_homebindY, m_homebindZ);
+ m_homebindMapId = loc.GetMapId();
+ m_homebindAreaId = areaId;
// update sql homebind
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_HOMEBIND);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index cdeeb3aa9df..4baa17d4377 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2541,7 +2541,7 @@ class Player : public Unit, public GridObject<Player>
float m_recallO;
void SaveRecallPosition();
- void SetHomebind(WorldLocation const& loc, uint32 area_id);
+ void SetHomebind(WorldLocation const& loc, uint32 areaId);
// Homebind coordinates
uint32 m_homebindMapId;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index f470862c890..b6573fe4f8a 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -559,18 +559,22 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
if (IsAIEnabled)
GetAI()->DamageDealt(victim, damage, damagetype);
- if (victim->GetTypeId() == TYPEID_PLAYER)
+ if (victim->GetTypeId() == TYPEID_PLAYER && this != victim)
{
- if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD))
- return 0;
-
// Signal to pets that their owner was attacked
Pet* pet = victim->ToPlayer()->GetPet();
if (pet && pet->isAlive())
- pet->AI()->OwnerDamagedBy(this);
+ pet->AI()->OwnerAttackedBy(this);
+
+ if (victim->ToPlayer()->GetCommandStatus(CHEAT_GOD))
+ return 0;
}
+ // Signal the pet it was attacked so the AI can respond if needed
+ if (victim->GetTypeId() == TYPEID_UNIT && this != victim && victim->isPet() && victim->isAlive())
+ victim->ToPet()->AI()->AttackedBy(this);
+
if (damagetype != NODAMAGE)
{
// interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
@@ -1018,6 +1022,9 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 dama
break;
}
+ // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
+ sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage);
+
// Calculate absorb resist
if (damage > 0)
{
@@ -1114,6 +1121,9 @@ void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* dam
damage = MeleeDamageBonusDone(damageInfo->target, damage, damageInfo->attackType);
damage = damageInfo->target->MeleeDamageBonusTaken(this, damage, damageInfo->attackType);
+ // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
+ sScriptMgr->ModifyMeleeDamage(damageInfo->target, damageInfo->attacker, damage);
+
// Calculate armor reduction
if (IsDamageReducedByArmor((SpellSchoolMask)(damageInfo->damageSchoolMask)))
{
@@ -13047,17 +13057,17 @@ void Unit::DeleteCharmInfo()
}
CharmInfo::CharmInfo(Unit* unit)
-: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_petnumber(0), m_barInit(false),
- m_isCommandAttack(false), m_isAtStay(false), m_isFollowing(false), m_isReturning(false),
- m_stayX(0.0f), m_stayY(0.0f), m_stayZ(0.0f)
+: _unit(unit), _CommandState(COMMAND_FOLLOW), _petnumber(0), _barInit(false),
+ _isCommandAttack(false), _isAtStay(false), _isFollowing(false), _isReturning(false),
+ _stayX(0.0f), _stayY(0.0f), _stayZ(0.0f)
{
for (uint8 i = 0; i < MAX_SPELL_CHARM; ++i)
- m_charmspells[i].SetActionAndType(0, ACT_DISABLED);
+ _charmspells[i].SetActionAndType(0, ACT_DISABLED);
- if (m_unit->GetTypeId() == TYPEID_UNIT)
+ if (_unit->GetTypeId() == TYPEID_UNIT)
{
- m_oldReactState = m_unit->ToCreature()->GetReactState();
- m_unit->ToCreature()->SetReactState(REACT_PASSIVE);
+ _oldReactState = _unit->ToCreature()->GetReactState();
+ _unit->ToCreature()->SetReactState(REACT_PASSIVE);
}
}
@@ -13067,9 +13077,9 @@ CharmInfo::~CharmInfo()
void CharmInfo::RestoreState()
{
- if (m_unit->GetTypeId() == TYPEID_UNIT)
- if (Creature* creature = m_unit->ToCreature())
- creature->SetReactState(m_oldReactState);
+ if (_unit->GetTypeId() == TYPEID_UNIT)
+ if (Creature* creature = _unit->ToCreature())
+ creature->SetReactState(_oldReactState);
}
void CharmInfo::InitPetActionBar()
@@ -13100,16 +13110,16 @@ void CharmInfo::InitEmptyActionBar(bool withAttack)
void CharmInfo::InitPossessCreateSpells()
{
InitEmptyActionBar();
- if (m_unit->GetTypeId() == TYPEID_UNIT)
+ if (_unit->GetTypeId() == TYPEID_UNIT)
{
for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
{
- uint32 spellId = m_unit->ToCreature()->m_spells[i];
+ uint32 spellId = _unit->ToCreature()->m_spells[i];
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (spellInfo && !(spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD))
{
if (spellInfo->IsPassive())
- m_unit->CastSpell(m_unit, spellInfo, true);
+ _unit->CastSpell(_unit, spellInfo, true);
else
AddSpellToActionBar(spellInfo, ACT_PASSIVE);
}
@@ -13119,7 +13129,7 @@ void CharmInfo::InitPossessCreateSpells()
void CharmInfo::InitCharmCreateSpells()
{
- if (m_unit->GetTypeId() == TYPEID_PLAYER) // charmed players don't have spells
+ if (_unit->GetTypeId() == TYPEID_PLAYER) // charmed players don't have spells
{
InitEmptyActionBar();
return;
@@ -13129,23 +13139,23 @@ void CharmInfo::InitCharmCreateSpells()
for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
{
- uint32 spellId = m_unit->ToCreature()->m_spells[x];
+ uint32 spellId = _unit->ToCreature()->m_spells[x];
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo || spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)
{
- m_charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
+ _charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
continue;
}
if (spellInfo->IsPassive())
{
- m_unit->CastSpell(m_unit, spellInfo, true);
- m_charmspells[x].SetActionAndType(spellId, ACT_PASSIVE);
+ _unit->CastSpell(_unit, spellInfo, true);
+ _charmspells[x].SetActionAndType(spellId, ACT_PASSIVE);
}
else
{
- m_charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
+ _charmspells[x].SetActionAndType(spellId, ACT_DISABLED);
ActiveStates newstate = ACT_PASSIVE;
@@ -13222,17 +13232,17 @@ void CharmInfo::ToggleCreatureAutocast(SpellInfo const* spellInfo, bool apply)
return;
for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
- if (spellInfo->Id == m_charmspells[x].GetAction())
- m_charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED);
+ if (spellInfo->Id == _charmspells[x].GetAction())
+ _charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED);
}
void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
{
- m_petnumber = petnumber;
+ _petnumber = petnumber;
if (statwindow)
- m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, m_petnumber);
+ _unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, _petnumber);
else
- m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
+ _unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
}
void CharmInfo::LoadPetActionBar(const std::string& data)
@@ -16963,58 +16973,68 @@ uint32 Unit::GetResistance(SpellSchoolMask mask) const
void CharmInfo::SetIsCommandAttack(bool val)
{
- m_isCommandAttack = val;
+ _isCommandAttack = val;
}
bool CharmInfo::IsCommandAttack()
{
- return m_isCommandAttack;
+ return _isCommandAttack;
+}
+
+void CharmInfo::SetIsCommandFollow(bool val)
+{
+ _isCommandFollow = val;
+}
+
+bool CharmInfo::IsCommandFollow()
+{
+ return _isCommandFollow;
}
void CharmInfo::SaveStayPosition()
{
//! At this point a new spline destination is enabled because of Unit::StopMoving()
- G3D::Vector3 const stayPos = m_unit->movespline->FinalDestination();
- m_stayX = stayPos.x;
- m_stayY = stayPos.y;
- m_stayZ = stayPos.z;
+ G3D::Vector3 const stayPos = _unit->movespline->FinalDestination();
+ _stayX = stayPos.x;
+ _stayY = stayPos.y;
+ _stayZ = stayPos.z;
}
void CharmInfo::GetStayPosition(float &x, float &y, float &z)
{
- x = m_stayX;
- y = m_stayY;
- z = m_stayZ;
+ x = _stayX;
+ y = _stayY;
+ z = _stayZ;
}
void CharmInfo::SetIsAtStay(bool val)
{
- m_isAtStay = val;
+ _isAtStay = val;
}
bool CharmInfo::IsAtStay()
{
- return m_isAtStay;
+ return _isAtStay;
}
void CharmInfo::SetIsFollowing(bool val)
{
- m_isFollowing = val;
+ _isFollowing = val;
}
bool CharmInfo::IsFollowing()
{
- return m_isFollowing;
+ return _isFollowing;
}
void CharmInfo::SetIsReturning(bool val)
{
- m_isReturning = val;
+ _isReturning = val;
}
bool CharmInfo::IsReturning()
{
- return m_isReturning;
+ return _isReturning;
}
void Unit::SetInFront(Unit const* target)
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 000a254cfbe..1bd3e5d59aa 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -253,6 +253,7 @@ enum UnitRename
#define MAX_SPELL_CONTROL_BAR 10
#define MAX_AGGRO_RESET_TIME 10 // in seconds
+#define MAX_AGGRO_RADIUS 45.0f // yards
enum Swing
{
@@ -1103,12 +1104,12 @@ struct CharmInfo
explicit CharmInfo(Unit* unit);
~CharmInfo();
void RestoreState();
- uint32 GetPetNumber() const { return m_petnumber; }
+ uint32 GetPetNumber() const { return _petnumber; }
void SetPetNumber(uint32 petnumber, bool statwindow);
- void SetCommandState(CommandStates st) { m_CommandState = st; }
- CommandStates GetCommandState() const { return m_CommandState; }
- bool HasCommandState(CommandStates state) const { return (m_CommandState == state); }
+ void SetCommandState(CommandStates st) { _CommandState = st; }
+ CommandStates GetCommandState() const { return _CommandState; }
+ bool HasCommandState(CommandStates state) const { return (_CommandState == state); }
void InitPossessCreateSpells();
void InitCharmCreateSpells();
@@ -1129,12 +1130,14 @@ struct CharmInfo
void ToggleCreatureAutocast(SpellInfo const* spellInfo, bool apply);
- CharmSpellInfo* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); }
+ CharmSpellInfo* GetCharmSpell(uint8 index) { return &(_charmspells[index]); }
GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; }
void SetIsCommandAttack(bool val);
bool IsCommandAttack();
+ void SetIsCommandFollow(bool val);
+ bool IsCommandFollow();
void SetIsAtStay(bool val);
bool IsAtStay();
void SetIsFollowing(bool val);
@@ -1146,23 +1149,24 @@ struct CharmInfo
private:
- Unit* m_unit;
+ Unit* _unit;
UnitActionBarEntry PetActionBar[MAX_UNIT_ACTION_BAR_INDEX];
- CharmSpellInfo m_charmspells[4];
- CommandStates m_CommandState;
- uint32 m_petnumber;
- bool m_barInit;
+ CharmSpellInfo _charmspells[4];
+ CommandStates _CommandState;
+ uint32 _petnumber;
+ bool _barInit;
//for restoration after charmed
- ReactStates m_oldReactState;
-
- bool m_isCommandAttack;
- bool m_isAtStay;
- bool m_isFollowing;
- bool m_isReturning;
- float m_stayX;
- float m_stayY;
- float m_stayZ;
+ ReactStates _oldReactState;
+
+ bool _isCommandAttack;
+ bool _isCommandFollow;
+ bool _isAtStay;
+ bool _isFollowing;
+ bool _isReturning;
+ float _stayX;
+ float _stayY;
+ float _stayZ;
GlobalCooldownMgr m_GlobalCooldownMgr;
};
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 6c1cdf6a7fb..1dbf1ba0be8 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -1087,6 +1087,35 @@ namespace Trinity
NearestHostileUnitInAttackDistanceCheck(NearestHostileUnitInAttackDistanceCheck const&);
};
+ class NearestHostileUnitInAggroRangeCheck
+ {
+ public:
+ explicit NearestHostileUnitInAggroRangeCheck(Creature const* creature, bool useLOS = false) : _me(creature), _useLOS(useLOS)
+ {
+ }
+ bool operator()(Unit* u)
+ {
+ if (!u->IsHostileTo(_me))
+ return false;
+
+ if (!u->IsWithinDistInMap(_me, _me->GetAggroRange(u)))
+ return false;
+
+ if (!_me->IsValidAttackTarget(u))
+ return false;
+
+ if (_useLOS && !u->IsWithinLOSInMap(_me))
+ return false;
+
+ return true;
+ }
+
+ private:
+ Creature const* _me;
+ bool _useLOS;
+ NearestHostileUnitInAggroRangeCheck(NearestHostileUnitInAggroRangeCheck const&);
+ };
+
class AnyAssistCreatureInRangeCheck
{
public:
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index 02a5a9c26e1..aa9b81aa534 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -495,22 +495,6 @@ void WorldSession::SendBindPoint(Creature* npc)
uint32 bindspell = 3286;
- // update sql homebind
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_HOMEBIND);
- stmt->setUInt16(0, _player->GetMapId());
- stmt->setUInt16(1, _player->GetAreaId());
- stmt->setFloat (2, _player->GetPositionX());
- stmt->setFloat (3, _player->GetPositionY());
- stmt->setFloat (4, _player->GetPositionZ());
- stmt->setUInt32(5, _player->GetGUIDLow());
- CharacterDatabase.Execute(stmt);
-
- _player->m_homebindMapId = _player->GetMapId();
- _player->m_homebindAreaId = _player->GetAreaId();
- _player->m_homebindX = _player->GetPositionX();
- _player->m_homebindY = _player->GetPositionY();
- _player->m_homebindZ = _player->GetPositionZ();
-
// send spell for homebinding (3286)
npc->CastSpell(_player, bindspell, true);
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 3bf64726f03..378b00ceed4 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -167,6 +167,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid
charmInfo->SetIsCommandAttack(false);
charmInfo->SetIsAtStay(true);
+ charmInfo->SetIsCommandFollow(false);
charmInfo->SetIsFollowing(false);
charmInfo->SetIsReturning(false);
charmInfo->SaveStayPosition();
@@ -180,6 +181,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid
charmInfo->SetIsCommandAttack(false);
charmInfo->SetIsAtStay(false);
charmInfo->SetIsReturning(true);
+ charmInfo->SetIsCommandFollow(true);
charmInfo->SetIsFollowing(false);
break;
case COMMAND_ATTACK: //spellid=1792 //ATTACK
@@ -220,6 +222,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid
charmInfo->SetIsCommandAttack(true);
charmInfo->SetIsAtStay(false);
charmInfo->SetIsFollowing(false);
+ charmInfo->SetIsCommandFollow(false);
charmInfo->SetIsReturning(false);
pet->ToCreature()->AI()->AttackStart(TargetUnit);
@@ -241,6 +244,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid
charmInfo->SetIsCommandAttack(true);
charmInfo->SetIsAtStay(false);
charmInfo->SetIsFollowing(false);
+ charmInfo->SetIsCommandFollow(false);
charmInfo->SetIsReturning(false);
pet->Attack(TargetUnit, true);
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index 051e71e3b27..cb10b607c4a 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -43,7 +43,7 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket& recvData)
Object* questgiver = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
if (!questgiver)
{
- sLog->outInfo(LOG_FILTER_NETWORKIO, "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for not found questgiver (Typeid: %u GUID: %u)", GuidHigh2TypeId(GUID_HIPART(guid)), GUID_LOPART(guid));
+ sLog->outInfo(LOG_FILTER_NETWORKIO, "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver (Typeid: %u GUID: %u)", GuidHigh2TypeId(GUID_HIPART(guid)), GUID_LOPART(guid));
return;
}
@@ -289,7 +289,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
if (reward >= QUEST_REWARD_CHOICES_COUNT)
{
- sLog->outError(LOG_FILTER_NETWORKIO, "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (guid %d) tried to get invalid reward (%u) (probably packet hacking)", _player->GetName().c_str(), _player->GetGUIDLow(), reward);
+ sLog->outError(LOG_FILTER_NETWORKIO, "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (guid %d) tried to get invalid reward (%u) (possible packet-hacking detected)", _player->GetName().c_str(), _player->GetGUIDLow(), reward);
return;
}
@@ -315,7 +315,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE) ||
(_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete()))
{
- sLog->outError(LOG_FILTER_NETWORKIO, "HACK ALERT: Player %s (guid: %u) is trying to complete quest (id: %u) but he has no right to do it!",
+ sLog->outError(LOG_FILTER_NETWORKIO, "Error in QUEST_STATUS_COMPLETE: player %s (guid %u) tried to complete quest %u, but is not allowed to do so (possible packet-hacking or high latency)",
_player->GetName().c_str(), _player->GetGUIDLow(), questId);
return;
}
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
index 7a669642e7e..8712b2cf527 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
@@ -66,7 +66,9 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
// We need to subtract GetObjectSize() because it gets added back further down the chain
// and that makes pets too far away. Subtracting it allows pets to properly
// be (GetCombatReach() + i_offset) away.
- if (owner.isPet())
+ // Only applies when i_target is pet's owner otherwise pets and mobs end up
+ // doing a "dance" while fighting
+ if (owner.isPet() && i_target->GetTypeId() == TYPEID_PLAYER)
{
dist = i_target->GetCombatReach();
size = i_target->GetCombatReach() - i_target->GetObjectSize();
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 988ef0937c3..51e6ced8d24 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -160,83 +160,7 @@ class ScriptRegistry
if (!V) \
return R;
-void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* target)
-{
- if (!pSource)
- {
- sLog->outError(LOG_FILTER_TSCR, "DoScriptText entry %i, invalid Source pointer.", iTextEntry);
- return;
- }
-
- if (iTextEntry >= 0)
- {
- sLog->outError(LOG_FILTER_TSCR, "DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry);
- return;
- }
-
- const StringTextData* pData = sScriptSystemMgr->GetTextData(iTextEntry);
-
- if (!pData)
- {
- sLog->outError(LOG_FILTER_TSCR, "DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry);
- return;
- }
-
- sLog->outDebug(LOG_FILTER_TSCR, "DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", iTextEntry, pData->uiSoundId, pData->uiType, pData->uiLanguage, pData->uiEmote);
-
- if (pData->uiSoundId)
- {
- if (sSoundEntriesStore.LookupEntry(pData->uiSoundId))
- pSource->SendPlaySound(pData->uiSoundId, false);
- else
- sLog->outError(LOG_FILTER_TSCR, "DoScriptText entry %i tried to process invalid sound id %u.", iTextEntry, pData->uiSoundId);
- }
-
- if (pData->uiEmote)
- {
- if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER)
- ((Unit*)pSource)->HandleEmoteCommand(pData->uiEmote);
- else
- sLog->outError(LOG_FILTER_TSCR, "DoScriptText entry %i tried to process emote for invalid TypeId (%u).", iTextEntry, pSource->GetTypeId());
- }
- switch (pData->uiType)
- {
- case CHAT_TYPE_SAY:
- pSource->MonsterSay(iTextEntry, pData->uiLanguage, target ? target->GetGUID() : 0);
- break;
- case CHAT_TYPE_YELL:
- pSource->MonsterYell(iTextEntry, pData->uiLanguage, target ? target->GetGUID() : 0);
- break;
- case CHAT_TYPE_TEXT_EMOTE:
- pSource->MonsterTextEmote(iTextEntry, target ? target->GetGUID() : 0);
- break;
- case CHAT_TYPE_BOSS_EMOTE:
- pSource->MonsterTextEmote(iTextEntry, target ? target->GetGUID() : 0, true);
- break;
- case CHAT_TYPE_WHISPER:
- {
- if (target && target->GetTypeId() == TYPEID_PLAYER)
- pSource->MonsterWhisper(iTextEntry, target->GetGUID());
- else
- sLog->outError(LOG_FILTER_TSCR, "DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry);
-
- break;
- }
- case CHAT_TYPE_BOSS_WHISPER:
- {
- if (target && target->GetTypeId() == TYPEID_PLAYER)
- pSource->MonsterWhisper(iTextEntry, target->GetGUID(), true);
- else
- sLog->outError(LOG_FILTER_TSCR, "DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry);
-
- break;
- }
- case CHAT_TYPE_ZONE_YELL:
- pSource->MonsterYellToZone(iTextEntry, pData->uiLanguage, target ? target->GetGUID() : 0);
- break;
- }
-}
ScriptMgr::ScriptMgr()
: _scriptCount(0), _scheduledScripts(0)
@@ -293,14 +217,13 @@ void ScriptMgr::Unload()
SCR_CLEAR(PlayerScript);
SCR_CLEAR(GuildScript);
SCR_CLEAR(GroupScript);
+ SCR_CLEAR(UnitScript);
#undef SCR_CLEAR
}
void ScriptMgr::LoadDatabase()
{
- sScriptSystemMgr->LoadScriptTexts();
- sScriptSystemMgr->LoadScriptTextsCustom();
sScriptSystemMgr->LoadScriptWaypoints();
}
@@ -1416,6 +1339,22 @@ void ScriptMgr::OnGroupDisband(Group* group)
FOREACH_SCRIPT(GroupScript)->OnDisband(group);
}
+// Unit
+void ScriptMgr::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage)
+{
+ FOREACH_SCRIPT(UnitScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage);
+}
+
+void ScriptMgr::ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage)
+{
+ FOREACH_SCRIPT(UnitScript)->ModifyMeleeDamage(target, attacker, damage);
+}
+
+void ScriptMgr::ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage)
+{
+ FOREACH_SCRIPT(UnitScript)->ModifySpellDamageTaken(target, attacker, damage);
+}
+
SpellScriptLoader::SpellScriptLoader(const char* name)
: ScriptObject(name)
{
@@ -1440,6 +1379,12 @@ FormulaScript::FormulaScript(const char* name)
ScriptRegistry<FormulaScript>::AddScript(this);
}
+UnitScript::UnitScript(const char* name)
+ : ScriptObject(name)
+{
+ ScriptRegistry<UnitScript>::AddScript(this);
+}
+
WorldMapScript::WorldMapScript(const char* name, uint32 mapId)
: ScriptObject(name), MapScript<Map>(mapId)
{
@@ -1474,7 +1419,7 @@ ItemScript::ItemScript(const char* name)
}
CreatureScript::CreatureScript(const char* name)
- : ScriptObject(name)
+ : UnitScript(name)
{
ScriptRegistry<CreatureScript>::AddScript(this);
}
@@ -1528,7 +1473,7 @@ ConditionScript::ConditionScript(const char* name)
}
VehicleScript::VehicleScript(const char* name)
- : ScriptObject(name)
+ : UnitScript(name)
{
ScriptRegistry<VehicleScript>::AddScript(this);
}
@@ -1552,7 +1497,7 @@ AchievementCriteriaScript::AchievementCriteriaScript(const char* name)
}
PlayerScript::PlayerScript(const char* name)
- : ScriptObject(name)
+ : UnitScript(name)
{
ScriptRegistry<PlayerScript>::AddScript(this);
}
@@ -1598,6 +1543,7 @@ template class ScriptRegistry<AchievementCriteriaScript>;
template class ScriptRegistry<PlayerScript>;
template class ScriptRegistry<GuildScript>;
template class ScriptRegistry<GroupScript>;
+template class ScriptRegistry<UnitScript>;
// Undefine utility macros.
#undef GET_SCRIPT_RET
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 22625d74e10..17cc3844605 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -68,8 +68,6 @@ struct OutdoorPvPData;
#define VISIBLE_RANGE 166.0f //MAX visible range (size of grid)
-// Generic scripting text function.
-void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target = NULL);
/*
TODO: Add more script type classes.
@@ -393,7 +391,24 @@ class ItemScript : public ScriptObject
virtual bool OnExpire(Player* /*player*/, ItemTemplate const* /*proto*/) { return false; }
};
-class CreatureScript : public ScriptObject, public UpdatableScript<Creature>
+class UnitScript : public ScriptObject
+{
+ protected:
+
+ UnitScript(const char* name);
+
+ public:
+ // Called when DoT's Tick Damage is being Dealt
+ virtual void ModifyPeriodicDamageAurasTick(Unit* /*target*/, Unit* /*attacker*/, uint32& /*damage*/) { }
+
+ // Called when Melee Damage is being Dealt
+ virtual void ModifyMeleeDamage(Unit* /*target*/, Unit* /*attacker*/, uint32& /*damage*/) { }
+
+ // Called when Spell Damage is being Dealt
+ virtual void ModifySpellDamageTaken(Unit* /*target*/, Unit* /*attacker*/, int32& /*damage*/) { }
+};
+
+class CreatureScript : public UnitScript, public UpdatableScript<Creature>
{
protected:
@@ -584,7 +599,7 @@ class ConditionScript : public ScriptObject
virtual bool OnConditionCheck(Condition* /*condition*/, ConditionSourceInfo& /*sourceInfo*/) { return true; }
};
-class VehicleScript : public ScriptObject
+class VehicleScript : public UnitScript
{
protected:
@@ -655,7 +670,7 @@ class AchievementCriteriaScript : public ScriptObject
virtual bool OnCheck(Player* source, Unit* target) = 0;
};
-class PlayerScript : public ScriptObject
+class PlayerScript : public UnitScript
{
protected:
@@ -1032,6 +1047,12 @@ class ScriptMgr
void OnGroupChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid);
void OnGroupDisband(Group* group);
+ public: /* UnitScript */
+
+ void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage);
+ void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage);
+ void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage);
+
public: /* Scheduled scripts */
uint32 IncreaseScheduledScriptsCount() { return ++_scheduledScripts; }
diff --git a/src/server/game/Scripting/ScriptSystem.cpp b/src/server/game/Scripting/ScriptSystem.cpp
index 41b41b91808..ea1cf6b1994 100644
--- a/src/server/game/Scripting/ScriptSystem.cpp
+++ b/src/server/game/Scripting/ScriptSystem.cpp
@@ -23,128 +23,6 @@
ScriptPointVector const SystemMgr::_empty;
-void SystemMgr::LoadScriptTexts()
-{
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Script Texts...");
- LoadTrinityStrings("script_texts", TEXT_SOURCE_RANGE, 1+(TEXT_SOURCE_RANGE*2));
-
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Script Texts additional data...");
- uint32 oldMSTime = getMSTime();
-
- // 0 1 2 3
- QueryResult result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM script_texts");
-
- if (!result)
- {
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 additional Script Texts data. DB table `script_texts` is empty.");
- return;
- }
-
- uint32 uiCount = 0;
-
- do
- {
- Field* pFields = result->Fetch();
- StringTextData temp;
-
- int32 iId = pFields[0].GetInt32();
- temp.uiSoundId = pFields[1].GetUInt32();
- temp.uiType = pFields[2].GetUInt8();
- temp.uiLanguage = pFields[3].GetUInt8();
- temp.uiEmote = pFields[4].GetUInt16();
-
- if (iId >= 0)
- {
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `script_texts` is not a negative value.", iId);
- continue;
- }
-
- if (iId > TEXT_SOURCE_RANGE || iId <= TEXT_SOURCE_RANGE*2)
- {
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `script_texts` is out of accepted entry range for table.", iId);
- continue;
- }
-
- if (temp.uiSoundId)
- {
- if (!sSoundEntriesStore.LookupEntry(temp.uiSoundId))
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `script_texts` has soundId %u but sound does not exist.", iId, temp.uiSoundId);
- }
-
- if (!GetLanguageDescByID(temp.uiLanguage))
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `script_texts` using Language %u but Language does not exist.", iId, temp.uiLanguage);
-
- if (temp.uiType > CHAT_TYPE_ZONE_YELL)
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `script_texts` has Type %u but this Chat Type does not exist.", iId, temp.uiType);
-
- m_mTextDataMap[iId] = temp;
- ++uiCount;
- }
- while (result->NextRow());
-
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u additional Script Texts data in %u ms", uiCount, GetMSTimeDiffToNow(oldMSTime));
-}
-
-void SystemMgr::LoadScriptTextsCustom()
-{
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Custom Texts...");
- LoadTrinityStrings("custom_texts", TEXT_SOURCE_RANGE*2, 1+(TEXT_SOURCE_RANGE*3));
-
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Custom Texts additional data...");
-
- QueryResult result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM custom_texts");
-
- if (!result)
- {
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 additional Custom Texts data. DB table `custom_texts` is empty.");
- return;
- }
-
- uint32 uiCount = 0;
-
- do
- {
- Field* pFields = result->Fetch();
- StringTextData temp;
-
- int32 iId = pFields[0].GetInt32();
- temp.uiSoundId = pFields[1].GetUInt32();
- temp.uiType = pFields[2].GetUInt8();
- temp.uiLanguage = pFields[3].GetUInt8();
- temp.uiEmote = pFields[4].GetUInt16();
-
- if (iId >= 0)
- {
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `custom_texts` is not a negative value.", iId);
- continue;
- }
-
- if (iId > TEXT_SOURCE_RANGE*2 || iId <= TEXT_SOURCE_RANGE*3)
- {
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `custom_texts` is out of accepted entry range for table.", iId);
- continue;
- }
-
- if (temp.uiSoundId)
- {
- if (!sSoundEntriesStore.LookupEntry(temp.uiSoundId))
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `custom_texts` has soundId %u but sound does not exist.", iId, temp.uiSoundId);
- }
-
- if (!GetLanguageDescByID(temp.uiLanguage))
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `custom_texts` using Language %u but Language does not exist.", iId, temp.uiLanguage);
-
- if (temp.uiType > CHAT_TYPE_ZONE_YELL)
- sLog->outError(LOG_FILTER_SQL, "TSCR: Entry %i in table `custom_texts` has Type %u but this Chat Type does not exist.", iId, temp.uiType);
-
- m_mTextDataMap[iId] = temp;
- ++uiCount;
- }
- while (result->NextRow());
-
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u additional Custom Texts data.", uiCount);
-}
-
void SystemMgr::LoadScriptWaypoints()
{
uint32 oldMSTime = getMSTime();
diff --git a/src/server/game/Scripting/ScriptSystem.h b/src/server/game/Scripting/ScriptSystem.h
index 4211a63b043..cc65d493f3e 100644
--- a/src/server/game/Scripting/ScriptSystem.h
+++ b/src/server/game/Scripting/ScriptSystem.h
@@ -46,14 +46,6 @@ struct ScriptPointMove
typedef std::vector<ScriptPointMove> ScriptPointVector;
-struct StringTextData
-{
- uint32 uiSoundId;
- uint8 uiType;
- uint32 uiLanguage;
- uint32 uiEmote;
-};
-
class SystemMgr
{
friend class ACE_Singleton<SystemMgr, ACE_Null_Mutex>;
@@ -61,26 +53,11 @@ class SystemMgr
~SystemMgr() {}
public:
- //Maps and lists
- typedef UNORDERED_MAP<int32, StringTextData> TextDataMap;
typedef UNORDERED_MAP<uint32, ScriptPointVector> PointMoveMap;
//Database
- void LoadScriptTexts();
- void LoadScriptTextsCustom();
void LoadScriptWaypoints();
- //Retrive from storage
- StringTextData const* GetTextData(int32 textId) const
- {
- TextDataMap::const_iterator itr = m_mTextDataMap.find(textId);
-
- if (itr == m_mTextDataMap.end())
- return NULL;
-
- return &itr->second;
- }
-
ScriptPointVector const& GetPointMoveList(uint32 creatureEntry) const
{
PointMoveMap::const_iterator itr = m_mPointMoveMap.find(creatureEntry);
@@ -92,7 +69,6 @@ class SystemMgr
}
protected:
- TextDataMap m_mTextDataMap; //additional data for text strings
PointMoveMap m_mPointMoveMap; //coordinates for waypoints
private:
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 6efeb061448..0ab0b3f21e9 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -3076,9 +3076,10 @@ void AuraEffect::HandleModPossess(AuraApplication const* aurApp, uint8 mode, boo
target->RemoveCharmedBy(caster);
}
-// only one spell has this aura
void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode, bool apply) const
{
+ // Used by spell "Eyes of the Beast"
+
if (!(mode & AURA_EFFECT_HANDLE_REAL))
return;
@@ -3101,6 +3102,9 @@ void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode,
if (caster->ToPlayer()->GetPet() != pet)
return;
+ // Must clear current motion or pet leashes back to owner after a few yards
+ // when under spell 'Eyes of the Beast'
+ pet->GetMotionMaster()->Clear();
pet->SetCharmedBy(caster, CHARM_TYPE_POSSESS, aurApp);
}
else
@@ -3111,13 +3115,15 @@ void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode,
pet->Remove(PET_SAVE_NOT_IN_SLOT, true);
else
{
- // Reinitialize the pet bar and make the pet come back to the owner
+ // Reinitialize the pet bar or it will appear greyed out
caster->ToPlayer()->PetSpellInitialize();
- if (!pet->getVictim())
+
+ // Follow owner only if not fighting or owner didn't click "stay" at new location
+ // This may be confusing because pet bar shows "stay" when under the spell but it retains
+ // the "follow" flag. Player MUST click "stay" while under the spell.
+ if (!pet->getVictim() && !pet->GetCharmInfo()->HasCommandState(COMMAND_STAY))
{
pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, pet->GetFollowAngle());
- //if (target->GetCharmInfo())
- // target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
}
}
}
@@ -6085,6 +6091,9 @@ 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);
+ // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations
+ sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage);
+
if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE)
{
damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount());
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 63198fd39aa..364127a55ba 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1372,7 +1372,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id))
{
// TODO: fix this check
- if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS))
+ if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || m_spellInfo->HasEffect(SPELL_EFFECT_BIND))
m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId);
else if (st->target_mapId == m_caster->GetMapId())
m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation);
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 57993ecdc08..ebe005ca67e 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -5988,51 +5988,38 @@ void Spell::EffectBind(SpellEffIndex effIndex)
Player* player = unitTarget->ToPlayer();
- uint32 area_id;
- WorldLocation loc;
- if (m_spellInfo->Effects[effIndex].TargetA.GetTarget() == TARGET_DEST_DB || m_spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DB)
- {
- SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id);
- if (!st)
- {
- sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::EffectBind - unknown teleport coordinates for spell ID %u", m_spellInfo->Id);
- return;
- }
+ WorldLocation homeLoc;
+ uint32 areaId = player->GetAreaId();
- loc.m_mapId = st->target_mapId;
- loc.m_positionX = st->target_X;
- loc.m_positionY = st->target_Y;
- loc.m_positionZ = st->target_Z;
- loc.SetOrientation(st->target_Orientation);
- area_id = player->GetAreaId();
- }
+ if (m_spellInfo->Effects[effIndex].MiscValue)
+ areaId = m_spellInfo->Effects[effIndex].MiscValue;
+
+ if (m_targets.HasDst())
+ homeLoc.WorldRelocate(*destTarget);
else
{
- player->GetPosition(&loc);
- area_id = player->GetAreaId();
+ player->GetPosition(&homeLoc);
+ homeLoc.m_mapId = player->GetMapId();
}
- player->SetHomebind(loc, area_id);
+ player->SetHomebind(homeLoc, areaId);
// binding
WorldPacket data(SMSG_BINDPOINTUPDATE, (4+4+4+4+4));
- data << float(loc.m_positionX);
- data << float(loc.m_positionY);
- data << float(loc.m_positionZ);
- data << uint32(loc.m_mapId);
- data << uint32(area_id);
+ data << float(homeLoc.GetPositionX());
+ data << float(homeLoc.GetPositionY());
+ data << float(homeLoc.GetPositionZ());
+ data << uint32(homeLoc.GetMapId());
+ data << uint32(areaId);
player->SendDirectMessage(&data);
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "New homebind X : %f", loc.m_positionX);
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "New homebind Y : %f", loc.m_positionY);
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "New homebind Z : %f", loc.m_positionZ);
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "New homebind MapId : %u", loc.m_mapId);
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "New homebind AreaId : %u", area_id);
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "EffectBind: New homebind X: %f, Y: %f, Z: %f, MapId: %u, AreaId: %u",
+ homeLoc.GetPositionX(), homeLoc.GetPositionY(), homeLoc.GetPositionZ(), homeLoc.GetMapId(), areaId);
// zone update
data.Initialize(SMSG_PLAYERBOUND, 8+4);
data << uint64(player->GetGUID());
- data << uint32(area_id);
+ data << uint32(areaId);
player->SendDirectMessage(&data);
}
diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp b/src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp
index 1ec0eda171c..27a3aaa3fae 100644
--- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp
+++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp
@@ -33,7 +33,7 @@ EndScriptData */
enum eEnums
{
- SAY_BOSS_DIE_AD = 0,
+ SAY_BOSS_DIE_AD = 4,
SAY_BOSS_DIE_AS = 3,
SAY_ARCHMAGE = 0,
diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
index 959f8a3f690..5c46519ab1c 100644
--- a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
+++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp
@@ -231,7 +231,7 @@ public:
{
npc_morriduneAI(Creature* creature) : npc_escortAI(creature)
{
- creature->AI()->Talk(SAY_MORRIDUNE_1);
+ Talk(SAY_MORRIDUNE_1);
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
Start(false, false, 0);
}
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
index 3329ecf88d2..4887c8adf62 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp
@@ -43,7 +43,7 @@ enum Says
SAY_PHASE201 = 10,
SAY_PHASE203 = 11,
SAY_PHASE205 = 12,
- SAY_PHASE208 = 13,
+ SAY_PHASE208 = 13,
SAY_PHASE209 = 14,
SAY_PHASE210 = 15,
@@ -96,7 +96,7 @@ enum Says
SAY_PHASE117 = 1,
//Cityman
- SAY_PHASE202 = 0,
+ SAY_PHASE202 = 0,
//Crazyman
SAY_PHASE204 = 0,
diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp
index 03bebe35fd9..5d9eaeac7b9 100644
--- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp
+++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp
@@ -59,7 +59,7 @@ enum MedivhBm
SPELL_CORRUPT = 31326,
SPELL_CORRUPT_AEONUS = 37853,
-
+
C_COUNCIL_ENFORCER = 17023
};
diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp
index 4ebdc408963..99a304e3726 100644
--- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp
+++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp
@@ -35,7 +35,7 @@ enum Skeram
SAY_SLAY = 1,
SAY_SPLIT = 2,
SAY_DEATH = 3,
-
+
SPELL_ARCANE_EXPLOSION = 25679,
SPELL_EARTH_SHOCK = 26194,
SPELL_TRUE_FULFILLMENT = 785,
diff --git a/src/server/scripts/Kalimdor/azuremyst_isle.cpp b/src/server/scripts/Kalimdor/azuremyst_isle.cpp
index ae0199e5dee..244a0abe8b2 100644
--- a/src/server/scripts/Kalimdor/azuremyst_isle.cpp
+++ b/src/server/scripts/Kalimdor/azuremyst_isle.cpp
@@ -411,14 +411,14 @@ enum Geezle
SPELL_TREE_DISGUISE = 30298,
GEEZLE_SAY_1 = 0,
- SPARK_SAY_2 = 0,
- SPARK_SAY_3 = 1,
+ SPARK_SAY_2 = 3,
+ SPARK_SAY_3 = 4,
GEEZLE_SAY_4 = 1,
- SPARK_SAY_5 = 2,
- SPARK_SAY_6 = 3,
+ SPARK_SAY_5 = 5,
+ SPARK_SAY_6 = 6,
GEEZLE_SAY_7 = 2,
- EMOTE_SPARK = 4,
+ EMOTE_SPARK = 7,
MOB_SPARK = 17243,
GO_NAGA_FLAG = 181694
@@ -490,23 +490,23 @@ public:
Spark->SetInFront(me);
me->SetInFront(Spark);
return 5000;
- case 3:
- Spark->AI()->Talk(SPARK_SAY_2);
+ case 3:
+ Spark->AI()->Talk(SPARK_SAY_2);
return 7000;
- case 4:
+ case 4:
Spark->AI()->Talk(SPARK_SAY_3);
return 8000;
- case 5:
+ case 5:
Talk(GEEZLE_SAY_4, SparkGUID);
return 8000;
- case 6:
+ case 6:
Spark->AI()->Talk(SPARK_SAY_5);
return 9000;
- case 7:
- Spark->AI()->Talk(SPARK_SAY_6);
+ case 7:
+ Spark->AI()->Talk(SPARK_SAY_6);
return 8000;
- case 8:
- Talk(GEEZLE_SAY_7, SparkGUID);
+ case 8:
+ Talk(GEEZLE_SAY_7, SparkGUID);
return 2000;
case 9:
me->GetMotionMaster()->MoveTargetedHome();
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
index d77c84b2978..3c20acf34a6 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp
@@ -27,10 +27,34 @@ EndScriptData */
#include "SpellScript.h"
#include "trial_of_the_champion.h"
#include "ScriptedEscortAI.h"
-
-enum eSpells
+/*
+enum Yells
+{
+ // Eadric the Pure
+ SAY_INTRO = 0,
+ SAY_AGGRO = 1,
+ EMOTE_RADIANCE = 2,
+ EMOTE_HAMMER_RIGHTEOUS = 3,
+ SAY_HAMMER_RIGHTEOUS = 4,
+ SAY_KILL_PLAYER = 5,
+ SAY_DEFEATED = 6,
+
+ // Argent Confessor Paletress
+ SAY_INTRO_1 = 0,
+ SAY_INTRO_2 = 1,
+ SAY_AGGRO = 2,
+ SAY_MEMORY_SUMMON = 3,
+ SAY_MEMORY_DEATH = 4,
+ SAY_KILL_PLAYER = 5,
+ SAY_DEFEATED = 6,
+
+ // Memory of X
+ EMOTE_WAKING_NIGHTMARE = 0
+};
+*/
+enum Spells
{
- //Eadric
+ // Eadric the Pure
SPELL_EADRIC_ACHIEVEMENT = 68197,
SPELL_HAMMER_JUSTICE = 66863,
SPELL_HAMMER_RIGHTEOUS = 66867,
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp
index c56d44ceb08..c1a2f9c07d2 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp
@@ -27,7 +27,7 @@ EndScriptData */
#include "ScriptedEscortAI.h"
#include "trial_of_the_champion.h"
-enum eSpells
+enum Spells
{
//phase 1
SPELL_PLAGUE_STRIKE = 67884,
@@ -61,13 +61,13 @@ enum eSpells
SPELL_KILL_CREDIT = 68663
};
-enum eModels
+enum Models
{
MODEL_SKELETON = 29846,
MODEL_GHOST = 21300
};
-enum ePhases
+enum Phases
{
PHASE_UNDEAD = 1,
PHASE_SKELETON = 2,
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp
index ffda3d12e2f..9c0b894bfa7 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp
@@ -33,6 +33,18 @@ EndContentData */
#include "Vehicle.h"
#include "Player.h"
+enum Yells
+{
+ SAY_INTRO_1 = 0,
+ SAY_INTRO_2 = 1,
+ SAY_INTRO_3 = 2,
+ SAY_AGGRO = 3,
+ SAY_PHASE_2 = 4,
+ SAY_PHASE_3 = 5,
+ SAY_KILL_PLAYER = 6,
+ SAY_DEATH = 7
+};
+
#define GOSSIP_START_EVENT1 "I'm ready to start challenge."
#define GOSSIP_START_EVENT2 "I'm ready for the next challenge."
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.h b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.h
index cb3a43acdd0..6116a150334 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.h
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.h
@@ -19,7 +19,7 @@
#ifndef DEF_TOC_H
#define DEF_TOC_H
-enum eData
+enum Data
{
BOSS_GRAND_CHAMPIONS,
BOSS_ARGENT_CHALLENGE_E,
@@ -46,7 +46,7 @@ enum Data64
DATA_GRAND_CHAMPION_3
};
-enum eNpcs
+enum CreatureIds
{
// Horde Champions
NPC_MOKRA = 35572,
@@ -78,7 +78,7 @@ enum eNpcs
NPC_ARELAS = 35005
};
-enum eGameObjects
+enum GameObjects
{
GO_MAIN_GATE = 195647,
@@ -92,7 +92,7 @@ enum eGameObjects
GO_PALETRESS_LOOT_H = 195324
};
-enum eVehicles
+enum Vehicles
{
//Grand Champions Alliance Vehicles
VEHICLE_MARSHAL_JACOB_ALERIUS_MOUNT = 35637,
diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp
index f618d0e04e7..a9dc9cf394d 100644
--- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp
+++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp
@@ -25,6 +25,7 @@
#include "ScriptedCreature.h"
#include "trial_of_the_crusader.h"
#include "SpellScript.h"
+#include "SpellAuraEffects.h"
#include <limits>
enum Yells
@@ -53,54 +54,54 @@ enum Summons
enum BossSpells
{
- SPELL_FREEZE_SLASH = 66012,
- SPELL_PENETRATING_COLD = 66013,
- SPELL_LEECHING_SWARM = 66118,
- SPELL_LEECHING_HEAL = 66125,
- SPELL_LEECHING_DAMAGE = 66240,
- SPELL_MARK = 67574,
- SPELL_SPIKE_CALL = 66169,
- SPELL_SUBMERGE_ANUBARAK = 65981,
- SPELL_CLEAR_ALL_DEBUFFS = 34098,
- SPELL_EMERGE_ANUBARAK = 65982,
- SPELL_SUMMON_BEATLES = 66339,
- SPELL_SUMMON_BURROWER = 66332,
+ SPELL_FREEZE_SLASH = 66012,
+ SPELL_PENETRATING_COLD = 66013,
+ SPELL_LEECHING_SWARM = 66118,
+ SPELL_LEECHING_SWARM_HEAL = 66125,
+ SPELL_LEECHING_SWARM_DMG = 66240,
+ SPELL_MARK = 67574,
+ SPELL_SPIKE_CALL = 66169,
+ SPELL_SUBMERGE_ANUBARAK = 65981,
+ SPELL_CLEAR_ALL_DEBUFFS = 34098,
+ SPELL_EMERGE_ANUBARAK = 65982,
+ SPELL_SUMMON_BEATLES = 66339,
+ SPELL_SUMMON_BURROWER = 66332,
// Burrow
- SPELL_CHURNING_GROUND = 66969,
+ SPELL_CHURNING_GROUND = 66969,
// Scarab
- SPELL_DETERMINATION = 66092,
- SPELL_ACID_MANDIBLE = 65774, //Passive - Triggered
+ SPELL_DETERMINATION = 66092,
+ SPELL_ACID_MANDIBLE = 65774, //Passive - Triggered
// Burrower
- SPELL_SPIDER_FRENZY = 66128,
- SPELL_EXPOSE_WEAKNESS = 67720, //Passive - Triggered
- SPELL_SHADOW_STRIKE = 66134,
- SPELL_SUBMERGE_EFFECT = 68394,
- SPELL_AWAKENED = 66311,
- SPELL_EMERGE_EFFECT = 65982,
+ SPELL_SPIDER_FRENZY = 66128,
+ SPELL_EXPOSE_WEAKNESS = 67720, //Passive - Triggered
+ SPELL_SHADOW_STRIKE = 66134,
+ SPELL_SUBMERGE_EFFECT = 68394,
+ SPELL_AWAKENED = 66311,
+ SPELL_EMERGE_EFFECT = 65982,
- SPELL_PERSISTENT_DIRT = 68048,
+ SPELL_PERSISTENT_DIRT = 68048,
- SUMMON_SCARAB = NPC_SCARAB,
- SUMMON_FROSTSPHERE = NPC_FROST_SPHERE,
- SPELL_BERSERK = 26662,
+ SUMMON_SCARAB = NPC_SCARAB,
+ SUMMON_FROSTSPHERE = NPC_FROST_SPHERE,
+ SPELL_BERSERK = 26662,
//Frost Sphere
- SPELL_FROST_SPHERE = 67539,
- SPELL_PERMAFROST = 66193,
- SPELL_PERMAFROST_VISUAL = 65882,
- SPELL_PERMAFROST_MODEL = 66185,
+ SPELL_FROST_SPHERE = 67539,
+ SPELL_PERMAFROST = 66193,
+ SPELL_PERMAFROST_VISUAL = 65882,
+ SPELL_PERMAFROST_MODEL = 66185,
//Spike
- SPELL_SUMMON_SPIKE = 66169,
- SPELL_SPIKE_SPEED1 = 65920,
- SPELL_SPIKE_TRAIL = 65921,
- SPELL_SPIKE_SPEED2 = 65922,
- SPELL_SPIKE_SPEED3 = 65923,
- SPELL_SPIKE_FAIL = 66181,
- SPELL_SPIKE_TELE = 66170
+ SPELL_SUMMON_SPIKE = 66169,
+ SPELL_SPIKE_SPEED1 = 65920,
+ SPELL_SPIKE_TRAIL = 65921,
+ SPELL_SPIKE_SPEED2 = 65922,
+ SPELL_SPIKE_SPEED3 = 65923,
+ SPELL_SPIKE_FAIL = 66181,
+ SPELL_SPIKE_TELE = 66170
};
#define SPELL_PERMAFROST_HELPER RAID_MODE<uint32>(66193, 67855, 67856, 67857)
@@ -841,6 +842,49 @@ class spell_impale : public SpellScriptLoader
}
};
+class spell_anubarak_leeching_swarm : public SpellScriptLoader
+{
+ public:
+ spell_anubarak_leeching_swarm() : SpellScriptLoader("spell_anubarak_leeching_swarm") { }
+
+ class spell_anubarak_leeching_swarm_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_anubarak_leeching_swarm_AuraScript);
+
+ bool Validate(SpellInfo const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_LEECHING_SWARM_DMG) || !sSpellMgr->GetSpellInfo(SPELL_LEECHING_SWARM_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleEffectPeriodic(AuraEffect const* aurEff)
+ {
+ Unit* caster = GetCaster();
+ if (Unit* target = GetTarget())
+ {
+ int32 lifeLeeched = target->CountPctFromCurHealth(aurEff->GetAmount());
+ if (lifeLeeched < 250)
+ lifeLeeched = 250;
+ // Damage
+ caster->CastCustomSpell(target, SPELL_LEECHING_SWARM_DMG, &lifeLeeched, 0, 0, false);
+ // Heal
+ caster->CastCustomSpell(caster, SPELL_LEECHING_SWARM_HEAL, &lifeLeeched, 0, 0, false);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_anubarak_leeching_swarm_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_anubarak_leeching_swarm_AuraScript();
+ }
+};
+
void AddSC_boss_anubarak_trial()
{
new boss_anubarak_trial();
@@ -850,4 +894,5 @@ void AddSC_boss_anubarak_trial()
new mob_frost_sphere();
new spell_impale();
+ new spell_anubarak_leeching_swarm();
}
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
index d4e3a9e677d..c1a3a432407 100644
--- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp
@@ -70,7 +70,7 @@ enum Yells
SAY_FALRIC_INTRO_1 = 5,
SAY_FALRIC_INTRO_2 = 6,
- SAY_MARWYN_INTRO_1 = 0
+ SAY_MARWYN_INTRO_1 = 4
};
enum Events
diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp
index 969a3621e8e..51eca327810 100644
--- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp
+++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp
@@ -29,7 +29,7 @@ enum Yells
SAY_GORKUN_INTRO_2 = 0,
SAY_GORKUN_OUTRO_1 = 1,
SAY_GORKUN_OUTRO_2 = 2,
-
+
//Tyrannus
SAY_AMBUSH_1 = 3,
SAY_AMBUSH_2 = 4,
@@ -43,7 +43,7 @@ enum Yells
SAY_MARK_RIMEFANG_2 = 12,
SAY_DARK_MIGHT_1 = 13,
SAY_DARK_MIGHT_2 = 14,
-
+
//Jaina
SAY_JAYNA_OUTRO_3 = 3,
SAY_JAYNA_OUTRO_4 = 4,
diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
index 0018c58f4cb..8be4ac6b8b6 100644
--- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp
@@ -117,12 +117,16 @@ public:
events.ScheduleEvent(EVENT_FEVER, urand(15000, 20000));
events.ScheduleEvent(EVENT_PHASE, 90000);
events.ScheduleEvent(EVENT_ERUPT, 15000);
+ me->GetMotionMaster()->MoveChase(me->getVictim());
}
else
{
float x, y, z, o;
me->GetHomePosition(x, y, z, o);
- me->NearTeleportTo(x, y, z, o);
+ me->NearTeleportTo(x, y, z, o - G3D::halfPi());
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveIdle();
+ me->SetTarget(0);
DoCastAOE(SPELL_PLAGUE_CLOUD);
events.ScheduleEvent(EVENT_PHASE, 45000);
events.ScheduleEvent(EVENT_ERUPT, 8000);
diff --git a/src/server/scripts/Northrend/borean_tundra.cpp b/src/server/scripts/Northrend/borean_tundra.cpp
index 628de0238e0..3f20a3d32bc 100644
--- a/src/server/scripts/Northrend/borean_tundra.cpp
+++ b/src/server/scripts/Northrend/borean_tundra.cpp
@@ -931,7 +931,7 @@ enum eThassarian
SAY_LICH_1 = 0,
SAY_LICH_2 = 1,
SAY_LICH_3 = 2,
-
+
SAY_ARLOS_1 = 0,
SAY_ARLOS_2 = 1,
diff --git a/src/server/scripts/Northrend/sholazar_basin.cpp b/src/server/scripts/Northrend/sholazar_basin.cpp
index c0635f897d9..5bf45452d34 100644
--- a/src/server/scripts/Northrend/sholazar_basin.cpp
+++ b/src/server/scripts/Northrend/sholazar_basin.cpp
@@ -18,7 +18,7 @@
/* ScriptData
SDName: Sholazar_Basin
SD%Complete: 100
-SDComment: Quest support: 12570, 12573, 12621.
+SDComment: Quest support: 12570, 12573, 12621, 12726
SDCategory: Sholazar_Basin
EndScriptData */
@@ -26,6 +26,7 @@ EndScriptData */
npc_injured_rainspeaker_oracle
npc_vekjik
avatar_of_freya
+npc_haiphoon (Quest: "Song of Wind and Water")
EndContentData */
#include "ScriptMgr.h"
@@ -34,6 +35,8 @@ EndContentData */
#include "ScriptedEscortAI.h"
#include "SpellScript.h"
#include "SpellAuras.h"
+#include "Vehicle.h"
+#include "CombatAI.h"
#include "Player.h"
/*######
@@ -984,6 +987,52 @@ public:
}
};
+/*######
+## Quest: Song of Wind and Water ID: 12726
+######*/
+/*This quest precisly needs core script since battle vehicles are not well integrated with SAI,
+may be easily converted to SAI when they get.*/
+enum SongOfWindAndWater
+{
+ // Spells
+ SPELL_DEVOUR_WIND = 52862,
+ SPELL_DEVOUR_WATER = 52864,
+ // NPCs
+ NPC_HAIPHOON_WATER = 28999,
+ NPC_HAIPHOON_AIR = 28985
+};
+
+class npc_haiphoon : public CreatureScript
+{
+public:
+ npc_haiphoon() : CreatureScript("npc_haiphoon") { }
+
+ struct npc_haiphoonAI : public VehicleAI
+ {
+ npc_haiphoonAI(Creature* creature) : VehicleAI(creature) { }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell)
+ {
+ if (target == me)
+ return;
+
+ if (spell->Id == SPELL_DEVOUR_WIND && me->GetCharmerOrOwnerPlayerOrPlayerItself())
+ {
+ me->UpdateEntry(NPC_HAIPHOON_AIR);
+ }
+ else if (spell->Id == SPELL_DEVOUR_WATER && me->GetCharmerOrOwnerPlayerOrPlayerItself())
+ {
+ me->UpdateEntry(NPC_HAIPHOON_WATER);
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_haiphoonAI(creature);
+ }
+};
+
void AddSC_sholazar_basin()
{
new npc_injured_rainspeaker_oracle();
@@ -995,4 +1044,5 @@ void AddSC_sholazar_basin()
new npc_jungle_punch_target();
new spell_q12620_the_lifewarden_wrath();
new spell_q12589_shoot_rjr();
+ new npc_haiphoon();
}
diff --git a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp
index 5a9b6e5a94e..dcbbb76162d 100644
--- a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp
+++ b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp
@@ -37,7 +37,7 @@ enum IllidariCouncil
SAY_GATH_SLAY = 4,
SAY_GATH_COMNT = 5,
SAY_GATH_DEATH = 6,
-
+
SAY_MALA_SPECIAL1 = 2,
SAY_MALA_SPECIAL2 = 3,
SAY_MALA_SLAY = 4,
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp
index 6fe1e86551a..157473463af 100644
--- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp
+++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp
@@ -387,7 +387,7 @@ public:
{
if (victim->GetTypeId() != TYPEID_PLAYER)
return;
-
+
Talk(DemonForm ? SAY_DEMON_SLAY : SAY_NIGHTELF_SLAY);
}
diff --git a/src/server/scripts/Outland/netherstorm.cpp b/src/server/scripts/Outland/netherstorm.cpp
index 96f707b06f1..7bec3674a84 100644
--- a/src/server/scripts/Outland/netherstorm.cpp
+++ b/src/server/scripts/Outland/netherstorm.cpp
@@ -247,7 +247,7 @@ public:
if (someplayer)
{
Unit* u = Unit::GetUnit(*me, someplayer);
- if (u && u->GetTypeId() == TYPEID_PLAYER)
+ if (u && u->GetTypeId() == TYPEID_PLAYER)
Talk(EMOTE_START, u->GetGUID());
}
Event_Timer = 60000;
@@ -375,7 +375,7 @@ enum eCommanderDawnforgeData
SAY_PATHALEON_CULATOR_IMAGE_2 = 1,
SAY_PATHALEON_CULATOR_IMAGE_2_1 = 2,
SAY_PATHALEON_CULATOR_IMAGE_2_2 = 3,
-
+
QUEST_INFO_GATHERING = 10198,
SPELL_SUNFURY_DISGUISE = 34603,
};
@@ -683,7 +683,7 @@ class npc_professor_dabiri : public CreatureScript
public:
npc_professor_dabiri() : CreatureScript("npc_professor_dabiri") { }
- //OnQuestAccept:
+ //OnQuestAccept:
//if (quest->GetQuestId() == QUEST_DIMENSIUS)
//creature->AI()->Talk(WHISPER_DABIRI, player->GetGUID());
diff --git a/src/server/scripts/Outland/shadowmoon_valley.cpp b/src/server/scripts/Outland/shadowmoon_valley.cpp
index 55fce0c4a8d..65a4dbe92a5 100644
--- a/src/server/scripts/Outland/shadowmoon_valley.cpp
+++ b/src/server/scripts/Outland/shadowmoon_valley.cpp
@@ -1495,8 +1495,8 @@ public:
if (!Announced && AnnounceTimer <= diff)
{
Announced = true;
- }
- else
+ }
+ else
AnnounceTimer -= diff;
if (WaveTimer <= diff)
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index b54cc3cdf55..c8ae44d9cd9 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -367,59 +367,9 @@ class spell_gen_remove_flight_auras : public SpellScriptLoader
}
};
-// 66118 Leeching Swarm
-enum LeechingSwarmSpells
-{
- SPELL_LEECHING_SWARM_DMG = 66240,
- SPELL_LEECHING_SWARM_HEAL = 66125,
-};
-
-class spell_gen_leeching_swarm : public SpellScriptLoader
-{
- public:
- spell_gen_leeching_swarm() : SpellScriptLoader("spell_gen_leeching_swarm") { }
-
- class spell_gen_leeching_swarm_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_gen_leeching_swarm_AuraScript);
-
- bool Validate(SpellInfo const* /*spellEntry*/)
- {
- if (!sSpellMgr->GetSpellInfo(SPELL_LEECHING_SWARM_DMG) || !sSpellMgr->GetSpellInfo(SPELL_LEECHING_SWARM_HEAL))
- return false;
- return true;
- }
-
- void HandleEffectPeriodic(AuraEffect const* aurEff)
- {
- Unit* caster = GetCaster();
- if (Unit* target = GetTarget())
- {
- int32 lifeLeeched = target->CountPctFromCurHealth(aurEff->GetAmount());
- if (lifeLeeched < 250)
- lifeLeeched = 250;
- // Damage
- caster->CastCustomSpell(target, SPELL_LEECHING_SWARM_DMG, &lifeLeeched, 0, 0, false);
- // Heal
- caster->CastCustomSpell(caster, SPELL_LEECHING_SWARM_HEAL, &lifeLeeched, 0, 0, false);
- }
- }
-
- void Register()
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_gen_leeching_swarm_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const
- {
- return new spell_gen_leeching_swarm_AuraScript();
- }
-};
-
enum EluneCandle
{
- NPC_OMEN = 15467,
+ NPC_OMEN = 15467,
SPELL_ELUNE_CANDLE_OMEN_HEAD = 26622,
SPELL_ELUNE_CANDLE_OMEN_CHEST = 26624,
@@ -483,128 +433,6 @@ class spell_gen_elune_candle : public SpellScriptLoader
}
};
-// 24750 Trick
-enum TrickSpells
-{
- SPELL_PIRATE_COSTUME_MALE = 24708,
- SPELL_PIRATE_COSTUME_FEMALE = 24709,
- SPELL_NINJA_COSTUME_MALE = 24710,
- SPELL_NINJA_COSTUME_FEMALE = 24711,
- SPELL_LEPER_GNOME_COSTUME_MALE = 24712,
- SPELL_LEPER_GNOME_COSTUME_FEMALE = 24713,
- SPELL_SKELETON_COSTUME = 24723,
- SPELL_GHOST_COSTUME_MALE = 24735,
- SPELL_GHOST_COSTUME_FEMALE = 24736,
- SPELL_TRICK_BUFF = 24753,
-};
-
-class spell_gen_trick : public SpellScriptLoader
-{
- public:
- spell_gen_trick() : SpellScriptLoader("spell_gen_trick") {}
-
- class spell_gen_trick_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_gen_trick_SpellScript);
- bool Validate(SpellInfo const* /*spellEntry*/)
- {
- if (!sSpellMgr->GetSpellInfo(SPELL_PIRATE_COSTUME_MALE) || !sSpellMgr->GetSpellInfo(SPELL_PIRATE_COSTUME_FEMALE) || !sSpellMgr->GetSpellInfo(SPELL_NINJA_COSTUME_MALE)
- || !sSpellMgr->GetSpellInfo(SPELL_NINJA_COSTUME_FEMALE) || !sSpellMgr->GetSpellInfo(SPELL_LEPER_GNOME_COSTUME_MALE) || !sSpellMgr->GetSpellInfo(SPELL_LEPER_GNOME_COSTUME_FEMALE)
- || !sSpellMgr->GetSpellInfo(SPELL_SKELETON_COSTUME) || !sSpellMgr->GetSpellInfo(SPELL_GHOST_COSTUME_MALE) || !sSpellMgr->GetSpellInfo(SPELL_GHOST_COSTUME_FEMALE) || !sSpellMgr->GetSpellInfo(SPELL_TRICK_BUFF))
- return false;
- return true;
- }
-
- void HandleScript(SpellEffIndex /*effIndex*/)
- {
- Unit* caster = GetCaster();
- if (Player* target = GetHitPlayer())
- {
- uint8 gender = target->getGender();
- uint32 spellId = SPELL_TRICK_BUFF;
- switch (urand(0, 5))
- {
- case 1:
- spellId = gender ? SPELL_LEPER_GNOME_COSTUME_FEMALE : SPELL_LEPER_GNOME_COSTUME_MALE;
- break;
- case 2:
- spellId = gender ? SPELL_PIRATE_COSTUME_FEMALE : SPELL_PIRATE_COSTUME_MALE;
- break;
- case 3:
- spellId = gender ? SPELL_GHOST_COSTUME_FEMALE : SPELL_GHOST_COSTUME_MALE;
- break;
- case 4:
- spellId = gender ? SPELL_NINJA_COSTUME_FEMALE : SPELL_NINJA_COSTUME_MALE;
- break;
- case 5:
- spellId = SPELL_SKELETON_COSTUME;
- break;
- default:
- break;
- }
-
- caster->CastSpell(target, spellId, true, NULL);
- }
- }
-
- void Register()
- {
- OnEffectHitTarget += SpellEffectFn(spell_gen_trick_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const
- {
- return new spell_gen_trick_SpellScript();
- }
-};
-
-// 24751 Trick or Treat
-enum TrickOrTreatSpells
-{
- SPELL_TRICK = 24714,
- SPELL_TREAT = 24715,
- SPELL_TRICKED_OR_TREATED = 24755
-};
-
-class spell_gen_trick_or_treat : public SpellScriptLoader
-{
- public:
- spell_gen_trick_or_treat() : SpellScriptLoader("spell_gen_trick_or_treat") {}
-
- class spell_gen_trick_or_treat_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_gen_trick_or_treat_SpellScript);
-
- bool Validate(SpellInfo const* /*spellEntry*/)
- {
- if (!sSpellMgr->GetSpellInfo(SPELL_TRICK) || !sSpellMgr->GetSpellInfo(SPELL_TREAT) || !sSpellMgr->GetSpellInfo(SPELL_TRICKED_OR_TREATED))
- return false;
- return true;
- }
-
- void HandleScript(SpellEffIndex /*effIndex*/)
- {
- Unit* caster = GetCaster();
- if (Player* target = GetHitPlayer())
- {
- caster->CastSpell(target, roll_chance_i(50) ? SPELL_TRICK : SPELL_TREAT, true, NULL);
- caster->CastSpell(target, SPELL_TRICKED_OR_TREATED, true, NULL);
- }
- }
-
- void Register()
- {
- OnEffectHitTarget += SpellEffectFn(spell_gen_trick_or_treat_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const
- {
- return new spell_gen_trick_or_treat_SpellScript();
- }
-};
-
class spell_creature_permanent_feign_death : public SpellScriptLoader
{
public:
@@ -3397,12 +3225,9 @@ void AddSC_generic_spell_scripts()
new spell_gen_av_drekthar_presence();
new spell_gen_burn_brutallus();
new spell_gen_cannibalize();
- new spell_gen_leeching_swarm();
new spell_gen_parachute();
new spell_gen_pet_summoned();
new spell_gen_remove_flight_auras();
- new spell_gen_trick();
- new spell_gen_trick_or_treat();
new spell_creature_permanent_feign_death();
new spell_pvp_trinket_wotf_shared_cd();
new spell_gen_animal_blood();
diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp
index 5b1cbe0c36a..4f48c311612 100644
--- a/src/server/scripts/Spells/spell_holiday.cpp
+++ b/src/server/scripts/Spells/spell_holiday.cpp
@@ -110,7 +110,176 @@ class spell_love_is_in_the_air_romantic_picnic : public SpellScriptLoader
}
};
+// 24750 Trick
+enum TrickSpells
+{
+ SPELL_PIRATE_COSTUME_MALE = 24708,
+ SPELL_PIRATE_COSTUME_FEMALE = 24709,
+ SPELL_NINJA_COSTUME_MALE = 24710,
+ SPELL_NINJA_COSTUME_FEMALE = 24711,
+ SPELL_LEPER_GNOME_COSTUME_MALE = 24712,
+ SPELL_LEPER_GNOME_COSTUME_FEMALE = 24713,
+ SPELL_SKELETON_COSTUME = 24723,
+ SPELL_GHOST_COSTUME_MALE = 24735,
+ SPELL_GHOST_COSTUME_FEMALE = 24736,
+ SPELL_TRICK_BUFF = 24753,
+};
+
+class spell_hallow_end_trick : public SpellScriptLoader
+{
+ public:
+ spell_hallow_end_trick() : SpellScriptLoader("spell_hallow_end_trick") { }
+
+ class spell_hallow_end_trick_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hallow_end_trick_SpellScript);
+ bool Validate(SpellInfo const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PIRATE_COSTUME_MALE) || !sSpellMgr->GetSpellInfo(SPELL_PIRATE_COSTUME_FEMALE) || !sSpellMgr->GetSpellInfo(SPELL_NINJA_COSTUME_MALE)
+ || !sSpellMgr->GetSpellInfo(SPELL_NINJA_COSTUME_FEMALE) || !sSpellMgr->GetSpellInfo(SPELL_LEPER_GNOME_COSTUME_MALE) || !sSpellMgr->GetSpellInfo(SPELL_LEPER_GNOME_COSTUME_FEMALE)
+ || !sSpellMgr->GetSpellInfo(SPELL_SKELETON_COSTUME) || !sSpellMgr->GetSpellInfo(SPELL_GHOST_COSTUME_MALE) || !sSpellMgr->GetSpellInfo(SPELL_GHOST_COSTUME_FEMALE) || !sSpellMgr->GetSpellInfo(SPELL_TRICK_BUFF))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ if (Player* target = GetHitPlayer())
+ {
+ uint8 gender = target->getGender();
+ uint32 spellId = SPELL_TRICK_BUFF;
+ switch (urand(0, 5))
+ {
+ case 1:
+ spellId = gender ? SPELL_LEPER_GNOME_COSTUME_FEMALE : SPELL_LEPER_GNOME_COSTUME_MALE;
+ break;
+ case 2:
+ spellId = gender ? SPELL_PIRATE_COSTUME_FEMALE : SPELL_PIRATE_COSTUME_MALE;
+ break;
+ case 3:
+ spellId = gender ? SPELL_GHOST_COSTUME_FEMALE : SPELL_GHOST_COSTUME_MALE;
+ break;
+ case 4:
+ spellId = gender ? SPELL_NINJA_COSTUME_FEMALE : SPELL_NINJA_COSTUME_MALE;
+ break;
+ case 5:
+ spellId = SPELL_SKELETON_COSTUME;
+ break;
+ default:
+ break;
+ }
+
+ caster->CastSpell(target, spellId, true, NULL);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_hallow_end_trick_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_hallow_end_trick_SpellScript();
+ }
+};
+
+// 24751 Trick or Treat
+enum TrickOrTreatSpells
+{
+ SPELL_TRICK = 24714,
+ SPELL_TREAT = 24715,
+ SPELL_TRICKED_OR_TREATED = 24755,
+ SPELL_TRICKY_TREAT_SPEED = 42919,
+ SPELL_TRICKY_TREAT_TRIGGER = 42965,
+ SPELL_UPSET_TUMMY = 42966
+};
+
+class spell_hallow_end_trick_or_treat : public SpellScriptLoader
+{
+ public:
+ spell_hallow_end_trick_or_treat() : SpellScriptLoader("spell_hallow_end_trick_or_treat") {}
+
+ class spell_hallow_end_trick_or_treat_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hallow_end_trick_or_treat_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_TRICK) || !sSpellMgr->GetSpellInfo(SPELL_TREAT) || !sSpellMgr->GetSpellInfo(SPELL_TRICKED_OR_TREATED))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ if (Player* target = GetHitPlayer())
+ {
+ caster->CastSpell(target, roll_chance_i(50) ? SPELL_TRICK : SPELL_TREAT, true, NULL);
+ caster->CastSpell(target, SPELL_TRICKED_OR_TREATED, true, NULL);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_hallow_end_trick_or_treat_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_hallow_end_trick_or_treat_SpellScript();
+ }
+};
+
+class spell_hallow_end_tricky_treat : public SpellScriptLoader
+{
+ public:
+ spell_hallow_end_tricky_treat() : SpellScriptLoader("spell_hallow_end_tricky_treat") { }
+
+ class spell_hallow_end_tricky_treat_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hallow_end_tricky_treat_SpellScript);
+
+ bool Validate(SpellInfo const* /*spell*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_TRICKY_TREAT_SPEED))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_TRICKY_TREAT_TRIGGER))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_UPSET_TUMMY))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ if (caster->HasAura(SPELL_TRICKY_TREAT_TRIGGER) && caster->GetAuraCount(SPELL_TRICKY_TREAT_SPEED) > 3 && roll_chance_i(33))
+ caster->CastSpell(caster, SPELL_UPSET_TUMMY, true);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_hallow_end_tricky_treat_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_hallow_end_tricky_treat_SpellScript();
+ }
+};
+
void AddSC_holiday_spell_scripts()
{
+ // Love is in the Air
new spell_love_is_in_the_air_romantic_picnic();
+ // Hallow's End
+ new spell_hallow_end_trick();
+ new spell_hallow_end_trick_or_treat();
+ new spell_hallow_end_tricky_treat();
}
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index e52034ed2d9..a5122ff5f08 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -706,14 +706,14 @@ class spell_hun_tame_beast : public SpellScriptLoader
}
};
-class spell_hun_furious_howl : public SpellScriptLoader
+class spell_hun_target_only_pet_and_owner : public SpellScriptLoader
{
public:
- spell_hun_furious_howl() : SpellScriptLoader("spell_hun_furious_howl") { }
+ spell_hun_target_only_pet_and_owner() : SpellScriptLoader("spell_hun_target_only_pet_and_owner") { }
- class spell_hun_furious_howl_SpellScript : public SpellScript
+ class spell_hun_target_only_pet_and_owner_SpellScript : public SpellScript
{
- PrepareSpellScript(spell_hun_furious_howl_SpellScript);
+ PrepareSpellScript(spell_hun_target_only_pet_and_owner_SpellScript);
void FilterTargets(std::list<WorldObject*>& targets)
{
@@ -725,14 +725,14 @@ class spell_hun_furious_howl : public SpellScriptLoader
void Register()
{
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_furious_howl_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_furious_howl_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_PARTY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_target_only_pet_and_owner_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_target_only_pet_and_owner_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_PARTY);
}
};
SpellScript* GetSpellScript() const
{
- return new spell_hun_furious_howl_SpellScript();
+ return new spell_hun_target_only_pet_and_owner_SpellScript();
}
};
@@ -752,5 +752,5 @@ void AddSC_hunter_spell_scripts()
new spell_hun_misdirection_proc();
new spell_hun_disengage();
new spell_hun_tame_beast();
- new spell_hun_furious_howl();
+ new spell_hun_target_only_pet_and_owner();
}
diff --git a/src/server/scripts/World/npc_professions.cpp b/src/server/scripts/World/npc_professions.cpp
index a04912d0828..a5f6b4cfecf 100644
--- a/src/server/scripts/World/npc_professions.cpp
+++ b/src/server/scripts/World/npc_professions.cpp
@@ -785,7 +785,7 @@ enum eEngineeringTrinkets
SPELL_TO_TOSHLEY = 36955,
};
-#define GOSSIP_ITEM_ZAP "[PH] Unknown"
+#define GOSSIP_ITEM_ZAP "This Dimensional Imploder sounds dangerous! How can I make one?"
#define GOSSIP_ITEM_JHORDY "I must build a beacon for this marvelous device!"
#define GOSSIP_ITEM_KABLAM "[PH] Unknown"
@@ -819,7 +819,7 @@ public:
switch (creature->GetEntry())
{
case NPC_ZAP:
- canLearn = CanLearn(player, 7249, 0, 260, S_GOBLIN, SPELL_TO_EVERLOOK, npcTextId);
+ canLearn = CanLearn(player, 6092, 0, 260, S_GOBLIN, SPELL_TO_EVERLOOK, npcTextId);
if (canLearn)
gossipItem = GOSSIP_ITEM_ZAP;
break;
diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp
index 96f7db23281..936052fd8ad 100644
--- a/src/server/scripts/World/npcs_special.cpp
+++ b/src/server/scripts/World/npcs_special.cpp
@@ -913,7 +913,7 @@ public:
struct npc_garments_of_questsAI : public npc_escortAI
{
- npc_garments_of_questsAI(Creature* creature) : npc_escortAI(creature)
+ npc_garments_of_questsAI(Creature* creature) : npc_escortAI(creature)
{
Reset();
}
diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp
index 050ec790dbb..3c7b433e125 100644
--- a/src/tools/vmap4_extractor/vmapexport.cpp
+++ b/src/tools/vmap4_extractor/vmapexport.cpp
@@ -586,7 +586,7 @@ int main(int argc, char ** argv)
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Create the working directory
if (mkdir(szWorkDirWmo
-#ifdef __linux__
+#if defined(__linux__) || defined(__APPLE__)
, 0711
#endif
))