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
This commit is contained in:
Injazz
2019-06-07 16:15:20 +05:00
committed by Pieter-Jan Briers
parent f1aeaaa640
commit 10801af2f7
42 changed files with 756 additions and 18 deletions

View File

@@ -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
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" /> <Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
<PropertyGroup> <PropertyGroup>
<TargetFramework>net472</TargetFramework> <TargetFramework>net472</TargetFramework>

View File

@@ -55,6 +55,8 @@ using Content.Server.Interfaces.GameObjects.Components.Movement;
using Content.Server.GameObjects.Components.Research; using Content.Server.GameObjects.Components.Research;
using Content.Shared.GameObjects.Components.Research; using Content.Shared.GameObjects.Components.Research;
using Robust.Shared.Interfaces.Log; using Robust.Shared.Interfaces.Log;
using Content.Server.GameObjects.Components.Explosive;
using Content.Server.GameObjects.Components.Triggers;
namespace Content.Server namespace Content.Server
{ {
@@ -178,6 +180,9 @@ namespace Content.Server
factory.Register<CatwalkComponent>(); factory.Register<CatwalkComponent>();
factory.Register<ExplosiveComponent>();
factory.Register<OnUseTimerTriggerComponent>();
factory.Register<FootstepModifierComponent>(); factory.Register<FootstepModifierComponent>();
factory.Register<EmitSoundOnUseComponent>(); factory.Register<EmitSoundOnUseComponent>();

View File

@@ -50,11 +50,13 @@ namespace Content.Server.GameObjects
{ {
public DamageThreshold DamageThreshold { get; } public DamageThreshold DamageThreshold { get; }
public bool Passed { 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; DamageThreshold = threshold;
Passed = passed; Passed = passed;
ExcessDamage = excess;
} }
} }
} }

View File

@@ -123,7 +123,13 @@ namespace Content.Server.GameObjects
var value = threshold.Value; var value = threshold.Value;
if (((value * changeSign) > (oldValue * changeSign)) && ((value * changeSign) <= (_currentDamage[damageType] * changeSign))) 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); DamageThresholdPassed?.Invoke(this, args);
} }
} }

View File

@@ -1,21 +1,27 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Robust.Shared.GameObjects; 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.Serialization;
using Robust.Shared.ViewVariables; 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 namespace Content.Server.GameObjects.Components.Destructible
{ {
/// <summary> /// <summary>
/// Deletes the entity once a certain damage threshold has been reached. /// Deletes the entity once a certain damage threshold has been reached.
/// </summary> /// </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 /> /// <inheritdoc />
public override string Name => "Destructible"; public override string Name => "Destructible";
@@ -28,16 +34,24 @@ namespace Content.Server.GameObjects.Components.Destructible
public DamageType damageType = DamageType.Total; public DamageType damageType = DamageType.Total;
public int damageValue = 0; public int damageValue = 0;
public string spawnOnDestroy = "SteelSheet"; public string spawnOnDestroy = "";
public bool destroyed = false; public bool destroyed = false;
ActSystem _actSystem;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
base.ExposeData(serializer); base.ExposeData(serializer);
serializer.DataField(ref damageValue, "thresholdvalue", 100); serializer.DataField(ref damageValue, "thresholdvalue", 100);
serializer.DataField(ref damageType, "thresholdtype", DamageType.Total); 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 /> /// <inheritdoc />
@@ -49,13 +63,40 @@ namespace Content.Server.GameObjects.Components.Destructible
/// <inheritdoc /> /// <inheritdoc />
void IOnDamageBehavior.OnDamageThresholdPassed(object obj, DamageThresholdPassedEventArgs e) void IOnDamageBehavior.OnDamageThresholdPassed(object obj, DamageThresholdPassedEventArgs e)
{ {
if (e.Passed && e.DamageThreshold == Threshold && destroyed == false) if (e.Passed && e.DamageThreshold == Threshold && destroyed == false)
{ {
destroyed = true; destroyed = true;
var wreck = Owner.EntityManager.SpawnEntity(spawnOnDestroy); _actSystem.HandleDestruction(Owner, true);
wreck.Transform.GridPosition = Owner.Transform.GridPosition; }
Owner.EntityManager.DeleteEntity(Owner);
}
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);
} }
} }
} }

View File

@@ -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();
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems; using System.Linq;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Storage; using Content.Shared.GameObjects.Components.Storage;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.Components.Container;
@@ -26,7 +27,7 @@ namespace Content.Server.GameObjects
/// <summary> /// <summary>
/// Storage component for containing entities within this one, matches a UI on the client which shows stored entities /// Storage component for containing entities within this one, matches a UI on the client which shows stored entities
/// </summary> /// </summary>
public class ServerStorageComponent : SharedStorageComponent, IAttackBy, IUse, IActivate, IStorageComponent public class ServerStorageComponent : SharedStorageComponent, IAttackBy, IUse, IActivate, IStorageComponent, IDestroyAct
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IMapManager _mapManager;
@@ -340,5 +341,14 @@ namespace Content.Server.GameObjects
_storageInitialCalculated = true; _storageInitialCalculated = true;
} }
void IDestroyAct.OnDestroy(DestructionEventArgs eventArgs)
{
var storedEntities = storage.ContainedEntities.ToList();
foreach (var entity in storedEntities)
{
Remove(entity);
}
}
} }
} }

View File

@@ -12,7 +12,7 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects namespace Content.Server.GameObjects
{ {
public class SpeciesComponent : SharedSpeciesComponent, IActionBlocker, IOnDamageBehavior public class SpeciesComponent : SharedSpeciesComponent, IActionBlocker, IOnDamageBehavior, IExAct
{ {
/// <summary> /// <summary>
/// Damagestates are reached by reaching a certain damage threshold, they will block actions after being reached /// 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)); 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> /// <summary>

View File

@@ -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;
}
}
}

View 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,
}
}

View 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;
}
}
});
}
}
}

View File

@@ -18,4 +18,7 @@
<ProjectReference Include="..\RobustToolbox\Robust.Shared.Maths\Robust.Shared.Maths.csproj" /> <ProjectReference Include="..\RobustToolbox\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.Shared\Robust.Shared.csproj" /> <ProjectReference Include="..\RobustToolbox\Robust.Shared\Robust.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="GameObjects\Components\Trigger\" />
</ItemGroup>
</Project> </Project>

View File

@@ -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,
}
}

View File

@@ -17,6 +17,7 @@ namespace Content.Shared.Maps
public string DisplayName { get; private set; } public string DisplayName { get; private set; }
public string SpriteName { get; private set; } public string SpriteName { get; private set; }
public bool IsSubFloor { get; private set; } public bool IsSubFloor { get; private set; }
public string SubFloor { get; private set; }
public bool CanCrowbar { get; private set; } public bool CanCrowbar { get; private set; }
public string FootstepSounds { get; private set; } public string FootstepSounds { get; private set; }
public float Friction { get; set; } public float Friction { get; set; }
@@ -36,6 +37,10 @@ namespace Content.Shared.Maps
{ {
IsSubFloor = node.AsBool(); IsSubFloor = node.AsBool();
} }
if (mapping.TryGetNode("subfloor", out var another_node))
{
SubFloor = another_node.AsString();
}
if (mapping.TryGetNode("can_crowbar", out node)) if (mapping.TryGetNode("can_crowbar", out node))
{ {

Binary file not shown.

Binary file not shown.

View File

@@ -18,6 +18,43 @@
- type: Collidable - type: Collidable
- type: Storage - type: Storage
Capacity: 60 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: placement:
snap: snap:

View 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

View File

@@ -136,3 +136,21 @@
- type: Sound - type: Sound
- type: EmitSoundOnUse - type: EmitSoundOnUse
sound: /Audio/items/bikehorn.ogg 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

View File

@@ -25,6 +25,9 @@
Anchored: false Anchored: false
- type: EntityStorage - type: EntityStorage
- type: PlaceableSurface - type: PlaceableSurface
- type: Damageable
- type: Destructible
thresholdvalue: 100
- type: Appearance - type: Appearance
visuals: visuals:
- type: StorageVisualizer2D - type: StorageVisualizer2D

View File

@@ -21,3 +21,8 @@
- type: IconSmooth - type: IconSmooth
key: tables key: tables
base: solid_ base: solid_
- type: Damageable
- type: Destructible
thresholdvalue: 50
spawnondestroy: TableParts

View File

@@ -6,6 +6,7 @@
can_crowbar: true can_crowbar: true
footstep_sounds: footstep_floor footstep_sounds: footstep_floor
friction: 0.35 friction: 0.35
subfloor: plating
- type: tile - type: tile
name: floor_white name: floor_white
@@ -15,6 +16,7 @@
can_crowbar: true can_crowbar: true
footstep_sounds: footstep_floor footstep_sounds: footstep_floor
friction: 0.1 friction: 0.1
subfloor: underplating
- type: tile - type: tile
name: floor_techmaint name: floor_techmaint
@@ -24,3 +26,4 @@
can_crowbar: true can_crowbar: true
footstep_sounds: footstep_floor footstep_sounds: footstep_floor
friction: 0.5 friction: 0.5
subfloor: underplating

View File

@@ -5,6 +5,7 @@
is_subfloor: true is_subfloor: true
footstep_sounds: footstep_plating footstep_sounds: footstep_plating
friction: 0.5 friction: 0.5
subfloor: space
- type: tile - type: tile
name: underplating name: underplating

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View 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
]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

View 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]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

View 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]]}]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

View 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]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

View 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]]}]}