WIP-broken

This commit is contained in:
Kamron Batman 2021-10-16 19:22:19 -07:00
parent 380f40890c
commit bb2999d3ab
No known key found for this signature in database
GPG key ID: 5C9DFD15804B6BB8
8 changed files with 63 additions and 73 deletions

View file

@ -13,8 +13,8 @@ namespace Server.Mobiles.AI
public class BehaviorTreeAI : BaseAI
{
private Blackboard blackboard;
private BehaviorTree behaviorTree;
private BehaviorTreeContext behaviorTreeContext;
private readonly BehaviorTree behaviorTree;
private readonly BehaviorTreeContext behaviorTreeContext;
public BehaviorTreeAI(BaseCreature m) : base(m)
{
// blackboard = new Blackboard();
@ -25,13 +25,13 @@ namespace Server.Mobiles.AI
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))
*/
/*
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);

View file

@ -40,16 +40,20 @@ namespace Server.Mobiles.BT
}
if (!string.IsNullOrEmpty(spell.Mantra))
{
mob.PublicOverheadMessage(Network.MessageType.Spell, 0, false, spell.Mantra, false);
}
return Result.Running;
}
else if (mob.Spell.IsCasting)
if (mob.Spell.IsCasting)
{
mob.DebugSay("Still casting...");
return Result.Running;
}
else if (!mob.Spell.IsCasting)
if (!mob.Spell.IsCasting)
{
mob.DebugSay("Finished casting...");
return Result.Success;

View file

@ -73,14 +73,18 @@ namespace Server.Mobiles.BT
}
if (mob.Combatant.Meditating)
{
return true;
}
return false;
}
private static bool shouldContinueCombo(BaseCreature mob, Blackboard board)
{
if (mob.Combatant == null || mob.Combatant.Deleted)
{
return false;
}
if (mob.Combatant.HitsMax - mob.Combatant.Hits >= 70)
{

View file

@ -7,13 +7,15 @@ namespace Server.Mobiles.BehaviorAI
{
Success,
Failure,
Running
Running,
Terminated
}
public abstract class Behavior
{
public BehaviorTree Tree { get; protected set; }
public BehaviorObserver Observer { get; protected set; }
private Dictionary<BaseCreature, Result> lastResultCache;
private readonly Dictionary<BaseCreature, Result> lastResultCache;
public virtual bool IsRunning(BehaviorTreeContext context) => GetResult(context) == Result.Running;
public Behavior(BehaviorTree tree)
{
@ -30,14 +32,15 @@ namespace Server.Mobiles.BehaviorAI
{
if (!lastResultCache.TryGetValue(context.Mobile, out Result result))
{
result = Result.Failure;
result = Result.Terminated;
lastResultCache.Add(context.Mobile, result);
}
return result;
}
public void SetResult(BehaviorTreeContext context, Result result)
{
if (!lastResultCache.TryGetValue(context.Mobile, out Result old))
if (!lastResultCache.TryGetValue(context.Mobile, out _))
{
lastResultCache.Add(context.Mobile, Result.Failure);
}

View file

@ -9,12 +9,12 @@ namespace Server.Mobiles.BehaviorAI
public class BehaviorTree
{
public Behavior Root { get; private set; }
private Dictionary<BaseCreature, Queue<BehaviorQueueEntry>> behaviorQueueCache;
private Dictionary<BaseCreature, bool> executingCache;
private readonly Dictionary<BaseCreature, Queue<BehaviorQueueEntry>> _behaviorQueueCache;
private readonly Dictionary<BaseCreature, bool> _executingCache;
public BehaviorTree()
{
behaviorQueueCache = new Dictionary<BaseCreature, Queue<BehaviorQueueEntry>>();
executingCache = new Dictionary<BaseCreature, bool>();
_behaviorQueueCache = new Dictionary<BaseCreature, Queue<BehaviorQueueEntry>>();
_executingCache = new Dictionary<BaseCreature, bool>();
}
public bool TryAddRoot(Composite behavior)
{
@ -38,30 +38,29 @@ namespace Server.Mobiles.BehaviorAI
}
public virtual void Tick(BehaviorTreeContext context)
{
if (!executingCache.TryGetValue(context.Mobile, out bool executing))
if (!_executingCache.TryGetValue(context.Mobile, out bool executing))
{
executing = false;
executingCache[context.Mobile] = executing;
_executingCache[context.Mobile] = executing;
}
if (!executing)
{
executingCache[context.Mobile] = true;
_executingCache[context.Mobile] = true;
Queue<BehaviorQueueEntry> queue = getQueue(context);
queue.Enqueue(null);
while (Step(context))
{
}
executingCache[context.Mobile] = false;
_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)
if (current?.Behavior == null || current.Context == null)
{
return false;
}
@ -70,10 +69,8 @@ namespace Server.Mobiles.BehaviorAI
if (!current.Behavior.IsRunning(current.Context))
{
if (current.Observer != null)
{
current.Observer(current.Context, current.Behavior.GetResult(current.Context));
}
current.Observer?.Invoke(current.Context, current.Behavior.GetResult(current.Context));
current.Behavior.SetResult(context, Result.Terminated);
return true;
}
@ -86,20 +83,20 @@ namespace Server.Mobiles.BehaviorAI
}
public void Enqueue(BehaviorTreeContext context, Behavior behavior, BehaviorObserver observer)
{
if (!behaviorQueueCache.TryGetValue(context.Mobile, out Queue<BehaviorQueueEntry> queue))
if (!_behaviorQueueCache.TryGetValue(context.Mobile, out Queue<BehaviorQueueEntry> queue))
{
queue = new Queue<BehaviorQueueEntry>();
behaviorQueueCache.Add(context.Mobile, queue);
_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))
if (!_behaviorQueueCache.TryGetValue(context.Mobile, out Queue<BehaviorQueueEntry> queue))
{
queue = new Queue<BehaviorQueueEntry>();
behaviorQueueCache.Add(context.Mobile, queue);
_behaviorQueueCache.Add(context.Mobile, queue);
}
return queue;
@ -195,38 +192,18 @@ namespace Server.Mobiles.BehaviorAI
{
var random = Utility.Random(0, 32);
Direction direction;
switch (random)
Direction direction = random switch
{
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;
}
0 => Direction.Up,
1 => Direction.North,
2 => Direction.Left,
3 => Direction.West,
5 => Direction.Down,
6 => Direction.South,
7 => Direction.Right,
8 => Direction.East,
_ => mob.Direction
};
DoMove(context, direction, run);
}
@ -327,7 +304,9 @@ namespace Server.Mobiles.BehaviorAI
}
if (obstacles.Count > 0)
{
blocked = true;
}
while (obstacles.Count > 0)
{

View file

@ -27,7 +27,7 @@ namespace Server.Mobiles.BehaviorAI
currentChildCache.Add(context.Mobile, currentChild);
}
if (GetResult(context) != Result.Running)
if (GetResult(context) != Result.Terminated)
{
currentChild = 0;
currentChildCache[context.Mobile] = currentChild;

View file

@ -12,19 +12,15 @@ namespace Server.Mobiles.BehaviorAI
}
public virtual Decorator AddChild(Behavior child)
{
if (Child == null)
{
Child = child;
}
Child ??= child;
return this;
}
public override void Tick(BehaviorTreeContext context)
{
if (Child != null && GetResult(context) != Result.Running)
if (Child != null && GetResult(context) != Result.Terminated)
{
Tree.Enqueue(context, Child, OnChildComplete);
SetResult(context, Result.Running);
return;
}
}
public virtual void OnChildComplete(BehaviorTreeContext context, Result lastResult)

View file

@ -41,18 +41,22 @@ namespace Server.Mobiles.BehaviorAI
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)
if (owner.Spell.IsCasting)
{
SetResult(context, Result.Running);
owner.DebugSay("Already casting {0}...", ((Spell)owner.Spell).Name);
return;
}
else if (!owner.Spell.IsCasting && ((Spell)owner.Spell).State == SpellState.Sequencing)
if (!owner.Spell.IsCasting && ((Spell)owner.Spell).State == SpellState.Sequencing)
{
SetResult(context, Result.Success);
owner.DebugSay("Finished casting {0}...", ((Spell)owner.Spell).Name);