aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp74
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp26
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h23
-rw-r--r--src/server/game/Spells/SpellInfo.cpp19
-rw-r--r--src/server/game/Spells/SpellInfo.h2
-rw-r--r--src/server/game/Spells/SpellMgr.cpp5
7 files changed, 137 insertions, 13 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 65b1e6c331e..b4e18b66a69 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1401,7 +1401,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
e.GetTargetType() == SMART_TARGET_GAMEOBJECT_GUID || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_DISTANCE ||
e.GetTargetType() == SMART_TARGET_CLOSEST_CREATURE || e.GetTargetType() == SMART_TARGET_CLOSEST_GAMEOBJECT ||
e.GetTargetType() == SMART_TARGET_OWNER_OR_SUMMONER || e.GetTargetType() == SMART_TARGET_ACTION_INVOKER ||
- e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY)
+ e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY || e.GetTargetType() == SMART_TARGET_CLOSEST_FRIENDLY)
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
@@ -2506,6 +2506,14 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*
break;
}
+ case SMART_TARGET_CLOSEST_FRIENDLY:
+ {
+ if (me)
+ if (Unit* target = DoFindClosestFriendlyInRange(e.target.closestFriendly.maxDist))
+ l->push_back(target);
+
+ break;
+ }
case SMART_TARGET_POSITION:
default:
break;
@@ -2623,7 +2631,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
return;
Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealt.radius, e.event.friendlyHealt.hpDeficit);
- if (!target)
+ if (!target || !target->IsInCombat())
return;
ProcessTimedAction(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax, target);
break;
@@ -2940,6 +2948,55 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
ProcessAction(e, unit, var0);
break;
}
+ case SMART_EVENT_FRIENDLY_HEALTH_PCT:
+ {
+ if (!me || !me->IsInCombat())
+ return;
+
+ ObjectList* _targets = NULL;
+
+ switch (e.GetTargetType())
+ {
+ case SMART_TARGET_CREATURE_RANGE:
+ case SMART_TARGET_CREATURE_GUID:
+ case SMART_TARGET_CREATURE_DISTANCE:
+ case SMART_TARGET_CLOSEST_CREATURE:
+ case SMART_TARGET_CLOSEST_PLAYER:
+ case SMART_TARGET_PLAYER_RANGE:
+ case SMART_TARGET_PLAYER_DISTANCE:
+ _targets = GetTargets(e);
+ break;
+ default:
+ return;
+ }
+
+ if (!_targets)
+ return;
+
+ Unit* target = NULL;
+
+ for (ObjectList::const_iterator itr = _targets->begin(); itr != _targets->end(); ++itr)
+ {
+ if (IsUnit(*itr) && me->IsFriendlyTo((*itr)->ToUnit()) && (*itr)->ToUnit()->IsAlive() && (*itr)->ToUnit()->IsInCombat())
+ {
+ uint32 healthPct = uint32((*itr)->ToUnit()->GetHealthPct());
+
+ if (healthPct > e.event.friendlyHealtPct.maxHpPct || healthPct < e.event.friendlyHealtPct.minHpPct)
+ continue;
+
+ target = (*itr)->ToUnit();
+ break;
+ }
+ }
+
+ delete _targets;
+
+ if (!target)
+ return;
+
+ ProcessTimedAction(e, e.event.friendlyHealtPct.repeatMin, e.event.friendlyHealtPct.repeatMax, target);
+ break;
+ }
default:
TC_LOG_ERROR(LOG_FILTER_SQL, "SmartScript::ProcessEvent: Unhandled Event type %u", e.GetEventType());
break;
@@ -3019,6 +3076,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
case SMART_EVENT_HAS_AURA:
case SMART_EVENT_TARGET_BUFFED:
case SMART_EVENT_IS_BEHIND_TARGET:
+ case SMART_EVENT_FRIENDLY_HEALTH_PCT:
{
ProcessEvent(e);
if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST)
@@ -3324,6 +3382,18 @@ void SmartScript::DoFindFriendlyMissingBuff(std::list<Creature*>& list, float ra
cell.Visit(p, grid_creature_searcher, *me->GetMap(), *me, range);
}
+Unit* SmartScript::DoFindClosestFriendlyInRange(float range)
+{
+ if (!me)
+ return NULL;
+
+ Unit* unit = NULL;
+ Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(me, me, range);
+ Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(me, unit, u_check);
+ me->VisitNearbyObject(range, searcher);
+ return unit;
+}
+
void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry)
{
mTimedActionList.clear();
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index 6801c132331..b22f2d81b26 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -89,6 +89,7 @@ class SmartScript
Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff);
void DoFindFriendlyCC(std::list<Creature*>& _list, float range);
void DoFindFriendlyMissingBuff(std::list<Creature*>& list, float range, uint32 spellid);
+ Unit* DoFindClosestFriendlyInRange(float range);
void StoreTargetList(ObjectList* targets, uint32 id)
{
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 6563aeec700..095440266f3 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -301,6 +301,7 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
case SMART_TARGET_CLOSEST_GAMEOBJECT:
case SMART_TARGET_CLOSEST_CREATURE:
case SMART_TARGET_CLOSEST_ENEMY:
+ case SMART_TARGET_CLOSEST_FRIENDLY:
case SMART_TARGET_STORED:
break;
default:
@@ -544,6 +545,31 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
break;
}
+ case SMART_EVENT_FRIENDLY_HEALTH_PCT:
+ if (!IsMinMaxValid(e, e.event.friendlyHealtPct.repeatMin, e.event.friendlyHealtPct.repeatMax))
+ return false;
+
+ if (e.event.friendlyHealtPct.maxHpPct > 100 || e.event.friendlyHealtPct.minHpPct > 100)
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u has pct value above 100, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
+ return false;
+ }
+
+ switch (e.GetTargetType())
+ {
+ case SMART_TARGET_CREATURE_RANGE:
+ case SMART_TARGET_CREATURE_GUID:
+ case SMART_TARGET_CREATURE_DISTANCE:
+ case SMART_TARGET_CLOSEST_CREATURE:
+ case SMART_TARGET_CLOSEST_PLAYER:
+ case SMART_TARGET_PLAYER_RANGE:
+ case SMART_TARGET_PLAYER_DISTANCE:
+ break;
+ default:
+ TC_LOG_ERROR(LOG_FILTER_SQL, "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid target_type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
+ return false;
+ }
+ break;
case SMART_EVENT_GO_STATE_CHANGED:
case SMART_EVENT_GO_EVENT_INFORM:
case SMART_EVENT_TIMED_EVENT_TRIGGERED:
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index e5f30a9709d..81336d0e0ca 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -156,8 +156,9 @@ enum SMART_EVENT
SMART_EVENT_GO_EVENT_INFORM = 71, // eventId
SMART_EVENT_ACTION_DONE = 72, // eventId (SharedDefines.EventId)
SMART_EVENT_ON_SPELLCLICK = 73, // clicker (unit)
+ SMART_EVENT_FRIENDLY_HEALTH_PCT = 74, // minHpPct, maxHpPct, repeatMin, repeatMax
- SMART_EVENT_END = 74
+ SMART_EVENT_END = 75
};
struct SmartEvent
@@ -364,6 +365,14 @@ struct SmartEvent
struct
{
+ uint32 minHpPct;
+ uint32 maxHpPct;
+ uint32 repeatMin;
+ uint32 repeatMax;
+ } friendlyHealtPct;
+
+ struct
+ {
uint32 param1;
uint32 param2;
uint32 param3;
@@ -1002,7 +1011,9 @@ enum SMARTAI_TARGETS
SMART_TARGET_OWNER_OR_SUMMONER = 23, // Unit's owner or summoner
SMART_TARGET_THREAT_LIST = 24, // All units on creature's threat list
SMART_TARGET_CLOSEST_ENEMY = 25, // maxDist
- SMART_TARGET_END = 26
+ SMART_TARGET_CLOSEST_FRIENDLY = 26, // maxDist
+
+ SMART_TARGET_END = 27
};
struct SmartTarget
@@ -1091,6 +1102,11 @@ struct SmartTarget
struct
{
+ uint32 maxDist;
+ } closestFriendly;
+
+ struct
+ {
uint32 param1;
uint32 param2;
uint32 param3;
@@ -1226,7 +1242,8 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] =
{SMART_EVENT_GO_STATE_CHANGED, SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_GO_EVENT_INFORM, SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
{SMART_EVENT_ACTION_DONE, SMART_SCRIPT_TYPE_MASK_CREATURE },
- {SMART_EVENT_ON_SPELLCLICK, SMART_SCRIPT_TYPE_MASK_CREATURE }
+ {SMART_EVENT_ON_SPELLCLICK, SMART_SCRIPT_TYPE_MASK_CREATURE },
+ {SMART_EVENT_FRIENDLY_HEALTH_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE },
};
enum SmartEventFlags
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 0fb463f222c..52d4e5487ee 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1172,8 +1172,12 @@ bool SpellInfo::NeedsExplicitUnitTarget() const
bool SpellInfo::NeedsToBeTriggeredByCaster() const
{
- if (NeedsExplicitUnitTarget() || Id == 96946 || Id == 101005)
+ if (AttributesCu & SPELL_ATTR0_CU_TRIGGERED_BY_CASTER)
return true;
+
+ if (NeedsExplicitUnitTarget())
+ return true;
+
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (Effects[i].IsEffect())
@@ -1183,6 +1187,7 @@ bool SpellInfo::NeedsToBeTriggeredByCaster() const
return true;
}
}
+
return false;
}
@@ -1891,7 +1896,7 @@ uint32 SpellInfo::GetAllEffectsMechanicMask() const
uint32 mask = 0;
if (Mechanic)
mask |= 1 << Mechanic;
- for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (Effects[i].IsEffect() && Effects[i].Mechanic)
mask |= 1 << Effects[i].Mechanic;
return mask;
@@ -1901,9 +1906,9 @@ uint32 SpellInfo::GetEffectMechanicMask(uint8 effIndex) const
{
uint32 mask = 0;
if (Mechanic)
- mask |= 1<< Mechanic;
+ mask |= 1 << Mechanic;
if (Effects[effIndex].IsEffect() && Effects[effIndex].Mechanic)
- mask |= 1<< Effects[effIndex].Mechanic;
+ mask |= 1 << Effects[effIndex].Mechanic;
return mask;
}
@@ -1911,10 +1916,10 @@ uint32 SpellInfo::GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
{
uint32 mask = 0;
if (Mechanic)
- mask |= 1<< Mechanic;
- for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ mask |= 1 << Mechanic;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if ((effectMask & (1 << i)) && Effects[i].Mechanic)
- mask |= 1<< Effects[i].Mechanic;
+ mask |= 1 << Effects[i].Mechanic;
return mask;
}
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 73d2ce3efcd..0ee8571196f 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -179,7 +179,7 @@ enum SpellCustomAttributes
SPELL_ATTR0_CU_CONE_LINE = 0x00000004,
SPELL_ATTR0_CU_SHARE_DAMAGE = 0x00000008,
SPELL_ATTR0_CU_NO_INITIAL_THREAT = 0x00000010,
- SPELL_ATTR0_CU_NONE2 = 0x00000020, // UNUSED
+ SPELL_ATTR0_CU_TRIGGERED_BY_CASTER = 0x00000020, // @todo: need generic solution, some triggered spells will be casted by target instead of caster
SPELL_ATTR0_CU_AURA_CC = 0x00000040,
SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
SPELL_ATTR0_CU_CHARGE = 0x00000200,
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index c6aba4853ee..cf694ff3348 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3047,6 +3047,11 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
break;
case 72293: // Mark of the Fallen Champion (Deathbringer Saurfang)
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0;
+ break;
+ case 38729: // Rod of Purification
+ case 96946: // Gaze of Occu'thar
+ case 101005: // Gaze of Occu'thar
+ spellInfo->AttributesCu |= SPELL_ATTR0_CU_TRIGGERED_BY_CASTER;
break;
default:
break;