Adds Spray Bottles (#1522)

* Spray Bottle

* -"Proper" wall detection
-Removed some using
-Fixed sound

* Just don't add it

* -Removed spill sound
-Added sound parameter to SpillHelper.SpillAt

* Now spawns Vapor instead of Puddles instantly

* -Review
-Nullable

* Reworkkkk

* AABB shittery

Co-authored-by: Víctor Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
This commit is contained in:
Exp
2020-08-08 14:33:36 +02:00
committed by GitHub
parent 322c2261b6
commit b4f08811eb
10 changed files with 312 additions and 5 deletions

View File

@@ -151,6 +151,8 @@
"Flippable", "Flippable",
"Airtight", "Airtight",
"MovedByPressure", "MovedByPressure",
"Spray",
"Vapor",
"DamageOnHighSpeedImpact", "DamageOnHighSpeedImpact",
}; };
} }

View File

@@ -0,0 +1,129 @@
using Content.Server.GameObjects.Components.Fluids;
using Content.Shared.Chemistry;
using Content.Shared.Physics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.EntityFrameworkCore.Update.Internal;
using Robust.Server.GameObjects;
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.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Serialization;
using Robust.Shared.Timers;
using Robust.Shared.ViewVariables;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using Timer = Robust.Shared.Timers.Timer;
namespace Content.Server.GameObjects.Components.Chemistry
{
[RegisterComponent]
class VaporComponent : Component, ICollideBehavior
{
#pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager = default!;
#pragma warning enable 649
public override string Name => "Vapor";
[ViewVariables]
private SolutionComponent _contents;
[ViewVariables]
private ReagentUnit _transferAmount;
private bool _running;
private Vector2 _direction;
private float _velocity;
public override void Initialize()
{
base.Initialize();
_contents = Owner.GetComponent<SolutionComponent>();
}
public void Start(Vector2 dir, float velocity)
{
_running = true;
_direction = dir;
_velocity = velocity;
// Set Move
if (Owner.TryGetComponent(out ICollidableComponent collidable))
{
var controller = collidable.EnsureController<VaporController>();
controller.Move(_direction, _velocity);
}
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _transferAmount, "transferAmount", ReagentUnit.New(0.5));
}
public void Update()
{
if (!_running)
return;
// Get all intersecting tiles with the vapor and spray the divided solution on there
if (Owner.TryGetComponent(out ICollidableComponent collidable))
{
var worldBounds = collidable.WorldAABB;
var mapGrid = _mapManager.GetGrid(Owner.Transform.GridID);
var tiles = mapGrid.GetTilesIntersecting(worldBounds);
var amount = _transferAmount / ReagentUnit.New(tiles.Count());
foreach (var tile in tiles)
{
var pos = tile.GridIndices.ToGridCoordinates(_mapManager, tile.GridIndex);
SpillHelper.SpillAt(pos, _contents.SplitSolution(amount), "PuddleSmear", false); //make non PuddleSmear?
}
}
if (_contents.CurrentVolume == 0)
{
// Delete this
Owner.Delete();
}
}
internal bool TryAddSolution(Solution solution)
{
if (solution.TotalVolume == 0)
{
return false;
}
var result = _contents.TryAddSolution(solution);
if (!result)
{
return false;
}
return true;
}
void ICollideBehavior.CollideWith(IEntity collidedWith)
{
// Check for collision with a impassable object (e.g. wall) and stop
if (collidedWith.TryGetComponent(out ICollidableComponent collidable))
{
if ((collidable.CollisionLayer & (int) CollisionGroup.Impassable) != 0 && collidable.Hard)
{
if (Owner.TryGetComponent(out ICollidableComponent coll))
{
var controller = coll.EnsureController<VaporController>();
controller.Stop();
}
}
}
}
}
}

View File

@@ -18,10 +18,11 @@ namespace Content.Server.GameObjects.Components.Fluids
/// <param name="entity">Entity location to spill at</param> /// <param name="entity">Entity location to spill at</param>
/// <param name="solution">Initial solution for the prototype</param> /// <param name="solution">Initial solution for the prototype</param>
/// <param name="prototype">Prototype to use</param> /// <param name="prototype">Prototype to use</param>
internal static void SpillAt(IEntity entity, Solution solution, string prototype) /// <param name="sound">Play the spill sound</param>
internal static void SpillAt(IEntity entity, Solution solution, string prototype, bool sound = true)
{ {
var entityLocation = entity.Transform.GridPosition; var entityLocation = entity.Transform.GridPosition;
SpillAt(entityLocation, solution, prototype); SpillAt(entityLocation, solution, prototype, sound);
} }
// Other functions will be calling this one // Other functions will be calling this one
@@ -32,7 +33,8 @@ namespace Content.Server.GameObjects.Components.Fluids
/// <param name="gridCoordinates"></param> /// <param name="gridCoordinates"></param>
/// <param name="solution">Initial solution for the prototype</param> /// <param name="solution">Initial solution for the prototype</param>
/// <param name="prototype">Prototype to use</param> /// <param name="prototype">Prototype to use</param>
internal static PuddleComponent? SpillAt(GridCoordinates gridCoordinates, Solution solution, string prototype) /// <param name="sound">Play the spill sound</param>
internal static PuddleComponent? SpillAt(GridCoordinates gridCoordinates, Solution solution, string prototype, bool sound = true)
{ {
if (solution.TotalVolume == 0) if (solution.TotalVolume == 0)
{ {
@@ -67,7 +69,7 @@ namespace Content.Server.GameObjects.Components.Fluids
continue; continue;
} }
if (!puddleComponent.TryAddSolution(solution)) if (!puddleComponent.TryAddSolution(solution, sound))
{ {
continue; continue;
} }
@@ -84,7 +86,7 @@ namespace Content.Server.GameObjects.Components.Fluids
var puddle = serverEntityManager.SpawnEntity(prototype, spillGridCoords); var puddle = serverEntityManager.SpawnEntity(prototype, spillGridCoords);
var newPuddleComponent = puddle.GetComponent<PuddleComponent>(); var newPuddleComponent = puddle.GetComponent<PuddleComponent>();
newPuddleComponent.TryAddSolution(solution); newPuddleComponent.TryAddSolution(solution, sound);
return newPuddleComponent; return newPuddleComponent;
} }

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Chemistry;
using Content.Server.Interfaces;
using Content.Shared.Chemistry;
using Content.Shared.Interfaces.GameObjects.Components;
using Microsoft.EntityFrameworkCore.Update.Internal;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Fluids
{
[RegisterComponent]
class SprayComponent : Component, IAfterInteract
{
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
#pragma warning restore 649
public override string Name => "Spray";
private ReagentUnit _transferAmount;
private string _spraySound;
private float _sprayVelocity;
/// <summary>
/// The amount of solution to be sprayer from this solution when using it
/// </summary>
[ViewVariables]
public ReagentUnit TransferAmount
{
get => _transferAmount;
set => _transferAmount = value;
}
/// <summary>
/// The speed at which the vapor starts when sprayed
/// </summary>
[ViewVariables]
public float Velocity
{
get => _sprayVelocity;
set => _sprayVelocity = value;
}
private SolutionComponent _contents;
public ReagentUnit CurrentVolume => _contents.CurrentVolume;
public override void Initialize()
{
base.Initialize();
_contents = Owner.GetComponent<SolutionComponent>();
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _transferAmount, "transferAmount", ReagentUnit.New(10));
serializer.DataField(ref _sprayVelocity, "sprayVelocity", 5.0f);
serializer.DataField(ref _spraySound, "spraySound", string.Empty);
}
void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{
if (CurrentVolume <= 0)
{
_notifyManager.PopupMessage(Owner, eventArgs.User, Loc.GetString("It's empty!"));
return;
}
var playerPos = eventArgs.User.Transform.GridPosition;
if (eventArgs.ClickLocation.GridID != playerPos.GridID)
return;
var direction = (eventArgs.ClickLocation.Position - playerPos.Position).Normalized;
var solution = _contents.SplitSolution(_transferAmount);
playerPos = playerPos.Offset(direction); // Move a bit so we don't hit the player
//TODO: check for wall?
var vapor = _serverEntityManager.SpawnEntity("Vapor", playerPos);
// Add the solution to the vapor and actually send the thing
var vaporComponent = vapor.GetComponent<VaporComponent>();
vaporComponent.TryAddSolution(solution);
vaporComponent.Start(direction, _sprayVelocity); //TODO: maybe make the velocity depending on the distance to the click
//Play sound
EntitySystem.Get<AudioSystem>().PlayFromEntity(_spraySound, Owner);
}
}
}

View File

@@ -0,0 +1,18 @@
using Content.Server.GameObjects.Components.Chemistry;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
namespace Content.Server.GameObjects.EntitySystems
{
public class VaporSystem : EntitySystem
{
/// <inheritdoc />
public override void Update(float frameTime)
{
foreach (var vaporComp in ComponentManager.EntityQuery<VaporComponent>())
{
vaporComp.Update();
}
}
}
}

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 VaporController : VirtualController
{
public void Move(Vector2 velocityDirection, float speed)
{
LinearVelocity = velocityDirection * speed;
}
}
}

Binary file not shown.

View File

@@ -174,3 +174,24 @@
state: soapomega state: soapomega
- type: Slippery - type: Slippery
paralyzeTime: 7 paralyzeTime: 7
- type: entity
name: spray bottle
id: SprayBottle
parent: BaseItem
description: A spray bottle with an unscrewable top.
components:
- type: Sprite
texture: Objects/Specific/Janitorial/cleaner.png
- type: Icon
texture: Objects/Specific/Janitorial/cleaner.png
- type: Solution
maxVol: 100
caps: 1
- type: Pourable
transferAmount: 5.0
- type: CanSpill
- type: Spray
transferAmount: 10
sprayVelocity: 5
spraySound: /Audio/Effects/spray.ogg

View File

@@ -6,3 +6,21 @@
components: components:
- type: Solution - type: Solution
maxVol: 5 maxVol: 5
- type: entity
id: Vapor
name: "vapor"
abstract: true
components:
- type: SnapGrid
offset: Center
- type: Solution
maxVol: 50
- type: Vapor
- type: Physics
- type: Collidable
shapes:
- !type:PhysShapeAabb
bounds: "-0.25,-0.25,0.25,0.25"
mask:
- Impassable

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B