Mopping Puddle Dilution and Wet Floor Sparkles (#6273)
This commit is contained in:
@@ -49,12 +49,13 @@ namespace Content.Client.Fluids
|
|||||||
if (component.TryGetData<float>(PuddleVisuals.VolumeScale, out var volumeScale) &&
|
if (component.TryGetData<float>(PuddleVisuals.VolumeScale, out var volumeScale) &&
|
||||||
entities.TryGetComponent<SpriteComponent>(component.Owner, out var spriteComponent))
|
entities.TryGetComponent<SpriteComponent>(component.Owner, out var spriteComponent))
|
||||||
{
|
{
|
||||||
|
component.TryGetData<bool>(PuddleVisuals.ForceWetFloorSprite, out var forceWetFloorSprite);
|
||||||
var cappedScale = Math.Min(1.0f, volumeScale * 0.75f +0.25f);
|
var cappedScale = Math.Min(1.0f, volumeScale * 0.75f +0.25f);
|
||||||
UpdateVisual(component, spriteComponent, cappedScale);
|
UpdateVisual(component, spriteComponent, cappedScale, forceWetFloorSprite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateVisual(AppearanceComponent component, SpriteComponent spriteComponent, float cappedScale)
|
private void UpdateVisual(AppearanceComponent component, SpriteComponent spriteComponent, float cappedScale, bool forceWetFloorSprite)
|
||||||
{
|
{
|
||||||
Color newColor;
|
Color newColor;
|
||||||
if (Recolor && component.TryGetData<Color>(PuddleVisuals.SolutionColor, out var solutionColor))
|
if (Recolor && component.TryGetData<Color>(PuddleVisuals.SolutionColor, out var solutionColor))
|
||||||
@@ -67,6 +68,20 @@ namespace Content.Client.Fluids
|
|||||||
}
|
}
|
||||||
|
|
||||||
spriteComponent.Color = newColor;
|
spriteComponent.Color = newColor;
|
||||||
|
|
||||||
|
if (forceWetFloorSprite)
|
||||||
|
{
|
||||||
|
//Change the puddle's sprite to the wet floor sprite
|
||||||
|
spriteComponent.LayerSetRSI(0, "Fluids/wet_floor_sparkles.rsi");
|
||||||
|
spriteComponent.LayerSetState(0, "sparkles");
|
||||||
|
spriteComponent.Color = spriteComponent.Color.WithAlpha(0.25f); //should be mostly transparent.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spriteComponent.LayerSetRSI(0, "Fluids/smear.rsi");
|
||||||
|
spriteComponent.LayerSetState(0, "smear-0"); // TODO: need a way to implement the random smears again when the mop creates new puddles.
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ namespace Content.Server.Chemistry.TileReactions
|
|||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public class CleanTileReaction : ITileReaction
|
public class CleanTileReaction : ITileReaction
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplier used in CleanTileReaction.
|
||||||
|
/// 1 (default) means normal consumption rate of the cleaning reagent.
|
||||||
|
/// 0 means no consumption of the cleaning reagent, i.e. the reagent is inexhaustible.
|
||||||
|
/// </summary>
|
||||||
[DataField("cleanAmountMultiplier")]
|
[DataField("cleanAmountMultiplier")]
|
||||||
public float CleanAmountMultiplier { get; private set; } = 1.0f;
|
public float CleanAmountMultiplier { get; private set; } = 1.0f;
|
||||||
|
|
||||||
@@ -29,7 +33,7 @@ namespace Content.Server.Chemistry.TileReactions
|
|||||||
{
|
{
|
||||||
if (entMan.TryGetComponent(entity, out CleanableComponent? cleanable))
|
if (entMan.TryGetComponent(entity, out CleanableComponent? cleanable))
|
||||||
{
|
{
|
||||||
var next = (amount + cleanable.CleanAmount) * CleanAmountMultiplier;
|
var next = amount + (cleanable.CleanAmount * CleanAmountMultiplier);
|
||||||
// Nothing left?
|
// Nothing left?
|
||||||
if (reactVolume < next)
|
if (reactVolume < next)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -71,10 +71,16 @@ namespace Content.Server.Fluids.Components
|
|||||||
public FixedPoint2 PickupAmount { get; } = FixedPoint2.New(10);
|
public FixedPoint2 PickupAmount { get; } = FixedPoint2.New(10);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// After cleaning a floor tile, leave this much reagent as a puddle. I.e., leave behind a wet floor.
|
/// When using the mop on an empty floor tile, leave this much reagent as a new puddle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("residueAmount")]
|
[DataField("residueAmount")]
|
||||||
public FixedPoint2 ResidueAmount { get; } = FixedPoint2.New(5);
|
public FixedPoint2 ResidueAmount { get; } = FixedPoint2.New(10); // Should be higher than MopLowerLimit
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// To leave behind a wet floor, the mop will be unable to take from puddles with a volume less than this amount.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("mopLowerLimit")]
|
||||||
|
public FixedPoint2 MopLowerLimit { get; } = FixedPoint2.New(5);
|
||||||
|
|
||||||
[DataField("pickup_sound")]
|
[DataField("pickup_sound")]
|
||||||
private SoundSpecifier _pickupSound = new SoundPathSpecifier("/Audio/Effects/Fluids/slosh.ogg");
|
private SoundSpecifier _pickupSound = new SoundPathSpecifier("/Audio/Effects/Fluids/slosh.ogg");
|
||||||
@@ -117,6 +123,14 @@ namespace Content.Server.Fluids.Components
|
|||||||
!solutionSystem.TryGetSolution((puddleComponent).Owner, puddleComponent.SolutionName, out var puddleSolution))
|
!solutionSystem.TryGetSolution((puddleComponent).Owner, puddleComponent.SolutionName, out var puddleSolution))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// if the puddle is too small for the mop to effectively take any more solution
|
||||||
|
if (puddleSolution.TotalVolume <= MopLowerLimit)
|
||||||
|
{
|
||||||
|
// Transfers solution from the mop to the puddle
|
||||||
|
solutionSystem.TryAddSolution(target, puddleSolution, solutionSystem.SplitSolution(Owner, contents, FixedPoint2.Min(ResidueAmount,CurrentVolume)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// if the mop is full
|
// if the mop is full
|
||||||
if(AvailableVolume <= 0)
|
if(AvailableVolume <= 0)
|
||||||
{
|
{
|
||||||
@@ -141,28 +155,28 @@ namespace Content.Server.Fluids.Components
|
|||||||
puddleComponent.Deleted)
|
puddleComponent.Deleted)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// The volume the mop will take from the puddle
|
||||||
FixedPoint2 transferAmount;
|
FixedPoint2 transferAmount;
|
||||||
// does the puddle actually have reagents? it might not if its a weird cosmetic entity.
|
// does the puddle actually have reagents? it might not if its a weird cosmetic entity.
|
||||||
if (puddleSolution.TotalVolume == 0)
|
if (puddleSolution.TotalVolume == 0)
|
||||||
transferAmount = FixedPoint2.Min(PickupAmount, AvailableVolume);
|
transferAmount = FixedPoint2.Min(PickupAmount, AvailableVolume);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
transferAmount = FixedPoint2.Min(PickupAmount, puddleSolution.TotalVolume, AvailableVolume);
|
transferAmount = FixedPoint2.Min(PickupAmount, puddleSolution.TotalVolume, AvailableVolume);
|
||||||
|
|
||||||
|
if ((puddleSolution.TotalVolume - transferAmount) < MopLowerLimit) // If the transferAmount would bring the puddle below the MopLowerLimit
|
||||||
// is the puddle cleaned?
|
transferAmount = puddleSolution.TotalVolume - MopLowerLimit; // Then the transferAmount should bring the puddle down to the MopLowerLimit exactly
|
||||||
bool isCleaned = (puddleSolution.TotalVolume - transferAmount <= 0);
|
}
|
||||||
|
|
||||||
// Transfers solution from the puddle to the mop
|
// Transfers solution from the puddle to the mop
|
||||||
solutionSystem.TryAddSolution(Owner, contents, solutionSystem.SplitSolution(target, puddleSolution, transferAmount));
|
solutionSystem.TryAddSolution(Owner, contents, solutionSystem.SplitSolution(target, puddleSolution, transferAmount));
|
||||||
|
|
||||||
if (isCleaned)
|
|
||||||
{
|
|
||||||
// deletes the puddle
|
|
||||||
_entities.DeleteEntity(puddleComponent.Owner);
|
|
||||||
}
|
|
||||||
SoundSystem.Play(Filter.Pvs(Owner), _pickupSound.GetSound(), Owner);
|
SoundSystem.Play(Filter.Pvs(Owner), _pickupSound.GetSound(), Owner);
|
||||||
|
|
||||||
|
// if the mop became full after that puddle, let the player know.
|
||||||
|
if(AvailableVolume <= 0)
|
||||||
|
Owner.PopupMessage(eventArgs.User, Loc.GetString("mop-component-mop-is-now-full-message"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,14 @@ namespace Content.Server.Fluids.EntitySystems
|
|||||||
var volumeScale = puddleComponent.CurrentVolume.Float() / puddleComponent.OverflowVolume.Float();
|
var volumeScale = puddleComponent.CurrentVolume.Float() / puddleComponent.OverflowVolume.Float();
|
||||||
var puddleSolution = _solutionContainerSystem.EnsureSolution(uid, puddleComponent.SolutionName);
|
var puddleSolution = _solutionContainerSystem.EnsureSolution(uid, puddleComponent.SolutionName);
|
||||||
|
|
||||||
|
// Puddles with volume below this threshold will have their sprite changed to a wet floor effect
|
||||||
|
var wetFloorEffectThreshold = FixedPoint2.New(5);
|
||||||
|
// "Does this puddle's sprite need changing to the wet floor effect sprite?"
|
||||||
|
bool changeToWetFloor = (puddleComponent.CurrentVolume <= wetFloorEffectThreshold);
|
||||||
|
|
||||||
appearanceComponent.SetData(PuddleVisuals.VolumeScale, volumeScale);
|
appearanceComponent.SetData(PuddleVisuals.VolumeScale, volumeScale);
|
||||||
appearanceComponent.SetData(PuddleVisuals.SolutionColor, puddleSolution.Color);
|
appearanceComponent.SetData(PuddleVisuals.SolutionColor, puddleSolution.Color);
|
||||||
|
appearanceComponent.SetData(PuddleVisuals.ForceWetFloorSprite, changeToWetFloor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSlip(EntityUid entityUid, PuddleComponent puddleComponent)
|
private void UpdateSlip(EntityUid entityUid, PuddleComponent puddleComponent)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace Content.Shared.Fluids
|
|||||||
public enum PuddleVisuals : byte
|
public enum PuddleVisuals : byte
|
||||||
{
|
{
|
||||||
VolumeScale,
|
VolumeScale,
|
||||||
SolutionColor
|
SolutionColor,
|
||||||
|
ForceWetFloorSprite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
mop-component-mop-is-dry-message = Mop needs to be wet!
|
mop-component-mop-is-dry-message = Mop needs to be wet!
|
||||||
mop-component-mop-is-full-message = Mop is full!
|
mop-component-mop-is-full-message = Mop is full!
|
||||||
|
mop-component-mop-is-now-full-message = Mop is now full
|
||||||
@@ -151,3 +151,4 @@
|
|||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
visuals:
|
||||||
- type: PuddleVisualizer
|
- type: PuddleVisualizer
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
- type: SolutionContainerManager
|
- type: SolutionContainerManager
|
||||||
solutions:
|
solutions:
|
||||||
bucket:
|
bucket:
|
||||||
maxVol: 500
|
maxVol: 100
|
||||||
- type: SolutionTransfer
|
- type: SolutionTransfer
|
||||||
transferAmount: 50
|
transferAmount: 50
|
||||||
maxTransferAmount: 100
|
maxTransferAmount: 100
|
||||||
|
|||||||
25
Resources/Textures/Fluids/wet_floor_sparkles.rsi/meta.json
Normal file
25
Resources/Textures/Fluids/wet_floor_sparkles.rsi/meta.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "https://github.com/tgstation/tgstation/commit/505e4414959d598c0d677a9bc734067a7bb513cd",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "sparkles",
|
||||||
|
"directions": 1,
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.14,
|
||||||
|
0.14,
|
||||||
|
0.14,
|
||||||
|
0.14,
|
||||||
|
0.14,
|
||||||
|
5
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Resources/Textures/Fluids/wet_floor_sparkles.rsi/sparkles.png
Normal file
BIN
Resources/Textures/Fluids/wet_floor_sparkles.rsi/sparkles.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Reference in New Issue
Block a user