things/enemies/Crate.cs
using Sandbox;
using SpriteTools;
public class Crate : Enemy
{
public override bool CanBleed => false;
public bool IsMysteryBox { get; set; }
[Property] public Sprite MysteryBoxSprite { get; set; }
protected override void OnAwake()
{
//OffsetY = -0.4f;
ShadowScale = 1.3f;
ShadowFullOpacity = 0.8f;
ShadowOpacity = 0f;
Scale = 0.95f;
base.OnAwake();
//AnimSpeed = 2f;
//BasePivotY = 0.05f;
//Sprite.Texture = Texture.Load("textures/sprites/crate.vtex");
//ScaleFactor = 0.95f;
//Sprite.Size = new Vector2( 1f, 1f ) * ScaleFactor;
PushStrength = 8f;
Deceleration = 15f;
Radius = 0.25f;
Health = 45f;
if ( Manager.Instance.Difficulty < 0 )
Health = 35f;
MaxHealth = Health;
CanTurn = false;
CanAttack = false;
FlipX = false;
Sprite.PlayAnimation( AnimSpawnPath );
AnimIdlePath = "idle";
if ( IsProxy )
return;
CollideWith.Add( typeof( Enemy ) );
CollideWith.Add( typeof( Player ) );
}
public void BecomeMysteryBox()
{
Sprite.Sprite = MysteryBoxSprite;
IsMysteryBox = true;
TintFullHp = new Color( 1f, 0.8f, 1f );
TintZeroHp = new Color( 0.5f, 0.2f, 0.5f );
TintDeath = new Color( 0.6f, 0.3f, 0.6f );
Sprite.Tint = TintFullHp;
FlipX = false;
}
protected override void UpdatePosition( float dt )
{
base.UpdatePosition( dt );
WorldPosition += (Vector3)Velocity * dt;
}
public override void Colliding( Thing other, float percent, float dt )
{
base.Colliding( other, percent, dt );
if ( other is Enemy enemy && !enemy.IsDying )
{
var spawnFactor = Utils.Map( enemy.TimeSinceSpawn, 0f, enemy.SpawnTime, 0f, 1f, EasingType.QuadIn );
Velocity += (Position2D - enemy.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 1f ) * enemy.PushStrength * (1f + enemy.TempWeight) * spawnFactor * dt;
}
else if ( other is Player player )
{
if ( !player.IsDead )
{
Velocity += (Position2D - player.Position2D).Normal * Utils.Map( percent, 0f, 1f, 0f, 1f ) * player.Stats[PlayerStat.PushStrength] * (1f + player.TempWeight) * dt;
}
}
}
public override void DropLoot( Player player )
{
float RAND_POS = 0.2f;
int num_coins = Game.Random.Int( 2, (IsMysteryBox ? 7 : 3) );
for ( int i = 0; i < num_coins; i++ )
{
var pos = Position2D + new Vector2( Game.Random.Float( -RAND_POS, RAND_POS ), Game.Random.Float( -RAND_POS, RAND_POS ) );
var vel = (pos - Position2D) * Game.Random.Float( 2f, 7f );
Manager.Instance.SpawnCoin( pos, vel, value: Game.Random.Int( CoinValueMin, CoinValueMax ), force: true );
}
var health_pack_chance = player != null ? Utils.Map( player.Health, player.Stats[PlayerStat.MaxHp], 0f, 0.2f, 0.75f ) : 0.1f;
if ( IsMysteryBox )
{
health_pack_chance = 1f;
}
else
{
if ( Manager.Instance.Difficulty == -1 )
health_pack_chance *= 1.3f;
else if ( Manager.Instance.Difficulty >= 3 )
health_pack_chance *= 0.7f;
}
int numHealthPacks = IsMysteryBox ? Game.Random.Int( 1, 2 ) : 1;
for( int i = 0; i < numHealthPacks; i++ )
{
if ( Game.Random.Float( 0f, 1f ) < health_pack_chance )
{
var pos = Position2D + new Vector2( Game.Random.Float( -RAND_POS, RAND_POS ), Game.Random.Float( -RAND_POS, RAND_POS ) );
var vel = (pos - Position2D) * Game.Random.Float( 2f, 6f );
Manager.Instance.SpawnHealthPack( pos, vel );
}
}
if ( Manager.Instance.TimeSinceMagnet > 50f || IsMysteryBox )
{
var magnet_chance = 0.09f * Utils.Map( Manager.Instance.TimeSinceMagnet, 50f, Utils.Map(Manager.Instance.Difficulty, 0, 3, 480f, 750f), 1f, 5.5f, EasingType.Linear );
if ( IsMysteryBox )
{
magnet_chance = 1f;
}
else
{
if ( Manager.Instance.Difficulty == -1 )
magnet_chance *= 1.3f;
else if ( Manager.Instance.Difficulty > 0 )
magnet_chance *= 0.85f;
else if ( Manager.Instance.Difficulty > 0 )
magnet_chance *= 0.5f;
}
if ( Game.Random.Float( 0f, 1f ) < magnet_chance )
{
var pos = Position2D + new Vector2( Game.Random.Float( -RAND_POS, RAND_POS ), Game.Random.Float( -RAND_POS, RAND_POS ) );
var vel = (pos - Position2D) * Game.Random.Float( 2f, 6f );
Manager.Instance.SpawnMagnet( pos, vel );
}
}
//var revive_chance = Manager.Instance.GetPlayers( alive: false ).Count() * 0.4f;
//if ( Game.Random.Float( 0f, 1f ) < revive_chance )
//{
// var pos = Position2D + new Vector2( Game.Random.Float( -RAND_POS, RAND_POS ), Game.Random.Float( -RAND_POS, RAND_POS ) );
// Manager.Instance.SpawnReviveSoul( pos, vel: (pos - Position2D) * Game.Random.Float( 2f, 6f ) );
//}
int numGrenadeChances = IsMysteryBox ? Game.Random.Int( 1, 6 ) : Game.Random.Int(1, (Manager.Instance.Difficulty >= 3 ? 5 : 2));
for( int i = 0; i < numGrenadeChances; i++ )
{
var grenade_chance = IsMysteryBox ? 1f : 0.125f;
if ( player != null && Game.Random.Float( 0f, 1f ) < grenade_chance )
{
var pos = Position2D + new Vector2( Game.Random.Float( -RAND_POS, RAND_POS ), Game.Random.Float( -RAND_POS, RAND_POS ) );
var vel = (pos - Position2D) * Game.Random.Float( 2f, 6f );
player.SpawnGrenade( pos, vel );
}
}
if( Manager.Instance.Difficulty >= 3 )
{
float reroll_chance = IsMysteryBox ? 0.75f : 0.22f;
int num_chances = IsMysteryBox ? 6 : 2;
for( int i = 0; i < num_chances; i++ )
{
if(Game.Random.Float(0f, 1f) < reroll_chance)
{
var pos = Position2D + new Vector2( Game.Random.Float( -RAND_POS, RAND_POS ), Game.Random.Float( -RAND_POS, RAND_POS ) );
var vel = (pos - Position2D) * Game.Random.Float( 2f, 6f );
Manager.Instance.SpawnRerollPickup( pos, vel );
}
}
}
if(IsMysteryBox)
SpawnMysteryEnemy();
}
void SpawnMysteryEnemy()
{
List<(TypeDescription Type, float Weight)> enemyTypes = new List<(TypeDescription, float)>
{
(TypeLibrary.GetType( typeof( Exploder ) ), 10f),
(TypeLibrary.GetType( typeof( ExploderElite ) ), 2f),
(TypeLibrary.GetType( typeof( Spitter ) ), 8f),
(TypeLibrary.GetType( typeof( SpitterElite ) ), 2f),
(TypeLibrary.GetType( typeof( Charger ) ), 6f),
(TypeLibrary.GetType( typeof( ChargerElite ) ), 1f),
(TypeLibrary.GetType( typeof( Spiker ) ), 6f),
(TypeLibrary.GetType( typeof( SpikerElite ) ), 0.5f),
(TypeLibrary.GetType( typeof( Zombie ) ), 0.1f),
(TypeLibrary.GetType( typeof( ZombieElite ) ), 2f),
(TypeLibrary.GetType( typeof( Runner ) ), 4f),
(TypeLibrary.GetType( typeof( RunnerElite ) ), 0.5f)
};
if(Manager.Instance.Difficulty >= 2)
{
enemyTypes.Add( (TypeLibrary.GetType( typeof( ExploderSpecial ) ), 1f) );
enemyTypes.Add( (TypeLibrary.GetType( typeof( SpitterSpecial ) ), 1f) );
enemyTypes.Add( (TypeLibrary.GetType( typeof( SpitterEliteSpecial ) ), 1f) );
enemyTypes.Add( (TypeLibrary.GetType( typeof( ChargerSpecial ) ), 1f) );
enemyTypes.Add( (TypeLibrary.GetType( typeof( SpikerSpecial ) ), 1f) );
enemyTypes.Add( (TypeLibrary.GetType( typeof( RunnerEliteSpecial ) ), 1f) );
}
TypeDescription chosenType = null;
float totalWeight = enemyTypes.Sum( x => x.Weight );
var rand = Game.Random.Float( 0f, totalWeight );
for ( int i = enemyTypes.Count - 1; i >= 0; i-- )
{
var (type, weight) = enemyTypes[i];
rand -= weight;
if ( rand < 0f )
{
chosenType = type;
break;
}
}
var enemy = Manager.Instance.SpawnEnemy( chosenType, Position2D, forceSpawn: true );
float charmChance = 0.25f;
if ( Manager.Instance.Difficulty == -1 )
charmChance *= 2.5f;
if ( Game.Random.Float( 0f, 1f ) < charmChance )
{
enemy.Charm();
enemy.Flash( 0f );
}
}
}