1
0

BuckleSystem.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using Content.Client.Rotation;
  2. using Content.Shared.Buckle;
  3. using Content.Shared.Buckle.Components;
  4. using Content.Shared.Rotation;
  5. using Robust.Client.GameObjects;
  6. using Robust.Client.Graphics;
  7. namespace Content.Client.Buckle;
  8. internal sealed class BuckleSystem : SharedBuckleSystem
  9. {
  10. [Dependency] private readonly RotationVisualizerSystem _rotationVisualizerSystem = default!;
  11. [Dependency] private readonly IEyeManager _eye = default!;
  12. [Dependency] private readonly SharedTransformSystem _xformSystem = default!;
  13. public override void Initialize()
  14. {
  15. base.Initialize();
  16. SubscribeLocalEvent<BuckleComponent, AppearanceChangeEvent>(OnAppearanceChange);
  17. SubscribeLocalEvent<StrapComponent, MoveEvent>(OnStrapMoveEvent);
  18. SubscribeLocalEvent<BuckleComponent, BuckledEvent>(OnBuckledEvent);
  19. SubscribeLocalEvent<BuckleComponent, UnbuckledEvent>(OnUnbuckledEvent);
  20. }
  21. private void OnStrapMoveEvent(EntityUid uid, StrapComponent component, ref MoveEvent args)
  22. {
  23. // I'm moving this to the client-side system, but for the sake of posterity let's keep this comment:
  24. // > This is mega cursed. Please somebody save me from Mr Buckle's wild ride
  25. // The nice thing is its still true, this is quite cursed, though maybe not omega cursed anymore.
  26. // This code is garbage, it doesn't work with rotated viewports. I need to finally get around to reworking
  27. // sprite rendering for entity layers & direction dependent sorting.
  28. // Future notes:
  29. // Right now this doesn't handle: other grids, other grids rotating, the camera rotation changing, and many other fun rotation specific things
  30. // The entire thing should be a concern of the engine, or something engine helps to implement properly.
  31. // Give some of the sprite rotations their own drawdepth, maybe as an offset within the rsi, or something like this
  32. // And we won't ever need to set the draw depth manually
  33. if (args.NewRotation == args.OldRotation)
  34. return;
  35. if (!TryComp<SpriteComponent>(uid, out var strapSprite))
  36. return;
  37. var angle = _xformSystem.GetWorldRotation(uid) + _eye.CurrentEye.Rotation; // Get true screen position, or close enough
  38. var isNorth = angle.GetCardinalDir() == Direction.North;
  39. foreach (var buckledEntity in component.BuckledEntities)
  40. {
  41. if (!TryComp<BuckleComponent>(buckledEntity, out var buckle))
  42. continue;
  43. if (!TryComp<SpriteComponent>(buckledEntity, out var buckledSprite))
  44. continue;
  45. if (isNorth)
  46. {
  47. // This will only assign if empty, it won't get overwritten by new depth on multiple calls, which do happen easily
  48. buckle.OriginalDrawDepth ??= buckledSprite.DrawDepth;
  49. buckledSprite.DrawDepth = strapSprite.DrawDepth - 1;
  50. }
  51. else if (buckle.OriginalDrawDepth.HasValue)
  52. {
  53. buckledSprite.DrawDepth = buckle.OriginalDrawDepth.Value;
  54. buckle.OriginalDrawDepth = null;
  55. }
  56. }
  57. }
  58. /// <summary>
  59. /// Lower the draw depth of the buckled entity without needing for the strap entity to rotate/move.
  60. /// Only do so when the entity is facing screen-local north
  61. /// </summary>
  62. private void OnBuckledEvent(Entity<BuckleComponent> ent, ref BuckledEvent args)
  63. {
  64. if (!TryComp<SpriteComponent>(args.Strap, out var strapSprite))
  65. return;
  66. if (!TryComp<SpriteComponent>(ent.Owner, out var buckledSprite))
  67. return;
  68. var angle = _xformSystem.GetWorldRotation(args.Strap) + _eye.CurrentEye.Rotation; // Get true screen position, or close enough
  69. if (angle.GetCardinalDir() != Direction.North)
  70. return;
  71. ent.Comp.OriginalDrawDepth ??= buckledSprite.DrawDepth;
  72. buckledSprite.DrawDepth = strapSprite.DrawDepth - 1;
  73. }
  74. /// <summary>
  75. /// Was the draw depth of the buckled entity lowered? Reset it upon unbuckling.
  76. /// </summary>
  77. private void OnUnbuckledEvent(Entity<BuckleComponent> ent, ref UnbuckledEvent args)
  78. {
  79. if (!TryComp<SpriteComponent>(ent.Owner, out var buckledSprite))
  80. return;
  81. if (!ent.Comp.OriginalDrawDepth.HasValue)
  82. return;
  83. buckledSprite.DrawDepth = ent.Comp.OriginalDrawDepth.Value;
  84. ent.Comp.OriginalDrawDepth = null;
  85. }
  86. private void OnAppearanceChange(EntityUid uid, BuckleComponent component, ref AppearanceChangeEvent args)
  87. {
  88. if (!TryComp<RotationVisualsComponent>(uid, out var rotVisuals))
  89. return;
  90. if (!Appearance.TryGetData<bool>(uid, BuckleVisuals.Buckled, out var buckled, args.Component) ||
  91. !buckled ||
  92. args.Sprite == null)
  93. {
  94. _rotationVisualizerSystem.SetHorizontalAngle((uid, rotVisuals), rotVisuals.DefaultRotation);
  95. return;
  96. }
  97. // Animate strapping yourself to something at a given angle
  98. // TODO: Dump this when buckle is better
  99. _rotationVisualizerSystem.AnimateSpriteRotation(uid, args.Sprite, rotVisuals.HorizontalRotation, 0.125f);
  100. }
  101. }