Add AutoEmote comp/system, updates to zombie code (#13932)
* Add AutoEmote comp/system * Reduce groan chance so it's the same as before Old code did 0.2 and then 0.5, now it's just one Prob(0.1) * Fix typo, curTime var, don't log Resolve * Maybe fix pausing? * Fix mistake * Update NextEmoteTime if an auto emote is removed * Fix stuff Get CurTime outside update loop Use MapInit instead of ComponentInit Fix a typo in a comment Debug assert prototype ID in RemoveEmote Do += PausedTime in OnUnpaused Add prototype as arg to ResetTimer to avoid an indexing
This commit is contained in:
134
Content.Server/Chat/Systems/AutoEmoteSystem.cs
Normal file
134
Content.Server/Chat/Systems/AutoEmoteSystem.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
namespace Content.Server.Chat.Systems;
|
||||
|
||||
using System.Linq;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
public sealed class AutoEmoteSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<AutoEmoteComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<AutoEmoteComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var curTime = _gameTiming.CurTime;
|
||||
foreach (var autoEmote in EntityQuery<AutoEmoteComponent>())
|
||||
{
|
||||
var uid = autoEmote.Owner;
|
||||
|
||||
if (autoEmote.NextEmoteTime > curTime)
|
||||
continue;
|
||||
|
||||
foreach ((var key, var time) in autoEmote.EmoteTimers)
|
||||
{
|
||||
if (time > curTime)
|
||||
continue;
|
||||
|
||||
var autoEmotePrototype = _prototypeManager.Index<AutoEmotePrototype>(key);
|
||||
ResetTimer(uid, key, autoEmote, autoEmotePrototype);
|
||||
|
||||
if (!_random.Prob(autoEmotePrototype.Chance))
|
||||
continue;
|
||||
|
||||
if (autoEmotePrototype.WithChat)
|
||||
{
|
||||
_chatSystem.TryEmoteWithChat(uid, autoEmotePrototype.EmoteId, autoEmotePrototype.HiddenFromChatWindow);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatSystem.TryEmoteWithoutChat(uid, autoEmotePrototype.EmoteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, AutoEmoteComponent autoEmote, MapInitEvent args)
|
||||
{
|
||||
// Start timers
|
||||
foreach (var autoEmotePrototypeId in autoEmote.Emotes)
|
||||
{
|
||||
ResetTimer(uid, autoEmotePrototypeId, autoEmote);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUnpaused(EntityUid uid, AutoEmoteComponent autoEmote, ref EntityUnpausedEvent args)
|
||||
{
|
||||
foreach (var key in autoEmote.EmoteTimers.Keys)
|
||||
{
|
||||
autoEmote.EmoteTimers[key] += args.PausedTime;
|
||||
}
|
||||
autoEmote.NextEmoteTime += args.PausedTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to add an emote to the entity, which will be performed at an interval.
|
||||
/// </summary>
|
||||
public bool AddEmote(EntityUid uid, string autoEmotePrototypeId, AutoEmoteComponent? autoEmote = null)
|
||||
{
|
||||
if (!Resolve(uid, ref autoEmote, logMissing: false))
|
||||
return false;
|
||||
|
||||
if (autoEmote.Emotes.Contains(autoEmotePrototypeId))
|
||||
return false;
|
||||
|
||||
autoEmote.Emotes.Add(autoEmotePrototypeId);
|
||||
ResetTimer(uid, autoEmotePrototypeId, autoEmote);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop preforming an emote.
|
||||
/// </summary>
|
||||
public bool RemoveEmote(EntityUid uid, string autoEmotePrototypeId, AutoEmoteComponent? autoEmote = null)
|
||||
{
|
||||
if (!Resolve(uid, ref autoEmote, logMissing: false))
|
||||
return false;
|
||||
|
||||
DebugTools.Assert(_prototypeManager.HasIndex<AutoEmotePrototype>(autoEmotePrototypeId), "Prototype not found. Did you make a typo?");
|
||||
|
||||
if (!autoEmote.EmoteTimers.Remove(autoEmotePrototypeId))
|
||||
return false;
|
||||
|
||||
autoEmote.NextEmoteTime = autoEmote.EmoteTimers.Values.Min();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the timer for a specific emote, or return false if it doesn't exist.
|
||||
/// </summary>
|
||||
public bool ResetTimer(EntityUid uid, string autoEmotePrototypeId, AutoEmoteComponent? autoEmote = null, AutoEmotePrototype? autoEmotePrototype = null)
|
||||
{
|
||||
if (!Resolve(uid, ref autoEmote))
|
||||
return false;
|
||||
|
||||
if (!autoEmote.Emotes.Contains(autoEmotePrototypeId))
|
||||
return false;
|
||||
|
||||
autoEmotePrototype ??= _prototypeManager.Index<AutoEmotePrototype>(autoEmotePrototypeId);
|
||||
|
||||
var curTime = _gameTiming.CurTime;
|
||||
var time = curTime + autoEmotePrototype.Interval;
|
||||
autoEmote.EmoteTimers[autoEmotePrototypeId] = time;
|
||||
|
||||
if (autoEmote.NextEmoteTime > time || autoEmote.NextEmoteTime <= curTime)
|
||||
autoEmote.NextEmoteTime = time;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user