diff options
Diffstat (limited to 'src/server/game/AI')
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.cpp | 16 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.h | 2 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 82 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.h | 5 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 76 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 16 |
6 files changed, 173 insertions, 24 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index a203aeb6b97..23dea877776 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -412,26 +412,12 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data) MovepointReached(Data); } -void SmartAI::RemoveAuras() -{ - /// @fixme: duplicated logic in CreatureAI::_EnterEvadeMode (could use RemoveAllAurasExceptType) - Unit::AuraApplicationMap& appliedAuras = me->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end();) - { - Aura const* aura = iter->second->GetBase(); - if (!aura->IsPassive() && !aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE) && !aura->HasEffectType(SPELL_AURA_CLONE_CASTER) && aura->GetCasterGUID() != me->GetGUID()) - me->RemoveAura(iter); - else - ++iter; - } -} - void SmartAI::EnterEvadeMode() { if (!me->IsAlive() || me->IsInEvadeMode()) return; - RemoveAuras(); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_CLONE_CASTER); me->AddUnitState(UNIT_STATE_EVADE); me->DeleteThreatList(); diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index dcf64b657f8..4d66b976746 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -193,8 +193,6 @@ class SmartAI : public CreatureAI } void StartDespawn() { mDespawnState = 2; } - void RemoveAuras(); - void OnSpellClick(Unit* clicker, bool& result); private: diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 99ac2ca6f25..006ee4b69ad 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -76,6 +76,7 @@ SmartScript::SmartScript() goOrigGUID = 0; mLastInvoker = 0; mScriptType = SMART_SCRIPT_TYPE_CREATURE; + isProcessingTimedActionList = false; } SmartScript::~SmartScript() @@ -511,7 +512,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u // unless target is outside spell range, out of mana, or LOS. bool _allowMove = false; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.cast.spell); + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); int32 mana = me->GetPower(POWER_MANA); if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || @@ -3116,6 +3117,68 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui ProcessTimedAction(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax, target); break; } + case SMART_EVENT_DISTANCE_CREATURE: + { + if (!me) + return; + + WorldObject* creature = NULL; + + if (e.event.distance.guid != 0) + { + creature = FindCreatureNear(me, e.event.distance.guid); + + if (!creature) + return; + + if (!me->IsInRange(creature, 0, (float)e.event.distance.dist)) + return; + } + else if (e.event.distance.entry != 0) + { + std::list<Creature*> list; + me->GetCreatureListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist); + + if (list.size() > 0) + creature = list.front(); + } + + if (creature) + ProcessTimedAction(e, e.event.distance.repeat, e.event.distance.repeat); + + break; + } + case SMART_EVENT_DISTANCE_GAMEOBJECT: + { + if (!me) + return; + + WorldObject* gameobject = NULL; + + if (e.event.distance.guid != 0) + { + gameobject = FindGameObjectNear(me, e.event.distance.guid); + + if (!gameobject) + return; + + if (!me->IsInRange(gameobject, 0, (float)e.event.distance.dist)) + return; + } + else if (e.event.distance.entry != 0) + { + std::list<GameObject*> list; + me->GetGameObjectListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist); + + if (list.size() > 0) + gameobject = list.front(); + } + + if (gameobject) + ProcessTimedAction(e, e.event.distance.repeat, e.event.distance.repeat); + + break; + } default: TC_LOG_ERROR("sql.sql", "SmartScript::ProcessEvent: Unhandled Event type %u", e.GetEventType()); break; @@ -3136,6 +3199,10 @@ void SmartScript::InitTimer(SmartScriptHolder& e) case SMART_EVENT_OOC_LOS: RecalcTimer(e, e.event.los.cooldownMin, e.event.los.cooldownMax); break; + case SMART_EVENT_DISTANCE_CREATURE: + case SMART_EVENT_DISTANCE_GAMEOBJECT: + RecalcTimer(e, e.event.distance.repeat, e.event.distance.repeat); + break; default: e.active = true; break; @@ -3196,6 +3263,8 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) case SMART_EVENT_TARGET_BUFFED: case SMART_EVENT_IS_BEHIND_TARGET: case SMART_EVENT_FRIENDLY_HEALTH_PCT: + case SMART_EVENT_DISTANCE_CREATURE: + case SMART_EVENT_DISTANCE_GAMEOBJECT: { ProcessEvent(e); if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST) @@ -3252,6 +3321,7 @@ void SmartScript::OnUpdate(uint32 const diff) bool needCleanup = true; if (!mTimedActionList.empty()) { + isProcessingTimedActionList = true; for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i) { if ((*i).enableTimed) @@ -3260,6 +3330,8 @@ void SmartScript::OnUpdate(uint32 const diff) needCleanup = false; } } + + isProcessingTimedActionList = false; } if (needCleanup) mTimedActionList.clear(); @@ -3501,6 +3573,14 @@ Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly) void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry) { + //do NOT clear mTimedActionList if it's being iterated because it will invalidate the iterator and delete + // any SmartScriptHolder contained like the "e" parameter passed to this function + if (isProcessingTimedActionList) + { + TC_LOG_ERROR("scripts.ai", "Entry %d SourceType %u Event %u Action %u is trying to overwrite timed action list from a timed action, this is not allowed!.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); + return; + } + mTimedActionList.clear(); mTimedActionList = sSmartScriptMgr->GetScript(entry, SMART_SCRIPT_TYPE_TIMED_ACTIONLIST); if (mTimedActionList.empty()) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 2e1068d1bff..244728a3037 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -118,7 +118,7 @@ class SmartScript smart = false; if (!smart) - TC_LOG_ERROR("sql.sql", "SmartScript: Action target Creature (GUID: %u Entry: %u) is not using SmartAI, action skipped to prevent crash.", c ? c->GetDBTableGUIDLow() : (me ? me->GetDBTableGUIDLow() : 0), c ? c->GetEntry() : (me ? me->GetEntry() : 0)); + TC_LOG_ERROR("sql.sql", "SmartScript: Action target Creature (GUID: %u Entry: %u) is not using SmartAI, action called by Creature (GUID: %u Entry: %u) skipped to prevent crash.", c ? c->GetDBTableGUIDLow() : 0, c ? c->GetEntry() : 0, me ? me->GetDBTableGUIDLow() : 0, me ? me->GetEntry() : 0); return smart; } @@ -132,7 +132,7 @@ class SmartScript if (!go || go->GetAIName() != "SmartGameObjectAI") smart = false; if (!smart) - TC_LOG_ERROR("sql.sql", "SmartScript: Action target GameObject (GUID: %u Entry: %u) is not using SmartGameObjectAI, action skipped to prevent crash.", g ? g->GetDBTableGUIDLow() : (go ? go->GetDBTableGUIDLow() : 0), g ? g->GetEntry() : (go ? go->GetEntry() : 0)); + TC_LOG_ERROR("sql.sql", "SmartScript: Action target GameObject (GUID: %u Entry: %u) is not using SmartGameObjectAI, action called by GameObject (GUID: %u Entry: %u) skipped to prevent crash.", g ? g->GetDBTableGUIDLow() : 0, g ? g->GetEntry() : 0, go ? go->GetDBTableGUIDLow() : 0, go ? go->GetEntry() : 0); return smart; } @@ -222,6 +222,7 @@ class SmartScript SmartAIEventList mEvents; SmartAIEventList mInstallEvents; SmartAIEventList mTimedActionList; + bool isProcessingTimedActionList; Creature* me; uint64 meOrigGUID; GameObject* go; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index d912de2a72c..993e6967ba5 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -583,6 +583,56 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) return false; } break; + case SMART_EVENT_DISTANCE_CREATURE: + if (e.event.distance.guid == 0 && e.event.distance.entry == 0) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE did not provide creature guid or entry, skipped."); + return false; + } + + if (e.event.distance.guid != 0 && e.event.distance.entry != 0) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE provided both an entry and guid, skipped."); + return false; + } + + if (e.event.distance.guid != 0 && !sObjectMgr->GetCreatureData(e.event.distance.guid)) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature guid %u, skipped.", e.event.distance.guid); + return false; + } + + if (e.event.distance.entry != 0 && !sObjectMgr->GetCreatureTemplate(e.event.distance.entry)) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature entry %u, skipped.", e.event.distance.entry); + return false; + } + break; + case SMART_EVENT_DISTANCE_GAMEOBJECT: + if (e.event.distance.guid == 0 && e.event.distance.entry == 0) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT did not provide gameobject guid or entry, skipped."); + return false; + } + + if (e.event.distance.guid != 0 && e.event.distance.entry != 0) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT provided both an entry and guid, skipped."); + return false; + } + + if (e.event.distance.guid != 0 && !sObjectMgr->GetGOData(e.event.distance.guid)) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid %u, skipped.", e.event.distance.guid); + return false; + } + + if (e.event.distance.entry != 0 && !sObjectMgr->GetGameObjectTemplate(e.event.distance.entry)) + { + TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject entry %u, skipped.", e.event.distance.entry); + return false; + } + break; case SMART_EVENT_GO_STATE_CHANGED: case SMART_EVENT_GO_EVENT_INFORM: case SMART_EVENT_TIMED_EVENT_TRIGGERED: @@ -887,6 +937,12 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) return false; break; } + case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: + { + if (!IsMinMaxValid(e, e.action.randTimedActionList.entry1, e.action.randTimedActionList.entry2)) + return false; + break; + } case SMART_ACTION_SET_POWER: case SMART_ACTION_ADD_POWER: case SMART_ACTION_REMOVE_POWER: @@ -934,6 +990,24 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) } break; } + case SMART_ACTION_EQUIP: + { + if (e.GetScriptType() == SMART_SCRIPT_TYPE_CREATURE) + { + int8 equipId = (int8)e.action.equip.entry; + + if (equipId) + { + EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(e.entryOrGuid, equipId); + if (!einfo) + { + TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature %u, skipped.", equipId, e.entryOrGuid); + return false; + } + } + } + break; + } case SMART_ACTION_FOLLOW: case SMART_ACTION_SET_ORIENTATION: case SMART_ACTION_STORE_TARGET_LIST: @@ -970,7 +1044,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_MOVE_TO_POS: case SMART_ACTION_RESPAWN_TARGET: case SMART_ACTION_CLOSE_GOSSIP: - case SMART_ACTION_EQUIP: case SMART_ACTION_TRIGGER_TIMED_EVENT: case SMART_ACTION_REMOVE_TIMED_EVENT: case SMART_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT: @@ -986,7 +1059,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_SIMPLE_TALK: case SMART_ACTION_CROSS_CAST: case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: - case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST: case SMART_ACTION_RANDOM_MOVE: case SMART_ACTION_SET_UNIT_FIELD_BYTES_1: case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index d47dbeae600..78a26e7e836 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -166,8 +166,10 @@ enum SMART_EVENT 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_DISTANCE_CREATURE = 75, // guid, entry, distance, repeat + SMART_EVENT_DISTANCE_GAMEOBJECT = 76, // guid, entry, distance, repeat - SMART_EVENT_END = 75 + SMART_EVENT_END = 77 }; struct SmartEvent @@ -389,6 +391,14 @@ struct SmartEvent struct { + uint32 guid; + uint32 entry; + uint32 dist; + uint32 repeat; + } distance; + + struct + { uint32 param1; uint32 param2; uint32 param3; @@ -1221,7 +1231,7 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] = {SMART_EVENT_REACHED_HOME, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_RECEIVE_EMOTE, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_HAS_AURA, SMART_SCRIPT_TYPE_MASK_CREATURE }, - {SMART_EVENT_TARGET_BUFFED, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, + {SMART_EVENT_TARGET_BUFFED, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_RESET, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_IC_LOS, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_PASSENGER_BOARDED, SMART_SCRIPT_TYPE_MASK_CREATURE }, @@ -1272,6 +1282,8 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] = {SMART_EVENT_ACTION_DONE, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_ON_SPELLCLICK, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_FRIENDLY_HEALTH_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE }, + {SMART_EVENT_DISTANCE_CREATURE, SMART_SCRIPT_TYPE_MASK_CREATURE }, + {SMART_EVENT_DISTANCE_GAMEOBJECT, SMART_SCRIPT_TYPE_MASK_CREATURE }, }; enum SmartEventFlags |
