aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortreeston <treeston.mmoc@gmail.com>2016-09-02 23:14:50 +0200
committertreeston <treeston.mmoc@gmail.com>2016-09-02 23:14:50 +0200
commite9eacae7b2ca3c8899a6ee9c8b8146e21fca54db (patch)
treeafb091a42277c5c737dbe16ba5bd5072c8d2f1c8
parentbe8d1136994fd5f0a90b03a52d21c9503857f15f (diff)
parent96f90381e3ed696861354ea4ddf4ac0c495031c5 (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.sql27
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp75
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h7
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp15
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h16
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h18
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