starting monster brain
This commit is contained in:
parent
3c851ddf1c
commit
09e0480485
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
user.block.title