a3dc7b3f48
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
2803 lines
113 KiB
C#
2803 lines
113 KiB
C#
/*
|
|
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
using Framework.Constants;
|
|
using Framework.Database;
|
|
using Game.DataStorage;
|
|
using Game.Entities;
|
|
using Game.Spells;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Game.AI
|
|
{
|
|
public class SmartAIManager : Singleton<SmartAIManager>
|
|
{
|
|
SmartAIManager()
|
|
{
|
|
for (byte i = 0; i < (int)SmartScriptType.Max; i++)
|
|
mEventMap[i] = new MultiMap<int, SmartScriptHolder>();
|
|
}
|
|
|
|
public void LoadFromDB()
|
|
{
|
|
uint oldMSTime = Time.GetMSTime();
|
|
|
|
for (byte i = 0; i < (int)SmartScriptType.Max; i++)
|
|
mEventMap[i].Clear(); //Drop Existing SmartAI List
|
|
|
|
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_SMART_SCRIPTS);
|
|
SQLResult result = DB.World.Query(stmt);
|
|
if (result.IsEmpty())
|
|
{
|
|
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 SmartAI scripts. DB table `smartai_scripts` is empty.");
|
|
return;
|
|
}
|
|
|
|
int count = 0;
|
|
do
|
|
{
|
|
SmartScriptHolder temp = new SmartScriptHolder();
|
|
|
|
temp.entryOrGuid = result.Read<int>(0);
|
|
SmartScriptType source_type = (SmartScriptType)result.Read<byte>(1);
|
|
if (source_type >= SmartScriptType.Max)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAI: invalid source_type ({0}), skipped loading.", source_type);
|
|
continue;
|
|
}
|
|
if (temp.entryOrGuid >= 0)
|
|
{
|
|
switch (source_type)
|
|
{
|
|
case SmartScriptType.Creature:
|
|
if (Global.ObjectMgr.GetCreatureTemplate((uint)temp.entryOrGuid) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAI: Creature entry ({0}) does not exist, skipped loading.", temp.entryOrGuid);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case SmartScriptType.GameObject:
|
|
{
|
|
if (Global.ObjectMgr.GetGameObjectTemplate((uint)temp.entryOrGuid) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAI: GameObject entry ({0}) does not exist, skipped loading.", temp.entryOrGuid);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case SmartScriptType.AreaTrigger:
|
|
{
|
|
if (CliDB.AreaTableStorage.LookupByKey((uint)temp.entryOrGuid) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAI: AreaTrigger entry ({0}) does not exist, skipped loading.", temp.entryOrGuid);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case SmartScriptType.Scene:
|
|
{
|
|
if (Global.ObjectMgr.GetSceneTemplate((uint)temp.entryOrGuid) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAIFromDB: Scene id ({0}) does not exist, skipped loading.", temp.entryOrGuid);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case SmartScriptType.Spell:
|
|
{
|
|
if (!Global.SpellMgr.HasSpellInfo((uint)temp.entryOrGuid))
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAIFromDB: Scene id ({0}) does not exist, skipped loading.", temp.entryOrGuid);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case SmartScriptType.TimedActionlist:
|
|
break;//nothing to check, really
|
|
default:
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAIFromDB: not yet implemented source_type {0}", source_type);
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Global.ObjectMgr.GetCreatureData((uint)Math.Abs(temp.entryOrGuid)) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAI: Creature guid ({0}) does not exist, skipped loading.", Math.Abs(temp.entryOrGuid));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
temp.source_type = source_type;
|
|
temp.event_id = result.Read<ushort>(2);
|
|
temp.link = result.Read<ushort>(3);
|
|
temp.Event.type = (SmartEvents)result.Read<byte>(4);
|
|
temp.Event.event_phase_mask = result.Read<byte>(5);
|
|
temp.Event.event_chance = result.Read<byte>(6);
|
|
temp.Event.event_flags = (SmartEventFlags)result.Read<ushort>(7);
|
|
|
|
temp.Event.raw.param1 = result.Read<uint>(8);
|
|
temp.Event.raw.param2 = result.Read<uint>(9);
|
|
temp.Event.raw.param3 = result.Read<uint>(10);
|
|
temp.Event.raw.param4 = result.Read<uint>(11);
|
|
temp.Event.param_string = result.Read<string>(12);
|
|
|
|
temp.Action.type = (SmartActions)result.Read<byte>(13);
|
|
temp.Action.raw.param1 = result.Read<uint>(14);
|
|
temp.Action.raw.param2 = result.Read<uint>(15);
|
|
temp.Action.raw.param3 = result.Read<uint>(16);
|
|
temp.Action.raw.param4 = result.Read<uint>(17);
|
|
temp.Action.raw.param5 = result.Read<uint>(18);
|
|
temp.Action.raw.param6 = result.Read<uint>(19);
|
|
|
|
temp.Target.type = (SmartTargets)result.Read<byte>(20);
|
|
temp.Target.raw.param1 = result.Read<uint>(21);
|
|
temp.Target.raw.param2 = result.Read<uint>(22);
|
|
temp.Target.raw.param3 = result.Read<uint>(23);
|
|
temp.Target.x = result.Read<float>(24);
|
|
temp.Target.y = result.Read<float>(25);
|
|
temp.Target.z = result.Read<float>(26);
|
|
temp.Target.o = result.Read<float>(27);
|
|
|
|
//check target
|
|
if (!IsTargetValid(temp))
|
|
continue;
|
|
|
|
// check all event and action params
|
|
if (!IsEventValid(temp))
|
|
continue;
|
|
|
|
// creature entry / guid not found in storage, create empty event list for it and increase counters
|
|
if (!mEventMap[(int)source_type].ContainsKey(temp.entryOrGuid))
|
|
++count;
|
|
|
|
// store the new event
|
|
mEventMap[(int)source_type].Add(temp.entryOrGuid, temp);
|
|
}
|
|
while (result.NextRow());
|
|
|
|
// Post Loading Validation
|
|
for (byte i = 0; i < (int)SmartScriptType.Max; ++i)
|
|
{
|
|
if (mEventMap[i] == null)
|
|
continue;
|
|
|
|
foreach (var key in mEventMap[i].Keys)
|
|
{
|
|
var list = mEventMap[i].LookupByKey(key);
|
|
foreach (var e in list)
|
|
{
|
|
if (e.link != 0)
|
|
{
|
|
if (FindLinkedEvent(list, e.link) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadFromDB: Entry {0} SourceType {1}, Event {2}, Link Event {3} not found or invalid.",
|
|
e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
|
|
}
|
|
}
|
|
|
|
if (e.GetEventType() == SmartEvents.Link)
|
|
{
|
|
if (FindLinkedSourceEvent(list, e.event_id) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr.LoadFromDB: Entry {0} SourceType {1}, Event {2}, Link Source Event not found or invalid. Event will never trigger.",
|
|
e.entryOrGuid, e.GetScriptType(), e.event_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} SmartAI scripts in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
|
}
|
|
public void LoadWaypointFromDB()
|
|
{
|
|
uint oldMSTime = Time.GetMSTime();
|
|
|
|
waypoint_map.Clear();
|
|
|
|
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_SMARTAI_WP);
|
|
SQLResult result = DB.World.Query(stmt);
|
|
|
|
if (result.IsEmpty())
|
|
{
|
|
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 SmartAI Waypoint Paths. DB table `waypoints` is empty.");
|
|
|
|
return;
|
|
}
|
|
|
|
uint count = 0;
|
|
uint total = 0;
|
|
uint last_entry = 0;
|
|
uint last_id = 1;
|
|
|
|
do
|
|
{
|
|
uint entry = result.Read<uint>(0);
|
|
uint id = result.Read<uint>(1);
|
|
float x, y, z;
|
|
x = result.Read<float>(2);
|
|
y = result.Read<float>(3);
|
|
z = result.Read<float>(4);
|
|
|
|
if (last_entry != entry)
|
|
{
|
|
waypoint_map[entry] = new Dictionary<uint, SmartPath>();
|
|
last_id = 1;
|
|
count++;
|
|
}
|
|
|
|
if (last_id != id)
|
|
Log.outError(LogFilter.Sql, "SmartWaypointMgr.LoadFromDB: Path entry {0}, unexpected point id {1}, expected {2}.", entry, id, last_id);
|
|
|
|
last_id++;
|
|
waypoint_map[entry][id] = new SmartPath(id, x, y, z);
|
|
|
|
last_entry = entry;
|
|
total++;
|
|
}
|
|
while (result.NextRow());
|
|
|
|
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} SmartAI waypoint paths (total {1} waypoints) in {2} ms", count, total, Time.GetMSTimeDiffToNow(oldMSTime));
|
|
}
|
|
|
|
bool IsTargetValid(SmartScriptHolder e)
|
|
{
|
|
if (Math.Abs(e.Target.o) > 2 * MathFunctions.PI)
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} has abs(`target.o` = {4}) > 2*PI (orientation is expressed in radians)",
|
|
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Target.o);
|
|
|
|
if (e.GetActionType() == SmartActions.InstallAiTemplate)
|
|
return true; // AI template has special handling
|
|
|
|
switch (e.GetTargetType())
|
|
{
|
|
case SmartTargets.CreatureDistance:
|
|
case SmartTargets.CreatureRange:
|
|
{
|
|
if (e.Target.unitDistance.creature != 0 && Global.ObjectMgr.GetCreatureTemplate(e.Target.unitDistance.creature) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Creature entry {4} as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Target.unitDistance.creature);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartTargets.GameobjectDistance:
|
|
case SmartTargets.GameobjectRange:
|
|
{
|
|
if (e.Target.goDistance.entry != 0 && Global.ObjectMgr.GetGameObjectTemplate(e.Target.goDistance.entry) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent GameObject entry {4} as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Target.goDistance.entry);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartTargets.CreatureGuid:
|
|
{
|
|
if (e.Target.unitGUID.entry != 0 && !IsCreatureValid(e, e.Target.unitGUID.entry))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartTargets.GameobjectGuid:
|
|
{
|
|
if (e.Target.goGUID.entry != 0 && !IsGameObjectValid(e, e.Target.goGUID.entry))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartTargets.PlayerDistance:
|
|
case SmartTargets.ClosestPlayer:
|
|
{
|
|
if (e.Target.playerDistance.dist == 0)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} has maxDist 0 as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartTargets.PlayerRange:
|
|
case SmartTargets.Self:
|
|
case SmartTargets.Victim:
|
|
case SmartTargets.HostileSecondAggro:
|
|
case SmartTargets.HostileLastAggro:
|
|
case SmartTargets.HostileRandom:
|
|
case SmartTargets.HostileRandomNotTop:
|
|
case SmartTargets.ActionInvoker:
|
|
case SmartTargets.InvokerParty:
|
|
case SmartTargets.Position:
|
|
case SmartTargets.None:
|
|
case SmartTargets.ActionInvokerVehicle:
|
|
case SmartTargets.OwnerOrSummoner:
|
|
case SmartTargets.ThreatList:
|
|
case SmartTargets.ClosestGameobject:
|
|
case SmartTargets.ClosestCreature:
|
|
case SmartTargets.ClosestEnemy:
|
|
case SmartTargets.ClosestFriendly:
|
|
case SmartTargets.Stored:
|
|
case SmartTargets.LootRecipients:
|
|
case SmartTargets.VehicleAccessory:
|
|
case SmartTargets.SpellTarget:
|
|
break;
|
|
default:
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Not handled target_type({0}), Entry {1} SourceType {2} Event {3} Action {4}, skipped.", e.GetTargetType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool IsEventValid(SmartScriptHolder e)
|
|
{
|
|
if (e.Event.type >= SmartEvents.End)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: EntryOrGuid {0} using event({1}) has invalid event type ({2}), skipped.", e.entryOrGuid, e.event_id, e.GetEventType());
|
|
return false;
|
|
}
|
|
|
|
// in SMART_SCRIPT_TYPE_TIMED_ACTIONLIST all event types are overriden by core
|
|
if (e.GetScriptType() != SmartScriptType.TimedActionlist && !Convert.ToBoolean(SmartAIEventMask[e.Event.type] & SmartAITypeMask[e.GetScriptType()]))
|
|
{
|
|
Log.outError(LogFilter.Scripts, "SmartAIMgr: EntryOrGuid {0}, event type {1} can not be used for Script type {2}", e.entryOrGuid, e.GetEventType(), e.GetScriptType());
|
|
return false;
|
|
}
|
|
if (e.Action.type <= 0 || e.Action.type >= SmartActions.End)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: EntryOrGuid {0} using event({1}) has invalid action type ({2}), skipped.", e.entryOrGuid, e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
if (e.Event.event_phase_mask > (uint)SmartPhase.All)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: EntryOrGuid {0} using event({1}) has invalid phase mask ({2}), skipped.", e.entryOrGuid, e.event_id, e.Event.event_phase_mask);
|
|
return false;
|
|
}
|
|
if (e.Event.event_flags > SmartEventFlags.All)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: EntryOrGuid {0} using event({1}) has invalid event flags ({2}), skipped.", e.entryOrGuid, e.event_id, e.Event.event_flags);
|
|
return false;
|
|
}
|
|
if (e.link != 0 && e.link == e.event_id)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: EntryOrGuid {0} SourceType {1}, Event {2}, Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id);
|
|
return false;
|
|
}
|
|
if (e.GetScriptType() == SmartScriptType.TimedActionlist)
|
|
{
|
|
e.Event.type = SmartEvents.UpdateOoc;//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 SmartEvents.Update:
|
|
case SmartEvents.UpdateIc:
|
|
case SmartEvents.UpdateOoc:
|
|
case SmartEvents.HealtPct:
|
|
case SmartEvents.ManaPct:
|
|
case SmartEvents.TargetHealthPct:
|
|
case SmartEvents.TargetManaPct:
|
|
case SmartEvents.Range:
|
|
case SmartEvents.Damaged:
|
|
case SmartEvents.DamagedTarget:
|
|
case SmartEvents.ReceiveHeal:
|
|
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 SmartEvents.SpellHit:
|
|
case SmartEvents.SpellhitTarget:
|
|
if (e.Event.spellHit.spell != 0)
|
|
{
|
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(e.Event.spellHit.spell);
|
|
if (spellInfo == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Spell entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Event.spellHit.spell);
|
|
return false;
|
|
}
|
|
if (e.Event.spellHit.school != 0 && ((SpellSchoolMask)e.Event.spellHit.school & spellInfo.SchoolMask) != spellInfo.SchoolMask)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses Spell entry {4} with invalid school mask, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Event.spellHit.spell);
|
|
return false;
|
|
}
|
|
}
|
|
if (!IsMinMaxValid(e, e.Event.spellHit.cooldownMin, e.Event.spellHit.cooldownMax))
|
|
return false;
|
|
break;
|
|
case SmartEvents.OocLos:
|
|
case SmartEvents.IcLos:
|
|
if (!IsMinMaxValid(e, e.Event.los.cooldownMin, e.Event.los.cooldownMax))
|
|
return false;
|
|
break;
|
|
case SmartEvents.Respawn:
|
|
if (e.Event.respawn.type == (uint)SmartRespawnCondition.Map && CliDB.MapStorage.LookupByKey(e.Event.respawn.map) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Map entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Event.respawn.map);
|
|
return false;
|
|
}
|
|
if (e.Event.respawn.type == (uint)SmartRespawnCondition.Area && !CliDB.AreaTableStorage.ContainsKey(e.Event.respawn.area))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Area entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Event.respawn.area);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartEvents.FriendlyHealth:
|
|
if (!NotNULL(e, e.Event.friendlyHealth.radius))
|
|
return false;
|
|
|
|
if (!IsMinMaxValid(e, e.Event.friendlyHealth.repeatMin, e.Event.friendlyHealth.repeatMax))
|
|
return false;
|
|
break;
|
|
case SmartEvents.FriendlyIsCc:
|
|
if (!IsMinMaxValid(e, e.Event.friendlyCC.repeatMin, e.Event.friendlyCC.repeatMax))
|
|
return false;
|
|
break;
|
|
case SmartEvents.FriendlyMissingBuff:
|
|
{
|
|
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 SmartEvents.Kill:
|
|
if (!IsMinMaxValid(e, e.Event.kill.cooldownMin, e.Event.kill.cooldownMax))
|
|
return false;
|
|
|
|
if (e.Event.kill.creature != 0 && !IsCreatureValid(e, e.Event.kill.creature))
|
|
return false;
|
|
break;
|
|
case SmartEvents.VictimCasting:
|
|
case SmartEvents.PassengerBoarded:
|
|
case SmartEvents.PassengerRemoved:
|
|
if (!IsMinMaxValid(e, e.Event.minMax.repeatMin, e.Event.minMax.repeatMax))
|
|
return false;
|
|
break;
|
|
case SmartEvents.SummonDespawned:
|
|
case SmartEvents.SummonedUnit:
|
|
if (e.Event.summoned.creature != 0 && !IsCreatureValid(e, e.Event.summoned.creature))
|
|
return false;
|
|
|
|
if (!IsMinMaxValid(e, e.Event.summoned.cooldownMin, e.Event.summoned.cooldownMax))
|
|
return false;
|
|
break;
|
|
case SmartEvents.AcceptedQuest:
|
|
case SmartEvents.RewardQuest:
|
|
if (e.Event.quest.questId != 0 && !IsQuestValid(e, e.Event.quest.questId))
|
|
return false;
|
|
break;
|
|
case SmartEvents.ReceiveEmote:
|
|
{
|
|
if (e.Event.emote.emoteId != 0 && !IsTextEmoteValid(e, e.Event.emote.emoteId))
|
|
return false;
|
|
|
|
if (!IsMinMaxValid(e, e.Event.emote.cooldownMin, e.Event.emote.cooldownMax))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartEvents.HasAura:
|
|
case SmartEvents.TargetBuffed:
|
|
{
|
|
if (!IsSpellValid(e, e.Event.aura.spell))
|
|
return false;
|
|
|
|
if (!IsMinMaxValid(e, e.Event.aura.repeatMin, e.Event.aura.repeatMax))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartEvents.TransportAddcreature:
|
|
{
|
|
if (e.Event.transportAddCreature.creature != 0 && !IsCreatureValid(e, e.Event.transportAddCreature.creature))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartEvents.Movementinform:
|
|
{
|
|
if (e.Event.movementInform.type >= (uint)MovementGeneratorType.Max)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid Motion type {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Event.movementInform.type);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartEvents.DataSet:
|
|
{
|
|
if (!IsMinMaxValid(e, e.Event.dataSet.cooldownMin, e.Event.dataSet.cooldownMax))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartEvents.AreatriggerOntrigger:
|
|
{
|
|
if (e.Event.areatrigger.id != 0 && !IsAreaTriggerValid(e, e.Event.areatrigger.id))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartEvents.TextOver:
|
|
{
|
|
if (!IsTextValid(e, e.Event.textOver.textGroupID))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartEvents.DummyEffect:
|
|
{
|
|
if (!IsSpellValid(e, e.Event.dummy.spell))
|
|
return false;
|
|
|
|
if (e.Event.dummy.effIndex > 2)
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartEvents.IsBehindTarget:
|
|
{
|
|
if (!IsMinMaxValid(e, e.Event.behindTarget.cooldownMin, e.Event.behindTarget.cooldownMax))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartEvents.GameEventStart:
|
|
case SmartEvents.GameEventEnd:
|
|
{
|
|
var events = Global.GameEventMgr.GetEventMap();
|
|
if (e.Event.gameEvent.gameEventId >= events.Length || !events[e.Event.gameEvent.gameEventId].isValid())
|
|
return false;
|
|
|
|
break;
|
|
}
|
|
case SmartEvents.ActionDone:
|
|
{
|
|
if (e.Event.doAction.eventId > EventId.Charge)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid event id {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Event.doAction.eventId);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartEvents.FriendlyHealthPCT:
|
|
if (!IsMinMaxValid(e, e.Event.friendlyHealthPct.repeatMin, e.Event.friendlyHealthPct.repeatMax))
|
|
return false;
|
|
|
|
if (e.Event.friendlyHealthPct.maxHpPct > 100 || e.Event.friendlyHealthPct.minHpPct > 100)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} has pct value above 100, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
|
|
switch (e.GetTargetType())
|
|
{
|
|
case SmartTargets.CreatureRange:
|
|
case SmartTargets.CreatureGuid:
|
|
case SmartTargets.CreatureDistance:
|
|
case SmartTargets.ClosestCreature:
|
|
case SmartTargets.ClosestPlayer:
|
|
case SmartTargets.PlayerRange:
|
|
case SmartTargets.PlayerDistance:
|
|
break;
|
|
default:
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid target_type {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartEvents.DistanceCreature:
|
|
if (e.Event.distance.guid == 0 && e.Event.distance.entry == 0)
|
|
{
|
|
Log.outError(LogFilter.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)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE provided both an entry and guid, skipped.");
|
|
return false;
|
|
}
|
|
|
|
if (e.Event.distance.guid != 0 && Global.ObjectMgr.GetCreatureData(e.Event.distance.guid) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature guid {0}, skipped.", e.Event.distance.guid);
|
|
return false;
|
|
}
|
|
|
|
if (e.Event.distance.entry != 0 && Global.ObjectMgr.GetCreatureTemplate(e.Event.distance.entry) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature entry {0}, skipped.", e.Event.distance.entry);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartEvents.DistanceGameobject:
|
|
if (e.Event.distance.guid == 0 && e.Event.distance.entry == 0)
|
|
{
|
|
Log.outError(LogFilter.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)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT provided both an entry and guid, skipped.");
|
|
return false;
|
|
}
|
|
|
|
if (e.Event.distance.guid != 0 && Global.ObjectMgr.GetGOData(e.Event.distance.guid) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid {0}, skipped.", e.Event.distance.guid);
|
|
return false;
|
|
}
|
|
|
|
if (e.Event.distance.entry != 0 && Global.ObjectMgr.GetGameObjectTemplate(e.Event.distance.entry) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject entry {0}, skipped.", e.Event.distance.entry);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartEvents.CounterSet:
|
|
if (!IsMinMaxValid(e, e.Event.counter.cooldownMin, e.Event.counter.cooldownMax))
|
|
return false;
|
|
|
|
if (e.Event.counter.id == 0)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid counter id {0}, skipped.", e.Event.counter.id);
|
|
return false;
|
|
}
|
|
|
|
if (e.Event.counter.value == 0)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid value {0}, skipped.", e.Event.counter.value);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartEvents.Link:
|
|
case SmartEvents.GoStateChanged:
|
|
case SmartEvents.GoEventInform:
|
|
case SmartEvents.TimedEventTriggered:
|
|
case SmartEvents.InstancePlayerEnter:
|
|
case SmartEvents.TransportRelocate:
|
|
case SmartEvents.Charmed:
|
|
case SmartEvents.CharmedTarget:
|
|
case SmartEvents.CorpseRemoved:
|
|
case SmartEvents.AiInit:
|
|
case SmartEvents.TransportAddplayer:
|
|
case SmartEvents.TransportRemovePlayer:
|
|
case SmartEvents.Aggro:
|
|
case SmartEvents.Death:
|
|
case SmartEvents.Evade:
|
|
case SmartEvents.ReachedHome:
|
|
case SmartEvents.Reset:
|
|
case SmartEvents.QuestAccepted:
|
|
case SmartEvents.QuestObjCompletion:
|
|
case SmartEvents.QuestCompletion:
|
|
case SmartEvents.QuestRewarded:
|
|
case SmartEvents.QuestFail:
|
|
case SmartEvents.JustSummoned:
|
|
case SmartEvents.WaypointStart:
|
|
case SmartEvents.WaypointReached:
|
|
case SmartEvents.WaypointPaused:
|
|
case SmartEvents.WaypointResumed:
|
|
case SmartEvents.WaypointStopped:
|
|
case SmartEvents.WaypointEnded:
|
|
case SmartEvents.GossipSelect:
|
|
case SmartEvents.GossipHello:
|
|
case SmartEvents.JustCreated:
|
|
case SmartEvents.FollowCompleted:
|
|
case SmartEvents.OnSpellclick:
|
|
case SmartEvents.SceneStart:
|
|
case SmartEvents.SceneCancel:
|
|
case SmartEvents.SceneComplete:
|
|
case SmartEvents.SceneTrigger:
|
|
case SmartEvents.SpellEffectHit:
|
|
break;
|
|
default:
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Not handled event_type({0}), Entry {1} SourceType {2} Event {3} Action {4}, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
switch (e.GetActionType())
|
|
{
|
|
case SmartActions.Talk:
|
|
case SmartActions.SimpleTalk:
|
|
{
|
|
if (!IsTextValid(e, e.Action.talk.textGroupId))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartActions.SetFaction:
|
|
if (e.Action.faction.factionID != 0 && CliDB.FactionTemplateStorage.LookupByKey(e.Action.faction.factionID) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Faction {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.faction.factionID);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.MorphToEntryOrModel:
|
|
case SmartActions.MountToEntryOrModel:
|
|
if (e.Action.morphOrMount.creature != 0 || e.Action.morphOrMount.model != 0)
|
|
{
|
|
if (e.Action.morphOrMount.creature > 0 && Global.ObjectMgr.GetCreatureTemplate(e.Action.morphOrMount.creature) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Creature entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.morphOrMount.creature);
|
|
return false;
|
|
}
|
|
|
|
if (e.Action.morphOrMount.model != 0)
|
|
{
|
|
if (e.Action.morphOrMount.creature != 0)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} has ModelID set with also set CreatureId, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
else if (!CliDB.CreatureDisplayInfoStorage.ContainsKey(e.Action.morphOrMount.model))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Model id {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.morphOrMount.model);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SmartActions.Sound:
|
|
if (!IsSoundValid(e, e.Action.sound.soundId))
|
|
return false;
|
|
break;
|
|
case SmartActions.SetEmoteState:
|
|
case SmartActions.PlayEmote:
|
|
if (!IsEmoteValid(e, e.Action.emote.emoteId))
|
|
return false;
|
|
break;
|
|
case SmartActions.PlayAnimkit:
|
|
if (e.Action.animKit.animKit != 0 && !IsAnimKitValid(e, e.Action.animKit.animKit))
|
|
return false;
|
|
|
|
if (e.Action.animKit.type > 3)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid AnimKit type {4}, skipped.",
|
|
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.animKit.type);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.FailQuest:
|
|
case SmartActions.OfferQuest:
|
|
if (e.Action.quest.questId == 0 || !IsQuestValid(e, e.Action.quest.questId))
|
|
return false;
|
|
break;
|
|
case SmartActions.ActivateTaxi:
|
|
{
|
|
if (!CliDB.TaxiPathStorage.ContainsKey(e.Action.taxi.id))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid Taxi path ID {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.taxi.id);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.RandomEmote:
|
|
if (e.Action.randomEmote.emote1 != 0 && !IsEmoteValid(e, e.Action.randomEmote.emote1))
|
|
return false;
|
|
if (e.Action.randomEmote.emote2 != 0 && !IsEmoteValid(e, e.Action.randomEmote.emote2))
|
|
return false;
|
|
if (e.Action.randomEmote.emote3 != 0 && !IsEmoteValid(e, e.Action.randomEmote.emote3))
|
|
return false;
|
|
if (e.Action.randomEmote.emote4 != 0 && !IsEmoteValid(e, e.Action.randomEmote.emote4))
|
|
return false;
|
|
if (e.Action.randomEmote.emote5 != 0 && !IsEmoteValid(e, e.Action.randomEmote.emote5))
|
|
return false;
|
|
if (e.Action.randomEmote.emote6 != 0 && !IsEmoteValid(e, e.Action.randomEmote.emote6))
|
|
return false;
|
|
break;
|
|
case SmartActions.RandomSound:
|
|
if (e.Action.randomSound.sound1 != 0 && !IsSoundValid(e, e.Action.randomSound.sound1))
|
|
return false;
|
|
if (e.Action.randomSound.sound2 != 0 && !IsSoundValid(e, e.Action.randomSound.sound2))
|
|
return false;
|
|
if (e.Action.randomSound.sound3 != 0 && !IsSoundValid(e, e.Action.randomSound.sound3))
|
|
return false;
|
|
if (e.Action.randomSound.sound4 != 0 && !IsSoundValid(e, e.Action.randomSound.sound4))
|
|
return false;
|
|
if (e.Action.randomSound.sound5 != 0 && !IsSoundValid(e, e.Action.randomSound.sound5))
|
|
return false;
|
|
break;
|
|
case SmartActions.Cast:
|
|
{
|
|
if (!IsSpellValid(e, e.Action.cast.spell))
|
|
return false;
|
|
|
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(e.Action.cast.spell);
|
|
foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None))
|
|
{
|
|
if (effect != null && (effect.IsEffect(SpellEffectName.KillCredit) || effect.IsEffect(SpellEffectName.KillCredit2)))
|
|
{
|
|
if (effect.TargetA.GetTarget() == Targets.UnitCaster)
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: {4} targetA: {5} - targetB: {6}) has invalid target for this Action",
|
|
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.cast.spell, effect.TargetA.GetTarget(), effect.TargetB.GetTarget());
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.AddAura:
|
|
case SmartActions.InvokerCast:
|
|
if (!IsSpellValid(e, e.Action.cast.spell))
|
|
return false;
|
|
break;
|
|
case SmartActions.CallAreaexploredoreventhappens:
|
|
case SmartActions.CallGroupeventhappens:
|
|
Quest qid = Global.ObjectMgr.GetQuestTemplate(e.Action.quest.questId);
|
|
if (qid != null)
|
|
{
|
|
if (!qid.HasSpecialFlag(QuestSpecialFlags.ExplorationOrEvent))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} SpecialFlags for Quest entry {4} does not include FLAGS_EXPLORATION_OR_EVENT(2), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.quest.questId);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Quest entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.quest.questId);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.SetEventPhase:
|
|
if (e.Action.setEventPhase.phase >= (uint)SmartPhase.Max)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} attempts to set phase {4}. Phase mask cannot be used past phase {5}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.setEventPhase.phase, SmartPhase.Max - 1);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.IncEventPhase:
|
|
if (e.Action.incEventPhase.inc == 0 && e.Action.incEventPhase.dec == 0)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} is incrementing phase by 0, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
else if (e.Action.incEventPhase.inc > (uint)SmartPhase.Max || e.Action.incEventPhase.dec > (uint)SmartPhase.Max)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} attempts to increment phase by too large value, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.Removeaurasfromspell:
|
|
if (e.Action.removeAura.spell != 0 && !IsSpellValid(e, e.Action.removeAura.spell))
|
|
return false;
|
|
break;
|
|
case SmartActions.RandomPhase:
|
|
{
|
|
if (e.Action.randomPhase.phase1 >= (uint)SmartPhase.Max ||
|
|
e.Action.randomPhase.phase2 >= (uint)SmartPhase.Max ||
|
|
e.Action.randomPhase.phase3 >= (uint)SmartPhase.Max ||
|
|
e.Action.randomPhase.phase4 >= (uint)SmartPhase.Max ||
|
|
e.Action.randomPhase.phase5 >= (uint)SmartPhase.Max ||
|
|
e.Action.randomPhase.phase6 >= (uint)SmartPhase.Max)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
case SmartActions.RandomPhaseRange: //PhaseMin, PhaseMax
|
|
{
|
|
if (e.Action.randomPhaseRange.phaseMin >= (uint)SmartPhase.Max ||
|
|
e.Action.randomPhaseRange.phaseMax >= (uint)SmartPhase.Max)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
if (!IsMinMaxValid(e, e.Action.randomPhaseRange.phaseMin, e.Action.randomPhaseRange.phaseMax))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartActions.SummonCreature:
|
|
if (!IsCreatureValid(e, e.Action.summonCreature.creature))
|
|
return false;
|
|
|
|
if (e.Action.summonCreature.type < (uint)TempSummonType.TimedOrDeadDespawn || e.Action.summonCreature.type > (uint)TempSummonType.ManualDespawn)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses incorrect TempSummonType {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.summonCreature.type);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.CallKilledmonster:
|
|
if (!IsCreatureValid(e, e.Action.killedMonster.creature))
|
|
return false;
|
|
|
|
if (e.GetTargetType() == SmartTargets.Position)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses incorrect TargetType {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.UpdateTemplate:
|
|
if (e.Action.updateTemplate.creature != 0 && !IsCreatureValid(e, e.Action.updateTemplate.creature))
|
|
return false;
|
|
break;
|
|
case SmartActions.SetSheath:
|
|
if (e.Action.setSheath.sheath != 0 && e.Action.setSheath.sheath >= (uint)SheathState.Max)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses incorrect Sheath state {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.setSheath.sheath);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.SetReactState:
|
|
{
|
|
if (e.Action.react.state > (uint)ReactStates.Aggressive)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Creature {0} Event {1} Action {2} uses invalid React State {3}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.Action.react.state);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.SummonGo:
|
|
if (!IsGameObjectValid(e, e.Action.summonGO.entry))
|
|
return false;
|
|
break;
|
|
case SmartActions.RemoveItem:
|
|
if (!IsItemValid(e, e.Action.item.entry))
|
|
return false;
|
|
|
|
if (!NotNULL(e, e.Action.item.count))
|
|
return false;
|
|
break;
|
|
case SmartActions.AddItem:
|
|
if (!IsItemValid(e, e.Action.item.entry))
|
|
return false;
|
|
|
|
if (!NotNULL(e, e.Action.item.count))
|
|
return false;
|
|
break;
|
|
case SmartActions.Teleport:
|
|
if (!CliDB.MapStorage.ContainsKey(e.Action.teleport.mapID))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Map entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.teleport.mapID);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.SetCounter:
|
|
if (e.Action.setCounter.counterId == 0)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses wrong counterId {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.setCounter.counterId);
|
|
return false;
|
|
}
|
|
|
|
if (e.Action.setCounter.value == 0)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses wrong value {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.setCounter.value);
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
case SmartActions.InstallAiTemplate:
|
|
if (e.Action.installTtemplate.id >= (uint)SmartAITemplate.End)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Creature {0} Event {1} Action {2} uses non-existent AI template id {3}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.Action.installTtemplate.id);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.WpStop:
|
|
if (e.Action.wpStop.quest != 0 && !IsQuestValid(e, e.Action.wpStop.quest))
|
|
return false;
|
|
break;
|
|
case SmartActions.WpStart:
|
|
{
|
|
if (Global.SmartAIMgr.GetPath(e.Action.wpStart.pathID) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Creature {0} Event {1} Action {2} uses non-existent WaypointPath id {3}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.Action.wpStart.pathID);
|
|
return false;
|
|
}
|
|
if (e.Action.wpStart.quest != 0 && !IsQuestValid(e, e.Action.wpStart.quest))
|
|
return false;
|
|
if (e.Action.wpStart.reactState > (uint)ReactStates.Aggressive)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Creature {0} Event {1} Action {2} uses invalid React State {3}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.Action.wpStart.reactState);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.CreateTimedEvent:
|
|
{
|
|
if (!IsMinMaxValid(e, e.Action.timeEvent.min, e.Action.timeEvent.max))
|
|
return false;
|
|
|
|
if (!IsMinMaxValid(e, e.Action.timeEvent.repeatMin, e.Action.timeEvent.repeatMax))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartActions.CallRandomRangeTimedActionlist:
|
|
{
|
|
if (!IsMinMaxValid(e, e.Action.randTimedActionList.entry1, e.Action.randTimedActionList.entry2))
|
|
return false;
|
|
break;
|
|
}
|
|
case SmartActions.SetPower:
|
|
case SmartActions.AddPower:
|
|
case SmartActions.RemovePower:
|
|
if (e.Action.power.powerType > (int)PowerType.Max)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Power {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.power.powerType);
|
|
return false;
|
|
}
|
|
break;
|
|
case SmartActions.GameEventStop:
|
|
{
|
|
uint eventId = e.Action.gameEventStop.id;
|
|
|
|
var events = Global.GameEventMgr.GetEventMap();
|
|
if (eventId < 1 || eventId >= events.Length)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent event, eventId {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.gameEventStop.id);
|
|
return false;
|
|
}
|
|
|
|
GameEventData eventData = events[eventId];
|
|
if (!eventData.isValid())
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent event, eventId {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.gameEventStop.id);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.GameEventStart:
|
|
{
|
|
uint eventId = e.Action.gameEventStart.id;
|
|
|
|
var events = Global.GameEventMgr.GetEventMap();
|
|
if (eventId < 1 || eventId >= events.Length)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent event, eventId {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.gameEventStart.id);
|
|
return false;
|
|
}
|
|
|
|
GameEventData eventData = events[eventId];
|
|
if (!eventData.isValid())
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent event, eventId {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.gameEventStart.id);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.Equip:
|
|
{
|
|
if (e.GetScriptType() == SmartScriptType.Creature)
|
|
{
|
|
sbyte equipId = (sbyte)e.Action.equip.entry;
|
|
|
|
if (equipId != 0 && Global.ObjectMgr.GetEquipmentInfo((uint)e.entryOrGuid, equipId) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {0} for creature {1}, skipped.", equipId, e.entryOrGuid);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.SetInstData:
|
|
{
|
|
if (e.Action.setInstanceData.type > 1)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid data type {4} (value range 0-1), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.setInstanceData.type);
|
|
return false;
|
|
}
|
|
else if (e.Action.setInstanceData.type == 1)
|
|
{
|
|
if (e.Action.setInstanceData.data > (int)EncounterState.ToBeDecided)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses invalid boss state {4} (value range 0-5), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Action.setInstanceData.data);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.SetIngamePhaseId:
|
|
{
|
|
uint phaseId = e.Action.ingamePhaseId.id;
|
|
uint apply = e.Action.ingamePhaseId.apply;
|
|
|
|
if (apply != 0 && apply != 1)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid apply value {0} (Should be 0 or 1) for creature {1}, skipped", apply, e.entryOrGuid);
|
|
return false;
|
|
}
|
|
|
|
if (!CliDB.PhaseStorage.ContainsKey(phaseId))
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid phaseid {0} for creature {1}, skipped", phaseId, e.entryOrGuid);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.SetIngamePhaseGroup:
|
|
{
|
|
uint phaseGroup = e.Action.ingamePhaseGroup.groupId;
|
|
uint apply = e.Action.ingamePhaseGroup.apply;
|
|
|
|
if (apply != 0 && apply != 1)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid apply value {0} (Should be 0 or 1) for creature {1}, skipped", apply, e.entryOrGuid);
|
|
return false;
|
|
}
|
|
|
|
if (Global.DB2Mgr.GetPhasesForGroup(phaseGroup).Empty())
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id {0} for creature {1}, skipped", phaseGroup, e.entryOrGuid);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case SmartActions.ScenePlay:
|
|
{
|
|
if (Global.ObjectMgr.GetSceneTemplate(e.Action.scene.sceneId) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartScript: SMART_ACTION_SCENE_PLAY uses sceneId {0} but scene don't exist, skipped", e.Action.scene.sceneId);
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SmartActions.SceneCancel:
|
|
{
|
|
if (Global.ObjectMgr.GetSceneTemplate(e.Action.scene.sceneId) == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartScript: SMART_ACTION_SCENE_CANCEL uses sceneId {0} but scene don't exist, skipped", e.Action.scene.sceneId);
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SmartActions.Follow:
|
|
case SmartActions.SetOrientation:
|
|
case SmartActions.StoreTargetList:
|
|
case SmartActions.Evade:
|
|
case SmartActions.FleeForAssist:
|
|
case SmartActions.CombatStop:
|
|
case SmartActions.Die:
|
|
case SmartActions.SetInCombatWithZone:
|
|
case SmartActions.SetActive:
|
|
case SmartActions.WpResume:
|
|
case SmartActions.KillUnit:
|
|
case SmartActions.SetInvincibilityHpLevel:
|
|
case SmartActions.ResetGobject:
|
|
case SmartActions.AttackStart:
|
|
case SmartActions.ThreatAllPct:
|
|
case SmartActions.ThreatSinglePct:
|
|
case SmartActions.SetInstData64:
|
|
case SmartActions.AutoAttack:
|
|
case SmartActions.AllowCombatMovement:
|
|
case SmartActions.CallForHelp:
|
|
case SmartActions.SetData:
|
|
case SmartActions.SetVisibility:
|
|
case SmartActions.WpPause:
|
|
case SmartActions.SetFly:
|
|
case SmartActions.SetRun:
|
|
case SmartActions.SetSwim:
|
|
case SmartActions.ForceDespawn:
|
|
case SmartActions.SetUnitFlag:
|
|
case SmartActions.RemoveUnitFlag:
|
|
case SmartActions.Playmovie:
|
|
case SmartActions.MoveToPos:
|
|
case SmartActions.RespawnTarget:
|
|
case SmartActions.CloseGossip:
|
|
case SmartActions.TriggerTimedEvent:
|
|
case SmartActions.RemoveTimedEvent:
|
|
case SmartActions.OverrideScriptBaseObject:
|
|
case SmartActions.ResetScriptBaseObject:
|
|
case SmartActions.ActivateGobject:
|
|
case SmartActions.CallScriptReset:
|
|
case SmartActions.SetRangedMovement:
|
|
case SmartActions.CallTimedActionlist:
|
|
case SmartActions.SetNpcFlag:
|
|
case SmartActions.AddNpcFlag:
|
|
case SmartActions.RemoveNpcFlag:
|
|
case SmartActions.CrossCast:
|
|
case SmartActions.CallRandomTimedActionlist:
|
|
case SmartActions.RandomMove:
|
|
case SmartActions.SetUnitFieldBytes1:
|
|
case SmartActions.RemoveUnitFieldBytes1:
|
|
case SmartActions.InterruptSpell:
|
|
case SmartActions.SendGoCustomAnim:
|
|
case SmartActions.SetDynamicFlag:
|
|
case SmartActions.AddDynamicFlag:
|
|
case SmartActions.RemoveDynamicFlag:
|
|
case SmartActions.JumpToPos:
|
|
case SmartActions.SendGossipMenu:
|
|
case SmartActions.GoSetLootState:
|
|
case SmartActions.SendTargetToTarget:
|
|
case SmartActions.SetHomePos:
|
|
case SmartActions.SetHealthRegen:
|
|
case SmartActions.SetRoot:
|
|
case SmartActions.SetGoFlag:
|
|
case SmartActions.AddGoFlag:
|
|
case SmartActions.RemoveGoFlag:
|
|
case SmartActions.SummonCreatureGroup:
|
|
case SmartActions.MoveOffset:
|
|
case SmartActions.SetCorpseDelay:
|
|
case SmartActions.DisableEvade:
|
|
break;
|
|
default:
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Not handled action_type({0}), event_type({1}), Entry {2} SourceType {3} Event {4}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
bool IsAnimKitValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (!CliDB.AnimKitStorage.ContainsKey(entry))
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent AnimKit entry {4}, skipped.",
|
|
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsTextValid(SmartScriptHolder e, uint id)
|
|
{
|
|
if (e.GetScriptType() != SmartScriptType.Creature)
|
|
return true;
|
|
|
|
uint entry = 0;
|
|
if (e.GetEventType() == SmartEvents.TextOver)
|
|
{
|
|
entry = e.Event.textOver.creatureEntry;
|
|
}
|
|
else
|
|
{
|
|
switch (e.GetTargetType())
|
|
{
|
|
case SmartTargets.CreatureDistance:
|
|
case SmartTargets.CreatureRange:
|
|
case SmartTargets.ClosestCreature:
|
|
return true; // ignore
|
|
default:
|
|
if (e.entryOrGuid < 0)
|
|
{
|
|
ulong guid = (ulong)-e.entryOrGuid;
|
|
CreatureData data = Global.ObjectMgr.GetCreatureData(guid);
|
|
if (data == null)
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} using non-existent Creature guid {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), guid);
|
|
return false;
|
|
}
|
|
else
|
|
entry = data.id;
|
|
}
|
|
else
|
|
entry = (uint)e.entryOrGuid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (entry == 0 || !Global.CreatureTextMgr.TextExist(entry, (byte)id))
|
|
{
|
|
Log.outError(LogFilter.Sql, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} using non-existent Text id {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), id);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
bool IsCreatureValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (Global.ObjectMgr.GetCreatureTemplate(entry) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Creature entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsGameObjectValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (Global.ObjectMgr.GetGameObjectTemplate(entry) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent GameObject entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsQuestValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (Global.ObjectMgr.GetQuestTemplate(entry) == null)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Quest entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsSpellValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (!Global.SpellMgr.HasSpellInfo(entry))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Spell entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsMinMaxValid(SmartScriptHolder e, uint min, uint max)
|
|
{
|
|
if (max < min)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses min/max params wrong ({4}/{5}), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), min, max);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool NotNULL(SmartScriptHolder e, uint data)
|
|
{
|
|
if (data == 0)
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} Parameter can not be NULL, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsEmoteValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (!CliDB.EmotesStorage.ContainsKey(entry))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Emote entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsItemValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (!CliDB.ItemSparseStorage.ContainsKey(entry))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Item entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsTextEmoteValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (!CliDB.EmotesTextStorage.ContainsKey(entry))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Text Emote entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsAreaTriggerValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (!CliDB.AreaTriggerStorage.ContainsKey(entry))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent AreaTrigger entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool IsSoundValid(SmartScriptHolder e, uint entry)
|
|
{
|
|
if (!CliDB.SoundKitStorage.ContainsKey(entry))
|
|
{
|
|
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Sound entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public List<SmartScriptHolder> GetScript(int entry, SmartScriptType type)
|
|
{
|
|
List<SmartScriptHolder> temp = new List<SmartScriptHolder>();
|
|
if (mEventMap[(uint)type].ContainsKey(entry))
|
|
{
|
|
foreach (var holder in mEventMap[(uint)type][entry])
|
|
temp.Add(new SmartScriptHolder(holder));
|
|
}
|
|
else
|
|
{
|
|
if (entry > 0)//first search is for guid (negative), do not drop error if not found
|
|
Log.outDebug(LogFilter.ScriptsAi, "SmartAIMgr.GetScript: Could not load Script for Entry {0} ScriptType {1}.", entry, type);
|
|
}
|
|
|
|
return temp;
|
|
}
|
|
|
|
public Dictionary<uint, SmartPath> GetPath(uint id)
|
|
{
|
|
return waypoint_map.LookupByKey(id);
|
|
}
|
|
|
|
public SmartScriptHolder FindLinkedSourceEvent(List<SmartScriptHolder> list, uint eventId)
|
|
{
|
|
var sch = list.Find(p => p.link == eventId);
|
|
if (sch != null)
|
|
return sch;
|
|
|
|
return null;
|
|
}
|
|
|
|
public SmartScriptHolder FindLinkedEvent(List<SmartScriptHolder> list, uint link)
|
|
{
|
|
var sch = list.Find(p => p.event_id == link && p.GetEventType() == SmartEvents.Link);
|
|
if (sch != null)
|
|
return sch;
|
|
|
|
return null;
|
|
}
|
|
|
|
MultiMap<int, SmartScriptHolder>[] mEventMap = new MultiMap<int, SmartScriptHolder>[(int)SmartScriptType.Max];
|
|
Dictionary<uint, Dictionary<uint, SmartPath>> waypoint_map = new Dictionary<uint, Dictionary<uint, SmartPath>>();
|
|
|
|
Dictionary<SmartScriptType, uint> SmartAITypeMask = new Dictionary<SmartScriptType, uint>
|
|
{
|
|
{ SmartScriptType.Creature, SmartScriptTypeMaskId.Creature },
|
|
{ SmartScriptType.GameObject, SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartScriptType.AreaTrigger, SmartScriptTypeMaskId.Areatrigger },
|
|
{ SmartScriptType.Event, SmartScriptTypeMaskId.Event },
|
|
{ SmartScriptType.Gossip, SmartScriptTypeMaskId.Gossip },
|
|
{ SmartScriptType.Quest, SmartScriptTypeMaskId.Quest },
|
|
{ SmartScriptType.Spell, SmartScriptTypeMaskId.Spell },
|
|
{ SmartScriptType.Transport, SmartScriptTypeMaskId.Transport },
|
|
{ SmartScriptType.Instance, SmartScriptTypeMaskId.Instance },
|
|
{ SmartScriptType.TimedActionlist, SmartScriptTypeMaskId.TimedActionlist },
|
|
{ SmartScriptType.Scene, SmartScriptTypeMaskId.Scene }
|
|
};
|
|
|
|
Dictionary<SmartEvents, uint> SmartAIEventMask = new Dictionary<SmartEvents, uint>
|
|
{
|
|
{ SmartEvents.UpdateIc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.TimedActionlist },
|
|
{ SmartEvents.UpdateOoc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.Instance },
|
|
{ SmartEvents.HealtPct, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.ManaPct, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Aggro, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Kill, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Death, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Evade, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.SpellHit, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.Range, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.OocLos, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Respawn, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.TargetHealthPct, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.VictimCasting, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.FriendlyHealth, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.FriendlyIsCc, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.FriendlyMissingBuff, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.SummonedUnit, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.TargetManaPct, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.AcceptedQuest, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.RewardQuest, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.ReachedHome, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.ReceiveEmote, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.HasAura, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.TargetBuffed, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Reset, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.IcLos, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.PassengerBoarded, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.PassengerRemoved, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Charmed, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.CharmedTarget, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.SpellhitTarget, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Damaged, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.DamagedTarget, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.Movementinform, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.SummonDespawned, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.CorpseRemoved, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.AiInit, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.DataSet, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.WaypointStart, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.WaypointReached, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.TransportAddplayer, SmartScriptTypeMaskId.Transport },
|
|
{ SmartEvents.TransportAddcreature, SmartScriptTypeMaskId.Transport },
|
|
{ SmartEvents.TransportRemovePlayer, SmartScriptTypeMaskId.Transport },
|
|
{ SmartEvents.TransportRelocate, SmartScriptTypeMaskId.Transport },
|
|
{ SmartEvents.InstancePlayerEnter, SmartScriptTypeMaskId.Instance },
|
|
{ SmartEvents.AreatriggerOntrigger, SmartScriptTypeMaskId.Areatrigger },
|
|
{ SmartEvents.QuestAccepted, SmartScriptTypeMaskId.Quest },
|
|
{ SmartEvents.QuestObjCompletion, SmartScriptTypeMaskId.Quest },
|
|
{ SmartEvents.QuestRewarded, SmartScriptTypeMaskId.Quest },
|
|
{ SmartEvents.QuestCompletion, SmartScriptTypeMaskId.Quest },
|
|
{ SmartEvents.QuestFail, SmartScriptTypeMaskId.Quest },
|
|
{ SmartEvents.TextOver, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.ReceiveHeal, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.JustSummoned, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.WaypointPaused, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.WaypointResumed, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.WaypointStopped, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.WaypointEnded, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.TimedEventTriggered, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.Update, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.Link, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.Areatrigger + SmartScriptTypeMaskId.Event + SmartScriptTypeMaskId.Gossip + SmartScriptTypeMaskId.Quest + SmartScriptTypeMaskId.Spell + SmartScriptTypeMaskId.Transport + SmartScriptTypeMaskId.Instance },
|
|
{ SmartEvents.GossipSelect, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.JustCreated, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.GossipHello, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.FollowCompleted, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.DummyEffect, SmartScriptTypeMaskId.Spell },
|
|
{ SmartEvents.IsBehindTarget, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.GameEventStart, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.GameEventEnd, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.GoStateChanged, SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.GoEventInform, SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.ActionDone, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.OnSpellclick, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.FriendlyHealthPCT, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.DistanceCreature, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.DistanceGameobject, SmartScriptTypeMaskId.Creature },
|
|
{ SmartEvents.CounterSet, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject },
|
|
{ SmartEvents.SceneStart, SmartScriptTypeMaskId.Scene },
|
|
{ SmartEvents.SceneTrigger, SmartScriptTypeMaskId.Scene },
|
|
{ SmartEvents.SceneCancel, SmartScriptTypeMaskId.Scene },
|
|
{ SmartEvents.SceneComplete, SmartScriptTypeMaskId.Scene },
|
|
{ SmartEvents.SpellEffectHit, SmartScriptTypeMaskId.Spell },
|
|
{ SmartEvents.SpellEffectHitTarget, SmartScriptTypeMaskId.Spell }
|
|
};
|
|
}
|
|
|
|
public class SmartPath
|
|
{
|
|
public SmartPath(uint _id, float _x, float _y, float _z)
|
|
{
|
|
id = _id;
|
|
x = _x;
|
|
y = _y;
|
|
z = _z;
|
|
}
|
|
|
|
public uint id;
|
|
public float x;
|
|
public float y;
|
|
public float z;
|
|
}
|
|
|
|
public class SmartScriptHolder
|
|
{
|
|
public SmartScriptHolder() { }
|
|
public SmartScriptHolder(SmartScriptHolder other)
|
|
{
|
|
entryOrGuid = other.entryOrGuid;
|
|
source_type = other.source_type;
|
|
event_id = other.event_id;
|
|
link = other.link;
|
|
Event = other.Event;
|
|
Action = other.Action;
|
|
Target = other.Target;
|
|
timer = other.timer;
|
|
active = other.active;
|
|
runOnce = other.runOnce;
|
|
enableTimed = other.enableTimed;
|
|
}
|
|
|
|
public SmartScriptType GetScriptType() { return source_type; }
|
|
public SmartEvents GetEventType() { return Event.type; }
|
|
public SmartActions GetActionType() { return Action.type; }
|
|
public SmartTargets GetTargetType() { return Target.type; }
|
|
|
|
public int entryOrGuid;
|
|
public SmartScriptType source_type;
|
|
public uint event_id;
|
|
public uint link;
|
|
public SmartEvent Event;
|
|
public SmartAction Action;
|
|
public SmartTarget Target;
|
|
public uint timer;
|
|
public bool active;
|
|
public bool runOnce;
|
|
public bool enableTimed;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
public struct SmartEvent
|
|
{
|
|
[FieldOffset(0)]
|
|
public SmartEvents type;
|
|
|
|
[FieldOffset(4)]
|
|
public uint event_phase_mask;
|
|
|
|
[FieldOffset(8)]
|
|
public uint event_chance;
|
|
|
|
[FieldOffset(12)]
|
|
public SmartEventFlags event_flags;
|
|
|
|
[FieldOffset(16)]
|
|
public MinMaxRepeat minMaxRepeat;
|
|
|
|
[FieldOffset(16)]
|
|
public Kill kill;
|
|
|
|
[FieldOffset(16)]
|
|
public SpellHit spellHit;
|
|
|
|
[FieldOffset(16)]
|
|
public Los los;
|
|
|
|
[FieldOffset(16)]
|
|
public Respawn respawn;
|
|
|
|
[FieldOffset(16)]
|
|
public MinMax minMax;
|
|
|
|
[FieldOffset(16)]
|
|
public TargetCasting targetCasting;
|
|
|
|
[FieldOffset(16)]
|
|
public FriendlyHealt friendlyHealth;
|
|
|
|
[FieldOffset(16)]
|
|
public FriendlyCC friendlyCC;
|
|
|
|
[FieldOffset(16)]
|
|
public MissingBuff missingBuff;
|
|
|
|
[FieldOffset(16)]
|
|
public Summoned summoned;
|
|
|
|
[FieldOffset(16)]
|
|
public Quest quest;
|
|
|
|
[FieldOffset(16)]
|
|
public Emote emote;
|
|
|
|
[FieldOffset(16)]
|
|
public Aura aura;
|
|
|
|
[FieldOffset(16)]
|
|
public Charm charm;
|
|
|
|
[FieldOffset(16)]
|
|
public TargetAura targetAura;
|
|
|
|
[FieldOffset(16)]
|
|
public MovementInform movementInform;
|
|
|
|
[FieldOffset(16)]
|
|
public DataSet dataSet;
|
|
|
|
[FieldOffset(16)]
|
|
public Waypoint waypoint;
|
|
|
|
[FieldOffset(16)]
|
|
public TransportAddCreature transportAddCreature;
|
|
|
|
[FieldOffset(16)]
|
|
public TransportRelocate transportRelocate;
|
|
|
|
[FieldOffset(16)]
|
|
public InstancePlayerEnter instancePlayerEnter;
|
|
|
|
[FieldOffset(16)]
|
|
public Areatrigger areatrigger;
|
|
|
|
[FieldOffset(16)]
|
|
public TextOver textOver;
|
|
|
|
[FieldOffset(16)]
|
|
public TimedEvent timedEvent;
|
|
|
|
[FieldOffset(16)]
|
|
public Gossip gossip;
|
|
|
|
[FieldOffset(16)]
|
|
public Dummy dummy;
|
|
|
|
[FieldOffset(16)]
|
|
public BehindTarget behindTarget;
|
|
|
|
[FieldOffset(16)]
|
|
public GameEvent gameEvent;
|
|
|
|
[FieldOffset(16)]
|
|
public GoStateChanged goStateChanged;
|
|
|
|
[FieldOffset(16)]
|
|
public EventInform eventInform;
|
|
|
|
[FieldOffset(16)]
|
|
public DoAction doAction;
|
|
|
|
[FieldOffset(16)]
|
|
public FriendlyHealthPct friendlyHealthPct;
|
|
|
|
[FieldOffset(16)]
|
|
public Distance distance;
|
|
|
|
[FieldOffset(16)]
|
|
public Counter counter;
|
|
|
|
[FieldOffset(16)]
|
|
public Scene scene;
|
|
|
|
[FieldOffset(16)]
|
|
public Spell spell;
|
|
|
|
[FieldOffset(16)]
|
|
public Raw raw;
|
|
|
|
[FieldOffset(32)]
|
|
public string param_string;
|
|
|
|
#region Structs
|
|
public struct MinMaxRepeat
|
|
{
|
|
public uint min;
|
|
public uint max;
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
}
|
|
public struct Kill
|
|
{
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
public uint playerOnly;
|
|
public uint creature;
|
|
}
|
|
public struct SpellHit
|
|
{
|
|
public uint spell;
|
|
public uint school;
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
}
|
|
public struct Los
|
|
{
|
|
public uint noHostile;
|
|
public uint maxDist;
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
}
|
|
public struct Respawn
|
|
{
|
|
public uint type;
|
|
public uint map;
|
|
public uint area;
|
|
}
|
|
public struct MinMax
|
|
{
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
}
|
|
public struct TargetCasting
|
|
{
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
public uint spellId;
|
|
}
|
|
public struct FriendlyHealt
|
|
{
|
|
public uint hpDeficit;
|
|
public uint radius;
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
}
|
|
public struct FriendlyCC
|
|
{
|
|
public uint radius;
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
}
|
|
public struct MissingBuff
|
|
{
|
|
public uint spell;
|
|
public uint radius;
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
}
|
|
public struct Summoned
|
|
{
|
|
public uint creature;
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
}
|
|
public struct Quest
|
|
{
|
|
public uint questId;
|
|
}
|
|
public struct Emote
|
|
{
|
|
public uint emoteId;
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
}
|
|
public struct Aura
|
|
{
|
|
public uint spell;
|
|
public uint count;
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
}
|
|
public struct Charm
|
|
{
|
|
public uint onRemove;
|
|
}
|
|
public struct TargetAura
|
|
{
|
|
public uint spell;
|
|
public uint count;
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
}
|
|
public struct MovementInform
|
|
{
|
|
public uint type;
|
|
public uint id;
|
|
}
|
|
public struct DataSet
|
|
{
|
|
public uint id;
|
|
public uint value;
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
}
|
|
public struct Waypoint
|
|
{
|
|
public uint pointID;
|
|
public uint pathID;
|
|
}
|
|
public struct TransportAddCreature
|
|
{
|
|
public uint creature;
|
|
}
|
|
public struct TransportRelocate
|
|
{
|
|
public uint pointID;
|
|
}
|
|
public struct InstancePlayerEnter
|
|
{
|
|
public uint team;
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
}
|
|
public struct Areatrigger
|
|
{
|
|
public uint id;
|
|
}
|
|
public struct TextOver
|
|
{
|
|
public uint textGroupID;
|
|
public uint creatureEntry;
|
|
}
|
|
public struct TimedEvent
|
|
{
|
|
public uint id;
|
|
}
|
|
public struct Gossip
|
|
{
|
|
public uint sender;
|
|
public uint action;
|
|
}
|
|
public struct Dummy
|
|
{
|
|
public uint spell;
|
|
public uint effIndex;
|
|
}
|
|
public struct BehindTarget
|
|
{
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
}
|
|
public struct GameEvent
|
|
{
|
|
public uint gameEventId;
|
|
}
|
|
public struct GoStateChanged
|
|
{
|
|
public uint state;
|
|
}
|
|
public struct EventInform
|
|
{
|
|
public uint eventId;
|
|
}
|
|
public struct DoAction
|
|
{
|
|
public uint eventId;
|
|
}
|
|
public struct FriendlyHealthPct
|
|
{
|
|
public uint minHpPct;
|
|
public uint maxHpPct;
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
}
|
|
public struct Distance
|
|
{
|
|
public uint guid;
|
|
public uint entry;
|
|
public uint dist;
|
|
public uint repeat;
|
|
}
|
|
public struct Counter
|
|
{
|
|
public uint id;
|
|
public uint value;
|
|
public uint cooldownMin;
|
|
public uint cooldownMax;
|
|
}
|
|
public struct Scene
|
|
{
|
|
public uint sceneId;
|
|
}
|
|
public struct Spell
|
|
{
|
|
public uint effIndex;
|
|
}
|
|
public struct Raw
|
|
{
|
|
public uint param1;
|
|
public uint param2;
|
|
public uint param3;
|
|
public uint param4;
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
public struct SmartAction
|
|
{
|
|
[FieldOffset(0)]
|
|
public SmartActions type;
|
|
|
|
[FieldOffset(4)]
|
|
public Talk talk;
|
|
|
|
[FieldOffset(4)]
|
|
public Faction faction;
|
|
|
|
[FieldOffset(4)]
|
|
public MorphOrMount morphOrMount;
|
|
|
|
[FieldOffset(4)]
|
|
public Sound sound;
|
|
|
|
[FieldOffset(4)]
|
|
public Emote emote;
|
|
|
|
[FieldOffset(4)]
|
|
public Quest quest;
|
|
|
|
[FieldOffset(4)]
|
|
public QuestOffer questOffer;
|
|
|
|
[FieldOffset(4)]
|
|
public React react;
|
|
|
|
[FieldOffset(4)]
|
|
public RandomEmote randomEmote;
|
|
|
|
[FieldOffset(4)]
|
|
public Cast cast;
|
|
|
|
[FieldOffset(4)]
|
|
public CrossCast crossCast;
|
|
|
|
[FieldOffset(4)]
|
|
public SummonCreature summonCreature;
|
|
|
|
[FieldOffset(4)]
|
|
public ThreatPCT threatPCT;
|
|
|
|
[FieldOffset(4)]
|
|
public CastCreatureOrGO castCreatureOrGO;
|
|
|
|
[FieldOffset(4)]
|
|
public AddUnitFlag addUnitFlag;
|
|
|
|
[FieldOffset(4)]
|
|
public RemoveUnitFlag removeUnitFlag;
|
|
|
|
[FieldOffset(4)]
|
|
public AutoAttack autoAttack;
|
|
|
|
[FieldOffset(4)]
|
|
public CombatMove combatMove;
|
|
|
|
[FieldOffset(4)]
|
|
public SetEventPhase setEventPhase;
|
|
|
|
[FieldOffset(4)]
|
|
public IncEventPhase incEventPhase;
|
|
|
|
[FieldOffset(4)]
|
|
public CastedCreatureOrGO castedCreatureOrGO;
|
|
|
|
[FieldOffset(4)]
|
|
public RemoveAura removeAura;
|
|
|
|
[FieldOffset(4)]
|
|
public Follow follow;
|
|
|
|
[FieldOffset(4)]
|
|
public RandomPhase randomPhase;
|
|
|
|
[FieldOffset(4)]
|
|
public RandomPhaseRange randomPhaseRange;
|
|
|
|
[FieldOffset(4)]
|
|
public KilledMonster killedMonster;
|
|
|
|
[FieldOffset(4)]
|
|
public SetInstanceData setInstanceData;
|
|
|
|
[FieldOffset(4)]
|
|
public SetInstanceData64 setInstanceData64;
|
|
|
|
[FieldOffset(4)]
|
|
public UpdateTemplate updateTemplate;
|
|
|
|
[FieldOffset(4)]
|
|
public CallHelp callHelp;
|
|
|
|
[FieldOffset(4)]
|
|
public SetSheath setSheath;
|
|
|
|
[FieldOffset(4)]
|
|
public ForceDespawn forceDespawn;
|
|
|
|
[FieldOffset(4)]
|
|
public InvincHP invincHP;
|
|
|
|
[FieldOffset(4)]
|
|
public IngamePhaseId ingamePhaseId;
|
|
|
|
[FieldOffset(4)]
|
|
public IngamePhaseGroup ingamePhaseGroup;
|
|
|
|
[FieldOffset(4)]
|
|
public SetData setData;
|
|
|
|
[FieldOffset(4)]
|
|
public MoveRandom moveRandom;
|
|
|
|
[FieldOffset(4)]
|
|
public Visibility visibility;
|
|
|
|
[FieldOffset(4)]
|
|
public SummonGO summonGO;
|
|
|
|
[FieldOffset(4)]
|
|
public Active active;
|
|
|
|
[FieldOffset(4)]
|
|
public Taxi taxi;
|
|
|
|
[FieldOffset(4)]
|
|
public WpStart wpStart;
|
|
|
|
[FieldOffset(4)]
|
|
public WpPause wpPause;
|
|
|
|
[FieldOffset(4)]
|
|
public WpStop wpStop;
|
|
|
|
[FieldOffset(4)]
|
|
public Item item;
|
|
|
|
[FieldOffset(4)]
|
|
public InstallTtemplate installTtemplate;
|
|
|
|
[FieldOffset(4)]
|
|
public SetRun setRun;
|
|
|
|
[FieldOffset(4)]
|
|
public SetFly setFly;
|
|
|
|
[FieldOffset(4)]
|
|
public SetSwim setSwim;
|
|
|
|
[FieldOffset(4)]
|
|
public Teleport teleport;
|
|
|
|
[FieldOffset(4)]
|
|
public SetCounter setCounter;
|
|
|
|
[FieldOffset(4)]
|
|
public StoreVar storeVar;
|
|
|
|
[FieldOffset(4)]
|
|
public StoreTargets storeTargets;
|
|
|
|
[FieldOffset(4)]
|
|
public TimeEvent timeEvent;
|
|
|
|
[FieldOffset(4)]
|
|
public Movie movie;
|
|
|
|
[FieldOffset(4)]
|
|
public Equip equip;
|
|
|
|
[FieldOffset(4)]
|
|
public UnitFlag unitFlag;
|
|
|
|
[FieldOffset(4)]
|
|
public SetunitByte setunitByte;
|
|
|
|
[FieldOffset(4)]
|
|
public DelunitByte delunitByte;
|
|
|
|
[FieldOffset(4)]
|
|
public EnterVehicle enterVehicle;
|
|
|
|
[FieldOffset(4)]
|
|
public TimedActionList timedActionList;
|
|
|
|
[FieldOffset(4)]
|
|
public RandTimedActionList randTimedActionList;
|
|
|
|
[FieldOffset(4)]
|
|
public InterruptSpellCasting interruptSpellCasting;
|
|
|
|
[FieldOffset(4)]
|
|
public SendGoCustomAnim sendGoCustomAnim;
|
|
|
|
[FieldOffset(4)]
|
|
public Jump jump;
|
|
|
|
[FieldOffset(4)]
|
|
public Flee flee;
|
|
|
|
[FieldOffset(4)]
|
|
public RespawnTarget respawnTarget;
|
|
|
|
[FieldOffset(4)]
|
|
public MoveToPos moveToPos;
|
|
|
|
[FieldOffset(4)]
|
|
public SendGossipMenu sendGossipMenu;
|
|
|
|
[FieldOffset(4)]
|
|
public SetGoLootState setGoLootState;
|
|
|
|
[FieldOffset(4)]
|
|
public SendTargetToTarget sendTargetToTarget;
|
|
|
|
[FieldOffset(4)]
|
|
public SetRangedMovement setRangedMovement;
|
|
|
|
[FieldOffset(4)]
|
|
public SetHealthRegen setHealthRegen;
|
|
|
|
[FieldOffset(4)]
|
|
public SetRoot setRoot;
|
|
|
|
[FieldOffset(4)]
|
|
public GoFlag goFlag;
|
|
|
|
[FieldOffset(4)]
|
|
public CreatureGroup creatureGroup;
|
|
|
|
[FieldOffset(4)]
|
|
public Power power;
|
|
|
|
[FieldOffset(4)]
|
|
public GameEventStop gameEventStop;
|
|
|
|
[FieldOffset(4)]
|
|
public GameEventStart gameEventStart;
|
|
|
|
[FieldOffset(4)]
|
|
public ClosestWaypointFromList closestWaypointFromList;
|
|
|
|
[FieldOffset(4)]
|
|
public RandomSound randomSound;
|
|
|
|
[FieldOffset(4)]
|
|
public CorpseDelay corpseDelay;
|
|
|
|
[FieldOffset(4)]
|
|
public DisableEvade disableEvade;
|
|
|
|
[FieldOffset(4)]
|
|
public AnimKit animKit;
|
|
|
|
[FieldOffset(4)]
|
|
public Scene scene;
|
|
|
|
[FieldOffset(4)]
|
|
public Raw raw;
|
|
|
|
#region Stucts
|
|
public struct Talk
|
|
{
|
|
public uint textGroupId;
|
|
public uint duration;
|
|
public uint useTalkTarget;
|
|
}
|
|
public struct Faction
|
|
{
|
|
public uint factionID;
|
|
}
|
|
public struct MorphOrMount
|
|
{
|
|
public uint creature;
|
|
public uint model;
|
|
}
|
|
public struct Sound
|
|
{
|
|
public uint soundId;
|
|
public uint onlySelf;
|
|
}
|
|
public struct Emote
|
|
{
|
|
public uint emoteId;
|
|
}
|
|
public struct Quest
|
|
{
|
|
public uint questId;
|
|
}
|
|
public struct QuestOffer
|
|
{
|
|
public uint questId;
|
|
public uint directAdd;
|
|
}
|
|
public struct React
|
|
{
|
|
public uint state;
|
|
}
|
|
public struct RandomEmote
|
|
{
|
|
public uint emote1;
|
|
public uint emote2;
|
|
public uint emote3;
|
|
public uint emote4;
|
|
public uint emote5;
|
|
public uint emote6;
|
|
}
|
|
public struct Cast
|
|
{
|
|
public uint spell;
|
|
public uint castFlags;
|
|
public uint triggerFlags;
|
|
}
|
|
public struct CrossCast
|
|
{
|
|
public uint spell;
|
|
public uint castFlags;
|
|
public uint targetType;
|
|
public uint targetParam1;
|
|
public uint targetParam2;
|
|
public uint targetParam3;
|
|
}
|
|
public struct SummonCreature
|
|
{
|
|
public uint creature;
|
|
public uint type;
|
|
public uint duration;
|
|
public uint storageID;
|
|
public uint attackInvoker;
|
|
}
|
|
public struct ThreatPCT
|
|
{
|
|
public uint threatINC;
|
|
public uint threatDEC;
|
|
}
|
|
public struct CastCreatureOrGO
|
|
{
|
|
public uint quest;
|
|
public uint spell;
|
|
}
|
|
public struct AddUnitFlag
|
|
{
|
|
public uint flag1;
|
|
public uint flag2;
|
|
public uint flag3;
|
|
public uint flag4;
|
|
public uint flag5;
|
|
public uint flag6;
|
|
}
|
|
public struct RemoveUnitFlag
|
|
{
|
|
public uint flag1;
|
|
public uint flag2;
|
|
public uint flag3;
|
|
public uint flag4;
|
|
public uint flag5;
|
|
public uint flag6;
|
|
}
|
|
public struct AutoAttack
|
|
{
|
|
public uint attack;
|
|
}
|
|
public struct CombatMove
|
|
{
|
|
public uint move;
|
|
}
|
|
public struct SetEventPhase
|
|
{
|
|
public uint phase;
|
|
}
|
|
public struct IncEventPhase
|
|
{
|
|
public uint inc;
|
|
public uint dec;
|
|
}
|
|
public struct CastedCreatureOrGO
|
|
{
|
|
public uint creature;
|
|
public uint spell;
|
|
}
|
|
public struct RemoveAura
|
|
{
|
|
public uint spell;
|
|
}
|
|
public struct Follow
|
|
{
|
|
public uint dist;
|
|
public uint angle;
|
|
public uint entry;
|
|
public uint credit;
|
|
public uint creditType;
|
|
}
|
|
public struct RandomPhase
|
|
{
|
|
public uint phase1;
|
|
public uint phase2;
|
|
public uint phase3;
|
|
public uint phase4;
|
|
public uint phase5;
|
|
public uint phase6;
|
|
}
|
|
public struct RandomPhaseRange
|
|
{
|
|
public uint phaseMin;
|
|
public uint phaseMax;
|
|
}
|
|
public struct KilledMonster
|
|
{
|
|
public uint creature;
|
|
}
|
|
public struct SetInstanceData
|
|
{
|
|
public uint field;
|
|
public uint data;
|
|
public uint type;
|
|
}
|
|
public struct SetInstanceData64
|
|
{
|
|
public uint field;
|
|
}
|
|
public struct UpdateTemplate
|
|
{
|
|
public uint creature;
|
|
public uint updateLevel;
|
|
}
|
|
public struct CallHelp
|
|
{
|
|
public uint range;
|
|
public uint withEmote;
|
|
}
|
|
public struct SetSheath
|
|
{
|
|
public uint sheath;
|
|
}
|
|
public struct ForceDespawn
|
|
{
|
|
public uint delay;
|
|
public uint respawn;
|
|
}
|
|
public struct InvincHP
|
|
{
|
|
public uint minHP;
|
|
public uint percent;
|
|
}
|
|
public struct IngamePhaseId
|
|
{
|
|
public uint id;
|
|
public uint apply;
|
|
}
|
|
public struct IngamePhaseGroup
|
|
{
|
|
public uint groupId;
|
|
public uint apply;
|
|
}
|
|
public struct SetData
|
|
{
|
|
public uint field;
|
|
public uint data;
|
|
}
|
|
public struct MoveRandom
|
|
{
|
|
public uint distance;
|
|
}
|
|
public struct Visibility
|
|
{
|
|
public uint state;
|
|
}
|
|
public struct SummonGO
|
|
{
|
|
public uint entry;
|
|
public uint despawnTime;
|
|
}
|
|
public struct Active
|
|
{
|
|
public uint state;
|
|
}
|
|
public struct Taxi
|
|
{
|
|
public uint id;
|
|
}
|
|
public struct WpStart
|
|
{
|
|
public uint run;
|
|
public uint pathID;
|
|
public uint repeat;
|
|
public uint quest;
|
|
public uint despawnTime;
|
|
public uint reactState;
|
|
}
|
|
public struct WpPause
|
|
{
|
|
public uint delay;
|
|
}
|
|
public struct WpStop
|
|
{
|
|
public uint despawnTime;
|
|
public uint quest;
|
|
public uint fail;
|
|
}
|
|
public struct Item
|
|
{
|
|
public uint entry;
|
|
public uint count;
|
|
}
|
|
public struct InstallTtemplate
|
|
{
|
|
public uint id;
|
|
public uint param1;
|
|
public uint param2;
|
|
public uint param3;
|
|
public uint param4;
|
|
public uint param5;
|
|
}
|
|
public struct SetRun
|
|
{
|
|
public uint run;
|
|
}
|
|
public struct SetFly
|
|
{
|
|
public uint fly;
|
|
}
|
|
public struct SetSwim
|
|
{
|
|
public uint swim;
|
|
}
|
|
public struct Teleport
|
|
{
|
|
public uint mapID;
|
|
}
|
|
public struct SetCounter
|
|
{
|
|
public uint counterId;
|
|
public uint value;
|
|
public uint reset;
|
|
}
|
|
public struct StoreVar
|
|
{
|
|
public uint id;
|
|
public uint number;
|
|
}
|
|
public struct StoreTargets
|
|
{
|
|
public uint id;
|
|
}
|
|
public struct TimeEvent
|
|
{
|
|
public uint id;
|
|
public uint min;
|
|
public uint max;
|
|
public uint repeatMin;
|
|
public uint repeatMax;
|
|
public uint chance;
|
|
}
|
|
public struct Movie
|
|
{
|
|
public uint entry;
|
|
}
|
|
|
|
public struct Equip
|
|
{
|
|
public uint entry;
|
|
public uint mask;
|
|
public uint slot1;
|
|
public uint slot2;
|
|
public uint slot3;
|
|
}
|
|
public struct UnitFlag
|
|
{
|
|
public uint flag;
|
|
public uint type;
|
|
}
|
|
public struct SetunitByte
|
|
{
|
|
public uint byte1;
|
|
public uint type;
|
|
}
|
|
public struct DelunitByte
|
|
{
|
|
public uint byte1;
|
|
public uint type;
|
|
}
|
|
public struct EnterVehicle
|
|
{
|
|
public uint seat;
|
|
}
|
|
public struct TimedActionList
|
|
{
|
|
public uint id;
|
|
public uint timerType;
|
|
}
|
|
public struct RandTimedActionList
|
|
{
|
|
public uint entry1;
|
|
public uint entry2;
|
|
public uint entry3;
|
|
public uint entry4;
|
|
public uint entry5;
|
|
public uint entry6;
|
|
}
|
|
public struct InterruptSpellCasting
|
|
{
|
|
public uint withDelayed;
|
|
public uint spell_id;
|
|
public uint withInstant;
|
|
}
|
|
public struct SendGoCustomAnim
|
|
{
|
|
public uint anim;
|
|
}
|
|
public struct Jump
|
|
{
|
|
public uint speedxy;
|
|
public uint speedz;
|
|
}
|
|
public struct Flee
|
|
{
|
|
public uint withEmote;
|
|
}
|
|
public struct RespawnTarget
|
|
{
|
|
public uint goRespawnTime;
|
|
}
|
|
public struct MoveToPos
|
|
{
|
|
public uint pointId;
|
|
public uint transport;
|
|
public uint disablePathfinding;
|
|
}
|
|
public struct SendGossipMenu
|
|
{
|
|
public uint gossipMenuId;
|
|
public uint gossipNpcTextId;
|
|
}
|
|
public struct SetGoLootState
|
|
{
|
|
public uint state;
|
|
}
|
|
public struct SendTargetToTarget
|
|
{
|
|
public uint id;
|
|
}
|
|
public struct SetRangedMovement
|
|
{
|
|
public uint distance;
|
|
public uint angle;
|
|
}
|
|
public struct SetHealthRegen
|
|
{
|
|
public uint regenHealth;
|
|
}
|
|
public struct SetRoot
|
|
{
|
|
public uint root;
|
|
}
|
|
public struct GoFlag
|
|
{
|
|
public uint flag;
|
|
}
|
|
public struct CreatureGroup
|
|
{
|
|
public uint group;
|
|
public uint attackInvoker;
|
|
}
|
|
public struct Power
|
|
{
|
|
public uint powerType;
|
|
public uint newPower;
|
|
}
|
|
public struct GameEventStop
|
|
{
|
|
public uint id;
|
|
}
|
|
public struct GameEventStart
|
|
{
|
|
public uint id;
|
|
}
|
|
public struct ClosestWaypointFromList
|
|
{
|
|
public uint wp1;
|
|
public uint wp2;
|
|
public uint wp3;
|
|
public uint wp4;
|
|
public uint wp5;
|
|
public uint wp6;
|
|
}
|
|
public struct RandomSound
|
|
{
|
|
public uint sound1;
|
|
public uint sound2;
|
|
public uint sound3;
|
|
public uint sound4;
|
|
public uint sound5;
|
|
public uint onlySelf;
|
|
}
|
|
public struct CorpseDelay
|
|
{
|
|
public uint timer;
|
|
}
|
|
public struct DisableEvade
|
|
{
|
|
public uint disable;
|
|
}
|
|
public struct AnimKit
|
|
{
|
|
public uint animKit;
|
|
public uint type;
|
|
}
|
|
public struct Scene
|
|
{
|
|
public uint sceneId;
|
|
}
|
|
public struct Raw
|
|
{
|
|
public uint param1;
|
|
public uint param2;
|
|
public uint param3;
|
|
public uint param4;
|
|
public uint param5;
|
|
public uint param6;
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
public struct SmartTarget
|
|
{
|
|
[FieldOffset(0)]
|
|
public SmartTargets type;
|
|
|
|
[FieldOffset(4)]
|
|
public float x;
|
|
|
|
[FieldOffset(8)]
|
|
public float y;
|
|
|
|
[FieldOffset(12)]
|
|
public float z;
|
|
|
|
[FieldOffset(16)]
|
|
public float o;
|
|
|
|
[FieldOffset(20)]
|
|
public UnitRange unitRange;
|
|
|
|
[FieldOffset(20)]
|
|
public UnitGUID unitGUID;
|
|
|
|
[FieldOffset(20)]
|
|
public UnitDistance unitDistance;
|
|
|
|
[FieldOffset(20)]
|
|
public PlayerDistance playerDistance;
|
|
|
|
[FieldOffset(20)]
|
|
public PlayerRange playerRange;
|
|
|
|
[FieldOffset(20)]
|
|
public Stored stored;
|
|
|
|
[FieldOffset(20)]
|
|
public GoRange goRange;
|
|
|
|
[FieldOffset(20)]
|
|
public GoGUID goGUID;
|
|
|
|
[FieldOffset(20)]
|
|
public GoDistance goDistance;
|
|
|
|
[FieldOffset(20)]
|
|
public Position postion;
|
|
|
|
[FieldOffset(20)]
|
|
public Closest closest;
|
|
|
|
[FieldOffset(20)]
|
|
public ClosestAttackable closestAttackable;
|
|
|
|
[FieldOffset(20)]
|
|
public ClosestFriendly closestFriendly;
|
|
|
|
[FieldOffset(20)]
|
|
public Vehicle vehicle;
|
|
|
|
[FieldOffset(20)]
|
|
public Raw raw;
|
|
|
|
#region Structs
|
|
|
|
public struct UnitRange
|
|
{
|
|
public uint creature;
|
|
public uint minDist;
|
|
public uint maxDist;
|
|
}
|
|
public struct UnitGUID
|
|
{
|
|
public uint dbGuid;
|
|
public uint entry;
|
|
}
|
|
public struct UnitDistance
|
|
{
|
|
public uint creature;
|
|
public uint dist;
|
|
}
|
|
public struct PlayerDistance
|
|
{
|
|
public uint dist;
|
|
}
|
|
public struct PlayerRange
|
|
{
|
|
public uint minDist;
|
|
public uint maxDist;
|
|
}
|
|
public struct Stored
|
|
{
|
|
public uint id;
|
|
}
|
|
public struct GoRange
|
|
{
|
|
public uint entry;
|
|
public uint minDist;
|
|
public uint maxDist;
|
|
}
|
|
public struct GoGUID
|
|
{
|
|
public uint dbGuid;
|
|
public uint entry;
|
|
}
|
|
public struct GoDistance
|
|
{
|
|
public uint entry;
|
|
public uint dist;
|
|
}
|
|
public struct Position
|
|
{
|
|
public uint map;
|
|
}
|
|
public struct Closest
|
|
{
|
|
public uint entry;
|
|
public uint dist;
|
|
public uint dead;
|
|
}
|
|
public struct ClosestAttackable
|
|
{
|
|
public uint maxDist;
|
|
}
|
|
public struct ClosestFriendly
|
|
{
|
|
public uint maxDist;
|
|
}
|
|
public struct Vehicle
|
|
{
|
|
public uint seat;
|
|
}
|
|
public struct Raw
|
|
{
|
|
public uint param1;
|
|
public uint param2;
|
|
public uint param3;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|