Client LuaCsForBarotrauma
BarotraumaClient/ClientSource/Items/Components/Projectile.cs
3 using Microsoft.Xna.Framework;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 
9 {
10  partial class Projectile : ItemComponent
11  {
12  private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
13 
14  public void ClientEventRead(IReadMessage msg, float sendingTime)
15  {
16  bool launch = msg.ReadBoolean();
17  if (launch)
18  {
19  ushort userId = msg.ReadUInt16();
20  User = Entity.FindEntityByID(userId) as Character;
21  Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle());
22  float rotation = msg.ReadSingle();
23  spreadIndex = msg.ReadByte();
24  ushort submarineID = msg.ReadUInt16();
25  if (User != null)
26  {
27  Shoot(User, simPosition, simPosition, rotation, ignoredBodies: User.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: false);
28  item.Submarine = Entity.FindEntityByID(submarineID) as Submarine;
29  }
30  else
31  {
32  Launch(User, simPosition, rotation);
33  }
34  }
35 
36  bool isStuck = msg.ReadBoolean();
37  if (isStuck)
38  {
39  ushort submarineID = msg.ReadUInt16();
40  ushort hullID = msg.ReadUInt16();
41  Vector2 simPosition = new Vector2(
42  msg.ReadSingle(),
43  msg.ReadSingle());
44  Vector2 axis = new Vector2(
45  msg.ReadSingle(),
46  msg.ReadSingle());
47  StickTargetType targetType = (StickTargetType)msg.ReadByte();
48 
49  Submarine submarine = Entity.FindEntityByID(submarineID) as Submarine;
50  Hull hull = Entity.FindEntityByID(hullID) as Hull;
51  item.Submarine = submarine;
52  item.CurrentHull = hull;
53  item.body.SetTransform(simPosition, item.body.Rotation);
54 
55  switch (targetType)
56  {
57  case StickTargetType.Structure:
58  UInt16 structureId = msg.ReadUInt16();
59  byte bodyIndex = msg.ReadByte();
60  if (Entity.FindEntityByID(structureId) is Structure structure)
61  {
62  if (bodyIndex == 255) { bodyIndex = 0; }
63  if (bodyIndex >= structure.Bodies.Count)
64  {
65  DebugConsole.ThrowError($"Failed to read a projectile update from the server. Structure body index out of bounds ({bodyIndex}, structure: {structure})");
66  return;
67  }
68  var body = structure.Bodies[bodyIndex];
69  StickToTarget(body, axis);
70  }
71  else
72  {
73  DebugConsole.AddWarning($"\"{item.Prefab.Identifier}\" failed to stick to a structure. Could not find a structure with the ID {structureId}");
74  }
75  break;
76  case StickTargetType.Limb:
77  UInt16 characterId = msg.ReadUInt16();
78  byte limbIndex = msg.ReadByte();
79  if (Entity.FindEntityByID(characterId) is Character character)
80  {
81  if (limbIndex >= character.AnimController.Limbs.Length)
82  {
83  DebugConsole.ThrowError($"Failed to read a projectile update from the server. Limb index out of bounds ({limbIndex}, character: {character})");
84  return;
85  }
86  if (character.Removed) { return; }
87  var limb = character.AnimController.Limbs[limbIndex];
88  StickToTarget(limb.body.FarseerBody, axis);
89  }
90  else
91  {
92  DebugConsole.AddWarning($"\"{this.item.Prefab.Identifier}\" failed to stick to a limb. Could not find a character with the ID {characterId}");
93  }
94  break;
95  case StickTargetType.Item:
96  UInt16 itemID = msg.ReadUInt16();
97  if (Entity.FindEntityByID(itemID) is Item targetItem)
98  {
99  if (targetItem.Removed) { return; }
100  var door = targetItem.GetComponent<Door>();
101  if (door != null)
102  {
103  StickToTarget(door.Body.FarseerBody, axis);
104  }
105  else if (targetItem.body != null)
106  {
107  StickToTarget(targetItem.body.FarseerBody, axis);
108  }
109  }
110  else
111  {
112  DebugConsole.AddWarning($"\"{this.item.Prefab.Identifier}\" failed to stick to an item. Could not find n item with the ID {itemID}");
113  }
114  break;
115  case StickTargetType.Submarine:
116  UInt16 targetSubmarineId = msg.ReadUInt16();
117  if (Entity.FindEntityByID(targetSubmarineId) is Submarine targetSub)
118  {
119  StickToTarget(targetSub.PhysicsBody.FarseerBody, axis);
120  }
121  else
122  {
123  DebugConsole.AddWarning($"\"{item.Prefab.Identifier}\" failed to stick to a submarine. Could not find a structure with the ID {targetSubmarineId}");
124  }
125  break;
126  case StickTargetType.LevelWall:
127  int levelWallIndex = msg.ReadInt32();
128  var allCells = Level.Loaded.GetAllCells();
129  if (levelWallIndex >= 0 && levelWallIndex < allCells.Count)
130  {
131  StickToTarget(allCells[levelWallIndex].Body, axis);
132  }
133  else
134  {
135  DebugConsole.ThrowError($"Failed to read a projectile update from the server. Level wall index out of bounds ({levelWallIndex}, wall count: {allCells.Count})");
136  }
137  break;
138  }
139  }
140  else
141  {
142  Unstick();
143  }
144  }
145 
146  partial void LaunchProjSpecific(Vector2 startLocation, Vector2 endLocation)
147  {
148  Vector2 particlePos = item.WorldPosition;
149  float rotation = -item.body.Rotation;
150  if (item.body.Dir < 0.0f) { rotation += MathHelper.Pi; }
151 
152  //if the position is in a sub's local coordinates, convert to world coordinates
153  particlePos = ConvertToWorldCoordinates(particlePos);
154  //if the start location is in a sub's local coordinates, convert to world coordinates
155  startLocation = ConvertToWorldCoordinates(startLocation);
156  //same for end location
157  endLocation = ConvertToWorldCoordinates(endLocation);
158 
159  Tuple<Vector2, Vector2> tracerPoints = new Tuple<Vector2, Vector2>(startLocation, endLocation);
160  foreach (ParticleEmitter emitter in particleEmitters)
161  {
162  emitter.Emit(1.0f, particlePos, hullGuess: null, angle: rotation, particleRotation: rotation, colorMultiplier: emitter.Prefab.Properties.ColorMultiplier, tracerPoints: tracerPoints);
163  }
164 
165  static Vector2 ConvertToWorldCoordinates(Vector2 position)
166  {
168  if (containing != null)
169  {
170  position += containing.Position;
171  }
172  return position;
173  }
174  }
175 
176  partial void InitProjSpecific(ContentXElement element)
177  {
178  foreach (var subElement in element.Elements())
179  {
180  switch (subElement.Name.ToString().ToLowerInvariant())
181  {
182  case "particleemitter":
183  particleEmitters.Add(new ParticleEmitter(subElement));
184  break;
185  }
186  }
187  }
188  }
189 }
Submarine Submarine
Definition: Entity.cs:53
static Entity FindEntityByID(ushort ID)
Find an entity based on the ID
Definition: Entity.cs:204
void Shoot(Character user, Vector2 weaponPos, Vector2 spawnPos, float rotation, List< Body > ignoredBodies, bool createNetworkEvent, float damageMultiplier=1f, float launchImpulseModifier=0f)
readonly ParticleEmitterPrefab Prefab
void Emit(float deltaTime, Vector2 position, Hull? hullGuess=null, float angle=0.0f, float particleRotation=0.0f, float velocityMultiplier=1.0f, float sizeMultiplier=1.0f, float amountMultiplier=1.0f, Color? colorMultiplier=null, ParticlePrefab? overrideParticle=null, bool mirrorAngle=false, Tuple< Vector2, Vector2 >? tracerPoints=null)
readonly ParticleEmitterProperties Properties
bool SetTransform(Vector2 simPosition, float rotation, bool setPrevTransform=true)
static Submarine FindContainingInLocalCoordinates(Vector2 position, float inflate=500.0f)
Finds the sub whose borders contain the position. Note that this method uses the "actual" position of...