using Content.Shared.Database; using Content.Shared.Mobs.Components; namespace Content.Shared.Mobs.Systems; public partial class MobStateSystem { #region Public API /// /// Check if an Entity can be set to a particular MobState /// /// Target Entity /// MobState to check /// MobState Component owned by the target /// If the entity can be set to that MobState public bool HasState(EntityUid entity, MobState mobState, MobStateComponent? component = null) { return Resolve(entity, ref component, false) && component.AllowedStates.Contains(mobState); } /// /// Run a MobState update check. This will trigger update events if the state has been changed. /// /// Target Entity we want to change the MobState of /// MobState Component attached to the entity /// Entity that caused the state update (if applicable) public void UpdateMobState(EntityUid entity, MobStateComponent? component = null, EntityUid? origin = null) { if (!Resolve(entity, ref component)) return; var ev = new UpdateMobStateEvent {Target = entity, Component = component, Origin = origin}; RaiseLocalEvent(entity, ref ev); ChangeState(entity, component, ev.State, origin: origin); } /// /// Change the MobState and trigger MobState update events /// /// Target Entity we want to change the MobState of /// The new MobState we want to set /// MobState Component attached to the entity /// Entity that caused the state update (if applicable) public void ChangeMobState(EntityUid entity, MobState mobState, MobStateComponent? component = null, EntityUid? origin = null) { if (!Resolve(entity, ref component)) return; var ev = new UpdateMobStateEvent {Target = entity, Component = component, Origin = origin, State = mobState}; RaiseLocalEvent(entity, ref ev); ChangeState(entity, component, ev.State); } #endregion #region Virtual API /// /// Called when a new MobState is entered. /// /// The owner of the MobState Component /// MobState Component owned by the target /// The new MobState protected virtual void OnEnterState(EntityUid entity, MobStateComponent component, MobState state) { OnStateEnteredSubscribers(entity, component, state); } /// /// Called when this entity changes MobState /// /// The owner of the MobState Component /// MobState Component owned by the target /// The previous MobState /// The new MobState protected virtual void OnStateChanged(EntityUid entity, MobStateComponent component, MobState oldState, MobState newState) { } /// /// Called when a new MobState is exited. /// /// The owner of the MobState Component /// MobState Component owned by the target /// The old MobState protected virtual void OnExitState(EntityUid entity, MobStateComponent component, MobState state) { OnStateExitSubscribers(entity, component, state); } #endregion #region Private Implementation //Actually change the MobState private void ChangeState(EntityUid target, MobStateComponent component, MobState newState, EntityUid? origin = null) { var oldState = component.CurrentState; //make sure we are allowed to enter the new state if (oldState == newState || !component.AllowedStates.Contains(newState)) return; OnExitState(target, component, oldState); component.CurrentState = newState; OnEnterState(target, component, newState); var ev = new MobStateChangedEvent(target, component, oldState, newState, origin); OnStateChanged(target, component, oldState, newState); RaiseLocalEvent(target, ev, true); _adminLogger.Add(LogType.Damaged, oldState == MobState.Alive ? LogImpact.Low : LogImpact.Medium, $"{ToPrettyString(target):user} state changed from {oldState} to {newState}"); Dirty(target, component); } #endregion } /// /// Event that gets triggered when we want to update the mobstate. This allows for systems to override MobState changes /// /// The Entity whose MobState is changing /// The MobState Component owned by the Target /// The new MobState we want to set /// Entity that caused the state update (if applicable) [ByRefEvent] public record struct UpdateMobStateEvent(EntityUid Target, MobStateComponent Component, MobState State, EntityUid? Origin = null);