Client LuaCsForBarotrauma
BarotraumaClient/ClientSource/Items/Components/Rope.cs
2 using Microsoft.Xna.Framework;
3 using Microsoft.Xna.Framework.Graphics;
4 using System;
5 using Barotrauma.Sounds;
6 
8 {
9  partial class Rope : ItemComponent, IDrawableComponent
10  {
11  private Sprite sprite, startSprite, endSprite;
12 
13  private RoundSound snapSound, reelSound;
14  private SoundChannel reelSoundChannel;
15 
16  [Serialize(5, IsPropertySaveable.No)]
17  public int SpriteWidth
18  {
19  get;
20  set;
21  }
22 
23  [Serialize("255,255,255,255", IsPropertySaveable.No)]
24  public Color SpriteColor
25  {
26  get;
27  set;
28  }
29 
30  [Serialize(false, IsPropertySaveable.No)]
31  public bool Tile
32  {
33  get;
34  set;
35  }
36 
37  [Serialize("0.5,0.5)", IsPropertySaveable.No)]
38  public Vector2 Origin { get; set; } = new Vector2(0.5f, 0.5f);
39 
40  [Serialize(true, IsPropertySaveable.No, description: "")]
41  public bool BreakFromMiddle
42  {
43  get;
44  set;
45  }
46 
47  public Vector2 DrawSize
48  {
49  get
50  {
51  if (target == null || source == null) { return Vector2.Zero; }
52 
53  Vector2 sourcePos = GetSourcePos();
54 
55  return new Vector2(
56  Math.Abs(target.DrawPosition.X - sourcePos.X),
57  Math.Abs(target.DrawPosition.Y - sourcePos.Y)) * 1.5f;
58  }
59  }
60 
61  [Serialize("1.0, 1.0", IsPropertySaveable.No, description: "When reeling in, the pitch slides from X to Y, depending on the length of the rope.")]
62  public Vector2 ReelSoundPitchSlide
63  {
64  get => _reelSoundPitchSlide;
65  set
66  {
67  _reelSoundPitchSlide = new Vector2(
68  Math.Max(value.X, SoundChannel.MinFrequencyMultiplier),
69  Math.Min(value.Y, SoundChannel.MaxFrequencyMultiplier));
70  }
71  }
72  private Vector2 _reelSoundPitchSlide;
73 
74  partial void InitProjSpecific(ContentXElement element)
75  {
76  foreach (var subElement in element.Elements())
77  {
78  switch (subElement.Name.ToString().ToLowerInvariant())
79  {
80  case "sprite":
81  sprite = new Sprite(subElement);
82  break;
83  case "startsprite":
84  startSprite = new Sprite(subElement);
85  break;
86  case "endsprite":
87  endSprite = new Sprite(subElement);
88  break;
89  case "snapsound":
90  snapSound = RoundSound.Load(subElement);
91  break;
92  case "reelsound":
93  reelSound = RoundSound.Load(subElement);
94  break;
95  }
96  }
97  }
98 
99  partial void UpdateProjSpecific()
100  {
101  if (isReelingIn && !Snapped)
102  {
103  PlaySound(reelSound, source.WorldPosition);
104  }
105  else
106  {
107  reelSoundChannel?.FadeOutAndDispose();
108  reelSoundChannel = null;
109  }
110  }
111 
112  public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1, Color? overrideColor = null)
113  {
114  if (target == null || target.Removed) { return; }
115  if (target.ParentInventory != null) { return; }
116  if (source is Limb limb && limb.Removed) { return; }
117  if (source is Entity e && e.Removed) { return; }
118 
119  Vector2 startPos = GetSourcePos(useDrawPosition: true);
120  startPos.Y = -startPos.Y;
121  if ((source as Item)?.GetComponent<Turret>() is { } turret)
122  {
123  if (turret.BarrelSprite != null)
124  {
125  startPos += new Vector2((float)Math.Cos(turret.Rotation), (float)Math.Sin(turret.Rotation)) * turret.BarrelSprite.size.Y * turret.BarrelSprite.RelativeOrigin.Y * item.Scale * 0.9f;
126  }
127  startPos -= turret.GetRecoilOffset();
128  }
129  Vector2 endPos = new Vector2(target.DrawPosition.X, target.DrawPosition.Y);
130  Vector2 flippedPos = target.Sprite.size * target.Scale * (Origin - new Vector2(0.5f));
131  if (target.body.Dir < 0.0f)
132  {
133  flippedPos.X = -flippedPos.X;
134  }
135  endPos += Vector2.Transform(flippedPos, Matrix.CreateRotationZ(target.body.Rotation));
136  endPos.Y = -endPos.Y;
137 
138  if (Snapped)
139  {
140  float snapState = 1.0f - snapTimer / SnapAnimDuration;
141  Vector2 diff = target.DrawPosition - new Vector2(startPos.X, -startPos.Y);
142  diff.Y = -diff.Y;
143 
144  int width = (int)(SpriteWidth * snapState);
145  if (width > 0.0f)
146  {
147  float positionMultiplier = snapState;
148  if (BreakFromMiddle)
149  {
150  positionMultiplier /= 2;
151  DrawRope(spriteBatch, endPos - diff * positionMultiplier, endPos, width);
152  }
153  DrawRope(spriteBatch, startPos, startPos + diff * positionMultiplier, width);
154  }
155  }
156  else
157  {
158  DrawRope(spriteBatch, startPos, endPos, SpriteWidth);
159  }
160 
161  if (startSprite != null || endSprite != null)
162  {
163  Vector2 dir = endPos - startPos;
164  float angle = (float)Math.Atan2(dir.Y, dir.X);
165  if (startSprite != null)
166  {
167  float depth = Math.Min(item.GetDrawDepth() + (startSprite.Depth - item.Sprite.Depth), 0.999f);
168  startSprite?.Draw(spriteBatch, startPos, overrideColor ?? SpriteColor, angle, depth: depth);
169  }
170  if (endSprite != null && (!Snapped || BreakFromMiddle))
171  {
172  float depth = Math.Min(item.GetDrawDepth() + (endSprite.Depth - item.Sprite.Depth), 0.999f);
173  endSprite?.Draw(spriteBatch, endPos, overrideColor ?? SpriteColor, angle, depth: depth);
174  }
175  }
176  }
177 
178  private void DrawRope(SpriteBatch spriteBatch, Vector2 startPos, Vector2 endPos, int width, Color? overrideColor = null)
179  {
180  float depth = sprite == null ?
181  item.Sprite.Depth + 0.001f :
182  Math.Min(item.GetDrawDepth() + (sprite.Depth - item.Sprite.Depth), 0.999f);
183 
184  if (sprite?.Texture == null)
185  {
186  GUI.DrawLine(spriteBatch,
187  startPos,
188  endPos,
189  overrideColor ?? SpriteColor, depth: depth, width: width);
190  return;
191  }
192 
193  if (Tile)
194  {
195  float length = Vector2.Distance(startPos, endPos);
196  Vector2 dir = (endPos - startPos) / length;
197  float x;
198  for (x = 0.0f; x <= length - sprite.size.X; x += sprite.size.X)
199  {
200  GUI.DrawLine(spriteBatch, sprite,
201  startPos + dir * (x - 5.0f),
202  startPos + dir * (x + sprite.size.X),
203  overrideColor ?? SpriteColor, depth: depth, width: width);
204  }
205  float leftOver = length - x;
206  if (leftOver > 0.0f)
207  {
208  GUI.DrawLine(spriteBatch, sprite,
209  startPos + dir * (x - 5.0f),
210  endPos,
211  overrideColor ?? SpriteColor, depth: depth, width: width);
212  }
213  }
214  else
215  {
216  GUI.DrawLine(spriteBatch, sprite,
217  startPos,
218  endPos,
219  overrideColor ?? SpriteColor, depth: depth, width: width);
220  }
221  }
222 
223  private void PlaySound(RoundSound sound, Vector2 position)
224  {
225  if (sound == null) { return; }
226  if (sound == reelSound)
227  {
228  if (reelSoundChannel is not { IsPlaying: true })
229  {
230  reelSoundChannel = SoundPlayer.PlaySound(sound.Sound, position, sound.Volume, sound.Range, ignoreMuffling: sound.IgnoreMuffling, freqMult: sound.GetRandomFrequencyMultiplier());
231  if (reelSoundChannel != null)
232  {
233  reelSoundChannel.Looping = true;
234  }
235  }
236  else
237  {
238  reelSoundChannel.Position = new Vector3(position, 0);
239  reelSoundChannel.Gain = MathHelper.Lerp(0, 1.0f, MathUtils.InverseLerp(MinPullDistance, MaxLength, MathUtils.Pow(currentRopeLength, 1.5f)));
240  reelSoundChannel.FrequencyMultiplier = MathHelper.Lerp(ReelSoundPitchSlide.X, ReelSoundPitchSlide.Y, MathUtils.InverseLerp(MinPullDistance, MaxLength, currentRopeLength));
241  }
242  }
243  else
244  {
245  SoundPlayer.PlaySound(sound.Sound, position, sound.Volume, sound.Range, ignoreMuffling: sound.IgnoreMuffling, freqMult: sound.GetRandomFrequencyMultiplier());
246  }
247  }
248 
249  public void ClientEventRead(IReadMessage msg, float sendingTime)
250  {
251  snapped = msg.ReadBoolean();
252 
253  if (!snapped)
254  {
255  ushort targetId = msg.ReadUInt16();
256  ushort sourceId = msg.ReadUInt16();
257  byte limbIndex = msg.ReadByte();
258 
259  if (Entity.FindEntityByID(targetId) is not Item target) { return; }
260  var source = Entity.FindEntityByID(sourceId);
261  switch (source)
262  {
263  case Character sourceCharacter when limbIndex >= 0 && limbIndex < sourceCharacter.AnimController.Limbs.Length:
264  {
265  Limb sourceLimb = sourceCharacter.AnimController.Limbs[limbIndex];
266  Attach(sourceLimb, target);
267  sourceCharacter.AnimController.DragWithRope();
268  break;
269  }
270  case ISpatialEntity spatialEntity:
271  Attach(spatialEntity, target);
272  break;
273  }
274  }
275  }
276 
277  protected override void RemoveComponentSpecific()
278  {
279  sprite?.Remove();
280  sprite = null;
281  startSprite?.Remove();
282  startSprite = null;
283  endSprite?.Remove();
284  endSprite = null;
285  reelSoundChannel?.FadeOutAndDispose();
286  reelSoundChannel = null;
287  }
288  }
289 }
IEnumerable< ContentXElement > Elements()
virtual Vector2 DrawPosition
Definition: Entity.cs:51
static Entity FindEntityByID(ushort ID)
Find an entity based on the ID
Definition: Entity.cs:204
void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth=-1, Color? overrideColor=null)
static ? RoundSound Load(ContentXElement element, bool stream=false)
Definition: RoundSound.cs:61