blizzless-diiis/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/HirelingBrain.cs
2023-01-29 23:55:03 +01:00

166 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using DiIiS_NA.Core.Extensions;
using DiIiS_NA.Core.Helpers.Math;
using DiIiS_NA.Core.MPQ;
using DiIiS_NA.GameServer.Core.Types.Math;
using DiIiS_NA.GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Actions;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Hirelings;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Movement;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.GSSystem.PowerSystem;
using DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations;
using DiIiS_NA.GameServer.GSSystem.TickerSystem;
using DiIiS_NA.GameServer.MessageSystem;
namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
{
public class HirelingBrain : Brain
{
public Player Owner { get; private set; }
public List<int> PresetPowers { get; private set; }
private Actor _target { get; set; }
private TickTimer _powerDelay;
private bool Feared = false;
public HirelingBrain(Actor body, Player master)
: base(body)
{
Owner = master;
PresetPowers = new List<int>();
if (body is Templar && body is MalthaelHireling)
PresetPowers.Add(30592); //melee instant
if (body is Scoundrel)
PresetPowers.Add(99902); //Scoundrel_ranged_Projectile
if (body is Enchantress)
PresetPowers.Add(30273); //HirelingMage_MagicMissile
if (body is Leah)
PresetPowers.Add(99902); //Scoundrel_ranged_Projectile
}
public override void Think(int tickCounter)
{
if (Owner == null) return;
if (Body.World.Game.Paused) return;
// check if in disabled state, if so cancel any action then do nothing
if (Body.Attributes[GameAttribute.Frozen] ||
Body.Attributes[GameAttribute.Stunned] ||
Body.Attributes[GameAttribute.Blind] ||
Body.Attributes[GameAttribute.Webbed] ||
Body.Disable ||
Body.World.BuffManager.GetFirstBuff<KnockbackBuff>(Body) != null)
{
if (CurrentAction != null)
{
CurrentAction.Cancel(tickCounter);
CurrentAction = null;
}
_powerDelay = null;
return;
}
if (Body.Attributes[GameAttribute.Feared])
{
if (!Feared || CurrentAction == null)
{
if (CurrentAction != null)
{
CurrentAction.Cancel(tickCounter);
CurrentAction = null;
}
Feared = true;
CurrentAction = new MoveToPointWithPathfindAction(
Body,
PowerContext.RandomDirection(Body.Position, 3f, 8f)
);
return;
}
else return;
}
else
Feared = false;
// select and start executing a power if no active action
if (CurrentAction == null)
{
// do a little delay so groups of monsters don't all execute at once
if (_powerDelay == null)
_powerDelay = new SecondsTickTimer(Body.World.Game, 1f);
var targets = Owner.GetObjectsInRange<Monster>(40f).Where(p => !p.Dead && p.Visible).OrderBy(m => PowerMath.Distance2D(m.Position, Body.Position)).ToList();
if (targets.Count != 0 && PowerMath.Distance2D(Body.Position, Owner.Position) < 80f)
{
int powerToUse = PickPowerToUse();
if (powerToUse > 0)
{
var elite = targets.FirstOrDefault(t => t is Champion or Rare or RareMinion);
_target = elite ?? targets.First();
PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse);
power.User = Body;
float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f ? (powerToUse == 30592 ? 10f : power.EvalTag(PowerKeys.AttackRadius)) : 35f);
float targetDistance = PowerMath.Distance2D(_target.Position, Body.Position);
if (targetDistance < attackRange + _target.ActorData.Cylinder.Ax2)
{
if (_powerDelay.TimedOut)
{
_powerDelay = null;
Body.TranslateFacing(_target.Position, false);
CurrentAction = new PowerAction(Body, powerToUse, _target);
}
}
else
{
CurrentAction = new MoveToTargetWithPathfindAction(
Body,
_target,
attackRange + _target.ActorData.Cylinder.Ax2
);
}
}
}
else
{
var distToMaster = PowerMath.Distance2D(Body.Position, Owner.Position);
if ((distToMaster > 8f) || (distToMaster < 3f))
{
var Rand = FastRandom.Instance;
var position = Owner.Position;
float angle = (float)(Rand.NextDouble() * Math.PI * 2);
float radius = 3f + (float)Rand.NextDouble() * (8f - 3f);
var near = new Vector3D(position.X + (float)Math.Cos(angle) * radius, position.Y + (float)Math.Sin(angle) * radius, position.Z);
CurrentAction = new MoveToPointAction(Body, near);
}
}
}
}
protected virtual int PickPowerToUse()
{
// randomly used an implemented power
var implementedPowers = PresetPowers.Where(PowerLoader.HasImplementationForPowerSNO);
return implementedPowers.TryPickRandom(out var randomPower)
? randomPower
: -1;
}
public void AddPresetPower(int powerSNO)
{
PresetPowers.Add(powerSNO);
}
}
}