using Content.Shared.Bed.Sleep; using Content.Shared.CombatMode.Pacification; using Content.Shared.Damage.ForceSay; using Content.Shared.Emoting; using Content.Shared.Hands; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Inventory.Events; using Content.Shared.Item; using Content.Shared.Mobs.Components; using Content.Shared.Movement.Events; using Content.Shared.Pointing; using Content.Shared.Projectiles; using Content.Shared.Pulling.Events; using Content.Shared.Speech; using Content.Shared.Standing; using Content.Shared.Strip.Components; using Content.Shared.Throwing; using Content.Shared.Weapons.Ranged.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; namespace Content.Shared.Mobs.Systems; public partial class MobStateSystem { //General purpose event subscriptions. If you can avoid it register these events inside their own systems private void SubscribeEvents() { SubscribeLocalEvent(OnGettingStripped); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckConcious); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(OnSpeakAttempt); SubscribeLocalEvent(OnEquipAttempt); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(OnUnequipAttempt); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(OnSleepAttempt); SubscribeLocalEvent(OnCombatModeShouldHandInteract); SubscribeLocalEvent(OnAttemptPacifiedAttack); } private void CheckConcious(Entity ent, ref ConsciousAttemptEvent args) { switch (ent.Comp.CurrentState) { case MobState.Dead: case MobState.Critical: args.Cancelled = true; break; } } private void OnStateExitSubscribers(EntityUid target, MobStateComponent component, MobState state) { switch (state) { case MobState.Alive: //unused break; case MobState.Critical: _standing.Stand(target); break; case MobState.Dead: RemComp(target); _standing.Stand(target); if (!_standing.IsDown(target) && TryComp(target, out var physics)) { _physics.SetCanCollide(target, true, body: physics); } break; case MobState.Invalid: //unused break; default: throw new NotImplementedException(); } } private void OnStateEnteredSubscribers(EntityUid target, MobStateComponent component, MobState state) { // All of the state changes here should already be networked, so we do nothing if we are currently applying a // server state. if (_timing.ApplyingState) return; _blocker.UpdateCanMove(target); //update movement anytime a state changes switch (state) { case MobState.Alive: _standing.Stand(target); _appearance.SetData(target, MobStateVisuals.State, MobState.Alive); break; case MobState.Critical: _standing.Down(target); _appearance.SetData(target, MobStateVisuals.State, MobState.Critical); break; case MobState.Dead: EnsureComp(target); _standing.Down(target); if (_standing.IsDown(target) && TryComp(target, out var physics)) { _physics.SetCanCollide(target, false, body: physics); } _appearance.SetData(target, MobStateVisuals.State, MobState.Dead); break; case MobState.Invalid: //unused; break; default: throw new NotImplementedException(); } } #region Event Subscribers private void OnSleepAttempt(EntityUid target, MobStateComponent component, ref TryingToSleepEvent args) { if (IsDead(target, component)) args.Cancelled = true; } private void OnGettingStripped(EntityUid target, MobStateComponent component, BeforeGettingStrippedEvent args) { // Incapacitated or dead targets get stripped two or three times as fast. Makes stripping corpses less tedious. if (IsDead(target, component)) args.Multiplier /= 3; else if (IsCritical(target, component)) args.Multiplier /= 2; } private void OnSpeakAttempt(EntityUid uid, MobStateComponent component, SpeakAttemptEvent args) { if (HasComp(uid)) { RemCompDeferred(uid); return; } CheckAct(uid, component, args); } private void CheckAct(EntityUid target, MobStateComponent component, CancellableEntityEventArgs args) { switch (component.CurrentState) { case MobState.Dead: case MobState.Critical: args.Cancel(); break; } } private void OnEquipAttempt(EntityUid target, MobStateComponent component, IsEquippingAttemptEvent args) { // is this a self-equip, or are they being stripped? if (args.Equipee == target) CheckAct(target, component, args); } private void OnUnequipAttempt(EntityUid target, MobStateComponent component, IsUnequippingAttemptEvent args) { // is this a self-equip, or are they being stripped? if (args.Unequipee == target) CheckAct(target, component, args); } private void OnCombatModeShouldHandInteract(EntityUid uid, MobStateComponent component, ref CombatModeShouldHandInteractEvent args) { // Disallow empty-hand-interacting in combat mode // for non-dead mobs if (!IsDead(uid, component)) args.Cancelled = true; } private void OnAttemptPacifiedAttack(Entity ent, ref AttemptPacifiedAttackEvent args) { args.Cancelled = true; } #endregion }