Attack Boon Changes

This commit is contained in:
2026-07-13 18:30:41 -07:00
parent 972e0d5b4f
commit 24800f4bcb
34 changed files with 1306 additions and 112 deletions
@@ -20,6 +20,9 @@ namespace ProjectM.Simulation
public int OwnerId;
public uint Stamp;
public uint KnockUntil;
public bool IsFinisher; // Phase 1.7: this swing is the combo finisher
public bool Detonate; // Phase 1.7: attacker has the FinisherDetonate boon
public bool Pull; // Phase 1.7: attacker has the KnockToPull boon
}
/// <summary>
@@ -54,6 +57,10 @@ namespace ProjectM.Simulation
ComponentLookup<RegionTag> m_RegionLookup;
BufferLookup<InventorySlot> m_InvLookup;
BufferLookup<StatModifier> m_StatModLookup;
ComponentLookup<BoonEffects> m_BoonEffectsLookup; // Phase 1.7 (player query is at the 7-type cap -> lookup)
/// <summary>Phase 1.7 Detonating Finisher blast radius (planar, tunable).</summary>
const float k_DetonateRadius = 3.5f;
[BurstCompile]
public void OnCreate(ref SystemState state)
@@ -64,6 +71,7 @@ namespace ProjectM.Simulation
m_RegionLookup = state.GetComponentLookup<RegionTag>(isReadOnly: true);
m_InvLookup = state.GetBufferLookup<InventorySlot>(isReadOnly: false);
m_StatModLookup = state.GetBufferLookup<StatModifier>(isReadOnly: true);
m_BoonEffectsLookup = state.GetComponentLookup<BoonEffects>(isReadOnly: true);
state.RequireForUpdate<NetworkTime>();
}
@@ -93,7 +101,8 @@ namespace ProjectM.Simulation
// Server-only queue of cleaves to resolve after the player loop (so enemies are gathered ONCE, and only
// when at least one swing actually started — no per-tick enemy gather on idle/client ticks).
var cleaves = isServer ? new NativeList<PendingCleave>(Allocator.Temp) : default;
m_StatModLookup.Update(ref state); // Slice 2: per-player melee stat fold (read inside the player loop)
m_StatModLookup.Update(ref state);
m_BoonEffectsLookup.Update(ref state); // Phase 1.7: per-player boon flags (read inside the player loop)
foreach (var (mc, control, input, facing, xform, owner, ds, entity) in
SystemAPI.Query<RefRW<MeleeCombo>, RefRW<CharacterControl>, RefRO<PlayerInput>,
@@ -147,6 +156,7 @@ namespace ProjectM.Simulation
bool isFin = swingStep >= comboLen;
// Slice 2: fold the player's class/run StatModifiers onto the live-tunable melee base so the
// PRIMARY verb scales with class identity (Warrior +MeleeDamage/+reach) + run augments.
byte bflags = m_BoonEffectsLookup.HasComponent(entity) ? m_BoonEffectsLookup[entity].Flags : (byte)0;
bool hasMods = m_StatModLookup.HasBuffer(entity);
float pDamage = math.max(0f, hasMods ? StatMath.Apply(baseDamage, StatTarget.MeleeDamage, m_StatModLookup[entity]) : baseDamage);
float pRange = math.max(0f, hasMods ? StatMath.Apply(baseRange, StatTarget.MeleeRange, m_StatModLookup[entity]) : baseRange);
@@ -162,6 +172,9 @@ namespace ProjectM.Simulation
OwnerId = owner.ValueRO.NetworkId,
Stamp = stamp,
KnockUntil = knockUntil,
IsFinisher = isFin,
Detonate = (bflags & BoonFlag.FinisherDetonate) != 0,
Pull = (bflags & BoonFlag.KnockToPull) != 0,
});
}
}
@@ -254,9 +267,31 @@ namespace ProjectM.Simulation
});
if (c.KnockSpeed > 0f)
KnockbackUtil.Stamp(ref m_KnockbackLookup, m_BossLookup, target,
c.From, enemyPositions[i], c.Face, c.KnockSpeed, c.KnockUntil);
c.From, enemyPositions[i], c.Face, c.KnockSpeed, c.KnockUntil, c.Pull);
}
}
// Phase 1.7 Detonating Finisher: a finisher swing with the boon blasts a planar AoE around its
// origin (mirrors HazardExplosionSystem). Cone+blast overlap is the normal DamageEvent-summation.
for (int s = 0; s < cleaves.Length; s++)
{
var dc = cleaves[s];
if (!dc.IsFinisher || !dc.Detonate)
continue;
float detRadSq = k_DetonateRadius * k_DetonateRadius;
for (int i = 0; i < enemyEntities.Length; i++)
{
float2 dd = new float2(enemyPositions[i].x - dc.From.x, enemyPositions[i].z - dc.From.z);
if (math.lengthsq(dd) > detRadSq)
continue;
ecb.AppendToBuffer(enemyEntities[i], new DamageEvent
{
Amount = dc.Damage,
SourceNetworkId = dc.OwnerId,
SourceTick = dc.Stamp,
});
}
}
// HARVEST: deplete every node/clutter in each swing's cone, crediting the shared ledger; write
// Remaining back so the [GhostField] replicates -> WorldFeedbackSystem chips fire on melee mining.
for (int s = 0; s < cleaves.Length; s++)