Fixed frustum dynamic projectile index
(cherry picked from commit 2b30d22c1f49ac3e8ec42815a48cef6fa646e119)
This commit is contained in:
@@ -134,6 +134,7 @@ public class AreaSkillAttackAction
|
||||
.GetAttackablesInRange(targetAreaCenter, range)
|
||||
.Where(a => a != player)
|
||||
.Where(a => !a.IsAtSafezone())
|
||||
.Where(a => a.IsActive())
|
||||
?? [];
|
||||
|
||||
if (skill.AreaSkillSettings is { UseFrustumFilter: true } areaSkillSettings)
|
||||
@@ -239,6 +240,7 @@ public class AreaSkillAttackAction
|
||||
|
||||
var orderedTargets = targets.ToList();
|
||||
FrustumBasedTargetFilter? filter = null;
|
||||
var extraProjectiles = 0;
|
||||
var projectileCount = 1;
|
||||
var attackRounds = areaSkillSettings.MaximumNumberOfHitsPerTarget;
|
||||
|
||||
@@ -246,11 +248,12 @@ public class AreaSkillAttackAction
|
||||
{
|
||||
// Order targets by distance to process nearest targets first
|
||||
orderedTargets.Sort((a, b) => player.GetDistanceTo(a).CompareTo(player.GetDistanceTo(b)));
|
||||
projectileCount = areaSkillSettings.ProjectileCount + (int)(player.Attributes?[Stats.ExtraProjectiles] ?? 0);
|
||||
filter = FrustumFilters.GetOrAdd(areaSkillSettings, static s => new FrustumBasedTargetFilter(s.FrustumStartWidth, s.FrustumEndWidth, s.FrustumDistance, s.ProjectileCount));
|
||||
extraProjectiles += (int)player.Attributes![Stats.ExtraProjectiles];
|
||||
projectileCount = areaSkillSettings.ProjectileCount + extraProjectiles;
|
||||
attackRounds = 1; // One attack round per projectile
|
||||
filter = FrustumFilters.GetOrAdd(areaSkillSettings, s => new FrustumBasedTargetFilter(s.FrustumStartWidth, s.FrustumEndWidth, s.FrustumDistance, projectileCount));
|
||||
minAttacks = projectileCount;
|
||||
maxAttacks = projectileCount;
|
||||
minAttacks = projectileCount;
|
||||
|
||||
extraTarget = orderedTargets.FirstOrDefault(t => t.Id == extraTargetId);
|
||||
if (extraTarget is not null)
|
||||
@@ -296,7 +299,7 @@ public class AreaSkillAttackAction
|
||||
}
|
||||
|
||||
// For multiple projectiles, check if this specific projectile can hit the target
|
||||
if (filter != null && !filter.IsTargetWithinBounds(player, target, rotation, projectileIndex))
|
||||
if (filter != null && !filter.IsTargetWithinBounds(player, target, rotation, projectileIndex, extraProjectiles))
|
||||
{
|
||||
continue; // This projectile cannot hit this target
|
||||
}
|
||||
@@ -345,6 +348,11 @@ public class AreaSkillAttackAction
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
break; // This projectile has hit, so we move on to the next projectile
|
||||
}
|
||||
}
|
||||
|
||||
currentDelay += areaSkillSettings.DelayBetweenHits;
|
||||
|
||||
@@ -78,8 +78,9 @@ public record FrustumBasedTargetFilter
|
||||
/// <param name="target">The target.</param>
|
||||
/// <param name="rotation">The rotation.</param>
|
||||
/// <param name="projectileIndex">The zero-based index of the projectile (0 to ProjectileCount-1).</param>
|
||||
/// <param name="extraProjectiles">The number of extra projectiles, if any.</param>
|
||||
/// <returns><c>true</c> if the target is within hit bounds for the specified projectile; otherwise, <c>false</c>.</returns>
|
||||
public bool IsTargetWithinBounds(ILocateable attacker, ILocateable target, byte rotation, int projectileIndex)
|
||||
public bool IsTargetWithinBounds(ILocateable attacker, ILocateable target, byte rotation, int projectileIndex, int extraProjectiles = 0)
|
||||
{
|
||||
if (this.ProjectileCount <= 1)
|
||||
{
|
||||
@@ -87,7 +88,8 @@ public record FrustumBasedTargetFilter
|
||||
return this.IsTargetWithinBounds(attacker, target, rotation);
|
||||
}
|
||||
|
||||
if (projectileIndex < 0 || projectileIndex >= this.ProjectileCount)
|
||||
var totalProjectiles = this.ProjectileCount + extraProjectiles;
|
||||
if (projectileIndex < 0 || projectileIndex >= totalProjectiles)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -103,19 +105,19 @@ public record FrustumBasedTargetFilter
|
||||
|
||||
// Divide the frustum into sections (-1 to 1 range)
|
||||
// For 3 projectiles: left (-1 to -0.33), center (-0.33 to 0.33), right (0.33 to 1)
|
||||
var sectionWidth = 2.0 / this.ProjectileCount;
|
||||
var sectionWidth = 2.0 / totalProjectiles;
|
||||
var sectionStart = -1.0 + (projectileIndex * sectionWidth);
|
||||
var sectionEnd = sectionStart + sectionWidth;
|
||||
|
||||
// Add overlap so targets near boundaries can be hit by adjacent projectiles
|
||||
var overlap = this.GetOverlap(attacker.Position, target.Position);
|
||||
var overlap = this.GetOverlap(attacker.Position, target.Position, extraProjectiles);
|
||||
sectionStart -= overlap;
|
||||
sectionEnd += overlap;
|
||||
|
||||
return relativePosition >= sectionStart && relativePosition <= sectionEnd;
|
||||
}
|
||||
|
||||
private double GetOverlap(Point attackerPos, Point targetPos)
|
||||
private double GetOverlap(Point attackerPos, Point targetPos, int extraProjectiles = 0)
|
||||
{
|
||||
var distance = attackerPos.EuclideanDistanceTo(targetPos);
|
||||
if (distance == 0)
|
||||
@@ -124,7 +126,7 @@ public record FrustumBasedTargetFilter
|
||||
}
|
||||
|
||||
// The overlap decreases over higher distance
|
||||
var overlap = (1.0 / Math.Floor(distance)) / this.ProjectileCount;
|
||||
var overlap = (1.0 / Math.Floor(distance)) / (this.ProjectileCount + extraProjectiles);
|
||||
overlap += 0.001; // Adding a small epsilon to make it slightly more tolerant in the comparisons
|
||||
return overlap;
|
||||
}
|
||||
|
||||
@@ -828,7 +828,7 @@ internal class SkillsInitializer : SkillsInitializerBase
|
||||
this.AddMasterSkillDefinition(SkillNumber.PenetrationStrengthener, SkillNumber.Penetration, SkillNumber.Undefined, 2, 3, SkillNumber.Penetration, 20, Formula502);
|
||||
this.AddMasterSkillDefinition(SkillNumber.DefenseIncreaseStr, SkillNumber.GreaterDefense, SkillNumber.Undefined, 2, 3, SkillNumber.GreaterDefense, 20, $"{Formula502} / 100", Formula502, Stats.GreaterDefenseBonus, AggregateType.Multiplicate);
|
||||
this.AddMasterSkillDefinition(SkillNumber.TripleShotMastery, SkillNumber.TripleShotStrengthener, SkillNumber.Undefined, 2, 3, SkillNumber.TripleShotStrengthener, 10, Formula1WhenComplete, Formula1WhenComplete, Stats.ExtraProjectiles, AggregateType.AddRaw);
|
||||
this.AddPassiveMasterSkillDefinition(SkillNumber.SummonedMonsterStr2, Stats.SummonedMonsterDefenseIncrease, AggregateType.AddRaw, Formula6020, 2, 3, SkillNumber.SummonGoblin);
|
||||
this.AddPassiveMasterSkillDefinition(SkillNumber.SummonedMonsterStr2, Stats.SummonedMonsterDefenseIncrease, AggregateType.AddRaw, Formula6020Value, 3, 2, SkillNumber.SummonGoblin);
|
||||
this.AddMasterSkillDefinition(SkillNumber.AttackIncreaseStr, SkillNumber.GreaterDamage, SkillNumber.Undefined, 2, 4, SkillNumber.GreaterDamage, 20, $"{Formula502} / 100", Formula502, Stats.GreaterDamageBonus, AggregateType.Multiplicate);
|
||||
this.AddPassiveMasterSkillDefinition(SkillNumber.WeaponMasteryHighElf, Stats.MasterSkillPhysBonusDmg, AggregateType.AddRaw, Formula502, 4, 2);
|
||||
this.AddMasterSkillDefinition(SkillNumber.AttackIncreaseMastery, SkillNumber.AttackIncreaseStr, SkillNumber.Undefined, 2, 5, SkillNumber.AttackIncreaseStr, 20, $"{Formula502} / 100", Formula502, Stats.GreaterDamageBonus, AggregateType.Multiplicate, true);
|
||||
|
||||
Reference in New Issue
Block a user