38f1ddb...178a853: v0.8.9.1, removed content folder
This commit is contained in:
@@ -14,27 +14,65 @@ namespace Barotrauma
|
||||
Vector2.Zero, 0.0f, hull);
|
||||
}
|
||||
|
||||
hull = hull ?? Hull.FindHull(worldPosition, useWorldCoordinates: true);
|
||||
bool underwater = hull == null || worldPosition.Y < hull.WorldSurface;
|
||||
|
||||
if (underwater && underwaterBubble)
|
||||
{
|
||||
var underwaterExplosion = GameMain.ParticleManager.CreateParticle("underwaterexplosion", worldPosition, Vector2.Zero, 0.0f, hull);
|
||||
if (underwaterExplosion != null)
|
||||
{
|
||||
underwaterExplosion.Size *= MathHelper.Clamp(attack.Range / 150.0f, 0.5f, 10.0f);
|
||||
underwaterExplosion.StartDelay = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < attack.Range * 0.1f; i++)
|
||||
{
|
||||
Vector2 bubblePos = Rand.Vector(attack.Range * 0.5f);
|
||||
GameMain.ParticleManager.CreateParticle("bubbles", worldPosition + bubblePos,
|
||||
bubblePos, 0.0f, hull);
|
||||
if (!underwater)
|
||||
{
|
||||
float particleSpeed = Rand.Range(0.0f, 1.0f);
|
||||
particleSpeed = particleSpeed * particleSpeed * attack.Range;
|
||||
|
||||
if (flames)
|
||||
{
|
||||
float particleScale = MathHelper.Clamp(attack.Range * 0.0025f, 0.5f, 2.0f);
|
||||
var flameParticle = GameMain.ParticleManager.CreateParticle("explosionfire",
|
||||
ClampParticlePos(worldPosition + Rand.Vector((float)System.Math.Sqrt(Rand.Range(0.0f, attack.Range))), hull),
|
||||
Rand.Vector(Rand.Range(0.0f, particleSpeed)), 0.0f, hull);
|
||||
if (flameParticle != null) flameParticle.Size *= particleScale;
|
||||
}
|
||||
if (smoke)
|
||||
{
|
||||
var smokeParticle = GameMain.ParticleManager.CreateParticle(Rand.Range(0.0f, 1.0f) < 0.5f ? "explosionsmoke" : "smoke",
|
||||
ClampParticlePos(worldPosition + Rand.Vector((float)System.Math.Sqrt(Rand.Range(0.0f, attack.Range))), hull),
|
||||
Rand.Vector(Rand.Range(0.0f, particleSpeed)), 0.0f, hull);
|
||||
}
|
||||
}
|
||||
else if (underwaterBubble)
|
||||
{
|
||||
Vector2 bubblePos = Rand.Vector(Rand.Range(0.0f, attack.Range * 0.5f));
|
||||
|
||||
GameMain.ParticleManager.CreateParticle("risingbubbles", worldPosition + bubblePos,
|
||||
Vector2.Zero, 0.0f, hull);
|
||||
|
||||
if (i < attack.Range * 0.02f)
|
||||
{
|
||||
var underwaterExplosion = GameMain.ParticleManager.CreateParticle("underwaterexplosion", worldPosition + bubblePos,
|
||||
Vector2.Zero, 0.0f, hull);
|
||||
if (underwaterExplosion != null)
|
||||
{
|
||||
underwaterExplosion.Size *= MathHelper.Clamp(attack.Range / 300.0f, 0.5f, 2.0f) * Rand.Range(0.8f, 1.2f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (sparks)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("spark", worldPosition,
|
||||
Rand.Vector(Rand.Range(500.0f, 800.0f)), 0.0f, hull);
|
||||
}
|
||||
if (flames)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("explosionfire", ClampParticlePos(worldPosition + Rand.Vector(50f), hull),
|
||||
Rand.Vector(Rand.Range(50.0f, 100.0f)), 0.0f, hull);
|
||||
}
|
||||
if (smoke)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("smoke", ClampParticlePos(worldPosition + Rand.Vector(50f), hull),
|
||||
Rand.Vector(Rand.Range(1.0f, 10.0f)), 0.0f, hull);
|
||||
}
|
||||
}
|
||||
|
||||
if (hull != null && !string.IsNullOrWhiteSpace(decal) && decalSize > 0.0f)
|
||||
|
||||
@@ -2,80 +2,17 @@ using Barotrauma.Lights;
|
||||
using Barotrauma.Particles;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class FireSource
|
||||
{
|
||||
static Sound fireSoundBasic, fireSoundLarge;
|
||||
|
||||
private LightSource lightSource;
|
||||
|
||||
partial void UpdateProjSpecific(float growModifier)
|
||||
{
|
||||
if (hull.FireSources.Any(fs => fs != this && fs.size.X > size.X))
|
||||
{
|
||||
if (basicSoundIndex > 0)
|
||||
{
|
||||
Sounds.SoundManager.Stop(basicSoundIndex);
|
||||
basicSoundIndex = -1;
|
||||
}
|
||||
if (largeSoundIndex > 0)
|
||||
{
|
||||
Sounds.SoundManager.Stop(largeSoundIndex);
|
||||
largeSoundIndex = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fireSoundBasic != null)
|
||||
{
|
||||
basicSoundIndex = fireSoundBasic.Loop(basicSoundIndex,
|
||||
Math.Min(size.X / 100.0f, 1.0f), WorldPosition + size / 2.0f, 1000.0f);
|
||||
|
||||
}
|
||||
if (fireSoundLarge != null)
|
||||
{
|
||||
largeSoundIndex = fireSoundLarge.Loop(largeSoundIndex,
|
||||
MathHelper.Clamp((size.X - 200.0f) / 100.0f, 0.0f, 1.0f), WorldPosition + size / 2.0f, 1000.0f);
|
||||
}
|
||||
}
|
||||
|
||||
float count = Rand.Range(0.0f, size.X / 50.0f);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Vector2 particlePos = new Vector2(
|
||||
WorldPosition.X + Rand.Range(0.0f, size.X),
|
||||
Rand.Range(WorldPosition.Y - size.Y, WorldPosition.Y + 20.0f));
|
||||
|
||||
Vector2 particleVel = new Vector2(
|
||||
(particlePos.X - (WorldPosition.X + size.X / 2.0f)),
|
||||
(float)Math.Sqrt(size.X) * Rand.Range(0.0f, 15.0f) * growModifier);
|
||||
|
||||
var particle = GameMain.ParticleManager.CreateParticle("flame",
|
||||
particlePos, particleVel, 0.0f, hull);
|
||||
|
||||
if (particle == null) continue;
|
||||
|
||||
//make some of the particles create another firesource when they enter another hull
|
||||
if (Rand.Int(20) == 1) particle.OnChangeHull = OnChangeHull;
|
||||
|
||||
particle.Size *= MathHelper.Clamp(size.X / 60.0f * Math.Max(hull.Oxygen / hull.Volume, 0.4f), 0.5f, 1.0f);
|
||||
|
||||
if (Rand.Int(5) == 1)
|
||||
{
|
||||
var smokeParticle = GameMain.ParticleManager.CreateParticle("smoke",
|
||||
particlePos, new Vector2(particleVel.X, particleVel.Y * 0.1f), 0.0f, hull);
|
||||
|
||||
if (smokeParticle != null)
|
||||
{
|
||||
smokeParticle.Size *= MathHelper.Clamp(size.X / 100.0f * Math.Max(hull.Oxygen / hull.Volume, 0.4f), 0.5f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmitParticles(size, WorldPosition, hull, growModifier, OnChangeHull);
|
||||
|
||||
lightSource.Color = new Color(1.0f, 0.45f, 0.3f) * Rand.Range(0.8f, 1.0f);
|
||||
if (Math.Abs((lightSource.Range * 0.2f) - Math.Max(size.X, size.Y)) > 1.0f) lightSource.Range = Math.Max(size.X, size.Y) * 5.0f;
|
||||
if (Vector2.DistanceSquared(lightSource.Position,position) > 5.0f) lightSource.Position = position + Vector2.UnitY * 30.0f;
|
||||
@@ -98,13 +35,49 @@ namespace Barotrauma
|
||||
if (newDecal != null) burnDecals.Add(newDecal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
foreach (Decal d in burnDecals)
|
||||
{
|
||||
//prevent the decals from fading out as long as the firesource is alive
|
||||
d.FadeTimer = Math.Min(d.FadeTimer, d.FadeInTime);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitParticles(Vector2 size, Vector2 worldPosition, Hull hull, float growModifier, Particle.OnChangeHullHandler onChangeHull = null)
|
||||
{
|
||||
float particleCount = Rand.Range(0.0f, size.X / 50.0f);
|
||||
|
||||
for (int i = 0; i < particleCount; i++)
|
||||
{
|
||||
Vector2 particlePos = new Vector2(
|
||||
worldPosition.X + Rand.Range(0.0f, size.X),
|
||||
Rand.Range(worldPosition.Y - size.Y, worldPosition.Y + 20.0f));
|
||||
|
||||
Vector2 particleVel = new Vector2(
|
||||
(particlePos.X - (worldPosition.X + size.X / 2.0f)),
|
||||
(float)Math.Sqrt(size.X) * Rand.Range(0.0f, 15.0f) * growModifier);
|
||||
|
||||
var particle = GameMain.ParticleManager.CreateParticle("flame",
|
||||
particlePos, particleVel, 0.0f, hull);
|
||||
|
||||
if (particle == null) continue;
|
||||
|
||||
//make some of the particles create another firesource when they enter another hull
|
||||
if (Rand.Int(20) == 1) particle.OnChangeHull = onChangeHull;
|
||||
|
||||
particle.Size *= MathHelper.Clamp(size.X / 60.0f * Math.Max(hull.Oxygen / hull.Volume, 0.4f), 0.5f, 1.0f);
|
||||
|
||||
if (Rand.Int(5) == 1)
|
||||
{
|
||||
var smokeParticle = GameMain.ParticleManager.CreateParticle("smoke",
|
||||
particlePos, new Vector2(particleVel.X, particleVel.Y * 0.1f), 0.0f, hull);
|
||||
|
||||
if (smokeParticle != null)
|
||||
{
|
||||
smokeParticle.Size *= MathHelper.Clamp(size.X / 100.0f * Math.Max(hull.Oxygen / hull.Volume, 0.4f), 0.5f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,14 @@ namespace Barotrauma
|
||||
{
|
||||
private float particleTimer;
|
||||
|
||||
public override bool SelectableInEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return ShowGaps;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch sb, bool editing, bool back = true)
|
||||
{
|
||||
if (GameMain.DebugDraw)
|
||||
@@ -28,9 +36,31 @@ namespace Barotrauma
|
||||
|
||||
GUI.DrawRectangle(
|
||||
sb, new Rectangle(WorldRect.X, -WorldRect.Y, rect.Width, rect.Height),
|
||||
clr * 0.5f, true,
|
||||
depth,
|
||||
(int)Math.Max((1.5f / GameScreen.Selected.Cam.Zoom), 1.0f));
|
||||
clr * 0.2f, true, depth);
|
||||
|
||||
int lineWidth = 5;
|
||||
if (IsHorizontal)
|
||||
{
|
||||
GUI.DrawLine(sb,
|
||||
new Vector2(WorldRect.X, -WorldRect.Y + lineWidth / 2),
|
||||
new Vector2(WorldRect.Right, -WorldRect.Y + lineWidth / 2),
|
||||
clr * 0.6f, width: lineWidth);
|
||||
GUI.DrawLine(sb,
|
||||
new Vector2(WorldRect.X, -WorldRect.Y + rect.Height - lineWidth / 2),
|
||||
new Vector2(WorldRect.Right, -WorldRect.Y + rect.Height - lineWidth / 2),
|
||||
clr * 0.6f, width: lineWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.DrawLine(sb,
|
||||
new Vector2(WorldRect.X + lineWidth / 2, -WorldRect.Y),
|
||||
new Vector2(WorldRect.X + lineWidth / 2, -WorldRect.Y + rect.Height),
|
||||
clr * 0.6f, width: lineWidth);
|
||||
GUI.DrawLine(sb,
|
||||
new Vector2(WorldRect.Right - lineWidth / 2, -WorldRect.Y),
|
||||
new Vector2(WorldRect.Right - lineWidth / 2, -WorldRect.Y + rect.Height),
|
||||
clr * 0.6f, width: lineWidth);
|
||||
}
|
||||
|
||||
for (int i = 0; i < linkedTo.Count; i++)
|
||||
{
|
||||
@@ -39,12 +69,17 @@ namespace Barotrauma
|
||||
: new Vector2(0.0f, Math.Sign((linkedTo[i].Rect.Y - linkedTo[i].Rect.Height / 2.0f) - (rect.Y - rect.Height / 2.0f)));
|
||||
|
||||
Vector2 arrowPos = new Vector2(WorldRect.Center.X, -(WorldRect.Y - WorldRect.Height / 2));
|
||||
arrowPos += new Vector2(dir.X * (WorldRect.Width / 2 + 10), dir.Y * (WorldRect.Height / 2 + 10));
|
||||
arrowPos += new Vector2(dir.X * (WorldRect.Width / 2), dir.Y * (WorldRect.Height / 2));
|
||||
|
||||
float arrowWidth = 32.0f;
|
||||
float arrowSize = 15.0f;
|
||||
|
||||
GUI.Arrow.Draw(sb,
|
||||
arrowPos, clr * 0.8f,
|
||||
GUI.Arrow.Origin, MathUtils.VectorToAngle(dir) + MathHelper.PiOver2,
|
||||
IsHorizontal ? new Vector2(rect.Height / 16.0f, 1.0f) : new Vector2(rect.Width / 16.0f, 1.0f),
|
||||
IsHorizontal ?
|
||||
new Vector2(Math.Min(rect.Height, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y) :
|
||||
new Vector2(Math.Min(rect.Width, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y),
|
||||
SpriteEffects.None, depth);
|
||||
}
|
||||
|
||||
@@ -64,8 +99,6 @@ namespace Barotrauma
|
||||
{
|
||||
if (flowTargetHull == null) return;
|
||||
|
||||
particleTimer += deltaTime;
|
||||
|
||||
Vector2 pos = Position;
|
||||
if (IsHorizontal)
|
||||
{
|
||||
@@ -80,7 +113,8 @@ namespace Barotrauma
|
||||
//light dripping
|
||||
if (open < 0.2f && LerpedFlowForce.LengthSquared() > 100.0f)
|
||||
{
|
||||
float particlesPerSec = open * 1000.0f;
|
||||
particleTimer += deltaTime;
|
||||
float particlesPerSec = open * 100.0f;
|
||||
float emitInterval = 1.0f / particlesPerSec;
|
||||
while (particleTimer > emitInterval)
|
||||
{
|
||||
@@ -106,70 +140,94 @@ namespace Barotrauma
|
||||
"bubbles",
|
||||
(Submarine == null ? pos : pos + Submarine.Position),
|
||||
velocity, 0, flowTargetHull);
|
||||
|
||||
particleTimer = 0.0f;
|
||||
|
||||
particleTimer -= emitInterval;
|
||||
}
|
||||
}
|
||||
//heavy flow -> strong waterfall type of particles
|
||||
else if (LerpedFlowForce.LengthSquared() > 20000.0f)
|
||||
{
|
||||
particleTimer += deltaTime;
|
||||
if (IsHorizontal)
|
||||
{
|
||||
Vector2 velocity = new Vector2(
|
||||
float particlesPerSec = open * rect.Height * 0.1f;
|
||||
float emitInterval = 1.0f / particlesPerSec;
|
||||
while (particleTimer > emitInterval)
|
||||
{
|
||||
Vector2 velocity = new Vector2(
|
||||
MathHelper.Clamp(flowForce.X, -5000.0f, 5000.0f) * Rand.Range(0.5f, 0.7f),
|
||||
flowForce.Y * Rand.Range(0.5f, 0.7f));
|
||||
|
||||
if (flowTargetHull.WaterVolume < flowTargetHull.Volume)
|
||||
{
|
||||
var particle = GameMain.ParticleManager.CreateParticle(
|
||||
"watersplash",
|
||||
(Submarine == null ? pos : pos + Submarine.Position) - Vector2.UnitY * Rand.Range(0.0f, 10.0f),
|
||||
velocity, 0, flowTargetHull);
|
||||
|
||||
if (particle != null)
|
||||
if (flowTargetHull.WaterVolume < flowTargetHull.Volume * 0.95f)
|
||||
{
|
||||
particle.Size = particle.Size * Math.Min(Math.Abs(flowForce.X / 1000.0f), 5.0f);
|
||||
var particle = GameMain.ParticleManager.CreateParticle(
|
||||
"watersplash",
|
||||
(Submarine == null ? pos : pos + Submarine.Position) - Vector2.UnitY * Rand.Range(0.0f, 10.0f),
|
||||
velocity, 0, flowTargetHull);
|
||||
|
||||
if (particle != null)
|
||||
{
|
||||
particle.Size = particle.Size * Math.Min(Math.Abs(flowForce.X / 1000.0f), 5.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.Abs(flowForce.X) > 300.0f)
|
||||
{
|
||||
pos.X += Math.Sign(flowForce.X) * 10.0f;
|
||||
pos.Y = Rand.Range(lowerSurface, rect.Y - rect.Height);
|
||||
|
||||
GameMain.ParticleManager.CreateParticle(
|
||||
"bubbles",
|
||||
Submarine == null ? pos : pos + Submarine.Position,
|
||||
flowForce / 10.0f, 0, flowTargetHull);
|
||||
if (Math.Abs(flowForce.X) > 300.0f)
|
||||
{
|
||||
pos.X += Math.Sign(flowForce.X) * 10.0f;
|
||||
if (rect.Height < 32)
|
||||
{
|
||||
pos.Y = rect.Y - rect.Height / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
float bottomY = rect.Y - rect.Height + 16;
|
||||
float topY = MathHelper.Clamp(lowerSurface, bottomY, rect.Y - 16);
|
||||
pos.Y = Rand.Range(bottomY, topY);
|
||||
}
|
||||
GameMain.ParticleManager.CreateParticle(
|
||||
"bubbles",
|
||||
Submarine == null ? pos : pos + Submarine.Position,
|
||||
flowForce / 10.0f, 0, flowTargetHull);
|
||||
}
|
||||
particleTimer -= emitInterval;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Sign(flowTargetHull.Rect.Y - rect.Y) != Math.Sign(lerpedFlowForce.Y)) return;
|
||||
|
||||
for (int i = 0; i < rect.Width; i += Rand.Range(80, 100))
|
||||
float particlesPerSec = open * rect.Width * 0.3f;
|
||||
float emitInterval = 1.0f / particlesPerSec;
|
||||
while (particleTimer > emitInterval)
|
||||
{
|
||||
pos.X = Rand.Range(rect.X, rect.X + rect.Width);
|
||||
|
||||
Vector2 velocity = new Vector2(
|
||||
lerpedFlowForce.X * Rand.Range(0.5f, 0.7f),
|
||||
MathHelper.Clamp(lerpedFlowForce.Y, -500.0f, 1000.0f) * Rand.Range(0.5f, 0.7f));
|
||||
|
||||
var splash = GameMain.ParticleManager.CreateParticle(
|
||||
if (flowTargetHull.WaterVolume < flowTargetHull.Volume * 0.95f)
|
||||
{
|
||||
var splash = GameMain.ParticleManager.CreateParticle(
|
||||
"watersplash",
|
||||
Submarine == null ? pos : pos + Submarine.Position,
|
||||
velocity, 0, FlowTargetHull);
|
||||
|
||||
if (splash != null) splash.Size = splash.Size * MathHelper.Clamp(rect.Width / 50.0f, 0.8f, 4.0f);
|
||||
|
||||
GameMain.ParticleManager.CreateParticle(
|
||||
if (splash != null) splash.Size = splash.Size * MathHelper.Clamp(rect.Width / 50.0f, 0.8f, 4.0f);
|
||||
}
|
||||
if (Math.Abs(flowForce.Y) > 190.0f && Rand.Range(0.0f, 1.0f) < 0.3f)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle(
|
||||
"bubbles",
|
||||
Submarine == null ? pos : pos + Submarine.Position,
|
||||
flowForce / 2.0f, 0, FlowTargetHull);
|
||||
}
|
||||
particleTimer -= emitInterval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
particleTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Hull : MapEntity, ISerializableEntity, IServerSerializable
|
||||
{
|
||||
public const int MaxDecalsPerHull = 10;
|
||||
|
||||
public static WaterRenderer renderer;
|
||||
|
||||
|
||||
private List<Decal> decals = new List<Decal>();
|
||||
|
||||
private Sound currentFlowSound;
|
||||
private int soundIndex;
|
||||
private float soundVolume;
|
||||
public override bool SelectableInEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return ShowHulls;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool DrawBelowWater
|
||||
{
|
||||
@@ -35,7 +39,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override bool IsMouseOn(Vector2 position)
|
||||
{
|
||||
if (!GameMain.DebugDraw && !ShowHulls) return false;
|
||||
@@ -57,9 +61,25 @@ namespace Barotrauma
|
||||
|
||||
return decal;
|
||||
}
|
||||
|
||||
private GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
{
|
||||
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
|
||||
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.8f), editingHUD.RectTransform, Anchor.Center), style: null);
|
||||
new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true);
|
||||
|
||||
PositionEditingHUD();
|
||||
|
||||
return editingHUD;
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
{
|
||||
if (editingHUD == null || editingHUD.UserData as Hull != this)
|
||||
{
|
||||
editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen);
|
||||
}
|
||||
|
||||
if (!PlayerInput.KeyDown(Keys.Space)) return;
|
||||
bool lClick = PlayerInput.LeftButtonClicked();
|
||||
bool rClick = PlayerInput.RightButtonClicked();
|
||||
@@ -124,53 +144,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
decals.RemoveAll(d => d.FadeTimer >= d.LifeTime);
|
||||
|
||||
float strongestFlow = 0.0f;
|
||||
foreach (Gap gap in ConnectedGaps)
|
||||
{
|
||||
if (gap.IsRoomToRoom)
|
||||
{
|
||||
//only the first linked hull plays the flow sound
|
||||
if (gap.linkedTo[1] == this) continue;
|
||||
}
|
||||
|
||||
float gapFlow = gap.LerpedFlowForce.Length();
|
||||
|
||||
if (gapFlow > strongestFlow)
|
||||
{
|
||||
strongestFlow = gapFlow;
|
||||
}
|
||||
}
|
||||
|
||||
if (strongestFlow > 1.0f)
|
||||
{
|
||||
soundVolume = soundVolume + ((strongestFlow < 100.0f) ? -deltaTime * 0.5f : deltaTime * 0.5f);
|
||||
soundVolume = MathHelper.Clamp(soundVolume, 0.0f, 1.0f);
|
||||
|
||||
int index = (int)Math.Floor(MathHelper.Lerp(0, SoundPlayer.FlowSounds.Count - 1, strongestFlow / 600.0f));
|
||||
index = Math.Min(index, SoundPlayer.FlowSounds.Count - 1);
|
||||
|
||||
var flowSound = SoundPlayer.FlowSounds[index];
|
||||
if (flowSound != currentFlowSound && soundIndex > -1)
|
||||
{
|
||||
Sounds.SoundManager.Stop(soundIndex);
|
||||
currentFlowSound = null;
|
||||
soundIndex = -1;
|
||||
}
|
||||
|
||||
currentFlowSound = flowSound;
|
||||
soundIndex = currentFlowSound.Loop(soundIndex, soundVolume, WorldPosition, Math.Min(strongestFlow * 5.0f, 2000.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (soundIndex > -1)
|
||||
{
|
||||
Sounds.SoundManager.Stop(soundIndex);
|
||||
currentFlowSound = null;
|
||||
soundIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (waterVolume < 1.0f) return;
|
||||
for (int i = 1; i < waveY.Length - 1; i++)
|
||||
{
|
||||
@@ -251,6 +225,21 @@ namespace Barotrauma
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * (waterVolume - Volume) / MaxCompress)), Color.Red, true);
|
||||
}
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, 100), Color.Black);
|
||||
|
||||
foreach (FireSource fs in FireSources)
|
||||
{
|
||||
Rectangle fireSourceRect = new Rectangle((int)fs.WorldPosition.X, -(int)fs.WorldPosition.Y, (int)fs.Size.X, (int)fs.Size.Y);
|
||||
GUI.DrawRectangle(spriteBatch, fireSourceRect, Color.Orange, false, 0, 5);
|
||||
//GUI.DrawRectangle(spriteBatch, new Rectangle((int)fs.LastExtinguishPos.X, (int)-fs.LastExtinguishPos.Y, 5,5), Color.Yellow, true);
|
||||
}
|
||||
|
||||
/*GUI.DrawLine(spriteBatch, new Vector2(drawRect.X, -WorldSurface), new Vector2(drawRect.Right, -WorldSurface), Color.Cyan * 0.5f);
|
||||
for (int i = 0; i < waveY.Length - 1; i++)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(drawRect.X + WaveWidth * i, -WorldSurface - waveY[i] - 10),
|
||||
new Vector2(drawRect.X + WaveWidth * (i + 1), -WorldSurface - waveY[i + 1] - 10), Color.Blue * 0.5f);
|
||||
}*/
|
||||
}
|
||||
|
||||
if ((IsSelected || isHighlighted) && editing)
|
||||
@@ -262,22 +251,47 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(GraphicsDevice graphicsDevice, Camera cam)
|
||||
public static void UpdateVertices(GraphicsDevice graphicsDevice, Camera cam, WaterRenderer renderer)
|
||||
{
|
||||
if (renderer.PositionInBuffer > renderer.vertices.Length - 6) return;
|
||||
foreach (EntityGrid entityGrid in EntityGrids)
|
||||
{
|
||||
if (entityGrid.WorldRect.X > cam.WorldView.Right || entityGrid.WorldRect.Right < cam.WorldView.X) continue;
|
||||
if (entityGrid.WorldRect.Y - entityGrid.WorldRect.Height > cam.WorldView.Y || entityGrid.WorldRect.Y < cam.WorldView.Y - cam.WorldView.Height) continue;
|
||||
|
||||
var allEntities = entityGrid.GetAllEntities();
|
||||
foreach (Hull hull in allEntities)
|
||||
{
|
||||
hull.UpdateVertices(graphicsDevice, cam, entityGrid, renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVertices(GraphicsDevice graphicsDevice, Camera cam, EntityGrid entityGrid, WaterRenderer renderer)
|
||||
{
|
||||
Vector2 submarinePos = Submarine == null ? Vector2.Zero : Submarine.DrawPosition;
|
||||
|
||||
//if there's no more space in the buffer, don't render the water in the hull
|
||||
//not an ideal solution, but this seems to only happen in cases where the missing
|
||||
//water is not very noticeable (e.g. zoomed very far out so that multiple subs and ruins are visible)
|
||||
if (renderer.PositionInBuffer > renderer.vertices.Length - 6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!renderer.IndoorsVertices.ContainsKey(entityGrid))
|
||||
{
|
||||
renderer.IndoorsVertices[entityGrid] = new VertexPositionColorTexture[WaterRenderer.DefaultIndoorsBufferSize];
|
||||
renderer.PositionInIndoorsBuffer[entityGrid] = 0;
|
||||
}
|
||||
|
||||
//calculate where the surface should be based on the water volume
|
||||
float top = rect.Y + submarinePos.Y;
|
||||
float bottom = top - rect.Height;
|
||||
|
||||
float drawSurface = surface + submarinePos.Y;
|
||||
|
||||
Matrix transform = cam.Transform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
|
||||
float renderSurface = drawSurface + submarinePos.Y;
|
||||
|
||||
if (bottom > cam.WorldView.Y || top < cam.WorldView.Y - cam.WorldView.Height) return;
|
||||
|
||||
Matrix transform = cam.Transform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
|
||||
if (!update)
|
||||
{
|
||||
// create the four corners of our triangle.
|
||||
@@ -310,54 +324,131 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
float x = rect.X + Submarine.DrawPosition.X;
|
||||
float x = rect.X;
|
||||
if (Submarine != null) { x += Submarine.DrawPosition.X; }
|
||||
|
||||
int start = (int)Math.Floor((cam.WorldView.X - x) / WaveWidth);
|
||||
start = Math.Max(start, 0);
|
||||
|
||||
int end = (waveY.Length - 1)
|
||||
- (int)Math.Floor((float)((x + rect.Width) - (cam.WorldView.X + cam.WorldView.Width)) / WaveWidth);
|
||||
int end = (waveY.Length - 1) - (int)Math.Floor(((x + rect.Width) - (cam.WorldView.Right)) / WaveWidth);
|
||||
end = Math.Min(end, waveY.Length - 1);
|
||||
|
||||
x += start * WaveWidth;
|
||||
|
||||
Vector3[] prevCorners = new Vector3[2];
|
||||
Vector2[] prevUVs = new Vector2[2];
|
||||
|
||||
int width = WaveWidth;
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
if (renderer.PositionInBuffer > renderer.vertices.Length - 6) return;
|
||||
|
||||
Vector3[] corners = new Vector3[4];
|
||||
Vector3[] corners = new Vector3[6];
|
||||
|
||||
//top left
|
||||
corners[0] = new Vector3(x, top, 0.0f);
|
||||
corners[3] = new Vector3(corners[0].X, drawSurface + waveY[i], 0.0f);
|
||||
|
||||
//skip adjacent "water rects" if the surface of the water is roughly at the same position
|
||||
int width = WaveWidth;
|
||||
while (i < end - 1 && Math.Abs(waveY[i + 1] - waveY[i]) < 1.0f)
|
||||
{
|
||||
width += WaveWidth;
|
||||
i++;
|
||||
}
|
||||
|
||||
//watersurface left
|
||||
corners[3] = new Vector3(corners[0].X, renderSurface + waveY[i], 0.0f);
|
||||
|
||||
//top right
|
||||
corners[1] = new Vector3(x + width, top, 0.0f);
|
||||
corners[2] = new Vector3(corners[1].X, drawSurface + waveY[i + 1], 0.0f);
|
||||
//watersurface right
|
||||
corners[2] = new Vector3(corners[1].X, renderSurface + waveY[i + 1], 0.0f);
|
||||
|
||||
//bottom left
|
||||
corners[4] = new Vector3(x, bottom, 0.0f);
|
||||
//bottom right
|
||||
corners[5] = new Vector3(x + width, bottom, 0.0f);
|
||||
|
||||
Vector2[] uvCoords = new Vector2[4];
|
||||
for (int n = 0; n < 4; n++)
|
||||
{
|
||||
uvCoords[n] = Vector2.Transform(new Vector2(corners[n].X, -corners[n].Y), transform);
|
||||
}
|
||||
|
||||
renderer.vertices[renderer.PositionInBuffer] = new VertexPositionTexture(corners[0], uvCoords[0]);
|
||||
renderer.vertices[renderer.PositionInBuffer + 1] = new VertexPositionTexture(corners[1], uvCoords[1]);
|
||||
renderer.vertices[renderer.PositionInBuffer + 2] = new VertexPositionTexture(corners[2], uvCoords[2]);
|
||||
if (renderer.PositionInBuffer <= renderer.vertices.Length - 6)
|
||||
{
|
||||
if (i == start)
|
||||
{
|
||||
prevCorners[0] = corners[0];
|
||||
prevCorners[1] = corners[3];
|
||||
prevUVs[0] = uvCoords[0];
|
||||
prevUVs[1] = uvCoords[3];
|
||||
}
|
||||
|
||||
renderer.vertices[renderer.PositionInBuffer + 3] = new VertexPositionTexture(corners[0], uvCoords[0]);
|
||||
renderer.vertices[renderer.PositionInBuffer + 4] = new VertexPositionTexture(corners[2], uvCoords[2]);
|
||||
renderer.vertices[renderer.PositionInBuffer + 5] = new VertexPositionTexture(corners[3], uvCoords[3]);
|
||||
//we only create a new quad if this is the first or the last one, of if there's a wave large enough that we need more geometry
|
||||
if (i == end - 1 || i == start || Math.Abs(prevCorners[1].Y - corners[3].Y) > 1.0f)
|
||||
{
|
||||
renderer.vertices[renderer.PositionInBuffer] = new VertexPositionTexture(prevCorners[0], prevUVs[0]);
|
||||
renderer.vertices[renderer.PositionInBuffer + 1] = new VertexPositionTexture(corners[1], uvCoords[1]);
|
||||
renderer.vertices[renderer.PositionInBuffer + 2] = new VertexPositionTexture(corners[2], uvCoords[2]);
|
||||
|
||||
renderer.PositionInBuffer += 6;
|
||||
renderer.vertices[renderer.PositionInBuffer + 3] = new VertexPositionTexture(prevCorners[0], prevUVs[0]);
|
||||
renderer.vertices[renderer.PositionInBuffer + 4] = new VertexPositionTexture(corners[2], uvCoords[2]);
|
||||
renderer.vertices[renderer.PositionInBuffer + 5] = new VertexPositionTexture(prevCorners[1], prevUVs[1]);
|
||||
|
||||
x += width;
|
||||
prevCorners[0] = corners[1];
|
||||
prevCorners[1] = corners[2];
|
||||
prevUVs[0] = uvCoords[1];
|
||||
prevUVs[1] = uvCoords[2];
|
||||
|
||||
renderer.PositionInBuffer += 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (renderer.PositionInIndoorsBuffer[entityGrid] <= renderer.IndoorsVertices[entityGrid].Length - 12 &&
|
||||
cam.Zoom > 0.6f)
|
||||
{
|
||||
const float SurfaceSize = 10.0f;
|
||||
const float SineFrequency1 = 0.01f;
|
||||
const float SineFrequency2 = 0.05f;
|
||||
|
||||
//surface shrinks and finally disappears when the water level starts to reach the top of the hull
|
||||
float surfaceScale = 1.0f - MathHelper.Clamp(corners[3].Y - (top - SurfaceSize), 0.0f, 1.0f);
|
||||
|
||||
Vector3 surfaceOffset = new Vector3(0.0f, -SurfaceSize, 0.0f);
|
||||
surfaceOffset.Y += (float)Math.Sin((rect.X + i * WaveWidth) * SineFrequency1 + renderer.WavePos.X * 0.25f) * 2;
|
||||
surfaceOffset.Y += (float)Math.Sin((rect.X + i * WaveWidth) * SineFrequency2 - renderer.WavePos.X) * 2;
|
||||
surfaceOffset *= surfaceScale;
|
||||
|
||||
Vector3 surfaceOffset2 = new Vector3(0.0f, -SurfaceSize, 0.0f);
|
||||
surfaceOffset2.Y += (float)Math.Sin((rect.X + i * WaveWidth + width) * SineFrequency1 + renderer.WavePos.X * 0.25f) * 2;
|
||||
surfaceOffset2.Y += (float)Math.Sin((rect.X + i * WaveWidth + width) * SineFrequency2 - renderer.WavePos.X) * 2;
|
||||
surfaceOffset2 *= surfaceScale;
|
||||
|
||||
int posInBuffer = renderer.PositionInIndoorsBuffer[entityGrid];
|
||||
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 0] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsWaterColor, Vector2.Zero);
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 1] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsWaterColor, Vector2.Zero);
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 2] = new VertexPositionColorTexture(corners[5], renderer.IndoorsWaterColor, Vector2.Zero);
|
||||
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 3] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsWaterColor, Vector2.Zero);
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 4] = new VertexPositionColorTexture(corners[5], renderer.IndoorsWaterColor, Vector2.Zero);
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 5] = new VertexPositionColorTexture(corners[4], renderer.IndoorsWaterColor, Vector2.Zero);
|
||||
|
||||
posInBuffer += 6;
|
||||
renderer.PositionInIndoorsBuffer[entityGrid] = posInBuffer;
|
||||
|
||||
if (surfaceScale > 0)
|
||||
{
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 0] = new VertexPositionColorTexture(corners[3], renderer.IndoorsSurfaceTopColor, Vector2.Zero);
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 1] = new VertexPositionColorTexture(corners[2], renderer.IndoorsSurfaceTopColor, Vector2.Zero);
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 2] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsSurfaceBottomColor, Vector2.Zero);
|
||||
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 3] = new VertexPositionColorTexture(corners[3], renderer.IndoorsSurfaceTopColor, Vector2.Zero);
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 4] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsSurfaceBottomColor, Vector2.Zero);
|
||||
renderer.IndoorsVertices[entityGrid][posInBuffer + 5] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsSurfaceBottomColor, Vector2.Zero);
|
||||
|
||||
renderer.PositionInIndoorsBuffer[entityGrid] += 6;
|
||||
}
|
||||
}
|
||||
|
||||
x += WaveWidth;
|
||||
//clamp the last segment to the right edge of the hull
|
||||
if (i == end - 2)
|
||||
{
|
||||
width -= (int)Math.Max((x + WaveWidth) - (Submarine == null ? rect.Right : (rect.Right + Submarine.DrawPosition.X)), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class ItemAssemblyPrefab
|
||||
{
|
||||
public void DrawIcon(SpriteBatch spriteBatch, GUICustomComponent guiComponent)
|
||||
{
|
||||
Rectangle drawArea = guiComponent.Rect;
|
||||
|
||||
float scale = Math.Min(drawArea.Width / (float)Bounds.Width, drawArea.Height / (float)Bounds.Height) * 0.9f;
|
||||
|
||||
foreach (Pair<MapEntityPrefab, Rectangle> entity in DisplayEntities)
|
||||
{
|
||||
Rectangle drawRect = entity.Second;
|
||||
drawRect = new Rectangle(
|
||||
(int)(drawRect.X * scale) + drawArea.Center.X, -((int)((drawRect.Y - drawRect.Height) * scale) + drawArea.Center.Y),
|
||||
(int)(drawRect.Width * scale), (int)(drawRect.Height * scale));
|
||||
entity.First.DrawPlacing(spriteBatch, drawRect, scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void DrawPlacing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
base.DrawPlacing(spriteBatch, cam);
|
||||
foreach (Pair<MapEntityPrefab, Rectangle> entity in DisplayEntities)
|
||||
{
|
||||
Rectangle drawRect = entity.Second;
|
||||
drawRect.Location += Submarine.MouseToWorldGrid(cam, Submarine.MainSub).ToPoint();
|
||||
entity.First.DrawPlacing(spriteBatch, drawRect);
|
||||
}
|
||||
}
|
||||
|
||||
public static XElement Save(List<MapEntity> entities, string name, string description, bool hideInMenus = false)
|
||||
{
|
||||
XElement element = new XElement("ItemAssembly",
|
||||
new XAttribute("name", name),
|
||||
new XAttribute("description", description),
|
||||
new XAttribute("hideinmenus", hideInMenus));
|
||||
|
||||
|
||||
//move the entities so that their "center of mass" is at {0,0}
|
||||
var assemblyEntities = MapEntity.CopyEntities(entities);
|
||||
|
||||
//find wires and items that are contained inside another item
|
||||
//place them at {0,0} to prevent them from messing up the origin of the prefab and to hide them in preview
|
||||
List<MapEntity> disabledEntities = new List<MapEntity>();
|
||||
foreach (MapEntity mapEntity in assemblyEntities)
|
||||
{
|
||||
if (mapEntity is Item item)
|
||||
{
|
||||
var wire = item.GetComponent<Wire>();
|
||||
if (item.ParentInventory != null ||
|
||||
(wire != null && wire.Connections.Any(c => c != null)))
|
||||
{
|
||||
item.SetTransform(Vector2.Zero, 0.0f);
|
||||
disabledEntities.Add(mapEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float minX = int.MaxValue, maxX = int.MinValue;
|
||||
float minY = int.MaxValue, maxY = int.MinValue;
|
||||
foreach (MapEntity mapEntity in assemblyEntities)
|
||||
{
|
||||
if (disabledEntities.Contains(mapEntity)) { continue; }
|
||||
minX = Math.Min(minX, mapEntity.WorldRect.X);
|
||||
maxX = Math.Max(maxX, mapEntity.WorldRect.Right);
|
||||
minY = Math.Min(minY, mapEntity.WorldRect.Y - mapEntity.WorldRect.Height);
|
||||
maxY = Math.Max(maxY, mapEntity.WorldRect.Y);
|
||||
}
|
||||
Vector2 center = new Vector2((minX + maxX) / 2.0f, (minY + maxY) / 2.0f);
|
||||
if (Submarine.MainSub != null) { center -= Submarine.MainSub.HiddenSubPosition; }
|
||||
center.X -= center.X % Submarine.GridSize.X;
|
||||
center.Y -= center.Y % Submarine.GridSize.Y;
|
||||
|
||||
MapEntity.SelectedList.Clear();
|
||||
MapEntity.SelectedList.AddRange(assemblyEntities);
|
||||
|
||||
foreach (MapEntity mapEntity in assemblyEntities)
|
||||
{
|
||||
mapEntity.Move(-center);
|
||||
mapEntity.Submarine = Submarine.MainSub;
|
||||
var entityElement = mapEntity.Save(element);
|
||||
if (disabledEntities.Contains(mapEntity))
|
||||
{
|
||||
entityElement.Add(new XAttribute("hideinassemblypreview", "true"));
|
||||
}
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
-45
@@ -26,6 +26,10 @@ namespace Barotrauma
|
||||
|
||||
private float checkWallsTimer;
|
||||
|
||||
private float wanderZPhase;
|
||||
private Vector2 obstacleDiff;
|
||||
private float obstacleDist;
|
||||
|
||||
public Swarm Swarm;
|
||||
|
||||
Vector2 drawPosition;
|
||||
@@ -71,12 +75,9 @@ namespace Barotrauma
|
||||
Rand.Range(0.0f, prefab.WanderZAmount));
|
||||
|
||||
checkWallsTimer = Rand.Range(0.0f, CheckWallsInterval);
|
||||
|
||||
|
||||
}
|
||||
|
||||
float ang;
|
||||
Vector2 obstacleDiff;
|
||||
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
position += new Vector2(velocity.X, velocity.Y) * deltaTime;
|
||||
@@ -109,30 +110,33 @@ namespace Barotrauma
|
||||
var cells = Level.Loaded.GetCells(position, 1);
|
||||
if (cells.Count > 0)
|
||||
{
|
||||
|
||||
int cellCount = 0;
|
||||
foreach (Voronoi2.VoronoiCell cell in cells)
|
||||
{
|
||||
obstacleDiff += cell.Center - position;
|
||||
Vector2 diff = cell.Center - position;
|
||||
if (diff.LengthSquared() > 5000.0f * 5000.0f) continue;
|
||||
obstacleDiff += diff;
|
||||
cellCount++;
|
||||
}
|
||||
if (cellCount > 0)
|
||||
{
|
||||
obstacleDiff /= cellCount;
|
||||
obstacleDist = obstacleDiff.Length();
|
||||
obstacleDiff = Vector2.Normalize(obstacleDiff);
|
||||
}
|
||||
obstacleDiff /= cells.Count;
|
||||
|
||||
obstacleDiff = Vector2.Normalize(obstacleDiff) * prefab.Speed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (Swarm!=null)
|
||||
if (Swarm != null)
|
||||
{
|
||||
Vector2 midPoint = Swarm.MidPoint();
|
||||
float midPointDist = Vector2.Distance(SimPosition, midPoint);
|
||||
|
||||
float midPointDist = Vector2.Distance(SimPosition, midPoint) * 100.0f;
|
||||
if (midPointDist > Swarm.MaxDistance)
|
||||
{
|
||||
steeringManager.SteeringSeek(midPoint, (midPointDist / Swarm.MaxDistance) * prefab.Speed);
|
||||
steeringManager.SteeringSeek(midPoint, ((midPointDist / Swarm.MaxDistance) - 1.0f) * prefab.Speed);
|
||||
}
|
||||
steeringManager.SteeringManual(deltaTime, Swarm.AvgVelocity() * Swarm.Cohesion);
|
||||
}
|
||||
|
||||
if (prefab.WanderAmount > 0.0f)
|
||||
@@ -140,26 +144,23 @@ namespace Barotrauma
|
||||
steeringManager.SteeringWander(prefab.Speed);
|
||||
}
|
||||
|
||||
//Level.Loaded.Size
|
||||
|
||||
|
||||
if (obstacleDiff != Vector2.Zero)
|
||||
{
|
||||
steeringManager.SteeringSeek(SimPosition-obstacleDiff, prefab.Speed*2.0f);
|
||||
steeringManager.SteeringManual(deltaTime, -obstacleDiff * (1.0f - obstacleDist / 5000.0f) * prefab.Speed);
|
||||
}
|
||||
|
||||
steeringManager.Update(prefab.Speed);
|
||||
|
||||
if (prefab.WanderZAmount>0.0f)
|
||||
if (prefab.WanderZAmount > 0.0f)
|
||||
{
|
||||
ang += Rand.Range(-prefab.WanderZAmount, prefab.WanderZAmount);
|
||||
velocity.Z = (float)Math.Sin(ang)*prefab.Speed;
|
||||
wanderZPhase += Rand.Range(-prefab.WanderZAmount, prefab.WanderZAmount);
|
||||
velocity.Z = (float)Math.Sin(wanderZPhase) * prefab.Speed;
|
||||
}
|
||||
|
||||
|
||||
velocity = Vector3.Lerp(velocity, new Vector3(Steering.X, Steering.Y, velocity.Z), deltaTime);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
float rotation = 0.0f;
|
||||
if (!prefab.DisableRotation)
|
||||
@@ -168,20 +169,18 @@ namespace Barotrauma
|
||||
if (velocity.X < 0.0f) rotation -= MathHelper.Pi;
|
||||
}
|
||||
|
||||
drawPosition = position;// +Level.Loaded.Position;
|
||||
|
||||
drawPosition = position;
|
||||
if (depth > 0.0f)
|
||||
{
|
||||
Vector2 camOffset = drawPosition - GameMain.GameScreen.Cam.WorldViewCenter;
|
||||
|
||||
Vector2 camOffset = drawPosition - cam.WorldViewCenter;
|
||||
drawPosition -= camOffset * (depth / MaxDepth) * 0.05f;
|
||||
}
|
||||
|
||||
prefab.Sprite.Draw(spriteBatch,
|
||||
new Vector2(drawPosition.X, -drawPosition.Y),
|
||||
Color.Lerp(Color.White, Color.DarkBlue, (depth/MaxDepth)*0.3f),
|
||||
rotation, (1.0f - (depth / MaxDepth) * 0.2f) * prefab.Scale,
|
||||
velocity.X > 0.0f ? SpriteEffects.None : SpriteEffects.FlipHorizontally,
|
||||
|
||||
prefab.Sprite.Draw(spriteBatch,
|
||||
new Vector2(drawPosition.X, -drawPosition.Y),
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundColor, (depth / MaxDepth) * 0.2f),
|
||||
rotation, (1.0f - (depth / MaxDepth) * 0.2f) * prefab.Scale,
|
||||
velocity.X > 0.0f ? SpriteEffects.None : SpriteEffects.FlipHorizontally,
|
||||
(depth / MaxDepth));
|
||||
}
|
||||
}
|
||||
@@ -191,6 +190,7 @@ namespace Barotrauma
|
||||
public List<BackgroundCreature> Members;
|
||||
|
||||
public readonly float MaxDistance;
|
||||
public readonly float Cohesion;
|
||||
|
||||
public Vector2 MidPoint()
|
||||
{
|
||||
@@ -213,23 +213,19 @@ namespace Barotrauma
|
||||
if (Members.Count == 0) return Vector2.Zero;
|
||||
|
||||
Vector2 avgVel = Vector2.Zero;
|
||||
|
||||
foreach (BackgroundCreature member in Members)
|
||||
{
|
||||
avgVel += member.Velocity;
|
||||
}
|
||||
|
||||
avgVel /= Members.Count;
|
||||
|
||||
avgVel /= Members.Count;
|
||||
return avgVel;
|
||||
}
|
||||
|
||||
public Swarm(List<BackgroundCreature> members, float maxDistance)
|
||||
public Swarm(List<BackgroundCreature> members, float maxDistance, float cohesion)
|
||||
{
|
||||
this.Members = members;
|
||||
|
||||
this.MaxDistance = maxDistance;
|
||||
|
||||
Members = members;
|
||||
MaxDistance = maxDistance;
|
||||
Cohesion = cohesion;
|
||||
foreach (BackgroundCreature bgSprite in members)
|
||||
{
|
||||
bgSprite.Swarm = this;
|
||||
+4
-4
@@ -22,7 +22,7 @@ namespace Barotrauma
|
||||
{
|
||||
LoadConfig(configPath);
|
||||
}
|
||||
public BackgroundCreatureManager(List<string> files)
|
||||
public BackgroundCreatureManager(IEnumerable<string> files)
|
||||
{
|
||||
foreach(var file in files)
|
||||
{
|
||||
@@ -92,7 +92,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (amount > 0)
|
||||
{
|
||||
new Swarm(swarmMembers, prefab.SwarmRadius);
|
||||
new Swarm(swarmMembers, prefab.SwarmRadius, prefab.SwarmCohesion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,12 +126,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
{
|
||||
if (!sprite.Enabled) continue;
|
||||
sprite.Draw(spriteBatch);
|
||||
sprite.Draw(spriteBatch, cam);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -13,8 +13,7 @@ namespace Barotrauma
|
||||
public readonly float WanderZAmount;
|
||||
|
||||
public readonly int SwarmMin, SwarmMax;
|
||||
|
||||
public readonly float SwarmRadius;
|
||||
public readonly float SwarmRadius, SwarmCohesion;
|
||||
|
||||
public readonly bool DisableRotation;
|
||||
|
||||
@@ -32,6 +31,7 @@ namespace Barotrauma
|
||||
SwarmMax = element.GetAttributeInt("swarmmax", 1);
|
||||
|
||||
SwarmRadius = element.GetAttributeFloat("swarmradius", 200.0f);
|
||||
SwarmCohesion = element.GetAttributeFloat("swarmcohesion", 0.2f);
|
||||
|
||||
DisableRotation = element.GetAttributeBool("disablerotation", false);
|
||||
|
||||
-139
@@ -1,139 +0,0 @@
|
||||
using Barotrauma.Particles;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class BackgroundSprite
|
||||
{
|
||||
public List<ParticleEmitter> ParticleEmitters;
|
||||
public Sound Sound;
|
||||
}
|
||||
|
||||
partial class BackgroundSpriteManager
|
||||
{
|
||||
private List<BackgroundSprite> visibleSprites = new List<BackgroundSprite>();
|
||||
|
||||
private Rectangle currentGridIndices;
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
foreach (BackgroundSprite s in visibleSprites)
|
||||
{
|
||||
if (s.ParticleEmitters != null)
|
||||
{
|
||||
for (int i = 0; i < s.ParticleEmitters.Count; i++)
|
||||
{
|
||||
Vector2 emitterPos = s.LocalToWorld(s.Prefab.EmitterPositions[i]);
|
||||
s.ParticleEmitters[i].Emit(deltaTime, emitterPos);
|
||||
}
|
||||
}
|
||||
|
||||
if (s.Sound != null)
|
||||
{
|
||||
int sourceIndex;
|
||||
Vector2 soundPos = s.LocalToWorld(new Vector2(s.Prefab.SoundPosition.X, s.Prefab.SoundPosition.Y));
|
||||
if (!Sounds.SoundManager.IsPlaying(s.Sound, out sourceIndex))
|
||||
{
|
||||
s.Sound.Play(soundPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.Sound.UpdatePosition(soundPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSprites(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Rectangle indices = Rectangle.Empty;
|
||||
indices.X = (int)Math.Floor(cam.WorldView.X / (float)GridSize);
|
||||
if (indices.X >= spriteGrid.GetLength(0)) return;
|
||||
indices.Y = (int)Math.Floor((cam.WorldView.Y - cam.WorldView.Height - Level.Loaded.BottomPos) / (float)GridSize);
|
||||
if (indices.Y >= spriteGrid.GetLength(1)) return;
|
||||
|
||||
indices.Width = (int)Math.Floor(cam.WorldView.Right / (float)GridSize)+1;
|
||||
if (indices.Width < 0) return;
|
||||
indices.Height = (int)Math.Floor((cam.WorldView.Y - Level.Loaded.BottomPos) / (float)GridSize)+1;
|
||||
if (indices.Height < 0) return;
|
||||
|
||||
indices.X = Math.Max(indices.X, 0);
|
||||
indices.Y = Math.Max(indices.Y, 0);
|
||||
indices.Width = Math.Min(indices.Width, spriteGrid.GetLength(0)-1);
|
||||
indices.Height = Math.Min(indices.Height, spriteGrid.GetLength(1)-1);
|
||||
|
||||
float z = 0.0f;
|
||||
if (currentGridIndices != indices)
|
||||
{
|
||||
visibleSprites.Clear();
|
||||
|
||||
for (int x = indices.X; x <= indices.Width; x++)
|
||||
{
|
||||
for (int y = indices.Y; y <= indices.Height; y++)
|
||||
{
|
||||
if (spriteGrid[x, y] == null) continue;
|
||||
foreach (BackgroundSprite sprite in spriteGrid[x, y])
|
||||
{
|
||||
int drawOrderIndex = 0;
|
||||
for (int i = 0; i < visibleSprites.Count; i++)
|
||||
{
|
||||
if (visibleSprites[i] == sprite)
|
||||
{
|
||||
drawOrderIndex = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (visibleSprites[i].Position.Z < sprite.Position.Z)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawOrderIndex = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (drawOrderIndex >= 0)
|
||||
{
|
||||
visibleSprites.Insert(drawOrderIndex, sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentGridIndices = indices;
|
||||
}
|
||||
|
||||
foreach (BackgroundSprite sprite in visibleSprites)
|
||||
{
|
||||
Vector2 camDiff = new Vector2(sprite.Position.X, sprite.Position.Y) - cam.WorldViewCenter;
|
||||
camDiff.Y = -camDiff.Y;
|
||||
|
||||
sprite.Prefab.Sprite.Draw(
|
||||
spriteBatch,
|
||||
new Vector2(sprite.Position.X, -sprite.Position.Y) - camDiff * sprite.Position.Z / 10000.0f,
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundColor, sprite.Position.Z / 5000.0f),
|
||||
sprite.Rotation + swingState * sprite.Prefab.SwingAmount,
|
||||
sprite.Scale,
|
||||
SpriteEffects.None,
|
||||
z);
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(sprite.Position.X, -sprite.Position.Y), new Vector2(10.0f, 10.0f), Color.Red, true);
|
||||
|
||||
if (sprite.Trigger != null && sprite.Trigger.PhysicsBody != null)
|
||||
{
|
||||
sprite.Trigger.PhysicsBody.UpdateDrawPosition();
|
||||
sprite.Trigger.PhysicsBody.DebugDraw(spriteBatch, Color.Cyan);
|
||||
}
|
||||
}
|
||||
|
||||
z += 0.0001f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
using Barotrauma.Particles;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class BackgroundSpritePrefab
|
||||
{
|
||||
public readonly List<ParticleEmitterPrefab> ParticleEmitterPrefabs;
|
||||
public readonly List<Vector2> EmitterPositions;
|
||||
|
||||
public readonly XElement SoundElement;
|
||||
public readonly Vector2 SoundPosition;
|
||||
}
|
||||
}
|
||||
@@ -29,52 +29,52 @@ namespace Barotrauma
|
||||
|
||||
public static VertexPositionTexture[] GenerateWallShapes(List<VoronoiCell> cells, Level level)
|
||||
{
|
||||
float inwardThickness = 500.0f, outWardThickness = 30.0f;
|
||||
float outWardThickness = 30.0f;
|
||||
|
||||
List<VertexPositionTexture> verticeList = new List<VertexPositionTexture>();
|
||||
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
//if (cell.body == null) continue;
|
||||
foreach (GraphEdge edge in cell.edges)
|
||||
CompareCCW compare = new CompareCCW(cell.Center);
|
||||
foreach (GraphEdge edge in cell.Edges)
|
||||
{
|
||||
if (edge.cell1 != null && edge.cell1.body == null && edge.cell1.CellType != CellType.Empty) edge.cell1 = null;
|
||||
if (edge.cell2 != null && edge.cell2.body == null && edge.cell2.CellType != CellType.Empty) edge.cell2 = null;
|
||||
if (edge.Cell1 != null && edge.Cell1.Body == null && edge.Cell1.CellType != CellType.Empty) edge.Cell1 = null;
|
||||
if (edge.Cell2 != null && edge.Cell2.Body == null && edge.Cell2.CellType != CellType.Empty) edge.Cell2 = null;
|
||||
|
||||
CompareCCW compare = new CompareCCW(cell.Center);
|
||||
if (compare.Compare(edge.point1, edge.point2) == -1)
|
||||
if (compare.Compare(edge.Point1, edge.Point2) == -1)
|
||||
{
|
||||
var temp = edge.point1;
|
||||
edge.point1 = edge.point2;
|
||||
edge.point2 = temp;
|
||||
var temp = edge.Point1;
|
||||
edge.Point1 = edge.Point2;
|
||||
edge.Point2 = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
//if (cell.body == null) continue;
|
||||
foreach (GraphEdge edge in cell.edges)
|
||||
foreach (GraphEdge edge in cell.Edges)
|
||||
{
|
||||
if (!edge.isSolid) continue;
|
||||
if (!edge.IsSolid) continue;
|
||||
|
||||
GraphEdge leftEdge = cell.edges.Find(e => e != edge && (edge.point1 == e.point1 || edge.point1 == e.point2));
|
||||
GraphEdge rightEdge = cell.edges.Find(e => e != edge && (edge.point2 == e.point1 || edge.point2 == e.point2));
|
||||
GraphEdge leftEdge = cell.Edges.Find(e => e != edge && (edge.Point1 == e.Point1 || edge.Point1 == e.Point2));
|
||||
GraphEdge rightEdge = cell.Edges.Find(e => e != edge && (edge.Point2 == e.Point1 || edge.Point2 == e.Point2));
|
||||
|
||||
Vector2 leftNormal = Vector2.Zero, rightNormal = Vector2.Zero;
|
||||
|
||||
if (leftEdge == null)
|
||||
float inwardThickness1 = 100;
|
||||
float inwardThickness2 = 100;
|
||||
if (leftEdge != null && !leftEdge.IsSolid)
|
||||
{
|
||||
leftNormal = GetEdgeNormal(edge, cell);
|
||||
leftNormal = edge.Point1 == leftEdge.Point1 ?
|
||||
Vector2.Normalize(leftEdge.Point2 - leftEdge.Point1) :
|
||||
Vector2.Normalize(leftEdge.Point1 - leftEdge.Point2);
|
||||
inwardThickness1 = Vector2.Distance(leftEdge.Point1, leftEdge.Point2) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftNormal = (leftEdge.isSolid) ?
|
||||
Vector2.Normalize(GetEdgeNormal(leftEdge) + GetEdgeNormal(edge, cell)) :
|
||||
Vector2.Normalize(leftEdge.Center - edge.point1);
|
||||
leftNormal = Vector2.Normalize(cell.Center - edge.Point1);
|
||||
inwardThickness1 = Vector2.Distance(edge.Point1, cell.Center) / 2;
|
||||
}
|
||||
|
||||
|
||||
if (!MathUtils.IsValid(leftNormal))
|
||||
{
|
||||
#if DEBUG
|
||||
@@ -84,25 +84,26 @@ namespace Barotrauma
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
"Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")");
|
||||
|
||||
if (cell.body != null)
|
||||
if (cell.Body != null)
|
||||
{
|
||||
GameMain.World.RemoveBody(cell.body);
|
||||
cell.body = null;
|
||||
GameMain.World.RemoveBody(cell.Body);
|
||||
cell.Body = null;
|
||||
}
|
||||
leftNormal = Vector2.UnitX;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (rightEdge == null)
|
||||
if (rightEdge != null && !rightEdge.IsSolid)
|
||||
{
|
||||
rightNormal = GetEdgeNormal(edge, cell);
|
||||
rightNormal = edge.Point2 == rightEdge.Point1 ?
|
||||
Vector2.Normalize(rightEdge.Point2 - rightEdge.Point1) :
|
||||
Vector2.Normalize(rightEdge.Point1 - rightEdge.Point2);
|
||||
inwardThickness2 = Vector2.Distance(rightEdge.Point1, rightEdge.Point2) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightNormal = (rightEdge.isSolid) ?
|
||||
Vector2.Normalize(GetEdgeNormal(rightEdge) + GetEdgeNormal(edge, cell)) :
|
||||
Vector2.Normalize(rightEdge.Center - edge.point2);
|
||||
rightNormal = Vector2.Normalize(cell.Center - edge.Point2);
|
||||
inwardThickness2 = Vector2.Distance(edge.Point2, cell.Center) / 2;
|
||||
}
|
||||
|
||||
if (!MathUtils.IsValid(rightNormal))
|
||||
@@ -114,49 +115,54 @@ namespace Barotrauma
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
"Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")");
|
||||
|
||||
if (cell.body != null)
|
||||
if (cell.Body != null)
|
||||
{
|
||||
GameMain.World.RemoveBody(cell.body);
|
||||
cell.body = null;
|
||||
GameMain.World.RemoveBody(cell.Body);
|
||||
cell.Body = null;
|
||||
}
|
||||
rightNormal = Vector2.UnitX;
|
||||
break;
|
||||
}
|
||||
|
||||
float point1UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point1 - cell.Center));
|
||||
float point2UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point2 - cell.Center));
|
||||
//handle wrapping around 0/360
|
||||
if (point1UV - point2UV > MathHelper.Pi)
|
||||
{
|
||||
point2UV += MathHelper.TwoPi;
|
||||
}
|
||||
//the texture wraps around the cell 4 times
|
||||
//TODO: define the uv scale in level generation parameters?
|
||||
point1UV = point1UV / MathHelper.TwoPi * 4;
|
||||
point2UV = point2UV / MathHelper.TwoPi * 4;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Vector2[] verts = new Vector2[3];
|
||||
VertexPositionTexture[] vertPos = new VertexPositionTexture[3];
|
||||
|
||||
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
verts[0] = edge.point1 - leftNormal * outWardThickness;
|
||||
verts[1] = edge.point2 - rightNormal * outWardThickness;
|
||||
verts[2] = edge.point1 + leftNormal * inwardThickness;
|
||||
verts[0] = edge.Point1 - leftNormal * outWardThickness;
|
||||
verts[1] = edge.Point2 - rightNormal * outWardThickness;
|
||||
verts[2] = edge.Point1 + leftNormal * inwardThickness1;
|
||||
|
||||
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), Vector2.Zero);
|
||||
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), Vector2.UnitX);
|
||||
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(0, 0.5f));
|
||||
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(point1UV, 0.0f));
|
||||
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), new Vector2(point2UV, 0.0f));
|
||||
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(point1UV, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
verts[0] = edge.point1 + leftNormal * inwardThickness;
|
||||
verts[1] = edge.point2 - rightNormal * outWardThickness;
|
||||
verts[2] = edge.point2 + rightNormal * inwardThickness;
|
||||
|
||||
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(0.0f, 0.5f));
|
||||
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), Vector2.UnitX);
|
||||
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(1.0f, 0.5f));
|
||||
}
|
||||
|
||||
var comparer = new CompareCCW((verts[0] + verts[1] + verts[2]) / 3.0f);
|
||||
Array.Sort(verts, vertPos, comparer);
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
verticeList.Add(vertPos[j]);
|
||||
verts[0] = edge.Point1 + leftNormal * inwardThickness1;
|
||||
verts[1] = edge.Point2 - rightNormal * outWardThickness;
|
||||
verts[2] = edge.Point2 + rightNormal * inwardThickness2;
|
||||
|
||||
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(point1UV, 0.5f));
|
||||
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), new Vector2(point2UV, 0.0f));
|
||||
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(point2UV, 0.5f));
|
||||
}
|
||||
verticeList.AddRange(vertPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -8,11 +13,42 @@ namespace Barotrauma
|
||||
private LevelRenderer renderer;
|
||||
|
||||
private BackgroundCreatureManager backgroundCreatureManager;
|
||||
|
||||
public LevelRenderer Renderer => renderer;
|
||||
|
||||
public void ReloadTextures()
|
||||
{
|
||||
renderer.ReloadTextures();
|
||||
|
||||
HashSet<Texture2D> uniqueTextures = new HashSet<Texture2D>();
|
||||
HashSet<Sprite> uniqueSprites = new HashSet<Sprite>();
|
||||
var allLevelObjects = levelObjectManager.GetAllObjects();
|
||||
foreach (var levelObj in allLevelObjects)
|
||||
{
|
||||
if (levelObj.Prefab.Sprite != null &&
|
||||
!uniqueTextures.Contains(levelObj.Prefab.Sprite.Texture))
|
||||
{
|
||||
uniqueTextures.Add(levelObj.Prefab.Sprite.Texture);
|
||||
uniqueSprites.Add(levelObj.Prefab.Sprite);
|
||||
}
|
||||
if (levelObj.Prefab.SpecularSprite != null &&
|
||||
!uniqueTextures.Contains(levelObj.Prefab.SpecularSprite.Texture))
|
||||
{
|
||||
uniqueTextures.Add(levelObj.Prefab.SpecularSprite.Texture);
|
||||
uniqueSprites.Add(levelObj.Prefab.SpecularSprite);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Sprite sprite in uniqueSprites)
|
||||
{
|
||||
sprite.ReloadTexture();
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawFront(SpriteBatch spriteBatch)
|
||||
public void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (renderer == null) return;
|
||||
renderer.Draw(spriteBatch);
|
||||
renderer.Draw(spriteBatch, cam);
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
@@ -43,13 +79,37 @@ namespace Barotrauma
|
||||
|
||||
public void DrawBack(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
float brightness = MathHelper.Clamp(1.1f + (cam.Position.Y - Size.Y) / 100000.0f, 0.1f, 1.0f);
|
||||
GameMain.LightManager.AmbientLight = new Color(backgroundColor * brightness, 1.0f);
|
||||
float brightness = MathHelper.Clamp(1.1f + (cam.Position.Y - Size.Y) / 100000.0f, 0.1f, 1.0f);
|
||||
var lightColorHLS = generationParams.AmbientLightColor.RgbToHLS();
|
||||
lightColorHLS.Y *= brightness;
|
||||
|
||||
graphics.Clear(backgroundColor);
|
||||
GameMain.LightManager.AmbientLight = ToolBox.HLSToRGB(lightColorHLS);
|
||||
|
||||
graphics.Clear(BackgroundColor);
|
||||
|
||||
if (renderer == null) return;
|
||||
renderer.DrawBackground(spriteBatch, cam, backgroundSpriteManager, backgroundCreatureManager);
|
||||
renderer.DrawBackground(spriteBatch, cam, levelObjectManager, backgroundCreatureManager);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
{
|
||||
if (GameMain.Server != null) return;
|
||||
|
||||
foreach (LevelWall levelWall in extraWalls)
|
||||
{
|
||||
if (levelWall.Body.BodyType == BodyType.Static) continue;
|
||||
|
||||
Vector2 bodyPos = new Vector2(
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
|
||||
levelWall.MoveState = msg.ReadRangedSingle(0.0f, MathHelper.TwoPi, 16);
|
||||
|
||||
if (Vector2.DistanceSquared(bodyPos, levelWall.Body.Position) > 0.5f)
|
||||
{
|
||||
levelWall.Body.SetTransform(bodyPos, levelWall.Body.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
using Barotrauma.Lights;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.SpriteDeformations;
|
||||
using Lidgren.Network;
|
||||
using System.Linq;
|
||||
using FarseerPhysics.Dynamics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelObject
|
||||
{
|
||||
public float SwingTimer;
|
||||
public float ScaleOscillateTimer;
|
||||
|
||||
public float CurrentSwingAmount;
|
||||
public Vector2 CurrentScaleOscillation;
|
||||
|
||||
public float CurrentRotation;
|
||||
|
||||
private List<SpriteDeformation> spriteDeformations = new List<SpriteDeformation>();
|
||||
|
||||
public Vector2 CurrentScale
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = Vector2.One;
|
||||
|
||||
public LightSource[] LightSources
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public LevelTrigger[] LightSourceTriggers
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ParticleEmitter[] ParticleEmitters
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public LevelTrigger[] ParticleEmitterTriggers
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public RoundSound[] Sounds
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public SoundChannel[] SoundChannels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public LevelTrigger[] SoundTriggers
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Vector2[,] CurrentSpriteDeformation
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
CurrentSwingAmount = Prefab.SwingAmountRad;
|
||||
CurrentScaleOscillation = Prefab.ScaleOscillation;
|
||||
|
||||
SwingTimer = Rand.Range(0.0f, MathHelper.TwoPi);
|
||||
ScaleOscillateTimer = Rand.Range(0.0f, MathHelper.TwoPi);
|
||||
|
||||
if (Prefab.ParticleEmitterPrefabs != null)
|
||||
{
|
||||
ParticleEmitters = new ParticleEmitter[Prefab.ParticleEmitterPrefabs.Count];
|
||||
ParticleEmitterTriggers = new LevelTrigger[Prefab.ParticleEmitterPrefabs.Count];
|
||||
for (int i = 0; i < Prefab.ParticleEmitterPrefabs.Count; i++)
|
||||
{
|
||||
ParticleEmitters[i] = new ParticleEmitter(Prefab.ParticleEmitterPrefabs[i]);
|
||||
ParticleEmitterTriggers[i] = Prefab.ParticleEmitterTriggerIndex[i] > -1 ?
|
||||
Triggers[Prefab.ParticleEmitterTriggerIndex[i]] : null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Prefab.LightSourceParams != null)
|
||||
{
|
||||
LightSources = new LightSource[Prefab.LightSourceParams.Count];
|
||||
LightSourceTriggers = new LevelTrigger[Prefab.LightSourceParams.Count];
|
||||
for (int i = 0; i < Prefab.LightSourceParams.Count; i++)
|
||||
{
|
||||
LightSources[i] = new LightSource(Prefab.LightSourceParams[i])
|
||||
{
|
||||
Position = new Vector2(Position.X, Position.Y),
|
||||
IsBackground = true
|
||||
};
|
||||
LightSourceTriggers[i] = Prefab.LightSourceTriggerIndex[i] > -1 ?
|
||||
Triggers[Prefab.LightSourceTriggerIndex[i]] : null;
|
||||
}
|
||||
}
|
||||
|
||||
Sounds = new RoundSound[Prefab.Sounds.Count];
|
||||
SoundChannels = new SoundChannel[Prefab.Sounds.Count];
|
||||
SoundTriggers = new LevelTrigger[Prefab.Sounds.Count];
|
||||
for (int i = 0; i < Prefab.Sounds.Count; i++)
|
||||
{
|
||||
Sounds[i] = Submarine.LoadRoundSound(Prefab.Sounds[i].SoundElement, false);
|
||||
SoundTriggers[i] = Prefab.Sounds[i].TriggerIndex > -1 ? Triggers[Prefab.Sounds[i].TriggerIndex] : null;
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
foreach (XElement subElement in Prefab.Config.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "deformablesprite") continue;
|
||||
foreach (XElement animationElement in subElement.Elements())
|
||||
{
|
||||
var newDeformation = SpriteDeformation.Load(animationElement, Prefab.Name);
|
||||
if (newDeformation != null)
|
||||
{
|
||||
newDeformation.DeformationParams = Prefab.SpriteDeformations[j].DeformationParams;
|
||||
spriteDeformations.Add(newDeformation);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (ParticleEmitters != null)
|
||||
{
|
||||
for (int i = 0; i < ParticleEmitters.Length; i++)
|
||||
{
|
||||
if (ParticleEmitterTriggers[i] != null && !ParticleEmitterTriggers[i].IsTriggered) continue;
|
||||
Vector2 emitterPos = LocalToWorld(Prefab.EmitterPositions[i]);
|
||||
ParticleEmitters[i].Emit(deltaTime, emitterPos, hullGuess: null,
|
||||
angle: ParticleEmitters[i].Prefab.CopyEntityAngle ? Rotation : 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentRotation = Rotation;
|
||||
if (ActivePrefab.SwingFrequency > 0.0f)
|
||||
{
|
||||
SwingTimer += deltaTime * ActivePrefab.SwingFrequency;
|
||||
SwingTimer = SwingTimer % MathHelper.TwoPi;
|
||||
//lerp the swing amount to the correct value to prevent it from abruptly changing to a different value
|
||||
//when a trigger changes the swing amoung
|
||||
CurrentSwingAmount = MathHelper.Lerp(CurrentSwingAmount, ActivePrefab.SwingAmountRad, deltaTime * 10.0f);
|
||||
|
||||
if (ActivePrefab.SwingAmountRad > 0.0f)
|
||||
{
|
||||
CurrentRotation += (float)Math.Sin(SwingTimer) * CurrentSwingAmount;
|
||||
}
|
||||
}
|
||||
|
||||
CurrentScale = Vector2.One * Scale;
|
||||
if (ActivePrefab.ScaleOscillationFrequency > 0.0f)
|
||||
{
|
||||
ScaleOscillateTimer += deltaTime * ActivePrefab.ScaleOscillationFrequency;
|
||||
ScaleOscillateTimer = ScaleOscillateTimer % MathHelper.TwoPi;
|
||||
CurrentScaleOscillation = Vector2.Lerp(CurrentScaleOscillation, ActivePrefab.ScaleOscillation, deltaTime * 10.0f);
|
||||
|
||||
float sin = (float)Math.Sin(ScaleOscillateTimer);
|
||||
CurrentScale *= new Vector2(
|
||||
1.0f + sin * CurrentScaleOscillation.X,
|
||||
1.0f + sin * CurrentScaleOscillation.Y);
|
||||
}
|
||||
|
||||
if (LightSources != null)
|
||||
{
|
||||
for (int i = 0; i < LightSources.Length; i++)
|
||||
{
|
||||
if (LightSourceTriggers[i] != null) LightSources[i].Enabled = LightSourceTriggers[i].IsTriggered;
|
||||
LightSources[i].Rotation = -CurrentRotation;
|
||||
LightSources[i].SpriteScale = CurrentScale;
|
||||
}
|
||||
}
|
||||
|
||||
if (spriteDeformations.Count > 0)
|
||||
{
|
||||
UpdateDeformations(deltaTime);
|
||||
}
|
||||
|
||||
for (int i = 0; i < Sounds.Length; i++)
|
||||
{
|
||||
if (SoundTriggers[i] == null || SoundTriggers[i].IsTriggered)
|
||||
{
|
||||
RoundSound roundSound = Sounds[i];
|
||||
Vector2 soundPos = LocalToWorld(new Vector2(Prefab.Sounds[i].Position.X, Prefab.Sounds[i].Position.Y));
|
||||
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), soundPos) <
|
||||
roundSound.Range * roundSound.Range)
|
||||
{
|
||||
if (SoundChannels[i] == null || !SoundChannels[i].IsPlaying)
|
||||
{
|
||||
SoundChannels[i] = roundSound.Sound.Play(roundSound.Volume, roundSound.Range, soundPos);
|
||||
}
|
||||
SoundChannels[i].Position = new Vector3(soundPos.X, soundPos.Y, 0.0f);
|
||||
}
|
||||
}
|
||||
else if (SoundChannels[i] != null && SoundChannels[i].IsPlaying)
|
||||
{
|
||||
SoundChannels[i].Dispose();
|
||||
SoundChannels[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDeformations(float deltaTime)
|
||||
{
|
||||
foreach (SpriteDeformation deformation in spriteDeformations)
|
||||
{
|
||||
if (deformation is PositionalDeformation positionalDeformation)
|
||||
{
|
||||
UpdatePositionalDeformation(positionalDeformation, deltaTime);
|
||||
}
|
||||
deformation.Update(deltaTime);
|
||||
}
|
||||
CurrentSpriteDeformation = SpriteDeformation.GetDeformation(spriteDeformations, ActivePrefab.DeformableSprite.Size);
|
||||
foreach (LightSource lightSource in LightSources)
|
||||
{
|
||||
if (lightSource?.DeformableLightSprite != null)
|
||||
{
|
||||
lightSource.DeformableLightSprite.Deform(CurrentSpriteDeformation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePositionalDeformation(PositionalDeformation positionalDeformation, float deltaTime)
|
||||
{
|
||||
Matrix matrix = ActivePrefab.DeformableSprite.GetTransform(
|
||||
Position,
|
||||
ActivePrefab.DeformableSprite.Origin,
|
||||
CurrentRotation,
|
||||
Vector2.One * Scale);
|
||||
|
||||
Matrix rotationMatrix = Matrix.CreateRotationZ(CurrentRotation);
|
||||
|
||||
foreach (LevelTrigger trigger in Triggers)
|
||||
{
|
||||
foreach (Entity triggerer in trigger.Triggerers)
|
||||
{
|
||||
Vector2 moveAmount = triggerer.WorldPosition - trigger.TriggererPosition[triggerer];
|
||||
|
||||
moveAmount = Vector2.Transform(moveAmount, rotationMatrix);
|
||||
moveAmount /= (ActivePrefab.DeformableSprite.Size * Scale);
|
||||
moveAmount.Y = -moveAmount.Y;
|
||||
|
||||
positionalDeformation.Deform(trigger.WorldPosition, moveAmount, deltaTime, Matrix.Invert(matrix) *
|
||||
Matrix.CreateScale(1.0f / ActivePrefab.DeformableSprite.Size.X, 1.0f / ActivePrefab.DeformableSprite.Size.Y, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(NetBuffer msg)
|
||||
{
|
||||
for (int i = 0; i < Triggers.Count; i++)
|
||||
{
|
||||
if (!Triggers[i].UseNetworkSyncing) continue;
|
||||
Triggers[i].ClientRead(msg);
|
||||
}
|
||||
}
|
||||
|
||||
partial void RemoveProjSpecific()
|
||||
{
|
||||
for (int i = 0; i < Sounds.Length; i++)
|
||||
{
|
||||
SoundChannels[i]?.Dispose();
|
||||
SoundChannels[i] = null;
|
||||
}
|
||||
if (LightSources != null)
|
||||
{
|
||||
for (int i = 0; i < LightSources.Length; i++)
|
||||
{
|
||||
LightSources[i].Remove();
|
||||
}
|
||||
LightSources = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelObjectManager
|
||||
{
|
||||
private List<LevelObject> visibleObjectsBack = new List<LevelObject>();
|
||||
private List<LevelObject> visibleObjectsFront = new List<LevelObject>();
|
||||
|
||||
private Rectangle currentGridIndices;
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
foreach (LevelObject obj in visibleObjectsBack)
|
||||
{
|
||||
obj.Update(deltaTime);
|
||||
}
|
||||
foreach (LevelObject obj in visibleObjectsFront)
|
||||
{
|
||||
obj.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<LevelObject> GetVisibleObjects()
|
||||
{
|
||||
return visibleObjectsBack.Union(visibleObjectsFront);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks which level objects are in camera view and adds them to the visibleObjects lists
|
||||
/// </summary>
|
||||
private void RefreshVisibleObjects(Rectangle currentIndices)
|
||||
{
|
||||
visibleObjectsBack.Clear();
|
||||
visibleObjectsFront.Clear();
|
||||
|
||||
for (int x = currentIndices.X; x <= currentIndices.Width; x++)
|
||||
{
|
||||
for (int y = currentIndices.Y; y <= currentIndices.Height; y++)
|
||||
{
|
||||
if (objectGrid[x, y] == null) continue;
|
||||
foreach (LevelObject obj in objectGrid[x, y])
|
||||
{
|
||||
var objectList = obj.Position.Z >= 0 ? visibleObjectsBack : visibleObjectsFront;
|
||||
int drawOrderIndex = 0;
|
||||
for (int i = 0; i < objectList.Count; i++)
|
||||
{
|
||||
if (objectList[i] == obj)
|
||||
{
|
||||
drawOrderIndex = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (objectList[i].Position.Z < obj.Position.Z)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawOrderIndex = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (drawOrderIndex >= 0)
|
||||
{
|
||||
objectList.Insert(drawOrderIndex, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentGridIndices = currentIndices;
|
||||
}
|
||||
|
||||
|
||||
public void DrawObjects(SpriteBatch spriteBatch, Camera cam, bool drawFront, bool specular = false)
|
||||
{
|
||||
Rectangle indices = Rectangle.Empty;
|
||||
indices.X = (int)Math.Floor(cam.WorldView.X / (float)GridSize);
|
||||
if (indices.X >= objectGrid.GetLength(0)) return;
|
||||
indices.Y = (int)Math.Floor((cam.WorldView.Y - cam.WorldView.Height - Level.Loaded.BottomPos) / (float)GridSize);
|
||||
if (indices.Y >= objectGrid.GetLength(1)) return;
|
||||
|
||||
indices.Width = (int)Math.Floor(cam.WorldView.Right / (float)GridSize) + 1;
|
||||
if (indices.Width < 0) return;
|
||||
indices.Height = (int)Math.Floor((cam.WorldView.Y - Level.Loaded.BottomPos) / (float)GridSize) + 1;
|
||||
if (indices.Height < 0) return;
|
||||
|
||||
indices.X = Math.Max(indices.X, 0);
|
||||
indices.Y = Math.Max(indices.Y, 0);
|
||||
indices.Width = Math.Min(indices.Width, objectGrid.GetLength(0) - 1);
|
||||
indices.Height = Math.Min(indices.Height, objectGrid.GetLength(1) - 1);
|
||||
|
||||
float z = 0.0f;
|
||||
if (currentGridIndices != indices)
|
||||
{
|
||||
RefreshVisibleObjects(indices);
|
||||
}
|
||||
|
||||
var objectList = drawFront ? visibleObjectsFront : visibleObjectsBack;
|
||||
foreach (LevelObject obj in objectList)
|
||||
{
|
||||
Vector2 camDiff = new Vector2(obj.Position.X, obj.Position.Y) - cam.WorldViewCenter;
|
||||
camDiff.Y = -camDiff.Y;
|
||||
|
||||
Sprite activeSprite = specular ? obj.ActivePrefab.SpecularSprite : obj.ActivePrefab.Sprite;
|
||||
activeSprite?.Draw(
|
||||
spriteBatch,
|
||||
new Vector2(obj.Position.X, -obj.Position.Y) - camDiff * obj.Position.Z / 10000.0f,
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundTextureColor, obj.Position.Z / 5000.0f),
|
||||
activeSprite.Origin,
|
||||
obj.CurrentRotation,
|
||||
obj.CurrentScale,
|
||||
SpriteEffects.None,
|
||||
z);
|
||||
|
||||
if (specular) continue;
|
||||
|
||||
if (obj.ActivePrefab.DeformableSprite != null)
|
||||
{
|
||||
if (obj.CurrentSpriteDeformation != null)
|
||||
{
|
||||
obj.ActivePrefab.DeformableSprite.Deform(obj.CurrentSpriteDeformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.ActivePrefab.DeformableSprite.Reset();
|
||||
}
|
||||
obj.ActivePrefab.DeformableSprite?.Draw(cam,
|
||||
new Vector3(new Vector2(obj.Position.X, obj.Position.Y) - camDiff * obj.Position.Z / 10000.0f, z * 10.0f),
|
||||
obj.ActivePrefab.DeformableSprite.Origin,
|
||||
obj.CurrentRotation,
|
||||
obj.CurrentScale,
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundTextureColor, obj.Position.Z / 5000.0f));
|
||||
}
|
||||
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(obj.Position.X, -obj.Position.Y), new Vector2(10.0f, 10.0f), Color.Red, true);
|
||||
|
||||
foreach (LevelTrigger trigger in obj.Triggers)
|
||||
{
|
||||
if (trigger.PhysicsBody == null) continue;
|
||||
GUI.DrawLine(spriteBatch, new Vector2(obj.Position.X, -obj.Position.Y), new Vector2(trigger.WorldPosition.X, -trigger.WorldPosition.Y), Color.Cyan, 0, 3);
|
||||
|
||||
Vector2 flowForce = trigger.GetWaterFlowVelocity();
|
||||
if (flowForce.LengthSquared() > 1)
|
||||
{
|
||||
flowForce.Y = -flowForce.Y;
|
||||
GUI.DrawLine(spriteBatch, new Vector2(trigger.WorldPosition.X, -trigger.WorldPosition.Y), new Vector2(trigger.WorldPosition.X, -trigger.WorldPosition.Y) + flowForce * 10, Color.Orange, 0, 5);
|
||||
}
|
||||
trigger.PhysicsBody.UpdateDrawPosition();
|
||||
trigger.PhysicsBody.DebugDraw(spriteBatch, trigger.IsTriggered ? Color.Cyan : Color.DarkCyan);
|
||||
}
|
||||
}
|
||||
|
||||
z += 0.0001f;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
{
|
||||
int objIndex = msg.ReadRangedInteger(0, objects.Count);
|
||||
objects[objIndex].ClientRead(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
using Barotrauma.Lights;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.SpriteDeformations;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelObjectPrefab
|
||||
{
|
||||
public class SoundConfig
|
||||
{
|
||||
public readonly XElement SoundElement;
|
||||
public readonly Vector2 Position;
|
||||
public readonly int TriggerIndex;
|
||||
|
||||
public SoundConfig(XElement element, int triggerIndex)
|
||||
{
|
||||
SoundElement = element;
|
||||
Position = element.GetAttributeVector2("position", Vector2.Zero);
|
||||
TriggerIndex = triggerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public List<int> ParticleEmitterTriggerIndex
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public List<ParticleEmitterPrefab> ParticleEmitterPrefabs
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public List<Vector2> EmitterPositions
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public List<SoundConfig> Sounds
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<SoundConfig>();
|
||||
|
||||
public List<int> LightSourceTriggerIndex
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<int>();
|
||||
public List<LightSourceParams> LightSourceParams
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<Lights.LightSourceParams>();
|
||||
|
||||
/// <summary>
|
||||
/// Only used for editing sprite deformation parameters. The actual LevelObjects use separate SpriteDeformation instances.
|
||||
/// </summary>
|
||||
public List<SpriteDeformation> SpriteDeformations
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<SpriteDeformation>();
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
LoadElementsProjSpecific(element, -1);
|
||||
}
|
||||
|
||||
private void LoadElementsProjSpecific(XElement element, int parentTriggerIndex)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "leveltrigger":
|
||||
case "trigger":
|
||||
LoadElementsProjSpecific(subElement, LevelTriggerElements.IndexOf(subElement));
|
||||
break;
|
||||
case "lightsource":
|
||||
LightSourceTriggerIndex.Add(parentTriggerIndex);
|
||||
LightSourceParams.Add(new LightSourceParams(subElement));
|
||||
break;
|
||||
case "particleemitter":
|
||||
if (ParticleEmitterPrefabs == null)
|
||||
{
|
||||
ParticleEmitterPrefabs = new List<ParticleEmitterPrefab>();
|
||||
EmitterPositions = new List<Vector2>();
|
||||
ParticleEmitterTriggerIndex = new List<int>();
|
||||
}
|
||||
|
||||
ParticleEmitterPrefabs.Add(new ParticleEmitterPrefab(subElement));
|
||||
ParticleEmitterTriggerIndex.Add(parentTriggerIndex);
|
||||
EmitterPositions.Add(subElement.GetAttributeVector2("position", Vector2.Zero));
|
||||
break;
|
||||
case "sound":
|
||||
Sounds.Add(new SoundConfig(subElement, parentTriggerIndex));
|
||||
break;
|
||||
case "deformablesprite":
|
||||
foreach (XElement deformElement in subElement.Elements())
|
||||
{
|
||||
var deformation = SpriteDeformation.Load(deformElement, Name);
|
||||
if (deformation != null)
|
||||
{
|
||||
SpriteDeformations.Add(deformation);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(XElement element)
|
||||
{
|
||||
this.Config = element;
|
||||
|
||||
SerializableProperty.SerializeProperties(this, element);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "childobject":
|
||||
case "lightsource":
|
||||
subElement.Remove();
|
||||
break;
|
||||
case "deformablesprite":
|
||||
subElement.RemoveNodes();
|
||||
foreach (SpriteDeformation deformation in SpriteDeformations)
|
||||
{
|
||||
var deformationElement = new XElement("SpriteDeformation");
|
||||
deformation.Save(deformationElement);
|
||||
subElement.Add(deformationElement);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (LightSourceParams lightSourceParams in LightSourceParams)
|
||||
{
|
||||
var lightElement = new XElement("LightSource");
|
||||
SerializableProperty.SerializeProperties(lightSourceParams, lightElement);
|
||||
element.Add(lightElement);
|
||||
}
|
||||
|
||||
foreach (ChildObject childObj in ChildObjects)
|
||||
{
|
||||
element.Add(new XElement("ChildObject",
|
||||
new XAttribute("names", string.Join(", ", childObj.AllowedNames)),
|
||||
new XAttribute("mincount", childObj.MinCount),
|
||||
new XAttribute("maxcount", childObj.MaxCount)));
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, float> overrideCommonness in OverrideCommonness)
|
||||
{
|
||||
bool elementFound = false;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() == "overridecommonness"
|
||||
&& subElement.GetAttributeString("leveltype", "") == overrideCommonness.Key)
|
||||
{
|
||||
subElement.Attribute("commonness").Value = overrideCommonness.Value.ToString("G", CultureInfo.InvariantCulture);
|
||||
elementFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!elementFound)
|
||||
{
|
||||
element.Add(new XElement("overridecommonness",
|
||||
new XAttribute("leveltype", overrideCommonness.Key),
|
||||
new XAttribute("commonness", overrideCommonness.Value.ToString("G", CultureInfo.InvariantCulture))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelTrigger
|
||||
{
|
||||
public void ClientRead(NetBuffer msg)
|
||||
{
|
||||
if (ForceFluctuationStrength > 0.0f)
|
||||
{
|
||||
currentForceFluctuation = msg.ReadRangedSingle(0.0f, 1.0f, 8);
|
||||
}
|
||||
if (stayTriggeredDelay > 0.0f)
|
||||
{
|
||||
triggeredTimer = msg.ReadRangedSingle(0.0f, stayTriggeredDelay, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -10,41 +11,21 @@ namespace Barotrauma
|
||||
{
|
||||
private static BasicEffect wallEdgeEffect, wallCenterEffect;
|
||||
|
||||
private static Sprite background, backgroundTop;
|
||||
private static Sprite dustParticles;
|
||||
private static Texture2D shaftTexture;
|
||||
private Vector2 dustOffset;
|
||||
private Vector2 defaultDustVelocity;
|
||||
private Vector2 dustVelocity;
|
||||
|
||||
Vector2 dustOffset;
|
||||
private RasterizerState cullNone;
|
||||
|
||||
private Level level;
|
||||
|
||||
private VertexBuffer wallVertices, bodyVertices;
|
||||
|
||||
public static Sprite Background
|
||||
{
|
||||
get
|
||||
{
|
||||
if (background == null) background = new Sprite("Content/Map/background2.png", Vector2.Zero);
|
||||
return background;
|
||||
}
|
||||
}
|
||||
|
||||
public static Sprite BackgroundTop
|
||||
{
|
||||
get
|
||||
{
|
||||
if (backgroundTop == null) backgroundTop = new Sprite("Content/Map/background.png", Vector2.Zero);
|
||||
return backgroundTop;
|
||||
}
|
||||
}
|
||||
|
||||
public LevelRenderer(Level level)
|
||||
{
|
||||
if (shaftTexture == null) shaftTexture = TextureLoader.FromFile("Content/Map/iceWall.png");
|
||||
defaultDustVelocity = Vector2.UnitY * 10.0f;
|
||||
|
||||
if (background == null) background = new Sprite("Content/Map/background2.png", Vector2.Zero);
|
||||
if (backgroundTop == null) backgroundTop = new Sprite("Content/Map/background.png", Vector2.Zero);
|
||||
if (dustParticles == null) dustParticles = new Sprite("Content/Map/dustparticles.png", Vector2.Zero);
|
||||
cullNone = new RasterizerState() { CullMode = CullMode.None };
|
||||
|
||||
if (wallEdgeEffect == null)
|
||||
{
|
||||
@@ -53,7 +34,7 @@ namespace Barotrauma
|
||||
DiffuseColor = new Vector3(0.8f, 0.8f, 0.8f),
|
||||
VertexColorEnabled = true,
|
||||
TextureEnabled = true,
|
||||
Texture = shaftTexture
|
||||
Texture = level.GenerationParams.WallEdgeSprite.Texture
|
||||
};
|
||||
wallEdgeEffect.CurrentTechnique = wallEdgeEffect.Techniques["BasicEffect_Texture"];
|
||||
}
|
||||
@@ -64,18 +45,56 @@ namespace Barotrauma
|
||||
{
|
||||
VertexColorEnabled = true,
|
||||
TextureEnabled = true,
|
||||
Texture = backgroundTop.Texture
|
||||
Texture = level.GenerationParams.WallSprite.Texture
|
||||
};
|
||||
wallCenterEffect.CurrentTechnique = wallCenterEffect.Techniques["BasicEffect_Texture"];
|
||||
}
|
||||
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
|
||||
public void ReloadTextures()
|
||||
{
|
||||
dustOffset -= Vector2.UnitY * 10.0f * deltaTime;
|
||||
while (dustOffset.Y <= -2048.0f) dustOffset.Y += 2048.0f;
|
||||
level.GenerationParams.WallEdgeSprite.ReloadTexture();
|
||||
wallEdgeEffect.Texture = level.GenerationParams.WallEdgeSprite.Texture;
|
||||
level.GenerationParams.WallSprite.ReloadTexture();
|
||||
wallCenterEffect.Texture = level.GenerationParams.WallSprite.Texture;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
//calculate the sum of the forces of nearby level triggers
|
||||
//and use it to move the dust texture and water distortion effect
|
||||
Vector2 currentDustVel = defaultDustVelocity;
|
||||
foreach (LevelObject levelObject in level.LevelObjectManager.GetVisibleObjects())
|
||||
{
|
||||
//use the largest water flow velocity of all the triggers
|
||||
Vector2 objectMaxFlow = Vector2.Zero;
|
||||
foreach (LevelTrigger trigger in levelObject.Triggers)
|
||||
{
|
||||
Vector2 vel = trigger.GetWaterFlowVelocity(cam.WorldViewCenter);
|
||||
if (vel.LengthSquared() > objectMaxFlow.LengthSquared())
|
||||
{
|
||||
objectMaxFlow = vel;
|
||||
}
|
||||
}
|
||||
currentDustVel += objectMaxFlow;
|
||||
}
|
||||
|
||||
dustVelocity = Vector2.Lerp(dustVelocity, currentDustVel, deltaTime);
|
||||
|
||||
WaterRenderer.Instance?.ScrollWater(dustVelocity, deltaTime);
|
||||
|
||||
if (level.GenerationParams.WaterParticles != null)
|
||||
{
|
||||
Vector2 waterTextureSize = level.GenerationParams.WaterParticles.size * level.GenerationParams.WaterParticleScale;
|
||||
dustOffset += new Vector2(dustVelocity.X, -dustVelocity.Y) * level.GenerationParams.WaterParticleScale * deltaTime;
|
||||
while (dustOffset.X <= -waterTextureSize.X) dustOffset.X += waterTextureSize.X;
|
||||
while (dustOffset.X >= waterTextureSize.X) dustOffset.X -= waterTextureSize.X;
|
||||
while (dustOffset.Y <= -waterTextureSize.Y) dustOffset.Y += waterTextureSize.Y;
|
||||
while (dustOffset.Y >= waterTextureSize.Y) dustOffset.Y -= waterTextureSize.Y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static VertexPositionColorTexture[] GetColoredVertices(VertexPositionTexture[] vertices, Color color)
|
||||
@@ -113,7 +132,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public void DrawBackground(SpriteBatch spriteBatch, Camera cam,
|
||||
BackgroundSpriteManager backgroundSpriteManager = null,
|
||||
LevelObjectManager backgroundSpriteManager = null,
|
||||
BackgroundCreatureManager backgroundCreatureManager = null)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap);
|
||||
@@ -123,21 +142,24 @@ namespace Barotrauma
|
||||
backgroundPos.Y = -backgroundPos.Y;
|
||||
backgroundPos *= 0.05f;
|
||||
|
||||
|
||||
if (backgroundPos.Y < 1024)
|
||||
{
|
||||
if (backgroundPos.Y < 0)
|
||||
if (backgroundPos.Y < 0 && level.GenerationParams.BackgroundTopSprite != null)
|
||||
{
|
||||
var backgroundTop = level.GenerationParams.BackgroundTopSprite;
|
||||
backgroundTop.SourceRect = new Rectangle((int)backgroundPos.X, (int)backgroundPos.Y, 1024, (int)Math.Min(-backgroundPos.Y, 1024));
|
||||
backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, Math.Min(-backgroundPos.Y, GameMain.GraphicsHeight)),
|
||||
color: level.BackgroundColor);
|
||||
color: level.BackgroundTextureColor);
|
||||
}
|
||||
if (backgroundPos.Y > -1024)
|
||||
if (backgroundPos.Y > -1024 && level.GenerationParams.BackgroundSprite != null)
|
||||
{
|
||||
var background = level.GenerationParams.BackgroundSprite;
|
||||
background.SourceRect = new Rectangle((int)backgroundPos.X, (int)Math.Max(backgroundPos.Y, 0), 1024, 1024);
|
||||
background.DrawTiled(spriteBatch,
|
||||
(backgroundPos.Y < 0) ? new Vector2(0.0f, (int)-backgroundPos.Y) : Vector2.Zero,
|
||||
new Vector2(GameMain.GraphicsWidth, (int)Math.Ceiling(1024 - backgroundPos.Y)),
|
||||
color: level.BackgroundColor);
|
||||
color: level.BackgroundTextureColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,129 +167,151 @@ namespace Barotrauma
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred,
|
||||
BlendState.AlphaBlend,
|
||||
SamplerState.LinearWrap, DepthStencilState.Default, null, null,
|
||||
cam.Transform);
|
||||
|
||||
SamplerState.LinearWrap, DepthStencilState.DepthRead, null, null,
|
||||
cam.Transform);
|
||||
|
||||
if (backgroundSpriteManager != null) backgroundSpriteManager.DrawSprites(spriteBatch, cam);
|
||||
if (backgroundCreatureManager != null) backgroundCreatureManager.Draw(spriteBatch);
|
||||
if (backgroundSpriteManager != null) backgroundSpriteManager.DrawObjects(spriteBatch, cam, drawFront: false);
|
||||
if (backgroundCreatureManager != null) backgroundCreatureManager.Draw(spriteBatch, cam);
|
||||
|
||||
Rectangle srcRect = new Rectangle(0, 0, 2048, 2048);
|
||||
Vector2 origin = new Vector2(cam.WorldView.X, -cam.WorldView.Y);
|
||||
Vector2 offset = -origin + dustOffset;
|
||||
while (offset.X <= -srcRect.Width) offset.X += srcRect.Width;
|
||||
while (offset.X > 0.0f) offset.X -= srcRect.Width;
|
||||
while (offset.Y <= -srcRect.Height) offset.Y += srcRect.Height;
|
||||
while (offset.Y > 0.0f) offset.Y -= srcRect.Height;
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (level.GenerationParams.WaterParticles != null)
|
||||
{
|
||||
float scale = 1.0f - i * 0.2f;
|
||||
float recipScale = 1.0f / scale;
|
||||
float textureScale = level.GenerationParams.WaterParticleScale;
|
||||
|
||||
//alpha goes from 1.0 to 0.0 when scale is in the range of 0.5-0.25
|
||||
float alpha = (cam.Zoom * scale) < 0.5f ? (cam.Zoom * scale - 0.25f) * 40.0f : 1.0f;
|
||||
if (alpha <= 0.0f) continue;
|
||||
Rectangle srcRect = new Rectangle(0, 0, 2048, 2048);
|
||||
Vector2 origin = new Vector2(cam.WorldView.X, -cam.WorldView.Y);
|
||||
Vector2 offset = -origin + dustOffset;
|
||||
while (offset.X <= -srcRect.Width * textureScale) offset.X += srcRect.Width * textureScale;
|
||||
while (offset.X > 0.0f) offset.X -= srcRect.Width * textureScale;
|
||||
while (offset.Y <= -srcRect.Height * textureScale) offset.Y += srcRect.Height * textureScale;
|
||||
while (offset.Y > 0.0f) offset.Y -= srcRect.Height * textureScale;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float scale = (1.0f - i * 0.2f);
|
||||
|
||||
Vector2 offsetS = offset * scale + new Vector2(cam.WorldView.Width, cam.WorldView.Height) * (1.0f - scale) * 0.5f - new Vector2(256.0f * i);
|
||||
while (offsetS.X <= -srcRect.Width * scale) offsetS.X += srcRect.Width * scale;
|
||||
while (offsetS.X > 0.0f) offsetS.X -= srcRect.Width * scale;
|
||||
while (offsetS.Y <= -srcRect.Height * scale) offsetS.Y += srcRect.Height * scale;
|
||||
while (offsetS.Y > 0.0f) offsetS.Y -= srcRect.Height * scale;
|
||||
//alpha goes from 1.0 to 0.0 when scale is in the range of 0.1 - 0.05
|
||||
float alpha = (cam.Zoom * scale) < 0.1f ? (cam.Zoom * scale - 0.05f) * 20.0f : 1.0f;
|
||||
if (alpha <= 0.0f) continue;
|
||||
|
||||
dustParticles.DrawTiled(spriteBatch, origin + offsetS, new Vector2(cam.WorldView.Width - offsetS.X, cam.WorldView.Height - offsetS.Y),
|
||||
rect: srcRect, color: Color.White * alpha, textureScale: new Vector2(scale));
|
||||
Vector2 offsetS = offset * scale
|
||||
+ new Vector2(cam.WorldView.Width, cam.WorldView.Height) * (1.0f - scale) * 0.5f
|
||||
- new Vector2(256.0f * i);
|
||||
|
||||
float texScale = scale * textureScale;
|
||||
|
||||
while (offsetS.X <= -srcRect.Width * texScale) offsetS.X += srcRect.Width * texScale;
|
||||
while (offsetS.X > 0.0f) offsetS.X -= srcRect.Width * texScale;
|
||||
while (offsetS.Y <= -srcRect.Height * texScale) offsetS.Y += srcRect.Height * texScale;
|
||||
while (offsetS.Y > 0.0f) offsetS.Y -= srcRect.Height * texScale;
|
||||
|
||||
level.GenerationParams.WaterParticles.DrawTiled(
|
||||
spriteBatch, origin + offsetS,
|
||||
new Vector2(cam.WorldView.Width - offsetS.X, cam.WorldView.Height - offsetS.Y),
|
||||
rect: srcRect, color: Color.White * alpha, textureScale: new Vector2(texScale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
RenderWalls(GameMain.Instance.GraphicsDevice, cam);
|
||||
RenderWalls(GameMain.Instance.GraphicsDevice, cam, specular: false);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred,
|
||||
BlendState.AlphaBlend,
|
||||
SamplerState.LinearClamp, DepthStencilState.Default, null, null,
|
||||
cam.Transform);
|
||||
if (backgroundSpriteManager != null) backgroundSpriteManager.DrawObjects(spriteBatch, cam, drawFront: true);
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (GameMain.DebugDraw)
|
||||
if (GameMain.DebugDraw && cam.Zoom > 0.05f)
|
||||
{
|
||||
var cells = level.GetCells(GameMain.GameScreen.Cam.WorldViewCenter, 2);
|
||||
var cells = level.GetCells(cam.WorldViewCenter, 2);
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(cell.Center.X - 10.0f, -cell.Center.Y-10.0f), new Vector2(20.0f, 20.0f), Color.Cyan, true);
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(cell.Center.X - 10.0f, -cell.Center.Y - 10.0f), new Vector2(20.0f, 20.0f), Color.Cyan, true);
|
||||
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(cell.edges[0].point1.X, -cell.edges[0].point1.Y),
|
||||
new Vector2(cell.Center.X, -cell.Center.Y),
|
||||
Color.Blue*0.5f);
|
||||
|
||||
foreach (GraphEdge edge in cell.edges)
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(cell.Edges[0].Point1.X + cell.Translation.X, -(cell.Edges[0].Point1.Y + cell.Translation.Y)),
|
||||
new Vector2(cell.Center.X, -(cell.Center.Y)),
|
||||
Color.Blue * 0.5f);
|
||||
|
||||
foreach (GraphEdge edge in cell.Edges)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, new Vector2(edge.point1.X, -edge.point1.Y),
|
||||
new Vector2(edge.point2.X, -edge.point2.Y), cell.body==null ? Color.Cyan*0.5f : Color.White);
|
||||
GUI.DrawLine(spriteBatch, new Vector2(edge.Point1.X + cell.Translation.X, -(edge.Point1.Y + cell.Translation.Y)),
|
||||
new Vector2(edge.Point2.X + cell.Translation.X, -(edge.Point2.Y + cell.Translation.Y)), cell.Body == null ? Color.Cyan * 0.5f : Color.White);
|
||||
}
|
||||
|
||||
foreach (Vector2 point in cell.bodyVertices)
|
||||
foreach (Vector2 point in cell.BodyVertices)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(point.X, -point.Y), new Vector2(10.0f, 10.0f), Color.White, true);
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(point.X + cell.Translation.X, -(point.Y + cell.Translation.Y)), new Vector2(10.0f, 10.0f), Color.White, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (List<Vector2> nodeList in level.SmallTunnels)
|
||||
foreach (List<Point> nodeList in level.SmallTunnels)
|
||||
{
|
||||
for (int i = 1; i<nodeList.Count; i++)
|
||||
for (int i = 1; i < nodeList.Count; i++)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(nodeList[i-1].X, -nodeList[i - 1].Y),
|
||||
new Vector2(nodeList[i].X, -nodeList[i].Y),
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(nodeList[i - 1].X, -nodeList[i - 1].Y),
|
||||
new Vector2(nodeList[i].X, -nodeList[i].Y),
|
||||
Color.Lerp(Color.Yellow, Color.Red, i / (float)nodeList.Count), 0, 10);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var ruin in level.Ruins)
|
||||
{
|
||||
ruin.DebugDraw(spriteBatch);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 pos = new Vector2(0.0f, -level.Size.Y);
|
||||
|
||||
if (GameMain.GameScreen.Cam.WorldView.Y >= -pos.Y - 1024)
|
||||
if (cam.WorldView.Y >= -pos.Y - 1024)
|
||||
{
|
||||
pos.X = GameMain.GameScreen.Cam.WorldView.X -1024;
|
||||
int width = (int)(Math.Ceiling(GameMain.GameScreen.Cam.WorldView.Width / 1024 + 4.0f) * 1024);
|
||||
pos.X = cam.WorldView.X -1024;
|
||||
int width = (int)(Math.Ceiling(cam.WorldView.Width / 1024 + 4.0f) * 1024);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,new Rectangle(
|
||||
(int)(MathUtils.Round(pos.X, 1024)),
|
||||
-GameMain.GameScreen.Cam.WorldView.Y,
|
||||
-cam.WorldView.Y,
|
||||
width,
|
||||
(int)(GameMain.GameScreen.Cam.WorldView.Y + pos.Y) - 30),
|
||||
(int)(cam.WorldView.Y + pos.Y) - 30),
|
||||
Color.Black, true);
|
||||
|
||||
spriteBatch.Draw(shaftTexture,
|
||||
spriteBatch.Draw(level.GenerationParams.WallEdgeSprite.Texture,
|
||||
new Rectangle((int)(MathUtils.Round(pos.X, 1024)), (int)pos.Y-1000, width, 1024),
|
||||
new Rectangle(0, 0, width, -1024),
|
||||
level.BackgroundColor, 0.0f,
|
||||
level.BackgroundTextureColor, 0.0f,
|
||||
Vector2.Zero,
|
||||
SpriteEffects.None, 0.0f);
|
||||
}
|
||||
|
||||
if (GameMain.GameScreen.Cam.WorldView.Y - GameMain.GameScreen.Cam.WorldView.Height < level.SeaFloorTopPos + 1024)
|
||||
if (cam.WorldView.Y - cam.WorldView.Height < level.SeaFloorTopPos + 1024)
|
||||
{
|
||||
pos = new Vector2(GameMain.GameScreen.Cam.WorldView.X - 1024, -level.BottomPos);
|
||||
pos = new Vector2(cam.WorldView.X - 1024, -level.BottomPos);
|
||||
|
||||
int width = (int)(Math.Ceiling(GameMain.GameScreen.Cam.WorldView.Width / 1024 + 4.0f) * 1024);
|
||||
int width = (int)(Math.Ceiling(cam.WorldView.Width / 1024 + 4.0f) * 1024);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(
|
||||
(int)(MathUtils.Round(pos.X, 1024)),
|
||||
(int)-(level.BottomPos - 30),
|
||||
width,
|
||||
(int)(level.BottomPos - (GameMain.GameScreen.Cam.WorldView.Y - GameMain.GameScreen.Cam.WorldView.Height))),
|
||||
(int)(level.BottomPos - (cam.WorldView.Y - cam.WorldView.Height))),
|
||||
Color.Black, true);
|
||||
|
||||
spriteBatch.Draw(shaftTexture,
|
||||
spriteBatch.Draw(level.GenerationParams.WallEdgeSprite.Texture,
|
||||
new Rectangle((int)(MathUtils.Round(pos.X, 1024)), (int)-level.BottomPos, width, 1024),
|
||||
new Rectangle(0, 0, width, -1024),
|
||||
level.BackgroundColor, 0.0f,
|
||||
level.BackgroundTextureColor, 0.0f,
|
||||
Vector2.Zero,
|
||||
SpriteEffects.FlipVertically, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RenderWalls(GraphicsDevice graphicsDevice, Camera cam)
|
||||
public void RenderWalls(GraphicsDevice graphicsDevice, Camera cam, bool specular)
|
||||
{
|
||||
if (wallVertices == null) return;
|
||||
|
||||
@@ -276,9 +320,11 @@ namespace Barotrauma
|
||||
|
||||
if (!renderLevel && !renderSeaFloor) return;
|
||||
|
||||
wallEdgeEffect.World = cam.ShaderTransform
|
||||
Matrix transformMatrix = cam.ShaderTransform
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 100) * 0.5f;
|
||||
wallCenterEffect.World = wallEdgeEffect.World;
|
||||
|
||||
wallEdgeEffect.World = transformMatrix;
|
||||
wallCenterEffect.World = transformMatrix;
|
||||
|
||||
graphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
|
||||
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
@@ -288,15 +334,19 @@ namespace Barotrauma
|
||||
graphicsDevice.SetVertexBuffer(bodyVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(bodyVertices.VertexCount / 3.0f));
|
||||
}
|
||||
if (renderSeaFloor)
|
||||
|
||||
foreach (LevelWall wall in level.ExtraWalls)
|
||||
{
|
||||
foreach (LevelWall wall in level.ExtraWalls)
|
||||
{
|
||||
graphicsDevice.SetVertexBuffer(wall.BodyVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.BodyVertices.VertexCount / 3.0f));
|
||||
}
|
||||
if (!renderSeaFloor && wall == level.SeaFloor) continue;
|
||||
wallCenterEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.BodyVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.BodyVertices.VertexCount / 3.0f));
|
||||
}
|
||||
|
||||
var defaultRasterizerState = graphicsDevice.RasterizerState;
|
||||
graphicsDevice.RasterizerState = cullNone;
|
||||
wallEdgeEffect.World = transformMatrix;
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
if (renderLevel)
|
||||
@@ -305,28 +355,27 @@ namespace Barotrauma
|
||||
graphicsDevice.SetVertexBuffer(wallVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wallVertices.VertexCount / 3.0f));
|
||||
}
|
||||
if (renderSeaFloor)
|
||||
foreach (LevelWall wall in level.ExtraWalls)
|
||||
{
|
||||
foreach (LevelWall wall in level.ExtraWalls)
|
||||
{
|
||||
graphicsDevice.SetVertexBuffer(wall.WallVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallVertices.VertexCount / 3.0f));
|
||||
}
|
||||
}
|
||||
if (!renderSeaFloor && wall == level.SeaFloor) continue;
|
||||
wallEdgeEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.WallVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallVertices.VertexCount / 3.0f));
|
||||
}
|
||||
graphicsDevice.RasterizerState = defaultRasterizerState;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (wallVertices!=null) wallVertices.Dispose();
|
||||
if (wallVertices != null) wallVertices.Dispose();
|
||||
if (bodyVertices != null) bodyVertices.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
@@ -18,6 +19,14 @@ namespace Barotrauma
|
||||
get { return bodyVertices; }
|
||||
}
|
||||
|
||||
public Matrix GetTransform()
|
||||
{
|
||||
return body.BodyType == FarseerPhysics.Dynamics.BodyType.Static ?
|
||||
Matrix.Identity :
|
||||
Matrix.CreateRotationZ(body.Rotation) *
|
||||
Matrix.CreateTranslation(new Vector3(ConvertUnits.ToDisplayUnits(body.Position), 0.0f));
|
||||
}
|
||||
|
||||
public void SetWallVertices(VertexPositionTexture[] vertices, Color color)
|
||||
{
|
||||
wallVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
|
||||
@@ -5,18 +5,12 @@ namespace Barotrauma.RuinGeneration
|
||||
{
|
||||
partial class Ruin
|
||||
{
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
public void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
//foreach (BTRoom room in leaves)
|
||||
//{
|
||||
// GUI.DrawRectangle(spriteBatch, room.Rect, Color.White);
|
||||
//}
|
||||
|
||||
//foreach (Corridor corr in corridors)
|
||||
//{
|
||||
// GUI.DrawRectangle(spriteBatch, corr.Rect, Color.Blue);
|
||||
//}
|
||||
|
||||
foreach (RuinShape shape in allShapes)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(shape.Center.X, -shape.Center.Y - 50), shape.DistanceFromEntrance.ToString(), Color.White, Color.Black * 0.5f, font: GUI.LargeFont);
|
||||
}
|
||||
foreach (Line line in walls)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, new Vector2(line.A.X, -line.A.Y), new Vector2(line.B.X, -line.B.Y), Color.Red, 0.0f, 10);
|
||||
|
||||
@@ -2,18 +2,58 @@ using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
struct WaterVertexData
|
||||
{
|
||||
float DistortStrengthX;
|
||||
float DistortStrengthY;
|
||||
float WaterAlpha;
|
||||
float WaterColorStrength;
|
||||
|
||||
public WaterVertexData(float distortStrengthX, float distortStrengthY, float waterAlpha, float waterColorStrength)
|
||||
{
|
||||
DistortStrengthX = distortStrengthX;
|
||||
DistortStrengthY = distortStrengthY;
|
||||
WaterAlpha = waterAlpha;
|
||||
WaterColorStrength = waterColorStrength;
|
||||
}
|
||||
|
||||
public static implicit operator Color(WaterVertexData wd)
|
||||
{
|
||||
return new Color(wd.DistortStrengthX, wd.DistortStrengthY, wd.WaterAlpha, wd.WaterColorStrength);
|
||||
}
|
||||
}
|
||||
|
||||
class WaterRenderer : IDisposable
|
||||
{
|
||||
const int DefaultBufferSize = 1500;
|
||||
public static WaterRenderer Instance;
|
||||
|
||||
private Vector2 wavePos;
|
||||
public const int DefaultBufferSize = 2000;
|
||||
public const int DefaultIndoorsBufferSize = 3000;
|
||||
|
||||
public static Vector2 DistortionScale = new Vector2(0.5f, 0.5f);
|
||||
public static Vector2 DistortionStrength = new Vector2(0.5f, 0.5f);
|
||||
public static float BlurAmount = 0.0f;
|
||||
|
||||
public Vector2 WavePos
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public readonly Color waterColor = new Color(0.75f * 0.5f, 0.8f * 0.5f, 0.9f * 0.5f, 1.0f);
|
||||
|
||||
public readonly WaterVertexData IndoorsWaterColor = new WaterVertexData(0.1f, 0.1f, 0.5f, 1.0f);
|
||||
public readonly WaterVertexData IndoorsSurfaceTopColor = new WaterVertexData(0.5f, 0.5f, 0.0f, 1.0f);
|
||||
public readonly WaterVertexData IndoorsSurfaceBottomColor = new WaterVertexData(0.2f, 0.1f, 0.9f, 1.0f);
|
||||
|
||||
public VertexPositionTexture[] vertices = new VertexPositionTexture[DefaultBufferSize];
|
||||
public Dictionary<EntityGrid, VertexPositionColorTexture[]> IndoorsVertices = new Dictionary<EntityGrid, VertexPositionColorTexture[]>();// VertexPositionColorTexture[DefaultBufferSize * 2];
|
||||
|
||||
public Effect waterEffect
|
||||
public Effect WaterEffect
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
@@ -21,29 +61,23 @@ namespace Barotrauma
|
||||
private BasicEffect basicEffect;
|
||||
|
||||
public int PositionInBuffer = 0;
|
||||
public Dictionary<EntityGrid, int> PositionInIndoorsBuffer = new Dictionary<EntityGrid, int>();
|
||||
|
||||
private Texture2D waterTexture;
|
||||
|
||||
public Texture2D WaterTexture
|
||||
{
|
||||
get { return waterTexture; }
|
||||
}
|
||||
public Texture2D WaterTexture { get; }
|
||||
|
||||
public WaterRenderer(GraphicsDevice graphicsDevice, ContentManager content)
|
||||
{
|
||||
#if WINDOWS
|
||||
waterEffect = content.Load<Effect>("watershader");
|
||||
WaterEffect = content.Load<Effect>("Effects/watershader");
|
||||
#endif
|
||||
#if LINUX
|
||||
#if LINUX || OSX
|
||||
|
||||
waterEffect = content.Load<Effect>("watershader_opengl");
|
||||
WaterEffect = content.Load<Effect>("Effects/watershader_opengl");
|
||||
#endif
|
||||
|
||||
waterTexture = TextureLoader.FromFile("Content/waterbump.png");
|
||||
waterEffect.Parameters["xWaveWidth"].SetValue(0.05f);
|
||||
waterEffect.Parameters["xWaveHeight"].SetValue(0.05f);
|
||||
|
||||
waterEffect.Parameters["xWaterBumpMap"].SetValue(waterTexture);
|
||||
WaterTexture = TextureLoader.FromFile("Content/Effects/waterbump.png");
|
||||
WaterEffect.Parameters["xWaterBumpMap"].SetValue(WaterTexture);
|
||||
WaterEffect.Parameters["waterColor"].SetValue(waterColor.ToVector4());
|
||||
|
||||
if (basicEffect == null)
|
||||
{
|
||||
@@ -54,46 +88,122 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderBack(SpriteBatch spriteBatch, RenderTarget2D texture, float blurAmount = 0.0f)
|
||||
public void RenderWater(SpriteBatch spriteBatch, RenderTarget2D texture, Camera cam)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, SamplerState.LinearWrap, null, null, waterEffect);
|
||||
|
||||
waterEffect.CurrentTechnique = waterEffect.Techniques["WaterShader"];
|
||||
waterEffect.Parameters["xWavePos"].SetValue(wavePos);
|
||||
waterEffect.Parameters["xBlurDistance"].SetValue(blurAmount);
|
||||
//waterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
spriteBatch.GraphicsDevice.BlendState = BlendState.AlphaBlend;
|
||||
|
||||
//#if WINDOWS
|
||||
waterEffect.Parameters["xTexture"].SetValue(texture);
|
||||
spriteBatch.Draw(texture, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
//#elif LINUX
|
||||
WaterEffect.Parameters["xTexture"].SetValue(texture);
|
||||
Vector2 distortionStrength = cam == null ? DistortionStrength : DistortionStrength * cam.Zoom;
|
||||
WaterEffect.Parameters["xWaveWidth"].SetValue(DistortionStrength.X);
|
||||
WaterEffect.Parameters["xWaveHeight"].SetValue(DistortionStrength.Y);
|
||||
if (BlurAmount > 0.0f)
|
||||
{
|
||||
WaterEffect.CurrentTechnique = WaterEffect.Techniques["WaterShaderBlurred"];
|
||||
WaterEffect.Parameters["xBlurDistance"].SetValue(BlurAmount / 100.0f);
|
||||
}
|
||||
else
|
||||
{ WaterEffect.CurrentTechnique = WaterEffect.Techniques["WaterShader"];
|
||||
WaterEffect.Parameters["xBlurDistance"].SetValue(BlurAmount / 100.0f);
|
||||
}
|
||||
|
||||
// spriteBatch.Draw(texture, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
//#endif
|
||||
spriteBatch.End();
|
||||
Vector2 offset = WavePos;
|
||||
if (cam != null)
|
||||
{
|
||||
offset += (cam.Position - new Vector2(cam.WorldView.Width / 2.0f, -cam.WorldView.Height / 2.0f));
|
||||
offset.Y += cam.WorldView.Height;
|
||||
offset.X += cam.WorldView.Width;
|
||||
offset *= DistortionScale;
|
||||
}
|
||||
offset.Y = -offset.Y;
|
||||
WaterEffect.Parameters["xUvOffset"].SetValue(new Vector2((offset.X / GameMain.GraphicsWidth) % 1.0f, (offset.Y / GameMain.GraphicsHeight) % 1.0f));
|
||||
WaterEffect.Parameters["xBumpPos"].SetValue(Vector2.Zero);
|
||||
|
||||
if (cam != null)
|
||||
{
|
||||
WaterEffect.Parameters["xBumpScale"].SetValue(new Vector2(
|
||||
(float)cam.WorldView.Width / GameMain.GraphicsWidth * DistortionScale.X,
|
||||
(float)cam.WorldView.Height / GameMain.GraphicsHeight * DistortionScale.Y));
|
||||
WaterEffect.Parameters["xTransform"].SetValue(cam.ShaderTransform
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f);
|
||||
WaterEffect.Parameters["xUvTransform"].SetValue(cam.ShaderTransform
|
||||
* Matrix.CreateOrthographicOffCenter(0, spriteBatch.GraphicsDevice.Viewport.Width * 2, spriteBatch.GraphicsDevice.Viewport.Height * 2, 0, 0, 1) * Matrix.CreateTranslation(0.5f, 0.5f, 0.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
WaterEffect.Parameters["xBumpScale"].SetValue(new Vector2(1.0f, 1.0f));
|
||||
WaterEffect.Parameters["xTransform"].SetValue(Matrix.Identity * Matrix.CreateTranslation(-1.0f, 1.0f, 0.0f));
|
||||
WaterEffect.Parameters["xUvTransform"].SetValue(Matrix.CreateScale(0.5f, -0.5f, 0.0f));
|
||||
}
|
||||
|
||||
WaterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
VertexPositionColorTexture[] verts = new VertexPositionColorTexture[6];
|
||||
|
||||
Rectangle view = cam != null ? cam.WorldView : spriteBatch.GraphicsDevice.Viewport.Bounds;
|
||||
|
||||
var corners = new Vector3[4];
|
||||
corners[0] = new Vector3(view.X, view.Y, 0.1f);
|
||||
corners[1] = new Vector3(view.Right, view.Y, 0.1f);
|
||||
corners[2] = new Vector3(view.Right, view.Y - view.Height, 0.1f);
|
||||
corners[3] = new Vector3(view.X, view.Y - view.Height, 0.1f);
|
||||
|
||||
WaterVertexData backGroundColor = new WaterVertexData(0.1f, 0.1f, 0.5f, 0.1f);
|
||||
verts[0] = new VertexPositionColorTexture(corners[0], backGroundColor, Vector2.Zero);
|
||||
verts[1] = new VertexPositionColorTexture(corners[1], backGroundColor, Vector2.Zero);
|
||||
verts[2] = new VertexPositionColorTexture(corners[2], backGroundColor, Vector2.Zero);
|
||||
verts[3] = new VertexPositionColorTexture(corners[0], backGroundColor, Vector2.Zero);
|
||||
verts[4] = new VertexPositionColorTexture(corners[2], backGroundColor, Vector2.Zero);
|
||||
verts[5] = new VertexPositionColorTexture(corners[3], backGroundColor, Vector2.Zero);
|
||||
|
||||
spriteBatch.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, 2);
|
||||
|
||||
foreach (KeyValuePair<EntityGrid, VertexPositionColorTexture[]> subVerts in IndoorsVertices)
|
||||
{
|
||||
if (!PositionInIndoorsBuffer.ContainsKey(subVerts.Key) || PositionInIndoorsBuffer[subVerts.Key] == 0) continue;
|
||||
|
||||
offset = WavePos;
|
||||
if (subVerts.Key.Submarine != null) { offset -= subVerts.Key.Submarine.WorldPosition; }
|
||||
if (cam != null)
|
||||
{
|
||||
offset += cam.Position - new Vector2(cam.WorldView.Width / 2.0f, -cam.WorldView.Height / 2.0f);
|
||||
offset.Y += cam.WorldView.Height;
|
||||
offset.X += cam.WorldView.Width;
|
||||
offset *= DistortionScale;
|
||||
}
|
||||
offset.Y = -offset.Y;
|
||||
WaterEffect.Parameters["xUvOffset"].SetValue(new Vector2((offset.X / GameMain.GraphicsWidth) % 1.0f, (offset.Y / GameMain.GraphicsHeight) % 1.0f));
|
||||
|
||||
WaterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
spriteBatch.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, subVerts.Value, 0, PositionInIndoorsBuffer[subVerts.Key] / 3);
|
||||
}
|
||||
}
|
||||
|
||||
public void ScrollWater(float deltaTime)
|
||||
public void ScrollWater(Vector2 vel, float deltaTime)
|
||||
{
|
||||
wavePos.X += 0.006f * deltaTime;
|
||||
wavePos.Y += 0.006f * deltaTime;
|
||||
WavePos = WavePos - vel * deltaTime;
|
||||
}
|
||||
|
||||
public void Render(GraphicsDevice graphicsDevice, Camera cam, RenderTarget2D texture, Matrix transform)
|
||||
public void RenderAir(GraphicsDevice graphicsDevice, Camera cam, RenderTarget2D texture, Matrix transform)
|
||||
{
|
||||
if (vertices == null) return;
|
||||
if (vertices.Length < 0) return;
|
||||
if (vertices == null || vertices.Length < 0 || PositionInBuffer <= 0) return;
|
||||
|
||||
basicEffect.Texture = texture;
|
||||
|
||||
basicEffect.View = Matrix.Identity;
|
||||
basicEffect.World = transform
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
|
||||
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f * Matrix.CreateTranslation(0.0f,0.0f,0f);
|
||||
basicEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
graphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
|
||||
graphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3);
|
||||
graphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vertices, 0, PositionInBuffer / 3);
|
||||
}
|
||||
|
||||
public void ResetBuffers()
|
||||
{
|
||||
PositionInBuffer = 0;
|
||||
PositionInIndoorsBuffer.Clear();
|
||||
IndoorsVertices.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -106,10 +216,10 @@ namespace Barotrauma
|
||||
{
|
||||
if (!disposing) return;
|
||||
|
||||
if (waterEffect != null)
|
||||
if (WaterEffect != null)
|
||||
{
|
||||
waterEffect.Dispose();
|
||||
waterEffect = null;
|
||||
WaterEffect.Dispose();
|
||||
WaterEffect = null;
|
||||
}
|
||||
|
||||
if (basicEffect != null)
|
||||
|
||||
@@ -41,9 +41,17 @@ namespace Barotrauma.Lights
|
||||
public ConvexHull ConvexHull;
|
||||
|
||||
public bool IsHorizontal;
|
||||
public bool IsAxisAligned;
|
||||
|
||||
public Segment(SegmentPoint start, SegmentPoint end, ConvexHull convexHull)
|
||||
{
|
||||
if (start.Pos.Y > end.Pos.Y)
|
||||
{
|
||||
var temp = start;
|
||||
start = end;
|
||||
end = temp;
|
||||
}
|
||||
|
||||
Start = start;
|
||||
End = end;
|
||||
ConvexHull = convexHull;
|
||||
@@ -52,6 +60,7 @@ namespace Barotrauma.Lights
|
||||
end.ConvexHull = convexHull;
|
||||
|
||||
IsHorizontal = Math.Abs(start.Pos.X - end.Pos.X) > Math.Abs(start.Pos.Y - end.Pos.Y);
|
||||
IsAxisAligned = Math.Abs(start.Pos.X - end.Pos.X) < 0.1f || Math.Abs(start.Pos.Y - end.Pos.Y) < 0.001f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,11 +160,12 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
if (penumbraEffect == null)
|
||||
{
|
||||
penumbraEffect = new BasicEffect(GameMain.Instance.GraphicsDevice);
|
||||
penumbraEffect.TextureEnabled = true;
|
||||
//shadowEffect.VertexColorEnabled = true;
|
||||
penumbraEffect.LightingEnabled = false;
|
||||
penumbraEffect.Texture = TextureLoader.FromFile("Content/Lights/penumbra.png");
|
||||
penumbraEffect = new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
{
|
||||
TextureEnabled = true,
|
||||
LightingEnabled = false,
|
||||
Texture = TextureLoader.FromFile("Content/Lights/penumbra.png")
|
||||
};
|
||||
}
|
||||
|
||||
parentEntity = parent;
|
||||
@@ -206,10 +216,23 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
ignoreEdge[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Rotate(Vector2 origin, float amount)
|
||||
{
|
||||
Matrix rotationMatrix = Matrix.CreateRotationZ(amount);
|
||||
|
||||
Vector2[] newVerts = new Vector2[vertices.Length];
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
newVerts[i] = Vector2.Transform(vertices[i].Pos - origin, rotationMatrix) + origin;
|
||||
}
|
||||
|
||||
SetVertices(newVerts);
|
||||
}
|
||||
|
||||
private void CalculateDimensions()
|
||||
{
|
||||
float minX = vertices[0].Pos.X, minY = vertices[0].Pos.Y, maxX = vertices[0].Pos.X, maxY = vertices[0].Pos.Y;
|
||||
@@ -332,10 +355,8 @@ namespace Barotrauma.Lights
|
||||
/// <summary>
|
||||
/// Returns the segments that are facing towards viewPosition
|
||||
/// </summary>
|
||||
public List<Segment> GetVisibleSegments(Vector2 viewPosition)
|
||||
{
|
||||
List<Segment> visibleFaces = new List<Segment>();
|
||||
|
||||
public void GetVisibleSegments(Vector2 viewPosition, List<Segment> visibleSegments)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (ignoreEdge[i]) continue;
|
||||
@@ -353,23 +374,26 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (Vector2.Dot(N, L) > 0)
|
||||
{
|
||||
visibleFaces.Add(segments[i]);
|
||||
visibleSegments.Add(segments[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return visibleFaces;
|
||||
}
|
||||
|
||||
|
||||
public void RefreshWorldPositions()
|
||||
{
|
||||
if (parentEntity == null || parentEntity.Submarine == null) return;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vertices[i].WorldPos = vertices[i].Pos + parentEntity.Submarine.DrawPosition;
|
||||
segments[i].Start.WorldPos = segments[i].Start.Pos + parentEntity.Submarine.DrawPosition;
|
||||
segments[i].End.WorldPos = segments[i].End.Pos + parentEntity.Submarine.DrawPosition;
|
||||
|
||||
vertices[i].WorldPos = vertices[i].Pos;
|
||||
segments[i].Start.WorldPos = segments[i].Start.Pos;
|
||||
segments[i].End.WorldPos = segments[i].End.Pos;
|
||||
}
|
||||
if (parentEntity == null || parentEntity.Submarine == null) { return; }
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vertices[i].WorldPos += parentEntity.Submarine.DrawPosition;
|
||||
segments[i].Start.WorldPos += parentEntity.Submarine.DrawPosition;
|
||||
segments[i].End.WorldPos += parentEntity.Submarine.DrawPosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma.Lights
|
||||
{
|
||||
@@ -11,6 +13,15 @@ namespace Barotrauma.Lights
|
||||
private const float AmbientLightUpdateInterval = 0.2f;
|
||||
private const float AmbientLightFalloff = 0.8f;
|
||||
|
||||
/// <summary>
|
||||
/// Enables a feature that makes lights inside the hull increase the brightness of the entire hull
|
||||
/// and adjacent ones to some extent, if there are gaps for the lights to pass through.
|
||||
/// Prevents unnaturally dark looking shadows in otherwise well-lit submarines, but disabled at least for
|
||||
/// the time being because it makes the lighting behave unpredictably and may cause rooms to appear
|
||||
/// excessively bright if different lighting conditions aren't tested and accounted for.
|
||||
/// </summary>
|
||||
private static bool UseHullSpecificAmbientLight = false;
|
||||
|
||||
private static Entity viewTarget;
|
||||
|
||||
public static Entity ViewTarget
|
||||
@@ -22,38 +33,44 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
private float currLightMapScale;
|
||||
|
||||
public Color AmbientLight;
|
||||
|
||||
private float lightmapScale = 0.5f;
|
||||
public RenderTarget2D lightMap
|
||||
public RenderTarget2D LightMap
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public RenderTarget2D losTexture
|
||||
public RenderTarget2D SpecularMap
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public RenderTarget2D LosTexture
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
BasicEffect lightEffect;
|
||||
private BasicEffect lightEffect;
|
||||
|
||||
public Effect LosEffect
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
private static Texture2D alphaClearTexture;
|
||||
|
||||
private List<LightSource> lights;
|
||||
|
||||
public bool LosEnabled = true;
|
||||
public LosMode LosMode = LosMode.Transparent;
|
||||
|
||||
public bool LightingEnabled = true;
|
||||
|
||||
public bool ObstructVision;
|
||||
|
||||
private Texture2D visionCircle;
|
||||
|
||||
|
||||
private Dictionary<Hull, Color> hullAmbientLights;
|
||||
private Dictionary<Hull, Color> smoothedHullAmbientLights;
|
||||
@@ -67,22 +84,17 @@ namespace Barotrauma.Lights
|
||||
AmbientLight = new Color(20, 20, 20, 255);
|
||||
|
||||
visionCircle = Sprite.LoadTexture("Content/Lights/visioncircle.png");
|
||||
//visionCircle = new Sprite("Content/Lights/visioncircle.png", new Vector2(0.2f, 0.5f));
|
||||
|
||||
var pp = graphics.PresentationParameters;
|
||||
|
||||
lightMap = new RenderTarget2D(graphics,
|
||||
(int)(GameMain.GraphicsWidth*lightmapScale), (int)(GameMain.GraphicsHeight*lightmapScale), false,
|
||||
pp.BackBufferFormat, pp.DepthStencilFormat, pp.MultiSampleCount,
|
||||
RenderTargetUsage.DiscardContents);
|
||||
|
||||
losTexture = new RenderTarget2D(graphics, (int)(GameMain.GraphicsWidth*lightmapScale), (int)(GameMain.GraphicsHeight*lightmapScale), false, SurfaceFormat.Color, DepthFormat.None);
|
||||
|
||||
CreateRenderTargets(graphics);
|
||||
GameMain.Instance.OnResolutionChanged += () =>
|
||||
{
|
||||
CreateRenderTargets(graphics);
|
||||
};
|
||||
|
||||
#if WINDOWS
|
||||
LosEffect = content.Load<Effect>("losshader");
|
||||
LosEffect = content.Load<Effect>("Effects/losshader");
|
||||
#else
|
||||
LosEffect = content.Load<Effect>("losshader_opengl");
|
||||
LosEffect = content.Load<Effect>("Effects/losshader_opengl");
|
||||
#endif
|
||||
|
||||
if (lightEffect == null)
|
||||
@@ -96,16 +108,33 @@ namespace Barotrauma.Lights
|
||||
|
||||
hullAmbientLights = new Dictionary<Hull, Color>();
|
||||
smoothedHullAmbientLights = new Dictionary<Hull, Color>();
|
||||
}
|
||||
|
||||
if (alphaClearTexture == null)
|
||||
{
|
||||
alphaClearTexture = TextureLoader.FromFile("Content/Lights/alphaOne.png");
|
||||
}
|
||||
private void CreateRenderTargets(GraphicsDevice graphics)
|
||||
{
|
||||
var pp = graphics.PresentationParameters;
|
||||
|
||||
currLightMapScale = GameMain.Config.LightMapScale;
|
||||
|
||||
LightMap?.Dispose();
|
||||
LightMap = new RenderTarget2D(graphics,
|
||||
(int)(GameMain.GraphicsWidth * GameMain.Config.LightMapScale), (int)(GameMain.GraphicsHeight * GameMain.Config.LightMapScale), false,
|
||||
pp.BackBufferFormat, pp.DepthStencilFormat, pp.MultiSampleCount,
|
||||
RenderTargetUsage.DiscardContents);
|
||||
|
||||
SpecularMap?.Dispose();
|
||||
SpecularMap = new RenderTarget2D(graphics,
|
||||
(int)(GameMain.GraphicsWidth * GameMain.Config.LightMapScale), (int)(GameMain.GraphicsHeight * GameMain.Config.LightMapScale), false,
|
||||
pp.BackBufferFormat, pp.DepthStencilFormat, pp.MultiSampleCount,
|
||||
RenderTargetUsage.DiscardContents);
|
||||
|
||||
LosTexture?.Dispose();
|
||||
LosTexture = new RenderTarget2D(graphics, (int)(GameMain.GraphicsWidth * GameMain.Config.LightMapScale), (int)(GameMain.GraphicsHeight * GameMain.Config.LightMapScale), false, SurfaceFormat.Color, DepthFormat.None);
|
||||
}
|
||||
|
||||
public void AddLight(LightSource light)
|
||||
{
|
||||
lights.Add(light);
|
||||
if (!lights.Contains(light)) lights.Add(light);
|
||||
}
|
||||
|
||||
public void RemoveLight(LightSource light)
|
||||
@@ -124,82 +153,126 @@ namespace Barotrauma.Lights
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (ambientLightUpdateTimer > 0.0f)
|
||||
if (UseHullSpecificAmbientLight)
|
||||
{
|
||||
ambientLightUpdateTimer -= deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculateAmbientLights();
|
||||
|
||||
ambientLightUpdateTimer = AmbientLightUpdateInterval;
|
||||
}
|
||||
|
||||
foreach (Hull hull in hullAmbientLights.Keys)
|
||||
{
|
||||
if (!smoothedHullAmbientLights.ContainsKey(hull))
|
||||
if (ambientLightUpdateTimer > 0.0f)
|
||||
{
|
||||
smoothedHullAmbientLights.Add(hull, Color.TransparentBlack);
|
||||
ambientLightUpdateTimer -= deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculateAmbientLights();
|
||||
ambientLightUpdateTimer = AmbientLightUpdateInterval;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Hull hull in smoothedHullAmbientLights.Keys.ToList())
|
||||
{
|
||||
Color targetColor = Color.TransparentBlack;
|
||||
foreach (Hull hull in hullAmbientLights.Keys)
|
||||
{
|
||||
if (!smoothedHullAmbientLights.ContainsKey(hull))
|
||||
{
|
||||
smoothedHullAmbientLights.Add(hull, Color.TransparentBlack);
|
||||
}
|
||||
}
|
||||
|
||||
hullAmbientLights.TryGetValue(hull, out targetColor);
|
||||
|
||||
smoothedHullAmbientLights[hull] = Color.Lerp(smoothedHullAmbientLights[hull], targetColor, deltaTime);
|
||||
foreach (Hull hull in smoothedHullAmbientLights.Keys.ToList())
|
||||
{
|
||||
Color targetColor = Color.TransparentBlack;
|
||||
hullAmbientLights.TryGetValue(hull, out targetColor);
|
||||
smoothedHullAmbientLights[hull] = Color.Lerp(smoothedHullAmbientLights[hull], targetColor, deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Effect blur)
|
||||
private List<LightSource> activeLights = new List<LightSource>(capacity: 100);
|
||||
|
||||
public void UpdateLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, RenderTarget2D backgroundObstructor = null)
|
||||
{
|
||||
if (!LightingEnabled) return;
|
||||
|
||||
graphics.SetRenderTarget(lightMap);
|
||||
|
||||
Rectangle viewRect = cam.WorldView;
|
||||
viewRect.Y -= cam.WorldView.Height;
|
||||
|
||||
//clear to some small ambient light
|
||||
graphics.Clear(AmbientLight);
|
||||
graphics.BlendState = BlendState.Additive;
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, null, null, cam.Transform * Matrix.CreateScale(new Vector3(lightmapScale, lightmapScale, 1.0f)));
|
||||
if (Math.Abs(currLightMapScale - GameMain.Config.LightMapScale) > 0.01f)
|
||||
{
|
||||
//lightmap scale has changed -> recreate render targets
|
||||
CreateRenderTargets(graphics);
|
||||
}
|
||||
|
||||
Matrix spriteBatchTransform = cam.Transform * Matrix.CreateScale(new Vector3(GameMain.Config.LightMapScale, GameMain.Config.LightMapScale, 1.0f));
|
||||
Matrix transform = cam.ShaderTransform
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
|
||||
|
||||
Vector3 offset = Vector3.Zero;// new Vector3(Submarine.MainSub.DrawPosition.X, Submarine.MainSub.DrawPosition.Y, 0.0f);
|
||||
if (GameMain.Config.SpecularityEnabled)
|
||||
{
|
||||
UpdateSpecularMap(graphics, spriteBatch, spriteBatchTransform, cam, backgroundObstructor);
|
||||
}
|
||||
|
||||
graphics.SetRenderTarget(LightMap);
|
||||
|
||||
Rectangle viewRect = cam.WorldView;
|
||||
viewRect.Y -= cam.WorldView.Height;
|
||||
|
||||
//check which lights need to be drawn
|
||||
activeLights.Clear();
|
||||
foreach (LightSource light in lights)
|
||||
{
|
||||
if (light.Color.A < 1 || light.Range < 1.0f || !light.Enabled) continue;
|
||||
if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, light.Range, viewRect)) continue;
|
||||
|
||||
light.Draw(spriteBatch, lightEffect, transform);
|
||||
activeLights.Add(light);
|
||||
}
|
||||
|
||||
lightEffect.World = Matrix.CreateTranslation(offset) * transform;
|
||||
|
||||
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
|
||||
|
||||
foreach (Hull hull in smoothedHullAmbientLights.Keys)
|
||||
//clear the lightmap
|
||||
graphics.Clear(Color.Black);
|
||||
graphics.BlendState = BlendState.Additive;
|
||||
|
||||
|
||||
//draw background lights
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
bool backgroundSpritesDrawn = false;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
|
||||
foreach (LightSource light in activeLights)
|
||||
{
|
||||
if (smoothedHullAmbientLights[hull].A < 0.01f) continue;
|
||||
if (!light.IsBackground) continue;
|
||||
light.DrawSprite(spriteBatch, cam);
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform);
|
||||
backgroundSpritesDrawn = true;
|
||||
}
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, null, Particles.ParticleBlendState.Additive);
|
||||
spriteBatch.End();
|
||||
|
||||
var drawRect =
|
||||
hull.Submarine == null ?
|
||||
hull.Rect :
|
||||
new Rectangle((int)(hull.Submarine.DrawPosition.X + hull.Rect.X), (int)(hull.Submarine.DrawPosition.Y + hull.Rect.Y), hull.Rect.Width, hull.Rect.Height);
|
||||
//draw a black rectangle on hulls to hide background lights behind subs
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(drawRect.X, -drawRect.Y),
|
||||
new Vector2(hull.Rect.Width, hull.Rect.Height),
|
||||
smoothedHullAmbientLights[hull], true);
|
||||
Dictionary<Hull, Rectangle> visibleHulls = null;
|
||||
if (backgroundSpritesDrawn)
|
||||
{
|
||||
if (backgroundObstructor != null)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
|
||||
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
|
||||
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.Black);
|
||||
spriteBatch.End();
|
||||
}
|
||||
else
|
||||
{
|
||||
visibleHulls = GetVisibleHulls(cam);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
|
||||
foreach (Rectangle drawRect in visibleHulls.Values)
|
||||
{
|
||||
//TODO: draw some sort of smoothed rectangle
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(drawRect.X, -drawRect.Y),
|
||||
new Vector2(drawRect.Width, drawRect.Height),
|
||||
Color.Black, true);
|
||||
}
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
graphics.BlendState = BlendState.Additive;
|
||||
}
|
||||
|
||||
//draw the focused item and character to highlight them,
|
||||
//and light sprites (done before drawing the actual light volumes so we can make characters obstruct the highlights and sprites)
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
|
||||
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
if (Character.Controlled.FocusedItem != null)
|
||||
@@ -208,7 +281,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
if (Character.Controlled.FocusedCharacter != null)
|
||||
{
|
||||
Character.Controlled.FocusedCharacter.Draw(spriteBatch);
|
||||
Character.Controlled.FocusedCharacter.Draw(spriteBatch, cam);
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
@@ -218,33 +291,182 @@ namespace Barotrauma.Lights
|
||||
item.Draw(spriteBatch, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 drawPos = Character.Controlled.DrawPosition;
|
||||
drawPos.Y = -drawPos.Y;
|
||||
foreach (LightSource light in activeLights)
|
||||
{
|
||||
if (light.IsBackground) continue;
|
||||
light.DrawSprite(spriteBatch, cam);
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
//draw characters to obstruct the highlighted items/characters and light sprites
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, transformMatrix: spriteBatchTransform);
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (character.CurrentHull == null || !character.Enabled) continue;
|
||||
if (Character.Controlled?.FocusedCharacter == character) continue;
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
{
|
||||
limb.Draw(spriteBatch, cam, Color.Black);
|
||||
}
|
||||
}
|
||||
spriteBatch.End();
|
||||
graphics.BlendState = BlendState.Additive;
|
||||
|
||||
//draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(cam.WorldView.X, -cam.WorldView.Y, cam.WorldView.Width, cam.WorldView.Height), AmbientLight, isFilled:true);
|
||||
|
||||
foreach (ElectricalDischarger discharger in ElectricalDischarger.List)
|
||||
{
|
||||
discharger.DrawElectricity(spriteBatch);
|
||||
}
|
||||
|
||||
foreach (LightSource light in activeLights)
|
||||
{
|
||||
if (light.IsBackground) continue;
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform);
|
||||
}
|
||||
Vector3 offset = Vector3.Zero;// new Vector3(Submarine.MainSub.DrawPosition.X, Submarine.MainSub.DrawPosition.Y, 0.0f);
|
||||
lightEffect.World = Matrix.CreateTranslation(Vector3.Zero) * transform;
|
||||
|
||||
GameMain.ParticleManager.Draw(spriteBatch, false, null, Particles.ParticleBlendState.Additive);
|
||||
|
||||
if (UseHullSpecificAmbientLight)
|
||||
{
|
||||
if (visibleHulls == null)
|
||||
{
|
||||
visibleHulls = GetVisibleHulls(cam);
|
||||
}
|
||||
foreach (Hull hull in smoothedHullAmbientLights.Keys)
|
||||
{
|
||||
if (smoothedHullAmbientLights[hull].A < 0.01f) continue;
|
||||
if (!visibleHulls.TryGetValue(hull, out Rectangle drawRect)) continue;
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(drawRect.X, -drawRect.Y),
|
||||
new Vector2(hull.Rect.Width, hull.Rect.Height),
|
||||
smoothedHullAmbientLights[hull], true);
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
Vector2 haloDrawPos = Character.Controlled.DrawPosition;
|
||||
haloDrawPos.Y = -haloDrawPos.Y;
|
||||
|
||||
//ambient light decreases the brightness of the halo (no need for a bright halo if the ambient light is bright enough)
|
||||
float ambientBrightness = (AmbientLight.R + AmbientLight.B + AmbientLight.G) / 255.0f / 3.0f;
|
||||
Color haloColor = Color.White * (1.0f - ambientBrightness);
|
||||
spriteBatch.Draw(
|
||||
LightSource.LightTexture, drawPos, null, haloColor * 0.4f, 0.0f,
|
||||
new Vector2(LightSource.LightTexture.Width / 2, LightSource.LightTexture.Height / 2), 1.0f, SpriteEffects.None, 0.0f);
|
||||
Color haloColor = Color.White * (0.4f - ambientBrightness);
|
||||
if (haloColor.A > 0)
|
||||
{
|
||||
spriteBatch.Draw(
|
||||
LightSource.LightTexture, haloDrawPos, null, haloColor, 0.0f,
|
||||
new Vector2(LightSource.LightTexture.Width / 2, LightSource.LightTexture.Height / 2), 1.0f, SpriteEffects.None, 0.0f);
|
||||
}
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
|
||||
if (GameMain.Config.SpecularityEnabled)
|
||||
{
|
||||
spriteBatch.Begin(blendState: CustomBlendStates.Multiplicative);
|
||||
spriteBatch.Draw(SpecularMap, Vector2.Zero, Color.White);
|
||||
//spriteBatch.Draw(SpecularMap, Vector2.Zero, Color.White);
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
//draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
graphics.SetRenderTarget(null);
|
||||
graphics.BlendState = BlendState.AlphaBlend;
|
||||
}
|
||||
|
||||
|
||||
public void UpdateSpecularMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Matrix spriteBatchTransform, Camera cam, RenderTarget2D backgroundObstructor = null)
|
||||
{
|
||||
graphics.SetRenderTarget(SpecularMap);
|
||||
|
||||
//clear the lightmap
|
||||
graphics.Clear(Color.Gray);
|
||||
graphics.BlendState = BlendState.AlphaBlend;
|
||||
|
||||
spriteBatch.Begin(sortMode: SpriteSortMode.Deferred, blendState: BlendState.AlphaBlend, transformMatrix: spriteBatchTransform);
|
||||
|
||||
if (Level.Loaded != null)
|
||||
{
|
||||
Level.Loaded.LevelObjectManager.DrawObjects(spriteBatch, cam, drawFront: false, specular: true);
|
||||
}
|
||||
|
||||
Dictionary<Hull, Rectangle> visibleHulls = new Dictionary<Hull, Rectangle>();
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
var drawRect =
|
||||
hull.Submarine == null ?
|
||||
hull.Rect :
|
||||
new Rectangle((int)(hull.Submarine.DrawPosition.X + hull.Rect.X), (int)(hull.Submarine.DrawPosition.Y + hull.Rect.Y), hull.Rect.Width, hull.Rect.Height);
|
||||
|
||||
if (drawRect.Right < cam.WorldView.X || drawRect.X > cam.WorldView.Right ||
|
||||
drawRect.Y - drawRect.Height > cam.WorldView.Y || drawRect.Y < cam.WorldView.Y - cam.WorldView.Height)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
visibleHulls.Add(hull, drawRect);
|
||||
}
|
||||
|
||||
foreach (Rectangle drawRect in visibleHulls.Values)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(drawRect.X, -drawRect.Y),
|
||||
new Vector2(drawRect.Width, drawRect.Height),
|
||||
Color.Gray, true);
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
//TODO: use renderTargetFront to obstruct the things behind the sub (has to be drawn with a solid gray color)
|
||||
/*spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
|
||||
spriteBatch.Draw(renderTargetFront, new Rectangle(0, 0,
|
||||
(int)(GameMain.GraphicsWidth * currLightMapScale), (int)(GameMain.GraphicsHeight * currLightMapScale)), Color.White);
|
||||
spriteBatch.End();*/
|
||||
|
||||
//TODO: specular maps for level walls
|
||||
Level.Loaded?.Renderer?.RenderWalls(graphics, cam, specular: true);
|
||||
|
||||
graphics.SetRenderTarget(null);
|
||||
graphics.BlendState = BlendState.AlphaBlend;
|
||||
}
|
||||
|
||||
private Dictionary<Hull, Rectangle> GetVisibleHulls(Camera cam)
|
||||
{
|
||||
Dictionary<Hull, Rectangle> visibleHulls = new Dictionary<Hull, Rectangle>();
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
var drawRect =
|
||||
hull.Submarine == null ?
|
||||
hull.Rect :
|
||||
new Rectangle((int)(hull.Submarine.DrawPosition.X + hull.Rect.X), (int)(hull.Submarine.DrawPosition.Y + hull.Rect.Y), hull.Rect.Width, hull.Rect.Height);
|
||||
|
||||
if (drawRect.Right < cam.WorldView.X || drawRect.X > cam.WorldView.Right ||
|
||||
drawRect.Y - drawRect.Height > cam.WorldView.Y || drawRect.Y < cam.WorldView.Y - cam.WorldView.Height)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
visibleHulls.Add(hull, drawRect);
|
||||
}
|
||||
return visibleHulls;
|
||||
}
|
||||
|
||||
public void UpdateObstructVision(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Vector2 lookAtPosition)
|
||||
{
|
||||
if (!LosEnabled && !ObstructVision) return;
|
||||
if ((!LosEnabled || LosMode == LosMode.None) && !ObstructVision) return;
|
||||
if (ViewTarget == null) return;
|
||||
|
||||
graphics.SetRenderTarget(losTexture);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, cam.Transform * Matrix.CreateScale(new Vector3(lightmapScale, lightmapScale, 1.0f)));
|
||||
|
||||
graphics.SetRenderTarget(LosTexture);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cam.Transform * Matrix.CreateScale(new Vector3(GameMain.Config.LightMapScale, GameMain.Config.LightMapScale, 1.0f)));
|
||||
if (ObstructVision)
|
||||
{
|
||||
graphics.Clear(Color.Black);
|
||||
@@ -256,7 +478,7 @@ namespace Barotrauma.Lights
|
||||
MathHelper.Clamp(diff.Length() / 256.0f, 2.0f, 5.0f), 2.0f);
|
||||
|
||||
spriteBatch.Draw(visionCircle, new Vector2(ViewTarget.WorldPosition.X, -ViewTarget.WorldPosition.Y), null, Color.White, rotation,
|
||||
new Vector2(LightSource.LightTexture.Width * 0.2f, LightSource.LightTexture.Height / 2), scale, SpriteEffects.None, 0.0f);
|
||||
new Vector2(visionCircle.Width * 0.2f, visionCircle.Height / 2), scale, SpriteEffects.None, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -267,7 +489,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
if (LosEnabled && ViewTarget != null)
|
||||
if (LosEnabled && LosMode != LosMode.None && ViewTarget != null)
|
||||
{
|
||||
Vector2 pos = ViewTarget.WorldPosition;
|
||||
|
||||
@@ -335,7 +557,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
foreach (LightSource light in lights)
|
||||
{
|
||||
if (light.Color.A < 1f || light.Range < 1.0f) continue;
|
||||
if (light.Color.A < 1f || light.Range < 1.0f || light.IsBackground) continue;
|
||||
|
||||
var newAmbientLights = AmbientLightHulls(light);
|
||||
foreach (Hull hull in newAmbientLights.Keys)
|
||||
@@ -367,7 +589,7 @@ namespace Barotrauma.Lights
|
||||
var hull = Hull.FindHull(light.WorldPosition);
|
||||
if (hull == null) return hullAmbientLight;
|
||||
|
||||
return AmbientLightHulls(hull, hullAmbientLight, light.Color * (light.Range / 2000.0f));
|
||||
return AmbientLightHulls(hull, hullAmbientLight, light.Color * Math.Min(light.Range / 1000.0f, 1.0f));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -419,27 +641,14 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
static CustomBlendStates()
|
||||
{
|
||||
Multiplicative = new BlendState();
|
||||
Multiplicative.ColorSourceBlend = Multiplicative.AlphaSourceBlend = Blend.Zero;
|
||||
Multiplicative.ColorDestinationBlend = Multiplicative.AlphaDestinationBlend = Blend.SourceColor;
|
||||
Multiplicative.ColorBlendFunction = Multiplicative.AlphaBlendFunction = BlendFunction.Add;
|
||||
|
||||
WriteToAlpha = new BlendState();
|
||||
WriteToAlpha.ColorWriteChannels = ColorWriteChannels.Alpha;
|
||||
|
||||
MultiplyWithAlpha = new BlendState();
|
||||
MultiplyWithAlpha.ColorDestinationBlend = MultiplyWithAlpha.AlphaDestinationBlend = Blend.One;
|
||||
MultiplyWithAlpha.ColorSourceBlend = MultiplyWithAlpha.AlphaSourceBlend = Blend.DestinationAlpha;
|
||||
|
||||
LOS = new BlendState();
|
||||
LOS.ColorSourceBlend = LOS.AlphaSourceBlend = Blend.Zero;
|
||||
LOS.ColorDestinationBlend = LOS.AlphaDestinationBlend = Blend.InverseSourceColor;
|
||||
LOS.ColorBlendFunction = LOS.AlphaBlendFunction = BlendFunction.Add;
|
||||
Multiplicative = new BlendState
|
||||
{
|
||||
ColorSourceBlend = Blend.DestinationColor,
|
||||
ColorDestinationBlend = Blend.SourceColor,
|
||||
ColorBlendFunction = BlendFunction.Add
|
||||
};
|
||||
}
|
||||
public static BlendState Multiplicative { get; private set; }
|
||||
public static BlendState WriteToAlpha { get; private set; }
|
||||
public static BlendState MultiplyWithAlpha { get; private set; }
|
||||
public static BlendState LOS { get; private set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,31 +8,121 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Lights
|
||||
{
|
||||
class LightSource
|
||||
class LightSourceParams : ISerializableEntity
|
||||
{
|
||||
private static Texture2D lightTexture;
|
||||
public string Name => "LightSource";
|
||||
|
||||
private List<ConvexHullList> hullsInRange;
|
||||
public bool Persistent;
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new Dictionary<string, SerializableProperty>();
|
||||
|
||||
[Serialize("1.0,1.0,1.0,1.0", true), Editable]
|
||||
public Color Color
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private Color color;
|
||||
private float range;
|
||||
[Serialize(100.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f)]
|
||||
public float Range
|
||||
{
|
||||
get { return range; }
|
||||
set
|
||||
{
|
||||
|
||||
range = MathHelper.Clamp(value, 0.0f, 2048.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public Sprite overrideLightTexture;
|
||||
public Texture2D texture;
|
||||
|
||||
public Sprite OverrideLightTexture
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
//Additional sprite drawn on top of the lightsource. Ignores shadows.
|
||||
//Can be used to make lamp sprites glow for example.
|
||||
public Sprite LightSprite;
|
||||
public Sprite LightSprite
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public XElement DeformableLightSpriteElement
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
//Override the alpha value of the light sprite (if not set, the alpha of the light color is used)
|
||||
//Can be used to make lamp sprites glow at full brightness even if the light itself is dim.
|
||||
public float? OverrideLightSpriteAlpha;
|
||||
|
||||
public LightSourceParams(XElement element)
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "sprite":
|
||||
{
|
||||
LightSprite = new Sprite(subElement);
|
||||
float spriteAlpha = subElement.GetAttributeFloat("alpha", -1.0f);
|
||||
if (spriteAlpha >= 0.0f)
|
||||
{
|
||||
OverrideLightSpriteAlpha = spriteAlpha;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "deformablesprite":
|
||||
{
|
||||
DeformableLightSpriteElement = subElement;
|
||||
float spriteAlpha = subElement.GetAttributeFloat("alpha", -1.0f);
|
||||
if (spriteAlpha >= 0.0f)
|
||||
{
|
||||
OverrideLightSpriteAlpha = spriteAlpha;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "lighttexture":
|
||||
OverrideLightTexture = new Sprite(subElement);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LightSourceParams(float range, Color color)
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this);
|
||||
Range = range;
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
class LightSource
|
||||
{
|
||||
private static Texture2D lightTexture;
|
||||
|
||||
private List<ConvexHullList> hullsInRange;
|
||||
|
||||
public Texture2D texture;
|
||||
|
||||
public SpriteEffects LightSpriteEffect;
|
||||
|
||||
public Submarine ParentSub;
|
||||
|
||||
public bool CastShadows;
|
||||
private bool castShadows;
|
||||
public bool CastShadows
|
||||
{
|
||||
get { return castShadows && !IsBackground; }
|
||||
set { castShadows = value; }
|
||||
}
|
||||
|
||||
//what was the range of the light when lightvolumes were last calculated
|
||||
private float prevCalculatedRange;
|
||||
@@ -69,13 +159,17 @@ namespace Barotrauma.Lights
|
||||
private int vertexCount;
|
||||
private int indexCount;
|
||||
|
||||
private readonly LightSourceParams lightSourceParams;
|
||||
|
||||
public LightSourceParams LightSourceParams => lightSourceParams;
|
||||
|
||||
private Vector2 position;
|
||||
public Vector2 Position
|
||||
{
|
||||
get { return position; }
|
||||
set
|
||||
{
|
||||
if (position == value) return;
|
||||
if (Math.Abs(position.X - value.X) < 0.1f && Math.Abs(position.Y - value.Y) < 0.1f) return;
|
||||
position = value;
|
||||
|
||||
if (Vector2.DistanceSquared(prevCalculatedPosition, position) < 5.0f * 5.0f) return;
|
||||
@@ -92,7 +186,7 @@ namespace Barotrauma.Lights
|
||||
get { return rotation; }
|
||||
set
|
||||
{
|
||||
if (rotation == value) return;
|
||||
if (Math.Abs(rotation - value) < 0.01f) return;
|
||||
rotation = value;
|
||||
|
||||
NeedsHullCheck = true;
|
||||
@@ -100,6 +194,12 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 SpriteScale
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = Vector2.One;
|
||||
|
||||
public Vector2 WorldPosition
|
||||
{
|
||||
get { return (ParentSub == null) ? position : position + ParentSub.Position; }
|
||||
@@ -111,81 +211,93 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
if (lightTexture == null)
|
||||
{
|
||||
lightTexture = TextureLoader.FromFile("Content/Lights/light.png");
|
||||
lightTexture = TextureLoader.FromFile("Content/Lights/pointlight_bright.png");
|
||||
}
|
||||
|
||||
return lightTexture;
|
||||
}
|
||||
}
|
||||
|
||||
public Color Color
|
||||
public Sprite OverrideLightTexture
|
||||
{
|
||||
get { return color; }
|
||||
set { color = value; }
|
||||
get { return lightSourceParams.OverrideLightTexture; }
|
||||
}
|
||||
|
||||
public Sprite LightSprite
|
||||
{
|
||||
get { return lightSourceParams.LightSprite; }
|
||||
}
|
||||
|
||||
public Color Color
|
||||
{
|
||||
get { return lightSourceParams.Color; }
|
||||
set { lightSourceParams.Color = value; }
|
||||
}
|
||||
|
||||
public float Range
|
||||
{
|
||||
get { return range; }
|
||||
get { return lightSourceParams.Range; }
|
||||
set
|
||||
{
|
||||
|
||||
range = MathHelper.Clamp(value, 0.0f, 2048.0f);
|
||||
if (Math.Abs(prevCalculatedRange - range) < 10.0f) return;
|
||||
lightSourceParams.Range = value;
|
||||
if (Math.Abs(prevCalculatedRange - lightSourceParams.Range) < 10.0f) return;
|
||||
|
||||
NeedsHullCheck = true;
|
||||
NeedsRecalculation = true;
|
||||
prevCalculatedRange = range;
|
||||
prevCalculatedRange = lightSourceParams.Range;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Background lights are drawn behind submarines and they don't cast shadows.
|
||||
/// </summary>
|
||||
public bool IsBackground
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public DeformableSprite DeformableLightSprite
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool Enabled = true;
|
||||
|
||||
public LightSource (XElement element)
|
||||
: this(Vector2.Zero, 100.0f, Color.White, null)
|
||||
{
|
||||
range = element.GetAttributeFloat("range", 100.0f);
|
||||
color = new Color(element.GetAttributeVector4("color", Vector4.One));
|
||||
|
||||
lightSourceParams = new LightSourceParams(element);
|
||||
CastShadows = element.GetAttributeBool("castshadows", true);
|
||||
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
if (lightSourceParams.DeformableLightSpriteElement != null)
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "sprite":
|
||||
LightSprite = new Sprite(subElement);
|
||||
DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement);
|
||||
}
|
||||
}
|
||||
|
||||
float spriteAlpha = subElement.GetAttributeFloat("alpha", -1.0f);
|
||||
if (spriteAlpha >= 0.0f)
|
||||
{
|
||||
OverrideLightSpriteAlpha = spriteAlpha;
|
||||
}
|
||||
break;
|
||||
case "lighttexture":
|
||||
overrideLightTexture = new Sprite(subElement);
|
||||
break;
|
||||
}
|
||||
public LightSource(LightSourceParams lightSourceParams)
|
||||
: this(Vector2.Zero, 100.0f, Color.White, null)
|
||||
{
|
||||
this.lightSourceParams = lightSourceParams;
|
||||
lightSourceParams.Persistent = true;
|
||||
if (lightSourceParams.DeformableLightSpriteElement != null)
|
||||
{
|
||||
DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement);
|
||||
}
|
||||
}
|
||||
|
||||
public LightSource(Vector2 position, float range, Color color, Submarine submarine, bool addLight=true)
|
||||
{
|
||||
hullsInRange = new List<ConvexHullList>();
|
||||
|
||||
this.ParentSub = submarine;
|
||||
|
||||
this.position = position;
|
||||
this.range = range;
|
||||
this.color = color;
|
||||
|
||||
CastShadows = true;
|
||||
|
||||
lightSourceParams = new LightSourceParams(range, color);
|
||||
CastShadows = true;
|
||||
texture = LightTexture;
|
||||
|
||||
diffToSub = new Dictionary<Submarine, Vector2>();
|
||||
|
||||
if (addLight) GameMain.LightManager.AddLight(this);
|
||||
}
|
||||
|
||||
@@ -197,7 +309,7 @@ namespace Barotrauma.Lights
|
||||
var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub);
|
||||
if (fullChList == null) return;
|
||||
|
||||
chList.List = fullChList.List.FindAll(ch => ch.Enabled && MathUtils.CircleIntersectsRectangle(lightPos, range, ch.BoundingBox));
|
||||
chList.List = fullChList.List.FindAll(ch => ch.Enabled && MathUtils.CircleIntersectsRectangle(lightPos, Range, ch.BoundingBox));
|
||||
|
||||
NeedsHullCheck = true;
|
||||
}
|
||||
@@ -249,7 +361,7 @@ namespace Barotrauma.Lights
|
||||
subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height);
|
||||
|
||||
//only draw if the light overlaps with the sub
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders))
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, Range, subBorders))
|
||||
{
|
||||
if (chList.List.Count > 0) NeedsRecalculation = true;
|
||||
chList.List.Clear();
|
||||
@@ -283,7 +395,7 @@ namespace Barotrauma.Lights
|
||||
subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height);
|
||||
|
||||
//don't draw any shadows if the light doesn't overlap with the borders of the sub
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, range, subBorders))
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, Range, subBorders))
|
||||
{
|
||||
if (chList.List.Count > 0) NeedsRecalculation = true;
|
||||
chList.List.Clear();
|
||||
@@ -316,19 +428,17 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (range < 1.0f || color.A < 0.01f) return null;
|
||||
if (Range < 1.0f || Color.A < 0.01f) return null;
|
||||
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
|
||||
var hulls = new List<ConvexHull>();// ConvexHull.GetHullsInRange(position, range, ParentSub);
|
||||
var hulls = new List<ConvexHull>();
|
||||
foreach (ConvexHullList chList in hullsInRange)
|
||||
{
|
||||
//hulls.AddRange(chList.List);
|
||||
foreach (ConvexHull hull in chList.List)
|
||||
{
|
||||
if (!chList.IsHidden.Contains(hull)) hulls.Add(hull);
|
||||
//hulls.Add(hull);
|
||||
}
|
||||
foreach (ConvexHull hull in chList.List)
|
||||
{
|
||||
@@ -336,16 +446,14 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
float bounds = range * 2;
|
||||
float bounds = Range * 2;
|
||||
//find convexhull segments that are close enough and facing towards the light source
|
||||
List<Segment> visibleSegments = new List<Segment>();
|
||||
List<SegmentPoint> points = new List<SegmentPoint>();
|
||||
foreach (ConvexHull hull in hulls)
|
||||
{
|
||||
hull.RefreshWorldPositions();
|
||||
|
||||
var visibleHullSegments = hull.GetVisibleSegments(drawPos);
|
||||
visibleSegments.AddRange(visibleHullSegments);
|
||||
hull.GetVisibleSegments(drawPos, visibleSegments);
|
||||
}
|
||||
|
||||
//Generate new points at the intersections between segments
|
||||
@@ -355,9 +463,15 @@ namespace Barotrauma.Lights
|
||||
Vector2 p1a = visibleSegments[i].Start.WorldPos;
|
||||
Vector2 p1b = visibleSegments[i].End.WorldPos;
|
||||
|
||||
for (int j = 0; j < visibleSegments.Count; j++)
|
||||
for (int j = i + 1; j < visibleSegments.Count; j++)
|
||||
{
|
||||
if (j == i) continue;
|
||||
//ignore intersections between parallel axis-aligned segments
|
||||
if (visibleSegments[i].IsAxisAligned && visibleSegments[j].IsAxisAligned &&
|
||||
visibleSegments[i].IsHorizontal == visibleSegments[j].IsHorizontal)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2 p2a = visibleSegments[j].Start.WorldPos;
|
||||
Vector2 p2b = visibleSegments[j].End.WorldPos;
|
||||
|
||||
@@ -369,15 +483,30 @@ namespace Barotrauma.Lights
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2? intersection = MathUtils.GetLineIntersection(p1a, p1b, p2a, p2b);
|
||||
|
||||
if (intersection != null)
|
||||
bool intersects;
|
||||
Vector2 intersection = Vector2.Zero;
|
||||
if (visibleSegments[i].IsAxisAligned)
|
||||
{
|
||||
Vector2 intersectionVal = intersection.Value;
|
||||
intersects = MathUtils.GetAxisAlignedLineIntersection(p2a, p2b, p1a, p1b, visibleSegments[i].IsHorizontal, out intersection);
|
||||
}
|
||||
else if (visibleSegments[j].IsAxisAligned)
|
||||
{
|
||||
intersects = MathUtils.GetAxisAlignedLineIntersection(p1a, p1b, p2a, p2b, visibleSegments[j].IsHorizontal, out intersection);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersects = MathUtils.GetLineIntersection(p1a, p1b, p2a, p2b, out intersection);
|
||||
}
|
||||
|
||||
if (intersects)
|
||||
{
|
||||
SegmentPoint start = visibleSegments[i].Start;
|
||||
SegmentPoint end = visibleSegments[i].End;
|
||||
SegmentPoint mid = new SegmentPoint(intersectionVal, null);
|
||||
SegmentPoint mid = new SegmentPoint(intersection, null);
|
||||
if (visibleSegments[i].ConvexHull?.ParentEntity?.Submarine != null)
|
||||
{
|
||||
mid.Pos -= visibleSegments[i].ConvexHull.ParentEntity.Submarine.DrawPosition;
|
||||
}
|
||||
|
||||
if (Vector2.DistanceSquared(start.WorldPos, mid.WorldPos) < 25.0f ||
|
||||
Vector2.DistanceSquared(end.WorldPos, mid.WorldPos) < 25.0f)
|
||||
@@ -385,10 +514,17 @@ namespace Barotrauma.Lights
|
||||
continue;
|
||||
}
|
||||
|
||||
Segment seg1 = new Segment(start, mid, visibleSegments[i].ConvexHull); seg1.IsHorizontal = visibleSegments[i].IsHorizontal;
|
||||
Segment seg2 = new Segment(mid, end, visibleSegments[i].ConvexHull); seg2.IsHorizontal = visibleSegments[i].IsHorizontal;
|
||||
Segment seg1 = new Segment(start, mid, visibleSegments[i].ConvexHull)
|
||||
{
|
||||
IsHorizontal = visibleSegments[i].IsHorizontal,
|
||||
};
|
||||
|
||||
Segment seg2 = new Segment(mid, end, visibleSegments[i].ConvexHull)
|
||||
{
|
||||
IsHorizontal = visibleSegments[i].IsHorizontal
|
||||
};
|
||||
visibleSegments[i] = seg1;
|
||||
visibleSegments.Insert(i+1,seg2);
|
||||
visibleSegments.Insert(i + 1, seg2);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
@@ -430,14 +566,14 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("Constructing light volumes failed! Light pos: "+drawPos+", Hull verts:\n");
|
||||
StringBuilder sb = new StringBuilder("Constructing light volumes failed! Light pos: " + drawPos + ", Hull verts:\n");
|
||||
foreach (SegmentPoint sp in points)
|
||||
{
|
||||
sb.AppendLine(sp.Pos.ToString());
|
||||
}
|
||||
DebugConsole.ThrowError(sb.ToString(), e);
|
||||
}
|
||||
|
||||
|
||||
List<Vector2> output = new List<Vector2>();
|
||||
//List<Pair<int, Vector2>> preOutput = new List<Pair<int, Vector2>>();
|
||||
|
||||
@@ -514,21 +650,47 @@ namespace Barotrauma.Lights
|
||||
return output;
|
||||
}
|
||||
|
||||
private Pair<int,Vector2> RayCast(Vector2 rayStart, Vector2 rayEnd, List<Segment> segments)
|
||||
private Pair<int, Vector2> RayCast(Vector2 rayStart, Vector2 rayEnd, List<Segment> segments)
|
||||
{
|
||||
float closestDist = 0.0f;
|
||||
float closestDist = float.PositiveInfinity;
|
||||
Vector2? closestIntersection = null;
|
||||
int segment = -1;
|
||||
|
||||
for (int i=0;i<segments.Count;i++)
|
||||
float minX = Math.Min(rayStart.X, rayEnd.X);
|
||||
float maxX = Math.Max(rayStart.X, rayEnd.X);
|
||||
float minY = Math.Min(rayStart.Y, rayEnd.Y);
|
||||
float maxY = Math.Max(rayStart.Y, rayEnd.Y);
|
||||
|
||||
for (int i = 0; i < segments.Count; i++)
|
||||
{
|
||||
Segment s = segments[i];
|
||||
Vector2? intersection = MathUtils.GetAxisAlignedLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, s.IsHorizontal);
|
||||
|
||||
if (intersection != null)
|
||||
//segment's end position always has a higher or equal y coordinate than the start position
|
||||
//so we can do this comparison and skip segments that are at the wrong side of the ray
|
||||
if (s.End.WorldPos.Y < s.Start.WorldPos.Y)
|
||||
{
|
||||
float dist = Vector2.DistanceSquared((Vector2)intersection, rayStart);
|
||||
if (closestIntersection == null || dist < closestDist)
|
||||
System.Diagnostics.Debug.Assert(s.End.WorldPos.Y >= s.Start.WorldPos.Y,
|
||||
"LightSource raycast failed. Segment's end positions should never be below the start position. Parent entity: " + (s.ConvexHull?.ParentEntity == null ? "null" : s.ConvexHull.ParentEntity.ToString()));
|
||||
}
|
||||
if (s.Start.WorldPos.Y > maxY || s.End.WorldPos.Y < minY) { continue; }
|
||||
//same for the x-axis
|
||||
if (s.Start.WorldPos.X > s.End.WorldPos.X)
|
||||
{
|
||||
if (s.Start.WorldPos.X < minX) continue;
|
||||
if (s.End.WorldPos.X > maxX) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.End.WorldPos.X < minX) continue;
|
||||
if (s.Start.WorldPos.X > maxX) continue;
|
||||
}
|
||||
|
||||
if (s.IsAxisAligned ?
|
||||
MathUtils.GetAxisAlignedLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, s.IsHorizontal, out Vector2 intersection) :
|
||||
MathUtils.GetLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, out intersection))
|
||||
{
|
||||
float dist = Vector2.DistanceSquared(intersection, rayStart);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestDist = dist;
|
||||
closestIntersection = intersection;
|
||||
@@ -536,10 +698,8 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pair<int,Vector2> retVal = new Pair<int,Vector2>();
|
||||
retVal.Second = closestIntersection == null ? rayEnd : (Vector2)closestIntersection;
|
||||
retVal.First = segment;
|
||||
|
||||
Pair<int, Vector2> retVal = new Pair<int, Vector2>(segment, closestIntersection == null ? rayEnd : (Vector2)closestIntersection);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -555,15 +715,27 @@ namespace Barotrauma.Lights
|
||||
|
||||
Vector2 uvOffset = Vector2.Zero;
|
||||
Vector2 overrideTextureDims = Vector2.One;
|
||||
if (overrideLightTexture != null)
|
||||
if (OverrideLightTexture != null)
|
||||
{
|
||||
overrideTextureDims = new Vector2(overrideLightTexture.SourceRect.Width, overrideLightTexture.SourceRect.Height);
|
||||
uvOffset = (overrideLightTexture.Origin / overrideTextureDims) - new Vector2(0.5f, 0.5f);
|
||||
overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height);
|
||||
uvOffset = (OverrideLightTexture.Origin / overrideTextureDims) - new Vector2(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
// Add a vertex for the center of the mesh
|
||||
vertices.Add(new VertexPositionColorTexture(new Vector3(position.X, position.Y, 0),
|
||||
Color.White,new Vector2(0.5f, 0.5f) + uvOffset));
|
||||
Color.White, new Vector2(0.5f, 0.5f) + uvOffset));
|
||||
|
||||
//hacky fix to exc excessively large light volumes (they used to be up to 4x the range of the light if there was nothing to block the rays).
|
||||
//might want to tweak the raycast logic in a way that this isn't necessary
|
||||
float boundRadius = Range * 1.1f / (1.0f - Math.Max(Math.Abs(uvOffset.X), Math.Abs(uvOffset.Y)));
|
||||
Rectangle boundArea = new Rectangle((int)(drawPos.X - boundRadius), (int)(drawPos.Y + boundRadius), (int)(boundRadius * 2), (int)(boundRadius * 2));
|
||||
for (int i = 0; i < rayCastHits.Count; i++)
|
||||
{
|
||||
if (MathUtils.GetLineRectangleIntersection(drawPos, rayCastHits[i], boundArea, out Vector2 intersection))
|
||||
{
|
||||
rayCastHits[i] = intersection;
|
||||
}
|
||||
}
|
||||
|
||||
// Add all the other encounter points as vertices
|
||||
// storing their world position as UV coordinates
|
||||
@@ -578,19 +750,6 @@ namespace Barotrauma.Lights
|
||||
Vector2 nextVertex = rayCastHits[i < rayCastHits.Count - 1 ? i + 1 : 0];
|
||||
|
||||
Vector2 rawDiff = vertex - drawPos;
|
||||
Vector2 diff = rawDiff;
|
||||
diff /= range * 2.0f;
|
||||
if (overrideLightTexture != null)
|
||||
{
|
||||
//calculate texture coordinates based on the light's rotation
|
||||
Vector2 originDiff = diff;
|
||||
|
||||
diff.X = originDiff.X * cosAngle - originDiff.Y * sinAngle;
|
||||
diff.Y = originDiff.X * sinAngle + originDiff.Y * cosAngle;
|
||||
diff *= (overrideTextureDims / overrideLightTexture.size) * 2.0f;
|
||||
|
||||
diff += uvOffset;
|
||||
}
|
||||
|
||||
//calculate normal of first segment
|
||||
Vector2 nDiff1 = vertex - nextVertex;
|
||||
@@ -614,6 +773,19 @@ namespace Barotrauma.Lights
|
||||
nDiff /= Math.Max(Math.Abs(nDiff.X), Math.Abs(nDiff.Y));
|
||||
nDiff *= 50.0f;
|
||||
|
||||
Vector2 diff = rawDiff;
|
||||
diff /= Range * 2.0f;
|
||||
if (OverrideLightTexture != null)
|
||||
{
|
||||
//calculate texture coordinates based on the light's rotation
|
||||
Vector2 originDiff = diff;
|
||||
|
||||
diff.X = originDiff.X * cosAngle - originDiff.Y * sinAngle;
|
||||
diff.Y = originDiff.X * sinAngle + originDiff.Y * cosAngle;
|
||||
diff *= (overrideTextureDims / OverrideLightTexture.size);// / (1.0f - Math.Max(Math.Abs(uvOffset.X), Math.Abs(uvOffset.Y)));
|
||||
diff += uvOffset;
|
||||
}
|
||||
|
||||
//finally, create the vertices
|
||||
VertexPositionColorTexture fullVert = new VertexPositionColorTexture(new Vector3(position.X + rawDiff.X, position.Y + rawDiff.Y, 0),
|
||||
Color.White, new Vector2(0.5f, 0.5f) + diff);
|
||||
@@ -678,50 +850,90 @@ namespace Barotrauma.Lights
|
||||
|
||||
lightVolumeBuffer.SetData<VertexPositionColorTexture>(vertices.ToArray());
|
||||
lightVolumeIndexBuffer.SetData<short>(indices.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, BasicEffect lightEffect, Matrix transform)
|
||||
/// <summary>
|
||||
/// Draws the optional "light sprite", just a simple sprite with no shadows
|
||||
/// </summary>
|
||||
/// <param name="spriteBatch"></param>
|
||||
public void DrawSprite(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (CastShadows)
|
||||
if (DeformableLightSprite != null)
|
||||
{
|
||||
CheckHullsInRange();
|
||||
Vector2 origin = DeformableLightSprite.Origin;
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
|
||||
DeformableLightSprite.Draw(
|
||||
cam, new Vector3(drawPos, 0.0f),
|
||||
origin, -Rotation, SpriteScale,
|
||||
new Color(Color, lightSourceParams.OverrideLightSpriteAlpha ?? Color.A / 255.0f),
|
||||
LightSpriteEffect == SpriteEffects.FlipHorizontally);
|
||||
}
|
||||
|
||||
Vector3 offset = ParentSub == null ? Vector3.Zero :
|
||||
new Vector3(ParentSub.DrawPosition.X, ParentSub.DrawPosition.Y, 0.0f);
|
||||
|
||||
lightEffect.World = Matrix.CreateTranslation(offset) * transform;
|
||||
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
if (LightSprite != null)
|
||||
{
|
||||
Vector2 origin = LightSprite.Origin;
|
||||
if (LightSpriteEffect == SpriteEffects.FlipHorizontally) origin.X = LightSprite.SourceRect.Width - origin.X;
|
||||
if (LightSpriteEffect == SpriteEffects.FlipVertically) origin.Y = LightSprite.SourceRect.Height - origin.Y;
|
||||
|
||||
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
LightSprite.Draw(
|
||||
spriteBatch, drawPos,
|
||||
new Color(Color, OverrideLightSpriteAlpha ?? Color.A / 255.0f),
|
||||
origin, -Rotation, 1, LightSpriteEffect);
|
||||
new Color(Color, lightSourceParams.OverrideLightSpriteAlpha ?? Color.A / 255.0f),
|
||||
origin, -Rotation, SpriteScale, LightSpriteEffect);
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
//visualize light recalculations
|
||||
float timeSinceRecalculation = (float)Timing.TotalTime - lastRecalculationTime;
|
||||
if (timeSinceRecalculation < 0.1f)
|
||||
{
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
drawPos.Y = -drawPos.Y;
|
||||
GUI.DrawRectangle(spriteBatch, drawPos - Vector2.One * 10, Vector2.One * 20, Color.Red * (1.0f - timeSinceRecalculation * 10.0f), isFilled: true);
|
||||
GUI.DrawLine(spriteBatch, drawPos - Vector2.One * Range, drawPos + Vector2.One * Range, Color);
|
||||
GUI.DrawLine(spriteBatch, drawPos - new Vector2(1.0f, -1.0f) * Range, drawPos + new Vector2(1.0f, -1.0f) * Range, Color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void DrawLightVolume(SpriteBatch spriteBatch, BasicEffect lightEffect, Matrix transform)
|
||||
{
|
||||
if (CastShadows)
|
||||
{
|
||||
CheckHullsInRange();
|
||||
}
|
||||
|
||||
//if the light doesn't cast shadows, we can simply render the texture without having to calculate the light volume
|
||||
if (!CastShadows)
|
||||
{
|
||||
Texture2D currentTexture = texture ?? LightTexture;
|
||||
if (overrideLightTexture != null) currentTexture = overrideLightTexture.Texture;
|
||||
if (OverrideLightTexture != null) { currentTexture = OverrideLightTexture.Texture; }
|
||||
|
||||
Vector2 center = new Vector2(currentTexture.Width / 2, currentTexture.Height / 2);
|
||||
float scale = range / (currentTexture.Width / 2.0f);
|
||||
Vector2 center = OverrideLightTexture == null ?
|
||||
new Vector2(currentTexture.Width / 2, currentTexture.Height / 2) :
|
||||
OverrideLightTexture.Origin;
|
||||
float scale = Range / (currentTexture.Width / 2.0f);
|
||||
|
||||
spriteBatch.Draw(currentTexture, drawPos, null, color * (color.A / 255.0f), 0, center, scale, SpriteEffects.None, 1);
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
spriteBatch.Draw(currentTexture, drawPos, null, Color, -rotation, center, scale, SpriteEffects.None, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 offset = ParentSub == null ?
|
||||
Vector3.Zero : new Vector3(ParentSub.DrawPosition.X, ParentSub.DrawPosition.Y, 0.0f);
|
||||
lightEffect.World = Matrix.CreateTranslation(offset) * transform;
|
||||
|
||||
if (NeedsRecalculation)
|
||||
{
|
||||
var verts = FindRaycastHits();
|
||||
@@ -733,10 +945,10 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (vertexCount == 0) return;
|
||||
|
||||
lightEffect.DiffuseColor = (new Vector3(color.R, color.G, color.B) * (color.A / 255.0f)) / 255.0f;
|
||||
if (overrideLightTexture != null)
|
||||
lightEffect.DiffuseColor = (new Vector3(Color.R, Color.G, Color.B) * (Color.A / 255.0f)) / 255.0f;
|
||||
if (OverrideLightTexture != null)
|
||||
{
|
||||
lightEffect.Texture = overrideLightTexture.Texture;
|
||||
lightEffect.Texture = OverrideLightTexture.Texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -777,19 +989,20 @@ namespace Barotrauma.Lights
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
if (LightSprite != null) LightSprite.Remove();
|
||||
|
||||
if (lightVolumeBuffer != null)
|
||||
if (!lightSourceParams.Persistent)
|
||||
{
|
||||
lightVolumeBuffer.Dispose();
|
||||
lightVolumeBuffer = null;
|
||||
LightSprite?.Remove();
|
||||
OverrideLightTexture?.Remove();
|
||||
}
|
||||
|
||||
if (lightVolumeIndexBuffer != null)
|
||||
{
|
||||
lightVolumeIndexBuffer.Dispose();
|
||||
lightVolumeIndexBuffer = null;
|
||||
}
|
||||
DeformableLightSprite?.Remove();
|
||||
DeformableLightSprite = null;
|
||||
|
||||
lightVolumeBuffer?.Dispose();
|
||||
lightVolumeBuffer = null;
|
||||
|
||||
lightVolumeIndexBuffer?.Dispose();
|
||||
lightVolumeIndexBuffer = null;
|
||||
|
||||
GameMain.LightManager.RemoveLight(this);
|
||||
}
|
||||
|
||||
@@ -40,12 +40,16 @@ namespace Barotrauma
|
||||
drawRect.Y = -rect.Y;
|
||||
GUI.DrawRectangle(spriteBatch, drawRect, Color.Red, true);
|
||||
|
||||
if (!Item.ShowLinks) return;
|
||||
|
||||
foreach (MapEntity e in linkedTo)
|
||||
{
|
||||
bool isLinkAllowed = e is Item item && item.HasTag("dock");
|
||||
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(WorldPosition.X, -WorldPosition.Y),
|
||||
new Vector2(e.WorldPosition.X, -e.WorldPosition.Y),
|
||||
Color.Red * 0.3f);
|
||||
isLinkAllowed ? Color.LightGreen * 0.5f : Color.Red * 0.5f, width: 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +60,7 @@ namespace Barotrauma
|
||||
editingHUD = CreateEditingHUD();
|
||||
}
|
||||
|
||||
editingHUD.Update((float)Timing.Step);
|
||||
editingHUD.UpdateManually((float)Timing.Step);
|
||||
|
||||
if (!PlayerInput.LeftButtonClicked() || !PlayerInput.KeyDown(Keys.Space)) return;
|
||||
|
||||
@@ -77,44 +81,43 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawEditing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (editingHUD == null) return;
|
||||
|
||||
editingHUD.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
|
||||
private GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
{
|
||||
int width = 450;
|
||||
int x = GameMain.GraphicsWidth / 2 - width / 2, y = 10;
|
||||
int width = 450, height = 120;
|
||||
int x = GameMain.GraphicsWidth / 2 - width / 2, y = 30;
|
||||
|
||||
editingHUD = new GUIFrame(new Rectangle(x, y, width, 100), "");
|
||||
editingHUD.Padding = new Vector4(10, 10, 0, 0);
|
||||
editingHUD.UserData = this;
|
||||
editingHUD = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas) { ScreenSpaceOffset = new Point(x, y) })
|
||||
{
|
||||
UserData = this
|
||||
};
|
||||
|
||||
new GUITextBlock(new Rectangle(0, 0, 100, 20), TextManager.Get("LinkedSub"), "",
|
||||
Alignment.TopLeft, Alignment.TopLeft, editingHUD, false, GUI.LargeFont);
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), editingHUD.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
var pathBox = new GUITextBox(new Rectangle(10, 30, 300, 20), "", editingHUD);
|
||||
pathBox.Font = GUI.SmallFont;
|
||||
pathBox.Text = filePath;
|
||||
|
||||
var reloadButton = new GUIButton(new Rectangle(320, 30, 80, 20), TextManager.Get("ReloadLinkedSub"), "", editingHUD);
|
||||
reloadButton.OnClicked = Reload;
|
||||
reloadButton.UserData = pathBox;
|
||||
reloadButton.ToolTip = TextManager.Get("ReloadLinkedSubTooltip");
|
||||
|
||||
y += 20;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("LinkedSub"), font: GUI.LargeFont);
|
||||
|
||||
if (!inGame)
|
||||
{
|
||||
new GUITextBlock(new Rectangle(0, 0, 0, 20), TextManager.Get("LinkLinkedSub"),
|
||||
"", Alignment.TopRight, Alignment.TopRight, editingHUD, false, GUI.SmallFont);
|
||||
y += 25;
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("LinkLinkedSub"), textColor: Color.Yellow, font: GUI.SmallFont);
|
||||
}
|
||||
|
||||
var pathContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), isHorizontal: true);
|
||||
|
||||
var pathBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1.0f), pathContainer.RectTransform), filePath, font: GUI.SmallFont);
|
||||
var reloadButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), pathContainer.RectTransform), TextManager.Get("ReloadLinkedSub"))
|
||||
{
|
||||
OnClicked = Reload,
|
||||
UserData = pathBox,
|
||||
ToolTip = TextManager.Get("ReloadLinkedSubTooltip")
|
||||
};
|
||||
|
||||
PositionEditingHUD();
|
||||
|
||||
return editingHUD;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,50 @@
|
||||
namespace Barotrauma
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Location
|
||||
{
|
||||
private HireManager hireManager;
|
||||
|
||||
public HireManager HireManager
|
||||
public void RemoveHireableCharacter(CharacterInfo character)
|
||||
{
|
||||
get { return hireManager; }
|
||||
if (!Type.HasHireableCharacters)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot hire a character from location \"" + Name + "\" - the location has no hireable characters.\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
if (hireManager == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot hire a character from location \"" + Name + "\" - hire manager has not been instantiated.\n" + Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
hireManager.RemoveCharacter(character);
|
||||
}
|
||||
|
||||
public IEnumerable<CharacterInfo> GetHireableCharacters()
|
||||
{
|
||||
if (!Type.HasHireableCharacters)
|
||||
{
|
||||
return Enumerable.Empty<CharacterInfo>();
|
||||
}
|
||||
|
||||
if (hireManager == null)
|
||||
{
|
||||
hireManager = new HireManager();
|
||||
}
|
||||
if (!hireManager.AvailableCharacters.Any())
|
||||
{
|
||||
hireManager.GenerateCharacters(location: this, amount: HireManager.MaxAvailableCharacters);
|
||||
}
|
||||
return hireManager.AvailableCharacters;
|
||||
}
|
||||
|
||||
partial void RemoveProjSpecific()
|
||||
{
|
||||
hireManager?.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,210 +1,795 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Map
|
||||
{
|
||||
private static Sprite iceTexture;
|
||||
private static Texture2D iceCraters;
|
||||
private static Texture2D iceCrack;
|
||||
//how much larger the ice background is compared to the size of the map
|
||||
private const float BackgroundScale = 1.5f;
|
||||
|
||||
class MapAnim
|
||||
{
|
||||
public Location StartLocation;
|
||||
public Location EndLocation;
|
||||
public string StartMessage;
|
||||
public string EndMessage;
|
||||
|
||||
public float? StartZoom;
|
||||
public float? EndZoom;
|
||||
|
||||
private float startDelay;
|
||||
public float StartDelay
|
||||
{
|
||||
get { return startDelay; }
|
||||
set
|
||||
{
|
||||
startDelay = value;
|
||||
Timer = -startDelay;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2? StartPos;
|
||||
|
||||
public float Duration;
|
||||
public float Timer;
|
||||
|
||||
public bool Finished;
|
||||
}
|
||||
|
||||
private Queue<MapAnim> mapAnimQueue = new Queue<MapAnim>();
|
||||
|
||||
private Location highlightedLocation;
|
||||
|
||||
public void Update(float deltaTime, Rectangle rect, float scale = 1.0f)
|
||||
{
|
||||
Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y);
|
||||
Vector2 offset = -currentLocation.MapPosition;
|
||||
private Vector2 drawOffset;
|
||||
private Vector2 drawOffsetNoise;
|
||||
|
||||
float maxDist = 20.0f;
|
||||
private float subReticleAnimState;
|
||||
private float targetReticleAnimState;
|
||||
private Vector2 subReticlePosition;
|
||||
|
||||
private float zoom = 3.0f;
|
||||
|
||||
private Rectangle borders;
|
||||
|
||||
private MapTile[,] mapTiles;
|
||||
private bool messageBoxOpen;
|
||||
#if DEBUG
|
||||
private GUIComponent editor;
|
||||
|
||||
private void CreateEditor()
|
||||
{
|
||||
editor = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), GUI.Canvas, Anchor.TopRight, minSize: new Point(400, 0)));
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), editor.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.02f,
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
var listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.95f), paddedFrame.RectTransform, Anchor.Center));
|
||||
new SerializableEntityEditor(listBox.Content.RectTransform, generationParams, false, true);
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedFrame.RectTransform), "Generate")
|
||||
{
|
||||
OnClicked =(btn, userData) =>
|
||||
{
|
||||
Rand.SetSyncedSeed(ToolBox.StringToInt(this.Seed));
|
||||
Generate();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
struct MapTile
|
||||
{
|
||||
public readonly Sprite Sprite;
|
||||
public SpriteEffects SpriteEffect;
|
||||
public Vector2 Offset;
|
||||
|
||||
public MapTile(Sprite sprite, SpriteEffects spriteEffect)
|
||||
{
|
||||
Sprite = sprite;
|
||||
SpriteEffect = spriteEffect;
|
||||
|
||||
Offset = Rand.Vector(Rand.Range(0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
{
|
||||
OnLocationChanged += LocationChanged;
|
||||
|
||||
borders = new Rectangle(
|
||||
(int)Locations.Min(l => l.MapPosition.X),
|
||||
(int)Locations.Min(l => l.MapPosition.Y),
|
||||
(int)Locations.Max(l => l.MapPosition.X),
|
||||
(int)Locations.Max(l => l.MapPosition.Y));
|
||||
borders.Width = borders.Width - borders.X;
|
||||
borders.Height = borders.Height - borders.Y;
|
||||
|
||||
mapTiles = new MapTile[
|
||||
(int)Math.Ceiling(size * BackgroundScale / generationParams.TileSpriteSpacing.X),
|
||||
(int)Math.Ceiling(size * BackgroundScale / generationParams.TileSpriteSpacing.Y)];
|
||||
|
||||
for (int x = 0; x < mapTiles.GetLength(0); x++)
|
||||
{
|
||||
for (int y = 0; y < mapTiles.GetLength(1); y++)
|
||||
{
|
||||
mapTiles[x, y] = new MapTile(
|
||||
generationParams.BackgroundTileSprites[Rand.Int(generationParams.BackgroundTileSprites.Count)], Rand.Range(0.0f, 1.0f) < 0.5f ?
|
||||
SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
||||
}
|
||||
}
|
||||
|
||||
drawOffset = -CurrentLocation.MapPosition;
|
||||
}
|
||||
|
||||
private static Texture2D rawNoiseTexture;
|
||||
private static Sprite rawNoiseSprite;
|
||||
private static Texture2D noiseTexture;
|
||||
|
||||
partial void GenerateNoiseMapProjSpecific()
|
||||
{
|
||||
if (noiseTexture == null)
|
||||
{
|
||||
noiseTexture = new Texture2D(GameMain.Instance.GraphicsDevice, generationParams.NoiseResolution, generationParams.NoiseResolution);
|
||||
rawNoiseTexture = new Texture2D(GameMain.Instance.GraphicsDevice, generationParams.NoiseResolution, generationParams.NoiseResolution);
|
||||
rawNoiseSprite = new Sprite(rawNoiseTexture, null, null);
|
||||
}
|
||||
|
||||
Color[] crackTextureData = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
|
||||
Color[] noiseTextureData = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
|
||||
Color[] rawNoiseTextureData = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
|
||||
for (int x = 0; x < generationParams.NoiseResolution; x++)
|
||||
{
|
||||
for (int y = 0; y < generationParams.NoiseResolution; y++)
|
||||
{
|
||||
noiseTextureData[x + y * generationParams.NoiseResolution] = Color.Lerp(Color.Black, Color.Transparent, Noise[x, y]);
|
||||
rawNoiseTextureData[x + y * generationParams.NoiseResolution] = Color.Lerp(Color.Black, Color.White, Rand.Range(0.0f,1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
float mapRadius = size / 2;
|
||||
Vector2 mapCenter = Vector2.One * mapRadius;
|
||||
foreach (LocationConnection connection in connections)
|
||||
{
|
||||
float centerDist = Vector2.Distance(connection.CenterPos, mapCenter);
|
||||
|
||||
Vector2 connectionStart = connection.Locations[0].MapPosition;
|
||||
Vector2 connectionEnd = connection.Locations[1].MapPosition;
|
||||
float connectionLength = Vector2.Distance(connectionStart, connectionEnd);
|
||||
int iterations = (int)(Math.Sqrt(connectionLength * generationParams.ConnectionIndicatorIterationMultiplier));
|
||||
connection.CrackSegments = MathUtils.GenerateJaggedLine(
|
||||
connectionStart, connectionEnd,
|
||||
iterations, connectionLength * generationParams.ConnectionIndicatorDisplacementMultiplier);
|
||||
|
||||
iterations = (int)(Math.Sqrt(connectionLength * generationParams.ConnectionIterationMultiplier));
|
||||
var visualCrackSegments = MathUtils.GenerateJaggedLine(
|
||||
connectionStart, connectionEnd,
|
||||
iterations, connectionLength * generationParams.ConnectionDisplacementMultiplier);
|
||||
|
||||
float totalLength = Vector2.Distance(visualCrackSegments[0][0], visualCrackSegments.Last()[1]);
|
||||
for (int i = 0; i < visualCrackSegments.Count; i++)
|
||||
{
|
||||
Vector2 start = visualCrackSegments[i][0] * (generationParams.NoiseResolution / (float)size);
|
||||
Vector2 end = visualCrackSegments[i][1] * (generationParams.NoiseResolution / (float)size);
|
||||
|
||||
float length = Vector2.Distance(start, end);
|
||||
for (float x = 0; x < 1; x += 1.0f / length)
|
||||
{
|
||||
Vector2 pos = Vector2.Lerp(start, end, x);
|
||||
SetNoiseColorOnArea(pos, MathHelper.Clamp((int)(totalLength / 30), 2, 5) + Rand.Range(-1,1), Color.Transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetNoiseColorOnArea(Vector2 pos, int dist, Color color)
|
||||
{
|
||||
for (int x = -dist; x < dist; x++)
|
||||
{
|
||||
for (int y = -dist; y < dist; y++)
|
||||
{
|
||||
float d = 1.0f - new Vector2(x, y).Length() / dist;
|
||||
if (d <= 0) continue;
|
||||
|
||||
int xIndex = (int)pos.X + x;
|
||||
if (xIndex < 0 || xIndex >= generationParams.NoiseResolution) continue;
|
||||
int yIndex = (int)pos.Y + y;
|
||||
if (yIndex < 0 || yIndex >= generationParams.NoiseResolution) continue;
|
||||
|
||||
float perlin = (float)PerlinNoise.CalculatePerlin(
|
||||
xIndex / (float)generationParams.NoiseResolution * 100.0f,
|
||||
yIndex / (float)generationParams.NoiseResolution * 100.0f, 0);
|
||||
|
||||
byte a = Math.Max(crackTextureData[xIndex + yIndex * generationParams.NoiseResolution].A, (byte)((d * perlin) * 255));
|
||||
|
||||
crackTextureData[xIndex + yIndex * generationParams.NoiseResolution].A = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < noiseTextureData.Length; i++)
|
||||
{
|
||||
float darken = noiseTextureData[i].A / 255.0f;
|
||||
Color pathColor = Color.Lerp(Color.White, Color.Transparent, noiseTextureData[i].A / 255.0f);
|
||||
noiseTextureData[i] =
|
||||
Color.Lerp(noiseTextureData[i], pathColor, crackTextureData[i].A / 255.0f * 0.5f);
|
||||
}
|
||||
|
||||
noiseTexture.SetData(noiseTextureData);
|
||||
rawNoiseTexture.SetData(rawNoiseTextureData);
|
||||
}
|
||||
|
||||
private void LocationChanged(Location prevLocation, Location newLocation)
|
||||
{
|
||||
if (prevLocation == newLocation) return;
|
||||
//focus on starting location
|
||||
mapAnimQueue.Enqueue(new MapAnim()
|
||||
{
|
||||
EndZoom = 2.0f,
|
||||
EndLocation = prevLocation,
|
||||
Duration = MathHelper.Clamp(Vector2.Distance(-drawOffset, prevLocation.MapPosition) / 1000.0f, 0.1f, 0.5f),
|
||||
});
|
||||
mapAnimQueue.Enqueue(new MapAnim()
|
||||
{
|
||||
EndZoom = 3.0f,
|
||||
StartLocation = prevLocation,
|
||||
EndLocation = newLocation,
|
||||
Duration = 2.0f,
|
||||
StartDelay = 0.5f
|
||||
});
|
||||
}
|
||||
|
||||
partial void ChangeLocationType(Location location, string prevName, LocationTypeChange change)
|
||||
{
|
||||
//focus on the location
|
||||
var mapAnim = new MapAnim()
|
||||
{
|
||||
EndZoom = zoom * 1.5f,
|
||||
EndLocation = location,
|
||||
Duration = CurrentLocation == location ? 1.0f : 2.0f,
|
||||
StartDelay = 1.0f
|
||||
};
|
||||
if (change.Messages.Count > 0)
|
||||
{
|
||||
mapAnim.EndMessage = change.Messages[Rand.Range(0,change.Messages.Count)]
|
||||
.Replace("[prevname]", prevName)
|
||||
.Replace("[name]", location.Name);
|
||||
}
|
||||
mapAnimQueue.Enqueue(mapAnim);
|
||||
|
||||
mapAnimQueue.Enqueue(new MapAnim()
|
||||
{
|
||||
EndZoom = zoom,
|
||||
StartLocation = location,
|
||||
EndLocation = CurrentLocation,
|
||||
Duration = 1.0f,
|
||||
StartDelay = 0.5f
|
||||
});
|
||||
}
|
||||
|
||||
partial void ClearAnimQueue()
|
||||
{
|
||||
mapAnimQueue.Clear();
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, GUICustomComponent mapContainer)
|
||||
{
|
||||
Rectangle rect = mapContainer.Rect;
|
||||
|
||||
subReticlePosition = Vector2.Lerp(subReticlePosition, CurrentLocation.MapPosition, deltaTime);
|
||||
subReticleAnimState = 0.8f - Vector2.Distance(subReticlePosition, CurrentLocation.MapPosition) / 50.0f;
|
||||
subReticleAnimState = MathHelper.Clamp(subReticleAnimState + (float)Math.Sin(Timing.TotalTime * 3.5f) * 0.2f, 0.0f, 1.0f);
|
||||
|
||||
targetReticleAnimState = SelectedLocation == null ?
|
||||
Math.Max(targetReticleAnimState - deltaTime, 0.0f) :
|
||||
Math.Min(targetReticleAnimState + deltaTime, 0.6f + (float)Math.Sin(Timing.TotalTime * 2.5f) * 0.4f);
|
||||
#if DEBUG
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
if (editor == null) CreateEditor();
|
||||
editor.AddToGUIUpdateList(order: 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mapAnimQueue.Count > 0)
|
||||
{
|
||||
hudOpenState = Math.Max(hudOpenState - deltaTime, 0.0f);
|
||||
UpdateMapAnim(mapAnimQueue.Peek(), deltaTime);
|
||||
if (mapAnimQueue.Peek().Finished)
|
||||
{
|
||||
mapAnimQueue.Dequeue();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
hudOpenState = Math.Min(hudOpenState + deltaTime, 0.75f + (float)Math.Sin(Timing.TotalTime * 3.0f) * 0.25f);
|
||||
|
||||
Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y);
|
||||
|
||||
float closestDist = 0.0f;
|
||||
highlightedLocation = null;
|
||||
for (int i = 0; i < locations.Count; i++)
|
||||
if (GUI.MouseOn == null || GUI.MouseOn == mapContainer)
|
||||
{
|
||||
Location location = locations[i];
|
||||
Vector2 pos = rectCenter + (location.MapPosition + offset) * scale;
|
||||
|
||||
if (!rect.Contains(pos)) continue;
|
||||
|
||||
float dist = Vector2.Distance(PlayerInput.MousePosition, pos);
|
||||
if (dist < maxDist && (highlightedLocation == null || dist < closestDist))
|
||||
for (int i = 0; i < Locations.Count; i++)
|
||||
{
|
||||
closestDist = dist;
|
||||
highlightedLocation = location;
|
||||
Location location = Locations[i];
|
||||
Vector2 pos = rectCenter + (location.MapPosition + drawOffset) * zoom;
|
||||
|
||||
if (!rect.Contains(pos)) continue;
|
||||
|
||||
float iconScale = MapGenerationParams.Instance.LocationIconSize / location.Type.Sprite.size.X;
|
||||
|
||||
Rectangle drawRect = location.Type.Sprite.SourceRect;
|
||||
drawRect.Width = (int)(drawRect.Width * iconScale * zoom * 1.4f);
|
||||
drawRect.Height = (int)(drawRect.Height * iconScale * zoom * 1.4f);
|
||||
drawRect.X = (int)pos.X - drawRect.Width / 2;
|
||||
drawRect.Y = (int)pos.Y - drawRect.Width / 2;
|
||||
|
||||
if (!drawRect.Contains(PlayerInput.MousePosition)) continue;
|
||||
|
||||
float dist = Vector2.Distance(PlayerInput.MousePosition, pos);
|
||||
if (highlightedLocation == null || dist < closestDist)
|
||||
{
|
||||
closestDist = dist;
|
||||
highlightedLocation = location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (LocationConnection connection in connections)
|
||||
{
|
||||
if (highlightedLocation != currentLocation &&
|
||||
connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation))
|
||||
if (highlightedLocation != CurrentLocation &&
|
||||
connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(CurrentLocation))
|
||||
{
|
||||
if (PlayerInput.LeftButtonClicked() &&
|
||||
selectedLocation != highlightedLocation && highlightedLocation != null)
|
||||
SelectedLocation != highlightedLocation && highlightedLocation != null)
|
||||
{
|
||||
selectedConnection = connection;
|
||||
selectedLocation = highlightedLocation;
|
||||
|
||||
//clients aren't allowed to select the location without a permission
|
||||
if (GameMain.Client == null || GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign))
|
||||
{
|
||||
OnLocationSelected?.Invoke(selectedLocation, selectedConnection);
|
||||
SelectedConnection = connection;
|
||||
SelectedLocation = highlightedLocation;
|
||||
targetReticleAnimState = 0.0f;
|
||||
|
||||
OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection);
|
||||
GameMain.Client?.SendCampaignState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GUI.MouseOn == mapContainer)
|
||||
{
|
||||
zoom += PlayerInput.ScrollWheelSpeed / 1000.0f;
|
||||
zoom = MathHelper.Clamp(zoom, 1.0f, 4.0f);
|
||||
|
||||
if (PlayerInput.MidButtonHeld())
|
||||
{
|
||||
drawOffset += PlayerInput.MouseSpeed / zoom;
|
||||
}
|
||||
#if DEBUG
|
||||
if (PlayerInput.DoubleClicked() && highlightedLocation != null)
|
||||
{
|
||||
currentLocation = highlightedLocation;
|
||||
OnLocationChanged?.Invoke(currentLocation);
|
||||
var passedConnection = CurrentLocation.Connections.Find(c => c.OtherLocation(CurrentLocation) == highlightedLocation);
|
||||
if (passedConnection != null)
|
||||
{
|
||||
passedConnection.Passed = true;
|
||||
}
|
||||
|
||||
Location prevLocation = CurrentLocation;
|
||||
CurrentLocation = highlightedLocation;
|
||||
CurrentLocation.Discovered = true;
|
||||
OnLocationChanged?.Invoke(prevLocation, CurrentLocation);
|
||||
SelectLocation(-1);
|
||||
ProgressWorld();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Rectangle rect, float scale = 1.0f)
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, GUICustomComponent mapContainer)
|
||||
{
|
||||
Rectangle rect = mapContainer.Rect;
|
||||
|
||||
Vector2 viewSize = new Vector2(rect.Width / zoom, rect.Height / zoom);
|
||||
float edgeBuffer = size * (BackgroundScale - 1.0f) / 2;
|
||||
drawOffset.X = MathHelper.Clamp(drawOffset.X, -size - edgeBuffer + viewSize.X / 2.0f, edgeBuffer -viewSize.X / 2.0f);
|
||||
drawOffset.Y = MathHelper.Clamp(drawOffset.Y, -size - edgeBuffer + viewSize.Y / 2.0f, edgeBuffer -viewSize.Y / 2.0f);
|
||||
|
||||
drawOffsetNoise = new Vector2(
|
||||
(float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.1f % 255, Timing.TotalTime * 0.1f % 255, 0) - 0.5f,
|
||||
(float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.2f % 255, Timing.TotalTime * 0.2f % 255, 0.5f) - 0.5f) * 10.0f;
|
||||
|
||||
Vector2 viewOffset = drawOffset + drawOffsetNoise;
|
||||
|
||||
Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y);
|
||||
Vector2 offset = -currentLocation.MapPosition;
|
||||
|
||||
Rectangle prevScissorRect = GameMain.Instance.GraphicsDevice.ScissorRectangle;
|
||||
GameMain.Instance.GraphicsDevice.ScissorRectangle = rect;
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, rect);
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||
|
||||
iceTexture.DrawTiled(spriteBatch, new Vector2(rect.X, rect.Y), new Vector2(rect.Width, rect.Height), color: Color.White * 0.8f);
|
||||
|
||||
foreach (LocationConnection connection in connections)
|
||||
for (int x = 0; x < mapTiles.GetLength(0); x++)
|
||||
{
|
||||
Color crackColor = Color.White * Math.Max(connection.Difficulty / 100.0f, 1.5f);
|
||||
|
||||
|
||||
if (selectedLocation != currentLocation &&
|
||||
(connection.Locations.Contains(selectedLocation) && connection.Locations.Contains(currentLocation)))
|
||||
for (int y = 0; y < mapTiles.GetLength(1); y++)
|
||||
{
|
||||
crackColor = Color.Red;
|
||||
}
|
||||
else if (highlightedLocation != currentLocation &&
|
||||
(connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation)))
|
||||
{
|
||||
crackColor = Color.Red * 0.5f;
|
||||
}
|
||||
else if (!connection.Passed)
|
||||
{
|
||||
crackColor *= 0.2f;
|
||||
Vector2 mapPos = new Vector2(
|
||||
x * generationParams.TileSpriteSpacing.X + ((y % 2 == 0) ? 0.0f : generationParams.TileSpriteSpacing.X * 0.5f),
|
||||
y * generationParams.TileSpriteSpacing.Y);
|
||||
|
||||
mapPos.X -= size / 2 * (BackgroundScale - 1.0f);
|
||||
mapPos.Y -= size / 2 * (BackgroundScale - 1.0f);
|
||||
|
||||
Vector2 scale = new Vector2(
|
||||
generationParams.TileSpriteSize.X / mapTiles[x, y].Sprite.size.X,
|
||||
generationParams.TileSpriteSize.Y / mapTiles[x, y].Sprite.size.Y);
|
||||
mapTiles[x, y].Sprite.Draw(spriteBatch, rectCenter + (mapPos + viewOffset) * zoom, Color.White,
|
||||
origin: new Vector2(256.0f, 256.0f), rotate: 0, scale: scale * zoom, spriteEffect: mapTiles[x, y].SpriteEffect);
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
if (generationParams.ShowNoiseMap)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, rectCenter + (borders.Location.ToVector2() + viewOffset) * zoom, borders.Size.ToVector2() * zoom, Color.White, true);
|
||||
}
|
||||
#endif
|
||||
Vector2 topLeft = rectCenter + viewOffset * zoom;
|
||||
topLeft.X = (int)topLeft.X;
|
||||
topLeft.Y = (int)topLeft.Y;
|
||||
|
||||
for (int i = 0; i < connection.CrackSegments.Count; i++)
|
||||
Vector2 bottomRight = rectCenter + (viewOffset + new Vector2(size,size)) * zoom;
|
||||
bottomRight.X = (int)bottomRight.X;
|
||||
bottomRight.Y = (int)bottomRight.Y;
|
||||
|
||||
spriteBatch.Draw(noiseTexture,
|
||||
destinationRectangle: new Rectangle((int)topLeft.X, (int)topLeft.Y, (int)(bottomRight.X- topLeft.X), (int)(bottomRight.Y - topLeft.Y)),
|
||||
sourceRectangle: null,
|
||||
color: Color.White);
|
||||
|
||||
if (topLeft.X > rect.X)
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Y, (int)(topLeft.X- rect.X), rect.Height), Color.Black* 0.8f, true);
|
||||
if (topLeft.Y > rect.Y)
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, rect.Y, (int)(bottomRight.X - topLeft.X), (int)(topLeft.Y - rect.Y)), Color.Black * 0.8f, true);
|
||||
if (bottomRight.X < rect.Right)
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)bottomRight.X, rect.Y, (int)(rect.Right - bottomRight.X), rect.Height), Color.Black * 0.8f, true);
|
||||
if (bottomRight.Y < rect.Bottom)
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)topLeft.X, (int)bottomRight.Y, (int)(bottomRight.X - topLeft.X), (int)(rect.Bottom - bottomRight.Y)), Color.Black * 0.8f, true);
|
||||
|
||||
var sourceRect = rect;
|
||||
float rawNoiseScale = 1.0f + Noise[(int)(Timing.TotalTime * 100 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 100 % Noise.GetLength(1) - 1)];
|
||||
cameraNoiseStrength = Noise[(int)(Timing.TotalTime * 10 % Noise.GetLength(0) - 1), (int)(Timing.TotalTime * 10 % Noise.GetLength(1) - 1)];
|
||||
|
||||
rawNoiseSprite.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(),
|
||||
startOffset: new Point(Rand.Range(0,rawNoiseSprite.SourceRect.Width), Rand.Range(0, rawNoiseSprite.SourceRect.Height)),
|
||||
color : Color.White * cameraNoiseStrength * 0.5f,
|
||||
textureScale: Vector2.One * rawNoiseScale);
|
||||
|
||||
rawNoiseSprite.DrawTiled(spriteBatch, rect.Location.ToVector2(), rect.Size.ToVector2(),
|
||||
startOffset: new Point(Rand.Range(0, rawNoiseSprite.SourceRect.Width), Rand.Range(0, rawNoiseSprite.SourceRect.Height)),
|
||||
color: new Color(20,20,20,100),
|
||||
textureScale: Vector2.One * rawNoiseScale * 2);
|
||||
|
||||
if (generationParams.ShowLocations)
|
||||
{
|
||||
foreach (LocationConnection connection in connections)
|
||||
{
|
||||
var segment = connection.CrackSegments[i];
|
||||
|
||||
Vector2 start = rectCenter + (segment[0] + offset) * scale;
|
||||
Vector2 end = rectCenter + (segment[1] + offset) * scale;
|
||||
|
||||
if (!rect.Contains(start) && !rect.Contains(end))
|
||||
Color connectionColor;
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
continue;
|
||||
float sizeFactor = MathUtils.InverseLerp(
|
||||
MapGenerationParams.Instance.SmallLevelConnectionLength,
|
||||
MapGenerationParams.Instance.LargeLevelConnectionLength,
|
||||
connection.Length);
|
||||
|
||||
connectionColor = ToolBox.GradientLerp(sizeFactor, Color.LightGreen, Color.Orange, Color.Red);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2? intersection = MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(rect.X, rect.Y + rect.Height, rect.Width, rect.Height));
|
||||
if (intersection != null)
|
||||
{
|
||||
if (!rect.Contains(start))
|
||||
{
|
||||
start = (Vector2)intersection;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = (Vector2)intersection;
|
||||
}
|
||||
}
|
||||
connectionColor = ToolBox.GradientLerp(connection.Difficulty / 100.0f,
|
||||
MapGenerationParams.Instance.LowDifficultyColor,
|
||||
MapGenerationParams.Instance.MediumDifficultyColor,
|
||||
MapGenerationParams.Instance.HighDifficultyColor);
|
||||
}
|
||||
|
||||
float dist = Vector2.Distance(start, end);
|
||||
int width = (int)(3 * zoom);
|
||||
|
||||
int width = (int)(MathHelper.Clamp(connection.Difficulty, 2.0f, 20.0f) * scale);
|
||||
if (SelectedLocation != CurrentLocation &&
|
||||
(connection.Locations.Contains(SelectedLocation) && connection.Locations.Contains(CurrentLocation)))
|
||||
{
|
||||
connectionColor = Color.Gold;
|
||||
width *= 2;
|
||||
}
|
||||
else if (highlightedLocation != CurrentLocation &&
|
||||
(connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(CurrentLocation)))
|
||||
{
|
||||
connectionColor = Color.Lerp(connectionColor, Color.White, 0.5f);
|
||||
width *= 2;
|
||||
}
|
||||
else if (!connection.Passed)
|
||||
{
|
||||
//crackColor *= 0.5f;
|
||||
}
|
||||
|
||||
spriteBatch.Draw(iceCrack,
|
||||
new Rectangle((int)start.X, (int)start.Y, (int)dist + 2, width),
|
||||
new Rectangle(0, 0, iceCrack.Width, 60), crackColor, MathUtils.VectorToAngle(end - start),
|
||||
new Vector2(0, 30), SpriteEffects.None, 0.01f);
|
||||
for (int i = 0; i < connection.CrackSegments.Count; i++)
|
||||
{
|
||||
var segment = connection.CrackSegments[i];
|
||||
|
||||
Vector2 start = rectCenter + (segment[0] + viewOffset) * zoom;
|
||||
Vector2 end = rectCenter + (segment[1] + viewOffset) * zoom;
|
||||
|
||||
if (!rect.Contains(start) && !rect.Contains(end))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MathUtils.GetLineRectangleIntersection(start, end, new Rectangle(rect.X, rect.Y + rect.Height, rect.Width, rect.Height), out Vector2 intersection))
|
||||
{
|
||||
if (!rect.Contains(start))
|
||||
{
|
||||
start = intersection;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = intersection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float distFromPlayer = Vector2.Distance(CurrentLocation.MapPosition, (segment[0] + segment[1]) / 2.0f);
|
||||
float dist = Vector2.Distance(start, end);
|
||||
|
||||
float a = GameMain.DebugDraw ? 1.0f : (200.0f - distFromPlayer) / 200.0f;
|
||||
spriteBatch.Draw(generationParams.ConnectionSprite.Texture,
|
||||
new Rectangle((int)start.X, (int)start.Y, (int)(dist - 1 * zoom), width),
|
||||
null, connectionColor * MathHelper.Clamp(a, 0.1f, 0.5f), MathUtils.VectorToAngle(end - start),
|
||||
new Vector2(0, 16), SpriteEffects.None, 0.01f);
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw && zoom > 1.0f && generationParams.ShowLevelTypeNames)
|
||||
{
|
||||
Vector2 center = rectCenter + (connection.CenterPos + viewOffset) * zoom;
|
||||
if (rect.Contains(center))
|
||||
{
|
||||
GUI.DrawString(spriteBatch, center, connection.Biome.Name + " (" + connection.Difficulty + ")", Color.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rect.Inflate(8, 8);
|
||||
GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8);
|
||||
GUI.DrawRectangle(spriteBatch, rect, Color.LightGray);
|
||||
|
||||
for (int i = 0; i < Locations.Count; i++)
|
||||
{
|
||||
Location location = Locations[i];
|
||||
Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom;
|
||||
|
||||
Rectangle drawRect = location.Type.Sprite.SourceRect;
|
||||
drawRect.X = (int)pos.X - drawRect.Width / 2;
|
||||
drawRect.Y = (int)pos.Y - drawRect.Width / 2;
|
||||
|
||||
if (!rect.Intersects(drawRect)) { continue; }
|
||||
|
||||
Color color = location.Type.SpriteColor;
|
||||
if (location.Connections.Find(c => c.Locations.Contains(CurrentLocation)) == null)
|
||||
{
|
||||
color *= 0.5f;
|
||||
}
|
||||
|
||||
float iconScale = location == CurrentLocation ? 1.2f : 1.0f;
|
||||
if (location == highlightedLocation)
|
||||
{
|
||||
iconScale *= 1.1f;
|
||||
color = Color.Lerp(color, Color.White, 0.5f);
|
||||
}
|
||||
|
||||
float distFromPlayer = Vector2.Distance(CurrentLocation.MapPosition, location.MapPosition);
|
||||
color *= MathHelper.Clamp((1000.0f - distFromPlayer) / 500.0f, 0.1f, 1.0f);
|
||||
|
||||
location.Type.Sprite.Draw(spriteBatch, pos, color,
|
||||
scale: MapGenerationParams.Instance.LocationIconSize / location.Type.Sprite.size.X * iconScale * zoom);
|
||||
MapGenerationParams.Instance.LocationIndicator.Draw(spriteBatch, pos, color,
|
||||
scale: MapGenerationParams.Instance.LocationIconSize / MapGenerationParams.Instance.LocationIndicator.size.X * iconScale * zoom * 1.4f);
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
//PLACEHOLDER until the stuff at the center of the map is implemented
|
||||
float centerIconSize = 50.0f;
|
||||
Vector2 centerPos = rectCenter + (new Vector2(size / 2) + viewOffset) * zoom;
|
||||
bool mouseOn = Vector2.Distance(PlayerInput.MousePosition, centerPos) < centerIconSize * zoom;
|
||||
|
||||
var centerLocationType = LocationType.List.Last();
|
||||
Color centerColor = centerLocationType.SpriteColor * (mouseOn ? 1.0f : 0.6f);
|
||||
centerLocationType.Sprite.Draw(spriteBatch, centerPos, centerColor,
|
||||
scale: centerIconSize / centerLocationType.Sprite.size.X * zoom);
|
||||
MapGenerationParams.Instance.LocationIndicator.Draw(spriteBatch, centerPos, centerColor,
|
||||
scale: centerIconSize / MapGenerationParams.Instance.LocationIndicator.size.X * zoom * 1.2f);
|
||||
|
||||
if (mouseOn && PlayerInput.LeftButtonClicked() && !messageBoxOpen)
|
||||
{
|
||||
Vector2 center = rectCenter + (connection.CenterPos + offset) * scale;
|
||||
GUI.DrawString(spriteBatch, center, connection.Biome.Name, Color.White);
|
||||
var messageBox = new GUIMessageBox("Mysteries lie ahead...", "This area is unreachable in this version of Barotrauma. Please wait for future updates!");
|
||||
CoroutineManager.StartCoroutine(WaitForMessageBoxClosed(messageBox));
|
||||
}
|
||||
}
|
||||
|
||||
DrawDecorativeHUD(spriteBatch, rect);
|
||||
|
||||
rect.Inflate(8, 8);
|
||||
GUI.DrawRectangle(spriteBatch, rect, Color.Black, false, 0.0f, 8);
|
||||
GUI.DrawRectangle(spriteBatch, rect, Color.LightGray);
|
||||
|
||||
for (int i = 0; i < locations.Count; i++)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Location location = locations[i];
|
||||
Vector2 pos = rectCenter + (location.MapPosition + offset) * scale;
|
||||
|
||||
Rectangle drawRect = location.Type.Sprite.SourceRect;
|
||||
Rectangle sourceRect = drawRect;
|
||||
drawRect.X = (int)pos.X - drawRect.Width / 2;
|
||||
drawRect.Y = (int)pos.Y - drawRect.Width / 2;
|
||||
|
||||
if (!rect.Intersects(drawRect)) continue;
|
||||
|
||||
Color color = location.Connections.Find(c => c.Locations.Contains(currentLocation)) == null ? Color.White : Color.Green;
|
||||
|
||||
color *= (location.Discovered) ? 0.8f : 0.2f;
|
||||
|
||||
if (location == currentLocation) color = Color.Orange;
|
||||
|
||||
if (drawRect.X < rect.X)
|
||||
{
|
||||
sourceRect.X += rect.X - drawRect.X;
|
||||
sourceRect.Width -= sourceRect.X;
|
||||
drawRect.X = rect.X;
|
||||
}
|
||||
else if (drawRect.Right > rect.Right)
|
||||
{
|
||||
sourceRect.Width -= (drawRect.Right - rect.Right);
|
||||
}
|
||||
|
||||
if (drawRect.Y < rect.Y)
|
||||
{
|
||||
sourceRect.Y += rect.Y - drawRect.Y;
|
||||
sourceRect.Height -= sourceRect.Y;
|
||||
drawRect.Y = rect.Y;
|
||||
}
|
||||
else if (drawRect.Bottom > rect.Bottom)
|
||||
{
|
||||
sourceRect.Height -= drawRect.Bottom - rect.Bottom;
|
||||
}
|
||||
|
||||
drawRect.Width = sourceRect.Width;
|
||||
drawRect.Height = sourceRect.Height;
|
||||
|
||||
spriteBatch.Draw(location.Type.Sprite.Texture, drawRect, sourceRect, color);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
Location location = (i == 0) ? highlightedLocation : selectedLocation;
|
||||
if (i == 2) location = currentLocation;
|
||||
|
||||
Location location = (i == 0) ? highlightedLocation : CurrentLocation;
|
||||
if (location == null) continue;
|
||||
|
||||
Vector2 pos = rectCenter + (location.MapPosition + offset) * scale;
|
||||
pos.X = (int)(pos.X + location.Type.Sprite.SourceRect.Width * 0.6f);
|
||||
pos.Y = (int)(pos.Y - 10);
|
||||
GUI.DrawString(spriteBatch, pos, location.Name, Color.White, Color.Black * 0.8f, 3);
|
||||
Vector2 pos = rectCenter + (location.MapPosition + viewOffset) * zoom;
|
||||
pos.X += 25 * zoom;
|
||||
pos.Y -= 5 * zoom;
|
||||
Vector2 size = GUI.LargeFont.MeasureString(location.Name);
|
||||
GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0].Draw(
|
||||
spriteBatch, new Rectangle((int)pos.X - 30, (int)pos.Y, (int)size.X + 60, (int)size.Y + 25), Color.Black * hudOpenState * 0.7f);
|
||||
GUI.DrawString(spriteBatch, pos,
|
||||
location.Name, Color.White * hudOpenState * 1.5f, font: GUI.LargeFont);
|
||||
GUI.DrawString(spriteBatch, pos + Vector2.UnitY * 25,
|
||||
location.Type.DisplayName, Color.White * hudOpenState * 1.5f);
|
||||
}
|
||||
|
||||
GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||
}
|
||||
|
||||
private IEnumerable<object> WaitForMessageBoxClosed(GUIMessageBox box)
|
||||
{
|
||||
messageBoxOpen = true;
|
||||
while (GUIMessageBox.MessageBoxes.Contains(box)) yield return null;
|
||||
yield return new WaitForSeconds(.1f);
|
||||
messageBoxOpen = false;
|
||||
}
|
||||
|
||||
private float hudOpenState;
|
||||
private float cameraNoiseStrength;
|
||||
|
||||
private void DrawDecorativeHUD(SpriteBatch spriteBatch, Rectangle rect)
|
||||
{
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, null, GameMain.ScissorTestEnable);
|
||||
|
||||
if (generationParams.ShowOverlay)
|
||||
{
|
||||
Vector2 mapCenter = rect.Center.ToVector2() + (new Vector2(size, size) / 2 + drawOffset + drawOffsetNoise) * zoom;
|
||||
Vector2 centerDiff = CurrentLocation.MapPosition - new Vector2(size) / 2;
|
||||
int currentZone = (int)Math.Floor((centerDiff.Length() / (size * 0.5f) * generationParams.DifficultyZones));
|
||||
for (int i = 0; i < generationParams.DifficultyZones; i++)
|
||||
{
|
||||
float radius = size / 2 * ((i + 1.0f) / generationParams.DifficultyZones);
|
||||
float textureSize = (radius / (generationParams.MapCircle.size.X / 2) * zoom);
|
||||
|
||||
generationParams.MapCircle.Draw(spriteBatch,
|
||||
mapCenter,
|
||||
i == currentZone || i == currentZone - 1 ? Color.White * 0.5f : Color.White * 0.2f,
|
||||
i * 0.4f + (float)Timing.TotalTime * 0.01f, textureSize);
|
||||
}
|
||||
}
|
||||
|
||||
float animPulsate = (float)Math.Sin(Timing.TotalTime * 2.0f) * 0.1f;
|
||||
|
||||
GameMain.Instance.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
Vector2 frameSize = generationParams.DecorativeGraphSprite.FrameSize.ToVector2();
|
||||
generationParams.DecorativeGraphSprite.Draw(spriteBatch, (int)((cameraNoiseStrength + animPulsate) * hudOpenState * generationParams.DecorativeGraphSprite.FrameCount),
|
||||
new Vector2(rect.Right, rect.Bottom), Color.White, frameSize, 0,
|
||||
Vector2.Divide(new Vector2(rect.Width / 4, rect.Height / 10), frameSize));
|
||||
|
||||
/*frameSize = generationParams.DecorativeMapSprite.FrameSize.ToVector2();
|
||||
generationParams.DecorativeMapSprite.Draw(spriteBatch, (int)((cameraNoiseStrength + animPulsate) * hudOpenState * generationParams.DecorativeMapSprite.FrameCount),
|
||||
new Vector2(rect.X, rect.Y + rect.Height * 0.17f), Color.White, new Vector2(0, frameSize.Y * 0.2f), 0,
|
||||
Vector2.Divide(new Vector2(rect.Width / 3, rect.Height / 5), frameSize), spriteEffect: SpriteEffects.FlipVertically);
|
||||
|
||||
GUI.DrawString(spriteBatch,
|
||||
new Vector2(rect.X + rect.Width / 15, rect.Y + rect.Height / 11),
|
||||
"JOVIAN FLUX " + ((cameraNoiseStrength + Rand.Range(-0.02f, 0.02f)) * 500), Color.White * hudOpenState, font: GUI.SmallFont);*/
|
||||
GUI.DrawString(spriteBatch,
|
||||
new Vector2(rect.X + rect.Width * 0.27f, rect.Y + rect.Height * 0.93f),
|
||||
"LAT " + (-drawOffset.Y / 100.0f) + " LON " + (-drawOffset.X / 100.0f), Color.White * hudOpenState, font: GUI.SmallFont);
|
||||
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder("GEST F ");
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
sb.Append(Rand.Range(0.0f, 1.0f) < cameraNoiseStrength ? ToolBox.RandomSeed(1) : "0");
|
||||
}
|
||||
GUI.DrawString(spriteBatch,
|
||||
new Vector2(rect.X + rect.Width * 0.8f, rect.Y + rect.Height * 0.96f),
|
||||
sb.ToString(), Color.White * hudOpenState, font: GUI.SmallFont);
|
||||
|
||||
frameSize = generationParams.DecorativeLineTop.FrameSize.ToVector2();
|
||||
generationParams.DecorativeLineTop.Draw(spriteBatch, (int)(hudOpenState * generationParams.DecorativeLineTop.FrameCount),
|
||||
new Vector2(rect.Right, rect.Y), Color.White, new Vector2(frameSize.X, frameSize.Y * 0.2f), 0,
|
||||
Vector2.Divide(new Vector2(rect.Width * 0.72f, rect.Height / 9), frameSize));
|
||||
frameSize = generationParams.DecorativeLineBottom.FrameSize.ToVector2();
|
||||
generationParams.DecorativeLineBottom.Draw(spriteBatch, (int)(hudOpenState * generationParams.DecorativeLineBottom.FrameCount),
|
||||
new Vector2(rect.X, rect.Bottom), Color.White, new Vector2(0, frameSize.Y * 0.6f), 0,
|
||||
Vector2.Divide(new Vector2(rect.Width * 0.72f, rect.Height / 9), frameSize));
|
||||
|
||||
frameSize = generationParams.DecorativeLineCorner.FrameSize.ToVector2();
|
||||
generationParams.DecorativeLineCorner.Draw(spriteBatch, (int)((hudOpenState + animPulsate) * generationParams.DecorativeLineCorner.FrameCount),
|
||||
new Vector2(rect.Right - rect.Width / 8, rect.Bottom), Color.White, frameSize * 0.8f, 0,
|
||||
Vector2.Divide(new Vector2(rect.Width / 4, rect.Height / 4), frameSize), spriteEffect: SpriteEffects.FlipVertically);
|
||||
|
||||
generationParams.DecorativeLineCorner.Draw(spriteBatch, (int)((hudOpenState + animPulsate) * generationParams.DecorativeLineCorner.FrameCount),
|
||||
new Vector2(rect.X + rect.Width / 8, rect.Y), Color.White, frameSize * 0.1f, 0,
|
||||
Vector2.Divide(new Vector2(rect.Width / 4, rect.Height / 4), frameSize), spriteEffect: SpriteEffects.FlipHorizontally);
|
||||
|
||||
//reticles
|
||||
generationParams.ReticleLarge.Draw(spriteBatch, (int)(subReticleAnimState * generationParams.ReticleLarge.FrameCount),
|
||||
rect.Center.ToVector2() + (subReticlePosition + drawOffset - drawOffsetNoise * 2) * zoom, Color.White,
|
||||
generationParams.ReticleLarge.Origin, 0, Vector2.One * (float)Math.Sqrt(zoom) * 0.4f);
|
||||
generationParams.ReticleMedium.Draw(spriteBatch, (int)(subReticleAnimState * generationParams.ReticleMedium.FrameCount),
|
||||
rect.Center.ToVector2() + (subReticlePosition + drawOffset - drawOffsetNoise) * zoom, Color.White,
|
||||
generationParams.ReticleMedium.Origin, 0, new Vector2(1.0f, 0.7f) * (float)Math.Sqrt(zoom) * 0.4f);
|
||||
|
||||
if (SelectedLocation != null)
|
||||
{
|
||||
generationParams.ReticleSmall.Draw(spriteBatch, (int)(targetReticleAnimState * generationParams.ReticleSmall.FrameCount),
|
||||
rect.Center.ToVector2() + (SelectedLocation.MapPosition + drawOffset + drawOffsetNoise * 2) * zoom, Color.White,
|
||||
generationParams.ReticleSmall.Origin, 0, new Vector2(1.0f, 0.7f) * (float)Math.Sqrt(zoom) * 0.4f);
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, GameMain.ScissorTestEnable);
|
||||
}
|
||||
|
||||
private void UpdateMapAnim(MapAnim anim, float deltaTime)
|
||||
{
|
||||
//pause animation while there are messageboxes on screen
|
||||
if (GUIMessageBox.MessageBoxes.Count > 0) return;
|
||||
|
||||
if (!string.IsNullOrEmpty(anim.StartMessage))
|
||||
{
|
||||
new GUIMessageBox("", anim.StartMessage);
|
||||
anim.StartMessage = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (anim.StartZoom == null) anim.StartZoom = zoom;
|
||||
if (anim.EndZoom == null) anim.EndZoom = zoom;
|
||||
|
||||
anim.StartPos = (anim.StartLocation == null) ? -drawOffset : anim.StartLocation.MapPosition;
|
||||
|
||||
|
||||
|
||||
anim.Timer = Math.Min(anim.Timer + deltaTime, anim.Duration);
|
||||
float t = anim.Duration <= 0.0f ? 1.0f : Math.Max(anim.Timer / anim.Duration, 0.0f);
|
||||
drawOffset = -Vector2.SmoothStep(anim.StartPos.Value, anim.EndLocation.MapPosition, t);
|
||||
drawOffset += new Vector2(
|
||||
(float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.3f % 255, Timing.TotalTime * 0.4f % 255, 0) - 0.5f,
|
||||
(float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.4f % 255, Timing.TotalTime * 0.3f % 255, 0.5f) - 0.5f) * 50.0f * (float)Math.Sin(t * MathHelper.Pi);
|
||||
|
||||
zoom = MathHelper.SmoothStep(anim.StartZoom.Value, anim.EndZoom.Value, t);
|
||||
|
||||
if (anim.Timer >= anim.Duration)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(anim.EndMessage))
|
||||
{
|
||||
new GUIMessageBox("", anim.EndMessage);
|
||||
anim.EndMessage = null;
|
||||
return;
|
||||
}
|
||||
anim.Finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
partial void RemoveProjSpecific()
|
||||
{
|
||||
rawNoiseSprite?.Remove();
|
||||
rawNoiseSprite = null;
|
||||
|
||||
rawNoiseTexture?.Dispose();
|
||||
rawNoiseTexture = null;
|
||||
|
||||
noiseTexture?.Dispose();
|
||||
noiseTexture = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace Barotrauma
|
||||
|
||||
protected static Vector2 startMovingPos = Vector2.Zero;
|
||||
|
||||
private static bool resizing;
|
||||
private int resizeDirX, resizeDirY;
|
||||
|
||||
//which entities have been selected for editing
|
||||
private static List<MapEntity> selectedList = new List<MapEntity>();
|
||||
public static List<MapEntity> SelectedList
|
||||
@@ -28,6 +31,9 @@ namespace Barotrauma
|
||||
|
||||
private static List<MapEntity> highlightedList = new List<MapEntity>();
|
||||
|
||||
// Test feature. Not yet saved.
|
||||
public static Dictionary<MapEntity, List<MapEntity>> SelectionGroups { get; private set; } = new Dictionary<MapEntity, List<MapEntity>>();
|
||||
|
||||
private static float highlightTimer;
|
||||
|
||||
private static GUIListBox highlightedListBox;
|
||||
@@ -64,6 +70,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool SelectableInEditor
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public static bool SelectedAny
|
||||
{
|
||||
get { return selectedList.Count > 0; }
|
||||
@@ -100,10 +111,10 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (GUIComponent.MouseOn != null || !PlayerInput.MouseInsideWindow)
|
||||
if (GUI.MouseOn != null || !PlayerInput.MouseInsideWindow)
|
||||
{
|
||||
if (highlightedListBox == null ||
|
||||
(GUIComponent.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUIComponent.MouseOn)))
|
||||
(GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn)))
|
||||
{
|
||||
UpdateHighlightedListBox(null);
|
||||
return;
|
||||
@@ -125,22 +136,18 @@ namespace Barotrauma
|
||||
|
||||
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
|
||||
{
|
||||
if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.C) &&
|
||||
PlayerInput.GetOldKeyboardState.IsKeyUp(Keys.C))
|
||||
if (PlayerInput.KeyHit(Keys.C))
|
||||
{
|
||||
CopyEntities(selectedList);
|
||||
}
|
||||
else if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.X) &&
|
||||
PlayerInput.GetOldKeyboardState.IsKeyUp(Keys.X))
|
||||
else if (PlayerInput.KeyHit(Keys.X))
|
||||
{
|
||||
CopyEntities(selectedList);
|
||||
|
||||
selectedList.ForEach(e => e.Remove());
|
||||
selectedList.Clear();
|
||||
}
|
||||
else if (copiedList.Count > 0 &&
|
||||
PlayerInput.GetKeyboardState.IsKeyDown(Keys.V) &&
|
||||
PlayerInput.GetOldKeyboardState.IsKeyUp(Keys.V))
|
||||
else if (copiedList.Count > 0 && PlayerInput.KeyHit(Keys.V))
|
||||
{
|
||||
List<MapEntity> prevEntities = new List<MapEntity>(mapEntityList);
|
||||
Clone(copiedList);
|
||||
@@ -160,6 +167,50 @@ namespace Barotrauma
|
||||
clone.Submarine = Submarine.MainSub;
|
||||
}
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.G))
|
||||
{
|
||||
if (selectedList.Any())
|
||||
{
|
||||
if (SelectionGroups.ContainsKey(selectedList.Last()))
|
||||
{
|
||||
// Ungroup all selected
|
||||
selectedList.ForEach(e => SelectionGroups.Remove(e));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var entity in selectedList)
|
||||
{
|
||||
// Remove the old group, if any
|
||||
SelectionGroups.Remove(entity);
|
||||
// Create a group that can be accessed with any member
|
||||
SelectionGroups.Add(entity, selectedList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.Z))
|
||||
{
|
||||
SetPreviousRects(e => e.rectMemento.Undo());
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.R))
|
||||
{
|
||||
SetPreviousRects(e => e.rectMemento.Redo());
|
||||
}
|
||||
void SetPreviousRects(Func<MapEntity, Rectangle> memoryMethod)
|
||||
{
|
||||
foreach (var e in SelectedList)
|
||||
{
|
||||
if (e.rectMemento != null)
|
||||
{
|
||||
Point diff = memoryMethod(e).Location - e.Rect.Location;
|
||||
// We have to call the move method, because there's a lot more than just storing the rect (in some cases)
|
||||
// We also have to reassign the rect, because the move method does not set the width and height. They might have changed too.
|
||||
// The Rect property is virtual and it's overridden for structs. Setting the rect via the property should automatically recreate the sections for resizable structures.
|
||||
e.Move(diff.ToVector2());
|
||||
e.Rect = e.rectMemento.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
@@ -169,9 +220,9 @@ namespace Barotrauma
|
||||
if (startMovingPos == Vector2.Zero)
|
||||
{
|
||||
List<MapEntity> highlightedEntities = new List<MapEntity>();
|
||||
if (highlightedListBox != null && highlightedListBox.IsParentOf(GUIComponent.MouseOn))
|
||||
if (highlightedListBox != null && highlightedListBox.IsParentOf(GUI.MouseOn))
|
||||
{
|
||||
highLightedEntity = GUIComponent.MouseOn.UserData as MapEntity;
|
||||
highLightedEntity = GUI.MouseOn.UserData as MapEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -184,7 +235,7 @@ namespace Barotrauma
|
||||
int i = 0;
|
||||
while (i < highlightedEntities.Count &&
|
||||
e.Sprite != null &&
|
||||
(highlightedEntities[i].Sprite == null || highlightedEntities[i].Sprite.Depth < e.Sprite.Depth))
|
||||
(highlightedEntities[i].Sprite == null || highlightedEntities[i].SpriteDepth < e.SpriteDepth))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
@@ -247,10 +298,11 @@ namespace Barotrauma
|
||||
//mouse released -> move the entities to the new position of the mouse
|
||||
|
||||
Vector2 moveAmount = position - startMovingPos;
|
||||
moveAmount = Submarine.VectorToWorldGrid(moveAmount);
|
||||
|
||||
if (moveAmount != Vector2.Zero)
|
||||
moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
|
||||
moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
|
||||
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y)
|
||||
{
|
||||
moveAmount = Submarine.VectorToWorldGrid(moveAmount);
|
||||
//clone
|
||||
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
|
||||
{
|
||||
@@ -260,10 +312,18 @@ namespace Barotrauma
|
||||
}
|
||||
else // move
|
||||
{
|
||||
foreach (MapEntity e in selectedList) e.Move(moveAmount);
|
||||
foreach (MapEntity e in selectedList)
|
||||
{
|
||||
if (e.rectMemento == null)
|
||||
{
|
||||
e.rectMemento = new Memento<Rectangle>();
|
||||
e.rectMemento.Store(e.Rect);
|
||||
}
|
||||
e.Move(moveAmount);
|
||||
e.rectMemento.Store(e.Rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startMovingPos = Vector2.Zero;
|
||||
}
|
||||
|
||||
@@ -281,7 +341,17 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (highLightedEntity != null) newSelection.Add(highLightedEntity);
|
||||
if (highLightedEntity != null)
|
||||
{
|
||||
if (SelectionGroups.TryGetValue(highLightedEntity, out List<MapEntity> group))
|
||||
{
|
||||
newSelection.AddRange(group);
|
||||
}
|
||||
else
|
||||
{
|
||||
newSelection.Add(highLightedEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PlayerInput.LeftButtonReleased())
|
||||
@@ -330,15 +400,17 @@ namespace Barotrauma
|
||||
{
|
||||
if (PlayerInput.LeftButtonHeld() &&
|
||||
PlayerInput.KeyUp(Keys.Space) &&
|
||||
(highlightedListBox == null || (GUIComponent.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUIComponent.MouseOn))))
|
||||
(highlightedListBox == null || (GUI.MouseOn != highlightedListBox && !highlightedListBox.IsParentOf(GUI.MouseOn))))
|
||||
{
|
||||
//if clicking a selected entity, start moving it
|
||||
foreach (MapEntity e in selectedList)
|
||||
{
|
||||
if (e.IsMouseOn(position)) startMovingPos = position;
|
||||
}
|
||||
|
||||
selectionPos = position;
|
||||
|
||||
//stop camera movement to prevent accidental dragging or rect selection
|
||||
Screen.Selected.Cam.StopMovement();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,23 +424,24 @@ namespace Barotrauma
|
||||
}
|
||||
if (highlightedListBox != null)
|
||||
{
|
||||
if (GUIComponent.MouseOn == highlightedListBox || highlightedListBox.IsParentOf(GUIComponent.MouseOn)) return;
|
||||
if (GUI.MouseOn == highlightedListBox || highlightedListBox.IsParentOf(GUI.MouseOn)) return;
|
||||
if (highlightedEntities.SequenceEqual(highlightedList)) return;
|
||||
}
|
||||
|
||||
highlightedList = highlightedEntities;
|
||||
|
||||
highlightedListBox = new GUIListBox(
|
||||
new Rectangle((int)PlayerInput.MousePosition.X + 15, (int)PlayerInput.MousePosition.Y + 15, 150, highlightedEntities.Count * 18 + 5),
|
||||
null, Alignment.TopLeft, "GUIToolTip", null, false);
|
||||
highlightedListBox = new GUIListBox(new RectTransform(new Point(180, highlightedEntities.Count * 18 + 5), GUI.Canvas)
|
||||
{
|
||||
ScreenSpaceOffset = PlayerInput.MousePosition.ToPoint() + new Point(15)
|
||||
}, style: "GUIToolTip");
|
||||
|
||||
foreach (MapEntity entity in highlightedEntities)
|
||||
{
|
||||
var textBlock = new GUITextBlock(
|
||||
new Rectangle(0, 0, highlightedListBox.Rect.Width, 18),
|
||||
ToolBox.LimitString(entity.Name, GUI.SmallFont, 140), "", Alignment.TopLeft, Alignment.CenterLeft, highlightedListBox, false, GUI.SmallFont);
|
||||
|
||||
textBlock.UserData = entity;
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Point(highlightedListBox.Content.Rect.Width, 15), highlightedListBox.Content.RectTransform),
|
||||
ToolBox.LimitString(entity.Name, GUI.SmallFont, 140), font: GUI.SmallFont)
|
||||
{
|
||||
UserData = entity
|
||||
};
|
||||
}
|
||||
|
||||
highlightedListBox.OnSelected = (GUIComponent component, object obj) =>
|
||||
@@ -391,14 +464,25 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static partial void UpdateAllProjSpecific(float deltaTime)
|
||||
{
|
||||
var entitiesToRender = Submarine.VisibleEntities ?? mapEntityList;
|
||||
foreach (MapEntity me in entitiesToRender)
|
||||
{
|
||||
if (me is Item item)
|
||||
{
|
||||
item.UpdateSpriteStates(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the "selection rectangle" and outlines of entities that are being dragged (if any)
|
||||
/// </summary>
|
||||
public static void DrawSelecting(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (GUIComponent.MouseOn != null) return;
|
||||
if (GUI.MouseOn != null) return;
|
||||
|
||||
Vector2 position = PlayerInput.MousePosition;
|
||||
position = cam.ScreenToWorld(position);
|
||||
@@ -406,10 +490,12 @@ namespace Barotrauma
|
||||
if (startMovingPos != Vector2.Zero)
|
||||
{
|
||||
Vector2 moveAmount = position - startMovingPos;
|
||||
moveAmount = Submarine.VectorToWorldGrid(moveAmount);
|
||||
moveAmount.Y = -moveAmount.Y;
|
||||
moveAmount.X = (float)(moveAmount.X > 0.0f ? Math.Floor(moveAmount.X / Submarine.GridSize.X) : Math.Ceiling(moveAmount.X / Submarine.GridSize.X)) * Submarine.GridSize.X;
|
||||
moveAmount.Y = (float)(moveAmount.Y > 0.0f ? Math.Floor(moveAmount.Y / Submarine.GridSize.Y) : Math.Ceiling(moveAmount.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y;
|
||||
|
||||
//started moving the selected entities
|
||||
if (moveAmount != Vector2.Zero)
|
||||
if (Math.Abs(moveAmount.X) >= Submarine.GridSize.X || Math.Abs(moveAmount.Y) >= Submarine.GridSize.Y)
|
||||
{
|
||||
foreach (MapEntity e in selectedList)
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
@@ -429,31 +515,67 @@ namespace Barotrauma
|
||||
|
||||
public static void UpdateEditor(Camera cam)
|
||||
{
|
||||
if (highlightedListBox != null) highlightedListBox.Update((float)Timing.Step);
|
||||
if (highlightedListBox != null) highlightedListBox.UpdateManually((float)Timing.Step);
|
||||
|
||||
if (editingHUD != null)
|
||||
{
|
||||
if (selectedList.Count == 0 || editingHUD.UserData != selectedList[0])
|
||||
{
|
||||
foreach (GUIComponent component in editingHUD.Children)
|
||||
{
|
||||
var textBox = component as GUITextBox;
|
||||
if (textBox == null) continue;
|
||||
textBox.Deselect();
|
||||
}
|
||||
editingHUD = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedList.Count == 0) return;
|
||||
|
||||
if (selectedList.Count == 1)
|
||||
{
|
||||
selectedList[0].UpdateEditing(cam);
|
||||
|
||||
if (selectedList[0].ResizeHorizontal || selectedList[0].ResizeVertical)
|
||||
{
|
||||
selectedList[0].UpdateResizing(cam);
|
||||
}
|
||||
}
|
||||
|
||||
if (editingHUD != null)
|
||||
if ((PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl)))
|
||||
{
|
||||
if (selectedList.Count == 0 || editingHUD.UserData != selectedList[0])
|
||||
//TODO: a UI button for flipping entities
|
||||
if (PlayerInput.KeyHit(Keys.N))
|
||||
{
|
||||
foreach (GUIComponent component in editingHUD.children)
|
||||
float minX = selectedList[0].WorldRect.X, maxX = selectedList[0].WorldRect.Right;
|
||||
for (int i = 0; i < selectedList.Count; i++)
|
||||
{
|
||||
var textBox = component as GUITextBox;
|
||||
if (textBox == null) continue;
|
||||
|
||||
textBox.Deselect();
|
||||
minX = Math.Min(minX, selectedList[i].WorldRect.X);
|
||||
maxX = Math.Max(maxX, selectedList[i].WorldRect.Right);
|
||||
}
|
||||
|
||||
editingHUD = null;
|
||||
float centerX = (minX + maxX) / 2.0f;
|
||||
foreach (MapEntity me in selectedList)
|
||||
{
|
||||
me.FlipX(false);
|
||||
me.Move(new Vector2((centerX - me.WorldPosition.X) * 2.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.M))
|
||||
{
|
||||
float minY = selectedList[0].WorldRect.Y - selectedList[0].WorldRect.Height, maxY = selectedList[0].WorldRect.Y;
|
||||
for (int i = 0; i < selectedList.Count; i++)
|
||||
{
|
||||
minY = Math.Min(minY, selectedList[i].WorldRect.Y - selectedList[i].WorldRect.Height);
|
||||
maxY = Math.Max(maxY, selectedList[i].WorldRect.Y);
|
||||
}
|
||||
|
||||
float centerY = (minY + maxY) / 2.0f;
|
||||
foreach (MapEntity me in selectedList)
|
||||
{
|
||||
me.FlipY(false);
|
||||
me.Move(new Vector2(0.0f, (centerY - me.WorldPosition.Y) * 2.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -472,7 +594,7 @@ namespace Barotrauma
|
||||
|
||||
if (highlightedListBox != null)
|
||||
{
|
||||
highlightedListBox.Draw(spriteBatch);
|
||||
highlightedListBox.DrawManually(spriteBatch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +614,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// copies a list of entities to the "clipboard" (copiedList)
|
||||
/// </summary>
|
||||
private static void CopyEntities(List<MapEntity> entities)
|
||||
public static List<MapEntity> CopyEntities(List<MapEntity> entities)
|
||||
{
|
||||
List<MapEntity> prevEntities = new List<MapEntity>(mapEntityList);
|
||||
|
||||
@@ -504,6 +626,8 @@ namespace Barotrauma
|
||||
//do a "shallow remove" (removes the entities from the game without removing links between them)
|
||||
// -> items will stay in their containers
|
||||
newEntities.ForEach(e => e.ShallowRemove());
|
||||
|
||||
return newEntities;
|
||||
}
|
||||
|
||||
public virtual void AddToGUIUpdateList()
|
||||
@@ -513,6 +637,42 @@ namespace Barotrauma
|
||||
|
||||
public virtual void UpdateEditing(Camera cam) { }
|
||||
|
||||
protected static void PositionEditingHUD()
|
||||
{
|
||||
int maxHeight = 100;
|
||||
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
editingHUD.RectTransform.SetPosition(Anchor.TopRight);
|
||||
editingHUD.RectTransform.AbsoluteOffset = new Point(0, GameMain.SubEditorScreen.TopPanel.Rect.Bottom);
|
||||
maxHeight = (GameMain.GraphicsHeight - GameMain.SubEditorScreen.EntityMenu.Rect.Height) - GameMain.SubEditorScreen.TopPanel.Rect.Bottom * 2 - 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
editingHUD.RectTransform.SetPosition(Anchor.TopRight);
|
||||
editingHUD.RectTransform.RelativeOffset = new Vector2(0.0f, (HUDLayoutSettings.InventoryAreaUpper.Bottom + 10.0f) / (editingHUD.RectTransform.Parent ?? GUI.Canvas).Rect.Height);
|
||||
maxHeight = HUDLayoutSettings.InventoryAreaLower.Bottom - HUDLayoutSettings.InventoryAreaLower.Y - 10;
|
||||
}
|
||||
|
||||
var listBox = editingHUD.GetChild<GUIListBox>();
|
||||
if (listBox != null)
|
||||
{
|
||||
int padding = 20;
|
||||
int contentHeight = 0;
|
||||
foreach (GUIComponent child in listBox.Content.Children)
|
||||
{
|
||||
contentHeight += child.Rect.Height + listBox.Spacing;
|
||||
child.RectTransform.MaxSize = new Point(int.MaxValue, child.Rect.Height);
|
||||
child.RectTransform.MinSize = new Point(0, child.Rect.Height);
|
||||
}
|
||||
|
||||
editingHUD.RectTransform.Resize(
|
||||
new Point(
|
||||
editingHUD.RectTransform.NonScaledSize.X,
|
||||
MathHelper.Clamp(contentHeight + padding * 2, 50, maxHeight)), resizeChildren: false);
|
||||
listBox.RectTransform.Resize(new Point(listBox.RectTransform.NonScaledSize.X, editingHUD.RectTransform.NonScaledSize.Y - padding * 2), resizeChildren: false);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DrawEditing(SpriteBatch spriteBatch, Camera cam) { }
|
||||
|
||||
private void UpdateResizing(Camera cam)
|
||||
@@ -542,6 +702,12 @@ namespace Barotrauma
|
||||
|
||||
if (resizing)
|
||||
{
|
||||
if (rectMemento == null)
|
||||
{
|
||||
rectMemento = new Memento<Rectangle>();
|
||||
rectMemento.Store(Rect);
|
||||
}
|
||||
|
||||
Vector2 placePosition = new Vector2(rect.X, rect.Y);
|
||||
Vector2 placeSize = new Vector2(rect.Width, rect.Height);
|
||||
|
||||
@@ -579,6 +745,7 @@ namespace Barotrauma
|
||||
|
||||
if (!PlayerInput.LeftButtonHeld())
|
||||
{
|
||||
rectMemento.Store(Rect);
|
||||
resizing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,18 +8,16 @@ namespace Barotrauma
|
||||
{
|
||||
public virtual void DrawPlacing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Vector2 placeSize = Submarine.GridSize;
|
||||
|
||||
if (placePosition == Vector2.Zero)
|
||||
{
|
||||
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
|
||||
|
||||
GUI.DrawLine(spriteBatch, new Vector2(position.X - GameMain.GraphicsWidth, -position.Y), new Vector2(position.X + GameMain.GraphicsWidth, -position.Y), Color.White, 0, (int)(2.0f / cam.Zoom));
|
||||
|
||||
GUI.DrawLine(spriteBatch, new Vector2(position.X, -(position.Y - GameMain.GraphicsHeight)), new Vector2(position.X, -(position.Y + GameMain.GraphicsHeight)), Color.White, 0, (int)(2.0f / cam.Zoom));
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 placeSize = Submarine.GridSize;
|
||||
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
|
||||
|
||||
if (ResizeHorizontal) placeSize.X = position.X - placePosition.X;
|
||||
@@ -39,6 +37,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DrawPlacing(SpriteBatch spriteBatch, Rectangle drawRect, float scale = 1.0f)
|
||||
{
|
||||
if (Submarine.MainSub != null)
|
||||
{
|
||||
drawRect.Location -= Submarine.MainSub.Position.ToPoint();
|
||||
}
|
||||
drawRect.Y = -drawRect.Y;
|
||||
GUI.DrawRectangle(spriteBatch, drawRect, Color.DarkBlue);
|
||||
}
|
||||
public void DrawListLine(SpriteBatch spriteBatch, Vector2 pos, Color color)
|
||||
{
|
||||
GUI.Font.DrawString(spriteBatch, name, pos, color);
|
||||
|
||||
@@ -15,10 +15,22 @@ namespace Barotrauma
|
||||
|
||||
partial class Structure : MapEntity, IDamageable, IServerSerializable
|
||||
{
|
||||
public static bool ShowWalls = true, ShowStructures = true;
|
||||
|
||||
private List<ConvexHull> convexHulls;
|
||||
|
||||
public override bool SelectableInEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return HasBody ? ShowWalls : ShowStructures;;
|
||||
}
|
||||
}
|
||||
|
||||
// Only for testing in the debug build. Not saved.
|
||||
protected Vector2 textureScale = Vector2.One;
|
||||
[Editable, Serialize("1.0, 1.0", true)]
|
||||
|
||||
[Editable(DecimalCount = 3, MinValueFloat = 0.01f, MaxValueFloat = 10f, ValueStep = 0.1f), Serialize("1.0, 1.0", false)]
|
||||
public Vector2 TextureScale
|
||||
{
|
||||
get { return textureScale; }
|
||||
@@ -29,61 +41,42 @@ namespace Barotrauma
|
||||
MathHelper.Clamp(value.Y, 0.01f, 10));
|
||||
}
|
||||
}
|
||||
|
||||
// Only for testing in the debug build. Not saved.
|
||||
#if DEBUG
|
||||
[Editable, Serialize(true, false)]
|
||||
#endif
|
||||
public bool DrawTiled { get; protected set; } = true;
|
||||
|
||||
protected Vector2 textureOffset = Vector2.Zero;
|
||||
[Editable, Serialize("0.0, 0.0", true)]
|
||||
[Editable(MinValueFloat = -1000f, MaxValueFloat = 1000f, ValueStep = 10f), Serialize("0.0, 0.0", true)]
|
||||
public Vector2 TextureOffset
|
||||
{
|
||||
get { return textureOffset; }
|
||||
set { textureOffset = value; }
|
||||
}
|
||||
|
||||
private void GenerateConvexHull()
|
||||
|
||||
partial void CreateConvexHull(Vector2 position, Vector2 size, float rotation)
|
||||
{
|
||||
// If not null and not empty , remove the hulls from the system
|
||||
if (convexHulls != null && convexHulls.Any())
|
||||
convexHulls.ForEach(x => x.Remove());
|
||||
if (!CastShadow) { return; }
|
||||
|
||||
// list all of hulls for this structure
|
||||
convexHulls = new List<ConvexHull>();
|
||||
|
||||
var mergedSections = new List<WallSection>();
|
||||
foreach (var section in sections)
|
||||
if (convexHulls == null)
|
||||
{
|
||||
if (mergedSections.Count > 5)
|
||||
{
|
||||
mergedSections.Add(section);
|
||||
GenerateMergedHull(mergedSections);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if there is a gap and we have sections to merge, do it.
|
||||
if (section.gap != null)
|
||||
{
|
||||
GenerateMergedHull(mergedSections);
|
||||
}
|
||||
else
|
||||
{
|
||||
mergedSections.Add(section);
|
||||
}
|
||||
convexHulls = new List<ConvexHull>();
|
||||
}
|
||||
|
||||
// take care of any leftover pieces
|
||||
if (mergedSections.Count > 0)
|
||||
Vector2 halfSize = size / 2;
|
||||
Vector2[] verts = new Vector2[]
|
||||
{
|
||||
GenerateMergedHull(mergedSections);
|
||||
}
|
||||
}
|
||||
position + new Vector2(-halfSize.X, halfSize.Y),
|
||||
position + new Vector2(halfSize.X, halfSize.Y),
|
||||
position + new Vector2(halfSize.X, -halfSize.Y),
|
||||
position + new Vector2(-halfSize.X, -halfSize.Y),
|
||||
};
|
||||
|
||||
private void GenerateMergedHull(List<WallSection> mergedSections)
|
||||
{
|
||||
if (!mergedSections.Any()) return;
|
||||
Rectangle mergedRect = GenerateMergedRect(mergedSections);
|
||||
|
||||
var h = new ConvexHull(CalculateExtremes(mergedRect), Color.Black, this);
|
||||
mergedSections.ForEach(x => x.hull = h);
|
||||
var h = new ConvexHull(verts, Color.Black, this);
|
||||
h.Rotate(position, rotation);
|
||||
convexHulls.Add(h);
|
||||
mergedSections.Clear();
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam)
|
||||
@@ -91,35 +84,36 @@ namespace Barotrauma
|
||||
if (editingHUD == null || editingHUD.UserData as Structure != this)
|
||||
{
|
||||
editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen);
|
||||
}
|
||||
|
||||
editingHUD.Update((float)Timing.Step);
|
||||
}
|
||||
}
|
||||
|
||||
private GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
{
|
||||
int width = 450;
|
||||
int height = 150;
|
||||
int x = GameMain.GraphicsWidth / 2 - width / 2, y = 30;
|
||||
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
|
||||
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.8f), editingHUD.RectTransform, Anchor.Center), style: null);
|
||||
var editor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, elementHeight: 20);
|
||||
var reloadTextureButton = new GUIButton(new RectTransform(new Point(editingHUD.Rect.Width / 2, 20)), "Reload Texture");
|
||||
reloadTextureButton.OnClicked += (button, data) =>
|
||||
{
|
||||
Sprite.ReloadTexture();
|
||||
Sprite.ReloadXML();
|
||||
return true;
|
||||
};
|
||||
editor.AddCustomContent(reloadTextureButton, editor.ContentCount);
|
||||
|
||||
editingHUD = new GUIListBox(new Rectangle(x, y, width, height), "");
|
||||
editingHUD.UserData = this;
|
||||
|
||||
new SerializableEntityEditor(this, inGame, editingHUD, true);
|
||||
|
||||
editingHUD.SetDimensions(new Point(editingHUD.Rect.Width, MathHelper.Clamp(editingHUD.children.Sum(c => c.Rect.Height), 50, editingHUD.Rect.Height)));
|
||||
PositionEditingHUD();
|
||||
|
||||
return editingHUD;
|
||||
}
|
||||
|
||||
public override void DrawEditing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (editingHUD != null && editingHUD.UserData == this) editingHUD.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
|
||||
{
|
||||
if (prefab.sprite == null) return;
|
||||
if (editing)
|
||||
{
|
||||
if (!HasBody && !ShowStructures) return;
|
||||
if (HasBody && !ShowWalls) return;
|
||||
}
|
||||
|
||||
Draw(spriteBatch, editing, back, null);
|
||||
}
|
||||
@@ -128,69 +122,140 @@ namespace Barotrauma
|
||||
{
|
||||
Draw(spriteBatch, false, false, damageEffect);
|
||||
}
|
||||
|
||||
|
||||
private void Draw(SpriteBatch spriteBatch, bool editing, bool back = true, Effect damageEffect = null)
|
||||
{
|
||||
if (prefab.sprite == null) return;
|
||||
if (editing)
|
||||
{
|
||||
if (!HasBody && !ShowStructures) return;
|
||||
if (HasBody && !ShowWalls) return;
|
||||
}
|
||||
|
||||
Color color = (isHighlighted) ? Color.Orange : spriteColor;
|
||||
Color color = isHighlighted ? Color.Orange : spriteColor;
|
||||
if (IsSelected && editing)
|
||||
{
|
||||
color = Color.Red;
|
||||
//color = Color.Lerp(color, Color.Gold, 0.5f);
|
||||
color = spriteColor;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, -rect.Y, rect.Width, rect.Height), color);
|
||||
Vector2 rectSize = rect.Size.ToVector2();
|
||||
if (BodyWidth > 0.0f) { rectSize.X = BodyWidth; }
|
||||
if (BodyHeight > 0.0f) { rectSize.Y = BodyHeight; }
|
||||
|
||||
Vector2 bodyPos = WorldPosition + BodyOffset;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(bodyPos.X, -bodyPos.Y), rectSize.X, rectSize.Y, BodyRotation, Color.White,
|
||||
thickness: Math.Max(1, (int)(2 / Screen.Selected.Cam.Zoom)));
|
||||
}
|
||||
|
||||
Vector2 drawOffset = Submarine == null ? Vector2.Zero : Submarine.DrawPosition;
|
||||
|
||||
float depth = prefab.sprite.Depth;
|
||||
float depth = SpriteDepthOverrideIsSet ? SpriteOverrideDepth : prefab.sprite.Depth;
|
||||
depth -= (ID % 255) * 0.000001f;
|
||||
|
||||
Vector2 textureOffset = this.textureOffset;
|
||||
if (flippedX) textureOffset.X = -textureOffset.X;
|
||||
if (flippedY) textureOffset.Y = -textureOffset.Y;
|
||||
|
||||
if (FlippedX) textureOffset.X = -textureOffset.X;
|
||||
if (FlippedY) textureOffset.Y = -textureOffset.Y;
|
||||
|
||||
if (back && damageEffect == null)
|
||||
{
|
||||
if (prefab.BackgroundSprite != null)
|
||||
{
|
||||
SpriteEffects oldEffects = prefab.BackgroundSprite.effects;
|
||||
prefab.BackgroundSprite.effects ^= SpriteEffects;
|
||||
bool drawDropShadow = Submarine != null && HasBody;
|
||||
Vector2 dropShadowOffset = Vector2.Zero;
|
||||
if (drawDropShadow)
|
||||
{
|
||||
dropShadowOffset = Submarine.WorldPosition - WorldPosition;
|
||||
if (dropShadowOffset != Vector2.Zero)
|
||||
{
|
||||
if (IsHorizontal)
|
||||
{
|
||||
dropShadowOffset = new Vector2(0.0f, Math.Sign(dropShadowOffset.Y) * 10.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
dropShadowOffset = new Vector2(Math.Sign(dropShadowOffset.X) * 10.0f, 0.0f);
|
||||
}
|
||||
dropShadowOffset.Y = -dropShadowOffset.Y;
|
||||
}
|
||||
}
|
||||
|
||||
Point backGroundOffset = new Point(
|
||||
MathUtils.PositiveModulo((int)-textureOffset.X, prefab.BackgroundSprite.SourceRect.Width),
|
||||
MathUtils.PositiveModulo((int)-textureOffset.Y, prefab.BackgroundSprite.SourceRect.Height));
|
||||
if (DrawTiled)
|
||||
{
|
||||
SpriteEffects oldEffects = prefab.BackgroundSprite.effects;
|
||||
prefab.BackgroundSprite.effects ^= SpriteEffects;
|
||||
|
||||
prefab.BackgroundSprite.DrawTiled(
|
||||
spriteBatch,
|
||||
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
|
||||
new Vector2(rect.Width, rect.Height),
|
||||
color: color,
|
||||
textureScale: TextureScale,
|
||||
startOffset: backGroundOffset);
|
||||
Point backGroundOffset = new Point(
|
||||
MathUtils.PositiveModulo((int)-textureOffset.X, prefab.BackgroundSprite.SourceRect.Width),
|
||||
MathUtils.PositiveModulo((int)-textureOffset.Y, prefab.BackgroundSprite.SourceRect.Height));
|
||||
|
||||
prefab.BackgroundSprite.effects = oldEffects;
|
||||
prefab.BackgroundSprite.DrawTiled(
|
||||
spriteBatch,
|
||||
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
|
||||
new Vector2(rect.Width, rect.Height),
|
||||
color: color,
|
||||
textureScale: TextureScale * Scale,
|
||||
startOffset: backGroundOffset);
|
||||
|
||||
if (drawDropShadow)
|
||||
{
|
||||
prefab.BackgroundSprite.DrawTiled(
|
||||
spriteBatch,
|
||||
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)) + dropShadowOffset,
|
||||
new Vector2(rect.Width, rect.Height),
|
||||
color: Color.Black * 0.5f,
|
||||
textureScale: TextureScale * Scale,
|
||||
startOffset: backGroundOffset,
|
||||
depth: (depth + prefab.BackgroundSprite.Depth) / 2.0f);
|
||||
}
|
||||
|
||||
prefab.BackgroundSprite.effects = oldEffects;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefab.BackgroundSprite.Draw(
|
||||
spriteBatch,
|
||||
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
|
||||
color,
|
||||
Vector2.Zero,
|
||||
scale: Scale,
|
||||
rotate: 0,
|
||||
spriteEffect: SpriteEffects);
|
||||
|
||||
if (drawDropShadow)
|
||||
{
|
||||
prefab.BackgroundSprite.Draw(
|
||||
spriteBatch,
|
||||
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)) + dropShadowOffset,
|
||||
Color.Black * 0.5f,
|
||||
Vector2.Zero,
|
||||
scale: Scale,
|
||||
rotate: 0,
|
||||
spriteEffect: SpriteEffects,
|
||||
depth: (depth + prefab.BackgroundSprite.Depth) / 2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (back == prefab.sprite.Depth > 0.5f || editing)
|
||||
if (back == depth > 0.5f || editing)
|
||||
{
|
||||
SpriteEffects oldEffects = prefab.sprite.effects;
|
||||
prefab.sprite.effects ^= SpriteEffects;
|
||||
|
||||
for (int i = 0; i < sections.Length; i++)
|
||||
for (int i = 0; i < Sections.Length; i++)
|
||||
{
|
||||
if (damageEffect != null)
|
||||
{
|
||||
float newCutoff = sections[i].damage > 0 ?
|
||||
MathHelper.Lerp(0.2f, 0.65f, sections[i].damage / prefab.Health) : 0.0f;
|
||||
float newCutoff = Sections[i].damage > 0 ?
|
||||
MathHelper.Lerp(0.2f, 0.65f, Sections[i].damage / prefab.Health) : 0.0f;
|
||||
|
||||
if (Math.Abs(newCutoff - Submarine.DamageEffectCutoff) > 0.01f || color != Submarine.DamageEffectColor)
|
||||
{
|
||||
damageEffect.Parameters["aCutoff"].SetValue(newCutoff);
|
||||
damageEffect.Parameters["cCutoff"].SetValue(newCutoff * 1.2f);
|
||||
damageEffect.Parameters["inColor"].SetValue(color.ToVector4());
|
||||
|
||||
|
||||
damageEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
Submarine.DamageEffectCutoff = newCutoff;
|
||||
@@ -198,28 +263,59 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Point sectionOffset = new Point(
|
||||
Math.Abs(rect.Location.X - sections[i].rect.Location.X),
|
||||
Math.Abs(rect.Location.Y - sections[i].rect.Location.Y));
|
||||
|
||||
if (flippedX && isHorizontal) sectionOffset.X = sections[i].rect.Right - rect.Right;
|
||||
if (flippedY && !isHorizontal) sectionOffset.Y = (rect.Y - rect.Height) - (sections[i].rect.Y - sections[i].rect.Height);
|
||||
if (DrawTiled)
|
||||
{
|
||||
Point sectionOffset = new Point(
|
||||
Math.Abs(rect.Location.X - Sections[i].rect.Location.X),
|
||||
Math.Abs(rect.Location.Y - Sections[i].rect.Location.Y));
|
||||
|
||||
sectionOffset.X += MathUtils.PositiveModulo((int)-textureOffset.X, prefab.sprite.SourceRect.Width);
|
||||
sectionOffset.Y += MathUtils.PositiveModulo((int)-textureOffset.Y, prefab.sprite.SourceRect.Height);
|
||||
if (FlippedX && IsHorizontal) sectionOffset.X = Sections[i].rect.Right - rect.Right;
|
||||
if (FlippedY && !IsHorizontal) sectionOffset.Y = (rect.Y - rect.Height) - (Sections[i].rect.Y - Sections[i].rect.Height);
|
||||
|
||||
prefab.sprite.DrawTiled(
|
||||
spriteBatch,
|
||||
new Vector2(sections[i].rect.X + drawOffset.X, -(sections[i].rect.Y + drawOffset.Y)),
|
||||
new Vector2(sections[i].rect.Width, sections[i].rect.Height),
|
||||
color: spriteColor,
|
||||
startOffset: sectionOffset,
|
||||
depth: depth,
|
||||
textureScale: TextureScale);
|
||||
sectionOffset.X += MathUtils.PositiveModulo((int)-textureOffset.X, prefab.sprite.SourceRect.Width);
|
||||
sectionOffset.Y += MathUtils.PositiveModulo((int)-textureOffset.Y, prefab.sprite.SourceRect.Height);
|
||||
|
||||
prefab.sprite.DrawTiled(
|
||||
spriteBatch,
|
||||
new Vector2(Sections[i].rect.X + drawOffset.X, -(Sections[i].rect.Y + drawOffset.Y)),
|
||||
new Vector2(Sections[i].rect.Width, Sections[i].rect.Height),
|
||||
color: color,
|
||||
startOffset: sectionOffset,
|
||||
depth: depth,
|
||||
textureScale: TextureScale * Scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
prefab.sprite.Draw(
|
||||
spriteBatch,
|
||||
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
|
||||
color,
|
||||
Vector2.Zero,
|
||||
scale: Scale,
|
||||
rotate: 0,
|
||||
spriteEffect: SpriteEffects);
|
||||
}
|
||||
}
|
||||
|
||||
prefab.sprite.effects = oldEffects;
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
if (Bodies != null)
|
||||
{
|
||||
for (int i = 0; i < Bodies.Count; i++)
|
||||
{
|
||||
Vector2 pos = FarseerPhysics.ConvertUnits.ToDisplayUnits(Bodies[i].Position);
|
||||
if (Submarine != null) pos += Submarine.Position;
|
||||
pos.Y = -pos.Y;
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
pos,
|
||||
FarseerPhysics.ConvertUnits.ToDisplayUnits(bodyDebugDimensions[i].X),
|
||||
FarseerPhysics.ConvertUnits.ToDisplayUnits(bodyDebugDimensions[i].Y),
|
||||
-Bodies[i].Rotation, Color.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ namespace Barotrauma
|
||||
public override void DrawPlacing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
|
||||
//Vector2 placeSize = size;
|
||||
|
||||
Rectangle newRect = new Rectangle((int)position.X, (int)position.Y, (int)size.X, (int)size.Y);
|
||||
|
||||
Rectangle newRect = new Rectangle((int)position.X, (int)position.Y, (int)ScaledSize.X, (int)ScaledSize.Y);
|
||||
|
||||
if (placePosition == Vector2.Zero)
|
||||
{
|
||||
@@ -20,22 +17,25 @@ namespace Barotrauma
|
||||
|
||||
newRect.X = (int)position.X;
|
||||
newRect.Y = (int)position.Y;
|
||||
|
||||
//sprite.Draw(spriteBatch, new Vector2(position.X, -position.Y), placeSize, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 placeSize = size;
|
||||
Vector2 placeSize = ScaledSize;
|
||||
if (ResizeHorizontal) placeSize.X = position.X - placePosition.X;
|
||||
if (ResizeVertical) placeSize.Y = placePosition.Y - position.Y;
|
||||
|
||||
newRect = Submarine.AbsRect(placePosition, placeSize);
|
||||
}
|
||||
|
||||
sprite.DrawTiled(spriteBatch, new Vector2(newRect.X, -newRect.Y), new Vector2(newRect.Width, newRect.Height));
|
||||
|
||||
sprite.DrawTiled(spriteBatch, new Vector2(newRect.X, -newRect.Y), new Vector2(newRect.Width, newRect.Height), textureScale: TextureScale * Scale);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(newRect.X - GameMain.GraphicsWidth, -newRect.Y, newRect.Width + GameMain.GraphicsWidth * 2, newRect.Height), Color.White);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(newRect.X, -newRect.Y - GameMain.GraphicsHeight, newRect.Width, newRect.Height + GameMain.GraphicsHeight * 2), Color.White);
|
||||
}
|
||||
|
||||
public override void DrawPlacing(SpriteBatch spriteBatch, Rectangle placeRect, float scale = 1.0f)
|
||||
{
|
||||
// TODO: the scale property is not used
|
||||
sprite.DrawTiled(spriteBatch, new Vector2(placeRect.X, -placeRect.Y), new Vector2(placeRect.Width, placeRect.Height), textureScale: TextureScale * Scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Sounds;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -7,13 +8,90 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class RoundSound
|
||||
{
|
||||
public Sound Sound;
|
||||
public readonly float Volume;
|
||||
public readonly float Range;
|
||||
public readonly bool Stream;
|
||||
|
||||
public string Filename
|
||||
{
|
||||
get { return Sound.Filename; }
|
||||
}
|
||||
|
||||
public RoundSound(XElement element, Sound sound)
|
||||
{
|
||||
Sound = sound;
|
||||
Stream = sound.Stream;
|
||||
Range = element.GetAttributeFloat("range", 1000.0f);
|
||||
Volume = element.GetAttributeFloat("volume", 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
partial class Submarine : Entity, IServerSerializable
|
||||
{
|
||||
public Sprite PreviewImage;
|
||||
|
||||
private static List<RoundSound> roundSounds = null;
|
||||
public static RoundSound LoadRoundSound(XElement element, bool stream=false)
|
||||
{
|
||||
string filename = element.GetAttributeString("file", "");
|
||||
if (string.IsNullOrEmpty(filename)) filename = element.GetAttributeString("sound", "");
|
||||
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
DebugConsole.ThrowError("Error when loading round sound (" + element + ") - file path not set");
|
||||
return null;
|
||||
}
|
||||
|
||||
filename = Path.GetFullPath(filename);
|
||||
Sound existingSound = null;
|
||||
if (roundSounds == null)
|
||||
{
|
||||
roundSounds = new List<RoundSound>();
|
||||
}
|
||||
else
|
||||
{
|
||||
existingSound = roundSounds.Find(s => s.Filename == filename && s.Stream == stream)?.Sound;
|
||||
}
|
||||
|
||||
if (existingSound == null)
|
||||
{
|
||||
existingSound = GameMain.SoundManager.LoadSound(filename, stream);
|
||||
}
|
||||
|
||||
RoundSound newSound = new RoundSound(element, existingSound);
|
||||
|
||||
roundSounds.Add(newSound);
|
||||
return newSound;
|
||||
}
|
||||
|
||||
private static void RemoveRoundSound(RoundSound roundSound)
|
||||
{
|
||||
roundSound.Sound?.Dispose();
|
||||
if (roundSounds == null) return;
|
||||
|
||||
if (roundSounds.Contains(roundSound)) roundSounds.Remove(roundSound);
|
||||
foreach (RoundSound otherSound in roundSounds)
|
||||
{
|
||||
if (otherSound.Sound == roundSound.Sound) otherSound.Sound = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveAllRoundSounds()
|
||||
{
|
||||
if (roundSounds == null) return;
|
||||
for (int i = roundSounds.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RemoveRoundSound(roundSounds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Draw(SpriteBatch spriteBatch, bool editing = false)
|
||||
{
|
||||
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList;
|
||||
@@ -118,46 +196,103 @@ namespace Barotrauma
|
||||
return MainSub.SaveAs(filePath, previewImage);
|
||||
}
|
||||
|
||||
public void CreatePreviewWindow(GUIComponent frame)
|
||||
public void CreatePreviewWindow(GUIMessageBox messageBox)
|
||||
{
|
||||
new GUITextBlock(new Rectangle(0, 0, 0, 20), Name, "", Alignment.TopCenter, Alignment.TopCenter, frame, true, GUI.LargeFont);
|
||||
var background = new GUIButton(new RectTransform(Vector2.One, messageBox.RectTransform), style: "GUIBackgroundBlocker")
|
||||
{
|
||||
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) messageBox.Close(); return true; }
|
||||
};
|
||||
background.RectTransform.SetAsFirstChild();
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), messageBox.Content.RectTransform, Anchor.TopCenter), Name, textAlignment: Alignment.Center, font: GUI.LargeFont, wrap: true);
|
||||
|
||||
var upperPart = new GUIFrame(new RectTransform(new Vector2(1, 0.4f), messageBox.Content.RectTransform, Anchor.Center, Pivot.BottomCenter), color: Color.Transparent);
|
||||
var descriptionBox = new GUIListBox(new RectTransform(new Vector2(1, 0.35f), messageBox.Content.RectTransform, Anchor.Center, Pivot.TopCenter));
|
||||
|
||||
if (PreviewImage == null)
|
||||
{
|
||||
var txtBlock = new GUITextBlock(new Rectangle(-20, 60, 256, 128), TextManager.Get("SubPreviewImageNotFound"), Color.Black * 0.5f, null, Alignment.Center, "", frame, true);
|
||||
txtBlock.OutlineColor = txtBlock.TextColor;
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.45f, 1), upperPart.RectTransform), TextManager.Get("SubPreviewImageNotFound"));
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUIImage(new Rectangle(-10, 60, 256, 128), PreviewImage, Alignment.TopLeft, frame);
|
||||
new GUIImage(new RectTransform(new Vector2(0.45f, 1), upperPart.RectTransform), PreviewImage);
|
||||
}
|
||||
|
||||
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
|
||||
string dimensionsStr = realWorldDimensions == Vector2.Zero ?
|
||||
TextManager.Get("Unknown") :
|
||||
TextManager.Get("DimensionsFormat").Replace("[width]", ((int)(realWorldDimensions.X)).ToString()).Replace("[height]", ((int)(realWorldDimensions.Y)).ToString());
|
||||
|
||||
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1), upperPart.RectTransform, Anchor.TopRight));
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
|
||||
$"{TextManager.Get("Dimensions")}: {dimensionsStr}",
|
||||
font: GUI.SmallFont, wrap: true);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
|
||||
$"{TextManager.Get("RecommendedCrewSize")}: {(RecommendedCrewSizeMax == 0 ? TextManager.Get("Unknown") : RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax)}",
|
||||
font: GUI.SmallFont, wrap: true);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
|
||||
$"{TextManager.Get("RecommendedCrewExperience")}: {(string.IsNullOrEmpty(RecommendedCrewExperience) ? TextManager.Get("unknown") : TextManager.Get(RecommendedCrewExperience))}",
|
||||
font: GUI.SmallFont, wrap: true);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
|
||||
$"{TextManager.Get("RequiredContentPackages")}: {string.Join(", ", RequiredContentPackages)}",
|
||||
font: GUI.SmallFont, wrap: true);
|
||||
|
||||
new GUITextBlock(new Rectangle(246, 60, 100, 20),
|
||||
TextManager.Get("Dimensions") + ": " + dimensionsStr,
|
||||
"", frame, GUI.SmallFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform, Anchor.TopLeft), Description, font: GUI.SmallFont, wrap: true)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
new GUITextBlock(new Rectangle(246, 80, 100, 20),
|
||||
TextManager.Get("RecommendedCrewSize") + ": " + (RecommendedCrewSizeMax == 0 ? TextManager.Get("Unknown") : RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax),
|
||||
"", frame, GUI.SmallFont);
|
||||
public void CreateMiniMap(GUIComponent parent, IEnumerable<Entity> pointsOfInterest = null)
|
||||
{
|
||||
Rectangle worldBorders = GetDockedBorders();
|
||||
worldBorders.Location += WorldPosition.ToPoint();
|
||||
|
||||
new GUITextBlock(new Rectangle(246, 100, 100, 20),
|
||||
TextManager.Get("RecommendedCrewExperience") + ": " + (string.IsNullOrEmpty(RecommendedCrewExperience) ? TextManager.Get("unknown") : TextManager.Get(RecommendedCrewExperience)),
|
||||
"", frame, GUI.SmallFont);
|
||||
//create a container that has the same "aspect ratio" as the sub
|
||||
float aspectRatio = worldBorders.Width / (float)worldBorders.Height;
|
||||
float parentAspectRatio = parent.Rect.Width / (float)parent.Rect.Height;
|
||||
|
||||
new GUITextBlock(new Rectangle(246, 120, 0, 20),
|
||||
TextManager.Get("CompatibleContentPackages") + ":\n" + string.Join(", ", CompatibleContentPackages),
|
||||
"", Alignment.TopLeft, Alignment.TopLeft, frame, true, GUI.SmallFont);
|
||||
float scale = 0.9f;
|
||||
|
||||
var descrBox = new GUIListBox(new Rectangle(0, 200, 0, 120), "", frame);
|
||||
GUIFrame hullContainer = new GUIFrame(new RectTransform(
|
||||
(parentAspectRatio > aspectRatio ? new Vector2(aspectRatio / parentAspectRatio, 1.0f) : new Vector2(1.0f, parentAspectRatio / aspectRatio)) * scale,
|
||||
parent.RectTransform, Anchor.Center),
|
||||
style: null);
|
||||
|
||||
var descr = new GUITextBlock(new Rectangle(0, 0, descrBox.Rect.Width - 15, 0), Description + "\n", "", Alignment.TopLeft, Alignment.TopLeft, null, true, GUI.SmallFont);
|
||||
descrBox.AddChild(descr);
|
||||
descr.CanBeFocused = false;
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.Submarine != this && !DockedTo.Contains(hull.Submarine)) continue;
|
||||
|
||||
Vector2 relativeHullPos = new Vector2(
|
||||
(hull.WorldRect.X - worldBorders.X) / (float)worldBorders.Width,
|
||||
(worldBorders.Y - hull.WorldRect.Y) / (float)worldBorders.Height);
|
||||
Vector2 relativeHullSize = new Vector2(hull.Rect.Width / (float)worldBorders.Width, hull.Rect.Height / (float)worldBorders.Height);
|
||||
|
||||
var hullFrame = new GUIFrame(new RectTransform(relativeHullSize, hullContainer.RectTransform) { RelativeOffset = relativeHullPos }, style: "MiniMapRoom", color: Color.DarkCyan * 0.8f)
|
||||
{
|
||||
UserData = hull
|
||||
};
|
||||
new GUIFrame(new RectTransform(Vector2.One, hullFrame.RectTransform), style: "ScanLines", color: Color.DarkCyan * 0.8f);
|
||||
}
|
||||
|
||||
if (pointsOfInterest != null)
|
||||
{
|
||||
foreach (Entity entity in pointsOfInterest)
|
||||
{
|
||||
Vector2 relativePos = new Vector2(
|
||||
(entity.WorldPosition.X - worldBorders.X) / Borders.Width,
|
||||
(worldBorders.Y - entity.WorldPosition.Y) / Borders.Height);
|
||||
new GUIFrame(new RectTransform(new Point(1, 1), hullContainer.RectTransform) { RelativeOffset = relativePos }, style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
UserData = entity
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckForErrors()
|
||||
@@ -190,11 +325,28 @@ namespace Barotrauma
|
||||
errorMsgs.Add(TextManager.Get("NoCargoSpawnpointWarning"));
|
||||
}
|
||||
|
||||
if (!Item.ItemList.Any(it => it.GetComponent<Items.Components.Pump>() != null && it.HasTag("ballast")))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoBallastTagsWarning"));
|
||||
}
|
||||
|
||||
if (errorMsgs.Any())
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("Warning"), string.Join("\n\n", errorMsgs), 400, 0);
|
||||
}
|
||||
|
||||
foreach (MapEntity e in MapEntity.mapEntityList)
|
||||
{
|
||||
if (Vector2.Distance(e.Position, HiddenSubPosition) > 20000)
|
||||
{
|
||||
//move disabled items (wires, items inside containers) inside the sub
|
||||
if (e is Item item && item.body != null && !item.body.Enabled)
|
||||
{
|
||||
item.SetTransform(ConvertUnits.ToSimUnits(HiddenSubPosition), 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapEntity e in MapEntity.mapEntityList)
|
||||
{
|
||||
if (Vector2.Distance(e.Position, HiddenSubPosition) > 20000)
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Barotrauma
|
||||
GUI.DrawLine(spriteBatch,
|
||||
drawPos,
|
||||
new Vector2(e.DrawPosition.X, -e.DrawPosition.Y),
|
||||
Color.Green);
|
||||
Color.Green, width: 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,9 +67,7 @@ namespace Barotrauma
|
||||
{
|
||||
editingHUD = CreateEditingHUD();
|
||||
}
|
||||
|
||||
editingHUD.Update((float)Timing.Step);
|
||||
|
||||
|
||||
if (PlayerInput.LeftButtonClicked())
|
||||
{
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
@@ -87,14 +85,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawEditing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (editingHUD != null) editingHUD.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
private bool ChangeSpawnType(GUIButton button, object obj)
|
||||
{
|
||||
GUITextBlock spawnTypeText = button.Parent as GUITextBlock;
|
||||
GUITextBlock spawnTypeText = button.Parent.GetChildByUserData("spawntypetext") as GUITextBlock;
|
||||
|
||||
spawnType += (int)button.UserData;
|
||||
|
||||
@@ -119,30 +112,12 @@ namespace Barotrauma
|
||||
private bool EnterIDCardTags(GUITextBox textBox, string text)
|
||||
{
|
||||
IdCardTags = text.Split(',');
|
||||
textBox.Text = text;
|
||||
textBox.Color = Color.Green;
|
||||
|
||||
textBox.Text = string.Join(",", IdCardTags);
|
||||
textBox.Flash(Color.Green);
|
||||
textBox.Deselect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool EnterAssignedJob(GUITextBox textBox, string text)
|
||||
{
|
||||
string trimmedName = text.ToLowerInvariant().Trim();
|
||||
assignedJob = JobPrefab.List.Find(jp => jp.Name.ToLowerInvariant() == trimmedName);
|
||||
|
||||
if (assignedJob != null && trimmedName != TextManager.Get("None").ToLowerInvariant())
|
||||
{
|
||||
textBox.Color = Color.Green;
|
||||
textBox.Text = (assignedJob == null) ? TextManager.Get("None") : assignedJob.Name;
|
||||
}
|
||||
|
||||
textBox.Deselect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private bool TextBoxChanged(GUITextBox textBox, string text)
|
||||
{
|
||||
textBox.Color = Color.Red;
|
||||
@@ -153,66 +128,97 @@ namespace Barotrauma
|
||||
private GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
{
|
||||
int width = 500;
|
||||
int height = spawnType == SpawnType.Path ? 100 : 200;
|
||||
int x = GameMain.GraphicsWidth / 2 - width / 2, y = 10;
|
||||
int height = spawnType == SpawnType.Path ? 80 : 200;
|
||||
int x = GameMain.GraphicsWidth / 2 - width / 2, y = 30;
|
||||
|
||||
editingHUD = new GUIFrame(new Rectangle(x, y, width, height));
|
||||
editingHUD.Padding = new Vector4(10, 10, 20, 0);
|
||||
editingHUD.UserData = this;
|
||||
editingHUD = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas) { ScreenSpaceOffset = new Point(x, y) })
|
||||
{
|
||||
UserData = this
|
||||
};
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), editingHUD.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
if (spawnType == SpawnType.Path)
|
||||
{
|
||||
new GUITextBlock(new Rectangle(0, 0, 100, 20), TextManager.Get("Editing")+" " +TextManager.Get("Waypoint"), "", editingHUD);
|
||||
new GUITextBlock(new Rectangle(0, 20, 100, 20), TextManager.Get("LinkWaypoint"), "", editingHUD);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), TextManager.Get("Editing") + " " + TextManager.Get("Waypoint"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), TextManager.Get("LinkWaypoint"));
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUITextBlock(new Rectangle(0, 0, 100, 20), TextManager.Get("Editing") + " " + TextManager.Get("Spawnpoint"), "", editingHUD);
|
||||
new GUITextBlock(new Rectangle(0, 25, 100, 20), TextManager.Get("SpawnType") + ": ", "", editingHUD);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), TextManager.Get("Editing") + " " + TextManager.Get("Spawnpoint"));
|
||||
|
||||
var spawnTypeContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), spawnTypeContainer.RectTransform), TextManager.Get("SpawnType") + ": ");
|
||||
|
||||
var spawnTypeText = new GUITextBlock(new Rectangle(0, 25, 200, 20), spawnType.ToString(), "", Alignment.Right, Alignment.TopLeft, editingHUD);
|
||||
var button = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), spawnTypeContainer.RectTransform), "-")
|
||||
{
|
||||
UserData = -1,
|
||||
OnClicked = ChangeSpawnType
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), spawnTypeContainer.RectTransform), spawnType.ToString(), textAlignment: Alignment.Center)
|
||||
{
|
||||
UserData = "spawntypetext"
|
||||
};
|
||||
button = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), spawnTypeContainer.RectTransform), "+")
|
||||
{
|
||||
UserData = 1,
|
||||
OnClicked = ChangeSpawnType
|
||||
};
|
||||
|
||||
var button = new GUIButton(new Rectangle(-30, 0, 20, 20), "-", Alignment.Right, "", spawnTypeText);
|
||||
button.UserData = -1;
|
||||
button.OnClicked = ChangeSpawnType;
|
||||
|
||||
button = new GUIButton(new Rectangle(0, 0, 20, 20), "+", Alignment.Right, "", spawnTypeText);
|
||||
button.UserData = 1;
|
||||
button.OnClicked = ChangeSpawnType;
|
||||
var descText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("IDCardDescription"), font: GUI.SmallFont);
|
||||
GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), descText.RectTransform, Anchor.CenterRight), idCardDesc)
|
||||
{
|
||||
MaxTextLength = 150,
|
||||
OnEnterPressed = EnterIDCardDesc,
|
||||
ToolTip = TextManager.Get("IDCardDescriptionTooltip")
|
||||
};
|
||||
propertyBox.OnTextChanged += TextBoxChanged;
|
||||
|
||||
y = 40 + 20;
|
||||
|
||||
new GUITextBlock(new Rectangle(0, y, 100, 20), TextManager.Get("IDCardDescription"), "", Alignment.TopLeft, Alignment.CenterLeft, editingHUD, false, GUI.SmallFont);
|
||||
GUITextBox propertyBox = new GUITextBox(new Rectangle(150, y, 0, 20), "", editingHUD);
|
||||
propertyBox.MaxTextLength = 150;
|
||||
propertyBox.Text = idCardDesc;
|
||||
propertyBox.OnEnterPressed = EnterIDCardDesc;
|
||||
propertyBox.OnTextChanged = TextBoxChanged;
|
||||
propertyBox.ToolTip = TextManager.Get("IDCardDescriptionTooltip");
|
||||
var tagsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("IDCardTags"), font: GUI.SmallFont);
|
||||
propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), tagsText.RectTransform, Anchor.CenterRight), string.Join(", ", idCardTags))
|
||||
{
|
||||
MaxTextLength = 60,
|
||||
OnEnterPressed = EnterIDCardTags,
|
||||
ToolTip = TextManager.Get("IDCardTagsTooltip")
|
||||
};
|
||||
propertyBox.OnTextChanged += TextBoxChanged;
|
||||
|
||||
y = y + 30;
|
||||
|
||||
new GUITextBlock(new Rectangle(0, y, 100, 20), TextManager.Get("IDCardTags"), "", Alignment.TopLeft, Alignment.CenterLeft, editingHUD, false, GUI.SmallFont);
|
||||
propertyBox = new GUITextBox(new Rectangle(150, y, 0, 20), "", editingHUD);
|
||||
propertyBox.MaxTextLength = 60;
|
||||
propertyBox.Text = string.Join(", ", idCardTags);
|
||||
propertyBox.OnEnterPressed = EnterIDCardTags;
|
||||
propertyBox.OnTextChanged = TextBoxChanged;
|
||||
propertyBox.ToolTip = TextManager.Get("IDCardTagsTooltip");
|
||||
|
||||
y = y + 30;
|
||||
|
||||
new GUITextBlock(new Rectangle(0, y, 100, 20), TextManager.Get("SpawnpointJobs"), "", Alignment.TopLeft, Alignment.CenterLeft, editingHUD, false, GUI.SmallFont);
|
||||
propertyBox = new GUITextBox(new Rectangle(150, y, 0, 20), "", editingHUD);
|
||||
propertyBox.MaxTextLength = 60;
|
||||
propertyBox.Text = (assignedJob == null) ? "None" : assignedJob.Name;
|
||||
propertyBox.OnEnterPressed = EnterAssignedJob;
|
||||
propertyBox.OnTextChanged = TextBoxChanged;
|
||||
propertyBox.ToolTip = TextManager.Get("SpawnpointJobsTooltip");
|
||||
|
||||
var jobsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("SpawnpointJobs"), font: GUI.SmallFont)
|
||||
{
|
||||
ToolTip = TextManager.Get("SpawnpointJobsTooltip")
|
||||
};
|
||||
var jobDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1.0f), jobsText.RectTransform, Anchor.CenterRight))
|
||||
{
|
||||
ToolTip = TextManager.Get("SpawnpointJobsTooltip"),
|
||||
OnSelected = (selected, userdata) =>
|
||||
{
|
||||
assignedJob = userdata as JobPrefab;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
jobDropDown.AddItem(TextManager.Get("Any"), null);
|
||||
foreach (JobPrefab jobPrefab in JobPrefab.List)
|
||||
{
|
||||
jobDropDown.AddItem(jobPrefab.Name, jobPrefab);
|
||||
}
|
||||
jobDropDown.SelectItem(assignedJob);
|
||||
}
|
||||
|
||||
y = y + 30;
|
||||
PositionEditingHUD();
|
||||
|
||||
return editingHUD;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user