combat/attack_profile.cs
using System;
using System.Collections.Generic;
using Sandbox;
public enum AttackShape
{
DirectTrace,
HorizontalSweep,
VerticalSweep
}
public sealed class AttackProfile
{
[Property, Group( "1. Dégâts & Identité" )] public string Name { get; set; } = "Attaque";
[Property, Group( "1. Dégâts & Identité" )] public float Damage { get; set; } = 15f;
[Property, Group( "1. Dégâts & Identité" )] public float BalanceDamage { get; set; } = 25f;
[Property, Group( "1. Dégâts & Identité" )] public DamageType Type { get; set; } = DamageType.Slash;
[Property, Group( "1. Dégâts & Identité" )] public bool IsHeavy { get; set; } = false;
[Property, Group( "2. Timing & Portée" )] public float Range { get; set; } = 75f;
[Property, Group( "2. Timing & Portée" )] public float Radius { get; set; } = 18f;
[Property, Group( "2. Timing & Portée" )] public float WindupDelay { get; set; } = 0.05f;
[Property, Group( "2. Timing & Portée" )] public float Cooldown { get; set; } = 0.4f;
[Property, Group( "2. Timing & Portée" )] public int AnimIndex { get; set; } = 1;
[Property, Group( "2. Timing & Portée" )] public bool IsKickAnim { get; set; } = false;
[Property, Group( "3. Animation Corporelle" )]
public bool AffectWholeBody { get; set; } = false;
[Property, Group( "3. Animation Corporelle" )]
public float FullBodyDuration { get; set; } = 0.85f;
// =========================================================================
// IMPACT SUR COMBATTANTS (Valeurs modérées, collées au sol)
// =========================================================================
[Property, Group( "4. Recul Combattant (Fighter)" )]
[Description( "Force de recul horizontal appliquée au combattant touché (ex: 30 à 60 pour une épée, 150 pour un kick)" )]
public float FighterKnockbackForce { get; set; } = 45f;
[Property, Group( "4. Recul Combattant (Fighter)" )]
[Description( "Élévation verticale du combattant. Laissez à 0 pour que le coup reste strictement au sol sans faire décoller la cible." )]
public float FighterUpwardLift { get; set; } = 0.0f;
[Property, Group( "4. Recul Combattant (Fighter)" )]
[Description( "Si coché, projette la cible au sol si sa garde est brisée (Staggered)." )]
public bool CausesKnockdownOnStagger { get; set; } = false;
// =========================================================================
// IMPACT SUR PROPS & DÉCORS (Physique lourde indépendante)
// =========================================================================
[Property, Group( "5. Propulsion Décors (Props & Rigidbodies)" )]
[Description( "Impulsion physique brute (en Ns) transmise exclusivement aux objets dynamiques du décor." )]
public float PropPhysicsImpulse { get; set; } = 18000f;
[Property, Group( "5. Propulsion Décors (Props & Rigidbodies)" )]
[Description( "Biais vertical pour faire voler les objets du décor vers le haut." )]
public float PropUpwardLift { get; set; } = 0.35f;
[Property, Group( "6. Origine & Tracé" )] public Vector3 OriginOffset { get; set; } = Vector3.Zero;
[Property, Group( "6. Origine & Tracé" )] public string SocketAttachment { get; set; } = "";
// =========================================================================
// EFFETS & FEEDBACK SONORE PROPRE AU MOUVEMENT
// =========================================================================
[Property, Group( "7. Effets" )] public SoundEvent SwingSound { get; set; }
[Property, Group( "7. Effets" )]
[Description( "Optionnel. Si assigné, remplace le HitFleshSound de la WeaponComboResource (ex: botte lourde pour un kick)." )]
public SoundEvent HitSoundOverride { get; set; }
[Property, Group( "7. Effets" )] public GameObject HitParticlePrefab { get; set; }
[Property, Group( "8. Géométrie" )] public AttackShape Shape { get; set; } = AttackShape.DirectTrace;
[Property, Group( "8. Géométrie" )] public int RayCount { get; set; } = 5;
[Property, Group( "8. Géométrie" )] public float SweepAngle { get; set; } = 60f;
public IEnumerable<Vector3> GenerateRays( Vector3 forwardDir )
{
if ( Shape == AttackShape.DirectTrace || RayCount <= 1 )
{
yield return forwardDir;
yield break;
}
var rotationAxis = Shape == AttackShape.HorizontalSweep ? Vector3.Up : Vector3.Cross( forwardDir, Vector3.Up ).Normal;
var halfAngle = SweepAngle * 0.5f;
var step = SweepAngle / (RayCount - 1);
for ( int i = 0; i < RayCount; i++ )
{
var angle = -halfAngle + (step * i);
var rot = Rotation.FromAxis( rotationAxis, angle );
yield return rot * forwardDir;
}
}
}