Fixed frustum dynamic projectile index

(cherry picked from commit 2b30d22c1f49ac3e8ec42815a48cef6fa646e119)
This commit is contained in:
ze-dom
2026-07-21 17:44:16 +01:00
committed by Acentech Dev
parent e3c2012ddb
commit 5e33f16cdd
3 changed files with 21 additions and 11 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);