A Mythic perk called Artillery. It periodically picks a random position near the player (clamped to game bounds), spawns an artillery shell prefab there, assigns the player as the shooter, network-spawns the object for the player's owner, resets its internal cooldown, and tells the Manager to show a warning at the impact position.
using System;
using Sandbox;
[Perk( Rarity.Mythic, locked: true, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Artillery, PerkCategory.Aoe, PerkCategory.Explosion })]
public class PerkArtillery : Perk
{
private enum Mod { RechargeTime };
private float _timer;
public override float ImportanceMultiplier => 1.2f;
static PerkArtillery()
{
Register<PerkArtillery>(
name: "Artillery",
imagePath: "textures/icons/vector/artillery.png",
description: level => $"An explosive missile\nlands nearby every {GetValue( level, Mod.RechargeTime )}s",
upgradeDescription: level => $"An explosive missile\nlands nearby every {GetValue( level - 1, Mod.RechargeTime )}→{GetValue( level, Mod.RechargeTime )}s"
);
}
public override void Start()
{
base.Start();
ShouldUpdate = true;
}
public override void Refresh()
{
base.Refresh();
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.RechargeTime:
default:
return 2.5f - level * 0.5f;
}
}
public override void Update( float dt )
{
base.Update( dt );
_timer += dt;
if ( _timer > GetValue( Level, Mod.RechargeTime ) )
Shoot();
}
public void Shoot()
{
Vector2 pos = Player.Position2D + Utils.GetRandomVector() * Game.Random.Float( 100f, 250f );
Vector2 min = Manager.Instance.BOUNDS_MIN;
Vector2 max = Manager.Instance.BOUNDS_MAX;
if ( pos.x < min.x )
pos = new Vector2( min.x + (min.x - pos.x), pos.y );
else if ( pos.x > max.x )
pos = new Vector2( max.x - (pos.x - max.x), pos.y );
if ( pos.y < min.y )
pos = new Vector2( pos.x, min.y + (min.y - pos.y) );
else if ( pos.y > max.y )
pos = new Vector2( pos.x, max.y - (pos.y - max.y) );
var artilleryShellGo = GameObject.Clone( $"prefabs/artillery_shell.prefab", new CloneConfig { StartEnabled = true, Transform = new Transform( position: new Vector3( pos.x, pos.y, -100f ), rotation: new Angles( 90f, Game.Random.Float( 0f, 360f ), 0f ) ) } );
var artilleryShell = artilleryShellGo.GetComponent<ArtilleryShell>();
artilleryShell.Shooter = Player;
artilleryShellGo.NetworkSpawn( Player.Network.Owner );
_timer = 0f;
Manager.Instance.SpawnArtilleryWarning( pos );
}
}