Add a fire extinguisher (#1685)

* added a lantern

* Add A Lantern with radiating light

* Added a GasVapor system and made a base for extinguisher spray.

* switched to using solution component for fire extinguisher

* made it so fire extinguisher's can run out of water vapor

* Added actual Gas to Gas Vapor, now getting atmosphere for touched tiles.

* Made it so gasVapor reacts and dissapates on reacting

* GasVapor now dissapates exponentially while traveling

* Added in-hands for fire extinguisher

* Added Spraysound to gasSprayer and to fire extinguisher prototype

* parameterized GasSprayer and GasVapor

* removed un-used imports in gasSprayer and gasVapor components and systems

* removed accidential threading import into gasmixturecomponent

* add a shared extinguisher component for extinguisher spray rotation instead of piggy-backing on RogueArrow

* paremeterized fuelCost and fuel name in GasSprayerComponent

* Paremeterized gasAmount, removed un-used code from gasVaporComponent

* Removed BaseItem Parent from Extinguisher_spray

* added GasVapor and GasSprayer to Ingored Components list

* reduced offset of spawned extinguisher vapor from player

* Update IgnoredComponents.cs

* renamed SharedExtinguisherComponent to SharedGasSprayerComponent and removed reference to RoguePointingArrow

* renamed shareExtinguisherComponent to SharedGasSprayerComponent

* Update Content.Server/Atmos/GasSprayerComponent.cs

Added check for solution component on GasSprayer.

Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>

* Update Content.Server/Atmos/GasSprayerComponent.cs

Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
This commit is contained in:
SoulSloth
2020-08-18 11:45:49 -04:00
committed by GitHub
parent 8ea9e4cd90
commit 7664b30951
19 changed files with 521 additions and 8 deletions

View File

@@ -0,0 +1,67 @@
using System;
using JetBrains.Annotations;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.GameObjects.Components.Animations;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Animations;
using Robust.Shared.Maths;
using Content.Shared.GameObjects.Components;
namespace Content.Client.GameObjects.Components.Atmos
{
[UsedImplicitly]
public class ExtinguisherVisualizer : AppearanceVisualizer
{
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
if (component.Deleted)
{
return;
}
if (component.TryGetData<double>(ExtinguisherVisuals.Rotation, out var degrees))
{
SetRotation(component, Angle.FromDegrees(degrees));
}
}
private void SetRotation(AppearanceComponent component, Angle rotation)
{
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (!sprite.Owner.TryGetComponent(out AnimationPlayerComponent animation))
{
sprite.Rotation = rotation;
return;
}
if (animation.HasRunningAnimation("rotate"))
{
animation.Stop("rotate");
}
animation.Play(new Animation
{
Length = TimeSpan.FromSeconds(0.125),
AnimationTracks =
{
new AnimationTrackComponentProperty
{
ComponentType = typeof(ISpriteComponent),
Property = nameof(ISpriteComponent.Rotation),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(sprite.Rotation, 0),
new AnimationTrackProperty.KeyFrame(rotation, 0.125f)
}
}
}
}, "rotate");
}
}
}

View File

@@ -156,6 +156,8 @@
"Vapor", "Vapor",
"DamageOnHighSpeedImpact", "DamageOnHighSpeedImpact",
"Barotrauma", "Barotrauma",
"GasSprayer",
"GasVapor",
"MobStateManager", "MobStateManager",
"Metabolism", "Metabolism",
}; };

View File

@@ -0,0 +1,74 @@
using Content.Server.GameObjects.Components.Chemistry;
using Content.Server.Interfaces;
using Content.Shared.Chemistry;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.Components.Pointing;
using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
namespace Content.Server.Atmos
{
[RegisterComponent]
public class GasSprayerComponent : Component, IAfterInteract
{
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
#pragma warning restore 649
//TODO: create a function that can create a gas based on a solution mix
public override string Name => "GasSprayer";
private string _spraySound;
private string _sprayType;
private string _fuelType;
private string _fuelName;
private int _fuelCost;
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _spraySound, "spraySound", string.Empty);
serializer.DataField(ref _sprayType, "sprayType", string.Empty);
serializer.DataField(ref _fuelType, "fuelType", string.Empty);
serializer.DataField(ref _fuelName, "fuelName", "fuel");
serializer.DataField(ref _fuelCost, "fuelCost", 50);
}
public void AfterInteract(AfterInteractEventArgs eventArgs)
{
if (!Owner.TryGetComponent(out SolutionComponent tank))
return;
if (tank.Solution.GetReagentQuantity(_fuelType) == 0)
{
_notifyManager.PopupMessage(Owner, eventArgs.User,
Loc.GetString("{0:theName} is out of {1}!", Owner, _fuelName));
}
else
{
tank.TryRemoveReagent(_fuelType, ReagentUnit.New(_fuelCost));
var playerPos = eventArgs.User.Transform.GridPosition;
var direction = (eventArgs.ClickLocation.Position - playerPos.Position).Normalized;
playerPos.Offset(direction/2);
var spray = _serverEntityManager.SpawnEntity(_sprayType, playerPos);
spray.GetComponent<AppearanceComponent>()
.SetData(ExtinguisherVisuals.Rotation, direction.ToAngle().Degrees);
spray.GetComponent<GasVaporComponent>().StartMove(direction, 5);
EntitySystem.Get<AudioSystem>().PlayFromEntity(_spraySound, Owner);
}
}
}
}

View File

@@ -0,0 +1,120 @@
using Content.Shared.Physics;
using Content.Server.Atmos.Reactions;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using Content.Server.GameObjects.Components.Atmos;
using Content.Server.Interfaces;
using Content.Shared.Atmos;
namespace Content.Server.Atmos
{
[RegisterComponent]
class GasVaporComponent : Component, ICollideBehavior, IGasMixtureHolder
{
[Dependency] private readonly IMapManager _mapManager = default!;
public override string Name => "GasVapor";
[ViewVariables] public GasMixture Air { get; set; }
private bool _running;
private Vector2 _direction;
private float _velocity;
private float _disspateTimer = 0;
private float _dissipationInterval;
private Gas _gas;
private float _gasVolume;
private float _gasTemperature;
private float _gasAmount;
public override void Initialize()
{
base.Initialize();
Air = new GasMixture(_gasVolume){Temperature = _gasTemperature};
Air.SetMoles(_gas,_gasAmount);
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _dissipationInterval, "dissipationInterval", 1);
serializer.DataField(ref _gas, "gas", Gas.WaterVapor);
serializer.DataField(ref _gasVolume, "gasVolume", 200);
serializer.DataField(ref _gasTemperature, "gasTemperature", Atmospherics.T20C);
serializer.DataField(ref _gasAmount, "gasAmount", 20);
}
public void StartMove(Vector2 dir, float velocity)
{
_running = true;
_direction = dir;
_velocity = velocity;
if (Owner.TryGetComponent(out ICollidableComponent collidable))
{
var controller = collidable.EnsureController<GasVaporController>();
controller.Move(_direction, _velocity);
}
}
public void Update(float frameTime)
{
if (!_running)
return;
if (Owner.TryGetComponent(out ICollidableComponent collidable))
{
var worldBounds = collidable.WorldAABB;
var mapGrid = _mapManager.GetGrid(Owner.Transform.GridID);
var tiles = mapGrid.GetTilesIntersecting(worldBounds);
foreach (var tile in tiles)
{
var pos = tile.GridIndices.ToGridCoordinates(_mapManager, tile.GridIndex);
var atmos = AtmosHelpers.GetTileAtmosphere(pos);
if (atmos.Air == null)
{
return;
}
if (atmos.Air.React(this) != ReactionResult.NoReaction)
{
Owner.Delete();
}
}
}
_disspateTimer += frameTime;
if (_disspateTimer > _dissipationInterval)
{
Air.SetMoles(_gas, Air.TotalMoles/2 );
}
if (Air.TotalMoles < 1)
{
Owner.Delete();
}
}
void ICollideBehavior.CollideWith(IEntity collidedWith)
{
// Check for collision with a impassable object (e.g. wall) and stop
if (collidedWith.TryGetComponent(out ICollidableComponent collidable) &&
(collidable.CollisionLayer & (int) CollisionGroup.Impassable) != 0 &&
collidable.Hard &&
Owner.TryGetComponent(out ICollidableComponent coll))
{
var controller = coll.EnsureController<GasVaporController>();
controller.Stop();
Owner.Delete();
}
}
}
}

View File

@@ -0,0 +1,20 @@
using Content.Server.Atmos;
using Robust.Shared.GameObjects.Systems;
namespace Content.Server.GameObjects.EntitySystems
{
public class GasVaporSystem : EntitySystem
{
/// <inheritdoc />
public override void Update(float frameTime)
{
foreach (var GasVapor in ComponentManager.EntityQuery<GasVaporComponent>())
{
if (GasVapor.Initialized)
{
GasVapor.Update(frameTime);
}
}
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components
{
public class SharedGasSprayerComponent : Component
{
public sealed override string Name => "GasSprayer";
}
[Serializable, NetSerializable]
public enum ExtinguisherVisuals
{
Rotation
}
}

View File

@@ -0,0 +1,16 @@
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using System;
using System.Collections.Generic;
using System.Text;
namespace Content.Shared.Physics
{
public class GasVaporController : VirtualController
{
public void Move(Vector2 velocityDirection, float speed)
{
LinearVelocity = velocityDirection * speed;
}
}
}

View File

@@ -0,0 +1,28 @@
- type: entity
name: Extinguisher Spray
id: ExtinguisherSpray
description: Extinguisher Spray
components:
- type: Sprite
sprite: Effects/extinguisherSpray.rsi
layers:
- state: extinguish
- type: Icon
sprite: Effects/extinguisherSpray.rsi
state: extinguish
- type: GasVapor
dissipationInterval: 1
gas: WaterVapor
gasVolume: 200
gasTemperature: 293.15
gasAmount: 20
- type: Physics
- type: Collidable
shapes:
- !type:PhysShapeAabb
bounds: "-0.25,-0.25,0.25,0.25"
mask:
- Impassable
- type: Appearance
visuals:
- type: ExtinguisherVisualizer

View File

@@ -4,9 +4,26 @@
id: FireExtinguisher id: FireExtinguisher
description: Extinguishes fires. description: Extinguishes fires.
components: components:
- type: Sprite - type: Sprite
texture: Objects/Misc/fire_extinguisher.png sprite: Objects/Misc/fire_extinguisher.rsi
- type: Icon layers:
texture: Objects/Misc/fire_extinguisher.png - state: fire_extinguisher_open
- type: Item - type: Icon
size: 10 sprite: Objects/Misc/fire_extinguisher.rsi
state: fire_extinguisher_open
- type: Item
sprite: Objects/Misc/fire_extinguisher.rsi
size: 10
- type: Solution
maxVol: 1000
caps: 9
contents:
reagents:
- ReagentId: chem.H2O
Quantity: 1000
- type: GasSprayer
spraySound: /Audio/Effects/spray.ogg
sprayType: ExtinguisherSpray
fuelType: chem.H2O
fuelName: water
fuelCost: 50

View File

@@ -1 +1,25 @@
{"version": 1, "size": {"x": 96, "y": 96}, "states": [{"name": "explosionfast", "directions": 1, "delays": [[0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06]]}]} {
"version": 1,
"size": {
"x": 96,
"y": 96
},
"states": [
{
"name": "explosionfast",
"directions": 1,
"delays": [
[
0.06,
0.06,
0.06,
0.06,
0.06,
0.06,
0.06,
0.06
]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -0,0 +1,63 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "extinguish",
"directions": 8,
"delays": [
[
0.2,
0.2,
0.2,
0.2
],
[
0.2,
0.2,
0.2,
0.2
],
[
0.2,
0.2,
0.2,
0.2
],
[
0.2,
0.2,
0.2,
0.2
],
[
0.2,
0.2,
0.2,
0.2
],
[
0.2,
0.2,
0.2,
0.2
],
[
0.2,
0.2,
0.2,
0.2
],
[
0.2,
0.2,
0.2,
0.2
]
]
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -0,0 +1,65 @@
{
"version": 1,
"license": "CC BY-SA 3.0",
"copyright": "Taken from https://github.com/tgstation/tgstation at commit 9bebd81ae0b0a7f952b59886a765c681205de31f",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "fire_extinguisher_open",
"directions": 1,
"delays": [
[
1.0
]
]
},
{
"name": "fire_extinguisher_closed",
"directions": 1,
"delays": [
[
1.0
]
]
},
{
"name": "inhand-right",
"directions": 4,
"delays": [
[
1
],
[
1
],
[
1
],
[
1
]
]
},
{
"name": "inhand-left",
"directions": 4,
"delays": [
[
1
],
[
1
],
[
1
],
[
1
]
]
}
]
}

View File

@@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"license": "CC BY-SA 3.0", "license": "CC BY-SA 3.0",
"copyright": "Taken from https://github.com/tgstation/tgstation at commit 9bebd81ae0b0a7f952b59886a765c681205de31f", "copyright": "Taken from https://github.com/tgstation/tgstation at commit 9bebd81ae0b0a7f952b59886a765c681205de31f",
"size": { "size": {
"x": 32, "x": 32,