asdfa
This commit is contained in:
parent
0e84739f2d
commit
3f309edffb
25 changed files with 947 additions and 3 deletions
|
|
@ -3,17 +3,34 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Mobiles.BT;
|
||||
// using Server.Mobiles.BT;
|
||||
using Server.Targeting;
|
||||
using Server.Mobiles.BehaviorAI;
|
||||
using Server.Spells.Third;
|
||||
|
||||
namespace Server.Mobiles.AI
|
||||
{
|
||||
public class BehaviorTreeAI : BaseAI
|
||||
{
|
||||
// private Blackboard blackboard;
|
||||
private Blackboard blackboard;
|
||||
private BehaviorTree behaviorTree;
|
||||
private BehaviorTreeContext behaviorTreeContext;
|
||||
public BehaviorTreeAI(BaseCreature m) : base(m)
|
||||
{
|
||||
// blackboard = new Blackboard();
|
||||
blackboard = new Blackboard();
|
||||
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))
|
||||
);
|
||||
|
||||
behaviorTree.Start(behaviorTreeContext);
|
||||
}
|
||||
|
||||
public override bool Think()
|
||||
|
|
@ -23,7 +40,10 @@ namespace Server.Mobiles.AI
|
|||
return false;
|
||||
}
|
||||
|
||||
MageBehaviorTree.Instance.RunBehavior(m_Mobile, blackboard);
|
||||
// MageBehaviorTree.Instance.RunBehavior(m_Mobile, blackboard);
|
||||
|
||||
m_Mobile.DebugSay("Thinking...");
|
||||
behaviorTree.Tick(behaviorTreeContext);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ namespace Server.Mobiles.BT
|
|||
AddChild(
|
||||
new SelectorNode(tree)
|
||||
.AddChild(new TapNode(tree, (mob, board) => { mob.CurrentSpeed = mob.ActiveSpeed; }))
|
||||
.AddChild(new CooldownNode(tree, TimeSpan.FromSeconds(0.5), new InverterNode(tree, new KeepRangeNode(tree, 1, 2))))
|
||||
.AddChild(new CooldownNode(tree, TimeSpan.FromSeconds(0.5), new InverterNode(tree, new KeepRangeNode(tree, 1, 3))))
|
||||
/*
|
||||
.AddChild(new MageDebuffNode(tree))
|
||||
.AddChild(new MageComboNode(tree))
|
||||
.AddChild(new OwnerConditionNode(tree, (mob, board) => mob.Poison != null, new CureSelfNode(tree, TimeSpan.FromSeconds(6.0))))
|
||||
.AddChild(new OwnerConditionNode(tree, (mob, board) => mob.HitsMax - mob.Hits >= 40, new HealSelfNode(tree, TimeSpan.FromSeconds(6.0))))
|
||||
.AddChild(new OwnerConditionNode(tree, shouldMeditate, new MeditateNode(tree, 75)))
|
||||
*/
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
50
Projects/UOContent/Mobiles/BehaviorAI/Composite/Selector.cs
Normal file
50
Projects/UOContent/Mobiles/BehaviorAI/Composite/Selector.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Selector : Composite
|
||||
{
|
||||
public Selector(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
}
|
||||
public override void OnChildComplete(BehaviorTreeContext context, Result lastResult)
|
||||
{
|
||||
if (!currentChildCache.TryGetValue(context.Mobile, out int currentChild))
|
||||
{
|
||||
currentChild = 0;
|
||||
currentChildCache.Add(context.Mobile, currentChild);
|
||||
}
|
||||
|
||||
Behavior child = Children[currentChild];
|
||||
|
||||
if (lastResult == Result.Success)
|
||||
{
|
||||
currentChildCache[context.Mobile] = 0;
|
||||
SetResult(context, Result.Success);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Projects/UOContent/Mobiles/BehaviorAI/Composite/Sequence.cs
Normal file
50
Projects/UOContent/Mobiles/BehaviorAI/Composite/Sequence.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Sequence : Composite
|
||||
{
|
||||
public Sequence(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
}
|
||||
public override void OnChildComplete(BehaviorTreeContext context, Result lastResult)
|
||||
{
|
||||
if (!currentChildCache.TryGetValue(context.Mobile, out int currentChild))
|
||||
{
|
||||
currentChild = 0;
|
||||
currentChildCache.Add(context.Mobile, currentChild);
|
||||
}
|
||||
|
||||
Behavior child = Children[currentChild];
|
||||
|
||||
if (lastResult == Result.Failure)
|
||||
{
|
||||
currentChildCache[context.Mobile] = 0;
|
||||
SetResult(context, Result.Failure);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Projects/UOContent/Mobiles/BehaviorAI/Core/Behavior.cs
Normal file
52
Projects/UOContent/Mobiles/BehaviorAI/Core/Behavior.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public delegate void BehaviorObserver(BehaviorTreeContext context, Result lastResult);
|
||||
public enum Result
|
||||
{
|
||||
Success,
|
||||
Failure,
|
||||
Running
|
||||
}
|
||||
public abstract class Behavior
|
||||
{
|
||||
public BehaviorTree Tree { get; protected set; }
|
||||
public BehaviorObserver Observer { get; protected set; }
|
||||
private Dictionary<BaseCreature, Result> lastResultCache;
|
||||
public virtual bool IsRunning(BehaviorTreeContext context) => GetResult(context) == Result.Running;
|
||||
public Behavior(BehaviorTree tree)
|
||||
{
|
||||
Tree = tree;
|
||||
lastResultCache = new Dictionary<BaseCreature, Result>();
|
||||
}
|
||||
public virtual void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
}
|
||||
public virtual void Execute(BehaviorTreeContext context)
|
||||
{
|
||||
}
|
||||
public Result GetResult(BehaviorTreeContext context)
|
||||
{
|
||||
if (!lastResultCache.TryGetValue(context.Mobile, out Result result))
|
||||
{
|
||||
result = Result.Failure;
|
||||
lastResultCache.Add(context.Mobile, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public void SetResult(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
if (!lastResultCache.TryGetValue(context.Mobile, out Result old))
|
||||
{
|
||||
lastResultCache.Add(context.Mobile, Result.Failure);
|
||||
}
|
||||
|
||||
lastResultCache[context.Mobile] = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class BehaviorQueueEntry
|
||||
{
|
||||
public BehaviorTreeContext Context { get; }
|
||||
public BehaviorObserver Observer { get; }
|
||||
public Behavior Behavior { get; }
|
||||
public BehaviorQueueEntry(BehaviorTreeContext context, Behavior behavior, BehaviorObserver observer)
|
||||
{
|
||||
Context = context;
|
||||
Behavior = behavior;
|
||||
Observer = observer;
|
||||
}
|
||||
}
|
||||
}
|
||||
108
Projects/UOContent/Mobiles/BehaviorAI/Core/BehaviorTree.cs
Normal file
108
Projects/UOContent/Mobiles/BehaviorAI/Core/BehaviorTree.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class BehaviorTree
|
||||
{
|
||||
public Behavior Root { get; private set; }
|
||||
private Dictionary<BaseCreature, Queue<BehaviorQueueEntry>> behaviorQueueCache;
|
||||
private Dictionary<BaseCreature, bool> executingCache;
|
||||
public BehaviorTree()
|
||||
{
|
||||
behaviorQueueCache = new Dictionary<BaseCreature, Queue<BehaviorQueueEntry>>();
|
||||
executingCache = new Dictionary<BaseCreature, bool>();
|
||||
}
|
||||
public bool TryAddRoot(Composite behavior)
|
||||
{
|
||||
if (Root == null)
|
||||
{
|
||||
Root = behavior;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void Start(BehaviorTreeContext context)
|
||||
{
|
||||
if (Root != null)
|
||||
{
|
||||
Enqueue(context, Root, ExecutionFinished);
|
||||
}
|
||||
}
|
||||
public void Stop(BehaviorTreeContext context)
|
||||
{
|
||||
getQueue(context).Clear();
|
||||
}
|
||||
public virtual void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (!executingCache.TryGetValue(context.Mobile, out bool executing))
|
||||
{
|
||||
executing = false;
|
||||
executingCache[context.Mobile] = executing;
|
||||
}
|
||||
|
||||
if (!executing)
|
||||
{
|
||||
executingCache[context.Mobile] = true;
|
||||
Queue<BehaviorQueueEntry> queue = getQueue(context);
|
||||
queue.Enqueue(null);
|
||||
while (Step(context))
|
||||
{
|
||||
}
|
||||
executingCache[context.Mobile] = false;
|
||||
}
|
||||
}
|
||||
public virtual bool Step(BehaviorTreeContext context)
|
||||
{
|
||||
Queue<BehaviorQueueEntry> queue = getQueue(context);
|
||||
|
||||
BehaviorQueueEntry current = queue.Dequeue();
|
||||
|
||||
if (current == null || current.Behavior == null || current.Context == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
current.Behavior.Tick(current.Context);
|
||||
|
||||
if (!current.Behavior.IsRunning(current.Context))
|
||||
{
|
||||
if (current.Observer != null)
|
||||
{
|
||||
current.Observer(current.Context, current.Behavior.GetResult(current.Context));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
queue.Enqueue(current);
|
||||
|
||||
return false;
|
||||
}
|
||||
public virtual void ExecutionFinished(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
}
|
||||
public void Enqueue(BehaviorTreeContext context, Behavior behavior, BehaviorObserver observer)
|
||||
{
|
||||
if (!behaviorQueueCache.TryGetValue(context.Mobile, out Queue<BehaviorQueueEntry> queue))
|
||||
{
|
||||
queue = new Queue<BehaviorQueueEntry>();
|
||||
behaviorQueueCache.Add(context.Mobile, queue);
|
||||
}
|
||||
|
||||
queue.Enqueue(new BehaviorQueueEntry(context, behavior, observer));
|
||||
}
|
||||
private Queue<BehaviorQueueEntry> getQueue(BehaviorTreeContext context)
|
||||
{
|
||||
if (!behaviorQueueCache.TryGetValue(context.Mobile, out Queue<BehaviorQueueEntry> queue))
|
||||
{
|
||||
queue = new Queue<BehaviorQueueEntry>();
|
||||
behaviorQueueCache.Add(context.Mobile, queue);
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class BehaviorTreeContext
|
||||
{
|
||||
public BaseCreature Mobile { get; }
|
||||
public Blackboard Blackboard { get; }
|
||||
public BehaviorTreeContext(BaseCreature mob, Blackboard blackboard)
|
||||
{
|
||||
Mobile = mob;
|
||||
Blackboard = blackboard;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Projects/UOContent/Mobiles/BehaviorAI/Core/Blackboard.cs
Normal file
12
Projects/UOContent/Mobiles/BehaviorAI/Core/Blackboard.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Blackboard : Dictionary<string, object>
|
||||
{
|
||||
}
|
||||
}
|
||||
51
Projects/UOContent/Mobiles/BehaviorAI/Core/Composite.cs
Normal file
51
Projects/UOContent/Mobiles/BehaviorAI/Core/Composite.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Composite : Behavior
|
||||
{
|
||||
public List<Behavior> Children { get; private set; }
|
||||
protected Dictionary<BaseCreature, int> currentChildCache;
|
||||
public Composite(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
Children = new List<Behavior>();
|
||||
currentChildCache = new Dictionary<BaseCreature, int>();
|
||||
}
|
||||
public Composite AddChild(Behavior child)
|
||||
{
|
||||
if (Children != null && child != null)
|
||||
{
|
||||
Children.Add(child);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (!currentChildCache.TryGetValue(context.Mobile, out int currentChild))
|
||||
{
|
||||
currentChild = 0;
|
||||
currentChildCache.Add(context.Mobile, currentChild);
|
||||
}
|
||||
|
||||
if (GetResult(context) != Result.Running)
|
||||
{
|
||||
currentChild = 0;
|
||||
currentChildCache[context.Mobile] = currentChild;
|
||||
SetResult(context, Result.Running);
|
||||
if (Children[currentChild] == null)
|
||||
{
|
||||
throw new NullReferenceException();
|
||||
}
|
||||
Tree.Enqueue(context, Children[currentChild], OnChildComplete);
|
||||
}
|
||||
}
|
||||
public virtual void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Projects/UOContent/Mobiles/BehaviorAI/Core/Decorator.cs
Normal file
42
Projects/UOContent/Mobiles/BehaviorAI/Core/Decorator.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Decorator : Behavior
|
||||
{
|
||||
public Behavior Child { get; private set; }
|
||||
public Decorator(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
}
|
||||
public Decorator(BehaviorTree tree, Behavior child) : base(tree)
|
||||
{
|
||||
Child = child;
|
||||
}
|
||||
public virtual bool AddChild(Behavior child)
|
||||
{
|
||||
if (Child == null)
|
||||
{
|
||||
Child = child;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (Child != null && GetResult(context) != Result.Running)
|
||||
{
|
||||
Tree.Enqueue(context, Child, OnChildComplete);
|
||||
SetResult(context, Result.Running);
|
||||
return;
|
||||
}
|
||||
}
|
||||
public virtual void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
SetResult(context, Child.GetResult(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
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);
|
||||
public class ConditionalLoop : Decorator
|
||||
{
|
||||
public ConditionalLoopPredicate Predicate { get; private set; }
|
||||
public ConditionalLoop(BehaviorTree tree, ConditionalLoopPredicate predicate) : base(tree)
|
||||
{
|
||||
Predicate = predicate;
|
||||
}
|
||||
public ConditionalLoop(BehaviorTree tree, ConditionalLoopPredicate predicate, Behavior child) : base(tree, child)
|
||||
{
|
||||
Predicate = predicate;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (Predicate(context))
|
||||
{
|
||||
base.Tick(context);
|
||||
return;
|
||||
}
|
||||
SetResult(context, Result.Failure);
|
||||
return;
|
||||
}
|
||||
public override void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
if (Predicate(context))
|
||||
{
|
||||
Tree.Enqueue(context, Child, OnChildComplete);
|
||||
return;
|
||||
}
|
||||
SetResult(context, Result.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Projects/UOContent/Mobiles/BehaviorAI/Decorator/Cooldown.cs
Normal file
57
Projects/UOContent/Mobiles/BehaviorAI/Decorator/Cooldown.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Cooldown : Decorator
|
||||
{
|
||||
public TimeSpan Duration { get; }
|
||||
private Dictionary<BaseCreature, long> nextCooldownCache;
|
||||
public Cooldown(BehaviorTree tree, TimeSpan duration) : base(tree)
|
||||
{
|
||||
nextCooldownCache = new Dictionary<BaseCreature, long>();
|
||||
Duration = duration;
|
||||
}
|
||||
public Cooldown(BehaviorTree tree, TimeSpan duration, Behavior child) : base(tree, child)
|
||||
{
|
||||
nextCooldownCache = new Dictionary<BaseCreature, long>();
|
||||
Duration = duration;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if(!nextCooldownCache.TryGetValue(context.Mobile, out long nextCooldown))
|
||||
{
|
||||
nextCooldown = Core.TickCount;
|
||||
nextCooldownCache.Add(context.Mobile, nextCooldown);
|
||||
}
|
||||
|
||||
if (Core.TickCount > nextCooldown)
|
||||
{
|
||||
base.Tick(context);
|
||||
}
|
||||
}
|
||||
public override void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
if (!nextCooldownCache.TryGetValue(context.Mobile, out long nextCooldown))
|
||||
{
|
||||
nextCooldown = Core.TickCount;
|
||||
nextCooldownCache.Add(context.Mobile, nextCooldown);
|
||||
}
|
||||
|
||||
if (Child != null)
|
||||
{
|
||||
if (Child.GetResult(context) == Result.Success)
|
||||
{
|
||||
nextCooldownCache[context.Mobile] = Core.TickCount + Duration.Ticks;
|
||||
}
|
||||
SetResult(context, Child.GetResult(context));
|
||||
return;
|
||||
}
|
||||
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class ForceSuccess : Decorator
|
||||
{
|
||||
public ForceSuccess(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
}
|
||||
public ForceSuccess(BehaviorTree tree, Behavior child) : base(tree, child)
|
||||
{
|
||||
}
|
||||
public override void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
SetResult(context, Result.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
29
Projects/UOContent/Mobiles/BehaviorAI/Decorator/Inverter.cs
Normal file
29
Projects/UOContent/Mobiles/BehaviorAI/Decorator/Inverter.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Inverter : Decorator
|
||||
{
|
||||
public Inverter(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
}
|
||||
public Inverter(BehaviorTree tree, Behavior child) : base(tree, child)
|
||||
{
|
||||
}
|
||||
public override void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
if (result == Result.Success)
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetResult(context, Result.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Projects/UOContent/Mobiles/BehaviorAI/Decorator/Loop.cs
Normal file
57
Projects/UOContent/Mobiles/BehaviorAI/Decorator/Loop.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class Loop : Decorator
|
||||
{
|
||||
private Dictionary<BaseCreature, int> currentIterationCache;
|
||||
private int totalIterations;
|
||||
public Loop(BehaviorTree tree, int n) : base(tree)
|
||||
{
|
||||
currentIterationCache = new Dictionary<BaseCreature, int>();
|
||||
totalIterations = n;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (!currentIterationCache.TryGetValue(context.Mobile, out int iteration))
|
||||
{
|
||||
iteration = 0;
|
||||
currentIterationCache.Add(context.Mobile, iteration);
|
||||
}
|
||||
|
||||
base.Tick(context);
|
||||
}
|
||||
public override void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
if (!currentIterationCache.TryGetValue(context.Mobile, out int iteration))
|
||||
{
|
||||
iteration = 0;
|
||||
currentIterationCache.Add(context.Mobile, iteration);
|
||||
}
|
||||
|
||||
iteration++;
|
||||
|
||||
if (iteration >= totalIterations)
|
||||
{
|
||||
currentIterationCache[context.Mobile] = 0;
|
||||
SetResult(context, Result.Success);
|
||||
return;
|
||||
}
|
||||
|
||||
currentIterationCache[context.Mobile] = iteration;
|
||||
|
||||
if (Child != null)
|
||||
{
|
||||
Tree.Enqueue(context, Child, OnChildComplete);
|
||||
return;
|
||||
}
|
||||
|
||||
currentIterationCache[context.Mobile] = 0;
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
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);
|
||||
public class OwnerCondition : Decorator
|
||||
{
|
||||
public OwnerConditionPredicate Predicate { get; }
|
||||
public OwnerCondition(BehaviorTree tree, OwnerConditionPredicate predicate) : base(tree)
|
||||
{
|
||||
Predicate = predicate;
|
||||
}
|
||||
public OwnerCondition(BehaviorTree tree, OwnerConditionPredicate predicate, Behavior child) : base(tree, child)
|
||||
{
|
||||
Predicate = predicate;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (Predicate(context))
|
||||
{
|
||||
base.Tick(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Projects/UOContent/Mobiles/BehaviorAI/Decorator/UntilFail.cs
Normal file
30
Projects/UOContent/Mobiles/BehaviorAI/Decorator/UntilFail.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class UntilFail : Decorator
|
||||
{
|
||||
public UntilFail(BehaviorTree tree): base(tree)
|
||||
{
|
||||
}
|
||||
public UntilFail(BehaviorTree tree, Behavior child) : base(tree, child)
|
||||
{
|
||||
}
|
||||
public override void OnChildComplete(BehaviorTreeContext context, Result result)
|
||||
{
|
||||
if (Child != null)
|
||||
{
|
||||
if (Child.GetResult(context) == Result.Failure)
|
||||
{
|
||||
SetResult(context, Result.Success);
|
||||
return;
|
||||
}
|
||||
Tree.Enqueue(context, Child, OnChildComplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Projects/UOContent/Mobiles/BehaviorAI/Leaf/AutoTarget.cs
Normal file
56
Projects/UOContent/Mobiles/BehaviorAI/Leaf/AutoTarget.cs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class AutoTarget : Behavior
|
||||
{
|
||||
public AutoTarget(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
Target target = context.Mobile.Target;
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
return;
|
||||
}
|
||||
|
||||
Mobile combatant = context.Mobile.Combatant;
|
||||
|
||||
if ((target.Flags & TargetFlags.Harmful) != 0 && combatant != null)
|
||||
{
|
||||
if (combatant.Deleted)
|
||||
{
|
||||
target.Cancel(context.Mobile, TargetCancelType.Canceled);
|
||||
SetResult(context, Result.Failure);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((target.Range == -1 || context.Mobile.InRange(combatant, target.Range)) &&
|
||||
context.Mobile.CanSee(combatant) &&
|
||||
context.Mobile.InLOS(combatant)
|
||||
)
|
||||
{
|
||||
target.Invoke(context.Mobile, combatant);
|
||||
SetResult(context, Result.Success);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ((target.Flags & TargetFlags.Beneficial) != 0)
|
||||
{
|
||||
target.Invoke(context.Mobile, context.Mobile);
|
||||
SetResult(context, Result.Success);
|
||||
return;
|
||||
}
|
||||
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Projects/UOContent/Mobiles/BehaviorAI/Leaf/CastSpell.cs
Normal file
70
Projects/UOContent/Mobiles/BehaviorAI/Leaf/CastSpell.cs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Spells;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public delegate Spell CastSpellCallback(BehaviorTreeContext context);
|
||||
public class CastSpell : Behavior
|
||||
{
|
||||
public CastSpellCallback Callback { get; }
|
||||
public CastSpell(BehaviorTree tree, CastSpellCallback callback) : base(tree)
|
||||
{
|
||||
Callback = callback;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
BaseCreature owner = context.Mobile;
|
||||
|
||||
if (owner.Spell == null)
|
||||
{
|
||||
Spell spell = Callback(context);
|
||||
|
||||
if (owner.Mana < spell.GetMana())
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
owner.DebugSay("Not enough mana...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Core.TickCount < owner.NextSpellTime)
|
||||
{
|
||||
SetResult(context, Result.Running);
|
||||
owner.DebugSay("On cooldown...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!spell.Cast())
|
||||
{
|
||||
SetResult(context, Result.Running);
|
||||
owner.DebugSay("Failed to cast...");
|
||||
return;
|
||||
}
|
||||
|
||||
owner.DebugSay("Casting {0}...", spell.Name);
|
||||
if (!string.IsNullOrEmpty(spell.Mantra))
|
||||
owner.PublicOverheadMessage(Network.MessageType.Spell, owner.SpeechHue, false, spell.Mantra, false);
|
||||
|
||||
SetResult(context, Result.Running);
|
||||
return;
|
||||
}
|
||||
else if (owner.Spell.IsCasting)
|
||||
{
|
||||
SetResult(context, Result.Running);
|
||||
owner.DebugSay("Already casting {0}...", ((Spell)owner.Spell).Name);
|
||||
return;
|
||||
}
|
||||
else if (!owner.Spell.IsCasting)
|
||||
{
|
||||
SetResult(context, Result.Success);
|
||||
owner.DebugSay("Finished casting {0}...", ((Spell)owner.Spell).Name);
|
||||
return;
|
||||
}
|
||||
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Projects/UOContent/Mobiles/BehaviorAI/Leaf/Condition.cs
Normal file
29
Projects/UOContent/Mobiles/BehaviorAI/Leaf/Condition.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
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);
|
||||
public class Condition : Behavior
|
||||
{
|
||||
public ConditionPredicate Predicate { get; }
|
||||
public Condition(BehaviorTree tree, ConditionPredicate predicate) : base(tree)
|
||||
{
|
||||
Predicate = predicate;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if(Predicate(context))
|
||||
{
|
||||
SetResult(context, Result.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Projects/UOContent/Mobiles/BehaviorAI/Leaf/DynamicTarget.cs
Normal file
46
Projects/UOContent/Mobiles/BehaviorAI/Leaf/DynamicTarget.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public delegate object DynamicTargetCallback(BehaviorTreeContext context);
|
||||
public class DynamicTarget : Behavior
|
||||
{
|
||||
public DynamicTargetCallback Transformation { get; private set; }
|
||||
public DynamicTarget(BehaviorTree tree, DynamicTargetCallback transformation) : base(tree)
|
||||
{
|
||||
Transformation = transformation;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (Transformation != null)
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
return;
|
||||
}
|
||||
|
||||
Target target = context.Mobile.Target;
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
return;
|
||||
}
|
||||
|
||||
object targeted = Transformation(context);
|
||||
|
||||
if (targeted == null)
|
||||
{
|
||||
SetResult(context, Result.Failure);
|
||||
return;
|
||||
}
|
||||
|
||||
target.Invoke(context.Mobile, targeted);
|
||||
SetResult(context, Result.Success);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Projects/UOContent/Mobiles/BehaviorAI/Leaf/Tap.cs
Normal file
23
Projects/UOContent/Mobiles/BehaviorAI/Leaf/Tap.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
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);
|
||||
public class Tap : Behavior
|
||||
{
|
||||
public TapAction Action { get; private set; }
|
||||
public Tap(BehaviorTree tree, TapAction action) : base(tree)
|
||||
{
|
||||
Action = action;
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
Action(context);
|
||||
SetResult(context, Result.Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Projects/UOContent/Mobiles/BehaviorAI/Leaf/WaitForTarget.cs
Normal file
24
Projects/UOContent/Mobiles/BehaviorAI/Leaf/WaitForTarget.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Mobiles.BehaviorAI
|
||||
{
|
||||
public class WaitForTarget : Behavior
|
||||
{
|
||||
public WaitForTarget(BehaviorTree tree) : base(tree)
|
||||
{
|
||||
}
|
||||
public override void Tick(BehaviorTreeContext context)
|
||||
{
|
||||
if (context.Mobile.Target != null)
|
||||
{
|
||||
SetResult(context, Result.Success);
|
||||
return;
|
||||
}
|
||||
SetResult(context, Result.Running);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,8 @@ namespace Server.Mobiles
|
|||
[Constructible]
|
||||
public BehaviorMage() : base(AIType.AI_BehaviorTree, FightMode.Evil, 2, 0, 0.01, 3)
|
||||
{
|
||||
Debug = true;
|
||||
|
||||
InitBody();
|
||||
|
||||
SetStr(100, 100);
|
||||
|
|
@ -32,6 +34,7 @@ namespace Server.Mobiles
|
|||
SetSkill(SkillName.MagicResist, 100.0);
|
||||
SetSkill(SkillName.Tactics, 100.0);
|
||||
SetSkill(SkillName.Meditation, 100.0);
|
||||
SetSkill(SkillName.Wrestling, 100.0);
|
||||
|
||||
AddItem(new Backpack() { Movable = false });
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue