Tippy, the helpful hint clown! (#26767)
* Tippy is BACK * Clean up clippy from aprils fools * Changed names from clippy to tippy, added localization, removed local_clippy command, made it easier to target a specific player * Rename clippy.yml to tippy.yml --------- Co-authored-by: Kara <lunarautomaton6@gmail.com>
This commit is contained in:
11
Content.Client/Tips/TippyUI.xaml
Normal file
11
Content.Client/Tips/TippyUI.xaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<tips:TippyUI xmlns="https://spacestation14.io"
|
||||||
|
xmlns:tips="clr-namespace:Content.Client.Tips"
|
||||||
|
MinSize="64 64"
|
||||||
|
Visible="False">
|
||||||
|
<PanelContainer Name="LabelPanel" Access="Public" Visible="False" MaxWidth="300" MaxHeight="200">
|
||||||
|
<ScrollContainer Name="ScrollingContents" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="False" ReturnMeasure="True">
|
||||||
|
<RichTextLabel Name="Label" Access="Public"/>
|
||||||
|
</ScrollContainer>
|
||||||
|
</PanelContainer>
|
||||||
|
<SpriteView Name="Entity" Access="Public" MinSize="128 128"/>
|
||||||
|
</tips:TippyUI>
|
||||||
54
Content.Client/Tips/TippyUI.xaml.cs
Normal file
54
Content.Client/Tips/TippyUI.xaml.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using Content.Client.Paper;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.ResourceManagement;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
|
||||||
|
namespace Content.Client.Tips;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class TippyUI : UIWidget
|
||||||
|
{
|
||||||
|
public TippyState State = TippyState.Hidden;
|
||||||
|
public bool ModifyLayers = true;
|
||||||
|
|
||||||
|
public TippyUI()
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitLabel(PaperVisualsComponent? visuals, IResourceCache resCache)
|
||||||
|
{
|
||||||
|
if (visuals == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Label.ModulateSelfOverride = visuals.FontAccentColor;
|
||||||
|
|
||||||
|
if (visuals.BackgroundImagePath == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LabelPanel.ModulateSelfOverride = visuals.BackgroundModulate;
|
||||||
|
var backgroundImage = resCache.GetResource<TextureResource>(visuals.BackgroundImagePath);
|
||||||
|
var backgroundImageMode = visuals.BackgroundImageTile ? StyleBoxTexture.StretchMode.Tile : StyleBoxTexture.StretchMode.Stretch;
|
||||||
|
var backgroundPatchMargin = visuals.BackgroundPatchMargin;
|
||||||
|
LabelPanel.PanelOverride = new StyleBoxTexture
|
||||||
|
{
|
||||||
|
Texture = backgroundImage,
|
||||||
|
TextureScale = visuals.BackgroundScale,
|
||||||
|
Mode = backgroundImageMode,
|
||||||
|
PatchMarginLeft = backgroundPatchMargin.Left,
|
||||||
|
PatchMarginBottom = backgroundPatchMargin.Bottom,
|
||||||
|
PatchMarginRight = backgroundPatchMargin.Right,
|
||||||
|
PatchMarginTop = backgroundPatchMargin.Top
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TippyState : byte
|
||||||
|
{
|
||||||
|
Hidden,
|
||||||
|
Revealing,
|
||||||
|
Speaking,
|
||||||
|
Hiding,
|
||||||
|
}
|
||||||
|
}
|
||||||
244
Content.Client/Tips/TippyUIController.cs
Normal file
244
Content.Client/Tips/TippyUIController.cs
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
using Content.Client.Gameplay;
|
||||||
|
using System.Numerics;
|
||||||
|
using Content.Client.Message;
|
||||||
|
using Content.Client.Paper;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Movement.Components;
|
||||||
|
using Content.Shared.Tips;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.ResourceManagement;
|
||||||
|
using Robust.Client.State;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Client.UserInterface.Controllers;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.Audio;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using static Content.Client.Tips.TippyUI;
|
||||||
|
|
||||||
|
namespace Content.Client.Tips;
|
||||||
|
|
||||||
|
public sealed class TippyUIController : UIController
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IStateManager _state = default!;
|
||||||
|
[Dependency] private readonly IConsoleHost _conHost = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
[Dependency] private readonly IResourceCache _resCache = default!;
|
||||||
|
[UISystemDependency] private readonly AudioSystem _audio = default!;
|
||||||
|
[UISystemDependency] private readonly EntityManager _entSys = default!;
|
||||||
|
|
||||||
|
public const float Padding = 50;
|
||||||
|
public static Angle WaddleRotation = Angle.FromDegrees(10);
|
||||||
|
|
||||||
|
private EntityUid _entity;
|
||||||
|
private float _secondsUntilNextState;
|
||||||
|
private int _previousStep = 0;
|
||||||
|
private TippyEvent? _currentMessage;
|
||||||
|
private readonly Queue<TippyEvent> _queuedMessages = new();
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
UIManager.OnScreenChanged += OnScreenChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMessage(TippyEvent ev)
|
||||||
|
{
|
||||||
|
_queuedMessages.Enqueue(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void FrameUpdate(FrameEventArgs args)
|
||||||
|
{
|
||||||
|
base.FrameUpdate(args);
|
||||||
|
|
||||||
|
var screen = UIManager.ActiveScreen;
|
||||||
|
if (screen == null)
|
||||||
|
{
|
||||||
|
_queuedMessages.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tippy = screen.GetOrAddWidget<TippyUI>();
|
||||||
|
_secondsUntilNextState -= args.DeltaSeconds;
|
||||||
|
|
||||||
|
if (_secondsUntilNextState <= 0)
|
||||||
|
NextState(tippy);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pos = UpdatePosition(tippy, screen.Size, args); ;
|
||||||
|
LayoutContainer.SetPosition(tippy, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2 UpdatePosition(TippyUI tippy, Vector2 screenSize, FrameEventArgs args)
|
||||||
|
{
|
||||||
|
if (_currentMessage == null)
|
||||||
|
return default;
|
||||||
|
|
||||||
|
var slideTime = _currentMessage.SlideTime;
|
||||||
|
|
||||||
|
var offset = tippy.State switch
|
||||||
|
{
|
||||||
|
TippyState.Hidden => 0,
|
||||||
|
TippyState.Revealing => Math.Clamp(1 - _secondsUntilNextState / slideTime, 0, 1),
|
||||||
|
TippyState.Hiding => Math.Clamp(_secondsUntilNextState / slideTime, 0, 1),
|
||||||
|
_ => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
var waddle = _currentMessage.WaddleInterval;
|
||||||
|
|
||||||
|
if (_currentMessage == null
|
||||||
|
|| waddle <= 0
|
||||||
|
|| tippy.State == TippyState.Hidden
|
||||||
|
|| tippy.State == TippyState.Speaking
|
||||||
|
|| !EntityManager.TryGetComponent(_entity, out SpriteComponent? sprite))
|
||||||
|
{
|
||||||
|
return new Vector2(screenSize.X - offset * (tippy.DesiredSize.X + Padding), (screenSize.Y - tippy.DesiredSize.Y) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var numSteps = (int) Math.Ceiling(slideTime / waddle);
|
||||||
|
var curStep = (int) Math.Floor(numSteps * offset);
|
||||||
|
var stepSize = (tippy.DesiredSize.X + Padding) / numSteps;
|
||||||
|
|
||||||
|
if (curStep != _previousStep)
|
||||||
|
{
|
||||||
|
_previousStep = curStep;
|
||||||
|
sprite.Rotation = sprite.Rotation > 0
|
||||||
|
? -WaddleRotation
|
||||||
|
: WaddleRotation;
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent(_entity, out FootstepModifierComponent? step))
|
||||||
|
{
|
||||||
|
var audioParams = step.FootstepSoundCollection.Params
|
||||||
|
.AddVolume(-7f)
|
||||||
|
.WithVariation(0.1f);
|
||||||
|
_audio.PlayGlobal(step.FootstepSoundCollection, EntityUid.Invalid, audioParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Vector2(screenSize.X - stepSize * curStep, (screenSize.Y - tippy.DesiredSize.Y) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NextState(TippyUI tippy)
|
||||||
|
{
|
||||||
|
SpriteComponent? sprite;
|
||||||
|
switch (tippy.State)
|
||||||
|
{
|
||||||
|
case TippyState.Hidden:
|
||||||
|
if (!_queuedMessages.TryDequeue(out var next))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (next.Proto != null)
|
||||||
|
{
|
||||||
|
_entity = EntityManager.SpawnEntity(next.Proto, MapCoordinates.Nullspace);
|
||||||
|
tippy.ModifyLayers = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_entity = EntityManager.SpawnEntity(_cfg.GetCVar(CCVars.TippyEntity), MapCoordinates.Nullspace);
|
||||||
|
tippy.ModifyLayers = true;
|
||||||
|
}
|
||||||
|
if (!EntityManager.TryGetComponent(_entity, out sprite))
|
||||||
|
return;
|
||||||
|
if (!EntityManager.HasComponent<PaperVisualsComponent>(_entity))
|
||||||
|
{
|
||||||
|
var paper = EntityManager.AddComponent<PaperVisualsComponent>(_entity);
|
||||||
|
paper.BackgroundImagePath = "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png";
|
||||||
|
paper.BackgroundPatchMargin = new(16f, 16f, 16f, 16f);
|
||||||
|
paper.BackgroundModulate = new(255, 255, 204);
|
||||||
|
paper.FontAccentColor = new(0, 0, 0);
|
||||||
|
}
|
||||||
|
tippy.InitLabel(EntityManager.GetComponentOrNull<PaperVisualsComponent>(_entity), _resCache);
|
||||||
|
|
||||||
|
var scale = sprite.Scale;
|
||||||
|
if (tippy.ModifyLayers)
|
||||||
|
{
|
||||||
|
sprite.Scale = Vector2.One;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprite.Scale = new Vector2(3, 3);
|
||||||
|
}
|
||||||
|
tippy.Entity.SetEntity(_entity);
|
||||||
|
tippy.Entity.Scale = scale;
|
||||||
|
|
||||||
|
_currentMessage = next;
|
||||||
|
_secondsUntilNextState = next.SlideTime;
|
||||||
|
tippy.State = TippyState.Revealing;
|
||||||
|
_previousStep = 0;
|
||||||
|
if (tippy.ModifyLayers)
|
||||||
|
{
|
||||||
|
sprite.LayerSetAnimationTime("revealing", 0);
|
||||||
|
sprite.LayerSetVisible("revealing", true);
|
||||||
|
sprite.LayerSetVisible("speaking", false);
|
||||||
|
sprite.LayerSetVisible("hiding", false);
|
||||||
|
}
|
||||||
|
sprite.Rotation = 0;
|
||||||
|
tippy.Label.SetMarkup(_currentMessage.Msg);
|
||||||
|
tippy.Label.Visible = false;
|
||||||
|
tippy.LabelPanel.Visible = false;
|
||||||
|
tippy.Visible = true;
|
||||||
|
sprite.Visible = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TippyState.Revealing:
|
||||||
|
tippy.State = TippyState.Speaking;
|
||||||
|
if (!EntityManager.TryGetComponent(_entity, out sprite))
|
||||||
|
return;
|
||||||
|
sprite.Rotation = 0;
|
||||||
|
_previousStep = 0;
|
||||||
|
if (tippy.ModifyLayers)
|
||||||
|
{
|
||||||
|
sprite.LayerSetAnimationTime("speaking", 0);
|
||||||
|
sprite.LayerSetVisible("revealing", false);
|
||||||
|
sprite.LayerSetVisible("speaking", true);
|
||||||
|
sprite.LayerSetVisible("hiding", false);
|
||||||
|
}
|
||||||
|
tippy.Label.Visible = true;
|
||||||
|
tippy.LabelPanel.Visible = true;
|
||||||
|
tippy.InvalidateArrange();
|
||||||
|
tippy.InvalidateMeasure();
|
||||||
|
if (_currentMessage != null)
|
||||||
|
_secondsUntilNextState = _currentMessage.SpeakTime;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TippyState.Speaking:
|
||||||
|
tippy.State = TippyState.Hiding;
|
||||||
|
if (!EntityManager.TryGetComponent(_entity, out sprite))
|
||||||
|
return;
|
||||||
|
if (tippy.ModifyLayers)
|
||||||
|
{
|
||||||
|
sprite.LayerSetAnimationTime("hiding", 0);
|
||||||
|
sprite.LayerSetVisible("revealing", false);
|
||||||
|
sprite.LayerSetVisible("speaking", false);
|
||||||
|
sprite.LayerSetVisible("hiding", true);
|
||||||
|
}
|
||||||
|
tippy.LabelPanel.Visible = false;
|
||||||
|
if (_currentMessage != null)
|
||||||
|
_secondsUntilNextState = _currentMessage.SlideTime;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // finished hiding
|
||||||
|
|
||||||
|
EntityManager.DeleteEntity(_entity);
|
||||||
|
_entity = default;
|
||||||
|
tippy.Visible = false;
|
||||||
|
_currentMessage = null;
|
||||||
|
_secondsUntilNextState = 0;
|
||||||
|
tippy.State = TippyState.Hidden;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnScreenChanged((UIScreen? Old, UIScreen? New) ev)
|
||||||
|
{
|
||||||
|
ev.Old?.RemoveWidget<TippyUI>();
|
||||||
|
_currentMessage = null;
|
||||||
|
EntityManager.DeleteEntity(_entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Content.Client/Tips/TipsSystem.cs
Normal file
20
Content.Client/Tips/TipsSystem.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using Content.Shared.Tips;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
|
||||||
|
namespace Content.Client.Tips;
|
||||||
|
|
||||||
|
public sealed class TipsSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IUserInterfaceManager _uiMan = default!;
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeNetworkEvent<TippyEvent>(OnClippyEv);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClippyEv(TippyEvent ev)
|
||||||
|
{
|
||||||
|
_uiMan.GetUIController<TippyUIController>().AddMessage(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Content.Shared.Dataset;
|
using Content.Shared.Dataset;
|
||||||
|
using Content.Shared.Tips;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
@@ -22,11 +26,14 @@ public sealed class TipsSystem : EntitySystem
|
|||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly GameTicker _ticker = default!;
|
[Dependency] private readonly GameTicker _ticker = default!;
|
||||||
|
[Dependency] private readonly IConsoleHost _conHost = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
|
||||||
private bool _tipsEnabled;
|
private bool _tipsEnabled;
|
||||||
private float _tipTimeOutOfRound;
|
private float _tipTimeOutOfRound;
|
||||||
private float _tipTimeInRound;
|
private float _tipTimeInRound;
|
||||||
private string _tipsDataset = "";
|
private string _tipsDataset = "";
|
||||||
|
private float _tipTippyChance;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
private TimeSpan _nextTipTime = TimeSpan.Zero;
|
private TimeSpan _nextTipTime = TimeSpan.Zero;
|
||||||
@@ -40,10 +47,101 @@ public sealed class TipsSystem : EntitySystem
|
|||||||
Subs.CVar(_cfg, CCVars.TipFrequencyInRound, SetInRound, true);
|
Subs.CVar(_cfg, CCVars.TipFrequencyInRound, SetInRound, true);
|
||||||
Subs.CVar(_cfg, CCVars.TipsEnabled, SetEnabled, true);
|
Subs.CVar(_cfg, CCVars.TipsEnabled, SetEnabled, true);
|
||||||
Subs.CVar(_cfg, CCVars.TipsDataset, SetDataset, true);
|
Subs.CVar(_cfg, CCVars.TipsDataset, SetDataset, true);
|
||||||
|
Subs.CVar(_cfg, CCVars.TipsTippyChance, SetTippyChance, true);
|
||||||
|
|
||||||
RecalculateNextTipTime();
|
RecalculateNextTipTime();
|
||||||
|
_conHost.RegisterCommand("tippy", Loc.GetString("cmd-tippy-desc"), Loc.GetString("cmd-tippy-help"), SendTippy, SendTippyHelper);
|
||||||
|
_conHost.RegisterCommand("tip", Loc.GetString("cmd-tip-desc"), "tip", SendTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CompletionResult SendTippyHelper(IConsoleShell shell, string[] args)
|
||||||
|
{
|
||||||
|
return args.Length switch
|
||||||
|
{
|
||||||
|
1 => CompletionResult.FromHintOptions(CompletionHelper.SessionNames(), Loc.GetString("cmd-tippy-auto-1")),
|
||||||
|
2 => CompletionResult.FromHint(Loc.GetString("cmd-tippy-auto-2")),
|
||||||
|
3 => CompletionResult.FromHintOptions(CompletionHelper.PrototypeIDs<EntityPrototype>(), Loc.GetString("cmd-tippy-auto-3")),
|
||||||
|
4 => CompletionResult.FromHint(Loc.GetString("cmd-tippy-auto-4")),
|
||||||
|
5 => CompletionResult.FromHint(Loc.GetString("cmd-tippy-auto-5")),
|
||||||
|
6 => CompletionResult.FromHint(Loc.GetString("cmd-tippy-auto-6")),
|
||||||
|
_ => CompletionResult.Empty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendTip(IConsoleShell shell, string argstr, string[] args)
|
||||||
|
{
|
||||||
|
AnnounceRandomTip();
|
||||||
|
RecalculateNextTipTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendTippy(IConsoleShell shell, string argstr, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length < 2)
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("cmd-tippy-help"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActorComponent? actor = null;
|
||||||
|
if (args[0] != "all")
|
||||||
|
{
|
||||||
|
ICommonSession? session;
|
||||||
|
if (args.Length > 0)
|
||||||
|
{
|
||||||
|
// Get player entity
|
||||||
|
if (!_playerManager.TryGetSessionByUsername(args[0], out session))
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("cmd-tippy-error-no-user"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
session = shell.Player;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session?.AttachedEntity is not { } user)
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("cmd-tippy-error-no-user"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryComp(user, out actor))
|
||||||
|
{
|
||||||
|
shell.WriteError(Loc.GetString("cmd-tippy-error-no-user"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ev = new TippyEvent(args[1]);
|
||||||
|
|
||||||
|
string proto;
|
||||||
|
if (args.Length > 2)
|
||||||
|
{
|
||||||
|
ev.Proto = args[2];
|
||||||
|
if (!_prototype.HasIndex<EntityPrototype>(args[2]))
|
||||||
|
{
|
||||||
|
shell.WriteError(Loc.GetString("cmd-tippy-error-no-prototype", ("proto", args[2])));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length > 3)
|
||||||
|
ev.SpeakTime = float.Parse(args[3]);
|
||||||
|
|
||||||
|
if (args.Length > 4)
|
||||||
|
ev.SlideTime = float.Parse(args[4]);
|
||||||
|
|
||||||
|
if (args.Length > 5)
|
||||||
|
ev.WaddleInterval = float.Parse(args[5]);
|
||||||
|
|
||||||
|
if (actor != null)
|
||||||
|
RaiseNetworkEvent(ev, actor.PlayerSession);
|
||||||
|
else
|
||||||
|
RaiseNetworkEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
@@ -81,6 +179,11 @@ public sealed class TipsSystem : EntitySystem
|
|||||||
_tipsDataset = value;
|
_tipsDataset = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetTippyChance(float value)
|
||||||
|
{
|
||||||
|
_tipTippyChance = value;
|
||||||
|
}
|
||||||
|
|
||||||
private void AnnounceRandomTip()
|
private void AnnounceRandomTip()
|
||||||
{
|
{
|
||||||
if (!_prototype.TryIndex<DatasetPrototype>(_tipsDataset, out var tips))
|
if (!_prototype.TryIndex<DatasetPrototype>(_tipsDataset, out var tips))
|
||||||
@@ -89,8 +192,16 @@ public sealed class TipsSystem : EntitySystem
|
|||||||
var tip = _random.Pick(tips.Values);
|
var tip = _random.Pick(tips.Values);
|
||||||
var msg = Loc.GetString("tips-system-chat-message-wrap", ("tip", tip));
|
var msg = Loc.GetString("tips-system-chat-message-wrap", ("tip", tip));
|
||||||
|
|
||||||
_chat.ChatMessageToManyFiltered(Filter.Broadcast(), ChatChannel.OOC, tip, msg,
|
if (_random.Prob(_tipTippyChance))
|
||||||
|
{
|
||||||
|
var ev = new TippyEvent(msg);
|
||||||
|
ev.SpeakTime = 1 + tip.Length * 0.05f;
|
||||||
|
RaiseNetworkEvent(ev);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
_chat.ChatMessageToManyFiltered(Filter.Broadcast(), ChatChannel.OOC, tip, msg,
|
||||||
EntityUid.Invalid, false, false, Color.MediumPurple);
|
EntityUid.Invalid, false, false, Color.MediumPurple);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecalculateNextTipTime()
|
private void RecalculateNextTipTime()
|
||||||
|
|||||||
@@ -435,6 +435,12 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<string> LoginTipsDataset =
|
public static readonly CVarDef<string> LoginTipsDataset =
|
||||||
CVarDef.Create("tips.login_dataset", "Tips");
|
CVarDef.Create("tips.login_dataset", "Tips");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The chance for Tippy to replace a normal tip message.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<float> TipsTippyChance =
|
||||||
|
CVarDef.Create("tips.tippy_chance", 0.01f);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Console
|
* Console
|
||||||
*/
|
*/
|
||||||
@@ -1985,6 +1991,10 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<bool> GatewayGeneratorEnabled =
|
public static readonly CVarDef<bool> GatewayGeneratorEnabled =
|
||||||
CVarDef.Create("gateway.generator_enabled", true);
|
CVarDef.Create("gateway.generator_enabled", true);
|
||||||
|
|
||||||
|
// Clippy!
|
||||||
|
public static readonly CVarDef<string> TippyEntity =
|
||||||
|
CVarDef.Create("tippy.entity", "Tippy", CVar.SERVER | CVar.REPLICATED);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DEBUG
|
* DEBUG
|
||||||
*/
|
*/
|
||||||
|
|||||||
19
Content.Shared/Tips/TippyEvent.cs
Normal file
19
Content.Shared/Tips/TippyEvent.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Tips;
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class TippyEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public TippyEvent(string msg)
|
||||||
|
{
|
||||||
|
Msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Msg;
|
||||||
|
public string? Proto;
|
||||||
|
public float SpeakTime = 5;
|
||||||
|
public float SlideTime = 3;
|
||||||
|
public float WaddleInterval = 0.5f;
|
||||||
|
}
|
||||||
12
Resources/Locale/en-US/commands/tippy-command.ftl
Normal file
12
Resources/Locale/en-US/commands/tippy-command.ftl
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
cmd-tippy-desc = Broadcast a message as Tippy the clown.
|
||||||
|
cmd-tippy-help = tippy <user | all> <message> [entity prototype] [speak time] [slide time] [waddle interval]
|
||||||
|
cmd-tippy-auto-1 = <user | all>
|
||||||
|
cmd-tippy-auto-2 = message
|
||||||
|
cmd-tippy-auto-3 = entity prototype
|
||||||
|
cmd-tippy-auto-4 = speak time, in seconds
|
||||||
|
cmd-tippy-auto-5 = slide time, in seconds
|
||||||
|
cmd-tippy-auto-6 = waddle interval, in seconds
|
||||||
|
cmd-tippy-error-no-user = User not found.
|
||||||
|
cmd-tippy-error-no-prototype = Prototype not found: {$proto}
|
||||||
|
|
||||||
|
cmd-tip-desc = Spawn a random game tip.
|
||||||
29
Resources/Prototypes/Entities/Debugging/tippy.yml
Normal file
29
Resources/Prototypes/Entities/Debugging/tippy.yml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
- type: entity
|
||||||
|
id: Tippy
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
noRot: false
|
||||||
|
scale: 4,4
|
||||||
|
layers:
|
||||||
|
- sprite: Tips/tippy.rsi
|
||||||
|
state: left
|
||||||
|
map: [ "revealing" ]
|
||||||
|
- sprite: Tips/tippy.rsi
|
||||||
|
state: right
|
||||||
|
map: [ "hiding" ]
|
||||||
|
- sprite: Tips/tippy.rsi
|
||||||
|
state: down
|
||||||
|
visible: false
|
||||||
|
map: [ "speaking" ]
|
||||||
|
# footstep sounds wile waddling onto the screen.
|
||||||
|
- type: FootstepModifier
|
||||||
|
footstepSoundCollection:
|
||||||
|
collection: FootstepClown
|
||||||
|
# visuals for the speech bubble.
|
||||||
|
# only supports background image.
|
||||||
|
- type: PaperVisuals
|
||||||
|
backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png"
|
||||||
|
backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0
|
||||||
|
backgroundModulate: "#ffffcc"
|
||||||
|
fontAccentColor: "#000000"
|
||||||
BIN
Resources/Textures/Tips/tippy.rsi/down.png
Normal file
BIN
Resources/Textures/Tips/tippy.rsi/down.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
Resources/Textures/Tips/tippy.rsi/left.png
Normal file
BIN
Resources/Textures/Tips/tippy.rsi/left.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
20
Resources/Textures/Tips/tippy.rsi/meta.json
Normal file
20
Resources/Textures/Tips/tippy.rsi/meta.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "down"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "right"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Resources/Textures/Tips/tippy.rsi/right.png
Normal file
BIN
Resources/Textures/Tips/tippy.rsi/right.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -96,6 +96,8 @@
|
|||||||
- tp
|
- tp
|
||||||
- tpto
|
- tpto
|
||||||
- respawn
|
- respawn
|
||||||
|
- tippy
|
||||||
|
- tip
|
||||||
|
|
||||||
- Flags: SERVER
|
- Flags: SERVER
|
||||||
Commands:
|
Commands:
|
||||||
|
|||||||
Reference in New Issue
Block a user