diff options
Diffstat (limited to 'src')
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 )) |