diff --git a/src/server/scripts/Pet/pet_generic.cpp b/src/server/scripts/Pet/pet_generic.cpp index c8318e43f..149321df8 100644 --- a/src/server/scripts/Pet/pet_generic.cpp +++ b/src/server/scripts/Pet/pet_generic.cpp @@ -38,57 +38,46 @@ enum Mojo SPELL_SEDUCTION_VISUAL = 43919 }; -class npc_pet_gen_mojo : public CreatureScript +struct npc_pet_gen_mojo : public ScriptedAI { -public: - npc_pet_gen_mojo() : CreatureScript("npc_pet_gen_mojo") { } + npc_pet_gen_mojo(Creature* creature) : ScriptedAI(creature) { } - struct npc_pet_gen_mojoAI : public ScriptedAI + void Reset() override { - npc_pet_gen_mojoAI(Creature* creature) : ScriptedAI(creature) { } + _victimGUID.Clear(); - void Reset() override - { - _victimGUID.Clear(); - - if (Unit* owner = me->GetOwner()) - me->GetMotionMaster()->MoveFollow(owner, 0.0f, 0.0f); - } - - void EnterCombat(Unit* /*who*/) override { } - void UpdateAI(uint32 /*diff*/) override { } - - void ReceiveEmote(Player* player, uint32 emote) override - { - me->HandleEmoteCommand(emote); - Unit* owner = me->GetOwner(); - if (emote != TEXT_EMOTE_KISS || !owner || owner->GetTypeId() != TYPEID_PLAYER || - owner->ToPlayer()->GetTeamId(true) != player->GetTeamId(true)) - { - return; - } - - Talk(SAY_MOJO, player); - - if (_victimGUID) - if (Player* victim = ObjectAccessor::GetPlayer(*me, _victimGUID)) - victim->RemoveAura(SPELL_FEELING_FROGGY); - - _victimGUID = player->GetGUID(); - - DoCast(player, SPELL_FEELING_FROGGY, true); - DoCast(me, SPELL_SEDUCTION_VISUAL, true); - me->GetMotionMaster()->MoveFollow(player, 0.0f, 0.0f); - } - - private: - ObjectGuid _victimGUID; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pet_gen_mojoAI(creature); + if (Unit* owner = me->GetOwner()) + me->GetMotionMaster()->MoveFollow(owner, 0.0f, 0.0f); } + + void EnterCombat(Unit* /*who*/) override { } + void UpdateAI(uint32 /*diff*/) override { } + + void ReceiveEmote(Player* player, uint32 emote) override + { + me->HandleEmoteCommand(emote); + Unit* owner = me->GetOwner(); + if (emote != TEXT_EMOTE_KISS || !owner || owner->GetTypeId() != TYPEID_PLAYER || + owner->ToPlayer()->GetTeamId(true) != player->GetTeamId(true)) + { + return; + } + + Talk(SAY_MOJO, player); + + if (_victimGUID) + if (Player* victim = ObjectAccessor::GetPlayer(*me, _victimGUID)) + victim->RemoveAura(SPELL_FEELING_FROGGY); + + _victimGUID = player->GetGUID(); + + DoCast(player, SPELL_FEELING_FROGGY, true); + DoCast(me, SPELL_SEDUCTION_VISUAL, true); + me->GetMotionMaster()->MoveFollow(player, 0.0f, 0.0f); + } + +private: + ObjectGuid _victimGUID; }; enum soulTrader @@ -103,59 +92,48 @@ enum soulTrader EVENT_ADD_TOKEN = 2 }; -class npc_pet_gen_soul_trader_beacon : public CreatureScript +struct npc_pet_gen_soul_trader_beacon : public ScriptedAI { -public: - npc_pet_gen_soul_trader_beacon() : CreatureScript("npc_pet_gen_soul_trader_beacon") { } - - struct npc_pet_gen_soul_trader_beaconAI : public ScriptedAI + ObjectGuid ownerGUID; + EventMap events; + npc_pet_gen_soul_trader_beacon(Creature* c) : ScriptedAI(c) { - ObjectGuid ownerGUID; - EventMap events; - npc_pet_gen_soul_trader_beaconAI(Creature* c) : ScriptedAI(c) - { - events.Reset(); - events.ScheduleEvent(EVENT_INITIAL_TALK, 0); - if (me->ToTempSummon()) - if (Unit* owner = me->ToTempSummon()->GetOwner()) - { - owner->CastSpell(owner, SPELL_PROC_TRIGGER_ON_KILL_AURA, true); - ownerGUID = owner->GetGUID(); - } - } - - Player* GetOwner() const { return ObjectAccessor::GetPlayer(*me, ownerGUID); } - - void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) override - { - if (spellInfo->Id == SPELL_STEAL_ESSENCE_VISUAL && target == me) + events.Reset(); + events.ScheduleEvent(EVENT_INITIAL_TALK, 0); + if (me->ToTempSummon()) + if (Unit* owner = me->ToTempSummon()->GetOwner()) { - Talk(1); - events.ScheduleEvent(EVENT_ADD_TOKEN, 3000); - me->CastSpell(me, SPELL_EMOTE_STATE_SWIM_RUN, true); + owner->CastSpell(owner, SPELL_PROC_TRIGGER_ON_KILL_AURA, true); + ownerGUID = owner->GetGUID(); } - } + } - void UpdateAI(uint32 diff) override - { - events.Update(diff); - switch (events.ExecuteEvent()) - { - case EVENT_INITIAL_TALK: - Talk(0); - break; - case EVENT_ADD_TOKEN: - me->RemoveAurasDueToSpell(SPELL_EMOTE_STATE_SWIM_RUN); - me->CastSpell(me, SPELL_CREATE_TOKEN, true); - Talk(2); - break; - } - } - }; + Player* GetOwner() const { return ObjectAccessor::GetPlayer(*me, ownerGUID); } - CreatureAI* GetAI(Creature* creature) const override + void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) override { - return new npc_pet_gen_soul_trader_beaconAI (creature); + if (spellInfo->Id == SPELL_STEAL_ESSENCE_VISUAL && target == me) + { + Talk(1); + events.ScheduleEvent(EVENT_ADD_TOKEN, 3000); + me->CastSpell(me, SPELL_EMOTE_STATE_SWIM_RUN, true); + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + switch (events.ExecuteEvent()) + { + case EVENT_INITIAL_TALK: + Talk(0); + break; + case EVENT_ADD_TOKEN: + me->RemoveAurasDueToSpell(SPELL_EMOTE_STATE_SWIM_RUN); + me->CastSpell(me, SPELL_CREATE_TOKEN, true); + Talk(2); + break; + } } }; @@ -216,139 +194,126 @@ static argentPonyBanner argentBanners[MAX_RACES] = {2778, 63423, "Exodar Champion's Pennant"} }; -class npc_pet_gen_argent_pony_bridle : public CreatureScript +struct npc_pet_gen_argent_pony_bridle : public ScriptedAI { -public: - npc_pet_gen_argent_pony_bridle() : CreatureScript("npc_pet_gen_argent_pony_bridle") { } - - struct npc_pet_gen_argent_pony_bridleAI : public ScriptedAI + npc_pet_gen_argent_pony_bridle(Creature* c) : ScriptedAI(c) { - npc_pet_gen_argent_pony_bridleAI(Creature* c) : ScriptedAI(c) + _state = ARGENT_PONY_STATE_NONE; + _init = false; + _mountTimer = 4000; + _lastAura = 0; + memset(_banners, 0, sizeof(_banners)); + } + + void EnterEvadeMode() override + { + if (Unit* owner = me->GetCharmerOrOwner()) { - _state = ARGENT_PONY_STATE_NONE; - _init = false; - _mountTimer = 4000; - _lastAura = 0; - memset(_banners, 0, sizeof(_banners)); + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); } + } - void EnterEvadeMode() override - { - if (Unit* owner = me->GetCharmerOrOwner()) - { - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); - } - } + void Reset() override + { + if (_init) + return; - void Reset() override - { - if (_init) - return; + _init = true; + uint32 duration = 0; + uint32 aura = 0; + me->SetUInt32Value(UNIT_NPC_FLAGS, 0); - _init = true; - uint32 duration = 0; - uint32 aura = 0; - me->SetUInt32Value(UNIT_NPC_FLAGS, 0); + if (Unit* owner = me->GetCharmerOrOwner()) + if (Player* player = owner->ToPlayer()) + if (player->HasAchieved(ACHIEVEMENT_PONY_UP)) + { + _state = ARGENT_PONY_STATE_ENCH; - if (Unit* owner = me->GetCharmerOrOwner()) - if (Player* player = owner->ToPlayer()) - if (player->HasAchieved(ACHIEVEMENT_PONY_UP)) + aura = (player->GetTeamId(true) == TEAM_ALLIANCE ? SPELL_AURA_TIRED_S : SPELL_AURA_TIRED_G); + duration = player->GetSpellCooldownDelay(aura); + me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + for (uint8 i = 0; i < 3; ++i) { - _state = ARGENT_PONY_STATE_ENCH; - - aura = (player->GetTeamId(true) == TEAM_ALLIANCE ? SPELL_AURA_TIRED_S : SPELL_AURA_TIRED_G); - duration = player->GetSpellCooldownDelay(aura); - me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - for (uint8 i = 0; i < 3; ++i) + if (player->GetTeamId(true) == TEAM_ALLIANCE) { - if (player->GetTeamId(true) == TEAM_ALLIANCE) + if (uint32 cooldown = player->GetSpellCooldownDelay(SPELL_AURA_POSTMAN_S + i)) { - if (uint32 cooldown = player->GetSpellCooldownDelay(SPELL_AURA_POSTMAN_S + i)) - { - duration = cooldown; - aura = SPELL_AURA_POSTMAN_S + i; - _state = argentPonyService[TEAM_ALLIANCE][i]; - me->ToTempSummon()->UnSummon(duration); - break; - } - } - else - { - if (uint32 cooldown = player->GetSpellCooldownDelay(SPELL_AURA_BANK_G + i)) - { - duration = cooldown * IN_MILLISECONDS; - aura = SPELL_AURA_BANK_G + i; - _state = argentPonyService[TEAM_HORDE][i]; - me->ToTempSummon()->UnSummon(duration); - break; - } + duration = cooldown; + aura = SPELL_AURA_POSTMAN_S + i; + _state = argentPonyService[TEAM_ALLIANCE][i]; + me->ToTempSummon()->UnSummon(duration); + break; + } + } + else + { + if (uint32 cooldown = player->GetSpellCooldownDelay(SPELL_AURA_BANK_G + i)) + { + duration = cooldown * IN_MILLISECONDS; + aura = SPELL_AURA_BANK_G + i; + _state = argentPonyService[TEAM_HORDE][i]; + me->ToTempSummon()->UnSummon(duration); + break; } } - - // Generate Banners - uint32 mask = player->GetTeamId(true) ? RACEMASK_HORDE : RACEMASK_ALLIANCE; - for (uint8 i = 1; i < MAX_RACES; ++i) - if (mask & (1 << (i - 1)) && player->HasAchieved(argentBanners[i].achievement)) - _banners[i] = true; } - if (duration && aura) - { - if (Aura* aur = me->AddAura(aura, me)) - aur->SetDuration(duration); - } - } - - void UpdateAI(uint32 diff) override - { - _mountTimer += diff; - if (_mountTimer > 5000) - { - _mountTimer = 0; - if (_state == ARGENT_PONY_STATE_NONE) - me->SetUInt32Value(UNIT_NPC_FLAGS, 0); - else if (Unit* owner = me->GetCharmerOrOwner()) - { - if (owner->IsMounted() && !me->IsMounted()) - me->CastSpell(me, SPELL_PONY_MOUNT, false); - else if (!owner->IsMounted() && me->IsMounted()) - me->RemoveAurasDueToSpell(SPELL_PONY_MOUNT); + // Generate Banners + uint32 mask = player->GetTeamId(true) ? RACEMASK_HORDE : RACEMASK_ALLIANCE; + for (uint8 i = 1; i < MAX_RACES; ++i) + if (mask & (1 << (i - 1)) && player->HasAchieved(argentBanners[i].achievement)) + _banners[i] = true; } - } - } - uint32 GetData(uint32 param) const override + if (duration && aura) { - if (param == 0) - return _state; - - return _banners[param]; + if (Aura* aur = me->AddAura(aura, me)) + aur->SetDuration(duration); } + } - void DoAction(int32 param) override + void UpdateAI(uint32 diff) override + { + _mountTimer += diff; + if (_mountTimer > 5000) { - if (param > 60000) + _mountTimer = 0; + if (_state == ARGENT_PONY_STATE_NONE) + me->SetUInt32Value(UNIT_NPC_FLAGS, 0); + else if (Unit* owner = me->GetCharmerOrOwner()) { - if (_lastAura) - me->RemoveAurasDueToSpell(_lastAura); - _lastAura = param; - return; + if (owner->IsMounted() && !me->IsMounted()) + me->CastSpell(me, SPELL_PONY_MOUNT, false); + else if (!owner->IsMounted() && me->IsMounted()) + me->RemoveAurasDueToSpell(SPELL_PONY_MOUNT); } + } + } - _state = param; + uint32 GetData(uint32 param) const override + { + if (param == 0) + return _state; + + return _banners[param]; + } + + void DoAction(int32 param) override + { + if (param > 60000) + { + if (_lastAura) + me->RemoveAurasDueToSpell(_lastAura); + _lastAura = param; + return; } - private: - bool _init; - uint8 _state; - int32 _mountTimer; - bool _banners[MAX_RACES]; - uint32 _lastAura; - }; + _state = param; + } - bool OnGossipHello(Player* player, Creature* creature) override + bool OnGossipHello(Player* player, Creature* creature) { if (player->GetGUID() != creature->GetOwnerGUID()) return true; @@ -372,7 +337,7 @@ public: return true; } - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 action) override + bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 action) { CloseGossipMenuFor(player); uint32 spellId = 0; @@ -417,10 +382,12 @@ public: return true; } - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pet_gen_argent_pony_bridleAI (creature); - } +private: + bool _init; + uint8 _state; + int32 _mountTimer; + bool _banners[MAX_RACES]; + uint32 _lastAura; }; enum eTargetFollowingBomb @@ -435,332 +402,266 @@ enum eTargetFollowingBomb SPELL_HIGH_EXPLOSIVE_SHEEP = 44279, }; -class npc_pet_gen_target_following_bomb : public CreatureScript +struct npc_pet_gen_target_following_bomb : public NullCreatureAI { -public: - npc_pet_gen_target_following_bomb() : CreatureScript("npc_pet_gen_target_following_bomb") { } - - struct npc_pet_gen_target_following_bombAI : public NullCreatureAI + npc_pet_gen_target_following_bomb(Creature* c) : NullCreatureAI(c) { - npc_pet_gen_target_following_bombAI(Creature* c) : NullCreatureAI(c) + checkTimer = 0; + bombSpellId = 0; + + switch (me->GetEntry()) + { + case NPC_EXPLOSIVE_SHEEP: + bombSpellId = SPELL_EXPLOSIVE_SHEEP; + break; + case NPC_GOBLIN_BOMB: + bombSpellId = SPELL_EXPLOSIVE_GOBLIN; + break; + case NPC_HIGH_EXPLOSIVE_SHEEP: + bombSpellId = SPELL_HIGH_EXPLOSIVE_SHEEP; + break; + } + } + + uint32 bombSpellId; + uint32 checkTimer; + + void UpdateAI(uint32 diff) override + { + checkTimer += diff; + if (checkTimer >= 1000) { checkTimer = 0; - bombSpellId = 0; - - switch (me->GetEntry()) + if (Unit* target = me->SelectNearestTarget(30.0f)) { - case NPC_EXPLOSIVE_SHEEP: - bombSpellId = SPELL_EXPLOSIVE_SHEEP; - break; - case NPC_GOBLIN_BOMB: - bombSpellId = SPELL_EXPLOSIVE_GOBLIN; - break; - case NPC_HIGH_EXPLOSIVE_SHEEP: - bombSpellId = SPELL_HIGH_EXPLOSIVE_SHEEP; - break; - } - } - - uint32 bombSpellId; - uint32 checkTimer; - - void UpdateAI(uint32 diff) override - { - checkTimer += diff; - if (checkTimer >= 1000) - { - checkTimer = 0; - if (Unit* target = me->SelectNearestTarget(30.0f)) + me->GetMotionMaster()->MoveFollow(target, 0.f, 0.f); + if (me->GetDistance(target) < 3.0f) { - me->GetMotionMaster()->MoveFollow(target, 0.f, 0.f); - if (me->GetDistance(target) < 3.0f) - { - me->CastSpell(me, bombSpellId, false); - me->DespawnOrUnsummon(500); - } + me->CastSpell(me, bombSpellId, false); + me->DespawnOrUnsummon(500); } - else if (!me->HasUnitState(UNIT_STATE_FOLLOW)) + } + else if (!me->HasUnitState(UNIT_STATE_FOLLOW)) + { + if (Unit* owner = me->GetCharmerOrOwner()) { - if (Unit* owner = me->GetCharmerOrOwner()) - { - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - } + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } } } - }; - - CreatureAI* GetAI(Creature* pCreature) const override - { - return new npc_pet_gen_target_following_bombAI (pCreature); } }; -class npc_pet_gen_gnomish_flame_turret : public CreatureScript +struct npc_pet_gen_gnomish_flame_turret : public ScriptedAI { -public: - npc_pet_gen_gnomish_flame_turret() : CreatureScript("npc_pet_gen_gnomish_flame_turret") { } - - struct npc_pet_gen_gnomish_flame_turretAI : public ScriptedAI + npc_pet_gen_gnomish_flame_turret(Creature* c) : ScriptedAI(c) { - npc_pet_gen_gnomish_flame_turretAI(Creature* c) : ScriptedAI(c) - { - checkTimer = 0; - } - - uint32 checkTimer; - - void Reset() override - { - me->GetMotionMaster()->Clear(false); - } - - void AttackStart(Unit* who) override - { - if (!who) - return; - - if (me->Attack(who, false)) - DoStartNoMovement(who); - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!me->GetVictim()) - return; - - if (Unit* target = me->SelectVictim()) - { - AttackStart(target); - DoSpellAttackIfReady(me->m_spells[0]); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pet_gen_gnomish_flame_turretAI (creature); + checkTimer = 0; } -}; -class npc_pet_gen_valkyr_guardian : public CreatureScript -{ -public: - npc_pet_gen_valkyr_guardian() : CreatureScript("npc_pet_gen_valkyr_guardian") { } + uint32 checkTimer; - struct npc_pet_gen_valkyr_guardianAI : public ScriptedAI + void Reset() override { - npc_pet_gen_valkyr_guardianAI(Creature* c) : ScriptedAI(c) + me->GetMotionMaster()->Clear(false); + } + + void AttackStart(Unit* who) override + { + if (!who) + return; + + if (me->Attack(who, false)) + DoStartNoMovement(who); + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!me->GetVictim()) + return; + + if (Unit* target = me->SelectVictim()) { - me->SetReactState(REACT_DEFENSIVE); - me->SetDisableGravity(true); - me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); - targetCheck = 0; - } - - uint32 targetCheck; - - void InitializeAI() override - { - if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) - if (Unit* target = owner->GetSelectedUnit()) - if (!owner->IsFriendlyTo(target)) - AttackStart(target); - } - - void OwnerAttacked(Unit* target) override - { - if (!target || (me->GetVictim() && me->GetVictim()->IsAlive() && !me->GetVictim()->HasBreakableByDamageCrowdControlAura())) - return; - AttackStart(target); + DoSpellAttackIfReady(me->m_spells[0]); + } + } +}; + +struct npc_pet_gen_valkyr_guardian : public ScriptedAI +{ + npc_pet_gen_valkyr_guardian(Creature* c) : ScriptedAI(c) + { + me->SetReactState(REACT_DEFENSIVE); + me->SetDisableGravity(true); + me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); + targetCheck = 0; + } + + uint32 targetCheck; + + void InitializeAI() override + { + if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) + if (Unit* target = owner->GetSelectedUnit()) + if (!owner->IsFriendlyTo(target)) + AttackStart(target); + } + + void OwnerAttacked(Unit* target) override + { + if (!target || (me->GetVictim() && me->GetVictim()->IsAlive() && !me->GetVictim()->HasBreakableByDamageCrowdControlAura())) + return; + + AttackStart(target); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + targetCheck += diff; + if (targetCheck > 1000) + { + targetCheck = 0; + if (Unit* owner = me->GetCharmerOrOwner()) + if (Unit* ownerVictim = owner->GetVictim()) + if (!ownerVictim->HasBreakableByDamageCrowdControlAura()) + AttackStart(ownerVictim); + } + return; } - void UpdateAI(uint32 diff) override + if (me->isAttackReady() && !me->GetVictim()->HasBreakableByDamageCrowdControlAura()) + DoSpellAttackIfReady(me->GetCreatureTemplate()->spells[0]); + } +}; + +class spell_pet_gen_valkyr_guardian_smite : public SpellScript +{ + PrepareSpellScript(spell_pet_gen_valkyr_guardian_smite); + + void RecalculateDamage() + { + if (GetHitUnit() != GetCaster()) { - if (!UpdateVictim()) - { - targetCheck += diff; - if (targetCheck > 1000) + std::list* targetsInfo = GetSpell()->GetUniqueTargetInfo(); + for (std::list::iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) + if (ihit->targetGUID == GetCaster()->GetGUID()) + ihit->damage = -int32(GetHitDamage() * 0.25f); + } + } + + void Register() override + { + OnHit += SpellHitFn(spell_pet_gen_valkyr_guardian_smite::RecalculateDamage); + } +}; + +struct npc_pet_gen_imp_in_a_bottle : public NullCreatureAI +{ + npc_pet_gen_imp_in_a_bottle(Creature* c) : NullCreatureAI(c) + { + _talkTimer = 0; + _ownerGUID.Clear(); + _hasParty = false; + } + + WorldPacket _data; + uint32 _talkTimer; + ObjectGuid _ownerGUID; + bool _hasParty; + + void InitializeAI() override + { + NullCreatureAI::InitializeAI(); + + if (TempSummon* summon = me->ToTempSummon()) + if (Unit* owner = summon->GetSummonerUnit()) + if (owner->GetTypeId() == TYPEID_PLAYER) { - targetCheck = 0; - if (Unit* owner = me->GetCharmerOrOwner()) - if (Unit* ownerVictim = owner->GetVictim()) - if (!ownerVictim->HasBreakableByDamageCrowdControlAura()) - AttackStart(ownerVictim); + _ownerGUID = owner->GetGUID(); + if (owner->ToPlayer()->GetGroup()) + { + _hasParty = true; + std::string const& text = sCreatureTextMgr->GetLocalizedChatString(me->GetEntry(), 0, 0 /*text group*/, urand(0, 60) /*text id*/, LOCALE_enUS); + + _data.Initialize(SMSG_MESSAGECHAT, 200); // guess size + _data << uint8(CHAT_MSG_MONSTER_PARTY); + _data << uint32(LANG_UNIVERSAL); + _data << me->GetGUID(); + _data << uint32(0); + _data << uint32(me->GetName().size() + 1); + _data << me->GetName(); + _data << uint64(0); + _data << uint32(text.size() + 1); + _data << text.c_str(); + _data << uint8(0); + } } - return; - } - - if (me->isAttackReady() && !me->GetVictim()->HasBreakableByDamageCrowdControlAura()) - DoSpellAttackIfReady(me->GetCreatureTemplate()->spells[0]); - } - }; - - CreatureAI* GetAI(Creature* pCreature) const override - { - return new npc_pet_gen_valkyr_guardianAI (pCreature); } -}; -class spell_pet_gen_valkyr_guardian_smite : public SpellScriptLoader -{ -public: - spell_pet_gen_valkyr_guardian_smite() : SpellScriptLoader("spell_pet_gen_valkyr_guardian_smite") { } - - class spell_pet_gen_valkyr_guardian_smite_SpellScript : public SpellScript + void UpdateAI(uint32 diff) override { - PrepareSpellScript(spell_pet_gen_valkyr_guardian_smite_SpellScript); - - void RecalculateDamage() - { - if (GetHitUnit() != GetCaster()) - { - std::list* targetsInfo = GetSpell()->GetUniqueTargetInfo(); - for (std::list::iterator ihit = targetsInfo->begin(); ihit != targetsInfo->end(); ++ihit) - if (ihit->targetGUID == GetCaster()->GetGUID()) - ihit->damage = -int32(GetHitDamage() * 0.25f); - } - } - - void Register() override - { - OnHit += SpellHitFn(spell_pet_gen_valkyr_guardian_smite_SpellScript::RecalculateDamage); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_pet_gen_valkyr_guardian_smite_SpellScript(); - } -}; - -class npc_pet_gen_imp_in_a_bottle : public CreatureScript -{ -public: - npc_pet_gen_imp_in_a_bottle() : CreatureScript("npc_pet_gen_imp_in_a_bottle") { } - - struct npc_pet_gen_imp_in_a_bottleAI : public NullCreatureAI - { - npc_pet_gen_imp_in_a_bottleAI(Creature* c) : NullCreatureAI(c) + _talkTimer += diff; + if (_talkTimer >= 5000) { _talkTimer = 0; - _ownerGUID.Clear(); - _hasParty = false; - } - - WorldPacket _data; - uint32 _talkTimer; - ObjectGuid _ownerGUID; - bool _hasParty; - - void InitializeAI() override - { - NullCreatureAI::InitializeAI(); - - if (TempSummon* summon = me->ToTempSummon()) - if (Unit* owner = summon->GetSummonerUnit()) - if (owner->GetTypeId() == TYPEID_PLAYER) - { - _ownerGUID = owner->GetGUID(); - if (owner->ToPlayer()->GetGroup()) - { - _hasParty = true; - std::string const& text = sCreatureTextMgr->GetLocalizedChatString(me->GetEntry(), 0, 0 /*text group*/, urand(0, 60) /*text id*/, LOCALE_enUS); - - _data.Initialize(SMSG_MESSAGECHAT, 200); // guess size - _data << uint8(CHAT_MSG_MONSTER_PARTY); - _data << uint32(LANG_UNIVERSAL); - _data << me->GetGUID(); - _data << uint32(0); - _data << uint32(me->GetName().size() + 1); - _data << me->GetName(); - _data << uint64(0); - _data << uint32(text.size() + 1); - _data << text.c_str(); - _data << uint8(0); - } - } - } - - void UpdateAI(uint32 diff) override - { - _talkTimer += diff; - if (_talkTimer >= 5000) + me->DespawnOrUnsummon(1); + if (!_hasParty) + Talk(0, ObjectAccessor::GetPlayer(*me, _ownerGUID)); + else if (Player* player = ObjectAccessor::GetPlayer(*me, _ownerGUID)) { - _talkTimer = 0; - me->DespawnOrUnsummon(1); - if (!_hasParty) - Talk(0, ObjectAccessor::GetPlayer(*me, _ownerGUID)); - else if (Player* player = ObjectAccessor::GetPlayer(*me, _ownerGUID)) - { - uint8 limit = 0; - if (player->GetGroup()) - for (GroupReference* itr = player->GetGroup()->GetFirstMember(); itr != nullptr && limit < 4; itr = itr->next(), ++limit) - if (Player* groupPlayer = itr->GetSource()) - if (groupPlayer != player) - groupPlayer->GetSession()->SendPacket(&_data); + uint8 limit = 0; + if (player->GetGroup()) + for (GroupReference* itr = player->GetGroup()->GetFirstMember(); itr != nullptr && limit < 4; itr = itr->next(), ++limit) + if (Player* groupPlayer = itr->GetSource()) + if (groupPlayer != player) + groupPlayer->GetSession()->SendPacket(&_data); - player->GetSession()->SendPacket(&_data); - } + player->GetSession()->SendPacket(&_data); } } - }; - - CreatureAI* GetAI(Creature* pCreature) const override - { - return new npc_pet_gen_imp_in_a_bottleAI (pCreature); } }; -class npc_pet_gen_wind_rider_cub : public CreatureScript +struct npc_pet_gen_wind_rider_cub : public NullCreatureAI { -public: - npc_pet_gen_wind_rider_cub() : CreatureScript("npc_pet_gen_wind_rider_cub") { } - - struct npc_pet_gen_wind_rider_cubAI : public NullCreatureAI + npc_pet_gen_wind_rider_cub(Creature* c) : NullCreatureAI(c) { - npc_pet_gen_wind_rider_cubAI(Creature* c) : NullCreatureAI(c) - { - isFlying = true; - checkTimer = 0; - checkTimer2 = 2000; - me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); - } + isFlying = true; + checkTimer = 0; + checkTimer2 = 2000; + me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); + } - bool isFlying; - uint32 checkTimer; - uint32 checkTimer2; + bool isFlying; + uint32 checkTimer; + uint32 checkTimer2; - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + checkTimer2 += diff; + if (checkTimer2 > 2000) { - checkTimer2 += diff; - if (checkTimer2 > 2000) + checkTimer2 = 0; + if (Unit* owner = me->GetOwner()) { - checkTimer2 = 0; - if (Unit* owner = me->GetOwner()) + if (owner->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || owner->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED)) { - if (owner->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || owner->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED)) - { - isFlying = true; - me->SetCanFly(true); - me->SetDisableGravity(true); - } - else if (isFlying) - { - isFlying = false; - me->SetCanFly(false); - me->SetDisableGravity(false); - me->GetMotionMaster()->MoveFall(); - } + isFlying = true; + me->SetCanFly(true); + me->SetDisableGravity(true); + } + else if (isFlying) + { + isFlying = false; + me->SetCanFly(false); + me->SetDisableGravity(false); + me->GetMotionMaster()->MoveFall(); } } } - }; - - CreatureAI* GetAI(Creature* pCreature) const override - { - return new npc_pet_gen_wind_rider_cubAI (pCreature); } }; @@ -770,218 +671,174 @@ enum turkey SPELL_TURKEY_STARTS_TO_BURN = 61768, }; -class npc_pet_gen_plump_turkey : public CreatureScript +struct npc_pet_gen_plump_turkey : public PassiveAI { -public: - npc_pet_gen_plump_turkey() : CreatureScript("npc_pet_gen_plump_turkey") { } - - struct npc_pet_gen_plump_turkeyAI : public PassiveAI + npc_pet_gen_plump_turkey(Creature* c) : PassiveAI(c) { - npc_pet_gen_plump_turkeyAI(Creature* c) : PassiveAI(c) + goGUID.Clear(); + jumpTimer = 0; + checkTimer = 0; + jumping = false; + } + + ObjectGuid goGUID; + uint32 jumpTimer; + uint32 checkTimer; + bool jumping; + + void MovementInform(uint32 type, uint32 id) override + { + if (type == EFFECT_MOTION_TYPE && id == 1) + { + Unit::Kill(me, me); + me->AddAura(SPELL_TURKEY_STARTS_TO_BURN, me); + } + } + + void UpdateAI(uint32 diff) override + { + if (jumping) + return; + + if (jumpTimer) + { + jumpTimer += diff; + if (jumpTimer >= 2000) + { + if (GameObject* go = me->GetMap()->GetGameObject(goGUID)) + me->GetMotionMaster()->MoveJump(*go, 5.0f, 10.0f, 1); + jumping = true; + } + return; + } + + checkTimer += diff; + if (checkTimer > 3000) { - goGUID.Clear(); - jumpTimer = 0; checkTimer = 0; - jumping = false; - } - - ObjectGuid goGUID; - uint32 jumpTimer; - uint32 checkTimer; - bool jumping; - - void MovementInform(uint32 type, uint32 id) override - { - if (type == EFFECT_MOTION_TYPE && id == 1) + if (GameObject* go = me->FindNearestGameObject(GO_BASIC_CAMPFIRE, 7.0f)) { - Unit::Kill(me, me); - me->AddAura(SPELL_TURKEY_STARTS_TO_BURN, me); + goGUID = go->GetGUID(); + me->StopMoving(); + me->GetMotionMaster()->Clear(false); + me->SetFacingTo(me->GetAngle(go)); + Talk(0); + jumpTimer = 1; } } + } +}; - void UpdateAI(uint32 diff) override +struct npc_pet_gen_toxic_wasteling : public PassiveAI +{ + npc_pet_gen_toxic_wasteling(Creature* c) : PassiveAI(c) + { + } + + uint32 checkTimer; + + void Reset() override { checkTimer = 3000; } + + void EnterEvadeMode() override + { + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type == EFFECT_MOTION_TYPE && id == 1) + checkTimer = 1; + } + + void UpdateAI(uint32 diff) override + { + if (checkTimer) { - if (jumping) - return; - - if (jumpTimer) - { - jumpTimer += diff; - if (jumpTimer >= 2000) - { - if (GameObject* go = me->GetMap()->GetGameObject(goGUID)) - me->GetMotionMaster()->MoveJump(*go, 5.0f, 10.0f, 1); - jumping = true; - } - return; - } - + if (checkTimer == 1) + me->GetMotionMaster()->MovementExpired(false); checkTimer += diff; - if (checkTimer > 3000) + if (checkTimer >= 3000) { - checkTimer = 0; - if (GameObject* go = me->FindNearestGameObject(GO_BASIC_CAMPFIRE, 7.0f)) + if (Unit* owner = me->GetCharmerOrOwner()) { - goGUID = go->GetGUID(); - me->StopMoving(); me->GetMotionMaster()->Clear(false); - me->SetFacingTo(me->GetAngle(go)); - Talk(0); - jumpTimer = 1; + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); } - } - } - }; - - CreatureAI* GetAI(Creature* pCreature) const override - { - return new npc_pet_gen_plump_turkeyAI (pCreature); - } -}; - -class npc_pet_gen_toxic_wasteling : public CreatureScript -{ -public: - npc_pet_gen_toxic_wasteling() : CreatureScript("npc_pet_gen_toxic_wasteling") { } - - struct npc_pet_gen_toxic_wastelingAI : public PassiveAI - { - npc_pet_gen_toxic_wastelingAI(Creature* c) : PassiveAI(c) - { - } - - uint32 checkTimer; - - void Reset() override { checkTimer = 3000; } - - void EnterEvadeMode() override - { - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type == EFFECT_MOTION_TYPE && id == 1) - checkTimer = 1; - } - - void UpdateAI(uint32 diff) override - { - if (checkTimer) - { - if (checkTimer == 1) - me->GetMotionMaster()->MovementExpired(false); - checkTimer += diff; - if (checkTimer >= 3000) - { - if (Unit* owner = me->GetCharmerOrOwner()) - { - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); - } - me->AddAura(71854, me); // Growth - checkTimer = 0; - } - } - } - }; - - CreatureAI* GetAI(Creature* pCreature) const override - { - return new npc_pet_gen_toxic_wastelingAI (pCreature); - } -}; - -class npc_pet_gen_fetch_ball : public CreatureScript -{ -public: - npc_pet_gen_fetch_ball() : CreatureScript("npc_pet_gen_fetch_ball") { } - - struct npc_pet_gen_fetch_ballAI : public NullCreatureAI - { - npc_pet_gen_fetch_ballAI(Creature* c) : NullCreatureAI(c) - { - } - - uint32 checkTimer; - ObjectGuid targetGUID; - - void IsSummonedBy(Unit* summoner) override - { - if (!summoner) - return; - - me->SetOwnerGUID(summoner->GetGUID()); - checkTimer = 0; - targetGUID.Clear(); - me->CastSpell(me, 48649 /*SPELL_PET_TOY_FETCH_BALL_COME_HERE*/, true); - } - - void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) override - { - if (spellInfo->Id == 48649 /*SPELL_PET_TOY_FETCH_BALL_COME_HERE*/) - { - target->GetMotionMaster()->MovePoint(50, me->GetHomePosition()); - targetGUID = target->GetGUID(); - } - } - - void UpdateAI(uint32 diff) override - { - checkTimer += diff; - if (checkTimer >= 1000) - { + me->AddAura(71854, me); // Growth checkTimer = 0; - if (Creature* target = ObjectAccessor::GetCreature(*me, targetGUID)) - if (me->GetDistance2d(target) < 2.0f) - { - target->AI()->EnterEvadeMode(); - target->CastSpell(target, 48708 /*SPELL_PET_TOY_FETCH_BALL_HAS_BALL*/, true); - me->DespawnOrUnsummon(1); - } } } - }; - - CreatureAI* GetAI(Creature* pCreature) const override - { - return new npc_pet_gen_fetch_ballAI (pCreature); } }; -class npc_pet_gen_moth : public CreatureScript +struct npc_pet_gen_fetch_ball : public NullCreatureAI { -public: - npc_pet_gen_moth() : CreatureScript("npc_pet_gen_moth") { } - - struct npc_pet_gen_mothAI : public NullCreatureAI + npc_pet_gen_fetch_ball(Creature* c) : NullCreatureAI(c) { - npc_pet_gen_mothAI(Creature* c) : NullCreatureAI(c) + } + + uint32 checkTimer; + ObjectGuid targetGUID; + + void IsSummonedBy(Unit* summoner) override + { + if (!summoner) + return; + + me->SetOwnerGUID(summoner->GetGUID()); + checkTimer = 0; + targetGUID.Clear(); + me->CastSpell(me, 48649 /*SPELL_PET_TOY_FETCH_BALL_COME_HERE*/, true); + } + + void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) override + { + if (spellInfo->Id == 48649 /*SPELL_PET_TOY_FETCH_BALL_COME_HERE*/) { - me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); - me->SetCanFly(true); - me->SetDisableGravity(true); + target->GetMotionMaster()->MovePoint(50, me->GetHomePosition()); + targetGUID = target->GetGUID(); } - }; + } - CreatureAI* GetAI(Creature* pCreature) const override + void UpdateAI(uint32 diff) override { - return new npc_pet_gen_mothAI (pCreature); + checkTimer += diff; + if (checkTimer >= 1000) + { + checkTimer = 0; + if (Creature* target = ObjectAccessor::GetCreature(*me, targetGUID)) + if (me->GetDistance2d(target) < 2.0f) + { + target->AI()->EnterEvadeMode(); + target->CastSpell(target, 48708 /*SPELL_PET_TOY_FETCH_BALL_HAS_BALL*/, true); + me->DespawnOrUnsummon(1); + } + } + } +}; + +struct npc_pet_gen_moth : public NullCreatureAI +{ + npc_pet_gen_moth(Creature* c) : NullCreatureAI(c) + { + me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); + me->SetCanFly(true); + me->SetDisableGravity(true); } }; void AddSC_generic_pet_scripts() { - new npc_pet_gen_mojo(); - new npc_pet_gen_soul_trader_beacon(); - new npc_pet_gen_argent_pony_bridle(); - new npc_pet_gen_target_following_bomb(); - new npc_pet_gen_gnomish_flame_turret(); - new npc_pet_gen_valkyr_guardian(); - new spell_pet_gen_valkyr_guardian_smite(); - new npc_pet_gen_imp_in_a_bottle(); - new npc_pet_gen_wind_rider_cub(); - new npc_pet_gen_plump_turkey(); - new npc_pet_gen_toxic_wasteling(); - new npc_pet_gen_fetch_ball(); - new npc_pet_gen_moth(); + RegisterCreatureAI(npc_pet_gen_mojo); + RegisterCreatureAI(npc_pet_gen_soul_trader_beacon); + RegisterCreatureAI(npc_pet_gen_argent_pony_bridle); + RegisterCreatureAI(npc_pet_gen_target_following_bomb); + RegisterCreatureAI(npc_pet_gen_gnomish_flame_turret); + RegisterCreatureAI(npc_pet_gen_valkyr_guardian); + RegisterSpellScript(spell_pet_gen_valkyr_guardian_smite); + RegisterCreatureAI(npc_pet_gen_imp_in_a_bottle); + RegisterCreatureAI(npc_pet_gen_wind_rider_cub); + RegisterCreatureAI(npc_pet_gen_plump_turkey); + RegisterCreatureAI(npc_pet_gen_toxic_wasteling); + RegisterCreatureAI(npc_pet_gen_fetch_ball); + RegisterCreatureAI(npc_pet_gen_moth); } diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index d1856f741..7fdb75094 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -32,124 +32,113 @@ enum HunterSpells SPELL_HUNTER_PET_SCALING = 62915 }; -class npc_pet_hunter_snake_trap : public CreatureScript +struct npc_pet_hunter_snake_trap : public ScriptedAI { -public: - npc_pet_hunter_snake_trap() : CreatureScript("npc_pet_hunter_snake_trap") { } + npc_pet_hunter_snake_trap(Creature* creature) : ScriptedAI(creature) { _init = false; } - struct npc_pet_hunter_snake_trapAI : public ScriptedAI + void Reset() override { - npc_pet_hunter_snake_trapAI(Creature* creature) : ScriptedAI(creature) { _init = false; } + _spellTimer = urand(1500, 3000); - void Reset() override - { - _spellTimer = urand(1500, 3000); - - // Start attacking attacker of owner on first ai update after spawn - move in line of sight may choose better target - if (!me->GetVictim()) - if (Unit* tgt = me->SelectNearestTarget(10.0f)) - { - me->AddThreat(tgt, 100000.0f); - AttackStart(tgt); - } - } - - void EnterEvadeMode() override - { - // _EnterEvadeMode(); - me->DeleteThreatList(); - me->CombatStop(true); - me->LoadCreaturesAddon(true); - me->SetLootRecipient(nullptr); - me->ResetPlayerDamageReq(); - me->SetLastDamagedTime(0); - - me->AddUnitState(UNIT_STATE_EVADE); - me->GetMotionMaster()->MoveTargetedHome(); - - Reset(); - } - - //Redefined for random target selection: - void MoveInLineOfSight(Unit* who) override - { - if (!me->GetVictim() && who->isTargetableForAttack() && (me->IsHostileTo(who)) && who->isInAccessiblePlaceFor(me)) + // Start attacking attacker of owner on first ai update after spawn - move in line of sight may choose better target + if (!me->GetVictim()) + if (Unit* tgt = me->SelectNearestTarget(10.0f)) { - if (me->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) - return; - - if (me->IsWithinDistInMap(who, 10.0f)) - { - me->AddThreat(who, 100000.0f); - AttackStart(who); - } + me->AddThreat(tgt, 100000.0f); + AttackStart(tgt); } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (me->GetVictim()->HasBreakableByDamageCrowdControlAura(me)) - { - me->InterruptNonMeleeSpells(false); - return; - } - - if (!_init) - { - _init = true; - - CreatureTemplate const* Info = me->GetCreatureTemplate(); - CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(me->getLevel(), Info->unit_class); - uint32 health = uint32(107 * (me->getLevel() - 40) * 0.025f); - me->SetCreateHealth(health); - - for (uint8 stat = 0; stat < MAX_STATS; ++stat) - { - me->SetStat(Stats(stat), 0); - me->SetCreateStat(Stats(stat), 0); - } - - me->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health); - me->SetMaxHealth(health); - //Add delta to make them not all hit the same time - uint32 delta = urand(0, 700); - me->SetAttackTime(BASE_ATTACK, Info->BaseAttackTime + delta); - me->SetStatFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER, float(stats->AttackPower)); - me->CastSpell(me, SPELL_HUNTER_DEADLY_POISON_PASSIVE, true); - - // Glyph of Snake Trap - if (Unit* owner = me->GetOwner()) - if (owner->GetAuraEffectDummy(SPELL_HUNTER_GLYPH_OF_SNAKE_TRAP)) - me->CastSpell(me, SPELL_HUNTER_PET_SCALING, true); - } - - _spellTimer += diff; - if (_spellTimer >= 3000) - { - if (urand(0, 2) == 0) // 33% chance to cast - DoCastVictim(RAND(SPELL_HUNTER_MIND_NUMBING_POISON, SPELL_HUNTER_CRIPPLING_POISON)); - - _spellTimer = 0; - } - - DoMeleeAttackIfReady(); - } - - private: - bool _init; - uint32 _spellTimer; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pet_hunter_snake_trapAI(creature); } + + void EnterEvadeMode() override + { + // _EnterEvadeMode(); + me->DeleteThreatList(); + me->CombatStop(true); + me->LoadCreaturesAddon(true); + me->SetLootRecipient(nullptr); + me->ResetPlayerDamageReq(); + me->SetLastDamagedTime(0); + + me->AddUnitState(UNIT_STATE_EVADE); + me->GetMotionMaster()->MoveTargetedHome(); + + Reset(); + } + + //Redefined for random target selection: + void MoveInLineOfSight(Unit* who) override + { + if (!me->GetVictim() && who->isTargetableForAttack() && (me->IsHostileTo(who)) && who->isInAccessiblePlaceFor(me)) + { + if (me->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) + return; + + if (me->IsWithinDistInMap(who, 10.0f)) + { + me->AddThreat(who, 100000.0f); + AttackStart(who); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (me->GetVictim()->HasBreakableByDamageCrowdControlAura(me)) + { + me->InterruptNonMeleeSpells(false); + return; + } + + if (!_init) + { + _init = true; + + CreatureTemplate const* Info = me->GetCreatureTemplate(); + CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(me->getLevel(), Info->unit_class); + uint32 health = uint32(107 * (me->getLevel() - 40) * 0.025f); + me->SetCreateHealth(health); + + for (uint8 stat = 0; stat < MAX_STATS; ++stat) + { + me->SetStat(Stats(stat), 0); + me->SetCreateStat(Stats(stat), 0); + } + + me->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health); + me->SetMaxHealth(health); + //Add delta to make them not all hit the same time + uint32 delta = urand(0, 700); + me->SetAttackTime(BASE_ATTACK, Info->BaseAttackTime + delta); + me->SetStatFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER, float(stats->AttackPower)); + me->CastSpell(me, SPELL_HUNTER_DEADLY_POISON_PASSIVE, true); + + // Glyph of Snake Trap + if (Unit* owner = me->GetOwner()) + if (owner->GetAuraEffectDummy(SPELL_HUNTER_GLYPH_OF_SNAKE_TRAP)) + me->CastSpell(me, SPELL_HUNTER_PET_SCALING, true); + } + + _spellTimer += diff; + if (_spellTimer >= 3000) + { + if (urand(0, 2) == 0) // 33% chance to cast + DoCastVictim(RAND(SPELL_HUNTER_MIND_NUMBING_POISON, SPELL_HUNTER_CRIPPLING_POISON)); + + _spellTimer = 0; + } + + DoMeleeAttackIfReady(); + } + +private: + bool _init; + uint32 _spellTimer; }; void AddSC_hunter_pet_scripts() { - new npc_pet_hunter_snake_trap(); + RegisterCreatureAI(npc_pet_hunter_snake_trap); } diff --git a/src/server/scripts/Pet/pet_mage.cpp b/src/server/scripts/Pet/pet_mage.cpp index 688a651f2..89ed6a699 100644 --- a/src/server/scripts/Pet/pet_mage.cpp +++ b/src/server/scripts/Pet/pet_mage.cpp @@ -53,182 +53,171 @@ private: Creature& _owner; }; -class npc_pet_mage_mirror_image : public CreatureScript +struct npc_pet_mage_mirror_image : CasterAI { -public: - npc_pet_mage_mirror_image() : CreatureScript("npc_pet_mage_mirror_image") { } + npc_pet_mage_mirror_image(Creature* creature) : CasterAI(creature) { } - struct npc_pet_mage_mirror_imageAI : CasterAI + uint32 selectionTimer; + ObjectGuid _ebonGargoyleGUID; + uint32 checktarget; + uint32 dist = urand(1, 5); + + void InitializeAI() override { - npc_pet_mage_mirror_imageAI(Creature* creature) : CasterAI(creature) { } + CasterAI::InitializeAI(); + Unit* owner = me->GetOwner(); + if (!owner) + return; - uint32 selectionTimer; - ObjectGuid _ebonGargoyleGUID; - uint32 checktarget; - uint32 dist = urand(1, 5); + // Clone Me! + owner->CastSpell(me, SPELL_MAGE_CLONE_ME, true); - void InitializeAI() override + // xinef: Glyph of Mirror Image (4th copy) + float angle = 0.0f; + switch (me->GetUInt32Value(UNIT_CREATED_BY_SPELL)) { - CasterAI::InitializeAI(); - Unit* owner = me->GetOwner(); - if (!owner) - return; + case SPELL_SUMMON_MIRROR_IMAGE1: + angle = 0.5f * M_PI; + break; + case SPELL_SUMMON_MIRROR_IMAGE2: + angle = M_PI; + break; + case SPELL_SUMMON_MIRROR_IMAGE3: + angle = 1.5f * M_PI; + break; + } - // Clone Me! - owner->CastSpell(me, SPELL_MAGE_CLONE_ME, true); + ((Minion*)me)->SetFollowAngle(angle); + if (owner->IsInCombat()) + me->NearTeleportTo(me->GetPositionX() + cos(angle)*dist, me->GetPositionY() + sin(angle)*dist, me->GetPositionZ(), me->GetOrientation(), false, false, false, false); + else + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); - // xinef: Glyph of Mirror Image (4th copy) - float angle = 0.0f; - switch (me->GetUInt32Value(UNIT_CREATED_BY_SPELL)) + me->SetReactState(REACT_DEFENSIVE); + + // Xinef: Inherit Master's Threat List (not yet implemented) + //owner->CastSpell((Unit*)nullptr, SPELL_MAGE_MASTERS_THREAT_LIST, true); + HostileReference* ref = owner->getHostileRefMgr().getFirst(); + while (ref) + { + if (Unit* unit = ref->GetSource()->GetOwner()) + unit->AddThreat(me, ref->getThreat() - ref->getTempThreatModifier()); + ref = ref->next(); + } + + _ebonGargoyleGUID.Clear(); + + // Xinef: copy caster auras + Unit::VisibleAuraMap const* visibleAuraMap = owner->GetVisibleAuras(); + for (Unit::VisibleAuraMap::const_iterator itr = visibleAuraMap->begin(); itr != visibleAuraMap->end(); ++itr) + if (Aura* visAura = itr->second->GetBase()) { - case SPELL_SUMMON_MIRROR_IMAGE1: - angle = 0.5f * M_PI; - break; - case SPELL_SUMMON_MIRROR_IMAGE2: - angle = M_PI; - break; - case SPELL_SUMMON_MIRROR_IMAGE3: - angle = 1.5f * M_PI; - break; + // Ebon Gargoyle + if (visAura->GetId() == 49206 && me->GetUInt32Value(UNIT_CREATED_BY_SPELL) == SPELL_SUMMON_MIRROR_IMAGE1) + { + if (Unit* gargoyle = visAura->GetCaster()) + _ebonGargoyleGUID = gargoyle->GetGUID(); + continue; + } + SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(visAura->GetId()); + if (bounds.first != bounds.second) + continue; + std::vector const* spellTriggered = sSpellMgr->GetSpellLinked(visAura->GetId() + SPELL_LINK_AURA); + if (!spellTriggered || !spellTriggered->empty()) + continue; + if (Aura* newAura = me->AddAura(visAura->GetId(), me)) + newAura->SetDuration(visAura->GetDuration()); } - ((Minion*)me)->SetFollowAngle(angle); - if (owner->IsInCombat()) - me->NearTeleportTo(me->GetPositionX() + cos(angle)*dist, me->GetPositionY() + sin(angle)*dist, me->GetPositionZ(), me->GetOrientation(), false, false, false, false); - else - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); + me->m_Events.AddEvent(new DeathEvent(*me), me->m_Events.CalculateTime(29500)); + } - me->SetReactState(REACT_DEFENSIVE); + // Do not reload Creature templates on evade mode enter - prevent visual lost + void EnterEvadeMode() override + { + if (me->IsInEvadeMode() || !me->IsAlive()) + return; - // Xinef: Inherit Master's Threat List (not yet implemented) - //owner->CastSpell((Unit*)nullptr, SPELL_MAGE_MASTERS_THREAT_LIST, true); - HostileReference* ref = owner->getHostileRefMgr().getFirst(); - while (ref) - { - if (Unit* unit = ref->GetSource()->GetOwner()) - unit->AddThreat(me, ref->getThreat() - ref->getTempThreatModifier()); - ref = ref->next(); - } + Unit* owner = me->GetCharmerOrOwner(); + me->CombatStop(true); + if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) + { + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); + } + } + + void MySelectNextTarget() + { + if (_ebonGargoyleGUID) + { + Unit* gargoyle = ObjectAccessor::GetUnit(*me, _ebonGargoyleGUID); + if (gargoyle && gargoyle->GetAI()) + gargoyle->GetAI()->AttackStart(me); _ebonGargoyleGUID.Clear(); - - // Xinef: copy caster auras - Unit::VisibleAuraMap const* visibleAuraMap = owner->GetVisibleAuras(); - for (Unit::VisibleAuraMap::const_iterator itr = visibleAuraMap->begin(); itr != visibleAuraMap->end(); ++itr) - if (Aura* visAura = itr->second->GetBase()) - { - // Ebon Gargoyle - if (visAura->GetId() == 49206 && me->GetUInt32Value(UNIT_CREATED_BY_SPELL) == SPELL_SUMMON_MIRROR_IMAGE1) - { - if (Unit* gargoyle = visAura->GetCaster()) - _ebonGargoyleGUID = gargoyle->GetGUID(); - continue; - } - SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(visAura->GetId()); - if (bounds.first != bounds.second) - continue; - std::vector const* spellTriggered = sSpellMgr->GetSpellLinked(visAura->GetId() + SPELL_LINK_AURA); - if (!spellTriggered || !spellTriggered->empty()) - continue; - if (Aura* newAura = me->AddAura(visAura->GetId(), me)) - newAura->SetDuration(visAura->GetDuration()); - } - - me->m_Events.AddEvent(new DeathEvent(*me), me->m_Events.CalculateTime(29500)); } - - // Do not reload Creature templates on evade mode enter - prevent visual lost - void EnterEvadeMode() override + Unit* owner = me->GetOwner(); + if (owner && owner->GetTypeId() == TYPEID_PLAYER) { - if (me->IsInEvadeMode() || !me->IsAlive()) - return; + Unit* selection = owner->ToPlayer()->GetSelectedUnit(); - Unit* owner = me->GetCharmerOrOwner(); - - me->CombatStop(true); - if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) + if (selection) { - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); + me->getThreatMgr().resetAllAggro(); + me->AddThreat(selection, 1000000.0f); + + if (owner->IsInCombat()) + AttackStart(selection); } + + if (!owner->IsInCombat() && !me->GetVictim()) + EnterEvadeMode(); + } + } + + void Reset() override + { + selectionTimer = 0; + checktarget = 0; + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + if (events.GetTimer() < 1200) + return; + + if (!me->IsInCombat() || !me->GetVictim()) + { + MySelectNextTarget(); + return; } - void MySelectNextTarget() + checktarget += diff; + + if (checktarget >= 1000) { - if (_ebonGargoyleGUID) - { - Unit* gargoyle = ObjectAccessor::GetUnit(*me, _ebonGargoyleGUID); - if (gargoyle && gargoyle->GetAI()) - gargoyle->GetAI()->AttackStart(me); - _ebonGargoyleGUID.Clear(); - } - Unit* owner = me->GetOwner(); - if (owner && owner->GetTypeId() == TYPEID_PLAYER) - { - Unit* selection = owner->ToPlayer()->GetSelectedUnit(); - - if (selection) - { - me->getThreatMgr().resetAllAggro(); - me->AddThreat(selection, 1000000.0f); - - if (owner->IsInCombat()) - AttackStart(selection); - } - - if (!owner->IsInCombat() && !me->GetVictim()) - EnterEvadeMode(); - } - } - - void Reset() override - { - selectionTimer = 0; - checktarget = 0; - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - if (events.GetTimer() < 1200) - return; - - if (!me->IsInCombat() || !me->GetVictim()) + if (me->GetVictim()->HasBreakableByDamageCrowdControlAura() || !me->GetVictim()->IsAlive()) { MySelectNextTarget(); + me->InterruptNonMeleeSpells(true); // Stop casting if target is CC or not Alive. return; } - - checktarget += diff; - - if (checktarget >= 1000) - { - if (me->GetVictim()->HasBreakableByDamageCrowdControlAura() || !me->GetVictim()->IsAlive()) - { - MySelectNextTarget(); - me->InterruptNonMeleeSpells(true); // Stop casting if target is CC or not Alive. - return; - } - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (uint32 spellId = events.ExecuteEvent()) - { - events.RescheduleEvent(spellId, spellId == 59637 ? 6500 : 2500); - me->CastSpell(me->GetVictim(), spellId, false); - } } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pet_mage_mirror_imageAI(creature); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (uint32 spellId = events.ExecuteEvent()) + { + events.RescheduleEvent(spellId, spellId == 59637 ? 6500 : 2500); + me->CastSpell(me->GetVictim(), spellId, false); + } } }; void AddSC_mage_pet_scripts() { - new npc_pet_mage_mirror_image(); + RegisterCreatureAI(npc_pet_mage_mirror_image); } diff --git a/src/server/scripts/Pet/pet_priest.cpp b/src/server/scripts/Pet/pet_priest.cpp index 2e6251bd4..d72b94620 100644 --- a/src/server/scripts/Pet/pet_priest.cpp +++ b/src/server/scripts/Pet/pet_priest.cpp @@ -34,72 +34,50 @@ enum PriestSpells SPELL_PRIEST_LIGHTWELL_CHARGES = 59907 }; -class npc_pet_pri_lightwell : public CreatureScript +struct npc_pet_pri_lightwell : public TotemAI { -public: - npc_pet_pri_lightwell() : CreatureScript("npc_pet_pri_lightwell") { } + npc_pet_pri_lightwell(Creature* creature) : TotemAI(creature) { } - struct npc_pet_pri_lightwellAI : public TotemAI + void InitializeAI() override { - npc_pet_pri_lightwellAI(Creature* creature) : TotemAI(creature) { } - - void InitializeAI() override + if (Unit* owner = me->ToTempSummon()->GetSummonerUnit()) { - if (Unit* owner = me->ToTempSummon()->GetSummonerUnit()) - { - uint32 hp = uint32(owner->GetMaxHealth() * 0.3f); - me->SetMaxHealth(hp); - me->SetHealth(hp); - me->SetLevel(owner->getLevel()); - } - - me->CastSpell(me, SPELL_PRIEST_LIGHTWELL_CHARGES, false); // Spell for Lightwell Charges - TotemAI::InitializeAI(); + uint32 hp = uint32(owner->GetMaxHealth() * 0.3f); + me->SetMaxHealth(hp); + me->SetHealth(hp); + me->SetLevel(owner->getLevel()); } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pet_pri_lightwellAI(creature); + me->CastSpell(me, SPELL_PRIEST_LIGHTWELL_CHARGES, false); // Spell for Lightwell Charges + TotemAI::InitializeAI(); } }; -class npc_pet_pri_shadowfiend : public CreatureScript +struct npc_pet_pri_shadowfiend : public PetAI { -public: - npc_pet_pri_shadowfiend() : CreatureScript("npc_pet_pri_shadowfiend") { } + npc_pet_pri_shadowfiend(Creature* creature) : PetAI(creature) { } - struct npc_pet_pri_shadowfiendAI : public PetAI + void Reset() override { - npc_pet_pri_shadowfiendAI(Creature* creature) : PetAI(creature) { } + PetAI::Reset(); + if (!me->HasAura(SPELL_PRIEST_SHADOWFIEND_DODGE)) + me->AddAura(SPELL_PRIEST_SHADOWFIEND_DODGE, me); - void Reset() override - { - PetAI::Reset(); - if (!me->HasAura(SPELL_PRIEST_SHADOWFIEND_DODGE)) - me->AddAura(SPELL_PRIEST_SHADOWFIEND_DODGE, me); + if (Unit* target = me->SelectNearestTarget(15.0f)) + AttackStart(target); + } - if (Unit* target = me->SelectNearestTarget(15.0f)) - AttackStart(target); - } - - void JustDied(Unit* /*killer*/) override - { - if (me->IsSummon()) - if (Unit* owner = me->ToTempSummon()->GetSummonerUnit()) - if (owner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND)) - owner->CastSpell(owner, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void JustDied(Unit* /*killer*/) override { - return new npc_pet_pri_shadowfiendAI(creature); + if (me->IsSummon()) + if (Unit* owner = me->ToTempSummon()->GetSummonerUnit()) + if (owner->HasAura(SPELL_PRIEST_GLYPH_OF_SHADOWFIEND)) + owner->CastSpell(owner, SPELL_PRIEST_GLYPH_OF_SHADOWFIEND_MANA, true); } }; void AddSC_priest_pet_scripts() { - new npc_pet_pri_lightwell(); - new npc_pet_pri_shadowfiend(); + RegisterCreatureAI(npc_pet_pri_lightwell); + RegisterCreatureAI(npc_pet_pri_shadowfiend); } diff --git a/src/server/scripts/Pet/pet_shaman.cpp b/src/server/scripts/Pet/pet_shaman.cpp index 9d6f6af7b..ef5973235 100644 --- a/src/server/scripts/Pet/pet_shaman.cpp +++ b/src/server/scripts/Pet/pet_shaman.cpp @@ -42,131 +42,109 @@ enum ShamanEvents EVENT_SHAMAN_FIREBLAST = 3 }; -class npc_pet_shaman_earth_elemental : public CreatureScript +struct npc_pet_shaman_earth_elemental : public ScriptedAI { -public: - npc_pet_shaman_earth_elemental() : CreatureScript("npc_pet_shaman_earth_elemental") { } + npc_pet_shaman_earth_elemental(Creature* creature) : ScriptedAI(creature), _initAttack(true) { } - struct npc_pet_shaman_earth_elementalAI : public ScriptedAI + void EnterCombat(Unit*) override { - npc_pet_shaman_earth_elementalAI(Creature* creature) : ScriptedAI(creature), _initAttack(true) { } - - void EnterCombat(Unit*) override - { - _events.Reset(); - _events.ScheduleEvent(EVENT_SHAMAN_ANGEREDEARTH, 0); - } - - void InitializeAI() override { } - - void UpdateAI(uint32 diff) override - { - if (_initAttack) - { - if (!me->IsInCombat()) - if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) - if (Unit* target = owner->GetSelectedUnit()) - if (me->_CanDetectFeignDeathOf(target) && me->CanCreatureAttack(target)) - AttackStart(target); - _initAttack = false; - } - - if (!UpdateVictim()) - return; - - _events.Update(diff); - - if (_events.ExecuteEvent() == EVENT_SHAMAN_ANGEREDEARTH) - { - DoCastVictim(SPELL_SHAMAN_ANGEREDEARTH); - _events.ScheduleEvent(EVENT_SHAMAN_ANGEREDEARTH, urand(5000, 20000)); - } - - DoMeleeAttackIfReady(); - } - - private: - EventMap _events; - bool _initAttack; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pet_shaman_earth_elementalAI(creature); + _events.Reset(); + _events.ScheduleEvent(EVENT_SHAMAN_ANGEREDEARTH, 0); } + + void InitializeAI() override { } + + void UpdateAI(uint32 diff) override + { + if (_initAttack) + { + if (!me->IsInCombat()) + if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) + if (Unit* target = owner->GetSelectedUnit()) + if (me->_CanDetectFeignDeathOf(target) && me->CanCreatureAttack(target)) + AttackStart(target); + _initAttack = false; + } + + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (_events.ExecuteEvent() == EVENT_SHAMAN_ANGEREDEARTH) + { + DoCastVictim(SPELL_SHAMAN_ANGEREDEARTH); + _events.ScheduleEvent(EVENT_SHAMAN_ANGEREDEARTH, urand(5000, 20000)); + } + + DoMeleeAttackIfReady(); + } + +private: + EventMap _events; + bool _initAttack; }; -class npc_pet_shaman_fire_elemental : public CreatureScript +struct npc_pet_shaman_fire_elemental : public ScriptedAI { -public: - npc_pet_shaman_fire_elemental() : CreatureScript("npc_pet_shaman_fire_elemental") { } + npc_pet_shaman_fire_elemental(Creature* creature) : ScriptedAI(creature), _initAttack(true) { } - struct npc_pet_shaman_fire_elementalAI : public ScriptedAI + void InitializeAI() override { } + + void EnterCombat(Unit*) override { - npc_pet_shaman_fire_elementalAI(Creature* creature) : ScriptedAI(creature), _initAttack(true) { } + _events.Reset(); + _events.ScheduleEvent(EVENT_SHAMAN_FIRENOVA, urand(5000, 20000)); + _events.ScheduleEvent(EVENT_SHAMAN_FIREBLAST, urand(5000, 20000)); + //_events.ScheduleEvent(EVENT_SHAMAN_FIRESHIELD, 0); - void InitializeAI() override { } - - void EnterCombat(Unit*) override - { - _events.Reset(); - _events.ScheduleEvent(EVENT_SHAMAN_FIRENOVA, urand(5000, 20000)); - _events.ScheduleEvent(EVENT_SHAMAN_FIREBLAST, urand(5000, 20000)); - //_events.ScheduleEvent(EVENT_SHAMAN_FIRESHIELD, 0); - - me->RemoveAurasDueToSpell(SPELL_SHAMAN_FIRESHIELD); - me->CastSpell(me, SPELL_SHAMAN_FIRESHIELD, true); - } - - void UpdateAI(uint32 diff) override - { - if (_initAttack) - { - if (!me->IsInCombat()) - if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) - if (Unit* target = owner->GetSelectedUnit()) - if (me->_CanDetectFeignDeathOf(target) && me->CanCreatureAttack(target)) - AttackStart(target); - _initAttack = false; - } - - if (!UpdateVictim()) - return; - - _events.Update(diff); - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHAMAN_FIRENOVA: - me->CastSpell(me, SPELL_SHAMAN_FIRENOVA, false); - _events.ScheduleEvent(EVENT_SHAMAN_FIRENOVA, urand(8000, 15000)); - break; - case EVENT_SHAMAN_FIREBLAST: - me->CastSpell(me->GetVictim(), SPELL_SHAMAN_FIREBLAST, false); - _events.ScheduleEvent(EVENT_SHAMAN_FIREBLAST, urand(4000, 8000)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - private: - EventMap _events; - bool _initAttack; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_pet_shaman_fire_elementalAI(creature); + me->RemoveAurasDueToSpell(SPELL_SHAMAN_FIRESHIELD); + me->CastSpell(me, SPELL_SHAMAN_FIRESHIELD, true); } + + void UpdateAI(uint32 diff) override + { + if (_initAttack) + { + if (!me->IsInCombat()) + if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) + if (Unit* target = owner->GetSelectedUnit()) + if (me->_CanDetectFeignDeathOf(target) && me->CanCreatureAttack(target)) + AttackStart(target); + _initAttack = false; + } + + if (!UpdateVictim()) + return; + + _events.Update(diff); + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHAMAN_FIRENOVA: + me->CastSpell(me, SPELL_SHAMAN_FIRENOVA, false); + _events.ScheduleEvent(EVENT_SHAMAN_FIRENOVA, urand(8000, 15000)); + break; + case EVENT_SHAMAN_FIREBLAST: + me->CastSpell(me->GetVictim(), SPELL_SHAMAN_FIREBLAST, false); + _events.ScheduleEvent(EVENT_SHAMAN_FIREBLAST, urand(4000, 8000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + +private: + EventMap _events; + bool _initAttack; }; void AddSC_shaman_pet_scripts() { - new npc_pet_shaman_earth_elemental(); - new npc_pet_shaman_fire_elemental(); + RegisterCreatureAI(npc_pet_shaman_earth_elemental); + RegisterCreatureAI(npc_pet_shaman_fire_elemental); }