diff --git a/data/sql/updates/pending_db_world/rev_1642750721076432402.sql b/data/sql/updates/pending_db_world/rev_1642750721076432402.sql new file mode 100644 index 000000000..c27889dcc --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1642750721076432402.sql @@ -0,0 +1,52 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1642750721076432402'); + +-- set "execute event while charmed" flag on all events except: +-- -) movement actions +-- -) nontriggered cast actions +-- -) talk/emote/sound actions +-- -) ally summon actions +UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND + (`action_type` not in (1,4,5,10,11,12,17,25,27,38,39,40,49,62,69,84,85,86,89,92,97,103,107,114) OR + (`action_type` in (11,86) AND (`action_param2`&2)=2)); + + +-- assorted quest fixes (no claim to completeness) +-- Seeds of Chaos (13172) +UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=31157; +UPDATE `smart_scripts` SET `event_type`=29, `comment`="Skeletal Assault Gryphon - On Charmed - Start Waypoint" WHERE `source_type`=0 AND `entryorguid`=31157 AND `id`=0; +-- Generosity Abounds (13146) +UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=30894; +-- Battling the Elements (12967) +UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=30124; +-- Krolmir, Hammer of Storms (13010) +UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=30331; +UPDATE `smart_scripts` SET `event_type`=29 WHERE `source_type`=0 AND `entryorguid`=30331 AND `id`=0; +UPDATE `smart_scripts` SET `target_type`=23 WHERE `source_type`=0 AND `entryorguid`=30331 AND `id`=1; +UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=9 AND `entryorguid`=3033100; +-- Spy Hunter (12994) +UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=30219; +UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=9 AND `entryorguid` IN (3021900,3021901,3021902); + +-- Always for SMART_EVENT_JUST_SUMMONED (Creature can be summoned already charmed by player ie TempSummons) +UPDATE `smart_scripts` SET `event_flags`=`event_flags`|0x200 WHERE `source_type` = 0 AND `event_type`=54; + +-- Event linked actions (Many levels of linked calls, do 8 times) +UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND + `ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0; +UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND + `ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0; +UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND + `ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0; +UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND + `ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0; +UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND + `ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0; +UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND + `ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0; +UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND + `ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0; +UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND + `ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0; + +-- Vehicles +UPDATE `smart_scripts` SET `event_flags`=`event_flags`|0x200 WHERE `source_type` = 0 AND `entryorguid` IN (SELECT `entry` FROM `creature_template` WHERE `AIName` = "SmartAI" AND `VehicleId` != 0); diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index ba51f7f08..614c4e610 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -70,7 +70,7 @@ void npc_escortAI::AttackStart(Unit* who) } //see followerAI -bool npc_escortAI::AssistPlayerInCombat(Unit* who) +bool npc_escortAI::AssistPlayerInCombatAgainst(Unit* who) { if (!who || !who->GetVictim()) { @@ -138,7 +138,7 @@ void npc_escortAI::MoveInLineOfSight(Unit* who) return; if (!me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack(true, me) && who->isInAccessiblePlaceFor(me)) - if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombat(who)) + if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombatAgainst(who)) return; if (me->CanStartAttack(who)) diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h index 956250151..1332837ff 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h @@ -114,7 +114,7 @@ protected: Player* GetPlayerForEscort() { return ObjectAccessor::GetPlayer(*me, m_uiPlayerGUID); } private: - bool AssistPlayerInCombat(Unit* who); + bool AssistPlayerInCombatAgainst(Unit* who); bool IsPlayerOrGroupInRange(); void FillPointMovementListForCreature(); diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index 9617d4afa..bf7c6d905 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -63,7 +63,7 @@ void FollowerAI::AttackStart(Unit* who) //This part provides assistance to a player that are attacked by who, even if out of normal aggro range //It will cause me to attack who that are attacking _any_ player (which has been confirmed may happen also on offi) //The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate. -bool FollowerAI::AssistPlayerInCombat(Unit* who) +bool FollowerAI::AssistPlayerInCombatAgainst(Unit* who) { if (!who || !who->GetVictim()) return false; @@ -96,7 +96,7 @@ void FollowerAI::MoveInLineOfSight(Unit* who) return; if (!me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack(true, me) && who->isInAccessiblePlaceFor(me)) - if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(who)) + if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombatAgainst(who)) return; if (me->CanStartAttack(who)) diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h index 1de968e43..d3eef03ad 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h @@ -69,7 +69,7 @@ private: void AddFollowState(uint32 uiFollowState) { m_uiFollowState |= uiFollowState; } void RemoveFollowState(uint32 uiFollowState) { m_uiFollowState &= ~uiFollowState; } - bool AssistPlayerInCombat(Unit* who); + bool AssistPlayerInCombatAgainst(Unit* who); ObjectGuid m_uiLeaderGUID; uint32 m_uiUpdateFollowTimer; diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 060e27f82..81362efba 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -30,6 +30,7 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c) { + mIsCharmed = false; // copy script to local (protection for table reload) mWayPoints = nullptr; @@ -76,6 +77,11 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c) conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry()); } +bool SmartAI::IsAIControlled() const +{ + return !mIsCharmed; +} + void SmartAI::UpdateDespawn(const uint32 diff) { if (mDespawnState <= 1 || mDespawnState > 3) @@ -347,7 +353,10 @@ void SmartAI::EndPath(bool fail) mCurrentWPID = 0; if (mCanRepeatPath) - StartPath(mRun, GetScript()->GetPathId(), mCanRepeatPath); + { + if (IsAIControlled()) + StartPath(mRun, GetScript()->GetPathId(), true); + } else GetScript()->SetPathId(0); @@ -370,6 +379,9 @@ void SmartAI::ResumePath() void SmartAI::ReturnToLastOOCPos() { + if (!IsAIControlled()) + return; + me->SetWalk(false); float x, y, z, o; me->GetHomePosition(x, y, z, o); @@ -511,6 +523,9 @@ void SmartAI::UpdateAI(uint32 diff) mFollowArrivedTimer -= diff; } + if (!IsAIControlled()) + return; + if (!UpdateVictim()) return; @@ -620,10 +635,6 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data) void SmartAI::EnterEvadeMode(EvadeReason /*why*/) { - // xinef: fixes strange jumps when charming SmartAI npc - if (!me->IsAlive() || me->IsInEvadeMode()) - return; - if (mEvadeDisabled) { GetScript()->ProcessEventsFor(SMART_EVENT_EVADE); @@ -636,12 +647,12 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/) return; } - me->RemoveEvadeAuras(); + if (!_EnterEvadeMode()) + return; me->AddUnitState(UNIT_STATE_EVADE); - _EnterEvadeMode(); - GetScript()->ProcessEventsFor(SMART_EVENT_EVADE);//must be after aura clear so we can cast spells from db + GetScript()->ProcessEventsFor(SMART_EVENT_EVADE); //must be after aura clear so we can cast spells from db SetRun(mRun); if (HasEscortState(SMART_ESCORT_ESCORTING)) @@ -675,10 +686,13 @@ void SmartAI::MoveInLineOfSight(Unit* who) GetScript()->OnMoveInLineOfSight(who); + if (!IsAIControlled()) + return; + if (me->GetVictim()) return; - if (me->HasReactState(REACT_PASSIVE) || AssistPlayerInCombat(who)) + if (me->HasReactState(REACT_PASSIVE) || AssistPlayerInCombatAgainst(who)) return; if (me->CanStartAttack(who)) @@ -694,13 +708,14 @@ void SmartAI::MoveInLineOfSight(Unit* who) bool SmartAI::CanAIAttack(Unit const* /*who*/) const { - if (me->GetReactState() == REACT_PASSIVE) - return false; - return true; + return !(me->GetReactState() == REACT_PASSIVE); } -bool SmartAI::AssistPlayerInCombat(Unit* who) +bool SmartAI::AssistPlayerInCombatAgainst(Unit* who) { + if (!IsAIControlled()) + return false; + // Xinef: if unit has no victim, or victim is player controlled thing if (!who->GetVictim() || who->GetCharmerOrOwnerOrOwnGUID().IsPlayer()) return false; @@ -773,7 +788,8 @@ void SmartAI::JustReachedHome() void SmartAI::EnterCombat(Unit* enemy) { // Xinef: Interrupt channeled spells - me->InterruptSpell(CURRENT_CHANNELED_SPELL, true, true); + if (IsAIControlled()) + me->InterruptSpell(CURRENT_CHANNELED_SPELL, true, true); GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy); } @@ -841,6 +857,9 @@ void SmartAI::DamageTaken(Unit* doneBy, uint32& damage, DamageEffectType damaget if (doneBy) GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage); + if (!IsAIControlled()) // don't allow players to use unkillable units + return; + // Xinef: skip nodamage type (eg. instakill effect) if (damagetype != NODAMAGE && mInvincibilityHpLevel && (damage >= me->GetHealth() - mInvincibilityHpLevel)) damage = me->GetHealth() - mInvincibilityHpLevel; // damage should not be nullified, because of player damage req. @@ -871,10 +890,6 @@ void SmartAI::SummonedCreatureDespawn(Creature* unit) GetScript()->ProcessEventsFor(SMART_EVENT_SUMMON_DESPAWNED, unit); } -void SmartAI::UpdateAIWhileCharmed(const uint32 /*diff*/) -{ -} - void SmartAI::CorpseRemoved(uint32& respawnDelay) { GetScript()->ProcessEventsFor(SMART_EVENT_CORPSE_REMOVED, nullptr, respawnDelay); @@ -900,9 +915,29 @@ void SmartAI::InitializeAI() } } -void SmartAI::OnCharmed(bool apply) +void SmartAI::OnCharmed(bool /* apply */) { - GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, apply); + bool const charmed = me->IsCharmed(); + if (charmed) // do this before we change charmed state, as charmed state might prevent these things from processing + { + if (HasEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING)) + EndPath(true); + } + + mIsCharmed = charmed; + + if (!charmed && !me->IsInEvadeMode()) + { + if (mCanRepeatPath) + StartPath(mRun, GetScript()->GetPathId(), true); + else + me->SetWalk(!mRun); + + if (Unit* charmer = me->GetCharmer()) + AttackStart(charmer); + } + + GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, charmed); } void SmartAI::DoAction(int32 param) @@ -995,6 +1030,10 @@ void SmartAI::SetCombatMove(bool on) return; mCanCombatMove = on; + + if (!IsAIControlled()) + return; + if (!HasEscortState(SMART_ESCORT_ESCORTING)) { if (on && me->GetVictim()) @@ -1024,7 +1063,6 @@ void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, ui return; } - SetRun(mRun); mFollowGuid = target->GetGUID(); mFollowDist = dist; mFollowAngle = angle; @@ -1032,9 +1070,9 @@ void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, ui mFollowCredit = credit; mFollowArrivedEntry = end; mFollowArrivedAlive = !aliveState; // negate - 0 is alive - - me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle); mFollowCreditType = creditType; + SetRun(mRun); + me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle); } void SmartAI::StopFollow(bool complete) diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 19c6ba422..7bc589ec5 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -47,6 +47,9 @@ public: ~SmartAI() override {}; explicit SmartAI(Creature* c); + // Check whether we are currently permitted to make the creature take action + bool IsAIControlled() const; + // Start moving to the desired MovePoint void StartPath(bool run = false, uint32 path = 0, bool repeat = false, Unit* invoker = nullptr); bool LoadPath(uint32 entry); @@ -133,9 +136,6 @@ public: // called when the corpse of this creature gets removed void CorpseRemoved(uint32& respawnDelay) override; - // Called at World update tick if creature is charmed - void UpdateAIWhileCharmed(const uint32 diff); - // Called when a Player/Creature enters the creature (vehicle) void PassengerBoarded(Unit* who, int8 seatId, bool apply) override; @@ -205,6 +205,7 @@ public: void SetForcedCombatMove(float dist); private: + bool mIsCharmed; uint32 mFollowCreditType; uint32 mFollowArrivedTimer; uint32 mFollowCredit; @@ -234,7 +235,7 @@ private: bool mForcedPaused; uint32 mInvincibilityHpLevel; - bool AssistPlayerInCombat(Unit* who); + bool AssistPlayerInCombatAgainst(Unit* who); uint32 mDespawnTime; uint32 mDespawnState; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index b5781e29e..412d99f95 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -121,7 +121,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u //calc random if (e.GetEventType() != SMART_EVENT_LINK && e.event.event_chance < 100 && e.event.event_chance) { - uint32 rnd = urand(0, 100); + uint32 rnd = urand(1, 100); if (e.event.event_chance <= rnd) return; } @@ -4031,6 +4031,9 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if ((e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask)) || ((e.event.event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE) && e.runOnce)) return; + if (!(e.event.event_flags & SMART_EVENT_FLAG_WHILE_CHARMED) && IsCharmedCreature(me)) + return; + switch (e.GetEventType()) { case SMART_EVENT_LINK://special handling @@ -4180,12 +4183,17 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax, me->GetVictim()); break; } + case SMART_EVENT_CHARMED: + { + if (bvar == (e.event.charm.onRemove != 1)) + ProcessAction(e, unit, var0, var1, bvar, spell, gob); + break; + } //no params case SMART_EVENT_AGGRO: case SMART_EVENT_DEATH: case SMART_EVENT_EVADE: case SMART_EVENT_REACHED_HOME: - case SMART_EVENT_CHARMED: case SMART_EVENT_CHARMED_TARGET: case SMART_EVENT_CORPSE_REMOVED: case SMART_EVENT_AI_INIT: @@ -5127,6 +5135,37 @@ Unit* SmartScript::GetLastInvoker(Unit* invoker) return nullptr; } +bool SmartScript::IsUnit(WorldObject* obj) +{ + return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER); +} + +bool SmartScript::IsPlayer(WorldObject* obj) +{ + return obj && obj->GetTypeId() == TYPEID_PLAYER; +} + +bool SmartScript::IsCreature(WorldObject* obj) +{ + return obj && obj->GetTypeId() == TYPEID_UNIT; +} + +bool SmartScript::IsCharmedCreature(WorldObject* obj) +{ + if (!obj) + return false; + + if (Creature* creatureObj = obj->ToCreature()) + return creatureObj->IsCharmed(); + + return false; +} + +bool SmartScript::IsGameObject(WorldObject* obj) +{ + return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT; +} + void SmartScript::IncPhase(uint32 p) { // protect phase from overflowing diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index ab63b9745..cd564b72b 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -61,25 +61,11 @@ public: return obj; } - bool IsUnit(WorldObject* obj) - { - return obj && obj->IsInWorld() && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER); - } - - bool IsPlayer(WorldObject* obj) - { - return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_PLAYER; - } - - bool IsCreature(WorldObject* obj) - { - return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_UNIT; - } - - bool IsGameObject(WorldObject* obj) - { - return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_GAMEOBJECT; - } + static bool IsUnit(WorldObject* obj); + static bool IsPlayer(WorldObject* obj); + static bool IsCreature(WorldObject* obj); + static bool IsCharmedCreature(WorldObject* obj); + static bool IsGameObject(WorldObject* obj); void OnUpdate(const uint32 diff); void OnMoveInLineOfSight(Unit* who); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index ba2626b7e..be9357fab 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -133,7 +133,7 @@ enum SMART_EVENT SMART_EVENT_IC_LOS = 26, // HostilityMode, MaxRnage, CooldownMin, CooldownMax, PlayerOnly SMART_EVENT_PASSENGER_BOARDED = 27, // CooldownMin, CooldownMax SMART_EVENT_PASSENGER_REMOVED = 28, // CooldownMin, CooldownMax - SMART_EVENT_CHARMED = 29, // NONE + SMART_EVENT_CHARMED = 29, // onRemove (0 - on apply, 1 - on remove) SMART_EVENT_CHARMED_TARGET = 30, // NONE SMART_EVENT_SPELLHIT_TARGET = 31, // SpellID, School, CooldownMin, CooldownMax SMART_EVENT_DAMAGED = 32, // MinDmg, MaxDmg, CooldownMin, CooldownMax @@ -312,6 +312,19 @@ struct SmartEvent uint32 repeatMax; } aura; + struct + { + uint32 onRemove; + } charm; + + struct + { + uint32 spell; + uint32 count; + uint32 repeatMin; + uint32 repeatMax; + } targetAura; + struct { uint32 type; @@ -1740,9 +1753,10 @@ enum SmartEventFlags SMART_EVENT_FLAG_RESERVED_6 = 0x040, SMART_EVENT_FLAG_DEBUG_ONLY = 0x080, //Event only occurs in debug build SMART_EVENT_FLAG_DONT_RESET = 0x100, //Event will not reset in SmartScript::OnReset() + SMART_EVENT_FLAG_WHILE_CHARMED = 0x200, //Event occurs even if AI owner is charmed SMART_EVENT_FLAG_DIFFICULTY_ALL = (SMART_EVENT_FLAG_DIFFICULTY_0 | SMART_EVENT_FLAG_DIFFICULTY_1 | SMART_EVENT_FLAG_DIFFICULTY_2 | SMART_EVENT_FLAG_DIFFICULTY_3), - SMART_EVENT_FLAGS_ALL = (SMART_EVENT_FLAG_NOT_REPEATABLE | SMART_EVENT_FLAG_DIFFICULTY_ALL | SMART_EVENT_FLAG_RESERVED_5 | SMART_EVENT_FLAG_RESERVED_6 | SMART_EVENT_FLAG_DEBUG_ONLY | SMART_EVENT_FLAG_DONT_RESET) + SMART_EVENT_FLAGS_ALL = (SMART_EVENT_FLAG_NOT_REPEATABLE | SMART_EVENT_FLAG_DIFFICULTY_ALL | SMART_EVENT_FLAG_RESERVED_5 | SMART_EVENT_FLAG_RESERVED_6 | SMART_EVENT_FLAG_DEBUG_ONLY | SMART_EVENT_FLAG_DONT_RESET | SMART_EVENT_FLAG_WHILE_CHARMED) }; enum SmartCastFlags