more event driven behavior tree
This commit is contained in:
parent
391c49553a
commit
e0874713d1
29 changed files with 473 additions and 165 deletions
|
|
@ -12,7 +12,6 @@ namespace Server.Mobiles.AI
|
|||
{
|
||||
public class BehaviorTreeAI : BaseAI
|
||||
{
|
||||
// private Blackboard blackboard;
|
||||
private Blackboard blackboard;
|
||||
private BehaviorTree behaviorTree;
|
||||
private BehaviorTreeContext behaviorTreeContext;
|
||||
|
|
@ -23,11 +22,16 @@ namespace Server.Mobiles.AI
|
|||
behaviorTreeContext = new BehaviorTreeContext(m, blackboard);
|
||||
behaviorTree = new BehaviorTree();
|
||||
behaviorTree.TryAddRoot(
|
||||
new Sequence(behaviorTree)
|
||||
.AddChild(new Condition(behaviorTree, (context) => context.Mobile.RawStr - context.Mobile.Str == 0))
|
||||
.AddChild(new CastSpell(behaviorTree, (context) => new BlessSpell(context.Mobile)))
|
||||
.AddChild(new WaitForTarget(behaviorTree))
|
||||
.AddChild(new DynamicTarget(behaviorTree, (context) => context.Mobile))
|
||||
new Selector(behaviorTree)
|
||||
.AddChild(new MageCombat(behaviorTree))
|
||||
.AddChild(new MagePassive(behaviorTree))
|
||||
/*
|
||||
new Sequence(behaviorTree)
|
||||
.AddChild(new Condition(behaviorTree, (context) => context.Mobile.RawStr - context.Mobile.Str == 0))
|
||||
.AddChild(new CastSpell(behaviorTree, (context) => new BlessSpell(context.Mobile)))
|
||||
.AddChild(new WaitForTarget(behaviorTree))
|
||||
.AddChild(new DynamicTarget(behaviorTree, (context) => context.Mobile))
|
||||
*/
|
||||
);
|
||||
|
||||
behaviorTree.Start(behaviorTreeContext);
|
||||
|
|
@ -42,7 +46,6 @@ namespace Server.Mobiles.AI
|
|||
|
||||
// MageBehaviorTree.Instance.RunBehavior(m_Mobile, blackboard);
|
||||
|
||||
m_Mobile.DebugSay("Thinking...");
|
||||
behaviorTree.Tick(behaviorTreeContext);
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Selector : Composite
|
||||
|
|
@ -19,8 +13,7 @@ namespace Server.Mobiles.BehaviorAI
|
|||
currentChildCache.Add(context.Mobile, currentChild);
|
||||
}
|
||||
|
||||
Behavior child = Children[currentChild];
|
||||
|
||||
currentChild++;
|
||||
if (lastResult == Result.Success)
|
||||
{
|
||||
currentChildCache[context.Mobile] = 0;
|
||||
|
|
@ -28,23 +21,16 @@ namespace Server.Mobiles.BehaviorAI
|
|||
return;
|
||||
}
|
||||
|
||||
currentChild++;
|
||||
if (currentChild >= Children.Count)
|
||||
{
|
||||
currentChildCache[context.Mobile] = 0;
|
||||
SetResult(context, Result.Failure);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentChildCache[context.Mobile] = currentChild;
|
||||
SetResult(context, Result.Running);
|
||||
if (Children[currentChild] == null)
|
||||
{
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
Tree.Enqueue(context, Children[currentChild], OnChildComplete);
|
||||
}
|
||||
|
||||
currentChildCache[context.Mobile] = currentChild;
|
||||
SetResult(context, Result.Running);
|
||||
Tree.Enqueue(context, Children[currentChild], OnChildComplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Sequence : Composite
|
||||
|
|
@ -19,8 +13,7 @@ namespace Server.Mobiles.BehaviorAI
|
|||
currentChildCache.Add(context.Mobile, currentChild);
|
||||
}
|
||||
|
||||
Behavior child = Children[currentChild];
|
||||
|
||||
currentChild++;
|
||||
if (lastResult == Result.Failure)
|
||||
{
|
||||
currentChildCache[context.Mobile] = 0;
|
||||
|
|
@ -28,23 +21,16 @@ namespace Server.Mobiles.BehaviorAI
|
|||
return;
|
||||
}
|
||||
|
||||
currentChild++;
|
||||
if (currentChild >= Children.Count)
|
||||
{
|
||||
currentChildCache[context.Mobile] = 0;
|
||||
SetResult(context, Result.Success);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetResult(context, Result.Running);
|
||||
currentChildCache[context.Mobile] = currentChild;
|
||||
if (Children[currentChild] == null)
|
||||
{
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
Tree.Enqueue(context, Children[currentChild], OnChildComplete);
|
||||
}
|
||||
|
||||
currentChildCache[context.Mobile] = currentChild;
|
||||
SetResult(context, Result.Running);
|
||||
Tree.Enqueue(context, Children[currentChild], OnChildComplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Items;
|
||||
using Server.Engines.Spawners;
|
||||
using MoveImpl = Server.Movement.MovementImpl;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
|
|
@ -79,7 +79,7 @@ namespace Server.Mobiles.BehaviorAI
|
|||
|
||||
queue.Enqueue(current);
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public virtual void ExecutionFinished(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
|
|
@ -104,5 +104,336 @@ namespace Server.Mobiles.BehaviorAI
|
|||
|
||||
return queue;
|
||||
}
|
||||
public static void WalkRandomInHome(BehaviorTreeContext context, int steps)
|
||||
{
|
||||
BaseCreature mob = context.Mobile;
|
||||
|
||||
if (mob.Deleted || mob.DisallowAllMoves)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mob.Home == Point3D.Zero)
|
||||
{
|
||||
if (mob.Spawner is RegionSpawner rs)
|
||||
{
|
||||
Region region = rs.SpawnRegion;
|
||||
|
||||
if (mob.Region.AcceptsSpawnsFrom(region))
|
||||
{
|
||||
mob.WalkRegion = region;
|
||||
WalkRandom(context, steps);
|
||||
mob.WalkRegion = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (region.GoLocation != Point3D.Zero && Utility.RandomDouble() > 0.5)
|
||||
{
|
||||
DoMove(context, mob.GetDirectionTo(region.GoLocation));
|
||||
}
|
||||
else
|
||||
{
|
||||
WalkRandom(context, steps);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WalkRandom(context, steps);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < steps; i++)
|
||||
{
|
||||
if (mob.RangeHome != 0)
|
||||
{
|
||||
var currentDistance = (int)mob.GetDistanceToSqrt(mob.Home);
|
||||
|
||||
if (currentDistance < mob.RangeHome * 2 / 3)
|
||||
{
|
||||
WalkRandom(context, 1);
|
||||
}
|
||||
else if (currentDistance > mob.RangeHome)
|
||||
{
|
||||
DoMove(context, mob.GetDirectionTo(mob.Home));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Utility.RandomDouble() > 0.5)
|
||||
{
|
||||
DoMove(context, mob.GetDirectionTo(mob.Home));
|
||||
}
|
||||
else
|
||||
{
|
||||
WalkRandom(context, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mob.Location != mob.Home)
|
||||
{
|
||||
DoMove(context, mob.GetDirectionTo(mob.Home));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static MoveResult WalkRandom(BehaviorTreeContext context, int steps, bool run = false)
|
||||
{
|
||||
BaseCreature mob = context.Mobile;
|
||||
|
||||
if (mob.Deleted || mob.DisallowAllMoves)
|
||||
{
|
||||
return MoveResult.BadState;
|
||||
}
|
||||
|
||||
for (var i = 0; i < steps; i++)
|
||||
{
|
||||
if (Utility.Random(8) <= 8)
|
||||
{
|
||||
var random = Utility.Random(0, 32);
|
||||
|
||||
Direction direction;
|
||||
|
||||
switch (random)
|
||||
{
|
||||
case 0:
|
||||
direction = Direction.Up;
|
||||
break;
|
||||
case 1:
|
||||
direction = Direction.North;
|
||||
break;
|
||||
case 2:
|
||||
direction = Direction.Left;
|
||||
break;
|
||||
case 3:
|
||||
direction = Direction.West;
|
||||
break;
|
||||
case 5:
|
||||
direction = Direction.Down;
|
||||
break;
|
||||
case 6:
|
||||
direction = Direction.South;
|
||||
break;
|
||||
case 7:
|
||||
direction = Direction.Right;
|
||||
break;
|
||||
case 8:
|
||||
direction = Direction.East;
|
||||
break;
|
||||
default:
|
||||
direction = mob.Direction;
|
||||
break;
|
||||
}
|
||||
|
||||
DoMove(context, direction, run);
|
||||
}
|
||||
}
|
||||
return MoveResult.Success;
|
||||
}
|
||||
public static MoveResult DoMove(BehaviorTreeContext context, Direction d, bool run = false)
|
||||
{
|
||||
BaseCreature mob = context.Mobile;
|
||||
|
||||
if (mob.Deleted || mob.Frozen || mob.Paralyzed || mob.Spell?.IsCasting == true || mob.DisallowAllMoves)
|
||||
{
|
||||
return MoveResult.BadState;
|
||||
}
|
||||
|
||||
Direction direction = d;
|
||||
|
||||
if (run)
|
||||
{
|
||||
direction |= Direction.Running;
|
||||
}
|
||||
|
||||
mob.Pushing = false;
|
||||
|
||||
MoveImpl.IgnoreMovableImpassables = mob.CanMoveOverObstacles && !mob.CanDestroyObstacles;
|
||||
|
||||
if ((mob.Direction & Direction.Mask) != (direction & Direction.Mask))
|
||||
{
|
||||
bool moved = mob.Move(direction);
|
||||
|
||||
MoveImpl.IgnoreMovableImpassables = false;
|
||||
return moved ? MoveResult.Success : MoveResult.Blocked;
|
||||
}
|
||||
|
||||
if (mob.Move(direction))
|
||||
{
|
||||
MoveImpl.IgnoreMovableImpassables = false;
|
||||
return MoveResult.Success;
|
||||
}
|
||||
|
||||
bool wasPushing = mob.Pushing;
|
||||
|
||||
bool blocked = true;
|
||||
|
||||
bool canOpenDoors = mob.CanOpenDoors;
|
||||
bool canDestroyObstacles = mob.CanDestroyObstacles;
|
||||
|
||||
if (canOpenDoors || canDestroyObstacles)
|
||||
{
|
||||
Map map = mob.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
int x = mob.X, y = mob.Y;
|
||||
Movement.Movement.Offset(direction, ref x, ref y);
|
||||
|
||||
int destroyables = 0;
|
||||
List<Item> obstacles = new List<Item>();
|
||||
|
||||
var eable = map.GetItemsInRange(new Point3D(x, y, mob.Location.Z), 1);
|
||||
|
||||
foreach (var item in eable)
|
||||
{
|
||||
if (canOpenDoors && item is BaseDoor door && door.Z + door.ItemData.Height > mob.Z && mob.Z + 16 > door.Z)
|
||||
{
|
||||
if (door.X != x || door.Y != y)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!door.Locked || !door.UseLocks())
|
||||
{
|
||||
obstacles.Add(item);
|
||||
}
|
||||
|
||||
if (!canDestroyObstacles)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (canDestroyObstacles && item.Movable && item.ItemData.Impassable && item.Z + item.ItemData.Height > mob.Z && mob.Z + 16 > item.Z)
|
||||
{
|
||||
if (!mob.InRange(item.GetWorldLocation(), 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
obstacles.Add(item);
|
||||
++destroyables;
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
if (destroyables > 0)
|
||||
{
|
||||
Effects.PlaySound(new Point3D(x, y, mob.Z), mob.Map, 0x3B3);
|
||||
}
|
||||
|
||||
if (obstacles.Count > 0)
|
||||
blocked = true;
|
||||
|
||||
while (obstacles.Count > 0)
|
||||
{
|
||||
Item item = obstacles.First();
|
||||
|
||||
if (item is BaseDoor door)
|
||||
{
|
||||
mob.DebugSay("Opening door...");
|
||||
if (!door.Open)
|
||||
{
|
||||
door.Use(mob);
|
||||
}
|
||||
obstacles.Remove(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item is Container container)
|
||||
{
|
||||
for (var i = 0; i < container.Items.Count; ++i)
|
||||
{
|
||||
Item check = container.Items[i];
|
||||
|
||||
if (check.Movable && check.ItemData.Impassable && container.Z + check.ItemData.Height > mob.Z)
|
||||
{
|
||||
obstacles.Add(check);
|
||||
}
|
||||
}
|
||||
|
||||
obstacles.Remove(item);
|
||||
container.Destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
obstacles.Remove(item);
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!blocked)
|
||||
{
|
||||
blocked = !mob.Move(direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (blocked)
|
||||
{
|
||||
int offset = Utility.RandomDouble() >= 0.6 ? 1 : -1;
|
||||
|
||||
for (var i = 0; i < 2; ++i)
|
||||
{
|
||||
mob.TurnInternal(offset);
|
||||
|
||||
if (mob.Move(mob.Direction))
|
||||
{
|
||||
MoveImpl.IgnoreMovableImpassables = false;
|
||||
return MoveResult.SuccessAutoTurn;
|
||||
}
|
||||
}
|
||||
|
||||
MoveImpl.IgnoreMovableImpassables = false;
|
||||
return wasPushing ? MoveResult.BadState : MoveResult.Blocked;
|
||||
}
|
||||
|
||||
MoveImpl.IgnoreMovableImpassables = false;
|
||||
return MoveResult.Success;
|
||||
}
|
||||
public static bool WalkMobileRange(BehaviorTreeContext context, BaseCreature target, int steps, bool run, int minRange, int maxRange)
|
||||
{
|
||||
BaseCreature mob = context.Mobile;
|
||||
|
||||
if (mob.Deleted || mob.DisallowAllMoves)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < steps; i++)
|
||||
{
|
||||
// Get the current distance
|
||||
var currentDistance = (int)mob.GetDistanceToSqrt(target);
|
||||
|
||||
if (currentDistance < minRange || currentDistance > maxRange)
|
||||
{
|
||||
var needCloser = currentDistance > maxRange;
|
||||
var direction = needCloser ?
|
||||
mob.GetDirectionTo(target, run) : target.GetDirectionTo(mob, run);
|
||||
|
||||
DoMove(context, direction, run);
|
||||
}
|
||||
else
|
||||
{
|
||||
WalkRandom(context, 2, run);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the current distance
|
||||
var newDistance = (int)mob.GetDistanceToSqrt(target);
|
||||
|
||||
return newDistance >= minRange && newDistance <= maxRange;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class BehaviorTreeContext
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
|
|
@ -36,10 +32,6 @@ namespace Server.Mobiles.BehaviorAI
|
|||
currentChild = 0;
|
||||
currentChildCache[context.Mobile] = currentChild;
|
||||
SetResult(context, Result.Running);
|
||||
if (Children[currentChild] == null)
|
||||
{
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
Tree.Enqueue(context, Children[currentChild], OnChildComplete);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Decorator : Behavior
|
||||
|
|
@ -16,14 +10,13 @@ namespace Server.Mobiles.BehaviorAI
|
|||
{
|
||||
Child = child;
|
||||
}
|
||||
public virtual bool AddChild(Behavior child)
|
||||
public virtual Decorator AddChild(Behavior child)
|
||||
{
|
||||
if (Child == null)
|
||||
{
|
||||
Child = child;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return this;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
|
|
@ -34,9 +27,9 @@ namespace Server.Mobiles.BehaviorAI
|
|||
return;
|
||||
}
|
||||
}
|
||||
public virtual void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
public virtual void OnChildComplete(BehaviorTreeContext context, Result lastResult)
|
||||
{
|
||||
SetResult(context, Child.GetResult(context));
|
||||
SetResult(context, lastResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public delegate bool ConditionalLoopPredicate(BehaviorTreeContext context);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class ForceSuccess : Decorator
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Inverter : Decorator
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public delegate bool OwnerConditionPredicate(BehaviorTreeContext context);
|
||||
|
|
@ -24,6 +18,7 @@ namespace Server.Mobiles.BehaviorAI
|
|||
{
|
||||
base.Tick(context);
|
||||
}
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class UntilFail : Decorator
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
|
|
|
|||
22
Projects/UOContent/Mobiles/BehaviorAI/Leaf/CancelTarget.cs
Normal file
22
Projects/UOContent/Mobiles/BehaviorAI/Leaf/CancelTarget.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using Server.Targeting;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class CancelTarget : Behavior
|
||||
{
|
||||
public CancelTarget(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
Target target = context.Mobile.Target;
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
target.Cancel(context.Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
|
||||
SetResult(context, Result.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Spells;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
|
|
@ -39,7 +34,7 @@ namespace Server.Mobiles.BehaviorAI
|
|||
|
||||
if (!spell.Cast())
|
||||
{
|
||||
SetResult(context, Result.Running);
|
||||
SetResult(context, Result.Failure);
|
||||
owner.DebugSay("Failed to cast...");
|
||||
return;
|
||||
}
|
||||
|
|
@ -57,7 +52,7 @@ namespace Server.Mobiles.BehaviorAI
|
|||
owner.DebugSay("Already casting {0}...", ((Spell)owner.Spell).Name);
|
||||
return;
|
||||
}
|
||||
else if (!owner.Spell.IsCasting)
|
||||
else if (!owner.Spell.IsCasting && ((Spell)owner.Spell).State == SpellState.Sequencing)
|
||||
{
|
||||
SetResult(context, Result.Success);
|
||||
owner.DebugSay("Finished casting {0}...", ((Spell)owner.Spell).Name);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public delegate bool ConditionPredicate(BehaviorTreeContext context);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
|
|
@ -10,14 +5,14 @@ namespace Server.Mobiles.BehaviorAI
|
|||
public delegate object DynamicTargetCallback(BehaviorTreeContext context);
|
||||
public class DynamicTarget : Behavior
|
||||
{
|
||||
public DynamicTargetCallback Transformation { get; private set; }
|
||||
public DynamicTargetCallback Callback { get; private set; }
|
||||
public DynamicTarget(BehaviorTree tree, DynamicTargetCallback transformation) : base(tree)
|
||||
{
|
||||
Transformation = transformation;
|
||||
Callback = transformation;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (Transformation != null)
|
||||
if (Callback == null)
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
return;
|
||||
|
|
@ -31,7 +26,7 @@ namespace Server.Mobiles.BehaviorAI
|
|||
return;
|
||||
}
|
||||
|
||||
object targeted = Transformation(context);
|
||||
object targeted = Callback(context);
|
||||
|
||||
if (targeted == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public delegate void TapAction(BehaviorTreeContext context);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class WaitForTarget : Behavior
|
||||
|
|
|
|||
29
Projects/UOContent/Mobiles/BehaviorAI/Leaf/Wander.cs
Normal file
29
Projects/UOContent/Mobiles/BehaviorAI/Leaf/Wander.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Wander : Behavior
|
||||
{
|
||||
public int Range { get; }
|
||||
public double Chance { get; }
|
||||
public Wander(BehaviorTree tree) : this(tree, 2)
|
||||
{
|
||||
}
|
||||
public Wander(BehaviorTree tree, int range) : this(tree, range, 1.0)
|
||||
{
|
||||
}
|
||||
public Wander(BehaviorTree tree, int range, double chance) : base(tree)
|
||||
{
|
||||
Range = range;
|
||||
Chance = chance;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (!context.Mobile.CheckIdle() && Utility.RandomDouble() < Chance)
|
||||
{
|
||||
BehaviorTree.WalkRandomInHome(context, Range);
|
||||
SetResult(context, Result.Success);
|
||||
return;
|
||||
}
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Projects/UOContent/Mobiles/BehaviorAI/MageCombat.cs
Normal file
37
Projects/UOContent/Mobiles/BehaviorAI/MageCombat.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
using Server.Spells;
|
||||
using Server.Spells.First;
|
||||
using Server.Spells.Second;
|
||||
using Server.Spells.Third;
|
||||
using Server.Spells.Sixth;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class MageCombat : OwnerCondition
|
||||
{
|
||||
public MageCombat(BehaviorTree tree) : base(tree, canActivate)
|
||||
{
|
||||
AddChild(
|
||||
new Sequence(tree)
|
||||
.AddChild(new Condition(tree, (context) => context.Mobile.Mana >= 65))
|
||||
.AddChild(new CastSpell(tree, (context) => new ExplosionSpell(context.Mobile)))
|
||||
.AddChild(new WaitForTarget(tree))
|
||||
.AddChild(new AutoTarget(tree))
|
||||
.AddChild(
|
||||
new ForceSuccess(tree)
|
||||
.AddChild(
|
||||
new Selector(tree)
|
||||
.AddChild(new OwnerCondition(tree, (context) => Utility.RandomBool(), new CastSpell(tree, (context) => new PoisonSpell(context.Mobile))))
|
||||
.AddChild(new OwnerCondition(tree, (context) => Utility.RandomBool(), new CastSpell(tree, (context) => new FireballSpell(context.Mobile))))
|
||||
.AddChild(new CastSpell(tree, (context) => new EnergyBoltSpell(context.Mobile)))
|
||||
)
|
||||
)
|
||||
.AddChild(new WaitForTarget(tree))
|
||||
.AddChild(new AutoTarget(tree))
|
||||
);
|
||||
}
|
||||
public static bool canActivate(BehaviorTreeContext context)
|
||||
{
|
||||
return context.Mobile.Combatant != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Projects/UOContent/Mobiles/BehaviorAI/MagePassive.cs
Normal file
14
Projects/UOContent/Mobiles/BehaviorAI/MagePassive.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class MagePassive : OwnerCondition
|
||||
{
|
||||
public MagePassive(BehaviorTree tree) : base(tree, canActivate)
|
||||
{
|
||||
AddChild(new Wander(tree, 2, 0.5));
|
||||
}
|
||||
public static bool canActivate(BehaviorTreeContext context)
|
||||
{
|
||||
return context.Mobile.Combatant == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,9 +11,9 @@ namespace Server.Mobiles
|
|||
public class BehaviorMage : BaseCreature
|
||||
{
|
||||
[Constructible]
|
||||
public BehaviorMage() : base(AIType.AI_BehaviorTree, FightMode.Evil, 2, 0, 0.01, 3)
|
||||
public BehaviorMage() : base(AIType.AI_BehaviorTree, FightMode.Evil, 2, 0, 0.01, 1)
|
||||
{
|
||||
Debug = true;
|
||||
// Debug = true;
|
||||
|
||||
InitBody();
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@
|
|||
<ItemGroup>
|
||||
<AdditionalFiles Include="Migrations/*.v*.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Mobiles\BehaviorAI\Sets\" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(RiderVersion)' != '' AND $([MSBuild]::VersionLessThan($(RiderVersion), '2021.2.0'))">
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue