Weapons/HornetGun/HornetGunWeapon.cs
using Sandbox.Rendering;
using Sandbox.Utility;
public class HornetGunWeapon : BaseWeapon
{
/// <summary>
/// Time between shots if not using turbo
/// </summary>
[Property] public float TimeBetweenShots { get; set; } = 2f;
/// <summary>
/// Time between shots if using turbo
/// </summary>
[Property] public float TurboDelay { get; set; } = 0.2f;
/// <summary>
/// Sound to play when shooting this weapon
/// </summary>
[Property] public SoundEvent FireSound { get; set; }
/// <summary>
/// Projectile prefab to create when shooting this weapon
/// </summary>
[Property] public GameObject ProjectilePrefab { get; set; }
/// <summary>
/// How frequently should we regenerate ammo for this weapon
/// </summary>
[Property] public float AmmoRegenerationRate { get; set; } = 1f; // Hornets per second
/// <summary>
/// The max ammo for this weapon
/// </summary>
[Property] public int MaxAmmo { get; set; } = 8;
private float ammo = 8;
protected override void OnStart()
{
base.OnStart();
ammo = MaxAmmo;
}
public override void OnControl( Player player )
{
base.OnControl( player );
if ( Input.Down( "attack1" ) )
{
if ( Input.Pressed( "attack1" ) )
StartAttack();
Shoot( player, HornetProjectile.FireMode.Normal );
}
else
{
if ( Input.Released( "attack1" ) )
StopAttack();
}
if ( Input.Down( "attack2" ) )
{
Shoot( player, HornetProjectile.FireMode.Turbo );
}
}
protected override void OnUpdate()
{
base.OnUpdate();
// Regenerate ammo over time
if ( ammo < MaxAmmo )
{
ammo += AmmoRegenerationRate * Time.Delta;
ammo = Math.Clamp( ammo, 0, MaxAmmo );
}
}
TimeSince TimeSinceShoot;
public void Shoot( Player player, HornetProjectile.FireMode fireMode )
{
if ( !CanShoot() )
return;
// Some debug asserts because we're apparently getting WeaponModel is not valid.
Assert.True( player.IsValid(), "HornetGunWeapon:::Shoot - player is invalid?" );
Assert.True( WeaponModel.IsValid(), "HornetGunWeapon:::Shoot - WeaponModel is invalid?" );
Assert.True( WeaponModel.MuzzleTransform.IsValid(), "HornetGunWeapon:::Shoot - MuzzleTransform GameObject is invalid?" );
if ( ammo < 1 )
{
AddShootDelay( 0.2f );
return;
}
if ( !GameSettings.InfiniteAmmo )
ammo -= 1;
TimeSinceShoot = 0;
AddShootDelay( fireMode == HornetProjectile.FireMode.Turbo ? TurboDelay : TimeBetweenShots );
var forward = player.EyeTransform.Forward;
var tr = Scene.Trace.Ray( player.EyeTransform.ForwardRay with { Forward = forward }, 4096 )
.IgnoreGameObjectHierarchy( player.GameObject )
.WithCollisionRules( "bullet" )
.UseHitboxes()
.Run();
var projectilePosition = CheckProjectilePosition( player, player.EyeTransform.Position, WeaponModel.MuzzleTransform.WorldPosition );
var direction = tr.EndPosition - projectilePosition;
CreateProjectile( projectilePosition, tr.Direction, fireMode );
player.Controller.EyeAngles += new Angles( Random.Shared.Float( -0.2f, -0.3f ), Random.Shared.Float( -0.1f, 0.1f ), 0 );
if ( !player.Controller.ThirdPerson && player.IsLocalPlayer )
{
new Sandbox.CameraNoise.Punch( new Vector3( Random.Shared.Float( 45, 35 ), Random.Shared.Float( -10, -5 ), 0 ), 1.5f, 2, 0.5f );
new Sandbox.CameraNoise.Shake( 1f, 0.6f );
}
}
private Vector3 CheckProjectilePosition( Player player, Vector3 eyePosition, Vector3 targetPosition )
{
var tr = Scene.Trace.Box( BBox.FromPositionAndSize( Vector3.Zero, 8.0f ), eyePosition, targetPosition )
.WithoutTags( "trigger", "ragdoll" )
.IgnoreGameObjectHierarchy( player.GameObject )
.Run();
if ( tr.Hit )
{
return tr.EndPosition;
}
return targetPosition;
}
/// <summary>
/// Creates the projectile with the host's permission
/// </summary>
[Rpc.Host]
void CreateProjectile( Vector3 start, Vector3 direction, HornetProjectile.FireMode fireMode )
{
if ( !Owner.IsValid() ) return;
var go = ProjectilePrefab?.Clone( start );
var projectile = go.GetComponent<HornetProjectile>();
Assert.True( projectile.IsValid(), "RpgProjectile not on projectile prefab" );
projectile.Instigator = Owner.PlayerData;
projectile.Mode = fireMode;
projectile.Weapon = GameObject;
go.NetworkSpawn();
//Projectile = projectile;
projectile.UpdateDirection( direction, projectile.GetSpeed() );
GameObject.PlaySound( FireSound );
}
public override void DrawCrosshair( HudPainter hud, Vector2 center )
{
var tss = TimeSinceShoot.Relative.Remap( 0, 0.2f, 1, 0 );
var gap = 6 + Easing.EaseOut( tss ) * 32;
var w = 2;
Color color = !CanShoot() ? UI.CrosshairInactive : UI.CrosshairActive;
// Define the size of the square
var squareSize = 64f;
// Draw the four edges of the square
hud.DrawLine( center + new Vector2( -squareSize / 2, -squareSize / 2 ), center + new Vector2( squareSize / 2, -squareSize / 2 ), w, color ); // Top edge
hud.DrawLine( center + new Vector2( squareSize / 2, -squareSize / 2 ), center + new Vector2( squareSize / 2, squareSize / 2 ), w, color ); // Right edge
hud.DrawLine( center + new Vector2( squareSize / 2, squareSize / 2 ), center + new Vector2( -squareSize / 2, squareSize / 2 ), w, color ); // Bottom edge
hud.DrawLine( center + new Vector2( -squareSize / 2, squareSize / 2 ), center + new Vector2( -squareSize / 2, -squareSize / 2 ), w, color ); // Left edge
}
}