aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp107
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp313
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h48
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)
{