diff options
author | Rat <none@none> | 2010-11-03 14:10:16 +0100 |
---|---|---|
committer | Rat <none@none> | 2010-11-03 14:10:16 +0100 |
commit | 9df4af80f4b19bb437a27c5c6189b058ef1196ba (patch) | |
tree | c1049a00cd0dac427d1b1c0419f07a066e13d881 | |
parent | afb3e790de943692e88fd5e8f539acda82aad704 (diff) |
Core/SmartAI: added script type 9 (TimedActionList)
- interrupt spells when entering combat
- fixed reset of timers
- added npc flag modify actions
- added action to call a TimedActionList, default options are: process only OOC and resume after combat
--HG--
branch : trunk
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.cpp | 1 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 107 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.h | 2 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 313 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 48 |
5 files changed, 305 insertions, 166 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 671b114fccc..f6aff7aee04 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -571,6 +571,7 @@ void SmartAI::JustReachedHome() void SmartAI::EnterCombat(Unit* enemy) { + me->InterruptNonMeleeSpells(false);//msut be before ProcessEvents GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy); me->GetPosition(&mLastOOCPos); } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index bdd5e12470d..6e090dafd68 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -51,6 +51,7 @@ SmartScript::SmartScript() mTemplate = SMARTAI_TEMPLATE_BASIC; meOrigGUID = 0; goOrigGUID = 0; + mResumeActionList = true; } void SmartScript::OnReset() @@ -59,8 +60,7 @@ void SmartScript::OnReset() ResetBaseObject(); for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i) { - if ((*i).GetEventType() == SMART_EVENT_UPDATE_OOC || (*i).GetEventType() == SMART_EVENT_UPDATE) - RecalcTimer((*i), (*i).event.minMaxRepeat.min, (*i).event.minMaxRepeat.max); + InitTimer((*i)); (*i).runOnce = false; } ProcessEventsFor(SMART_EVENT_RESET); @@ -68,10 +68,27 @@ void SmartScript::OnReset() void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellEntry* spell, GameObject* gob) { + if (e == SMART_EVENT_AGGRO) + { + if (!mResumeActionList) + mTimedActionList.clear();//clear action list if it is not resumable + else + { + for (SmartAIEventList::iterator itr = mTimedActionList.begin(); itr != mTimedActionList.end(); ++itr) + { + if (itr->enableTimed) + { + InitTimer((*itr));//re-init the currently enabled timer, so it restarts the timer when resumed + break; + } + } + } + } for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i) { if ((*i).GetEventType() == SMART_EVENT_LINK)//special handling continue; + if ((*i).GetEventType() == e/* && (!(*i).event.event_phase_mask || IsInPhase((*i).event.event_phase_mask)) && !((*i).event.event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE && (*i).runOnce)*/) ProcessEvent(*i, unit, var0, var1, bvar, spell, gob); } @@ -989,6 +1006,57 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u } break; } + case SMART_ACTION_CALL_TIMED_ACTIONLIST: + { + mTimedActionList.clear(); + mTimedActionList = sSmartScriptMgr.GetScript(e.action.timedActionList.id, SMART_SCRIPT_TYPE_TIMED_ACTIONLIST); + if (mTimedActionList.empty()) + return; + for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i) + { + if (i == mTimedActionList.begin()) + { + i->enableTimed = true;//enable processing only for the first action + } + else i->enableTimed = false; + + //i->event.type = SMART_EVENT_UPDATE_IC;//default value + if (e.action.timedActionList.timerType == 1) + i->event.type = SMART_EVENT_UPDATE_IC; + else if (e.action.timedActionList.timerType > 1) + i->event.type = SMART_EVENT_UPDATE; + mResumeActionList = e.action.timedActionList.dontResume ? false : true; + InitTimer((*i)); + } + break; + } + case SMART_ACTION_SET_NPC_FLAG: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) + if (IsUnit((*itr))) + (*itr)->ToUnit()->SetUInt32Value(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + break; + } + case SMART_ACTION_ADD_NPC_FLAG: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) + if (IsUnit((*itr))) + (*itr)->ToUnit()->SetFlag(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + break; + } + case SMART_ACTION_REMOVE_NPC_FLAG: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) + if (IsUnit((*itr))) + (*itr)->ToUnit()->RemoveFlag(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + break; + } default: sLog.outErrorDb("SmartScript::ProcessAction: Unhandled Action type %u", e.GetActionType()); break; @@ -1738,6 +1806,11 @@ void SmartScript::UpdateTimer(SmartScriptHolder &e, const uint32 diff) return; if (e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask)) return; + + if (e.GetEventType() == SMART_EVENT_UPDATE_IC && (!me || !me->isInCombat())) + return; + if (e.GetEventType() == SMART_EVENT_UPDATE_OOC && (me && me->isInCombat()))//can be used with me=NULL (go script) + return; if (e.timer < diff) { e.active = true;//activate events with cooldown @@ -1757,8 +1830,23 @@ void SmartScript::UpdateTimer(SmartScriptHolder &e, const uint32 diff) case SMART_EVENT_FRIENDLY_MISSING_BUFF: case SMART_EVENT_HAS_AURA: case SMART_EVENT_TARGET_BUFFED: + { ProcessEvent(e); + if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST) + { + e.enableTimed = false;//disable event if it is in an ActionList and was processed once + for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i) + { + //find the first event which is not the current one and enable it + if (i->event_id > e.event_id) + { + i->enableTimed = true; + break; + } + } + } break; + } } } else e.timer -= diff; } @@ -1796,6 +1884,21 @@ void SmartScript::OnUpdate(const uint32 diff) UpdateTimer((*i), diff); } } + bool needCleanup = true; + if (!mTimedActionList.empty()) + { + for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i) + { + if ((*i).enableTimed) + { + UpdateTimer((*i), diff); + needCleanup = false; + } + } + } + if (needCleanup) + mTimedActionList.clear(); + if (!mRemIDs.empty()) { for (std::list<uint32>::iterator i = mRemIDs.begin(); i != mRemIDs.end(); ++i) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 48e79408783..8a15e6b725c 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -193,6 +193,8 @@ class SmartScript SmartAIEventList mEvents; SmartAIEventList mInstallEvents; + SmartAIEventList mTimedActionList; + bool mResumeActionList; 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 70adaf864b9..50604dcaf35 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -159,6 +159,8 @@ void SmartAIMgr::LoadSmartAIFromDB() } break; } + case SMART_SCRIPT_TYPE_TIMED_ACTIONLIST: + break;//nothing to check, really default: sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type %u", (uint32)source_type); continue; @@ -284,14 +286,15 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder e) return true; } -bool SmartAIMgr::IsEventValid(SmartScriptHolder e) +bool SmartAIMgr::IsEventValid(SmartScriptHolder &e) { if (e.event.type >= SMART_EVENT_END) { sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid event type (%u), skipped.", e.entryOrGuid, e.event_id, e.GetEventType()); return false; } - if (!(SmartAIEventMask[e.event.type][1] & SmartAITypeMask[e.GetScriptType()][1])) + // in SMART_SCRIPT_TYPE_TIMED_ACTIONLIST all event types are overriden by core + if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && !(SmartAIEventMask[e.event.type][1] & SmartAITypeMask[e.GetScriptType()][1])) { sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d, event type %u can not be used for Script type %u", e.entryOrGuid, e.GetEventType(), e.GetScriptType()); return false; @@ -306,173 +309,183 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder e) sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid phase mask (%u), skipped.", e.entryOrGuid, e.event_id, e.event.event_phase_mask); return false; } - switch (e.event.type) + if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST) { - case SMART_EVENT_UPDATE: - case SMART_EVENT_UPDATE_IC: - case SMART_EVENT_UPDATE_OOC: - case SMART_EVENT_HEALT_PCT: - case SMART_EVENT_MANA_PCT: - case SMART_EVENT_TARGET_HEALTH_PCT: - case SMART_EVENT_TARGET_MANA_PCT: - case SMART_EVENT_RANGE: - case SMART_EVENT_DAMAGED: - case SMART_EVENT_DAMAGED_TARGET: - case SMART_EVENT_RECEIVE_HEAL: - if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max)) return false; - if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax)) return false; - break; - case SMART_EVENT_SPELLHIT: - case SMART_EVENT_SPELLHIT_TARGET: - if (e.event.spellHit.spell) - { - SpellEntry const* pSpell = sSpellStore.LookupEntry(e.event.spellHit.spell); - if (!pSpell) + e.event.type = SMART_EVENT_UPDATE_OOC;//force default OOC, can change when calling the script! + if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max)) return false; + if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax)) return false; + } + else + { + switch (e.event.type) + { + case SMART_EVENT_UPDATE: + case SMART_EVENT_UPDATE_IC: + case SMART_EVENT_UPDATE_OOC: + case SMART_EVENT_HEALT_PCT: + case SMART_EVENT_MANA_PCT: + case SMART_EVENT_TARGET_HEALTH_PCT: + case SMART_EVENT_TARGET_MANA_PCT: + case SMART_EVENT_RANGE: + case SMART_EVENT_DAMAGED: + case SMART_EVENT_DAMAGED_TARGET: + case SMART_EVENT_RECEIVE_HEAL: + if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max)) return false; + if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax)) return false; + break; + case SMART_EVENT_SPELLHIT: + case SMART_EVENT_SPELLHIT_TARGET: + if (e.event.spellHit.spell) { - sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); - return false; + SpellEntry const* pSpell = sSpellStore.LookupEntry(e.event.spellHit.spell); + if (!pSpell) + { + sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); + return false; + } + if (e.event.spellHit.school && (e.event.spellHit.school & pSpell->SchoolMask) != pSpell->SchoolMask) + { + sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses Spell entry %u with invalid school mask, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); + return false; + } } - if (e.event.spellHit.school && (e.event.spellHit.school & pSpell->SchoolMask) != pSpell->SchoolMask) + if (!IsMinMaxValid(e, e.event.spellHit.cooldownMin, e.event.spellHit.cooldownMax)) return false; + break; + case SMART_EVENT_OOC_LOS: + case SMART_EVENT_IC_LOS: + if (!IsMinMaxValid(e, e.event.los.cooldownMin, e.event.los.cooldownMax)) return false; + break; + case SMART_EVENT_RESPAWN: + if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && !sMapStore.LookupEntry(e.event.respawn.map)) { - sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses Spell entry %u with invalid school mask, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); + sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map); return false; } - } - if (!IsMinMaxValid(e, e.event.spellHit.cooldownMin, e.event.spellHit.cooldownMax)) return false; - break; - case SMART_EVENT_OOC_LOS: - case SMART_EVENT_IC_LOS: - if (!IsMinMaxValid(e, e.event.los.cooldownMin, e.event.los.cooldownMax)) return false; - break; - case SMART_EVENT_RESPAWN: - if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && !sMapStore.LookupEntry(e.event.respawn.map)) - { - sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map); - return false; - } - if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area)) - { - sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area); - return false; - } - break; - case SMART_EVENT_FRIENDLY_HEALTH: - if (!NotNULL(e, e.event.friendlyHealt.radius)) return false; - if (!IsMinMaxValid(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax)) return false; - break; - case SMART_EVENT_FRIENDLY_IS_CC: - if (!IsMinMaxValid(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax)) return false; - break; - case SMART_EVENT_FRIENDLY_MISSING_BUFF: - { - if (!IsSpellValid(e, e.event.missingBuff.spell)) return false; - if (!NotNULL(e, e.event.missingBuff.radius)) return false; - if (!IsMinMaxValid(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax)) return false; - break; - } - case SMART_EVENT_KILL: - if (!IsMinMaxValid(e, e.event.kill.cooldownMin, e.event.kill.cooldownMax)) return false; - if (e.event.kill.creature && !IsCreatureValid(e, e.event.kill.creature)) return false; - break; - case SMART_EVENT_TARGET_CASTING: - case SMART_EVENT_PASSENGER_BOARDED: - case SMART_EVENT_PASSENGER_REMOVED: - if (!IsMinMaxValid(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax)) return false; - break; - case SMART_EVENT_SUMMON_DESPAWNED: - case SMART_EVENT_SUMMONED_UNIT: - if (e.event.summoned.creature && !IsCreatureValid(e, e.event.summoned.creature)) return false; - if (!IsMinMaxValid(e, e.event.summoned.cooldownMin, e.event.summoned.cooldownMax)) return false; - break; - case SMART_EVENT_ACCEPTED_QUEST: - case SMART_EVENT_REWARD_QUEST: - if (!IsQuestValid(e, e.event.quest.quest)) return false; - break; - case SMART_EVENT_RECEIVE_EMOTE: - { - if (e.event.emote.emote && !IsEmoteValid(e, e.event.emote.emote)) return false; - if (!IsMinMaxValid(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax)) return false; - break; - } - case SMART_EVENT_HAS_AURA: - case SMART_EVENT_TARGET_BUFFED: - { - if (!IsSpellValid(e, e.event.aura.spell)) return false; - if (!IsMinMaxValid(e, e.event.aura.repeatMin, e.event.aura.repeatMax)) return false; - break; - } - case SMART_EVENT_TRANSPORT_ADDCREATURE: - { - if (e.event.transportAddCreature.creature && !IsCreatureValid(e, e.event.transportAddCreature.creature)) return false; - break; - } - case SMART_EVENT_MOVEMENTINFORM: - { - if (e.event.movementInform.type > NULL_MOTION_TYPE) + if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area)) { - sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Motion type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.movementInform.type); + sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area); return false; } break; - } - case SMART_EVENT_DATA_SET: + case SMART_EVENT_FRIENDLY_HEALTH: + if (!NotNULL(e, e.event.friendlyHealt.radius)) return false; + if (!IsMinMaxValid(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax)) return false; + break; + case SMART_EVENT_FRIENDLY_IS_CC: + if (!IsMinMaxValid(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax)) return false; + break; + case SMART_EVENT_FRIENDLY_MISSING_BUFF: { - if (!IsMinMaxValid(e, e.event.dataSet.cooldownMin, e.event.dataSet.cooldownMax)) return false; + if (!IsSpellValid(e, e.event.missingBuff.spell)) return false; + if (!NotNULL(e, e.event.missingBuff.radius)) return false; + if (!IsMinMaxValid(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax)) return false; break; } - case SMART_EVENT_AREATRIGGER_ONTRIGGER: + case SMART_EVENT_KILL: + if (!IsMinMaxValid(e, e.event.kill.cooldownMin, e.event.kill.cooldownMax)) return false; + if (e.event.kill.creature && !IsCreatureValid(e, e.event.kill.creature)) return false; + break; + case SMART_EVENT_TARGET_CASTING: + case SMART_EVENT_PASSENGER_BOARDED: + case SMART_EVENT_PASSENGER_REMOVED: + if (!IsMinMaxValid(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax)) return false; + break; + case SMART_EVENT_SUMMON_DESPAWNED: + case SMART_EVENT_SUMMONED_UNIT: + if (e.event.summoned.creature && !IsCreatureValid(e, e.event.summoned.creature)) return false; + if (!IsMinMaxValid(e, e.event.summoned.cooldownMin, e.event.summoned.cooldownMax)) return false; + break; + case SMART_EVENT_ACCEPTED_QUEST: + case SMART_EVENT_REWARD_QUEST: + if (!IsQuestValid(e, e.event.quest.quest)) return false; + break; + case SMART_EVENT_RECEIVE_EMOTE: { - if (e.event.areatrigger.id && !IsAreaTriggerValid(e, e.event.areatrigger.id)) return false; + if (e.event.emote.emote && !IsEmoteValid(e, e.event.emote.emote)) return false; + if (!IsMinMaxValid(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax)) return false; break; } - case SMART_EVENT_TEXT_OVER: - //if (e.event.textOver.textGroupID && !IsTextValid(e, e.event.textOver.textGroupID)) return false;// 0 is a valid text group! - break; - case SMART_EVENT_LINK: + case SMART_EVENT_HAS_AURA: + case SMART_EVENT_TARGET_BUFFED: { - if (e.link && e.link == e.event_id) + if (!IsSpellValid(e, e.event.aura.spell)) return false; + if (!IsMinMaxValid(e, e.event.aura.repeatMin, e.event.aura.repeatMax)) return false; + break; + } + case SMART_EVENT_TRANSPORT_ADDCREATURE: { - sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u, Event %u, Link Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id); - return false; + if (e.event.transportAddCreature.creature && !IsCreatureValid(e, e.event.transportAddCreature.creature)) return false; + break; + } + case SMART_EVENT_MOVEMENTINFORM: + { + if (e.event.movementInform.type > NULL_MOTION_TYPE) + { + sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Motion type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.movementInform.type); + return false; + } + break; } + case SMART_EVENT_DATA_SET: + { + if (!IsMinMaxValid(e, e.event.dataSet.cooldownMin, e.event.dataSet.cooldownMax)) return false; + break; + } + case SMART_EVENT_AREATRIGGER_ONTRIGGER: + { + if (e.event.areatrigger.id && !IsAreaTriggerValid(e, e.event.areatrigger.id)) return false; + break; + } + case SMART_EVENT_TEXT_OVER: + //if (e.event.textOver.textGroupID && !IsTextValid(e, e.event.textOver.textGroupID)) return false;// 0 is a valid text group! break; - } - case SMART_EVENT_TIMED_EVENT_TRIGGERED: - case SMART_EVENT_INSTANCE_PLAYER_ENTER: - case SMART_EVENT_TRANSPORT_RELOCATE: - case SMART_EVENT_CHARMED: - case SMART_EVENT_CHARMED_TARGET: - case SMART_EVENT_CORPSE_REMOVED: - case SMART_EVENT_AI_INIT: - case SMART_EVENT_TRANSPORT_ADDPLAYER: - case SMART_EVENT_TRANSPORT_REMOVE_PLAYER: - case SMART_EVENT_AGGRO: - case SMART_EVENT_DEATH: - case SMART_EVENT_EVADE: - case SMART_EVENT_REACHED_HOME: - case SMART_EVENT_RESET: - case SMART_EVENT_QUEST_ACCEPTED: - case SMART_EVENT_QUEST_OBJ_COPLETETION: - case SMART_EVENT_QUEST_COMPLETION: - case SMART_EVENT_QUEST_REWARDED: - case SMART_EVENT_QUEST_FAIL: - case SMART_EVENT_JUST_SUMMONED: - case SMART_EVENT_WAYPOINT_START: - case SMART_EVENT_WAYPOINT_REACHED: - case SMART_EVENT_WAYPOINT_PAUSED: - case SMART_EVENT_WAYPOINT_RESUMED: - case SMART_EVENT_WAYPOINT_STOPPED: - case SMART_EVENT_WAYPOINT_ENDED: - case SMART_ACTION_PLAYMOVIE: - case SMART_EVENT_GOSSIP_SELECT: - case SMART_EVENT_GOSSIP_HELLO: - case SMART_EVENT_JUST_CREATED: - case SMART_EVENT_FOLLOW_COPMLETE: - break; - default: - sLog.outErrorDb("SmartAIMgr: Not handled event_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); - return false; + case SMART_EVENT_LINK: + { + if (e.link && e.link == e.event_id) + { + sLog.outErrorDb("SmartAIMgr: Entry %d SourceType %u, Event %u, Link Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id); + return false; + } + break; + } + case SMART_EVENT_TIMED_EVENT_TRIGGERED: + case SMART_EVENT_INSTANCE_PLAYER_ENTER: + case SMART_EVENT_TRANSPORT_RELOCATE: + case SMART_EVENT_CHARMED: + case SMART_EVENT_CHARMED_TARGET: + case SMART_EVENT_CORPSE_REMOVED: + case SMART_EVENT_AI_INIT: + case SMART_EVENT_TRANSPORT_ADDPLAYER: + case SMART_EVENT_TRANSPORT_REMOVE_PLAYER: + case SMART_EVENT_AGGRO: + case SMART_EVENT_DEATH: + case SMART_EVENT_EVADE: + case SMART_EVENT_REACHED_HOME: + case SMART_EVENT_RESET: + case SMART_EVENT_QUEST_ACCEPTED: + case SMART_EVENT_QUEST_OBJ_COPLETETION: + case SMART_EVENT_QUEST_COMPLETION: + case SMART_EVENT_QUEST_REWARDED: + case SMART_EVENT_QUEST_FAIL: + case SMART_EVENT_JUST_SUMMONED: + case SMART_EVENT_WAYPOINT_START: + case SMART_EVENT_WAYPOINT_REACHED: + case SMART_EVENT_WAYPOINT_PAUSED: + case SMART_EVENT_WAYPOINT_RESUMED: + case SMART_EVENT_WAYPOINT_STOPPED: + case SMART_EVENT_WAYPOINT_ENDED: + case SMART_ACTION_PLAYMOVIE: + case SMART_EVENT_GOSSIP_SELECT: + case SMART_EVENT_GOSSIP_HELLO: + case SMART_EVENT_JUST_CREATED: + case SMART_EVENT_FOLLOW_COPMLETE: + break; + default: + sLog.outErrorDb("SmartAIMgr: Not handled event_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); + return false; + } } + switch (e.GetActionType()) { case SMART_ACTION_TALK: @@ -735,6 +748,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder e) case SMART_ACTION_CALL_SCRIPT_RESET: case SMART_ACTION_ENTER_VEHICLE: case SMART_ACTION_NONE: + case SMART_ACTION_CALL_TIMED_ACTIONLIST: + case SMART_ACTION_SET_NPC_FLAG: + case SMART_ACTION_ADD_NPC_FLAG: + case SMART_ACTION_REMOVE_NPC_FLAG: break; default: sLog.outErrorDb("SmartAIMgr: Not handled action_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index b4655783f73..b70c65c1e04 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -345,7 +345,7 @@ enum SMART_SCRIPT_RESPAWN_CONDITION enum SMART_ACTION { SMART_ACTION_NONE = 0, // No action - SMART_ACTION_TALK = 1, // groupID from creature_text + SMART_ACTION_TALK = 1, // groupID from creature_text, duration to wait before TEXT_OVER event is triggered SMART_ACTION_SET_FACTION = 2, // FactionId (or 0 for default) SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL = 3, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph) SMART_ACTION_SOUND = 4, // SoundId, TextRange @@ -426,7 +426,12 @@ enum SMART_ACTION SMART_ACTION_RESET_SCRIPT_BASE_OBJECT = 77, // none SMART_ACTION_CALL_SCRIPT_RESET = 78, // none SMART_ACTION_ENTER_VEHICLE = 79, // seatID - SMART_ACTION_END = 80, + SMART_ACTION_CALL_TIMED_ACTIONLIST = 80, // ID (overwrites already running actionlist), stop after combat?(0/1), timer update type(0-OOC, 1-IC, 2-ALWAYS) + SMART_ACTION_SET_NPC_FLAG = 81, // Flags + SMART_ACTION_ADD_NPC_FLAG = 82, // Flags + SMART_ACTION_REMOVE_NPC_FLAG = 83, // Flags + + SMART_ACTION_END = 84, }; struct SmartAction @@ -766,6 +771,13 @@ struct SmartAction { uint32 seat; } enterVehicle; + + struct + { + uint32 id; + uint32 dontResume; + uint32 timerType; + } timedActionList; struct { @@ -927,7 +939,8 @@ enum SmartScriptType SMART_SCRIPT_TYPE_SPELL = 6,// SMART_SCRIPT_TYPE_TRANSPORT = 7,// SMART_SCRIPT_TYPE_INSTANCE = 8,// - SMART_SCRIPT_TYPE_MAX = 9 + SMART_SCRIPT_TYPE_TIMED_ACTIONLIST = 9,// + SMART_SCRIPT_TYPE_MAX = 10 }; enum SmartAITypeMaskId @@ -941,24 +954,26 @@ enum SmartAITypeMaskId SMART_SCRIPT_TYPE_MASK_SPELL = 64, SMART_SCRIPT_TYPE_MASK_TRANSPORT = 128, SMART_SCRIPT_TYPE_MASK_INSTANCE = 256, + SMART_SCRIPT_TYPE_MASK_TIMED_ACTIONLIST = 512, }; const uint32 SmartAITypeMask[SMART_SCRIPT_TYPE_MAX][2] = { - {SMART_SCRIPT_TYPE_CREATURE, SMART_SCRIPT_TYPE_MASK_CREATURE }, - {SMART_SCRIPT_TYPE_GAMEOBJECT, SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, - {SMART_SCRIPT_TYPE_AREATRIGGER, SMART_SCRIPT_TYPE_MASK_AREATRIGGER }, - {SMART_SCRIPT_TYPE_EVENT, SMART_SCRIPT_TYPE_MASK_EVENT }, - {SMART_SCRIPT_TYPE_GOSSIP, SMART_SCRIPT_TYPE_MASK_GOSSIP }, - {SMART_SCRIPT_TYPE_QUEST, SMART_SCRIPT_TYPE_MASK_QUEST }, - {SMART_SCRIPT_TYPE_SPELL, SMART_SCRIPT_TYPE_MASK_SPELL }, - {SMART_SCRIPT_TYPE_TRANSPORT, SMART_SCRIPT_TYPE_MASK_TRANSPORT }, - {SMART_SCRIPT_TYPE_INSTANCE, SMART_SCRIPT_TYPE_MASK_INSTANCE } + {SMART_SCRIPT_TYPE_CREATURE, SMART_SCRIPT_TYPE_MASK_CREATURE }, + {SMART_SCRIPT_TYPE_GAMEOBJECT, SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, + {SMART_SCRIPT_TYPE_AREATRIGGER, SMART_SCRIPT_TYPE_MASK_AREATRIGGER }, + {SMART_SCRIPT_TYPE_EVENT, SMART_SCRIPT_TYPE_MASK_EVENT }, + {SMART_SCRIPT_TYPE_GOSSIP, SMART_SCRIPT_TYPE_MASK_GOSSIP }, + {SMART_SCRIPT_TYPE_QUEST, SMART_SCRIPT_TYPE_MASK_QUEST }, + {SMART_SCRIPT_TYPE_SPELL, SMART_SCRIPT_TYPE_MASK_SPELL }, + {SMART_SCRIPT_TYPE_TRANSPORT, SMART_SCRIPT_TYPE_MASK_TRANSPORT }, + {SMART_SCRIPT_TYPE_INSTANCE, SMART_SCRIPT_TYPE_MASK_INSTANCE }, + {SMART_SCRIPT_TYPE_TIMED_ACTIONLIST, SMART_SCRIPT_TYPE_MASK_TIMED_ACTIONLIST } }; const uint32 SmartAIEventMask[SMART_EVENT_END][2] = { - {SMART_EVENT_UPDATE_IC, SMART_SCRIPT_TYPE_MASK_CREATURE }, + {SMART_EVENT_UPDATE_IC, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_TIMED_ACTIONLIST}, {SMART_EVENT_UPDATE_OOC, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT + SMART_SCRIPT_TYPE_MASK_INSTANCE }, {SMART_EVENT_HEALT_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_MANA_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE }, @@ -1062,6 +1077,7 @@ struct SmartScriptHolder entryOrGuid = 0; link = 0; event_id = 0; + enableTimed = false; } int32 entryOrGuid; SmartScriptType source_type; @@ -1081,7 +1097,7 @@ struct SmartScriptHolder uint32 timer; bool active; bool runOnce; - + bool enableTimed; }; @@ -1133,7 +1149,7 @@ class SmartAIMgr else { if(entry > 0)//first search is for guid (negative), do not drop error if not found - sLog.outError("SmartAIMgr::GetScript: Could not load Script for Entry %d AIType %u.", entry, uint32(type)); + sLog.outError("SmartAIMgr::GetScript: Could not load Script for Entry %d ScriptType %u.", entry, uint32(type)); return temp; } } @@ -1142,7 +1158,7 @@ class SmartAIMgr //event stores SmartAIEventMap mEventMap[SMART_SCRIPT_TYPE_MAX]; - bool IsEventValid(SmartScriptHolder e); + bool IsEventValid(SmartScriptHolder &e); bool IsTargetValid(SmartScriptHolder e); /*inline bool IsTargetValid(SmartScriptHolder e, int32 target) { |