2021-05-04 15:37:16 +02:00
using System.Threading.Tasks ;
2021-10-29 13:40:15 +01:00
using Content.Server.Chemistry.EntitySystems ;
2021-06-09 22:19:39 +02:00
using Content.Server.DoAfter ;
2021-10-27 09:24:18 +01:00
using Content.Server.Fluids.EntitySystems ;
2021-09-06 15:49:44 +02:00
using Content.Shared.Chemistry.Components ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Chemistry.Reagent ;
using Content.Shared.Interaction ;
using Content.Shared.Interaction.Helpers ;
2021-09-26 15:18:45 +02:00
using Content.Shared.Popups ;
2021-07-10 17:35:33 +02:00
using Content.Shared.Sound ;
2021-05-04 15:37:16 +02:00
using Robust.Shared.Audio ;
2020-04-22 04:23:12 +10:00
using Robust.Shared.GameObjects ;
using Robust.Shared.Localization ;
2021-03-21 09:12:03 -07:00
using Robust.Shared.Player ;
2021-03-05 01:08:38 +01:00
using Robust.Shared.Serialization.Manager.Attributes ;
2021-05-04 15:37:16 +02:00
using Robust.Shared.ViewVariables ;
2020-04-22 04:23:12 +10:00
2021-06-09 22:19:39 +02:00
namespace Content.Server.Fluids.Components
2020-04-22 04:23:12 +10:00
{
/// <summary>
/// For cleaning up puddles
/// </summary>
[RegisterComponent]
2020-05-23 17:23:25 +02:00
public class MopComponent : Component , IAfterInteract
2020-04-22 04:23:12 +10:00
{
public override string Name = > "Mop" ;
2021-09-06 15:49:44 +02:00
public const string SolutionName = "mop" ;
2020-08-24 13:39:00 +02:00
2021-02-25 11:32:08 +11:00
/// <summary>
/// Used to prevent do_after spam if we're currently mopping.
/// </summary>
2021-03-05 01:08:38 +01:00
public bool Mopping { get ; private set ; }
2021-02-25 11:32:08 +11:00
2021-09-06 15:49:44 +02:00
public Solution ? MopSolution
{
get
{
EntitySystem . Get < SolutionContainerSystem > ( ) . TryGetSolution ( Owner , SolutionName , out var solution ) ;
return solution ;
}
}
2020-04-22 04:23:12 +10:00
public ReagentUnit MaxVolume
{
2021-09-06 15:49:44 +02:00
get = > MopSolution ? . MaxVolume ? ? ReagentUnit . Zero ;
2020-08-24 13:39:00 +02:00
set
{
2021-09-06 15:49:44 +02:00
var solution = MopSolution ;
if ( solution ! = null )
2020-08-24 13:39:00 +02:00
{
solution . MaxVolume = value ;
}
}
2020-04-22 04:23:12 +10:00
}
2021-09-06 15:49:44 +02:00
public ReagentUnit CurrentVolume = > MopSolution ? . CurrentVolume ? ? ReagentUnit . Zero ;
2020-04-22 04:23:12 +10:00
// Currently there's a separate amount for pickup and dropoff so
// Picking up a puddle requires multiple clicks
// Dumping in a bucket requires 1 click
// Long-term you'd probably use a cooldown and start the pickup once we have some form of global cooldown
2021-05-04 15:37:16 +02:00
[DataField("pickup_amount")]
2021-03-05 01:08:38 +01:00
public ReagentUnit PickupAmount { get ; } = ReagentUnit . New ( 5 ) ;
2020-04-22 04:23:12 +10:00
2021-03-05 01:08:38 +01:00
[DataField("pickup_sound")]
2021-07-10 17:35:33 +02:00
private SoundSpecifier _pickupSound = new SoundPathSpecifier ( "/Audio/Effects/Fluids/slosh.ogg" ) ;
2021-02-25 11:32:08 +11:00
/// <summary>
/// Multiplier for the do_after delay for how fast the mop works.
/// </summary>
[ViewVariables]
2021-09-06 15:49:44 +02:00
[DataField("speed")] private float _mopSpeed = 1 ;
2020-04-22 04:23:12 +10:00
2021-02-03 14:05:31 +01:00
async Task < bool > IAfterInteract . AfterInteract ( AfterInteractEventArgs eventArgs )
2020-04-22 04:23:12 +10:00
{
2021-02-25 11:32:08 +11:00
/ *
* Functionality :
* Essentially if we click on an empty tile spill our contents there
* Otherwise , try to mop up the puddle ( if it is a puddle ) .
* It will try to destroy solution on the mop to do so , and if it is successful
* will spill some of the mop ' s solution onto the puddle which will evaporate eventually .
* /
2021-09-06 15:49:44 +02:00
if ( ! EntitySystem . Get < SolutionContainerSystem > ( ) . TryGetSolution ( Owner , SolutionName , out var contents ) | |
2021-03-05 01:08:38 +01:00
Mopping | |
2021-02-25 11:32:08 +11:00
! eventArgs . InRangeUnobstructed ( ignoreInsideBlocker : true , popup : true ) )
2020-07-11 16:49:54 -05:00
{
2021-02-25 11:32:08 +11:00
return false ;
2020-07-11 16:49:54 -05:00
}
2021-02-25 11:32:08 +11:00
var currentVolume = CurrentVolume ;
2020-05-23 17:23:25 +02:00
if ( eventArgs . Target = = null )
2020-04-22 04:23:12 +10:00
{
2021-02-25 11:32:08 +11:00
if ( currentVolume > 0 )
{
// Drop the liquid on the mop on to the ground
2021-09-06 15:49:44 +02:00
EntitySystem . Get < SolutionContainerSystem > ( ) . SplitSolution ( Owner . Uid , contents , CurrentVolume )
. SpillAt ( eventArgs . ClickLocation , "PuddleSmear" ) ;
2021-02-25 11:32:08 +11:00
return true ;
}
2020-04-22 04:23:12 +10:00
2021-02-25 11:32:08 +11:00
return false ;
2020-04-22 04:23:12 +10:00
}
2020-08-24 13:39:00 +02:00
if ( ! eventArgs . Target . TryGetComponent ( out PuddleComponent ? puddleComponent ) )
2020-04-22 04:23:12 +10:00
{
2021-02-25 11:32:08 +11:00
return false ;
}
var puddleVolume = puddleComponent . CurrentVolume ;
if ( currentVolume < = 0 )
{
2021-06-21 02:13:54 +02:00
Owner . PopupMessage ( eventArgs . User , Loc . GetString ( "mop-component-mop-is-dry-message" ) ) ;
2021-02-25 11:32:08 +11:00
return false ;
2020-04-22 04:23:12 +10:00
}
2021-02-25 11:32:08 +11:00
2021-03-05 01:08:38 +01:00
Mopping = true ;
2021-02-25 11:32:08 +11:00
// So if the puddle has 20 units we mop in 2 seconds. Don't just store CurrentVolume given it can change so need to re-calc it anyway.
2021-09-06 15:49:44 +02:00
var doAfterArgs = new DoAfterEventArgs ( eventArgs . User , _mopSpeed * puddleVolume . Float ( ) / 10.0f ,
target : eventArgs . Target )
2021-02-25 11:32:08 +11:00
{
BreakOnUserMove = true ,
BreakOnStun = true ,
BreakOnDamage = true ,
} ;
2021-07-04 13:32:24 +02:00
var result = await EntitySystem . Get < DoAfterSystem > ( ) . WaitDoAfter ( doAfterArgs ) ;
2021-02-25 11:32:08 +11:00
2021-03-05 01:08:38 +01:00
Mopping = false ;
2021-02-25 11:32:08 +11:00
if ( result = = DoAfterStatus . Cancelled | |
Owner . Deleted | |
puddleComponent . Deleted )
return false ;
// Annihilate the puddle
2020-07-11 16:49:54 -05:00
var transferAmount = ReagentUnit . Min ( ReagentUnit . New ( 5 ) , puddleComponent . CurrentVolume , CurrentVolume ) ;
2021-02-25 11:32:08 +11:00
var puddleCleaned = puddleComponent . CurrentVolume - transferAmount < = 0 ;
2020-07-11 16:49:54 -05:00
2021-10-27 09:24:18 +01:00
var puddleSystem = EntitySystem . Get < PuddleSystem > ( ) ;
var solutionSystem = EntitySystem . Get < SolutionContainerSystem > ( ) ;
2020-04-22 04:23:12 +10:00
if ( transferAmount = = 0 )
{
2021-10-27 09:24:18 +01:00
if ( puddleSystem . EmptyHolder ( puddleComponent . Owner . Uid , puddleComponent ) ) //The puddle doesn't actually *have* reagents, for example vomit because there's no "vomit" reagent.
2020-07-11 16:49:54 -05:00
{
puddleComponent . Owner . Delete ( ) ;
transferAmount = ReagentUnit . Min ( ReagentUnit . New ( 5 ) , CurrentVolume ) ;
puddleCleaned = true ;
}
else
{
2021-02-03 14:05:31 +01:00
return true ;
2020-07-11 16:49:54 -05:00
}
}
else
{
2021-10-27 09:24:18 +01:00
if ( solutionSystem . TryGetSolution ( eventArgs . Target , puddleComponent . SolutionName , out var puddleSolution ) )
solutionSystem . SplitSolution ( eventArgs . Target . Uid , puddleSolution , transferAmount ) ;
2020-04-22 04:23:12 +10:00
}
2021-10-27 09:24:18 +01:00
if ( puddleCleaned ) //After cleaning the puddle, make a new puddle with solution from the mop as a "wet floor". Then evaporate it slowly.
2020-07-11 16:49:54 -05:00
{
2021-10-27 09:24:18 +01:00
solutionSystem . SplitSolution ( Owner . Uid , contents , transferAmount )
2021-09-06 15:49:44 +02:00
. SpillAt ( eventArgs . ClickLocation , "PuddleSmear" ) ;
2020-07-11 16:49:54 -05:00
}
else
2020-04-22 04:23:12 +10:00
{
2021-09-06 15:49:44 +02:00
EntitySystem . Get < SolutionContainerSystem > ( ) . SplitSolution ( Owner . Uid , contents , transferAmount ) ;
2020-04-22 04:23:12 +10:00
}
2021-07-31 19:52:33 +02:00
SoundSystem . Play ( Filter . Pvs ( Owner ) , _pickupSound . GetSound ( ) , Owner ) ;
2020-04-22 04:23:12 +10:00
2021-02-03 14:05:31 +01:00
return true ;
2020-04-22 04:23:12 +10:00
}
}
}