Skip to content

Commit

Permalink
HS-1280: initial implementation of fear/charm conditions (with monste…
Browse files Browse the repository at this point in the history
…r targets)
  • Loading branch information
baughj committed Jan 15, 2024
1 parent 36a38fc commit a5ee019
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 72 deletions.
4 changes: 4 additions & 0 deletions hybrasyl/Objects/Creature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public Creature LastHitter
set => _mLastHitter = value?.Id ?? 0;
}

public Creature LastTarget { get; set; }

public bool AbsoluteImmortal { get; set; }
public bool PhysicalImmortal { get; set; }
public bool MagicalImmortal { get; set; }
Expand Down Expand Up @@ -646,6 +648,8 @@ public virtual bool UseCastable(Castable castableXml, Creature target = null)
$"UseCastable: {Name} casting {castableXml.Name} - failed to remove status {status}, does not exist!");
}
}

LastTarget = tar;
}

// Now flood away
Expand Down
154 changes: 82 additions & 72 deletions hybrasyl/Objects/Monster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,9 @@ public void ProcessActions()
while (!_actionQueue.IsEmpty)
{
_actionQueue.TryDequeue(out var action);
List<Creature> targets = new();
var nextCastable = CastableController.GetNextCastable();

GameLog.SpawnDebug($"ActionQueue: {action}");
switch (action)
{
Expand All @@ -922,34 +925,38 @@ public void ProcessActions()
}
break;
case MobAction.Attack:
var next = CastableController.GetNextCastable();
if (next is null)
if (nextCastable is null)
{
Attack();
return;
}

var targets = ThreatInfo.GetTargets(next.CurrentPriority);
targets = ThreatInfo.GetTargets(nextCastable.CurrentPriority);
if (targets.Count == 0)
{
GameLog.SpawnDebug(
$"{Name}: ({Map.Name}@{X},{Y}): no targets returned from priority {next.CurrentPriority}");
$"{Name}: ({Map.Name}@{X},{Y}): no targets returned from priority {nextCastable.CurrentPriority}");
return;
}

if (targets.Count == 1 && next.Slot.Castable.IsAssail)
if (targets.Count != 0 && nextCastable.Slot.Castable.IsAssail)
{
if (Distance(ThreatInfo.HighestThreat) > 1)
var target = targets.First();
if (Distance(target) > 1)
{
_actionQueue.Enqueue(MobAction.Move);
return;
}

if (!CheckFacing(Direction, ThreatInfo.HighestThreat))
Turn(Relation(ThreatInfo.HighestThreat.X, ThreatInfo.HighestThreat.Y));
if (!CheckFacing(Direction, targets.First()))
Turn(Relation(targets.First().X, targets.First().Y));
return;
}

foreach (var target in targets) Cast(next.Slot, target);
foreach (var target in targets)
{
Cast(nextCastable.Slot, target);
LastTarget = target;
}

return;
case MobAction.Move when !Condition.MovementAllowed:
Expand All @@ -974,69 +981,72 @@ public void ProcessActions()

break;
}
case MobAction.Move:
{
if (ThreatInfo.HighestThreat == null)
{
ShouldWander = true;
return;
}

if (Condition.MovementAllowed)
{
if (CurrentPath == null || !AStarPathClear())
// If we don't have a current path to our threat target, OR if there is something in the way of
// our existing path, calculate a new one
{
if (CurrentPath == null) GameLog.Info("Path is null. Recalculating");
if (!AStarPathClear()) GameLog.Info("Path wasn't clear. Recalculating");
Target = ThreatInfo.HighestThreat;
CurrentPath = AStarPathFind(ThreatInfo.HighestThreat.Location.X,
ThreatInfo.HighestThreat.Location.Y, X, Y);
}

if (CurrentPath != null)
{
// We have a path, check its validity
// We recalculate our path if we're within five spaces of the target and they have moved

if (Distance(ThreatInfo.HighestThreat) < 5 &&
CurrentPath.Target.X != ThreatInfo.HighestThreat.Location.X &&
CurrentPath.Target.Y != ThreatInfo.HighestThreat.Location.Y)
{
GameLog.Info("Distance less than five and target moved, recalculating path");
CurrentPath = AStarPathFind(ThreatInfo.HighestThreat.Location.X,
ThreatInfo.HighestThreat.Location.Y, X, Y);
}

if (Walk(AStarGetDirection()))
{
if (X != CurrentPath.X || Y != CurrentPath.Y)
GameLog.SpawnError(
$"Walk: followed astar path but not on path (at {X},{Y} path is {CurrentPath.X}, {CurrentPath.Y}");
// We've moved; update our path
CurrentPath = CurrentPath.Parent;
}
else
// Couldn't move, attempt to recalculate path
{
CurrentPath = AStarPathFind(ThreatInfo.HighestThreat.Location.X,
ThreatInfo.HighestThreat.Location.Y, X, Y);
}
}
else
// If we can't find a path, return to wandering
{
ShouldWander = true;
}
}
else
{
GameLog.SpawnError("Can't move");
}

break;
case MobAction.Move:
{
var target = ThreatInfo.GetTargets(nextCastable.CurrentPriority).FirstOrDefault();

if (target == null)
{
ShouldWander = true;
return;
}

LastTarget = target;
if (Condition.MovementAllowed)
{
if (CurrentPath == null || !AStarPathClear())
// If we don't have a current path to our threat target, OR if there is something in the way of
// our existing path, calculate a new one
{
if (CurrentPath == null) GameLog.Info("Path is null. Recalculating");
if (!AStarPathClear()) GameLog.Info("Path wasn't clear. Recalculating");
Target = target;
CurrentPath = AStarPathFind(Target.Location.X,
Target.Location.Y, X, Y);
}

if (CurrentPath != null)
{
// We have a path, check its validity
// We recalculate our path if we're within five spaces of the target and they have moved

if (Distance(target) < 5 &&
CurrentPath.Target.X != target.Location.X &&
CurrentPath.Target.Y != target.Location.Y)
{
GameLog.Info("Distance less than five and target moved, recalculating path");
CurrentPath = AStarPathFind(target.Location.X,
target.Location.Y, X, Y);
}

if (Walk(AStarGetDirection()))
{
if (X != CurrentPath.X || Y != CurrentPath.Y)
GameLog.SpawnError(
$"Walk: followed astar path but not on path (at {X},{Y} path is {CurrentPath.X}, {CurrentPath.Y}");
// We've moved; update our path
CurrentPath = CurrentPath.Parent;
}
else
// Couldn't move, attempt to recalculate path
{
CurrentPath = AStarPathFind(target.Location.X,
target.Location.Y, X, Y);
}
}
else
// If we can't find a path, return to wandering
{
ShouldWander = true;
}
}
else
{
GameLog.SpawnError("Can't move");
}

break;
}
case MobAction.Idle:
//do nothing
break;
Expand Down
10 changes: 10 additions & 0 deletions hybrasyl/Objects/ThreatInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ public List<Creature> GetTargets(CreatureTargetPriority priority)
var ret = new List<Creature>();
if (OwnerObject == null) return ret;
ThreatEntry entry;
if (OwnerObject.Condition.Charmed)
{
// Generate target list: for every creature in threat table, last target of that creature; if nothing found, use monsters in viewport
ret.AddRange(ThreatTableByCreature.Values.Where(x => x.TargetObject is User { LastTarget: not null })
.Select(y => y.TargetObject).ToList());
if (ret.Count == 0)
ret.AddRange(OwnerObject.Map.EntityTree.GetObjects(OwnerObject.GetViewport()).OfType<Monster>().ToList());
return ret;
}

switch (priority)
{
case CreatureTargetPriority.HighThreat:
Expand Down
1 change: 1 addition & 0 deletions hybrasyl/Objects/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2850,6 +2850,7 @@ public void AssailAttack(Direction direction, Creature target = null)
if (target != null && target.GetType() != typeof(Merchant))
{
UseSkill(SkillBook.SlotOf(c.Castable.Name));
LastTarget = target;
animation = true;
}

Expand Down

0 comments on commit a5ee019

Please sign in to comment.