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
This commit is contained in:
Rat
2010-11-03 14:10:16 +01:00
parent afb3e790de
commit 9df4af80f4
5 changed files with 324 additions and 185 deletions
@@ -571,6 +571,7 @@ void SmartAI::JustReachedHome()
void SmartAI::EnterCombat(Unit* enemy) void SmartAI::EnterCombat(Unit* enemy)
{ {
me->InterruptNonMeleeSpells(false);//msut be before ProcessEvents
GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy); GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy);
me->GetPosition(&mLastOOCPos); me->GetPosition(&mLastOOCPos);
} }
+105 -2
View File
@@ -51,6 +51,7 @@ SmartScript::SmartScript()
mTemplate = SMARTAI_TEMPLATE_BASIC; mTemplate = SMARTAI_TEMPLATE_BASIC;
meOrigGUID = 0; meOrigGUID = 0;
goOrigGUID = 0; goOrigGUID = 0;
mResumeActionList = true;
} }
void SmartScript::OnReset() void SmartScript::OnReset()
@@ -59,8 +60,7 @@ void SmartScript::OnReset()
ResetBaseObject(); ResetBaseObject();
for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i) for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
{ {
if ((*i).GetEventType() == SMART_EVENT_UPDATE_OOC || (*i).GetEventType() == SMART_EVENT_UPDATE) InitTimer((*i));
RecalcTimer((*i), (*i).event.minMaxRepeat.min, (*i).event.minMaxRepeat.max);
(*i).runOnce = false; (*i).runOnce = false;
} }
ProcessEventsFor(SMART_EVENT_RESET); 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) 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) for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
{ {
if ((*i).GetEventType() == SMART_EVENT_LINK)//special handling if ((*i).GetEventType() == SMART_EVENT_LINK)//special handling
continue; 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)*/) 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); ProcessEvent(*i, unit, var0, var1, bvar, spell, gob);
} }
@@ -989,6 +1006,57 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u
} }
break; 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: default:
sLog.outErrorDb("SmartScript::ProcessAction: Unhandled Action type %u", e.GetActionType()); sLog.outErrorDb("SmartScript::ProcessAction: Unhandled Action type %u", e.GetActionType());
break; break;
@@ -1738,6 +1806,11 @@ void SmartScript::UpdateTimer(SmartScriptHolder &e, const uint32 diff)
return; return;
if (e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask)) if (e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask))
return; 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) if (e.timer < diff)
{ {
e.active = true;//activate events with cooldown e.active = true;//activate events with cooldown
@@ -1757,9 +1830,24 @@ void SmartScript::UpdateTimer(SmartScriptHolder &e, const uint32 diff)
case SMART_EVENT_FRIENDLY_MISSING_BUFF: case SMART_EVENT_FRIENDLY_MISSING_BUFF:
case SMART_EVENT_HAS_AURA: case SMART_EVENT_HAS_AURA:
case SMART_EVENT_TARGET_BUFFED: case SMART_EVENT_TARGET_BUFFED:
{
ProcessEvent(e); 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;
} }
}
}
break;
}
}
} else e.timer -= diff; } else e.timer -= diff;
} }
@@ -1796,6 +1884,21 @@ void SmartScript::OnUpdate(const uint32 diff)
UpdateTimer((*i), 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()) if (!mRemIDs.empty())
{ {
for (std::list<uint32>::iterator i = mRemIDs.begin(); i != mRemIDs.end(); ++i) for (std::list<uint32>::iterator i = mRemIDs.begin(); i != mRemIDs.end(); ++i)
@@ -193,6 +193,8 @@ class SmartScript
SmartAIEventList mEvents; SmartAIEventList mEvents;
SmartAIEventList mInstallEvents; SmartAIEventList mInstallEvents;
SmartAIEventList mTimedActionList;
bool mResumeActionList;
Creature* me; Creature* me;
uint64 meOrigGUID; uint64 meOrigGUID;
GameObject* go; GameObject* go;
@@ -159,6 +159,8 @@ void SmartAIMgr::LoadSmartAIFromDB()
} }
break; break;
} }
case SMART_SCRIPT_TYPE_TIMED_ACTIONLIST:
break;//nothing to check, really
default: default:
sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type %u", (uint32)source_type); sLog.outErrorDb("SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type %u", (uint32)source_type);
continue; continue;
@@ -284,14 +286,15 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder e)
return true; return true;
} }
bool SmartAIMgr::IsEventValid(SmartScriptHolder e) bool SmartAIMgr::IsEventValid(SmartScriptHolder &e)
{ {
if (e.event.type >= SMART_EVENT_END) 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()); sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid event type (%u), skipped.", e.entryOrGuid, e.event_id, e.GetEventType());
return false; 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()); sLog.outErrorDb("SmartAIMgr: EntryOrGuid %d, event type %u can not be used for Script type %u", e.entryOrGuid, e.GetEventType(), e.GetScriptType());
return false; return false;
@@ -306,6 +309,14 @@ 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); 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; return false;
} }
if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST)
{
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) switch (e.event.type)
{ {
case SMART_EVENT_UPDATE: case SMART_EVENT_UPDATE:
@@ -473,6 +484,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder e)
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()); 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; return false;
} }
}
switch (e.GetActionType()) switch (e.GetActionType())
{ {
case SMART_ACTION_TALK: case SMART_ACTION_TALK:
@@ -735,6 +748,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder e)
case SMART_ACTION_CALL_SCRIPT_RESET: case SMART_ACTION_CALL_SCRIPT_RESET:
case SMART_ACTION_ENTER_VEHICLE: case SMART_ACTION_ENTER_VEHICLE:
case SMART_ACTION_NONE: 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; break;
default: 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); 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);
@@ -345,7 +345,7 @@ enum SMART_SCRIPT_RESPAWN_CONDITION
enum SMART_ACTION enum SMART_ACTION
{ {
SMART_ACTION_NONE = 0, // No 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_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_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 SMART_ACTION_SOUND = 4, // SoundId, TextRange
@@ -426,7 +426,12 @@ enum SMART_ACTION
SMART_ACTION_RESET_SCRIPT_BASE_OBJECT = 77, // none SMART_ACTION_RESET_SCRIPT_BASE_OBJECT = 77, // none
SMART_ACTION_CALL_SCRIPT_RESET = 78, // none SMART_ACTION_CALL_SCRIPT_RESET = 78, // none
SMART_ACTION_ENTER_VEHICLE = 79, // seatID 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 struct SmartAction
@@ -767,6 +772,13 @@ struct SmartAction
uint32 seat; uint32 seat;
} enterVehicle; } enterVehicle;
struct
{
uint32 id;
uint32 dontResume;
uint32 timerType;
} timedActionList;
struct struct
{ {
uint32 param1; uint32 param1;
@@ -927,7 +939,8 @@ enum SmartScriptType
SMART_SCRIPT_TYPE_SPELL = 6,// SMART_SCRIPT_TYPE_SPELL = 6,//
SMART_SCRIPT_TYPE_TRANSPORT = 7,// SMART_SCRIPT_TYPE_TRANSPORT = 7,//
SMART_SCRIPT_TYPE_INSTANCE = 8,// SMART_SCRIPT_TYPE_INSTANCE = 8,//
SMART_SCRIPT_TYPE_MAX = 9 SMART_SCRIPT_TYPE_TIMED_ACTIONLIST = 9,//
SMART_SCRIPT_TYPE_MAX = 10
}; };
enum SmartAITypeMaskId enum SmartAITypeMaskId
@@ -941,6 +954,7 @@ enum SmartAITypeMaskId
SMART_SCRIPT_TYPE_MASK_SPELL = 64, SMART_SCRIPT_TYPE_MASK_SPELL = 64,
SMART_SCRIPT_TYPE_MASK_TRANSPORT = 128, SMART_SCRIPT_TYPE_MASK_TRANSPORT = 128,
SMART_SCRIPT_TYPE_MASK_INSTANCE = 256, SMART_SCRIPT_TYPE_MASK_INSTANCE = 256,
SMART_SCRIPT_TYPE_MASK_TIMED_ACTIONLIST = 512,
}; };
const uint32 SmartAITypeMask[SMART_SCRIPT_TYPE_MAX][2] = const uint32 SmartAITypeMask[SMART_SCRIPT_TYPE_MAX][2] =
@@ -953,12 +967,13 @@ const uint32 SmartAITypeMask[SMART_SCRIPT_TYPE_MAX][2] =
{SMART_SCRIPT_TYPE_QUEST, SMART_SCRIPT_TYPE_MASK_QUEST }, {SMART_SCRIPT_TYPE_QUEST, SMART_SCRIPT_TYPE_MASK_QUEST },
{SMART_SCRIPT_TYPE_SPELL, SMART_SCRIPT_TYPE_MASK_SPELL }, {SMART_SCRIPT_TYPE_SPELL, SMART_SCRIPT_TYPE_MASK_SPELL },
{SMART_SCRIPT_TYPE_TRANSPORT, SMART_SCRIPT_TYPE_MASK_TRANSPORT }, {SMART_SCRIPT_TYPE_TRANSPORT, SMART_SCRIPT_TYPE_MASK_TRANSPORT },
{SMART_SCRIPT_TYPE_INSTANCE, SMART_SCRIPT_TYPE_MASK_INSTANCE } {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] = 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_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_HEALT_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_MANA_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_MANA_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE },
@@ -1062,6 +1077,7 @@ struct SmartScriptHolder
entryOrGuid = 0; entryOrGuid = 0;
link = 0; link = 0;
event_id = 0; event_id = 0;
enableTimed = false;
} }
int32 entryOrGuid; int32 entryOrGuid;
SmartScriptType source_type; SmartScriptType source_type;
@@ -1081,7 +1097,7 @@ struct SmartScriptHolder
uint32 timer; uint32 timer;
bool active; bool active;
bool runOnce; bool runOnce;
bool enableTimed;
}; };
@@ -1133,7 +1149,7 @@ class SmartAIMgr
else else
{ {
if(entry > 0)//first search is for guid (negative), do not drop error if not found 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; return temp;
} }
} }
@@ -1142,7 +1158,7 @@ class SmartAIMgr
//event stores //event stores
SmartAIEventMap mEventMap[SMART_SCRIPT_TYPE_MAX]; SmartAIEventMap mEventMap[SMART_SCRIPT_TYPE_MAX];
bool IsEventValid(SmartScriptHolder e); bool IsEventValid(SmartScriptHolder &e);
bool IsTargetValid(SmartScriptHolder e); bool IsTargetValid(SmartScriptHolder e);
/*inline bool IsTargetValid(SmartScriptHolder e, int32 target) /*inline bool IsTargetValid(SmartScriptHolder e, int32 target)
{ {