diff options
author | treeston <treeston.mmoc@gmail.com> | 2016-09-02 23:14:50 +0200 |
---|---|---|
committer | treeston <treeston.mmoc@gmail.com> | 2016-09-02 23:14:50 +0200 |
commit | e9eacae7b2ca3c8899a6ee9c8b8146e21fca54db (patch) | |
tree | afb091a42277c5c737dbe16ba5bd5072c8d2f1c8 | |
parent | be8d1136994fd5f0a90b03a52d21c9503857f15f (diff) | |
parent | 96f90381e3ed696861354ea4ddf4ac0c495031c5 (diff) |
Merge branch '3.3.5-goshdangitsmartai' into 3.3.5 (PR #17738)
-rw-r--r-- | sql/updates/world/3.3.5/2016_09_02_03_world.sql | 27 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.cpp | 75 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.h | 7 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 15 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.h | 16 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 2 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 18 |
7 files changed, 127 insertions, 33 deletions
diff --git a/sql/updates/world/3.3.5/2016_09_02_03_world.sql b/sql/updates/world/3.3.5/2016_09_02_03_world.sql new file mode 100644 index 00000000000..435919c5071 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_09_02_03_world.sql @@ -0,0 +1,27 @@ +-- set "execute event while charmed" flag on all events except: +-- -) movement actions +-- -) nontriggered cast actions +-- -) talk/emote/sound actions +-- -) ally summon actions +ALTER TABLE `smart_scripts` MODIFY COLUMN `event_flags` SMALLINT(3) UNSIGNED NOT NULL DEFAULT '0'; +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); diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 5e08149570d..40f71d94632 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -28,6 +28,7 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c) { + mIsCharmed = false; // copy script to local (protection for table reload) mWayPoints = nullptr; @@ -70,6 +71,15 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c) mJustReset = false; } +bool SmartAI::IsAIControlled() const +{ + if (me->IsControlledByPlayer()) + return false; + if (mIsCharmed) + return false; + return true; +} + void SmartAI::UpdateDespawn(const uint32 diff) { if (mDespawnState <= 1 || mDespawnState > 3) @@ -155,7 +165,7 @@ void SmartAI::PausePath(uint32 delay, bool forced) return; if (HasEscortState(SMART_ESCORT_PAUSED)) { - TC_LOG_ERROR("misc", "SmartAI::StartPath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry()); + TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry()); return; } mForcedPaused = forced; @@ -199,7 +209,10 @@ void SmartAI::EndPath(bool fail) mLastWP = nullptr; if (mCanRepeatPath) - StartPath(mRun, GetScript()->GetPathId(), true); + { + if (IsAIControlled()) + StartPath(mRun, GetScript()->GetPathId(), true); + } else GetScript()->SetPathId(0); @@ -249,7 +262,6 @@ void SmartAI::EndPath(bool fail) void SmartAI::ResumePath() { - //mWPReached = false; SetRun(mRun); if (mLastWP) me->GetMotionMaster()->MovePoint(mLastWP->id, mLastWP->x, mLastWP->y, mLastWP->z); @@ -257,6 +269,9 @@ void SmartAI::ResumePath() void SmartAI::ReturnToLastOOCPos() { + if (!IsAIControlled()) + return; + SetRun(mRun); me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, mLastOOCPos); } @@ -347,6 +362,9 @@ void SmartAI::UpdateAI(uint32 diff) mFollowArrivedTimer -= diff; } + if (!IsAIControlled()) + return; + if (!UpdateVictim()) return; @@ -413,19 +431,15 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data) void SmartAI::EnterEvadeMode(EvadeReason /*why*/) { - if (!me->IsAlive() || me->IsInEvadeMode()) - return; - if (mEvadeDisabled) { GetScript()->ProcessEventsFor(SMART_EVENT_EVADE); return; } - me->RemoveAurasOnEvade(); - + 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 @@ -446,7 +460,7 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/) else me->GetMotionMaster()->MoveTargetedHome(); - if (!HasEscortState(SMART_ESCORT_ESCORTING))//dont mess up escort movement after combat + if (!HasEscortState(SMART_ESCORT_ESCORTING)) //dont mess up escort movement after combat SetRun(mRun); } @@ -457,6 +471,9 @@ void SmartAI::MoveInLineOfSight(Unit* who) GetScript()->OnMoveInLineOfSight(who); + if (!IsAIControlled()) + return; + if (AssistPlayerInCombatAgainst(who)) return; @@ -470,7 +487,7 @@ bool SmartAI::CanAIAttack(const Unit* /*who*/) const bool SmartAI::AssistPlayerInCombatAgainst(Unit* who) { - if (me->HasReactState(REACT_PASSIVE)) + if (me->HasReactState(REACT_PASSIVE) || !IsAIControlled()) return false; if (!who || !who->GetVictim()) @@ -552,8 +569,13 @@ void SmartAI::JustReachedHome() void SmartAI::EnterCombat(Unit* enemy) { - me->InterruptNonMeleeSpells(false); // must be before ProcessEvents + if (IsAIControlled()) + me->InterruptNonMeleeSpells(false); // must be before ProcessEvents + GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy); + + if (!IsAIControlled()) + return; mLastOOCPos = me->GetPosition(); SetRun(mRun); if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == POINT_MOTION_TYPE) @@ -603,6 +625,10 @@ void SmartAI::SpellHitTarget(Unit* target, const SpellInfo* spellInfo) void SmartAI::DamageTaken(Unit* doneBy, uint32& damage) { GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage); + + if (!IsAIControlled()) // don't allow players to use unkillable units + return; + if (mInvincibilityHpLevel && (damage >= me->GetHealth() - mInvincibilityHpLevel)) damage = me->GetHealth() - mInvincibilityHpLevel; // damage should not be nullified, because of player damage req. } @@ -632,8 +658,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); @@ -655,11 +679,26 @@ void SmartAI::InitializeAI() void SmartAI::OnCharmed(bool apply) { - GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, apply); + if (apply) // 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); + me->StopMoving(); + } + mIsCharmed = apply; if (!apply && !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, apply); } void SmartAI::DoAction(int32 param) @@ -738,6 +777,8 @@ void SmartAI::SetCombatMove(bool on) if (mCanCombatMove == on) return; mCanCombatMove = on; + if (!IsAIControlled()) + return; if (!HasEscortState(SMART_ESCORT_ESCORTING)) { if (on && me->GetVictim()) @@ -770,15 +811,15 @@ void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, ui return; } - SetRun(mRun); mFollowGuid = target->GetGUID(); mFollowDist = dist >= 0.0f ? dist : PET_FOLLOW_DIST; mFollowAngle = angle >= 0.0f ? angle : me->GetFollowAngle(); mFollowArrivedTimer = 1000; mFollowCredit = credit; mFollowArrivedEntry = end; - me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle); mFollowCreditType = creditType; + SetRun(mRun); + me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle); } void SmartAI::StopFollow() diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 46363143c6f..ac389ccd166 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -48,6 +48,9 @@ class TC_GAME_API SmartAI : public CreatureAI ~SmartAI(){ } 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); @@ -129,9 +132,6 @@ class TC_GAME_API SmartAI : public CreatureAI // 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; @@ -197,6 +197,7 @@ class TC_GAME_API SmartAI : public CreatureAI void OnSpellClick(Unit* clicker, bool& result) override; private: + bool mIsCharmed; uint32 mFollowCreditType; uint32 mFollowArrivedTimer; uint32 mFollowCredit; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 398364dc98a..e13ed9da929 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -99,7 +99,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; } @@ -769,6 +769,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; me->DoFleeToGetAssistance(); + if (e.action.flee.withEmote) { Trinity::BroadcastTextBuilder builder(me, CHAT_MSG_MONSTER_EMOTE, BROADCAST_TEXT_FLEE_FOR_ASSIST); @@ -1175,6 +1176,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!IsCreature(*itr)) continue; + if (!(e.event.event_flags & SMART_EVENT_FLAG_WHILE_CHARMED) && !IsCreatureInControlOfSelf(*itr)) + continue; + Position pos = (*itr)->GetPosition(); // Use forward/backward/left/right cartesian plane movement @@ -2848,6 +2852,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) && IsCreature(me) && !IsCreatureInControlOfSelf(me)) + return; + switch (e.GetEventType()) { case SMART_EVENT_LINK://special handling @@ -2987,12 +2994,16 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax); break; } + case SMART_EVENT_CHARMED: + { + if (bvar == (e.event.charm.onRemove != 1)) + ProcessAction(e, unit, var0, var1, bvar, spell, gob); + } //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: diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 3e3af58a813..8ac5b494911 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -63,22 +63,30 @@ class TC_GAME_API SmartScript return obj; } - bool IsUnit(WorldObject* obj) + static bool IsUnit(WorldObject* obj) { return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER); } - bool IsPlayer(WorldObject* obj) + static bool IsPlayer(WorldObject* obj) { return obj && obj->GetTypeId() == TYPEID_PLAYER; } - bool IsCreature(WorldObject* obj) + static bool IsCreature(WorldObject* obj) { return obj && obj->GetTypeId() == TYPEID_UNIT; } - bool IsGameObject(WorldObject* obj) + static bool IsCreatureInControlOfSelf(WorldObject* obj) + { + if (Creature* creatureObj = obj ? obj->ToCreature() : nullptr) + return !creatureObj->IsCharmed() && !creatureObj->IsControlledByPlayer(); + else + return false; + } + + static bool IsGameObject(WorldObject* obj) { return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT; } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 7b4ffc8bd04..d7051e10988 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -225,7 +225,7 @@ void SmartAIMgr::LoadSmartAIFromDB() temp.event.type = (SMART_EVENT)fields[4].GetUInt8(); temp.event.event_phase_mask = fields[5].GetUInt8(); temp.event.event_chance = fields[6].GetUInt8(); - temp.event.event_flags = fields[7].GetUInt8(); + temp.event.event_flags = fields[7].GetUInt16(); temp.event.raw.param1 = fields[8].GetUInt32(); temp.event.raw.param2 = fields[9].GetUInt32(); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 28d434ad988..1b51fd20c1a 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -129,7 +129,7 @@ enum SMART_EVENT SMART_EVENT_IC_LOS = 26, // NoHostile, MaxRnage, CooldownMin, CooldownMax 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 @@ -294,6 +294,11 @@ struct SmartEvent struct { + uint32 onRemove; + } charm; + + struct + { uint32 spell; uint32 count; uint32 repeatMin; @@ -1361,20 +1366,21 @@ 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 { - SMARTCAST_INTERRUPT_PREVIOUS = 0x01, //Interrupt any spell casting - SMARTCAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time) + SMARTCAST_INTERRUPT_PREVIOUS = 0x01, // Interrupt any spell casting + SMARTCAST_TRIGGERED = 0x02, // Triggered (this makes spell cost zero mana and have no cast time) //SMARTCAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range //SMARTCAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range //SMARTCAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself - SMARTCAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell - SMARTCAST_COMBAT_MOVE = 0x40 //Prevents combat movement if cast successful. Allows movement on range, OOM, LOS + SMARTCAST_AURA_NOT_PRESENT = 0x20, // Only casts the spell if the target does not have an aura from the spell + SMARTCAST_COMBAT_MOVE = 0x40 // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS }; // one line in DB is one event |