Explosions and Grenades, Triggers, OnDestroy, OnExAct, Fueltanks and destructible tables (#247)
* initial explosiveComponent * remove garbagee * assets * tile mass deletion baby * grenades * tweaks * Update Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs Co-Authored-By: Pieter-Jan Briers <pieterjan.briers@gmail.com> * Ex_act based on damage, fixes and tweaks * One finishing touch Done the most cringe way * ex_act explosions, tables are destructible now also adds fuel tanks * adds ex_act to mobs
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Triggers;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameObjects.Components.Animations;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Doors
|
||||
{
|
||||
public class TimerTriggerVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private const string AnimationKey = "priming_animation";
|
||||
|
||||
private Animation PrimingAnimation;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
var countdownSound = node.GetNode("countdown_sound").AsString();
|
||||
|
||||
|
||||
PrimingAnimation = new Animation { Length = TimeSpan.MaxValue };
|
||||
{
|
||||
var flick = new AnimationTrackSpriteFlick();
|
||||
PrimingAnimation.AnimationTracks.Add(flick);
|
||||
flick.LayerKey = TriggerVisualLayers.Base;
|
||||
flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("primed", 0f));
|
||||
|
||||
var sound = new AnimationTrackPlaySound();
|
||||
PrimingAnimation.AnimationTracks.Add(sound);
|
||||
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(countdownSound, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
if (!entity.HasComponent<AnimationPlayerComponent>())
|
||||
{
|
||||
entity.AddComponent<AnimationPlayerComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
var animPlayer = component.Owner.GetComponent<AnimationPlayerComponent>();
|
||||
if (!component.TryGetData(TriggerVisuals.VisualState, out TriggerVisualState state))
|
||||
{
|
||||
state = TriggerVisualState.Unprimed;
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case TriggerVisualState.Primed:
|
||||
if (!animPlayer.HasRunningAnimation(AnimationKey))
|
||||
{
|
||||
animPlayer.Play(PrimingAnimation, AnimationKey);
|
||||
}
|
||||
break;
|
||||
case TriggerVisualState.Unprimed:
|
||||
sprite.LayerSetState(0, "icon");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum TriggerVisualLayers
|
||||
{
|
||||
Base
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
|
||||
@@ -55,6 +55,8 @@ using Content.Server.Interfaces.GameObjects.Components.Movement;
|
||||
using Content.Server.GameObjects.Components.Research;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Robust.Shared.Interfaces.Log;
|
||||
using Content.Server.GameObjects.Components.Explosive;
|
||||
using Content.Server.GameObjects.Components.Triggers;
|
||||
|
||||
namespace Content.Server
|
||||
{
|
||||
@@ -178,6 +180,9 @@ namespace Content.Server
|
||||
|
||||
factory.Register<CatwalkComponent>();
|
||||
|
||||
factory.Register<ExplosiveComponent>();
|
||||
factory.Register<OnUseTimerTriggerComponent>();
|
||||
|
||||
factory.Register<FootstepModifierComponent>();
|
||||
factory.Register<EmitSoundOnUseComponent>();
|
||||
|
||||
|
||||
@@ -50,11 +50,13 @@ namespace Content.Server.GameObjects
|
||||
{
|
||||
public DamageThreshold DamageThreshold { get; }
|
||||
public bool Passed { get; }
|
||||
public int ExcessDamage { get; }
|
||||
|
||||
public DamageThresholdPassedEventArgs(DamageThreshold threshold, bool passed)
|
||||
public DamageThresholdPassedEventArgs(DamageThreshold threshold, bool passed, int excess)
|
||||
{
|
||||
DamageThreshold = threshold;
|
||||
Passed = passed;
|
||||
ExcessDamage = excess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,13 @@ namespace Content.Server.GameObjects
|
||||
var value = threshold.Value;
|
||||
if (((value * changeSign) > (oldValue * changeSign)) && ((value * changeSign) <= (_currentDamage[damageType] * changeSign)))
|
||||
{
|
||||
var args = new DamageThresholdPassedEventArgs(threshold, (changeSign > 0));
|
||||
var excessDamage = change - value;
|
||||
var typeOfDamage = damageType;
|
||||
if (change - value < 0)
|
||||
{
|
||||
excessDamage = 0;
|
||||
}
|
||||
var args = new DamageThresholdPassedEventArgs(threshold, (changeSign > 0), excessDamage);
|
||||
DamageThresholdPassed?.Invoke(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Destructible
|
||||
{
|
||||
/// <summary>
|
||||
/// Deletes the entity once a certain damage threshold has been reached.
|
||||
/// </summary>
|
||||
public class DestructibleComponent : Component, IOnDamageBehavior
|
||||
public class DestructibleComponent : Component, IOnDamageBehavior, IDestroyAct, IExAct
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Destructible";
|
||||
|
||||
@@ -28,16 +34,24 @@ namespace Content.Server.GameObjects.Components.Destructible
|
||||
|
||||
public DamageType damageType = DamageType.Total;
|
||||
public int damageValue = 0;
|
||||
public string spawnOnDestroy = "SteelSheet";
|
||||
public string spawnOnDestroy = "";
|
||||
public bool destroyed = false;
|
||||
|
||||
ActSystem _actSystem;
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref damageValue, "thresholdvalue", 100);
|
||||
serializer.DataField(ref damageType, "thresholdtype", DamageType.Total);
|
||||
serializer.DataField(ref spawnOnDestroy, "spawnondestroy", "SteelSheet");
|
||||
serializer.DataField(ref spawnOnDestroy, "spawnondestroy", "");
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_actSystem = _entitySystemManager.GetEntitySystem<ActSystem>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -53,9 +67,36 @@ namespace Content.Server.GameObjects.Components.Destructible
|
||||
if (e.Passed && e.DamageThreshold == Threshold && destroyed == false)
|
||||
{
|
||||
destroyed = true;
|
||||
var wreck = Owner.EntityManager.SpawnEntity(spawnOnDestroy);
|
||||
wreck.Transform.GridPosition = Owner.Transform.GridPosition;
|
||||
Owner.EntityManager.DeleteEntity(Owner);
|
||||
_actSystem.HandleDestruction(Owner, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IExAct.OnExplosion(ExplosionEventArgs eventArgs)
|
||||
{
|
||||
var prob = new Random();
|
||||
switch (eventArgs.Severity)
|
||||
{
|
||||
case ExplosionSeverity.Destruction:
|
||||
_actSystem.HandleDestruction(Owner, false);
|
||||
break;
|
||||
case ExplosionSeverity.Heavy:
|
||||
_actSystem.HandleDestruction(Owner, true);
|
||||
break;
|
||||
case ExplosionSeverity.Light:
|
||||
if (RandomExtensions.Prob(prob, 40))
|
||||
_actSystem.HandleDestruction(Owner, true);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void IDestroyAct.OnDestroy(DestructionEventArgs eventArgs)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(spawnOnDestroy) && eventArgs.IsSpawnWreck)
|
||||
{
|
||||
Owner.EntityManager.TrySpawnEntityAt(spawnOnDestroy, Owner.Transform.GridPosition, out var wreck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects.EntitySystemMessages;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.Maps;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Explosive
|
||||
{
|
||||
public class ExplosiveComponent : Component, ITimerTrigger, IDestroyAct
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager;
|
||||
[Dependency] private readonly IMapManager _mapManager;
|
||||
[Dependency] private readonly IServerEntityManager _serverEntityManager;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
public override string Name => "Explosive";
|
||||
|
||||
public int DevastationRange = 0;
|
||||
public int HeavyImpactRange = 0;
|
||||
public int LightImpactRange = 0;
|
||||
public int FlashRange = 0;
|
||||
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref DevastationRange, "devastationRange", 0);
|
||||
serializer.DataField(ref HeavyImpactRange, "heavyImpactRange", 0);
|
||||
serializer.DataField(ref LightImpactRange, "lightImpactRange", 0);
|
||||
serializer.DataField(ref FlashRange, "flashRange", 0);
|
||||
}
|
||||
|
||||
private bool Explosion()
|
||||
{
|
||||
var maxRange = MathHelper.Max(DevastationRange, HeavyImpactRange, LightImpactRange, 0f);
|
||||
//Entity damage calculation
|
||||
var entitiesAll = _serverEntityManager.GetEntitiesInRange(Owner.Transform.GridPosition, maxRange).ToList();
|
||||
|
||||
foreach (var entity in entitiesAll)
|
||||
{
|
||||
Owner.Delete();
|
||||
if (entity == Owner)
|
||||
continue;
|
||||
if (!entity.Transform.IsMapTransform)
|
||||
continue;
|
||||
var distanceFromEntity = (int)entity.Transform.GridPosition.Distance(_mapManager, Owner.Transform.GridPosition);
|
||||
var exAct = _entitySystemManager.GetEntitySystem<ActSystem>();
|
||||
var severity = ExplosionSeverity.Destruction;
|
||||
if (distanceFromEntity < DevastationRange)
|
||||
{
|
||||
severity = ExplosionSeverity.Destruction;
|
||||
}
|
||||
else if (distanceFromEntity < HeavyImpactRange)
|
||||
{
|
||||
severity = ExplosionSeverity.Heavy;
|
||||
}
|
||||
else if (distanceFromEntity < LightImpactRange)
|
||||
{
|
||||
severity = ExplosionSeverity.Light;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
exAct.HandleExplosion(Owner, entity, severity);
|
||||
}
|
||||
|
||||
//Tile damage calculation mockup
|
||||
//TODO: make it into some sort of actual damage component or whatever the boys think is appropriate
|
||||
var mapGrid = _mapManager.GetGrid(Owner.Transform.GridPosition.GridID);
|
||||
var circle = new Circle(Owner.Transform.GridPosition.Position, maxRange);
|
||||
var tiles = mapGrid.GetTilesIntersecting(circle);
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
var tileLoc = mapGrid.GridTileToLocal(tile.GridIndices);
|
||||
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];
|
||||
var distanceFromTile = (int)tileLoc.Distance(_mapManager, Owner.Transform.GridPosition);
|
||||
if (!string.IsNullOrWhiteSpace(tileDef.SubFloor)) {
|
||||
if (distanceFromTile < DevastationRange)
|
||||
mapGrid.SetTile(tileLoc, new Tile(_tileDefinitionManager["space"].TileId));
|
||||
if (distanceFromTile < HeavyImpactRange)
|
||||
{
|
||||
if (new Random().Prob(80))
|
||||
{
|
||||
mapGrid.SetTile(tileLoc, new Tile(_tileDefinitionManager[tileDef.SubFloor].TileId));
|
||||
}
|
||||
else
|
||||
{
|
||||
mapGrid.SetTile(tileLoc, new Tile(_tileDefinitionManager["space"].TileId));
|
||||
}
|
||||
}
|
||||
if (distanceFromTile < LightImpactRange)
|
||||
{
|
||||
if (new Random().Prob(50))
|
||||
{
|
||||
mapGrid.SetTile(tileLoc, new Tile(_tileDefinitionManager[tileDef.SubFloor].TileId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Effects and sounds
|
||||
var time = IoCManager.Resolve<IGameTiming>().CurTime;
|
||||
var message = new EffectSystemMessage
|
||||
{
|
||||
EffectSprite = "Effects/explosion.png",
|
||||
Born = time,
|
||||
DeathTime = time + TimeSpan.FromSeconds(5),
|
||||
Size = new Vector2(FlashRange / 2, FlashRange / 2),
|
||||
Coordinates = Owner.Transform.GridPosition,
|
||||
//Rotated from east facing
|
||||
Rotation = 0f,
|
||||
ColorDelta = new Vector4(0, 0, 0, -1500f),
|
||||
Color = Vector4.Multiply(new Vector4(255, 255, 255, 750), 0.5f),
|
||||
Shaded = false
|
||||
};
|
||||
_entitySystemManager.GetEntitySystem<EffectSystem>().CreateParticle(message);
|
||||
_entitySystemManager.GetEntitySystem<AudioSystem>().Play("/Audio/effects/explosion.ogg", Owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ITimerTrigger.Trigger(TimerTriggerEventArgs eventArgs)
|
||||
{
|
||||
return Explosion();
|
||||
}
|
||||
|
||||
void IDestroyAct.OnDestroy(DestructionEventArgs eventArgs)
|
||||
{
|
||||
Explosion();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Components.Storage;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
@@ -26,7 +27,7 @@ namespace Content.Server.GameObjects
|
||||
/// <summary>
|
||||
/// Storage component for containing entities within this one, matches a UI on the client which shows stored entities
|
||||
/// </summary>
|
||||
public class ServerStorageComponent : SharedStorageComponent, IAttackBy, IUse, IActivate, IStorageComponent
|
||||
public class ServerStorageComponent : SharedStorageComponent, IAttackBy, IUse, IActivate, IStorageComponent, IDestroyAct
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IMapManager _mapManager;
|
||||
@@ -340,5 +341,14 @@ namespace Content.Server.GameObjects
|
||||
|
||||
_storageInitialCalculated = true;
|
||||
}
|
||||
|
||||
void IDestroyAct.OnDestroy(DestructionEventArgs eventArgs)
|
||||
{
|
||||
var storedEntities = storage.ContainedEntities.ToList();
|
||||
foreach (var entity in storedEntities)
|
||||
{
|
||||
Remove(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Server.GameObjects
|
||||
{
|
||||
public class SpeciesComponent : SharedSpeciesComponent, IActionBlocker, IOnDamageBehavior
|
||||
public class SpeciesComponent : SharedSpeciesComponent, IActionBlocker, IOnDamageBehavior, IExAct
|
||||
{
|
||||
/// <summary>
|
||||
/// Damagestates are reached by reaching a certain damage threshold, they will block actions after being reached
|
||||
@@ -115,6 +115,28 @@ namespace Content.Server.GameObjects
|
||||
|
||||
Owner.RaiseEvent(new MobDamageStateChangedMessage(this));
|
||||
}
|
||||
|
||||
void IExAct.OnExplosion(ExplosionEventArgs eventArgs)
|
||||
{
|
||||
var burnDamage = 0;
|
||||
var bruteDamage = 0;
|
||||
switch(eventArgs.Severity)
|
||||
{
|
||||
case ExplosionSeverity.Destruction:
|
||||
bruteDamage += 250;
|
||||
burnDamage += 250;
|
||||
break;
|
||||
case ExplosionSeverity.Heavy:
|
||||
bruteDamage += 60;
|
||||
burnDamage += 60;
|
||||
break;
|
||||
case ExplosionSeverity.Light:
|
||||
bruteDamage += 30;
|
||||
break;
|
||||
}
|
||||
Owner.GetComponent<DamageableComponent>().TakeDamage(Shared.GameObjects.DamageType.Brute, bruteDamage);
|
||||
Owner.GetComponent<DamageableComponent>().TakeDamage(Shared.GameObjects.DamageType.Heat, burnDamage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Components.Triggers;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Triggers
|
||||
{
|
||||
public class OnUseTimerTriggerComponent : Component, IUse
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
public override string Name => "OnUseTimerTrigger";
|
||||
|
||||
private float _delay = 0f;
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _delay, "delay", 0f);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
|
||||
{
|
||||
var triggerSystem = _entitySystemManager.GetEntitySystem<TriggerSystem>();
|
||||
if (Owner.TryGetComponent<AppearanceComponent>(out var appearance)) {
|
||||
appearance.SetData(TriggerVisuals.VisualState, TriggerVisualState.Primed);
|
||||
}
|
||||
triggerSystem.HandleTimerTrigger(TimeSpan.FromSeconds(_delay), eventArgs.User, Owner);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Content.Server/GameObjects/EntitySystems/ActSystem.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Content.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface gives components behavior on getting destoyed.
|
||||
/// </summary>
|
||||
public interface IDestroyAct
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when object is destroyed
|
||||
/// </summary>
|
||||
void OnDestroy(DestructionEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class DestructionEventArgs : EventArgs
|
||||
{
|
||||
public IEntity Owner { get; set; }
|
||||
public bool IsSpawnWreck { get; set; }
|
||||
}
|
||||
|
||||
public interface IExAct
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when explosion reaches the entity
|
||||
/// </summary>
|
||||
void OnExplosion(ExplosionEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class ExplosionEventArgs : EventArgs
|
||||
{
|
||||
public IEntity Source { get; set; }
|
||||
public IEntity Target { get; set; }
|
||||
public ExplosionSeverity Severity { get; set; }
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class ActSystem : EntitySystem
|
||||
{
|
||||
public void HandleDestruction(IEntity owner, bool isWreck)
|
||||
{
|
||||
var eventArgs = new DestructionEventArgs
|
||||
{
|
||||
Owner = owner,
|
||||
IsSpawnWreck = isWreck
|
||||
};
|
||||
var destroyActs = owner.GetAllComponents<IDestroyAct>().ToList();
|
||||
|
||||
foreach (var destroyAct in destroyActs)
|
||||
{
|
||||
destroyAct.OnDestroy(eventArgs);
|
||||
}
|
||||
owner.Delete();
|
||||
}
|
||||
|
||||
public void HandleExplosion(IEntity source, IEntity target, ExplosionSeverity severity)
|
||||
{
|
||||
var eventArgs = new ExplosionEventArgs
|
||||
{
|
||||
Source = source,
|
||||
Target = target,
|
||||
Severity = severity
|
||||
};
|
||||
var exActs = target.GetAllComponents<IExAct>().ToList();
|
||||
|
||||
foreach (var exAct in exActs)
|
||||
{
|
||||
exAct.OnExplosion(eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
public enum ExplosionSeverity
|
||||
{
|
||||
Destruction,
|
||||
Heavy,
|
||||
Light,
|
||||
}
|
||||
}
|
||||
53
Content.Server/GameObjects/EntitySystems/TriggerSystem.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Timers;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when being "triggered" by timer or other conditions
|
||||
/// </summary>
|
||||
public interface ITimerTrigger
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when one object is triggering some event
|
||||
/// </summary>
|
||||
bool Trigger(TimerTriggerEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class TimerTriggerEventArgs : EventArgs
|
||||
{
|
||||
public IEntity User { get; set; }
|
||||
public IEntity Source { get; set; }
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class TriggerSystem : EntitySystem
|
||||
{
|
||||
public void HandleTimerTrigger(TimeSpan delay, IEntity user, IEntity trigger)
|
||||
{
|
||||
|
||||
Timer.Spawn(delay, () =>
|
||||
{
|
||||
var timerTriggerEventArgs = new TimerTriggerEventArgs
|
||||
{
|
||||
User = user,
|
||||
Source = trigger
|
||||
};
|
||||
var timerTriggers = trigger.GetAllComponents<ITimerTrigger>().ToList();
|
||||
|
||||
foreach (var timerTrigger in timerTriggers)
|
||||
{
|
||||
if (timerTrigger.Trigger(timerTriggerEventArgs))
|
||||
{
|
||||
// If an IOnTimerTrigger returns a status completion we finish our trigger
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,4 +18,7 @@
|
||||
<ProjectReference Include="..\RobustToolbox\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
|
||||
<ProjectReference Include="..\RobustToolbox\Robust.Shared\Robust.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="GameObjects\Components\Trigger\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Triggers
|
||||
{
|
||||
[NetSerializable]
|
||||
[Serializable]
|
||||
public enum TriggerVisuals
|
||||
{
|
||||
VisualState,
|
||||
}
|
||||
|
||||
[NetSerializable]
|
||||
[Serializable]
|
||||
public enum TriggerVisualState
|
||||
{
|
||||
Primed,
|
||||
Unprimed,
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ namespace Content.Shared.Maps
|
||||
public string DisplayName { get; private set; }
|
||||
public string SpriteName { get; private set; }
|
||||
public bool IsSubFloor { get; private set; }
|
||||
public string SubFloor { get; private set; }
|
||||
public bool CanCrowbar { get; private set; }
|
||||
public string FootstepSounds { get; private set; }
|
||||
public float Friction { get; set; }
|
||||
@@ -36,6 +37,10 @@ namespace Content.Shared.Maps
|
||||
{
|
||||
IsSubFloor = node.AsBool();
|
||||
}
|
||||
if (mapping.TryGetNode("subfloor", out var another_node))
|
||||
{
|
||||
SubFloor = another_node.AsString();
|
||||
}
|
||||
|
||||
if (mapping.TryGetNode("can_crowbar", out node))
|
||||
{
|
||||
|
||||
BIN
Resources/Audio/effects/countdown.ogg
Normal file
BIN
Resources/Audio/effects/explosion.ogg
Normal file
@@ -19,6 +19,43 @@
|
||||
- type: Storage
|
||||
Capacity: 60
|
||||
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholdvalue: 100
|
||||
|
||||
placement:
|
||||
snap:
|
||||
- Wall
|
||||
|
||||
- type: entity
|
||||
id: weldtank
|
||||
name: Fueltank
|
||||
description: A storage tank containing welding fuel.
|
||||
components:
|
||||
- type: Sprite
|
||||
texture: Buildings/weldtank.png
|
||||
|
||||
- type: Icon
|
||||
texture: Buildings/weldtank.png
|
||||
|
||||
- type: Clickable
|
||||
- type: BoundingBox
|
||||
aabb: "-0.5,-0.25,0.5,0.25"
|
||||
- type: Collidable
|
||||
mask: 3
|
||||
IsScrapingFloor: true
|
||||
- type: Physics
|
||||
mass: 15
|
||||
Anchored: false
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholdvalue: 10
|
||||
- type: Explosive
|
||||
devastationRange: 1
|
||||
heavyImpactRange: 2
|
||||
lightImpactRange: 4
|
||||
flashRange: 5
|
||||
|
||||
placement:
|
||||
snap:
|
||||
- Wall
|
||||
74
Resources/Prototypes/Entities/Explosives.yml
Normal file
@@ -0,0 +1,74 @@
|
||||
- type: entity
|
||||
name: Explosive Grenade
|
||||
description: Grenade that creates small devastating explosion
|
||||
parent: BaseItem
|
||||
id: ExGrenade
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/grenade.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
map: ["enum.TriggerVisualLayers.Base"]
|
||||
|
||||
- type: Icon
|
||||
sprite: Objects/grenade.rsi
|
||||
state: icon
|
||||
|
||||
- type: Item
|
||||
Size: 5
|
||||
|
||||
- type: OnUseTimerTrigger
|
||||
delay: 5
|
||||
|
||||
- type: Explosive
|
||||
devastationRange: 1
|
||||
heavyImpactRange: 3
|
||||
lightImpactRange: 5
|
||||
flashRange: 7
|
||||
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholdvalue: 10
|
||||
|
||||
- type: Appearance
|
||||
visuals:
|
||||
- type: TimerTriggerVisualizer2D
|
||||
countdown_sound: /Audio/effects/countdown.ogg
|
||||
|
||||
- type: entity
|
||||
name: Syndicate Minibomb
|
||||
description: A syndicate manufactured explosive used to sow destruction and chaos.
|
||||
parent: BaseItem
|
||||
id: SyndieMiniBomb
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/syndgrenade.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
map: ["enum.TriggerVisualLayers.Base"]
|
||||
|
||||
- type: Icon
|
||||
sprite: Objects/syndgrenade.rsi
|
||||
state: icon
|
||||
|
||||
- type: Item
|
||||
Size: 5
|
||||
|
||||
- type: OnUseTimerTrigger
|
||||
delay: 5
|
||||
|
||||
- type: Explosive
|
||||
devastationRange: 3
|
||||
heavyImpactRange: 5
|
||||
lightImpactRange: 7
|
||||
flashRange: 10
|
||||
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholdvalue: 10
|
||||
|
||||
- type: Appearance
|
||||
visuals:
|
||||
- type: TimerTriggerVisualizer2D
|
||||
countdown_sound: /Audio/effects/countdown.ogg
|
||||
|
||||
@@ -136,3 +136,21 @@
|
||||
- type: Sound
|
||||
- type: EmitSoundOnUse
|
||||
sound: /Audio/items/bikehorn.ogg
|
||||
|
||||
- type: entity
|
||||
name: Table Parts
|
||||
parent: BaseItem
|
||||
id: TableParts
|
||||
description: Parts of a table.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/table_parts.rsi
|
||||
state: icon
|
||||
|
||||
- type: Icon
|
||||
sprite: Objects/table_parts.rsi
|
||||
state: icon
|
||||
|
||||
- type: Item
|
||||
Size: 25
|
||||
sprite: Objects/table_parts.rsi
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
Anchored: false
|
||||
- type: EntityStorage
|
||||
- type: PlaceableSurface
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholdvalue: 100
|
||||
- type: Appearance
|
||||
visuals:
|
||||
- type: StorageVisualizer2D
|
||||
|
||||
@@ -21,3 +21,8 @@
|
||||
- type: IconSmooth
|
||||
key: tables
|
||||
base: solid_
|
||||
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholdvalue: 50
|
||||
spawnondestroy: TableParts
|
||||
@@ -6,6 +6,7 @@
|
||||
can_crowbar: true
|
||||
footstep_sounds: footstep_floor
|
||||
friction: 0.35
|
||||
subfloor: plating
|
||||
|
||||
- type: tile
|
||||
name: floor_white
|
||||
@@ -15,6 +16,7 @@
|
||||
can_crowbar: true
|
||||
footstep_sounds: footstep_floor
|
||||
friction: 0.1
|
||||
subfloor: underplating
|
||||
|
||||
- type: tile
|
||||
name: floor_techmaint
|
||||
@@ -24,3 +26,4 @@
|
||||
can_crowbar: true
|
||||
footstep_sounds: footstep_floor
|
||||
friction: 0.5
|
||||
subfloor: underplating
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
is_subfloor: true
|
||||
footstep_sounds: footstep_plating
|
||||
friction: 0.5
|
||||
subfloor: space
|
||||
|
||||
- type: tile
|
||||
name: underplating
|
||||
|
||||
BIN
Resources/Textures/Buildings/weldtank.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Resources/Textures/Effects/explosion.png
Executable file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
Resources/Textures/Effects/explosion.rsi/explosion.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
28
Resources/Textures/Effects/explosion.rsi/meta.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 96,
|
||||
"y": 96
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://github.com/vgstation-coders/vgstation13/icons/effects/96x96.dmi at commit 96d69b71a3a0549b4b668c0a095306580bd157c0",
|
||||
"states": [
|
||||
{
|
||||
"name": "explosion",
|
||||
"select": [],
|
||||
"flags": {},
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Objects/grenade.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 274 B |
25
Resources/Textures/Objects/grenade.rsi/meta.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://github.com/vgstation-coders/vgstation13/icons/obj/grenade.dmi at commit 8c96d52deed1eeea28a16334eea549369d7f9974",
|
||||
"states": [
|
||||
{
|
||||
"name": "icon",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[1.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "primed",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[0.2, 0.2]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Objects/grenade.rsi/primed.png
Normal file
|
After Width: | Height: | Size: 332 B |
BIN
Resources/Textures/Objects/rack_parts.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 535 B |
BIN
Resources/Textures/Objects/rack_parts.rsi/inhand-left.png
Normal file
|
After Width: | Height: | Size: 240 B |
BIN
Resources/Textures/Objects/rack_parts.rsi/inhand-right.png
Normal file
|
After Width: | Height: | Size: 233 B |
1
Resources/Textures/Objects/rack_parts.rsi/meta.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at commit 125c975f1b3bf9826b37029e9ab5a5f89e975a7e", "states": [{"name": "icon", "directions": 1, "delays": [[1.0]]}, {"name": "inhand-left", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "inhand-right", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]}
|
||||
BIN
Resources/Textures/Objects/syndgrenade.rsi/icon.png
Executable file
|
After Width: | Height: | Size: 215 B |
25
Resources/Textures/Objects/syndgrenade.rsi/meta.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://github.com/vgstation-coders/vgstation13/icons/obj/grenade.dmi at commit 8c96d52deed1eeea28a16334eea549369d7f9974",
|
||||
"states": [
|
||||
{
|
||||
"name": "icon",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[1.0]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "primed",
|
||||
"directions": 1,
|
||||
"delays": [
|
||||
[0.2, 0.2, 0.2]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Objects/syndgrenade.rsi/primed.png
Normal file
|
After Width: | Height: | Size: 524 B |
BIN
Resources/Textures/Objects/table_parts.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 915 B |
BIN
Resources/Textures/Objects/table_parts.rsi/inhand-left.png
Normal file
|
After Width: | Height: | Size: 240 B |
BIN
Resources/Textures/Objects/table_parts.rsi/inhand-right.png
Normal file
|
After Width: | Height: | Size: 233 B |
1
Resources/Textures/Objects/table_parts.rsi/meta.json
Normal file
@@ -0,0 +1 @@
|
||||
{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at commit 125c975f1b3bf9826b37029e9ab5a5f89e975a7e", "states": [{"name": "icon", "directions": 1, "delays": [[1.0]]}, {"name": "inhand-left", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "inhand-right", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]}
|
||||