diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 74 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.h | 1 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 26 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 23 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 19 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 5 |
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; |