Add basic meteor swarm (#4420)

* Add basic meteor swarm

* Map fixes

* Dependency cache

* Fix projectile crash

* Last of the reviews
This commit is contained in:
metalgearsloth
2021-08-23 13:28:47 +10:00
committed by GitHub
parent 92209aac9a
commit 8fa7f902a1
7 changed files with 187 additions and 2 deletions

View File

@@ -26,7 +26,7 @@ namespace Content.Server.Projectiles.Components
public bool DeleteOnCollide { get; } = true;
// Get that juicy FPS hit sound
[DataField("soundHit", required: true)] public SoundSpecifier SoundHit = default!;
[DataField("soundHit", required: true)] public SoundSpecifier? SoundHit = default!;
[DataField("soundHitSpecies")] public SoundSpecifier? SoundHitSpecies = null;
public bool DamagedEntity;

View File

@@ -39,7 +39,10 @@ namespace Content.Server.Projectiles
}
else
{
SoundSystem.Play(playerFilter, component.SoundHit.GetSound(), coordinates);
var soundHit = component.SoundHit?.GetSound();
if (!string.IsNullOrEmpty(soundHit))
SoundSystem.Play(playerFilter, soundHit, coordinates);
}
if (!otherEntity.Deleted && otherEntity.TryGetComponent(out IDamageableComponent? damage))

View File

@@ -0,0 +1,127 @@
using System;
using System.Linq;
using Content.Server.GameTicking;
using Content.Server.Projectiles.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server.StationEvents.Events
{
public sealed class MeteorSwarm : StationEvent
{
[Dependency] private readonly IComponentManager _compManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
public override string Name => "MeteorSwarm";
public override int EarliestStart => 30;
public override float Weight => WeightLow;
public override int? MaxOccurrences => 2;
public override int MinimumPlayers => 20;
public override string StartAnnouncement => "Meteors are on a collision course with the station. Brace for impact.";
protected override string EndAnnouncement => "The meteor swarm has passed. Please return to your stations.";
public override string? StartAudio => "/Audio/Announcements/bloblarm.ogg";
protected override float StartAfter => 30f;
protected override float EndAfter => float.MaxValue;
private float _cooldown;
/// <summary>
/// We'll send a specific amount of waves of meteors towards the station per ending rather than using a timer.
/// </summary>
private int _waveCounter;
private const int MinimumWaves = 3;
private const int MaximumWaves = 8;
private const float MinimumCooldown = 10f;
private const float MaximumCooldown = 60f;
private const int MeteorsPerWave = 5;
private const float MeteorVelocity = 10f;
private const float MaxAngularVelocity = 0.25f;
private const float MinAngularVelocity = -0.25f;
public override void Startup()
{
base.Startup();
var robustRandom = IoCManager.Resolve<IRobustRandom>();
_waveCounter = robustRandom.Next(MinimumWaves, MaximumWaves);
}
public override void Shutdown()
{
base.Shutdown();
_waveCounter = 0;
_cooldown = 0f;
EndAfter = float.MaxValue;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
if (!Started) return;
if (_waveCounter <= 0)
{
EndAfter = float.MinValue;
return;
}
_cooldown -= frameTime;
if (_cooldown > 0f) return;
_waveCounter--;
_cooldown += (MaximumCooldown - MinimumCooldown) * _robustRandom.NextFloat() + MinimumCooldown;
Box2? playableArea = null;
var mapId = EntitySystem.Get<GameTicker>().DefaultMap;
foreach (var grid in _mapManager.GetAllGrids())
{
if (grid.ParentMapId != mapId || !_compManager.TryGetComponent(grid.GridEntityId, out PhysicsComponent? gridBody)) continue;
var aabb = gridBody.GetWorldAABB();
playableArea = playableArea?.Union(aabb) ?? aabb;
}
if (playableArea == null)
{
EndAfter = float.MinValue;
return;
}
var minimumDistance = (playableArea.Value.TopRight - playableArea.Value.Center).Length + 50f;
var maximumDistance = minimumDistance + 100f;
var center = playableArea.Value.Center;
for (var i = 0; i < MeteorsPerWave; i++)
{
var angle = new Angle(_robustRandom.NextFloat() * MathF.Tau);
var offset = angle.RotateVec(new Vector2((maximumDistance - minimumDistance) * _robustRandom.NextFloat() + minimumDistance, 0));
var spawnPosition = new MapCoordinates(center + offset, mapId);
var meteor = _entityManager.SpawnEntity("MeteorLarge", spawnPosition);
var physics = _compManager.GetComponent<PhysicsComponent>(meteor.Uid);
physics.BodyStatus = BodyStatus.InAir;
physics.ApplyLinearImpulse(-offset.Normalized * MeteorVelocity * physics.Mass);
physics.ApplyAngularImpulse(
// Get a random angular velocity.
physics.Mass * ((MaxAngularVelocity - MinAngularVelocity) * _robustRandom.NextFloat() +
MinAngularVelocity));
// TODO: God this disgusts me but projectile needs a refactor.
meteor.GetComponent<ProjectileComponent>().TimeLeft = 120f;
}
}
}
}

View File

@@ -175,6 +175,7 @@ namespace Content.Server.StationEvents
if (type.IsAbstract) continue;
var stationEvent = (StationEvent) typeFactory.CreateInstance(type);
IoCManager.InjectDependencies(stationEvent);
_stationEvents.Add(stationEvent);
}

View File

@@ -0,0 +1,39 @@
- type: entity
id: MeteorLarge
name: meteor
abstract: true
components:
- type: Sprite
noRot: false
netsync: false
sprite: Objects/Weapons/Guns/Projectiles/meteor.rsi
scale: 4,4
layers:
- state: large
shader: unshaded
- type: ExplodeOnTrigger
- type: DeleteOnTrigger
- type: TriggerOnCollide
- type: Projectile
deleteOnCollide: false
- type: Explosive
devastationRange: 3
heavyImpactRange: 5
lightImpactRange: 7
flashRange: 10
- type: Physics
bodyType: Dynamic
fixedRotation: false
fixtures:
- shape:
!type:PhysShapeCircle
radius: 0.5
mass: 200
hard: true
# Didn't use MapGrid for now as the bounds are stuffed.
layer:
- Impassable
- SmallImpassable
- VaultImpassable
mask:
- Impassable

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

View File

@@ -0,0 +1,15 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/raw/2acc4d34a894dbcc9dbf3779b696ddf296aa2c56/icons/obj/projectiles.dmi",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "large"
}
]
}