mirror of
https://github.com/wega-team/ss14-wega.git
synced 2026-02-14 19:30:01 +01:00
Add water flower for clowns (#41469)
* Spray! * Add to clown loadout * Fix the easy things * lot nicer * spray update.. * Fix yaml * fixes * changed it to warning! * review * review * sku
This commit is contained in:
7
Content.Client/Fluids/SpraySystem.cs
Normal file
7
Content.Client/Fluids/SpraySystem.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.Fluids.Components;
|
||||
using Content.Shared.Fluids.EntitySystems;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Client.Fluids;
|
||||
|
||||
public sealed class SpraySystem : SharedSpraySystem;
|
||||
@@ -1,6 +1,5 @@
|
||||
using Content.Server.Chemistry.Components;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Server.Fluids.Components;
|
||||
using Content.Server.Gravity;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.CCVar;
|
||||
@@ -16,11 +15,14 @@ using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Numerics;
|
||||
using Content.Shared.Fluids.EntitySystems;
|
||||
using Content.Shared.Fluids.Components;
|
||||
using Robust.Server.Containers;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Fluids.EntitySystems;
|
||||
|
||||
public sealed class SpraySystem : EntitySystem
|
||||
public sealed class SpraySystem : SharedSpraySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly GravitySystem _gravity = default!;
|
||||
@@ -33,6 +35,7 @@ public sealed class SpraySystem : EntitySystem
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly ContainerSystem _container = default!;
|
||||
|
||||
private float _gridImpulseMultiplier;
|
||||
|
||||
@@ -54,7 +57,7 @@ public sealed class SpraySystem : EntitySystem
|
||||
|
||||
var targetMapPos = _transform.GetMapCoordinates(GetEntityQuery<TransformComponent>().GetComponent(args.Target));
|
||||
|
||||
Spray(entity, args.User, targetMapPos);
|
||||
Spray(entity, targetMapPos, args.User);
|
||||
}
|
||||
|
||||
private void UpdateGridMassMultiplier(float value)
|
||||
@@ -71,10 +74,19 @@ public sealed class SpraySystem : EntitySystem
|
||||
|
||||
var clickPos = _transform.ToMapCoordinates(args.ClickLocation);
|
||||
|
||||
Spray(entity, args.User, clickPos);
|
||||
Spray(entity, clickPos, args.User);
|
||||
}
|
||||
|
||||
public void Spray(Entity<SprayComponent> entity, EntityUid user, MapCoordinates mapcoord)
|
||||
public override void Spray(Entity<SprayComponent> entity, EntityUid? user = null)
|
||||
{
|
||||
var xform = Transform(entity);
|
||||
var throwing = xform.LocalRotation.ToWorldVec() * entity.Comp.SprayDistance;
|
||||
var direction = xform.Coordinates.Offset(throwing);
|
||||
|
||||
Spray(entity, _transform.ToMapCoordinates(direction), user);
|
||||
}
|
||||
|
||||
public override void Spray(Entity<SprayComponent> entity, MapCoordinates mapcoord, EntityUid? user = null)
|
||||
{
|
||||
if (!_solutionContainer.TryGetSolution(entity.Owner, SprayComponent.SolutionName, out var soln, out var solution))
|
||||
return;
|
||||
@@ -82,25 +94,29 @@ public sealed class SpraySystem : EntitySystem
|
||||
var ev = new SprayAttemptEvent(user);
|
||||
RaiseLocalEvent(entity, ref ev);
|
||||
if (ev.Cancelled)
|
||||
{
|
||||
if (ev.CancelPopupMessage != null && user != null)
|
||||
_popupSystem.PopupEntity(Loc.GetString(ev.CancelPopupMessage), entity.Owner, user.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TryComp<UseDelayComponent>(entity, out var useDelay)
|
||||
&& _useDelay.IsDelayed((entity, useDelay)))
|
||||
if (_useDelay.IsDelayed((entity, null)))
|
||||
return;
|
||||
|
||||
if (solution.Volume <= 0)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), entity.Owner, user);
|
||||
if (user != null)
|
||||
_popupSystem.PopupEntity(Loc.GetString(entity.Comp.SprayEmptyPopupMessage, ("entity", entity)), entity.Owner, user.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var userXform = xformQuery.GetComponent(user);
|
||||
var sprayerXform = xformQuery.GetComponent(entity);
|
||||
|
||||
var userMapPos = _transform.GetMapCoordinates(userXform);
|
||||
var sprayerMapPos = _transform.GetMapCoordinates(sprayerXform);
|
||||
var clickMapPos = mapcoord;
|
||||
|
||||
var diffPos = clickMapPos.Position - userMapPos.Position;
|
||||
var diffPos = clickMapPos.Position - sprayerMapPos.Position;
|
||||
if (diffPos == Vector2.Zero || diffPos == Vector2Helpers.NaN)
|
||||
return;
|
||||
|
||||
@@ -127,12 +143,12 @@ public sealed class SpraySystem : EntitySystem
|
||||
Angle.FromDegrees(spread * (amount - 1) / 2));
|
||||
|
||||
// Calculate the destination for the vapor cloud. Limit to the maximum spray distance.
|
||||
var target = userMapPos
|
||||
var target = sprayerMapPos
|
||||
.Offset((diffNorm + rotation.ToVec()).Normalized() * diffLength + quarter);
|
||||
|
||||
var distance = (target.Position - userMapPos.Position).Length();
|
||||
var distance = (target.Position - sprayerMapPos.Position).Length();
|
||||
if (distance > entity.Comp.SprayDistance)
|
||||
target = userMapPos.Offset(diffNorm * entity.Comp.SprayDistance);
|
||||
target = sprayerMapPos.Offset(diffNorm * entity.Comp.SprayDistance);
|
||||
|
||||
var adjustedSolutionAmount = entity.Comp.TransferAmount / entity.Comp.VaporAmount;
|
||||
var newSolution = _solutionContainer.SplitSolution(soln.Value, adjustedSolutionAmount);
|
||||
@@ -141,7 +157,7 @@ public sealed class SpraySystem : EntitySystem
|
||||
break;
|
||||
|
||||
// Spawn the vapor cloud onto the grid/map the user is present on. Offset the start position based on how far the target destination is.
|
||||
var vaporPos = userMapPos.Offset(distance < 1 ? quarter : threeQuarters);
|
||||
var vaporPos = sprayerMapPos.Offset(distance < 1 ? quarter : threeQuarters);
|
||||
var vapor = Spawn(entity.Comp.SprayedPrototype, vaporPos);
|
||||
var vaporXform = xformQuery.GetComponent(vapor);
|
||||
|
||||
@@ -164,17 +180,21 @@ public sealed class SpraySystem : EntitySystem
|
||||
|
||||
_vapor.Start(ent, vaporXform, impulseDirection * diffLength, entity.Comp.SprayVelocity, target, time, user);
|
||||
|
||||
if (TryComp<PhysicsComponent>(user, out var body))
|
||||
var thingGettingPushed = entity.Owner;
|
||||
if (_container.TryGetOuterContainer(entity, sprayerXform, out var container))
|
||||
thingGettingPushed = container.Owner;
|
||||
|
||||
if (TryComp<PhysicsComponent>(thingGettingPushed, out var body))
|
||||
{
|
||||
if (_gravity.IsWeightless(user))
|
||||
if (_gravity.IsWeightless(thingGettingPushed))
|
||||
{
|
||||
// push back the player
|
||||
_physics.ApplyLinearImpulse(user, -impulseDirection * entity.Comp.PushbackAmount, body: body);
|
||||
_physics.ApplyLinearImpulse(thingGettingPushed, -impulseDirection * entity.Comp.PushbackAmount, body: body);
|
||||
}
|
||||
else
|
||||
{
|
||||
// push back the grid the player is standing on
|
||||
var userTransform = Transform(user);
|
||||
var userTransform = Transform(thingGettingPushed);
|
||||
if (userTransform.GridUid == userTransform.ParentUid)
|
||||
{
|
||||
// apply both linear and angular momentum depending on the player position
|
||||
@@ -187,7 +207,6 @@ public sealed class SpraySystem : EntitySystem
|
||||
|
||||
_audio.PlayPvs(entity.Comp.SpraySound, entity, entity.Comp.SpraySound.Params.WithVariation(0.125f));
|
||||
|
||||
if (useDelay != null)
|
||||
_useDelay.TryResetDelay((entity, useDelay));
|
||||
_useDelay.TryResetDelay(entity);
|
||||
}
|
||||
}
|
||||
|
||||
16
Content.Shared/Fluids/Components/EquipSprayComponent.cs
Normal file
16
Content.Shared/Fluids/Components/EquipSprayComponent.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Fluids.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Allows items with the spray component to be equipped and sprayable with a unique action.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class EquipSprayComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Verb locid that will come up when interacting with the sprayer. Set to null for no verb!
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId? VerbLocId;
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Fluids.EntitySystems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Fluids.Components;
|
||||
namespace Content.Shared.Fluids.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
[Access(typeof(SpraySystem))]
|
||||
[Access(typeof(SharedSpraySystem))]
|
||||
public sealed partial class SprayComponent : Component
|
||||
{
|
||||
public const string SolutionName = "spray";
|
||||
@@ -36,6 +36,9 @@ public sealed partial class SprayComponent : Component
|
||||
public float PushbackAmount = 5f;
|
||||
|
||||
[DataField(required: true)]
|
||||
[Access(typeof(SpraySystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||
[Access(typeof(SharedSpraySystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||
public SoundSpecifier SpraySound { get; private set; } = default!;
|
||||
|
||||
[DataField]
|
||||
public LocId SprayEmptyPopupMessage = "spray-component-is-empty-message";
|
||||
}
|
||||
80
Content.Shared/Fluids/EntitySystems/SharedSpraySystem.cs
Normal file
80
Content.Shared/Fluids/EntitySystems/SharedSpraySystem.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Fluids.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared.Fluids.EntitySystems;
|
||||
|
||||
public abstract class SharedSpraySystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<EquipSprayComponent, GetVerbsEvent<EquipmentVerb>>(OnGetVerb);
|
||||
SubscribeLocalEvent<SprayLiquidEvent>(SprayLiquid);
|
||||
}
|
||||
|
||||
private void SprayLiquid(SprayLiquidEvent ev)
|
||||
{
|
||||
var equipSprayEnt = ev.Action.Comp.Container;
|
||||
|
||||
if (equipSprayEnt == null)
|
||||
{
|
||||
Log.Warning($"{ev.Action.Comp.AttachedEntity} tried to use the SprayLiquidEvent but the entity was null.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<SprayComponent>(equipSprayEnt, out var sprayComponent))
|
||||
{
|
||||
Log.Warning($"{ev.Action.Comp.AttachedEntity} tried to use the SprayLiquidEvent on {equipSprayEnt} but the SprayComponent did not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
Spray((equipSprayEnt.Value, sprayComponent), ev.Performer);
|
||||
}
|
||||
|
||||
private void OnGetVerb(Entity<EquipSprayComponent> entity, ref GetVerbsEvent<EquipmentVerb> args)
|
||||
{
|
||||
if (entity.Comp.VerbLocId == null || !args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
var sprayComponent = Comp<SprayComponent>(entity);
|
||||
var user = args.User;
|
||||
|
||||
var verb = new EquipmentVerb
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
Spray((entity, sprayComponent), user);
|
||||
},
|
||||
Text = Loc.GetString(entity.Comp.VerbLocId),
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spray starting from the entity, to the given coordinates. If the user is supplied, will give them failure
|
||||
/// popups and will also push them in space.
|
||||
/// </summary>
|
||||
/// <param name="entity">Entity that is spraying.</param>
|
||||
/// <param name="mapcoord">The coordinates being aimed at.</param>
|
||||
/// <param name="user">The user that is using the spraying device.</param>
|
||||
public virtual void Spray(Entity<SprayComponent> entity, MapCoordinates mapcoord, EntityUid? user = null)
|
||||
{
|
||||
// do nothing!
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spray starting from the entity and facing the direction its pointing.
|
||||
/// </summary>
|
||||
/// <param name="entity">Entity that is spraying.</param>
|
||||
/// <param name="user">User that is using the spraying device.</param>
|
||||
public virtual void Spray(Entity<SprayComponent> entity, EntityUid? user = null)
|
||||
{
|
||||
// do nothing!
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class SprayLiquidEvent : InstantActionEvent;
|
||||
|
||||
@@ -39,7 +39,7 @@ public sealed partial class AbsorbantDoAfterEvent : DoAfterEvent
|
||||
/// Raised when trying to spray something, for example a fire extinguisher.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct SprayAttemptEvent(EntityUid User, bool Cancelled = false)
|
||||
public record struct SprayAttemptEvent(EntityUid? User, bool Cancelled = false, string? CancelPopupMessage = null)
|
||||
{
|
||||
public void Cancel()
|
||||
{
|
||||
|
||||
@@ -35,10 +35,10 @@ public sealed class SpraySafetySystem : EntitySystem
|
||||
|
||||
private void OnSprayAttempt(Entity<SpraySafetyComponent> ent, ref SprayAttemptEvent args)
|
||||
{
|
||||
if (!_toggle.IsActivated(ent.Owner))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString(ent.Comp.Popup), ent, args.User);
|
||||
args.Cancel();
|
||||
}
|
||||
if (_toggle.IsActivated(ent.Owner) || args.Cancelled)
|
||||
return;
|
||||
|
||||
args.Cancel();
|
||||
args.CancelPopupMessage = Loc.GetString(ent.Comp.Popup);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
equip-spray-verb-press = Press
|
||||
@@ -1 +1,3 @@
|
||||
spray-component-is-empty-message = It's empty!
|
||||
spray-component-is-empty-message = {CAPITALIZE(THE($entity))} is empty!
|
||||
|
||||
pin-spray-popup-empty = {CAPITALIZE(THE($entity))} is wilting and needs to be watered!
|
||||
|
||||
@@ -254,6 +254,17 @@
|
||||
- type: InstantAction
|
||||
event: !type:VoiceMaskSetNameEvent
|
||||
|
||||
- type: entity
|
||||
parent: BaseAction
|
||||
id: ActionShootWater
|
||||
name: Spray water!
|
||||
description: Spray water towards your enemies.
|
||||
components:
|
||||
- type: Action
|
||||
icon: { sprite: Clothing/Neck/Misc/pins.rsi, state: flower }
|
||||
- type: InstantAction
|
||||
event: !type:SprayLiquidEvent
|
||||
|
||||
- type: entity
|
||||
parent: BaseAction
|
||||
id: ActionVendingThrow
|
||||
|
||||
@@ -261,3 +261,55 @@
|
||||
state: goldautism
|
||||
- type: Clothing
|
||||
equippedPrefix: goldautism
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: SprayFlowerPin
|
||||
name: flower pin
|
||||
description: A cute flower pin. Something seems off with it...
|
||||
components:
|
||||
- type: Item
|
||||
size: Tiny
|
||||
- type: Sprite
|
||||
sprite: Clothing/Neck/Misc/pins.rsi
|
||||
state: flower
|
||||
- type: Clothing
|
||||
equippedPrefix: flower
|
||||
sprite: Clothing/Neck/Misc/pins.rsi
|
||||
quickEquip: true
|
||||
slots:
|
||||
- neck
|
||||
- type: EquipSpray
|
||||
verbLocId: equip-spray-verb-press
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
spray:
|
||||
maxVol: 30
|
||||
reagents:
|
||||
- ReagentId: Water
|
||||
Quantity: 30
|
||||
- type: RefillableSolution
|
||||
solution: spray
|
||||
- type: DrainableSolution
|
||||
solution: spray
|
||||
- type: SolutionTransfer
|
||||
maxTransferAmount: 30
|
||||
transferAmount: 30
|
||||
- type: UseDelay
|
||||
- type: Spray
|
||||
transferAmount: 5
|
||||
pushbackAmount: 30
|
||||
spraySound:
|
||||
path: /Audio/Effects/spray3.ogg
|
||||
sprayedPrototype: FlowerVapor
|
||||
vaporAmount: 1
|
||||
vaporSpread: 90
|
||||
sprayVelocity: 1.0
|
||||
sprayEmptyPopupMessage: pin-spray-popup-empty
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- ActionShootWater
|
||||
- type: ItemActionGrant
|
||||
actions:
|
||||
- ActionShootWater
|
||||
activeIfWorn: true
|
||||
|
||||
@@ -194,3 +194,17 @@
|
||||
mask:
|
||||
- FullTileMask
|
||||
- Opaque
|
||||
|
||||
- type: entity
|
||||
parent: Vapor
|
||||
id: FlowerVapor
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Effects/extinguisherSpray.rsi
|
||||
layers:
|
||||
- state: extinguish
|
||||
map: [ "enum.VaporVisualLayers.Base" ]
|
||||
- type: VaporVisuals
|
||||
animationTime: 0.8
|
||||
animationState: extinguish
|
||||
|
||||
@@ -153,6 +153,18 @@
|
||||
back:
|
||||
- PlushieLizardJobClown
|
||||
|
||||
- type: loadout
|
||||
id: FlowerWaterClown
|
||||
effects:
|
||||
- !type:JobRequirementLoadoutEffect
|
||||
requirement:
|
||||
!type:RoleTimeRequirement
|
||||
role: JobClown
|
||||
time: 4h
|
||||
storage:
|
||||
back:
|
||||
- SprayFlowerPin
|
||||
|
||||
- type: loadout
|
||||
id: LizardPlushieMime
|
||||
effects:
|
||||
|
||||
@@ -587,6 +587,7 @@
|
||||
minLimit: 0
|
||||
loadouts:
|
||||
- LizardPlushieClown
|
||||
- FlowerWaterClown
|
||||
|
||||
- type: loadoutGroup
|
||||
id: MimeHead
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 164 B |
BIN
Resources/Textures/Clothing/Neck/Misc/pins.rsi/flower.png
Normal file
BIN
Resources/Textures/Clothing/Neck/Misc/pins.rsi/flower.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 342 B |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Aromantic, asexual, bisexual, intersex, lesbian, lgbt, non-binary, pansexual and transgender pins by PixelTK, gay pin by BackeTako, autism pins by Terraspark, omnisexual pin by juliangiebel, genderqueer and genderfluid by centcomofficer24, ally by FairlySadPanda, aroace by momochitters, plural by CubixThree",
|
||||
"copyright": "Aromantic, asexual, bisexual, intersex, lesbian, lgbt, non-binary, pansexual and transgender pins by PixelTK, gay pin by BackeTako, autism pins by Terraspark, omnisexual pin by juliangiebel, genderqueer and genderfluid by centcomofficer24, ally by FairlySadPanda, aroace by momochitters, plural by CubixThree, flower by toast_enjoyer1 (Discord)",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
@@ -132,6 +132,13 @@
|
||||
{
|
||||
"name": "fluid-equipped-NECK",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "flower"
|
||||
},
|
||||
{
|
||||
"name": "flower-equipped-NECK",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user