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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,9 +1830,24 @@ 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)
|
||||
|
||||
@@ -193,6 +193,8 @@ class SmartScript
|
||||
|
||||
SmartAIEventList mEvents;
|
||||
SmartAIEventList mInstallEvents;
|
||||
SmartAIEventList mTimedActionList;
|
||||
bool mResumeActionList;
|
||||
Creature* me;
|
||||
uint64 meOrigGUID;
|
||||
GameObject* go;
|
||||
|
||||
@@ -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,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);
|
||||
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)
|
||||
{
|
||||
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());
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
@@ -767,6 +772,13 @@ struct SmartAction
|
||||
uint32 seat;
|
||||
} enterVehicle;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 id;
|
||||
uint32 dontResume;
|
||||
uint32 timerType;
|
||||
} timedActionList;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 param1;
|
||||
@@ -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,6 +954,7 @@ 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] =
|
||||
@@ -953,12 +967,13 @@ const uint32 SmartAITypeMask[SMART_SCRIPT_TYPE_MAX][2] =
|
||||
{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_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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user