| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- using Content.Shared.Hands.Components;
- using Content.Shared.Physics;
- using Content.Shared.Rotation;
- using Robust.Shared.Audio;
- using Robust.Shared.Audio.Systems;
- using Robust.Shared.Physics;
- using Robust.Shared.Physics.Systems;
- namespace Content.Shared.Standing
- {
- public sealed class StandingStateSystem : EntitySystem
- {
- [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly SharedPhysicsSystem _physics = default!;
- // If StandingCollisionLayer value is ever changed to more than one layer, the logic needs to be edited.
- private const int StandingCollisionLayer = (int) CollisionGroup.MidImpassable;
- public bool IsDown(EntityUid uid, StandingStateComponent? standingState = null)
- {
- if (!Resolve(uid, ref standingState, false))
- return false;
- return !standingState.Standing;
- }
- public bool Down(EntityUid uid,
- bool playSound = true,
- bool dropHeldItems = true,
- bool force = false,
- StandingStateComponent? standingState = null,
- AppearanceComponent? appearance = null,
- HandsComponent? hands = null)
- {
- // TODO: This should actually log missing comps...
- if (!Resolve(uid, ref standingState, false))
- return false;
- // Optional component.
- Resolve(uid, ref appearance, ref hands, false);
- if (!standingState.Standing)
- return true;
- // This is just to avoid most callers doing this manually saving boilerplate
- // 99% of the time you'll want to drop items but in some scenarios (e.g. buckling) you don't want to.
- // We do this BEFORE downing because something like buckle may be blocking downing but we want to drop hand items anyway
- // and ultimately this is just to avoid boilerplate in Down callers + keep their behavior consistent.
- if (dropHeldItems && hands != null)
- {
- RaiseLocalEvent(uid, new DropHandItemsEvent(), false);
- }
- if (!force)
- {
- var msg = new DownAttemptEvent();
- RaiseLocalEvent(uid, msg, false);
- if (msg.Cancelled)
- return false;
- }
- standingState.Standing = false;
- Dirty(uid, standingState);
- RaiseLocalEvent(uid, new DownedEvent(), false);
- // Seemed like the best place to put it
- _appearance.SetData(uid, RotationVisuals.RotationState, RotationState.Horizontal, appearance);
- // Change collision masks to allow going under certain entities like flaps and tables
- if (TryComp(uid, out FixturesComponent? fixtureComponent))
- {
- foreach (var (key, fixture) in fixtureComponent.Fixtures)
- {
- if ((fixture.CollisionMask & StandingCollisionLayer) == 0)
- continue;
- standingState.ChangedFixtures.Add(key);
- _physics.SetCollisionMask(uid, key, fixture, fixture.CollisionMask & ~StandingCollisionLayer, manager: fixtureComponent);
- }
- }
- // check if component was just added or streamed to client
- // if true, no need to play sound - mob was down before player could seen that
- if (standingState.LifeStage <= ComponentLifeStage.Starting)
- return true;
- if (playSound)
- {
- _audio.PlayPredicted(standingState.DownSound, uid, uid);
- }
- return true;
- }
- public bool Stand(EntityUid uid,
- StandingStateComponent? standingState = null,
- AppearanceComponent? appearance = null,
- bool force = false)
- {
- // TODO: This should actually log missing comps...
- if (!Resolve(uid, ref standingState, false))
- return false;
- // Optional component.
- Resolve(uid, ref appearance, false);
- if (standingState.Standing)
- return true;
- if (!force)
- {
- var msg = new StandAttemptEvent();
- RaiseLocalEvent(uid, msg, false);
- if (msg.Cancelled)
- return false;
- }
- standingState.Standing = true;
- Dirty(uid, standingState);
- RaiseLocalEvent(uid, new StoodEvent(), false);
- _appearance.SetData(uid, RotationVisuals.RotationState, RotationState.Vertical, appearance);
- if (TryComp(uid, out FixturesComponent? fixtureComponent))
- {
- foreach (var key in standingState.ChangedFixtures)
- {
- if (fixtureComponent.Fixtures.TryGetValue(key, out var fixture))
- _physics.SetCollisionMask(uid, key, fixture, fixture.CollisionMask | StandingCollisionLayer, fixtureComponent);
- }
- }
- standingState.ChangedFixtures.Clear();
- return true;
- }
- }
- public sealed class DropHandItemsEvent : EventArgs
- {
- }
- /// <summary>
- /// Subscribe if you can potentially block a down attempt.
- /// </summary>
- public sealed class DownAttemptEvent : CancellableEntityEventArgs
- {
- }
- /// <summary>
- /// Subscribe if you can potentially block a stand attempt.
- /// </summary>
- public sealed class StandAttemptEvent : CancellableEntityEventArgs
- {
- }
- /// <summary>
- /// Raised when an entity becomes standing
- /// </summary>
- public sealed class StoodEvent : EntityEventArgs
- {
- }
- /// <summary>
- /// Raised when an entity is not standing
- /// </summary>
- public sealed class DownedEvent : EntityEventArgs
- {
- }
- }
|