starting monster brain

This commit is contained in:
Lucca Faria Ferri 2023-07-20 05:18:38 -07:00
parent 3c851ddf1c
commit 09e0480485

View File

@ -23,7 +23,8 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
{ {
public class MonsterBrain : Brain public class MonsterBrain : Brain
{ {
private new readonly Logger Logger; private new readonly Logger _logger;
// list of power SNOs that are defined for the monster // list of power SNOs that are defined for the monster
public Dictionary<int, Cooldown> PresetPowers { get; private set; } public Dictionary<int, Cooldown> PresetPowers { get; private set; }
@ -36,9 +37,9 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
} }
private bool _warnedNoPowers; private bool _warnedNoPowers;
private Actor _target { get; set; } private Actor Target { get; set; }
private int _mpqPowerCount; private int _mpqPowerCount;
private bool Feared = false; private bool _feared = false;
public Actor AttackedBy = null; public Actor AttackedBy = null;
public TickTimer TimeoutAttacked = null; public TickTimer TimeoutAttacked = null;
@ -48,30 +49,33 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
public MonsterBrain(Actor body) public MonsterBrain(Actor body)
: base(body) : base(body)
{ {
Logger = LogManager.CreateLogger(GetType().Name); _logger = LogManager.CreateLogger(GetType().Name);
PresetPowers = new Dictionary<int, Cooldown>(); PresetPowers = new Dictionary<int, Cooldown>();
// build list of powers defined in monster mpq data // build list of powers defined in monster mpq data
if (body.ActorData.MonsterSNO <= 0) if (body.ActorData.MonsterSNO <= 0)
{ {
Logger.Warn($"$[red]${GetType().Name}$[/]$ - Monster \"{body.SNO}\" has no monster SNO"); _logger.Warn($"$[red]${GetType().Name}$[/]$ - Monster \"{body.SNO}\" has no monster SNO");
return; return;
} }
var monsterData = (DiIiS_NA.Core.MPQ.FileFormats.Monster)MPQStorage.Data.Assets[SNOGroup.Monster][body.ActorData.MonsterSNO].Data;
var monsterData =
(DiIiS_NA.Core.MPQ.FileFormats.Monster)MPQStorage.Data.Assets[SNOGroup.Monster][
body.ActorData.MonsterSNO].Data;
_mpqPowerCount = monsterData.SkillDeclarations.Count(e => e.SNOPower != -1); _mpqPowerCount = monsterData.SkillDeclarations.Count(e => e.SNOPower != -1);
for (int i = 0; i < monsterData.SkillDeclarations.Length; i++) for (int i = 0; i < monsterData.SkillDeclarations.Length; i++)
{ {
if (monsterData.SkillDeclarations[i].SNOPower == -1) continue; if (monsterData.SkillDeclarations[i].SNOPower == -1) continue;
if (PowerLoader.HasImplementationForPowerSNO(monsterData.SkillDeclarations[i].SNOPower)) if (!PowerLoader.HasImplementationForPowerSNO(monsterData.SkillDeclarations[i].SNOPower)) continue;
{
var cooldownTime = monsterData.MonsterSkillDeclarations[i].Timer / 10f; var cooldownTime = monsterData.MonsterSkillDeclarations[i].Timer / 10f;
PresetPowers.Add(monsterData.SkillDeclarations[i].SNOPower, new Cooldown { CooldownTimer = null, CooldownTime = cooldownTime }); PresetPowers.Add(monsterData.SkillDeclarations[i].SNOPower,
} new Cooldown { CooldownTimer = null, CooldownTime = cooldownTime });
} }
if (monsterData.SkillDeclarations.All(s => s.SNOPower != 30592)) if (monsterData.SkillDeclarations.All(s => s.SNOPower != 30592))
PresetPowers.Add(30592, new Cooldown { CooldownTimer = null, CooldownTime = 0f }); //hack for dummy mobs without powers PresetPowers.Add(30592,
new Cooldown { CooldownTimer = null, CooldownTime = 0f }); //hack for dummy mobs without powers
} }
public override void Think(int tickCounter) public override void Think(int tickCounter)
@ -88,7 +92,8 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
if (Body.Hidden) if (Body.Hidden)
return; return;
if (CurrentAction != null && PriorityTarget != null && PriorityTarget.Attributes[GameAttributes.Is_Helper] == true) if (CurrentAction != null && PriorityTarget != null &&
PriorityTarget.Attributes[GameAttributes.Is_Helper] == true)
{ {
PriorityTarget = null; PriorityTarget = null;
CurrentAction.Cancel(tickCounter); CurrentAction.Cancel(tickCounter);
@ -118,6 +123,7 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
CurrentAction.Cancel(tickCounter); CurrentAction.Cancel(tickCounter);
CurrentAction = null; CurrentAction = null;
} }
_powerDelay = null; _powerDelay = null;
return; return;
@ -125,14 +131,14 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
if (Body.Attributes[GameAttributes.Feared]) if (Body.Attributes[GameAttributes.Feared])
{ {
if (!Feared || CurrentAction == null) if (_feared && CurrentAction != null) return;
{
if (CurrentAction != null) if (CurrentAction != null)
{ {
CurrentAction.Cancel(tickCounter); CurrentAction.Cancel(tickCounter);
CurrentAction = null; CurrentAction = null;
} }
Feared = true;
_feared = true;
CurrentAction = new MoveToPointWithPathfindAction( CurrentAction = new MoveToPointWithPathfindAction(
Body, Body,
PowerContext.RandomDirection(Body.Position, 3f, 8f) PowerContext.RandomDirection(Body.Position, 3f, 8f)
@ -140,35 +146,40 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
return; return;
} }
return; _feared = false;
}
Feared = false; if (CurrentAction != null) return;
if (CurrentAction == null)
{
_powerDelay ??= new SecondsTickTimer(Body.World.Game, 1.0f); _powerDelay ??= new SecondsTickTimer(Body.World.Game, 1.0f);
// Check if the character has been attacked or if there are any players within 50 units range
if (AttackedBy != null || Body.GetObjectsInRange<Player>(50f).Count != 0) if (AttackedBy != null || Body.GetObjectsInRange<Player>(50f).Count != 0)
{ {
if (_powerDelay.TimedOut) // If the power delay hasn't timed out, return
{ if (!_powerDelay.TimedOut) return;
// Reset the power delay
_powerDelay = new SecondsTickTimer(Body.World.Game, 1.0f); _powerDelay = new SecondsTickTimer(Body.World.Game, 1.0f);
// If the character has been attacked, set the attacker as the priority target
if (AttackedBy != null) if (AttackedBy != null)
PriorityTarget = AttackedBy; PriorityTarget = AttackedBy;
// If there's no defined priority target, start a search
if (PriorityTarget == null) if (PriorityTarget == null)
{ {
Actor[] targets; Actor[] targets;
// If the character is part of a team, search for alive monsters within a range of 60 units and order them by distance
if (Body.Attributes[GameAttributes.Team_Override] == 1) if (Body.Attributes[GameAttributes.Team_Override] == 1)
targets = Body.GetObjectsInRange<Monster>(60f) targets = Body.GetObjectsInRange<Monster>(60f)
.Where(p => !p.Dead) .Where(p => !p.Dead)
.OrderBy((monster) => PowerMath.Distance2D(monster.Position, Body.Position)) .OrderBy((monster) => PowerMath.Distance2D(monster.Position, Body.Position))
.ToArray(); .ToArray();
else else
// Otherwise, search for different types of actors including players, minions, destructible loot containers, or hirelings that are alive, not loading and not helpers, and order them by distance
targets = Body.GetActorsInRange(50f) targets = Body.GetActorsInRange(50f)
.Where(p => ((p is Player) && !p.Dead && p.Attributes[GameAttributes.Loading] == false && p.Attributes[GameAttributes.Is_Helper] == false && p.World.BuffManager.GetFirstBuff<ActorGhostedBuff>(p) == null) .Where(p => ((p is Player) && !p.Dead && p.Attributes[GameAttributes.Loading] == false &&
p.Attributes[GameAttributes.Is_Helper] == false &&
p.World.BuffManager.GetFirstBuff<ActorGhostedBuff>(p) == null)
|| ((p is Minion) && !p.Dead && p.Attributes[GameAttributes.Is_Helper] == false) || ((p is Minion) && !p.Dead && p.Attributes[GameAttributes.Is_Helper] == false)
|| (p is DesctructibleLootContainer && p.SNO.IsDoorOrBarricade()) || (p is DesctructibleLootContainer && p.SNO.IsDoorOrBarricade())
|| ((p is Hireling) && !p.Dead) || ((p is Hireling) && !p.Dead)
@ -176,55 +187,74 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
.OrderBy((actor) => PowerMath.Distance2D(actor.Position, Body.Position)) .OrderBy((actor) => PowerMath.Distance2D(actor.Position, Body.Position))
.ToArray(); .ToArray();
// If there are no targets, return
if (targets.Length == 0) return; if (targets.Length == 0) return;
_target = targets.First(); // Set the first found target as the target
Target = targets.First();
} }
else else
_target = PriorityTarget; // If there is a priority target, set it as the target
Target = PriorityTarget;
int powerToUse = PickPowerToUse(); int powerToUse = PickPowerToUse();
if (powerToUse > 0) if (powerToUse <= 0) return;
{
PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse); PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse);
power.User = Body; power.User = Body;
float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f ? (powerToUse == 30592 ? 10f : Math.Min((float)power.EvalTag(PowerKeys.AttackRadius), 35f)) : 35f); float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f
float targetDistance = PowerMath.Distance2D(_target.Position, Body.Position); ? (powerToUse == 30592 ? 10f : Math.Min((float)power.EvalTag(PowerKeys.AttackRadius), 35f))
if (targetDistance < attackRange + _target.ActorData.Cylinder.Ax2) : 35f);
float targetDistance = PowerMath.Distance2D(Target.Position, Body.Position);
if (targetDistance < attackRange + Target.ActorData.Cylinder.Ax2)
{ {
if (Body.WalkSpeed != 0) if (Body.WalkSpeed != 0)
Body.TranslateFacing(_target.Position, false); Body.TranslateFacing(Target.Position, false);
CurrentAction = new PowerAction(Body, powerToUse, _target); CurrentAction = new PowerAction(Body, powerToUse, Target);
if (power is SummoningSkill) PresetPowers[powerToUse] = power switch
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }; {
SummoningSkill => new Cooldown
if (power is MonsterAffixSkill monsterAffixSkill) {
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = monsterAffixSkill.CooldownTime }; CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f)
},
MonsterAffixSkill monsterAffixSkill => new Cooldown
{
CooldownTimer = null, CooldownTime = monsterAffixSkill.CooldownTime
},
_ => PresetPowers[powerToUse]
};
if (PresetPowers[powerToUse].CooldownTime > 0f) if (PresetPowers[powerToUse].CooldownTime > 0f)
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime), CooldownTime = PresetPowers[powerToUse].CooldownTime }; PresetPowers[powerToUse] = new Cooldown
{
CooldownTimer =
new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime),
CooldownTime = PresetPowers[powerToUse].CooldownTime
};
if (powerToUse is 96925 or 223284) if (powerToUse is 96925 or 223284)
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, 10f), CooldownTime = 10f }; PresetPowers[powerToUse] = new Cooldown
{ CooldownTimer = new SecondsTickTimer(Body.World.Game, 10f), CooldownTime = 10f };
} }
else if (Body.WalkSpeed != 0) else if (Body.WalkSpeed != 0)
{ {
if (Body.SNO.IsWoodwraithOrWasp()) if (Body.SNO.IsWoodwraithOrWasp())
{ {
Logger.Trace($"{GetType().Name} $[underline white]${nameof(MoveToPointAction)}$[/]$ to target $[white]${_target.ActorType}$[/]$ [{_target.Position}]"); _logger.Trace(
$"{GetType().Name} $[underline white]${nameof(MoveToPointAction)}$[/]$ to target $[white]${Target.ActorType}$[/]$ [{Target.Position}]");
CurrentAction = new MoveToPointAction( CurrentAction = new MoveToPointAction(
Body, _target.Position Body, Target.Position
); );
} }
else else
{ {
Logger.Trace($"{GetType().Name} {nameof(MoveToTargetWithPathfindAction)} to target [{_target.ActorType}] {_target.SNO.ToString()}"); _logger.Trace(
$"{GetType().Name} {nameof(MoveToTargetWithPathfindAction)} to target [{Target.ActorType}] {Target.SNO.ToString()}");
CurrentAction = new MoveToTargetWithPathfindAction( CurrentAction = new MoveToTargetWithPathfindAction(
Body, Body,
_target, Target,
attackRange + _target.ActorData.Cylinder.Ax2, attackRange + Target.ActorData.Cylinder.Ax2,
powerToUse powerToUse
); );
} }
@ -236,29 +266,38 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
ActorSno._a1dun_leor_firewall2 => 223284, ActorSno._a1dun_leor_firewall2 => 223284,
_ => powerToUse _ => powerToUse
}; };
CurrentAction = new PowerAction(Body, powerToUse, _target); CurrentAction = new PowerAction(Body, powerToUse, Target);
if (power is SummoningSkill) PresetPowers[powerToUse] = power switch
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }; {
SummoningSkill => new Cooldown
if (power is MonsterAffixSkill) {
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = (power as MonsterAffixSkill).CooldownTime }; CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f)
},
MonsterAffixSkill skill => new Cooldown
{
CooldownTimer = null, CooldownTime = skill.CooldownTime
},
_ => PresetPowers[powerToUse]
};
if (PresetPowers[powerToUse].CooldownTime > 0f) if (PresetPowers[powerToUse].CooldownTime > 0f)
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime), CooldownTime = PresetPowers[powerToUse].CooldownTime }; PresetPowers[powerToUse] = new Cooldown
{
CooldownTimer =
new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime),
CooldownTime = PresetPowers[powerToUse].CooldownTime
};
if (powerToUse == 96925 || if (powerToUse is 96925 or 223284)
powerToUse == 223284) PresetPowers[powerToUse] = new Cooldown
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, 10f), CooldownTime = 10f }; { CooldownTimer = new SecondsTickTimer(Body.World.Game, 10f), CooldownTime = 10f };
}
}
} }
} }
else if (Body.GetObjectsInRange<Living>(50f).Count != 0) else if (Body.GetObjectsInRange<Living>(50f).Count != 0)
{ {
if (_powerDelay.TimedOut) if (!_powerDelay.TimedOut) return;
{
_powerDelay = new SecondsTickTimer(Body.World.Game, 1.0f); _powerDelay = new SecondsTickTimer(Body.World.Game, 1.0f);
if (AttackedBy != null) if (AttackedBy != null)
@ -287,28 +326,33 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
if (targets.Length == 0) if (targets.Length == 0)
return; return;
foreach (var monsterActor in targets.Where(tar => _target == null)) foreach (var monsterActor in targets.Where(tar => Target == null))
if (monsterActor is Monster { Brain: MonsterBrain brain } monster && monsterActor != Body) if (monsterActor is Monster { Brain: MonsterBrain brain } monster && monsterActor != Body)
if (brain.AttackedBy != null) if (brain.AttackedBy != null)
_target = brain.AttackedBy; Target = brain.AttackedBy;
} }
else else
{ {
_target = targets.First(); Target = targets.First();
} }
foreach (var tar in targets) foreach (var tar in targets)
if (tar is DesctructibleLootContainer && tar.SNO.IsDoorOrBarricade() && tar.SNO != ActorSno._trout_wagon_barricade) if (tar is DesctructibleLootContainer && tar.SNO.IsDoorOrBarricade() &&
{ _target = tar; break; } tar.SNO != ActorSno._trout_wagon_barricade)
{
Target = tar;
break;
}
} }
else else
_target = PriorityTarget; Target = PriorityTarget;
int powerToUse = PickPowerToUse(); int powerToUse = PickPowerToUse();
if (powerToUse > 0) if (powerToUse > 0)
{ {
PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse); PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse);
power.User = Body; power.User = Body;
if (_target == null) if (Target == null)
{ {
/* /*
if (!this.Body.ActorSNO.Name.ToLower().Contains("woodwraith") && if (!this.Body.ActorSNO.Name.ToLower().Contains("woodwraith") &&
@ -322,59 +366,72 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
//*/ //*/
return; return;
} }
float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f ? (powerToUse == 30592 ? 10f : Math.Min((float)power.EvalTag(PowerKeys.AttackRadius), 35f)) : 35f);
float targetDistance = PowerMath.Distance2D(_target.Position, Body.Position); float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f
if (targetDistance < attackRange + _target.ActorData.Cylinder.Ax2) ? (powerToUse == 30592 ? 10f : Math.Min((float)power.EvalTag(PowerKeys.AttackRadius), 35f))
: 35f);
float targetDistance = PowerMath.Distance2D(Target.Position, Body.Position);
if (targetDistance < attackRange + Target.ActorData.Cylinder.Ax2)
{ {
if (Body.WalkSpeed != 0) if (Body.WalkSpeed != 0)
Body.TranslateFacing(_target.Position, false); //columns and other non-walkable shit can't turn Body.TranslateFacing(Target.Position,
false); //columns and other non-walkable shit can't turn
Logger.Trace($"{GetType().Name} {nameof(PowerAction)} to target [{_target.ActorType}] {_target.SNO.ToString()}"); _logger.Trace(
$"{GetType().Name} {nameof(PowerAction)} to target [{Target.ActorType}] {Target.SNO.ToString()}");
// Logger.Trace("PowerAction to target"); // Logger.Trace("PowerAction to target");
CurrentAction = new PowerAction(Body, powerToUse, _target); CurrentAction = new PowerAction(Body, powerToUse, Target);
if (power is SummoningSkill) if (power is SummoningSkill)
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }; PresetPowers[powerToUse] = new Cooldown
{ CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) };
if (power is MonsterAffixSkill monsterSkill) if (power is MonsterAffixSkill monsterSkill)
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = monsterSkill.CooldownTime }; PresetPowers[powerToUse] = new Cooldown
{ CooldownTimer = null, CooldownTime = monsterSkill.CooldownTime };
if (PresetPowers[powerToUse].CooldownTime > 0f) if (PresetPowers[powerToUse].CooldownTime > 0f)
PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime), CooldownTime = PresetPowers[powerToUse].CooldownTime }; PresetPowers[powerToUse] = new Cooldown
{
CooldownTimer = new SecondsTickTimer(Body.World.Game,
PresetPowers[powerToUse].CooldownTime),
CooldownTime = PresetPowers[powerToUse].CooldownTime
};
} }
else if (Body.WalkSpeed != 0) else if (Body.WalkSpeed != 0)
{ {
if (Body.SNO.IsWoodwraithOrWasp()) if (Body.SNO.IsWoodwraithOrWasp())
{ {
Logger.Trace($"{GetType().Name} {nameof(MoveToPointAction)} to target [{_target.Position}]"); _logger.Trace(
$"{GetType().Name} {nameof(MoveToPointAction)} to target [{Target.Position}]");
CurrentAction = new MoveToPointAction( CurrentAction = new MoveToPointAction(
Body, _target.Position Body, Target.Position
); );
} }
else else
{ {
Logger.Trace($"{GetType().Name} {nameof(MoveToTargetWithPathfindAction)} to target [{_target.ActorType}] {_target.SNO.ToString()}"); _logger.Trace(
$"{GetType().Name} {nameof(MoveToTargetWithPathfindAction)} to target [{Target.ActorType}] {Target.SNO.ToString()}");
CurrentAction = new MoveToTargetWithPathfindAction( CurrentAction = new MoveToTargetWithPathfindAction(
Body, Body,
//( //(
_target,// + MovementHelpers.GetMovementPosition( Target, // + MovementHelpers.GetMovementPosition(
//new Vector3D(0, 0, 0), //new Vector3D(0, 0, 0),
//this.Body.WalkSpeed, //this.Body.WalkSpeed,
//MovementHelpers.GetFacingAngle(_target.Position, this.Body.Position), //MovementHelpers.GetFacingAngle(_target.Position, this.Body.Position),
//6 //6
//) //)
//) //)
attackRange + _target.ActorData.Cylinder.Ax2, attackRange + Target.ActorData.Cylinder.Ax2,
powerToUse powerToUse
); );
} }
} }
} }
} }
}
else else
{ {
@ -383,8 +440,9 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
CurrentAction = new MoveToPointWithPathfindAction(Body, Body.CheckPointPosition); CurrentAction = new MoveToPointWithPathfindAction(Body, Body.CheckPointPosition);
} }
} }
}
public static Core.Types.Math.Vector3D RandomPossibleDirection(Core.Types.Math.Vector3D position, float minRadius, float maxRadius, MapSystem.World world) public static Core.Types.Math.Vector3D RandomPossibleDirection(Core.Types.Math.Vector3D position,
float minRadius, float maxRadius, MapSystem.World world)
{ {
float angle = (float)(FastRandom.Instance.NextDouble() * Math.PI * 2); float angle = (float)(FastRandom.Instance.NextDouble() * Math.PI * 2);
float radius = minRadius + (float)FastRandom.Instance.NextDouble() * (maxRadius - minRadius); float radius = minRadius + (float)FastRandom.Instance.NextDouble() * (maxRadius - minRadius);
@ -400,33 +458,42 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
break; break;
tryC++; tryC++;
} }
return point; return point;
} }
public void FastAttack(Actor target, int skillSNO) public void FastAttack(Actor target, int skillSno)
{ {
PowerScript power = PowerLoader.CreateImplementationForPowerSNO(skillSNO); PowerScript power = PowerLoader.CreateImplementationForPowerSNO(skillSno);
power.User = Body; power.User = Body;
if (Body.WalkSpeed != 0) if (Body.WalkSpeed != 0)
Body.TranslateFacing(target.Position, false); //columns and other non-walkable shit can't turn Body.TranslateFacing(target.Position, false); //columns and other non-walkable shit can't turn
Logger.Trace($"{GetType().Name} {nameof(FastAttack)} {nameof(PowerAction)} to target [{_target.ActorType}] {_target.SNO.ToString()}"); _logger.Trace(
CurrentAction = new PowerAction(Body, skillSNO, target); $"{GetType().Name} {nameof(FastAttack)} {nameof(PowerAction)} to target [{Target.ActorType}] {Target.SNO.ToString()}");
CurrentAction = new PowerAction(Body, skillSno, target);
if (power is SummoningSkill) if (power is SummoningSkill)
PresetPowers[skillSNO] = new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }; PresetPowers[skillSno] = new Cooldown
{ CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) };
if (power is MonsterAffixSkill monsterAffixSkill) if (power is MonsterAffixSkill monsterAffixSkill)
PresetPowers[skillSNO] = new Cooldown { CooldownTimer = null, CooldownTime = monsterAffixSkill.CooldownTime }; PresetPowers[skillSno] = new Cooldown
{ CooldownTimer = null, CooldownTime = monsterAffixSkill.CooldownTime };
if (PresetPowers[skillSNO].CooldownTime > 0f) if (PresetPowers[skillSno].CooldownTime > 0f)
PresetPowers[skillSNO] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[skillSNO].CooldownTime), CooldownTime = PresetPowers[skillSNO].CooldownTime }; PresetPowers[skillSno] = new Cooldown
{
CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[skillSno].CooldownTime),
CooldownTime = PresetPowers[skillSno].CooldownTime
};
} }
protected virtual int PickPowerToUse() protected virtual int PickPowerToUse()
{ {
if (!_warnedNoPowers && PresetPowers.Count == 0) if (!_warnedNoPowers && PresetPowers.Count == 0)
{ {
Logger.Warn($"Monster $[red]$\"{Body.Name}\"$[/]$ has no usable powers. {_mpqPowerCount} are defined in mpq data."); _logger.Warn(
$"Monster $[red]$\"{Body.Name}\"$[/]$ has no usable powers. {_mpqPowerCount} are defined in mpq data.");
_warnedNoPowers = true; _warnedNoPowers = true;
return -1; return -1;
} }
@ -435,7 +502,9 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
if (PresetPowers.Count <= 0) return -1; if (PresetPowers.Count <= 0) return -1;
//int power = this.PresetPowers[RandomHelper.Next(this.PresetPowers.Count)].Key; //int power = this.PresetPowers[RandomHelper.Next(this.PresetPowers.Count)].Key;
var availablePowers = PresetPowers.Where(p => (p.Value.CooldownTimer == null || p.Value.CooldownTimer.TimedOut) && PowerLoader.HasImplementationForPowerSNO(p.Key)).Select(p => p.Key).ToList(); var availablePowers = PresetPowers
.Where(p => (p.Value.CooldownTimer == null || p.Value.CooldownTimer.TimedOut) &&
PowerLoader.HasImplementationForPowerSNO(p.Key)).Select(p => p.Key).ToList();
if (availablePowers.Where(p => p != 30592).TryPickRandom(out var selectedPower)) if (availablePowers.Where(p => p != 30592).TryPickRandom(out var selectedPower))
{ {
return selectedPower; return selectedPower;
@ -448,28 +517,28 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains
return -1; return -1;
} }
public void AddPresetPower(int powerSNO) public void AddPresetPower(int powerSno)
{ {
if (PresetPowers.ContainsKey(powerSNO)) if (PresetPowers.ContainsKey(powerSno))
{ {
Logger.Debug($"Monster $[red]$\"{Body.Name}\"$[/]$ already has power {powerSNO}."); _logger.Debug($"Monster $[red]$\"{Body.Name}\"$[/]$ already has power {powerSno}.");
// Logger.MethodTrace("power sno {0} already defined for monster \"{1}\"", // Logger.MethodTrace("power sno {0} already defined for monster \"{1}\"",
//powerSNO, this.Body.ActorSNO.Name); //powerSNO, this.Body.ActorSNO.Name);
return; return;
} }
PresetPowers.Add(powerSNO, PresetPowers.Add(powerSno,
PresetPowers.ContainsKey(30592) //if can cast melee PresetPowers.ContainsKey(30592) //if can cast melee
? new Cooldown { CooldownTimer = null, CooldownTime = 5f } ? new Cooldown { CooldownTimer = null, CooldownTime = 5f }
: new Cooldown : new Cooldown
{ CooldownTimer = null, CooldownTime = 1f + (float)FastRandom.Instance.NextDouble() }); { CooldownTimer = null, CooldownTime = 1f + (float)FastRandom.Instance.NextDouble() });
} }
public void RemovePresetPower(int powerSNO) public void RemovePresetPower(int powerSno)
{ {
if (PresetPowers.ContainsKey(powerSNO)) if (PresetPowers.ContainsKey(powerSno))
{ {
PresetPowers.Remove(powerSNO); PresetPowers.Remove(powerSno);
} }
} }
} }