Files
tbd-station-14/Content.Shared/Nutrition/EntitySystems/SharedDrinkSystem.cs
Tayrtahn cfa94be4c2 Add ability to shake fizzy drinks so they spray in peoples' faces (#25574)
* Implemented Shakeable

* Prevent shaking open Openables

* Prevent shaking empty drinks. Moved part of DrinkSystem to Shared.

* DrinkSystem can have a little more prediction, as a treat

* Cleanup

* Overhauled PressurizedDrink

* Make soda cans/bottles and champagne shakeable. The drink shaker too, for fun.

* We do a little refactoring.
PressurizedDrink is now PressurizedSolution, and fizziness now only works on solutions containing a reagent marked as fizzy.

* Documentation, cleanup, and tweaks.

* Changed fizziness calculation to use a cubic-out easing curve.

* Removed broken YAML that has avoid the linter's wrath for far too long

* Changed reagent fizzy bool to fizziness float.
Solution fizzability now scales with reagent proportion.

* Rename file to match changed class name

* DoAfter improvements. Cancel if the user moves away; block if no hands.

* Match these filenames too

* And this one

* guh

* Updated to use Shared puddle methods

* Various fixes and improvements.

* Made AttemptShakeEvent a struct

* AttemptAddFizzinessEvent too
2024-04-18 11:49:58 +10:00

91 lines
3.2 KiB
C#

using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Nutrition.Components;
namespace Content.Shared.Nutrition.EntitySystems;
public abstract partial class SharedDrinkSystem : EntitySystem
{
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly OpenableSystem _openable = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DrinkComponent, AttemptShakeEvent>(OnAttemptShake);
SubscribeLocalEvent<DrinkComponent, ExaminedEvent>(OnExamined);
}
protected void OnAttemptShake(Entity<DrinkComponent> entity, ref AttemptShakeEvent args)
{
if (IsEmpty(entity, entity.Comp))
args.Cancelled = true;
}
protected void OnExamined(Entity<DrinkComponent> entity, ref ExaminedEvent args)
{
TryComp<OpenableComponent>(entity, out var openable);
if (_openable.IsClosed(entity.Owner, null, openable) || !args.IsInDetailsRange || !entity.Comp.Examinable)
return;
var empty = IsEmpty(entity, entity.Comp);
if (empty)
{
args.PushMarkup(Loc.GetString("drink-component-on-examine-is-empty"));
return;
}
if (HasComp<ExaminableSolutionComponent>(entity))
{
//provide exact measurement for beakers
args.PushText(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(entity, entity.Comp))));
}
else
{
//general approximation
var remainingString = (int) _solutionContainer.PercentFull(entity) switch
{
100 => "drink-component-on-examine-is-full",
> 66 => "drink-component-on-examine-is-mostly-full",
> 33 => HalfEmptyOrHalfFull(args),
_ => "drink-component-on-examine-is-mostly-empty",
};
args.PushMarkup(Loc.GetString(remainingString));
}
}
protected FixedPoint2 DrinkVolume(EntityUid uid, DrinkComponent? component = null)
{
if (!Resolve(uid, ref component))
return FixedPoint2.Zero;
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out _, out var sol))
return FixedPoint2.Zero;
return sol.Volume;
}
protected bool IsEmpty(EntityUid uid, DrinkComponent? component = null)
{
if (!Resolve(uid, ref component))
return true;
return DrinkVolume(uid, component) <= 0;
}
// some see half empty, and others see half full
private string HalfEmptyOrHalfFull(ExaminedEvent args)
{
string remainingString = "drink-component-on-examine-is-half-full";
if (TryComp<MetaDataComponent>(args.Examiner, out var examiner) && examiner.EntityName.Length > 0
&& string.Compare(examiner.EntityName.Substring(0, 1), "m", StringComparison.InvariantCultureIgnoreCase) > 0)
remainingString = "drink-component-on-examine-is-half-empty";
return remainingString;
}
}