Core/SmartAI: Various fixes and extensions for smart scripts:

Port From (https://github.com/TrinityCore/TrinityCore/commit/a32d5cfa1762ae1158ee2f40b4c9b36e5b41913a)
This commit is contained in:
hondacrx
2019-08-30 12:00:42 -04:00
parent b85860dd78
commit 1657f720dc
15 changed files with 863 additions and 257 deletions
+386 -123
View File
@@ -103,8 +103,7 @@ namespace Game.AI
case SmartActions.Talk:
{
List<WorldObject> targets = GetTargets(e, unit);
Creature talker = me;
Player targetPlayer = null;
Creature talker = e.Target.type == 0 ? me : null;
Unit talkTarget = null;
if (!targets.Empty())
@@ -114,31 +113,33 @@ namespace Game.AI
if (IsCreature(obj) && !obj.ToCreature().IsPet()) // Prevented sending text to pets.
{
if (e.Action.talk.useTalkTarget != 0)
{
talker = me;
talkTarget = obj.ToCreature();
}
else
talker = obj.ToCreature();
break;
}
else if (IsPlayer(obj))
{
targetPlayer = obj.ToPlayer();
talker = me;
talkTarget = obj.ToPlayer();
break;
}
}
}
if (!talker)
if (talkTarget == null)
talkTarget = GetLastInvoker();
if (talker == null)
break;
mTalkerEntry = talker.GetEntry();
mLastTextID = e.Action.talk.textGroupId;
mTextTimer = e.Action.talk.duration;
if (IsPlayer(GetLastInvoker())) // used for $vars in texts and whisper target
talkTarget = GetLastInvoker();
else if (targetPlayer != null)
talkTarget = targetPlayer;
mUseTextTimer = true;
Global.CreatureTextMgr.SendChat(talker, (byte)e.Action.talk.textGroupId, talkTarget);
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_TALK: talker: {0} (Guid: {1}), textGuid: {2}",
@@ -464,8 +465,17 @@ namespace Game.AI
if (targets.Empty())
break;
if (e.Action.cast.targetsLimit > 0 && targets.Count > e.Action.cast.targetsLimit)
targets.RandomResize(e.Action.cast.targetsLimit);
foreach (var obj in targets)
{
if (go)
{
// may be nullptr
go.CastSpell(obj.ToUnit(), e.Action.cast.spell);
}
if (!IsUnit(obj))
continue;
@@ -548,6 +558,9 @@ namespace Game.AI
if (targets.Empty())
break;
if (e.Action.cast.targetsLimit > 0 && targets.Count > e.Action.cast.targetsLimit)
targets.RandomResize(e.Action.cast.targetsLimit);
foreach (var obj in targets)
{
if (!IsUnit(obj))
@@ -748,8 +761,8 @@ namespace Game.AI
if (GetBaseObject() == null)
break;
IncPhase((int)e.Action.incEventPhase.inc);
DecPhase((int)e.Action.incEventPhase.dec);
IncPhase(e.Action.incEventPhase.inc);
DecPhase(e.Action.incEventPhase.dec);
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction. SMART_ACTION_INC_EVENT_PHASE: Creature {0} inc event phase by {1}, " +
"decrease by {2}", GetBaseObject().GetGUID().ToString(), e.Action.incEventPhase.inc, e.Action.incEventPhase.dec);
break;
@@ -769,7 +782,7 @@ namespace Game.AI
break;
me.DoFleeToGetAssistance();
if (e.Action.flee.withEmote != 0)
if (e.Action.fleeAssist.withEmote != 0)
{
var builder = new BroadcastTextBuilder(me, ChatMsg.MonsterEmote, (uint)BroadcastTextIds.FleeForAssist, me.GetGender());
Global.CreatureTextMgr.SendChatPacket(me, builder, ChatMsg.Emote);
@@ -782,9 +795,11 @@ namespace Game.AI
if (unit == null)
break;
if (IsPlayer(unit) && GetBaseObject() != null)
// If invoker was pet or charm
Player player = unit.GetCharmerOrOwnerPlayerOrPlayerItself();
if (player && GetBaseObject() != null)
{
unit.ToPlayer().GroupEventHappens(e.Action.quest.questId, GetBaseObject());
player.GroupEventHappens(e.Action.quest.questId, GetBaseObject());
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {0}, group credit for quest {1}",
unit.GetGUID().ToString(), e.Action.quest.questId);
}
@@ -795,9 +810,9 @@ namespace Game.AI
{
foreach (var seat in vehicle.Seats)
{
Player player = Global.ObjAccessor.GetPlayer(unit, seat.Value.Passenger.Guid);
if (player != null)
player.GroupEventHappens(e.Action.quest.questId, GetBaseObject());
Player player1 = Global.ObjAccessor.GetPlayer(unit, seat.Value.Passenger.Guid);
if (player1 != null)
player1.GroupEventHappens(e.Action.quest.questId, GetBaseObject());
}
}
break;
@@ -811,7 +826,7 @@ namespace Game.AI
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_COMBAT_STOP: {0} CombatStop", me.GetGUID().ToString());
break;
}
case SmartActions.Removeaurasfromspell:
case SmartActions.RemoveAurasFromSpell:
{
List<WorldObject> targets = GetTargets(e, unit);
if (targets.Empty())
@@ -841,13 +856,17 @@ namespace Game.AI
List<WorldObject> targets = GetTargets(e, unit);
if (targets.Empty())
{
((SmartAI)me.GetAI()).StopFollow(false);
break;
}
foreach (var obj in targets)
{
if (IsUnit(obj))
{
((SmartAI)me.GetAI()).SetFollow(obj.ToUnit(), e.Action.follow.dist, e.Action.follow.angle, e.Action.follow.credit, e.Action.follow.entry, e.Action.follow.creditType);
float angle = e.Action.follow.angle > 6 ? (e.Action.follow.angle * (float)Math.PI / 180.0f) : e.Action.follow.angle;
((SmartAI)me.GetAI()).SetFollow(obj.ToUnit(), e.Action.follow.dist + 0.1f, angle, e.Action.follow.credit, e.Action.follow.entry, e.Action.follow.creditType);
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_FOLLOW: Creature {0} following target {1}",
me.GetGUID().ToString(), obj.GetGUID().ToString());
break;
@@ -1026,24 +1045,39 @@ namespace Game.AI
}
case SmartActions.SetInCombatWithZone:
{
if (me != null)
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
{
me.SetInCombatWithZone();
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature {0}", me.GetGUID().ToString());
if (IsCreature(obj))
{
me.SetInCombatWithZone();
Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature: {me.GetGUID().ToString()}, Target: {obj.GetGUID().ToString()}");
}
}
break;
}
case SmartActions.CallForHelp:
{
if (me != null)
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
{
me.CallForHelp(e.Action.callHelp.range);
if (e.Action.callHelp.withEmote != 0)
if (IsCreature(obj))
{
var builder = new BroadcastTextBuilder(me, ChatMsg.Emote, (uint)BroadcastTextIds.CallForHelp, me.GetGender());
Global.CreatureTextMgr.SendChatPacket(me, builder, ChatMsg.MonsterEmote);
obj.ToCreature().CallForHelp(e.Action.callHelp.range);
if (e.Action.callHelp.withEmote != 0)
{
var builder = new BroadcastTextBuilder(me, ChatMsg.Emote, (uint)BroadcastTextIds.CallForHelp, me.GetGender());
Global.CreatureTextMgr.SendChatPacket(me, builder, ChatMsg.MonsterEmote);
}
Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature: {me.GetGUID().ToString()}, Target: {obj.GetGUID().ToString()}");
}
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature {0}", me.GetGUID().ToString());
}
break;
}
@@ -1156,18 +1190,25 @@ namespace Game.AI
}
case SmartActions.SetInvincibilityHpLevel:
{
if (me == null)
List<WorldObject> targets = GetTargets(e, unit);
if (targets.Empty())
break;
SmartAI ai = ((SmartAI)me.GetAI());
foreach (var obj in targets)
{
if (IsCreature(obj))
{
SmartAI ai = (SmartAI)me.GetAI();
if (ai == null)
continue;
if (ai == null)
break;
if (e.Action.invincHP.percent != 0)
ai.SetInvincibilityHpLevel((uint)obj.ToCreature().CountPctFromMaxHealth((int)e.Action.invincHP.percent));
else
ai.SetInvincibilityHpLevel(e.Action.invincHP.minHP);
}
}
if (e.Action.invincHP.percent != 0)
ai.SetInvincibilityHpLevel((uint)me.CountPctFromMaxHealth((int)e.Action.invincHP.percent));
else
ai.SetInvincibilityHpLevel(e.Action.invincHP.minHP);
break;
}
case SmartActions.SetData:
@@ -1214,15 +1255,25 @@ namespace Game.AI
}
case SmartActions.SetVisibility:
{
if (me != null)
me.SetVisible(Convert.ToBoolean(e.Action.visibility.state));
List<WorldObject> targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
if (IsUnit(obj))
obj.ToUnit().SetVisible(e.Action.visibility.state != 0);
break;
}
case SmartActions.SetActive:
{
WorldObject baseObj = GetBaseObject();
if (baseObj != null)
baseObj.setActive(e.Action.active.state != 0);
List<WorldObject> targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
obj.setActive(e.Action.active.state != 0);
break;
}
case SmartActions.AttackStart:
@@ -1234,15 +1285,9 @@ namespace Game.AI
if (targets.Empty())
break;
foreach (var obj in targets)
{
if (IsUnit(obj))
{
me.GetAI().AttackStart(obj.ToUnit());
break;
}
}
Unit target = targets.SelectRandom().ToUnit();
if (target != null)
me.GetAI().AttackStart(target);
break;
}
@@ -1290,20 +1335,19 @@ namespace Game.AI
{
foreach (var obj in targets)
{
if (!IsUnit(obj))
continue;
// allow gameobjects to summon gameobjects
//if (!IsUnit(*itr))
// continue;
Position pos = obj.GetPositionWithOffset(new Position(e.Target.x, e.Target.y, e.Target.z, e.Target.o));
Quaternion rot = Quaternion.fromEulerAnglesZYX(pos.GetOrientation(), 0.0f, 0.0f);
summoner.SummonGameObject(e.Action.summonGO.entry, pos, rot, e.Action.summonGO.despawnTime);
summoner.SummonGameObject(e.Action.summonGO.entry, pos, Quaternion.fromEulerAnglesZYX(pos.GetOrientation(), 0.0f, 0.0f), e.Action.summonGO.despawnTime);
}
}
if (e.GetTargetType() != SmartTargets.Position)
break;
Quaternion rot1 = Quaternion.fromEulerAnglesZYX(e.Target.o, 0.0f, 0.0f);
summoner.SummonGameObject(e.Action.summonGO.entry, new Position(e.Target.x, e.Target.y, e.Target.z, e.Target.o), rot1, e.Action.summonGO.despawnTime);
summoner.SummonGameObject(e.Action.summonGO.entry, new Position(e.Target.x, e.Target.y, e.Target.z, e.Target.o), Quaternion.fromEulerAnglesZYX(e.Target.o, 0.0f, 0.0f), e.Action.summonGO.despawnTime);
break;
}
case SmartActions.KillUnit:
@@ -1379,12 +1423,20 @@ namespace Game.AI
break;
}
case SmartActions.SetFly:
case SmartActions.SetDisableGravity:
{
if (!IsSmart())
break;
((SmartAI)me.GetAI()).SetFly(e.Action.setFly.fly != 0 ? true : false);
((SmartAI)me.GetAI()).SetDisableGravity(e.Action.setDisableGravity.disable != 0);
break;
}
case SmartActions.SetCanFly:
{
if (!IsSmart())
break;
((SmartAI)me.GetAI()).SetCanFly(e.Action.setFly.fly != 0);
break;
}
case SmartActions.SetRun:
@@ -1438,11 +1490,24 @@ namespace Game.AI
if (!IsSmart())
break;
bool run = e.Action.wpStart.run != 0 ? true : false;
bool run = e.Action.wpStart.run != 0;
uint entry = e.Action.wpStart.pathID;
bool repeat = e.Action.wpStart.repeat != 0 ? true : false;
bool repeat = e.Action.wpStart.repeat != 0;
// ensure that SMART_ESCORT_TARGETS contains at least one player reference
List<WorldObject> targets = GetTargets(e, unit);
StoreTargetList(targets, SharedConst.SmartEscortTargets);
if (!targets.Empty())
{
foreach (var obj in targets)
{
if (IsPlayer(obj))
{
StoreTargetList(targets, SharedConst.SmartEscortTargets);
break;
}
}
}
me.SetReactState((ReactStates)e.Action.wpStart.reactState);
((SmartAI)me.GetAI()).StartPath(run, entry, repeat, unit);
@@ -1477,7 +1542,7 @@ namespace Game.AI
if (!IsSmart())
break;
((SmartAI)me.GetAI()).ResumePath();
((SmartAI)me.GetAI()).SetWPPauseTimer(0);
break;
}
case SmartActions.SetOrientation:
@@ -1520,34 +1585,32 @@ namespace Game.AI
WorldObject target = null;
if (e.GetTargetType() == SmartTargets.CreatureRange || e.GetTargetType() == SmartTargets.CreatureGuid ||
/*if (e.GetTargetType() == SmartTargets.CreatureRange || e.GetTargetType() == SmartTargets.CreatureGuid ||
e.GetTargetType() == SmartTargets.CreatureDistance || e.GetTargetType() == SmartTargets.GameobjectRange ||
e.GetTargetType() == SmartTargets.GameobjectGuid || e.GetTargetType() == SmartTargets.GameobjectDistance ||
e.GetTargetType() == SmartTargets.ClosestCreature || e.GetTargetType() == SmartTargets.ClosestGameobject ||
e.GetTargetType() == SmartTargets.OwnerOrSummoner || e.GetTargetType() == SmartTargets.ActionInvoker ||
e.GetTargetType() == SmartTargets.ClosestEnemy || e.GetTargetType() == SmartTargets.ClosestFriendly)
e.GetTargetType() == SmartTargets.ClosestEnemy || e.GetTargetType() == SmartTargets.ClosestFriendly)*/
{
List<WorldObject> targets = GetTargets(e, unit);
if (targets.Empty())
break;
target = targets.First();
// we want to move to random element
target = targets.SelectRandom();
}
if (!target)
{
float x = e.Target.x;
float y = e.Target.y;
float z = e.Target.z;
float o = 0;
Position dest = new Position(e.Target.x, e.Target.y, e.Target.z);
if (e.Action.moveToPos.transport != 0)
{
ITransport trans = me.GetDirectTransport();
if (trans != null)
trans.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
trans.CalculatePassengerPosition(ref dest.posX, ref dest.posY, ref dest.posZ, ref dest.Orientation);
}
me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, x, y, z, e.Action.moveToPos.disablePathfinding == 0);
me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, dest, e.Action.moveToPos.disablePathfinding == 0);
}
else
{
@@ -1555,7 +1618,7 @@ namespace Game.AI
target.GetPosition(out x, out y, out z);
if (e.Action.moveToPos.contactDistance > 0)
target.GetContactPoint(me, out x, out y, out z, e.Action.moveToPos.contactDistance);
me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, x, y, z, e.Action.moveToPos.disablePathfinding == 0);
me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, x + e.Target.x, y + e.Target.y, z + e.Target.z, e.Action.moveToPos.disablePathfinding == 0);
}
break;
}
@@ -1570,10 +1633,15 @@ namespace Game.AI
if (IsCreature(obj))
obj.ToCreature().Respawn();
else if (IsGameObject(obj))
obj.ToGameObject().SetRespawnTime((int)e.Action.respawnTarget.goRespawnTime);
{
// do not modify respawndelay of already spawned gameobjects
if (obj.ToGameObject().isSpawnedByDefault())
obj.ToGameObject().Respawn();
else
obj.ToGameObject().SetRespawnTime((int)e.Action.respawnTarget.goRespawnTime);
}
}
break;
}
case SmartActions.CloseGossip:
@@ -1664,6 +1732,10 @@ namespace Game.AI
}
case SmartActions.TriggerTimedEvent:
ProcessEventsFor(SmartEvents.TimedEventTriggered, null, e.Action.timeEvent.id);
// remove this event if not repeatable
if (e.Event.event_flags.HasAnyFlag(SmartEventFlags.NotRepeatable))
mRemIDs.Add(e.Action.timeEvent.id);
break;
case SmartActions.RemoveTimedEvent:
mRemIDs.Add(e.Action.timeEvent.id);
@@ -2306,7 +2378,7 @@ namespace Game.AI
WayPoint closestWp = null;
var targets = GetTargets(e, unit);
if (targets != null)
if (!targets.Empty())
{
foreach (var obj in targets)
{
@@ -2357,7 +2429,7 @@ namespace Game.AI
bool onlySelf = e.Action.randomSound.onlySelf != 0;
var targets = GetTargets(e, unit);
if (targets != null)
if (!targets.Empty())
{
foreach (var obj in targets)
{
@@ -2375,7 +2447,7 @@ namespace Game.AI
case SmartActions.SetCorpseDelay:
{
var targets = GetTargets(e, unit);
if (targets == null)
if (targets.Empty())
break;
foreach (var obj in targets)
@@ -2392,6 +2464,104 @@ namespace Game.AI
break;
((SmartAI)me.GetAI()).SetEvadeDisabled(e.Action.disableEvade.disable != 0);
break;
}
case SmartActions.RemoveAurasByType: // can be used to exit vehicle for example
{
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
if (IsUnit(obj))
obj.ToUnit().RemoveAurasByType((AuraType)e.Action.auraType.type);
break;
}
case SmartActions.SetSightDist:
{
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
if (IsCreature(obj))
obj.ToCreature().m_SightDistance = e.Action.sightDistance.dist;
break;
}
case SmartActions.Flee:
{
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
if (IsCreature(obj))
obj.ToCreature().GetMotionMaster().MoveFleeing(me, e.Action.flee.fleeTime);
break;
}
case SmartActions.AddThreat:
{
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
if (IsUnit(obj))
me.AddThreat(obj.ToUnit(), (float)e.Action.threatPCT.threatINC - (float)e.Action.threatPCT.threatDEC);
break;
}
case SmartActions.LoadEquipment:
{
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
if (IsCreature(obj))
obj.ToCreature().LoadEquipment((int)e.Action.loadEquipment.id, e.Action.loadEquipment.force != 0);
break;
}
case SmartActions.TriggerRandomTimedEvent:
{
uint eventId = RandomHelper.URand(e.Action.randomTimedEvent.minId, e.Action.randomTimedEvent.maxId);
ProcessEventsFor(SmartEvents.TimedEventTriggered, null, eventId);
break;
}
case SmartActions.RemoveAllGameobjects:
{
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
if (IsUnit(obj))
obj.ToUnit().RemoveAllGameObjects();
break;
}
case SmartActions.StopMotion:
{
var targets = GetTargets(e, unit);
if (targets.Empty())
break;
foreach (var obj in targets)
{
if (IsUnit(obj))
{
if (e.Action.stopMotion.stopMovement != 0)
obj.ToUnit().StopMoving();
if (e.Action.stopMotion.movementExpired != 0)
obj.ToUnit().GetMotionMaster().MovementExpired();
}
}
break;
}
case SmartActions.PlayAnimkit:
@@ -2471,10 +2641,15 @@ namespace Game.AI
void ProcessTimedAction(SmartScriptHolder e, uint min, uint max, Unit unit = null, uint var0 = 0, uint var1 = 0, bool bvar = false, SpellInfo spell = null, GameObject gob = null, string varString = "")
{
// We may want to execute action rarely and because of this if condition is not fulfilled the action will be rechecked in a long time
if (Global.ConditionMgr.IsObjectMeetingSmartEventConditions(e.entryOrGuid, e.event_id, e.source_type, unit, GetBaseObject()))
{
ProcessAction(e, unit, var0, var1, bvar, spell, gob, varString);
RecalcTimer(e, min, max);
RecalcTimer(e, min, max);
}
else
RecalcTimer(e, Math.Min(min, 5000), Math.Min(min, 5000));
}
void InstallTemplate(SmartScriptHolder e)
@@ -2615,36 +2790,79 @@ namespace Game.AI
case SmartTargets.HostileSecondAggro:
if (me != null)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.TopAggro, 1);
if (u != null)
l.Add(u);
if (e.Target.hostilRandom.powerType != 0)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.TopAggro, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
if (u != null)
l.Add(u);
}
else
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.TopAggro, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
if (u != null)
l.Add(u);
}
}
break;
case SmartTargets.HostileLastAggro:
if (me != null)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.BottomAggro, 0);
if (u != null)
l.Add(u);
if (e.Target.hostilRandom.powerType != 0)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.BottomAggro, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
if (u != null)
l.Add(u);
}
else
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.BottomAggro, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
if (u != null)
l.Add(u);
}
}
break;
case SmartTargets.HostileRandom:
if (me != null)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 0);
if (u != null)
l.Add(u);
if (e.Target.hostilRandom.powerType != 0)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
if (u != null)
l.Add(u);
}
else
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
if (u != null)
l.Add(u);
}
}
break;
case SmartTargets.HostileRandomNotTop:
if (me != null)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1);
if (e.Target.hostilRandom.powerType != 0)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
if (u != null)
l.Add(u);
}
else
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
if (u != null)
l.Add(u);
}
}
break;
case SmartTargets.Farthest:
if (me)
{
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Farthest, 0, new FarthestTargetSelector(me, (float)e.Target.farthest.maxDist, e.Target.farthest.playerOnly != 0, e.Target.farthest.isInLos != 0));
if (u != null)
l.Add(u);
}
break;
case SmartTargets.None:
case SmartTargets.ActionInvoker:
if (scriptTrigger != null)
l.Add(scriptTrigger);
@@ -2794,7 +3012,7 @@ namespace Game.AI
if (!list.Empty())
l.AddRange(list);
return l;
break;
}
case SmartTargets.ClosestCreature:
{
@@ -2812,9 +3030,10 @@ namespace Game.AI
}
case SmartTargets.ClosestPlayer:
{
if (me)
WorldObject obj = GetBaseObject();
if (obj != null)
{
Player target = me.SelectNearestPlayer(e.Target.playerDistance.dist);
Player target = obj.SelectNearestPlayer(e.Target.playerDistance.dist);
if (target)
l.Add(target);
}
@@ -2843,6 +3062,23 @@ namespace Game.AI
if (owner != null)
l.Add(owner);
}
else if (go != null)
{
Unit owner = Global.ObjAccessor.GetUnit(go, go.GetOwnerGUID());
if (owner)
l.Add(owner);
}
// Get owner of owner
if (e.Target.owner.useCharmerOrOwner != 0 && !l.Empty())
{
Unit owner = l.First().ToUnit();
l.Clear();
Unit unitBase = Global.ObjAccessor.GetUnit(owner, owner.GetCharmerOrOwnerGUID());
if (unitBase != null)
l.Add(unitBase);
}
break;
}
case SmartTargets.ThreatList:
@@ -2854,7 +3090,8 @@ namespace Game.AI
{
Unit temp = Global.ObjAccessor.GetUnit(me, i.getUnitGuid());
if (temp != null)
l.Add(temp);
if (e.Target.hostilRandom.maxDist == 0 || me.IsWithinCombatRange(temp, (float)e.Target.hostilRandom.maxDist))
l.Add(temp);
}
}
break;
@@ -2971,7 +3208,7 @@ namespace Game.AI
return;
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax);
break;
case SmartEvents.HealtPct:
case SmartEvents.HealthPct:
{
if (me == null || !me.IsInCombat() || me.GetMaxHealth() == 0)
return;
@@ -3018,6 +3255,8 @@ namespace Game.AI
if (me.IsInRange(me.GetVictim(), e.Event.minMaxRepeat.min, e.Event.minMaxRepeat.max))
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax, me.GetVictim());
else // make it predictable
RecalcTimer(e, 500, 500);
break;
}
case SmartEvents.VictimCasting:
@@ -3048,7 +3287,12 @@ namespace Game.AI
Unit target = DoSelectLowestHpFriendly(e.Event.friendlyHealth.radius, e.Event.friendlyHealth.hpDeficit);
if (target == null || !target.IsInCombat())
{
// if there are at least two same npcs, they will perform the same action immediately even if this is useless...
RecalcTimer(e, 1000, 3000);
return;
}
ProcessTimedAction(e, e.Event.friendlyHealth.repeatMin, e.Event.friendlyHealth.repeatMax, target);
break;
}
@@ -3060,7 +3304,12 @@ namespace Game.AI
List<Creature> pList = new List<Creature>();
DoFindFriendlyCC(pList, e.Event.friendlyCC.radius);
if (pList.Empty())
{
// if there are at least two same npcs, they will perform the same action immediately even if this is useless...
RecalcTimer(e, 1000, 3000);
return;
}
ProcessTimedAction(e, e.Event.friendlyCC.repeatMin, e.Event.friendlyCC.repeatMax, pList.First());
break;
}
@@ -3072,7 +3321,7 @@ namespace Game.AI
if (pList.Empty())
return;
ProcessTimedAction(e, e.Event.missingBuff.repeatMin, e.Event.missingBuff.repeatMax, pList.First());
ProcessTimedAction(e, e.Event.missingBuff.repeatMin, e.Event.missingBuff.repeatMax, pList.SelectRandom());
break;
}
case SmartEvents.HasAura:
@@ -3118,11 +3367,17 @@ namespace Game.AI
case SmartEvents.JustSummoned:
case SmartEvents.Reset:
case SmartEvents.JustCreated:
case SmartEvents.GossipHello:
case SmartEvents.FollowCompleted:
case SmartEvents.OnSpellclick:
ProcessAction(e, unit, var0, var1, bvar, spell, gob);
break;
case SmartEvents.GossipHello:
{
if (e.Event.gossipHello.noReportUse != 0 && var0 != 0)
return;
ProcessAction(e, unit, var0, var1, bvar, spell, gob);
break;
}
case SmartEvents.IsBehindTarget:
{
if (me == null)
@@ -3266,6 +3521,13 @@ namespace Game.AI
break;
}
case SmartEvents.SummonDespawned:
{
if (e.Event.summoned.creature != 0 && e.Event.summoned.creature != var0)
return;
ProcessAction(e, unit, var0);
RecalcTimer(e, e.Event.summoned.cooldownMin, e.Event.summoned.cooldownMax);
break;
}
case SmartEvents.InstancePlayerEnter:
{
if (e.Event.instancePlayerEnter.team != 0 && var0 != e.Event.instancePlayerEnter.team)
@@ -3480,8 +3742,10 @@ namespace Game.AI
break;
}
case SmartEvents.CounterSet:
if (GetCounterId(e.Event.counter.id) != 0 && GetCounterValue(e.Event.counter.id) == e.Event.counter.value)
ProcessTimedAction(e, e.Event.counter.cooldownMin, e.Event.counter.cooldownMax);
if (e.Event.counter.id != var0 || GetCounterValue(e.Event.counter.id) != e.Event.counter.value)
return;
ProcessTimedAction(e, e.Event.counter.cooldownMin, e.Event.counter.cooldownMax);
break;
case SmartEvents.SceneStart:
case SmartEvents.SceneCancel:
@@ -3570,7 +3834,7 @@ namespace Game.AI
// Delay flee for assist event if stunned or rooted
if (e.GetActionType() == SmartActions.FleeForAssist)
{
if (me && me.HasUnitState(UnitState.Root | UnitState.Stunned))
if (me && me.HasUnitState(UnitState.Root | UnitState.LostControl))
{
e.timer = 1;
return;
@@ -3583,7 +3847,7 @@ namespace Game.AI
case SmartEvents.Update:
case SmartEvents.UpdateIc:
case SmartEvents.UpdateOoc:
case SmartEvents.HealtPct:
case SmartEvents.HealthPct:
case SmartEvents.TargetHealthPct:
case SmartEvents.ManaPct:
case SmartEvents.TargetManaPct:
@@ -3676,9 +3940,9 @@ namespace Game.AI
if (!mRemIDs.Empty())
{
foreach (var id in mRemIDs)
{
RemoveStoredEvent(id);
}
mRemIDs.Clear();
}
if (mUseTextTimer && me != null)
{
@@ -4078,19 +4342,14 @@ namespace Game.AI
if (mCounterList.ContainsKey(id))
{
if (reset == 0)
value += GetCounterValue(id);
mCounterList.Remove(id);
mCounterList[id] += value;
else
mCounterList[id] = value;
}
else
mCounterList.Add(id, value);
mCounterList.Add(id, value);
ProcessEventsFor(SmartEvents.CounterSet);
}
uint GetCounterId(uint id)
{
if (mCounterList.ContainsKey(id))
return id;
return 0;
ProcessEventsFor(SmartEvents.CounterSet, null, id);
}
uint GetCounterValue(uint id)
@@ -4152,22 +4411,26 @@ namespace Game.AI
meOrigGUID.Clear();
}
void IncPhase(int p = 1)
void IncPhase(uint p)
{
if (p >= 0)
mEventPhase += (uint)p;
else
DecPhase(-p);
// protect phase from overflowing
mEventPhase = Math.Min((uint)SmartPhase.Phase12, mEventPhase + p);
}
void DecPhase(int p = 1)
void DecPhase(uint p)
{
if (mEventPhase > p)
mEventPhase -= (uint)p;
else
if (p >= mEventPhase)
mEventPhase = 0;
else
mEventPhase -= p;
}
bool IsInPhase(uint p)
{
if (mEventPhase == 0)
return false;
return ((1 << (int)(mEventPhase - 1)) & p) != 0;
}
bool IsInPhase(uint p) { return Convert.ToBoolean((1 << (int)(mEventPhase - 1)) & p); }
void SetPhase(uint p = 0) { mEventPhase = p; }
void RemoveStoredEvent(uint id)