2 using Microsoft.Xna.Framework;
4 using System.Collections.Generic;
18 const float OxygenConsumption = 50.0f;
19 const float GrowSpeed = 20.0f;
20 const float MaxDamageRange = 250.0f;
32 private readonly List<Decal> burnDecals =
new List<Decal>();
39 if (!MathUtils.IsValid(value))
return;
57 if (value ==
size)
return;
59 Vector2 sizeChange = value -
size;
69 get {
return Math.Min((
float)Math.Sqrt(
size.X) * 10.0f, MaxDamageRange); }
99 public FireSource(Vector2 worldPosition,
Hull spawningHull =
null,
Character sourceCharacter =
null,
bool isNetworkMessage =
false)
105 if (!isNetworkMessage &&
GameMain.Client !=
null) {
return; }
110 position = worldPosition -
new Vector2(-5.0f, 5.0f);
120 lightSource =
new LightSource(this.position, 50.0f,
new Color(1.0f, 0.9f, 0.7f),
hull?.
Submarine);
123 size =
new Vector2(10.0f, 10.0f);
128 if (
hull ==
null)
return;
137 public static void UpdateAll(List<FireSource> fireSources,
float deltaTime)
139 for (
int i = fireSources.Count - 1; i >= 0; i--)
141 fireSources[i].Update(deltaTime);
145 for (
int i = fireSources.Count - 1; i >= 0; i--)
147 for (
int j = i - 1; j >= 0; j--)
149 i = Math.Min(i, fireSources.Count - 1);
150 j = Math.Min(j, i - 1);
152 if (!fireSources[i].CheckOverLap(fireSources[j])) {
continue; }
154 float leftEdge = Math.Min(fireSources[i].
position.X, fireSources[j].position.X);
156 fireSources[j].size.X =
157 Math.Max(fireSources[i].
position.X + fireSources[i].size.X, fireSources[j].position.X + fireSources[j].size.X)
160 fireSources[j].position.X = leftEdge;
161 fireSources[j].burnDecals.AddRange(fireSources[i].burnDecals);
162 fireSources[j].burnDecals.Sort((d1, d2) => {
return Math.Sign(d1.WorldPosition.X - d2.WorldPosition.X); });
163 fireSources[i].Remove();
168 public static void UpdateAll(List<DummyFireSource> fireSources,
float deltaTime)
170 for (
int i = fireSources.Count - 1; i >= 0; i--)
172 fireSources[i].Update(deltaTime);
176 for (
int i = fireSources.Count - 1; i >= 0; i--)
178 for (
int j = i - 1; j >= 0; j--)
180 i = Math.Min(i, fireSources.Count - 1);
181 j = Math.Min(j, i - 1);
183 if (!fireSources[i].CheckOverLap(fireSources[j])) {
continue; }
185 float leftEdge = Math.Min(fireSources[i].
position.X, fireSources[j].position.X);
187 fireSources[j].size.X =
188 Math.Max(fireSources[i].
position.X + fireSources[i].size.X, fireSources[j].position.X + fireSources[j].size.X)
191 fireSources[j].position.X = leftEdge;
192 fireSources[i].Remove();
197 private bool CheckOverLap(
FireSource fireSource)
218 HullWaterExtinguish(deltaTime);
229 size.X += GrowSpeed * growModifier * deltaTime;
230 size.Y = MathHelper.Clamp(
size.Y + GrowSpeed * growModifier * deltaTime, 10.0f, 50.0f);
234 this.position.Y = MathHelper.Lerp(this.position.Y,
hull.
Rect.Y -
hull.
Rect.Height +
size.Y, deltaTime);
241 if (burnDecals.Count == 0)
244 if (newDecal !=
null) { burnDecals.Add(newDecal); }
246 else if (
WorldPosition.X < burnDecals[0].WorldPosition.X - 256.0f)
249 if (newDecal !=
null) { burnDecals.Insert(0, newDecal); }
251 else if (
WorldPosition.X +
size.X > burnDecals[burnDecals.Count - 1].WorldPosition.X + 256.0f)
254 if (newDecal !=
null) { burnDecals.Add(newDecal); }
258 foreach (
Decal d
in burnDecals)
264 UpdateProjSpecific(growModifier, deltaTime);
278 protected virtual void AdjustXPos(
float growModifier,
float deltaTime)
280 position.X -= GrowSpeed * growModifier * 0.5f * deltaTime;
283 partial
void UpdateProjSpecific(
float growModifier,
float deltaTime);
285 private void OnChangeHull(Vector2 pos,
Hull particleHull)
287 if (particleHull ==
hull || particleHull ==
null)
return;
290 if (particleHull.
FireSources.Find(fs => pos.X > fs.position.X - 100.0f && pos.X < fs.position.X + fs.size.X + 100.0f) !=
null)
return;
295 private void DamageCharacters(
float deltaTime)
297 if (
size.X <= 0.0f) {
return; }
299 for (
int i = 0; i <
Character.CharacterList.Count; i++)
302 if (c.CurrentHull ==
null || c.IsDead) {
continue; }
312 float dmg = (float)Math.Sqrt(Math.Min(500,
size.X)) * deltaTime / c.AnimController.Limbs.Count(l => !l.IsSevered && !l.Hidden);
313 foreach (Limb limb
in c.AnimController.Limbs)
315 if (limb.IsSevered) {
continue; }
320 attackImpulse: Vector2.Zero,
325 c.CharacterHealth.DisplayedVitality = c.Vitality;
327 c.ApplyStatusEffects(
ActionType.OnFire, deltaTime);
347 private void DamageItems(
float deltaTime)
349 if (
size.X <= 0.0f) {
return; }
351 if (GameMain.Client !=
null) {
return; }
353 foreach (
Item item
in Item.ItemList)
355 if (item.CurrentHull !=
hull || item.FireProof || item.Condition <= 0.0f) {
continue; }
359 Item container = item.Container;
360 bool fireProof =
false;
361 while (container !=
null)
363 if (container.FireProof)
368 container = container.Container;
370 if (fireProof) {
continue; }
372 float range = (float)Math.Sqrt(
size.X) * 10.0f;
373 if (item.Position.X <
position.X - range || item.Position.X >
position.X +
size.X + range) {
continue; }
376 item.ApplyStatusEffects(
ActionType.OnFire, deltaTime);
377 if (item.Condition <= 0.0f && GameMain.NetworkMember is { IsServer:
true })
379 GameMain.NetworkMember.CreateEntityEvent(item,
new Item.ApplyStatusEffectEventData(
ActionType.OnFire));
384 private void HullWaterExtinguish(
float deltaTime)
387 float extinguishAmount = (hull.
Surface - (position.Y - size.Y)) * deltaTime;
389 if (extinguishAmount < 0.0f)
return;
392 float steamCount = Rand.Range(-5.0f, Math.Min(extinguishAmount * 100.0f, 10));
393 for (
int i = 0; i < steamCount; i++)
395 Vector2 spawnPos =
new Vector2(
396 WorldPosition.X + Rand.Range(0.0f, size.X),
397 WorldPosition.Y + 10.0f);
399 Vector2 speed =
new Vector2((spawnPos.X - (WorldPosition.X + size.X / 2.0f)), (
float)Math.Sqrt(size.X) * Rand.Range(20.0f, 25.0f));
401 var particle = GameMain.ParticleManager.CreateParticle(
"steam",
402 spawnPos, speed, 0.0f, hull);
405 extinguishAmount = Math.Min(size.X, extinguishAmount);
407 position.X += extinguishAmount / 2.0f;
408 size.X -= extinguishAmount;
413 if (size.X < 1.0f && (GameMain.NetworkMember ==
null || GameMain.NetworkMember.IsServer))
421 float extinguishAmount = amount * deltaTime;
424 float steamCount = Rand.Range(-5.0f, (
float)Math.Sqrt(amount));
425 for (
int i = 0; i < steamCount; i++)
427 Vector2 spawnPos =
new Vector2(Rand.Range(position.X, position.X + size.X), Rand.Range(position.Y - size.Y, position.Y) + 10.0f);
429 Vector2 speed =
new Vector2((spawnPos.X - (position.X + size.X / 2.0f)), (
float)Math.Sqrt(size.X) * Rand.Range(20.0f, 25.0f));
431 var particle =
GameMain.ParticleManager.CreateParticle(
"steam",
432 spawnPos, speed, 0.0f, hull);
435 extinguishAmount = Math.Min(size.X, extinguishAmount);
437 position.X += extinguishAmount / 2.0f;
438 size.X -= extinguishAmount;
448 public void Extinguish(
float deltaTime,
float amount, Vector2 worldPosition)
450 if (IsInDamageRange(worldPosition, 100.0f))
452 Extinguish(deltaTime, amount);
459 lightSource?.Remove();
462 foreach (
Decal d
in burnDecals)
AttackResult DamageLimb(Vector2 worldPosition, Limb hitLimb, IEnumerable< Affliction > afflictions, float stun, bool playSound, Vector2 attackImpulse, Character attacker=null, float damageMultiplier=1, bool allowStacking=true, float penetration=0f, bool shouldImplode=false, bool ignoreDamageOverlay=false, bool recalculateVitality=true)
override Vector2 Position
void ForceRefreshFadeTimer(float val)
void Extinguish(float deltaTime, float amount)
FireSource(Vector2 worldPosition, Hull spawningHull=null, Character sourceCharacter=null, bool isNetworkMessage=false)
static void UpdateAll(List< DummyFireSource > fireSources, float deltaTime)
bool IsInDamageRange(Character c, float damageRange)
void Extinguish(float deltaTime, float amount, Vector2 worldPosition)
virtual void AdjustXPos(float growModifier, float deltaTime)
void Update(float deltaTime)
virtual float DamageRange
virtual void ReduceOxygen(float deltaTime)
bool IsInDamageRange(Vector2 worldPosition, float damageRange)
readonly Character SourceCharacter
Which character caused this fire (if any)?
static void UpdateAll(List< FireSource > fireSources, float deltaTime)
static NetworkMember NetworkMember
void AddFireSource(FireSource fireSource)
float GetApproximateDistance(Vector2 startPos, Vector2 endPos, Hull targetHull, float maxDistance, float distanceMultiplierPerClosedDoor=0)
Approximate distance from this hull to the target hull, moving through open gaps without passing thro...
Decal AddDecal(UInt32 decalId, Vector2 worldPosition, float scale, bool isNetworkEvent, int? spriteIndex=null)
void RemoveFire(FireSource fire)
static Hull FindHull(Vector2 position, Hull guess=null, bool useWorldCoordinates=true, bool inclusive=true)
Returns the hull which contains the point (or null if it isn't inside any)
List< FireSource > FireSources
override Vector2? Position
ActionType
ActionTypes define when a StatusEffect is executed.
@ Character
Characters only