A perk component named "Trigger Discipline" that accumulates extra shot damage while the player is not shooting or reloading, and only applies it when the player fires. It updates UI elements such as icon scale, display text and cooldown, modifies player stats for shot damage and enforces an "only shoot with mouse1" flag.
using System;
using Sandbox;
[Perk( Rarity.Unique, locked: true, minUnlocksReq: 2, alwaysOfferDebug: false )]
public class PerkShootOnlyWhenClick : Perk
{
private enum Mod { DamageGainSpeed, MaxDamage };
private float _accumulatedDamage;
private int _currDmgInt;
static PerkShootOnlyWhenClick()
{
Register<PerkShootOnlyWhenClick>(
name: "Trigger Discipline",
imagePath: "textures/icons/vector/shoot_only_when_click.png",
description: level => $"Shoot with left-click\nWhile not shooting or reloading,\n+{GetValue( level, Mod.DamageGainSpeed ).ToString("0.##")} dmg/s for next shot (max: [n]+{(int)GetValue( level, Mod.MaxDamage )}[/n])"
);
}
public override void Start()
{
base.Start();
ShouldUpdate = true;
}
public override void Refresh()
{
base.Refresh();
Player.Modify( this, PlayerStat.OnlyShootWithMouse1, 1f, ModifierType.Add );
DisplayCooldownColor = new Color( 0.4f, 0.4f, 1f );
}
public override void Update( float dt )
{
base.Update( dt );
if ( !Player.IsReloading )
{
var maxDmg = GetValue( Level, Mod.MaxDamage );
_accumulatedDamage = Math.Min( _accumulatedDamage + GetValue( Level, Mod.DamageGainSpeed ) * dt, maxDmg );
Player.Modify( this, PlayerStat.ShotDamageAdd, _accumulatedDamage, ModifierType.Add );
DisplayCooldown = Utils.Map( _accumulatedDamage, 0f, maxDmg, 0f, 1f );
}
DisplayText = $"+{_accumulatedDamage.ToString("0.#")}";
var targetScale = Input.Down( "click" )
? 1f
: 1.3f;
IconScale = MathX.Lerp( IconScale, targetScale, Time.Delta * 20f );
var newDmg = _accumulatedDamage.FloorToInt();
if( newDmg != _currDmgInt )
{
if(!Input.Down( "click" ) )
{
IconScale *= 1.1f;
Manager.Instance.PlaySfxUI( "click", pitch: Utils.Map( _currDmgInt, 1, 50, 1f, 3f ), volume: Utils.Map( _currDmgInt, 1, 20, 0.05f, 0.3f ) );
}
_currDmgInt = newDmg;
}
// todo: different holdtype while not shooting
}
public override void OnShoot()
{
base.OnShoot();
_accumulatedDamage = 0f;
Player.StopModifying( this, PlayerStat.ShotDamageAdd );
DisplayCooldown = 0f;
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.DamageGainSpeed:
default:
return 1f;
case Mod.MaxDamage:
return 30f;
}
}
}