Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/Map/Levels/LevelObjects/LevelObject.cs
2 using FarseerPhysics;
3 using Microsoft.Xna.Framework;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 using System.Xml.Linq;
8 
9 namespace Barotrauma
10 {
12  {
13  public readonly LevelObjectPrefab Prefab;
14  public Vector3 Position;
15 
16  public float NetworkUpdateTimer;
17 
18  public float Scale;
19 
20  public float Rotation;
21 
22  private int spriteIndex;
23 
24  protected bool tookDamage;
25 
27 
29  {
30  get;
31  private set;
32  }
33 
34  public List<LevelTrigger> Triggers
35  {
36  get;
37  private set;
38  }
39 
40  public bool NeedsNetworkSyncing
41  {
42  get
43  {
44  return tookDamage || (Triggers != null && Triggers.Any(t => t.NeedsNetworkSyncing));
45  }
46  set
47  {
48  if (Triggers == null) { return; }
49  Triggers.ForEach(t => t.NeedsNetworkSyncing = false);
50  tookDamage = false;
51  }
52  }
53 
54  public bool NeedsUpdate
55  {
56  get; private set;
57  }
58 
59  public float Health
60  {
61  get;
62  private set;
63  }
64 
65  public Sprite Sprite
66  {
67  get
68  {
69  var prefab = ActivePrefab?.Sprites.Count > 0 ? ActivePrefab : Prefab;
70  return spriteIndex < 0 || prefab.Sprites.Count == 0 ? null : prefab.Sprites[spriteIndex % prefab.Sprites.Count];
71  }
72  }
73 
74  Vector2 ISpatialEntity.Position => new Vector2(Position.X, Position.Y);
75 
76  public Vector2 WorldPosition => new Vector2(Position.X, Position.Y);
77 
78  public Vector2 SimPosition => ConvertUnits.ToSimUnits(WorldPosition);
79 
80  public Submarine Submarine => null;
81 
82  public string Name => Prefab?.Name ?? "LevelObject (null)";
83 
84  public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; } = new Dictionary<Identifier, SerializableProperty>();
85 
87 
88  public LevelObject(LevelObjectPrefab prefab, Vector3 position, float scale, float rotation = 0.0f)
89  {
90  ActivePrefab = Prefab = prefab;
91  Position = position;
92  Scale = scale;
93  Rotation = rotation;
94  Health = prefab.Health;
95 
96  spriteIndex = ActivePrefab.Sprites.Any() ? Rand.Int(ActivePrefab.Sprites.Count, Rand.RandSync.ServerAndClient) : -1;
97 
98  if (Sprite != null && prefab.SpriteSpecificPhysicsBodyElements.ContainsKey(Sprite))
99  {
100  PhysicsBody = new PhysicsBody(prefab.SpriteSpecificPhysicsBodyElements[Sprite], ConvertUnits.ToSimUnits(new Vector2(position.X, position.Y)), Scale);
101  }
102  else if (prefab.PhysicsBodyElement != null)
103  {
104  PhysicsBody = new PhysicsBody(prefab.PhysicsBodyElement, ConvertUnits.ToSimUnits(new Vector2(position.X, position.Y)), Scale);
105  }
106 
107  if (PhysicsBody != null)
108  {
109  PhysicsBody.UserData = this;
111  PhysicsBody.BodyType = BodyType.Static;
112  PhysicsBody.CollisionCategories = Physics.CollisionLevel;
113  PhysicsBody.CollidesWith = Prefab.TakeLevelWallDamage?
114  Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionProjectile :
115  Physics.CollisionWall | Physics.CollisionCharacter;
116  }
117 
118  foreach (var triggerElement in prefab.LevelTriggerElements)
119  {
120  Triggers ??= new List<LevelTrigger>();
121  Vector2 triggerPosition = triggerElement.GetAttributeVector2("position", Vector2.Zero) * scale;
122 
123  if (rotation != 0.0f)
124  {
125  var ca = (float)Math.Cos(rotation);
126  var sa = (float)Math.Sin(rotation);
127 
128  triggerPosition = new Vector2(
129  ca * triggerPosition.X + sa * triggerPosition.Y,
130  -sa * triggerPosition.X + ca * triggerPosition.Y);
131  }
132 
133  var newTrigger = new LevelTrigger(triggerElement, new Vector2(position.X, position.Y) + triggerPosition, -rotation, scale, prefab.Name);
134  if (newTrigger.PhysicsBody != null)
135  {
136  newTrigger.PhysicsBody.UserData = this;
137  }
138  int parentTriggerIndex = prefab.LevelTriggerElements.IndexOf(triggerElement.Parent);
139  if (parentTriggerIndex > -1) { newTrigger.ParentTrigger = Triggers[parentTriggerIndex]; }
140  Triggers.Add(newTrigger);
141  }
142 
143  if (spriteIndex == -1)
144  {
145  foreach (var overrideProperties in prefab.OverrideProperties)
146  {
147  if (overrideProperties == null) { continue; }
148  if (overrideProperties.Sprites.Count > 0)
149  {
150  spriteIndex = Rand.Int(overrideProperties.Sprites.Count, Rand.RandSync.ServerAndClient);
151  break;
152  }
153  }
154  }
155 
156  NeedsUpdate = NeedsNetworkSyncing || (Triggers != null && Triggers.Any()) || Prefab.PhysicsBodyTriggerIndex > -1;
157 
158  InitProjSpecific();
159  }
160 
161  partial void InitProjSpecific();
162 
163  public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, Vector2 impulseDirection, float deltaTime, bool playSound = true)
164  {
165  if (Health <= 0.0f) { return new AttackResult(0.0f); }
166 
167  float damage = 0.0f;
168  if (Prefab.TakeLevelWallDamage)
169  {
170  damage += attack.GetLevelWallDamage(deltaTime);
171  }
172  damage = Math.Max(Health, damage);
173  AddDamage(damage, deltaTime, attacker);
174  return new AttackResult(damage);
175  }
176 
177  public void AddDamage(float damage, float deltaTime, Entity attacker, bool isNetworkEvent = false)
178  {
179  if (Health <= 0.0f) { return; }
180  if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && !isNetworkEvent)
181  {
182  return;
183  }
184  tookDamage |= !MathUtils.NearlyEqual(damage, 0.0f);
185  Health -= damage;
186  if (Health <= 0.0f)
187  {
188 #if CLIENT
190  {
192  }
193 #endif
194  if (PhysicsBody != null)
195  {
196  PhysicsBody.Enabled = false;
197  }
198  foreach (LevelTrigger trigger in Triggers)
199  {
200  trigger.PhysicsBody.Enabled = false;
201  foreach (StatusEffect effect in trigger.StatusEffects)
202  {
203  if (effect.type != ActionType.OnBroken) { continue; }
204  effect.Apply(effect.type, deltaTime, attacker, this, worldPosition: WorldPosition);
205  }
206  }
207  }
208  }
209 
210  public Vector2 LocalToWorld(Vector2 localPosition, float swingState = 0.0f)
211  {
212  Vector2 emitterPos = localPosition * Scale;
213 
214  if (Rotation != 0.0f || Prefab.SwingAmountRad != 0.0f)
215  {
216  float rot = Rotation + swingState * Prefab.SwingAmountRad;
217 
218  var ca = (float)Math.Cos(rot);
219  var sa = (float)Math.Sin(rot);
220 
221  emitterPos = new Vector2(
222  ca * emitterPos.X + sa * emitterPos.Y,
223  -sa * emitterPos.X + ca * emitterPos.Y);
224  }
225  return new Vector2(Position.X, Position.Y) + emitterPos;
226  }
227 
228  public void Remove()
229  {
230  RemoveProjSpecific();
231  }
232 
233  partial void RemoveProjSpecific();
234 
235  public override string ToString()
236  {
237  return "LevelObject (" + ActivePrefab.Name + ")";
238  }
239 
240  public void ServerWrite(IWriteMessage msg, Client c)
241  {
242  if (Triggers == null) { return; }
243  if (Prefab.TakeLevelWallDamage)
244  {
245  msg.WriteRangedSingle(MathHelper.Clamp(Health, 0.0f, Prefab.Health), 0.0f, Prefab.Health, 8);
246  }
247  for (int j = 0; j < Triggers.Count; j++)
248  {
249  if (!Triggers[j].UseNetworkSyncing) { continue; }
250  Triggers[j].ServerWrite(msg, c);
251  }
252  }
253  }
254 }
Attacks are used to deal damage to characters, structures and items. They can be defined in the weapo...
static GameSession?? GameSession
Definition: GameMain.cs:88
static NetworkMember NetworkMember
Definition: GameMain.cs:190
void AddDamage(float damage, float deltaTime, Entity attacker, bool isNetworkEvent=false)
LevelObject(LevelObjectPrefab prefab, Vector3 position, float scale, float rotation=0.0f)
Dictionary< Identifier, SerializableProperty > SerializableProperties
AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, Vector2 impulseDirection, float deltaTime, bool playSound=true)
Vector2 LocalToWorld(Vector2 localPosition, float swingState=0.0f)
bool SetTransformIgnoreContacts(Vector2 simPosition, float rotation, bool setPrevTransform=true)
StatusEffects can be used to execute various kinds of effects: modifying the state of some entity in ...
virtual void Apply(ActionType type, float deltaTime, Entity entity, ISerializableEntity target, Vector2? worldPosition=null)
void WriteRangedSingle(Single val, Single min, Single max, int bitCount)
ActionType
ActionTypes define when a StatusEffect is executed.
Definition: Enums.cs:19