Merge branch 'dedicated-server' (TODO: make sure I didn't break anything)
Conflicts: Barotrauma/Barotrauma.csproj Barotrauma/BarotraumaShared/Source/Characters/AI/AIController.cs Barotrauma/BarotraumaShared/Source/Characters/AI/EnemyAIController.cs Barotrauma/BarotraumaShared/Source/Characters/AICharacter.cs Barotrauma/BarotraumaShared/Source/Characters/Animation/Ragdoll.cs Barotrauma/BarotraumaShared/Source/Characters/Attack.cs Barotrauma/BarotraumaShared/Source/Characters/Character.cs Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs Barotrauma/BarotraumaShared/Source/Characters/Limb.cs Barotrauma/BarotraumaShared/Source/Events/MonsterEvent.cs Barotrauma/BarotraumaShared/Source/Map/Explosion.cs
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Explosion
|
||||
{
|
||||
private Attack attack;
|
||||
|
||||
private float force;
|
||||
|
||||
public float CameraShake;
|
||||
|
||||
private bool sparks, shockwave, flames, smoke;
|
||||
|
||||
public Explosion(float range, float force, float damage, float structureDamage)
|
||||
{
|
||||
attack = new Attack(damage, structureDamage, 0.0f, range);
|
||||
this.force = force;
|
||||
sparks = true;
|
||||
shockwave = true;
|
||||
flames = true;
|
||||
}
|
||||
|
||||
public Explosion(XElement element)
|
||||
{
|
||||
attack = new Attack(element);
|
||||
|
||||
force = ToolBox.GetAttributeFloat(element, "force", 0.0f);
|
||||
|
||||
sparks = ToolBox.GetAttributeBool(element, "sparks", true);
|
||||
shockwave = ToolBox.GetAttributeBool(element, "shockwave", true);
|
||||
flames = ToolBox.GetAttributeBool(element, "flames", true);
|
||||
smoke = ToolBox.GetAttributeBool(element, "smoke", true);
|
||||
|
||||
CameraShake = ToolBox.GetAttributeFloat(element, "camerashake", attack.Range*0.1f);
|
||||
}
|
||||
|
||||
public void Explode(Vector2 worldPosition)
|
||||
{
|
||||
Hull hull = Hull.FindHull(worldPosition);
|
||||
|
||||
ExplodeProjSpecific(worldPosition, hull);
|
||||
|
||||
float displayRange = attack.Range;
|
||||
if (displayRange < 0.1f) return;
|
||||
|
||||
float cameraDist = Vector2.Distance(GameMain.GameScreen.Cam.Position, worldPosition)/2.0f;
|
||||
GameMain.GameScreen.Cam.Shake = CameraShake * Math.Max((displayRange - cameraDist) / displayRange, 0.0f);
|
||||
|
||||
if (attack.GetStructureDamage(1.0f) > 0.0f)
|
||||
{
|
||||
RangedStructureDamage(worldPosition, displayRange, attack.GetStructureDamage(1.0f));
|
||||
}
|
||||
|
||||
if (force == 0.0f && attack.Stun == 0.0f && attack.GetDamage(1.0f) == 0.0f) return;
|
||||
|
||||
ApplyExplosionForces(worldPosition, attack, force);
|
||||
|
||||
if (flames && GameMain.Client == null)
|
||||
{
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f) continue;
|
||||
|
||||
if (Vector2.Distance(item.WorldPosition, worldPosition) > attack.Range * 0.1f) continue;
|
||||
|
||||
item.ApplyStatusEffects(ActionType.OnFire, 1.0f);
|
||||
|
||||
if (item.Condition <= 0.0f && GameMain.Server != null)
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFire });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
partial void ExplodeProjSpecific(Vector2 worldPosition, Hull hull);
|
||||
|
||||
private Vector2 ClampParticlePos(Vector2 particlePos, Hull hull)
|
||||
{
|
||||
if (hull == null) return particlePos;
|
||||
|
||||
return new Vector2(
|
||||
MathHelper.Clamp(particlePos.X, hull.WorldRect.X, hull.WorldRect.Right),
|
||||
MathHelper.Clamp(particlePos.Y, hull.WorldRect.Y - hull.WorldRect.Height, hull.WorldRect.Y));
|
||||
}
|
||||
|
||||
public static void ApplyExplosionForces(Vector2 worldPosition, Attack attack, float force)
|
||||
{
|
||||
if (attack.Range <= 0.0f) return;
|
||||
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
Vector2 explosionPos = worldPosition;
|
||||
if (c.Submarine != null) explosionPos -= c.Submarine.Position;
|
||||
|
||||
explosionPos = ConvertUnits.ToSimUnits(explosionPos);
|
||||
|
||||
bool wasDead = c.IsDead;
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
float dist = Vector2.Distance(limb.WorldPosition, worldPosition);
|
||||
|
||||
//calculate distance from the "outer surface" of the physics body
|
||||
//doesn't take the rotation of the limb into account, but should be accurate enough for this purpose
|
||||
float limbRadius = Math.Max(Math.Max(limb.body.width * 0.5f, limb.body.height * 0.5f), limb.body.radius);
|
||||
dist = Math.Max(0.0f, dist - FarseerPhysics.ConvertUnits.ToDisplayUnits(limbRadius));
|
||||
|
||||
if (dist > attack.Range) continue;
|
||||
|
||||
float distFactor = 1.0f - dist / attack.Range;
|
||||
|
||||
//solid obstacles between the explosion and the limb reduce the effect of the explosion by 90%
|
||||
if (Submarine.CheckVisibility(limb.SimPosition, explosionPos) != null) distFactor *= 0.1f;
|
||||
|
||||
c.AddDamage(limb.WorldPosition, DamageType.None,
|
||||
attack.GetDamage(1.0f) / c.AnimController.Limbs.Length * distFactor,
|
||||
attack.GetBleedingDamage(1.0f) / c.AnimController.Limbs.Length * distFactor,
|
||||
attack.Stun * distFactor,
|
||||
false);
|
||||
|
||||
if (limb.WorldPosition != worldPosition && force > 0.0f)
|
||||
{
|
||||
limb.body.ApplyLinearImpulse(Vector2.Normalize(limb.WorldPosition - worldPosition) * distFactor * force);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasDead && c.IsDead)
|
||||
{
|
||||
foreach (LimbJoint joint in c.AnimController.LimbJoints)
|
||||
{
|
||||
if (Rand.Range(0.0f, 1.0f) < attack.SeverLimbsProbability)
|
||||
{
|
||||
c.AnimController.SeverLimbJoint(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary where the keys are the structures that took damage and the values are the amount of damage taken
|
||||
/// </summary>
|
||||
public static Dictionary<Structure,float> RangedStructureDamage(Vector2 worldPosition, float worldRange, float damage)
|
||||
{
|
||||
List<Structure> structureList = new List<Structure>();
|
||||
float dist = 600.0f;
|
||||
foreach (MapEntity entity in MapEntity.mapEntityList)
|
||||
{
|
||||
Structure structure = entity as Structure;
|
||||
if (structure == null) continue;
|
||||
|
||||
if (structure.HasBody &&
|
||||
!structure.IsPlatform &&
|
||||
Vector2.Distance(structure.WorldPosition, worldPosition) < dist * 3.0f)
|
||||
{
|
||||
structureList.Add(structure);
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<Structure, float> damagedStructures = new Dictionary<Structure, float>();
|
||||
foreach (Structure structure in structureList)
|
||||
{
|
||||
for (int i = 0; i < structure.SectionCount; i++)
|
||||
{
|
||||
float distFactor = 1.0f - (Vector2.Distance(structure.SectionPosition(i, true), worldPosition) / worldRange);
|
||||
if (distFactor <= 0.0f) continue;
|
||||
|
||||
structure.AddDamage(i, damage * distFactor);
|
||||
|
||||
if (damagedStructures.ContainsKey(structure))
|
||||
{
|
||||
damagedStructures[structure] += damage * distFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
damagedStructures.Add(structure, damage * distFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return damagedStructures;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user