using Content.Shared.Database;
using Content.Shared.Humanoid;
using Content.Shared.Mobs.Components;
using Robust.Shared.Player;
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 _mobStateQuery.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 (!_mobStateQuery.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 without triggering UpdateMobState events.
/// WARNING: use this sparingly when you need to override other systems (MobThresholds)
///
/// 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 (!_mobStateQuery.Resolve(entity, ref component))
return;
ChangeState(entity, component, mobState, origin: origin);
}
#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);
if (origin != null && HasComp(origin) && HasComp(target) && oldState < newState)
_adminLogger.Add(LogType.Damaged, LogImpact.High, $"{ToPrettyString(origin):player} caused {ToPrettyString(target):player} state to change from {oldState} to {newState}");
else
_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);