diff --git a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj index b9cdec336..c47ac50f9 100644 --- a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj +++ b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj @@ -73,8 +73,6 @@ - - @@ -153,6 +151,8 @@ + + diff --git a/Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundCreatureManager.cs b/Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundCreatureManager.cs index c7f3ec9a0..a43503531 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundCreatureManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundCreatureManager.cs @@ -11,9 +11,9 @@ namespace Barotrauma { const int MaxSprites = 100; - const float checkActiveInterval = 1.0f; + const float CheckActiveInterval = 1.0f; - float checkActiveTimer; + private float checkActiveTimer; private List prefabs = new List(); private List activeSprites = new List(); @@ -104,15 +104,15 @@ namespace Barotrauma public void Update(float deltaTime, Camera cam) { - if (checkActiveTimer<0.0f) + if (checkActiveTimer < 0.0f) { foreach (BackgroundCreature sprite in activeSprites) { - sprite.Enabled = (Math.Abs(sprite.TransformedPosition.X - cam.WorldViewCenter.X) < 4000.0f && - Math.Abs(sprite.TransformedPosition.Y - cam.WorldViewCenter.Y) < 4000.0f); + sprite.Enabled = Math.Abs(sprite.TransformedPosition.X - cam.WorldViewCenter.X) < cam.WorldView.Width && + Math.Abs(sprite.TransformedPosition.Y - cam.WorldViewCenter.Y) < cam.WorldView.Height; } - checkActiveTimer = checkActiveInterval; + checkActiveTimer = CheckActiveInterval; } else { diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs index 6221afc36..f40f6f185 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/Tutorials/BasicTutorial.cs @@ -17,10 +17,6 @@ namespace Barotrauma.Tutorials public override IEnumerable UpdateState() { - //spawn some fish next to the player - GameMain.GameScreen.BackgroundCreatureManager.SpawnSprites(2, - Submarine.MainSub.Position + Character.Controlled.Position); - foreach (Item item in Item.ItemList) { var wire = item.GetComponent(); diff --git a/Barotrauma/BarotraumaClient/Source/Map/Levels/BackgroundSpriteManager.cs b/Barotrauma/BarotraumaClient/Source/Map/Levels/BackgroundSpriteManager.cs new file mode 100644 index 000000000..31c726aeb --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Map/Levels/BackgroundSpriteManager.cs @@ -0,0 +1,132 @@ +using Barotrauma.Particles; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; + +namespace Barotrauma +{ + partial class BackgroundSprite + { + public ParticleEmitter ParticleEmitter; + } + + partial class BackgroundSpriteManager + { + private List visibleSprites = new List(); + + private Rectangle currentGridIndices; + + partial void UpdateProjSpecific(float deltaTime) + { + foreach (BackgroundSprite s in visibleSprites) + { + if (s.Prefab.ParticleEmitterPrefab != null) + { + Vector2 emitterPos = new Vector2(s.Prefab.EmitterPosition.X, s.Prefab.EmitterPosition.Y) * s.Scale; + + if (s.Rotation != 0.0f || s.Prefab.SwingAmount != 0.0f) + { + var ca = (float)Math.Cos(s.Rotation + swingState * s.Prefab.SwingAmount); + var sa = (float)Math.Sin(s.Rotation + swingState * s.Prefab.SwingAmount); + + emitterPos = new Vector2( + ca * emitterPos.X + sa * emitterPos.Y, + -sa * emitterPos.X + ca * emitterPos.Y); + } + + s.ParticleEmitter.Emit(deltaTime, new Vector2(s.Position.X, s.Position.Y) + emitterPos); + } + } + } + + 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; + } + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Map/Levels/BackgroundSpritePrefab.cs b/Barotrauma/BarotraumaClient/Source/Map/Levels/BackgroundSpritePrefab.cs new file mode 100644 index 000000000..0249978aa --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/Map/Levels/BackgroundSpritePrefab.cs @@ -0,0 +1,10 @@ +using Microsoft.Xna.Framework; + +namespace Barotrauma +{ + partial class BackgroundSpritePrefab + { + public readonly Particles.ParticleEmitterPrefab ParticleEmitterPrefab; + public readonly Vector2 EmitterPosition; + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Map/Levels/Level.cs b/Barotrauma/BarotraumaClient/Source/Map/Levels/Level.cs index 4ca62ed1e..577cb9a74 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Levels/Level.cs @@ -7,6 +7,8 @@ namespace Barotrauma { private LevelRenderer renderer; + private BackgroundCreatureManager backgroundCreatureManager; + public void DrawFront(SpriteBatch spriteBatch) { if (renderer == null) return; @@ -32,7 +34,7 @@ namespace Barotrauma } } - public void DrawBack(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, BackgroundCreatureManager backgroundSpriteManager = null) + public void DrawBack(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, BackgroundCreatureManager backgroundCreatureManager = null) { float brightness = MathHelper.Clamp(50.0f + (cam.Position.Y - Size.Y) / 2000.0f, 10.0f, 40.0f); @@ -42,7 +44,7 @@ namespace Barotrauma graphics.Clear(backgroundColor); if (renderer == null) return; - renderer.DrawBackground(spriteBatch, cam, backgroundSpriteManager); + renderer.DrawBackground(spriteBatch, cam, backgroundSpriteManager, backgroundCreatureManager); } } } diff --git a/Barotrauma/BarotraumaClient/Source/Map/Levels/LevelRenderer.cs b/Barotrauma/BarotraumaClient/Source/Map/Levels/LevelRenderer.cs index c1be3e9da..b0a315e67 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Levels/LevelRenderer.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Levels/LevelRenderer.cs @@ -13,8 +13,6 @@ namespace Barotrauma private static Sprite dustParticles; private static Texture2D shaftTexture; - private static BackgroundSpriteManager backgroundSpriteManager; - Vector2 dustOffset; private Level level; @@ -57,31 +55,13 @@ namespace Barotrauma }; wallCenterEffect.CurrentTechnique = wallCenterEffect.Techniques["BasicEffect_Texture"]; } - - - if (backgroundSpriteManager==null) - { - - var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundSpritePrefabs); - if (files.Count > 0) - backgroundSpriteManager = new BackgroundSpriteManager(files); - else - backgroundSpriteManager = new BackgroundSpriteManager("Content/BackgroundSprites/BackgroundSpritePrefabs.xml"); - } - + this.level = level; } - - public void PlaceSprites(int amount) - { - backgroundSpriteManager.PlaceSprites(level, amount); - } - + public void Update(float deltaTime) { dustOffset -= Vector2.UnitY * 10.0f * deltaTime; - - backgroundSpriteManager.Update(deltaTime); } public static VertexPositionColorTexture[] GetColoredVertices(VertexPositionTexture[] vertices, Color color) @@ -118,7 +98,9 @@ namespace Barotrauma bodyVertices.SetData(vertices); } - public void DrawBackground(SpriteBatch spriteBatch, Camera cam, BackgroundCreatureManager backgroundCreatureManager = null) + public void DrawBackground(SpriteBatch spriteBatch, Camera cam, + BackgroundSpriteManager backgroundSpriteManager = null, + BackgroundCreatureManager backgroundCreatureManager = null) { spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap); @@ -152,11 +134,9 @@ namespace Barotrauma SamplerState.LinearWrap, DepthStencilState.Default, null, null, cam.Transform); - backgroundSpriteManager.DrawSprites(spriteBatch, cam); - - if (backgroundCreatureManager!=null) backgroundCreatureManager.Draw(spriteBatch); - - + if (backgroundSpriteManager != null) backgroundSpriteManager.DrawSprites(spriteBatch, cam); + if (backgroundCreatureManager != null) backgroundCreatureManager.Draw(spriteBatch); + for (int i = 0; i < 4; i++) { float scale = 1.0f - i * 0.2f; diff --git a/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs index 33262bee8..d1761d676 100644 --- a/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaClient/Source/Physics/PhysicsBody.cs @@ -7,6 +7,8 @@ namespace Barotrauma { partial class PhysicsBody { + private float bodyShapeTextureScale; + private Texture2D bodyShapeTexture; public Texture2D BodyShapeTexture { @@ -59,18 +61,45 @@ namespace Barotrauma switch (BodyShape) { case PhysicsBody.Shape.Rectangle: - bodyShapeTexture = GUI.CreateRectangle( - (int)ConvertUnits.ToDisplayUnits(width), - (int)ConvertUnits.ToDisplayUnits(height)); - break; + { + float maxSize = Math.Max(ConvertUnits.ToDisplayUnits(width), ConvertUnits.ToDisplayUnits(height)); + if (maxSize > 128.0f) + { + bodyShapeTextureScale = 128.0f / maxSize; + } + else + { + bodyShapeTextureScale = 1.0f; + } + bodyShapeTexture = GUI.CreateRectangle( + (int)ConvertUnits.ToDisplayUnits(width * bodyShapeTextureScale), + (int)ConvertUnits.ToDisplayUnits(height * bodyShapeTextureScale)); + break; + } case PhysicsBody.Shape.Capsule: - bodyShapeTexture = GUI.CreateCapsule( - (int)ConvertUnits.ToDisplayUnits(radius), - (int)ConvertUnits.ToDisplayUnits(Math.Max(height, width))); - break; + { + float maxSize = Math.Max(ConvertUnits.ToDisplayUnits(radius), ConvertUnits.ToDisplayUnits(Math.Max(height, width))); + if (maxSize > 128.0f) + { + bodyShapeTextureScale = 128.0f / maxSize; + } + else + { + bodyShapeTextureScale = 1.0f; + } + + bodyShapeTexture = GUI.CreateCapsule( + (int)ConvertUnits.ToDisplayUnits(radius * bodyShapeTextureScale), + (int)ConvertUnits.ToDisplayUnits(Math.Max(height, width) * bodyShapeTextureScale)); + break; + } case PhysicsBody.Shape.Circle: - bodyShapeTexture = GUI.CreateCircle((int)ConvertUnits.ToDisplayUnits(radius)); + if (ConvertUnits.ToDisplayUnits(radius)> 128.0f) + { + bodyShapeTextureScale = 128.0f / ConvertUnits.ToDisplayUnits(radius); + } + bodyShapeTexture = GUI.CreateCircle((int)ConvertUnits.ToDisplayUnits(radius * bodyShapeTextureScale)); break; } } @@ -80,7 +109,7 @@ namespace Barotrauma { rot -= MathHelper.PiOver2; } - + spriteBatch.Draw( bodyShapeTexture, new Vector2(DrawPosition.X, -DrawPosition.Y), @@ -88,7 +117,7 @@ namespace Barotrauma color, rot, new Vector2(bodyShapeTexture.Width / 2, bodyShapeTexture.Height / 2), - 1.0f, SpriteEffects.None, 0.0f); + 1.0f / bodyShapeTextureScale, SpriteEffects.None, 0.0f); } partial void DisposeProjSpecific() diff --git a/Barotrauma/BarotraumaClient/Source/Screens/GameScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/GameScreen.cs index 8ffb7ca9f..d403935ab 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/GameScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/GameScreen.cs @@ -22,7 +22,6 @@ namespace Barotrauma private Texture2D damageStencil; - public BackgroundCreatureManager BackgroundCreatureManager; public GameScreen(GraphicsDevice graphics, ContentManager content) { @@ -34,11 +33,6 @@ namespace Barotrauma renderTargetWater = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight); renderTargetAir = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight); - var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundCreaturePrefabs); - if (files.Count > 0) - BackgroundCreatureManager = new BackgroundCreatureManager(files); - else - BackgroundCreatureManager = new BackgroundCreatureManager("Content/BackgroundSprites/BackgroundCreaturePrefabs.xml"); #if LINUX var blurEffect = content.Load("blurshader_opengl"); @@ -145,7 +139,7 @@ namespace Barotrauma } else { - Level.Loaded.DrawBack(graphics, spriteBatch, cam, BackgroundCreatureManager); + Level.Loaded.DrawBack(graphics, spriteBatch, cam); } spriteBatch.Begin(SpriteSortMode.BackToFront, diff --git a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems index 1c409d7b1..9fa382616 100644 --- a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems +++ b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems @@ -1432,7 +1432,10 @@ + + + diff --git a/Barotrauma/BarotraumaShared/Content/BackgroundSprites/BackgroundSpritePrefabs.xml b/Barotrauma/BarotraumaShared/Content/BackgroundSprites/BackgroundSpritePrefabs.xml index 0900f75e1..45469165b 100644 --- a/Barotrauma/BarotraumaShared/Content/BackgroundSprites/BackgroundSpritePrefabs.xml +++ b/Barotrauma/BarotraumaShared/Content/BackgroundSprites/BackgroundSpritePrefabs.xml @@ -109,41 +109,51 @@ - + + + + + + velocitymax="2000"/> - + + + + + velocitymax="2000"/> - + + + + + velocitymax="2000"/> \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/Content/Particles/ParticlePrefabs.xml b/Barotrauma/BarotraumaShared/Content/Particles/ParticlePrefabs.xml index c609b0af2..5033cbb00 100644 --- a/Barotrauma/BarotraumaShared/Content/Particles/ParticlePrefabs.xml +++ b/Barotrauma/BarotraumaShared/Content/Particles/ParticlePrefabs.xml @@ -169,9 +169,7 @@ growtime="10" lifetime="25" drawtarget="water" - collideswithwalls="true" - collisionradius="102.0" - velocitychange="0.0, 2.0"> + velocitychange="0.0, 0.0"> diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs b/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs index 6dd580b3e..bb64860b6 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs @@ -40,6 +40,8 @@ namespace Barotrauma private readonly float damage; private readonly float bleedingDamage; + private readonly bool onlyHumans; + private readonly List statusEffects; public readonly float Force; @@ -99,15 +101,17 @@ namespace Barotrauma SeverLimbsProbability = ToolBox.GetAttributeFloat(element, "severlimbsprobability", 0.0f); - Force = ToolBox.GetAttributeFloat(element,"force", 0.0f); + Force = ToolBox.GetAttributeFloat(element, "force", 0.0f); TargetForce = ToolBox.GetAttributeFloat(element, "targetforce", 0.0f); Torque = ToolBox.GetAttributeFloat(element, "torque", 0.0f); - + Range = ToolBox.GetAttributeFloat(element, "range", 0.0f); Duration = ToolBox.GetAttributeFloat(element, "duration", 0.0f); priority = ToolBox.GetAttributeFloat(element, "priority", 1.0f); + onlyHumans = ToolBox.GetAttributeBool(element, "onlyhumans", false); + InitProjSpecific(element); string limbIndicesStr = ToolBox.GetAttributeString(element, "applyforceonlimbs", ""); @@ -143,6 +147,12 @@ namespace Barotrauma public AttackResult DoDamage(IDamageable attacker, IDamageable target, Vector2 worldPosition, float deltaTime, bool playSound = true) { + if (onlyHumans) + { + Character character = target as Character; + if (character != null && character.ConfigPath != Character.HumanConfigFile) return new AttackResult(); + } + DamageParticles(deltaTime, worldPosition); var attackResult = target.AddDamage(attacker, worldPosition, this, deltaTime, playSound); diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index c47f79fd1..37b0f35a2 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -184,10 +184,6 @@ namespace Barotrauma level.Generate(); submarine.SetPosition(submarine.FindSpawnPos(level.StartPosition - new Vector2(0.0f, 2000.0f))); - -#if CLIENT - GameMain.GameScreen.BackgroundCreatureManager.SpawnSprites(80); -#endif } if (gameMode.Mission != null) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundSpriteManager.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/BackgroundSpriteManager.cs similarity index 64% rename from Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundSpriteManager.cs rename to Barotrauma/BarotraumaShared/Source/Map/Levels/BackgroundSpriteManager.cs index 40f164564..ce56ba5da 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundSpriteManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/BackgroundSpriteManager.cs @@ -1,4 +1,6 @@ -using Barotrauma.Particles; +#if CLIENT +using Barotrauma.Particles; +#endif using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; @@ -9,7 +11,7 @@ using Voronoi2; namespace Barotrauma { - class BackgroundSprite + partial class BackgroundSprite { public readonly BackgroundSpritePrefab Prefab; public Vector3 Position; @@ -18,10 +20,8 @@ namespace Barotrauma public float Rotation; - public Particles.ParticleEmitter ParticleEmitter; + public LevelTrigger Trigger; - //public Vector2[] spriteCorners; - public BackgroundSprite(BackgroundSpritePrefab prefab, Vector3 position, float scale, float rotation = 0.0f) { this.Prefab = prefab; @@ -31,25 +31,42 @@ namespace Barotrauma this.Rotation = rotation; + if (prefab.LevelTriggerElement != null) + { + Vector2 triggerPosition = ToolBox.GetAttributeVector2(prefab.LevelTriggerElement, "position", Vector2.Zero) * scale; + + if (rotation != 0.0f) + { + var ca = (float)Math.Cos(rotation); + var sa = (float)Math.Sin(rotation); + + triggerPosition = new Vector2( + ca * triggerPosition.X + sa * triggerPosition.Y, + -sa * triggerPosition.X + ca * triggerPosition.Y); + } + + this.Trigger = new LevelTrigger(prefab.LevelTriggerElement, new Vector2(position.X, position.Y) + triggerPosition, -rotation); + } + +#if CLIENT if (prefab.ParticleEmitterPrefab != null) { this.ParticleEmitter = new ParticleEmitter(prefab.ParticleEmitterPrefab); } +#endif + } } - class BackgroundSpriteManager + partial class BackgroundSpriteManager { const int GridSize = 2000; private List prefabs = new List(); + + private List sprites; + private List[,] spriteGrid; - private List[,] sprites; - - private List visibleSprites = new List(); - - private Rectangle currentGridIndices; - private float swingTimer, swingState; public BackgroundSpriteManager(string configPath) @@ -84,9 +101,11 @@ namespace Barotrauma public void PlaceSprites(Level level, int amount) { - sprites = new List[ + spriteGrid = new List[ (int)Math.Ceiling(level.Size.X / GridSize), (int)Math.Ceiling((level.Size.Y - level.BottomPos) / GridSize)]; + + sprites = new List(); for (int i = 0 ; i < amount; i++) { @@ -131,27 +150,37 @@ namespace Barotrauma spriteCorners[j] += pos.Value + pivotOffset; } +#if CLIENT if (newSprite.ParticleEmitter != null) { Rectangle particleBounds = newSprite.ParticleEmitter.CalculateParticleBounds(pos.Value); spriteCorners.Add(particleBounds.Location.ToVector2()); spriteCorners.Add(new Vector2(particleBounds.Right, particleBounds.Bottom)); } - +#endif + + sprites.Add(newSprite); + int minX = (int)Math.Floor((spriteCorners.Min(c => c.X) - newSprite.Position.Z) / GridSize); int maxX = (int)Math.Floor((spriteCorners.Max(c => c.X) + newSprite.Position.Z) / GridSize); - if (minX < 0 || maxX >= sprites.GetLength(0)) continue; + + if (maxX < 0 || minX >= spriteGrid.GetLength(0)) continue; int minY = (int)Math.Floor((spriteCorners.Min(c => c.Y) - newSprite.Position.Z - level.BottomPos) / GridSize); int maxY = (int)Math.Floor((spriteCorners.Max(c => c.Y) + newSprite.Position.Z - level.BottomPos) / GridSize); - if (minY < 0 || maxY >= sprites.GetLength(1)) continue; + if (maxY < 0 || minY >= spriteGrid.GetLength(1)) continue; + + minX = Math.Max(minX, 0); + maxX = Math.Min(maxX, spriteGrid.GetLength(0) - 1); + minY = Math.Max(minY, 0); + maxY = Math.Min(maxY, spriteGrid.GetLength(1) - 1); for (int x = minX; x <= maxX; x++) { for (int y = minY; y <= maxY; y++) { - if (sprites[x, y] == null) sprites[x, y] = new List(); - sprites[x, y].Add(newSprite); + if (spriteGrid[x, y] == null) spriteGrid[x, y] = new List(); + spriteGrid[x, y].Add(newSprite); } } } @@ -251,118 +280,15 @@ namespace Barotrauma swingTimer += deltaTime; swingState = (float)Math.Sin(swingTimer * 0.1f); - foreach (BackgroundSprite s in visibleSprites) + foreach (BackgroundSprite sprite in sprites) { - if (s.Prefab.ParticleEmitterPrefab != null) - { - Vector2 emitterPos = new Vector2(s.Prefab.EmitterPosition.X, s.Prefab.EmitterPosition.Y) * s.Scale; - - if (s.Rotation != 0.0f || s.Prefab.SwingAmount != 0.0f) - { - var ca = (float)Math.Cos(s.Rotation + swingState * s.Prefab.SwingAmount); - var sa = (float)Math.Sin(s.Rotation + swingState * s.Prefab.SwingAmount); - - emitterPos = new Vector2( - ca * emitterPos.X + sa * emitterPos.Y, - -sa * emitterPos.X + ca * emitterPos.Y); - } - - s.ParticleEmitter.Emit(deltaTime, new Vector2(s.Position.X, s.Position.Y) + emitterPos); - } + sprite.Trigger?.Update(deltaTime); } + UpdateProjSpecific(deltaTime); } - public void DrawSprites(SpriteBatch spriteBatch, Camera cam) - { - Rectangle indices = Rectangle.Empty; - indices.X = (int)Math.Floor(cam.WorldView.X / (float)GridSize); - if (indices.X >= sprites.GetLength(0)) return; - indices.Y = (int)Math.Floor((cam.WorldView.Y - cam.WorldView.Height - Level.Loaded.BottomPos) / (float)GridSize); - if (indices.Y >= sprites.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, sprites.GetLength(0)-1); - indices.Height = Math.Min(indices.Height, sprites.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 (sprites[x, y] == null) continue; - foreach (BackgroundSprite sprite in sprites[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); - - /*for (int i = 0; i < 4; i++) - { - GUI.DrawLine(spriteBatch, - new Vector2(sprite.spriteCorners[i].X, -sprite.spriteCorners[i].Y), - new Vector2(sprite.spriteCorners[(i + 1) % 4].X, -sprite.spriteCorners[(i + 1) % 4].Y), - Color.White, 0, 5); - }*/ - - if (GameMain.DebugDraw) - { - GUI.DrawRectangle(spriteBatch, new Vector2(sprite.Position.X, -sprite.Position.Y), new Vector2(10.0f, 10.0f), Color.Red, true); - } - - z += 0.0001f; - } - } + partial void UpdateProjSpecific(float deltaTime); private BackgroundSpritePrefab GetRandomPrefab(string levelType) { diff --git a/Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundSpritePrefab.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/BackgroundSpritePrefab.cs similarity index 92% rename from Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundSpritePrefab.cs rename to Barotrauma/BarotraumaShared/Source/Map/Levels/BackgroundSpritePrefab.cs index eac9d87d0..05456d28e 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/BackgroundSprite/BackgroundSpritePrefab.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/BackgroundSpritePrefab.cs @@ -5,7 +5,7 @@ using System.Xml.Linq; namespace Barotrauma { - class BackgroundSpritePrefab + partial class BackgroundSpritePrefab { [Flags] public enum SpawnPosType @@ -15,11 +15,13 @@ namespace Barotrauma RuinWall = 2, SeaFloor = 4 } + + public readonly Alignment Alignment; + + public readonly Vector2 DepthRange; public readonly Sprite Sprite; - public readonly Alignment Alignment; - public readonly Vector2 Scale; public SpawnPosType SpawnPos; @@ -27,18 +29,15 @@ namespace Barotrauma public readonly bool AlignWithSurface; public readonly Vector2 RandomRotation; - - public readonly Vector2 DepthRange; - - public readonly Particles.ParticleEmitterPrefab ParticleEmitterPrefab; - public readonly Vector2 EmitterPosition; - + public readonly float SwingAmount; public readonly int Commonness; public Dictionary OverrideCommonness; + public readonly XElement LevelTriggerElement; + public BackgroundSpritePrefab(XElement element) { string alignmentStr = ToolBox.GetAttributeString(element, "alignment", ""); @@ -89,10 +88,16 @@ namespace Barotrauma OverrideCommonness.Add(levelType, ToolBox.GetAttributeInt(subElement, "commonness", 1)); } break; + case "leveltrigger": + case "trigger": + LevelTriggerElement = subElement; + break; +#if CLIENT case "particleemitter": ParticleEmitterPrefab = new Particles.ParticleEmitterPrefab(subElement); EmitterPosition = ToolBox.GetAttributeVector2(subElement, "position", Vector2.Zero); break; +#endif } } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs index 915ea3d47..7f14224fc 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs @@ -15,7 +15,6 @@ namespace Barotrauma { //all entities are disabled after they reach this depth public const float MaxEntityDepth = -300000.0f; - public const float ShaftHeight = 1000.0f; public static Level Loaded @@ -75,6 +74,8 @@ namespace Barotrauma private LevelGenerationParams generationParams; + private static BackgroundSpriteManager backgroundSpriteManager; + public Vector2 StartPosition { get { return startPosition; } @@ -150,7 +151,7 @@ namespace Barotrauma { get { return wallColor; } } - + public Level(string seed, float difficulty, LevelGenerationParams generationParams) { this.seed = seed; @@ -183,6 +184,25 @@ namespace Barotrauma public void Generate(bool mirror = false) { + if (backgroundSpriteManager == null) + { + var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundSpritePrefabs); + if (files.Count > 0) + backgroundSpriteManager = new BackgroundSpriteManager(files); + else + backgroundSpriteManager = new BackgroundSpriteManager("Content/BackgroundSprites/BackgroundSpritePrefabs.xml"); + } +#if CLIENT + if (backgroundCreatureManager == null) + { + var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundCreaturePrefabs); + if (files.Count > 0) + backgroundCreatureManager = new BackgroundCreatureManager(files); + else + backgroundCreatureManager = new BackgroundCreatureManager("Content/BackgroundSprites/BackgroundCreaturePrefabs.xml"); + } +#endif + Stopwatch sw = new Stopwatch(); sw.Start(); @@ -485,8 +505,9 @@ namespace Barotrauma GenerateSeaFloor(); + backgroundSpriteManager.PlaceSprites(this, generationParams.BackgroundSpriteAmount); #if CLIENT - renderer.PlaceSprites(generationParams.BackgroundSpriteAmount); + backgroundCreatureManager.SpawnSprites(80); #endif foreach (VoronoiCell cell in cells) @@ -872,15 +893,13 @@ namespace Barotrauma return matchingPositions[Rand.Int(matchingPositions.Count, (useSyncedRand ? Rand.RandSync.Server : Rand.RandSync.Unsynced))].Position; } - public void Update(float deltaTime) + public void Update(float deltaTime, Camera cam) { - /* - if (Submarine.MainSub != null) - { - WrappingWall.UpdateWallShift(Submarine.MainSub.WorldPosition, wrappingWalls); - }*/ + backgroundSpriteManager.Update(deltaTime); #if CLIENT + backgroundCreatureManager.Update(deltaTime, cam); + if (Hull.renderer != null) { Hull.renderer.ScrollWater((float)deltaTime); diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelTrigger.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelTrigger.cs new file mode 100644 index 000000000..bf534eeba --- /dev/null +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/LevelTrigger.cs @@ -0,0 +1,134 @@ +using FarseerPhysics; +using FarseerPhysics.Dynamics; +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Xml.Linq; + +namespace Barotrauma +{ + partial class LevelTrigger + { + private PhysicsBody physicsBody; + + /// + /// Effects applied to entities that are inside the trigger + /// + private List statusEffects = new List(); + + /// + /// Attacks applied to entities that are inside the trigger + /// + private List attacks = new List(); + + private List triggerers = new List(); + + public Vector2 WorldPosition + { + get { return ConvertUnits.ToDisplayUnits(physicsBody.Position); } + set { physicsBody.SetTransform(ConvertUnits.ToSimUnits(value), physicsBody.Rotation); } + } + + public float Rotation + { + get { return physicsBody.Rotation; } + set { physicsBody.SetTransform(physicsBody.Position, value); } + } + + public PhysicsBody PhysicsBody + { + get { return physicsBody; } + } + + public LevelTrigger(XElement element, Vector2 position, float rotation, float scale = 1.0f) + { + physicsBody = new PhysicsBody(element, scale); + physicsBody.CollisionCategories = Physics.CollisionLevel; + physicsBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionProjectile | Physics.CollisionWall; + physicsBody.FarseerBody.OnCollision += PhysicsBody_OnCollision; + physicsBody.FarseerBody.OnSeparation += PhysicsBody_OnSeparation; + physicsBody.FarseerBody.IsSensor = true; + physicsBody.FarseerBody.IsStatic = true; + physicsBody.FarseerBody.IsKinematic = true; + + physicsBody.SetTransform(ConvertUnits.ToSimUnits(position), rotation); + + foreach (XElement subElement in element.Elements()) + { + switch (subElement.Name.ToString().ToLowerInvariant()) + { + case "statuseffect": + statusEffects.Add(StatusEffect.Load(subElement)); + break; + case "attack": + case "damage": + attacks.Add(new Attack(subElement)); + break; + } + } + } + + private bool PhysicsBody_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact) + { + Entity entity = GetEntity(fixtureB); + if (entity == null) return false; + + if (!triggerers.Contains(entity)) + { + triggerers.Add(entity); + } + return true; + } + + private void PhysicsBody_OnSeparation(Fixture fixtureA, Fixture fixtureB) + { + Entity entity = GetEntity(fixtureB); + if (entity == null) return; + + if (triggerers.Contains(entity)) + { + triggerers.Remove(entity); + } + } + + private Entity GetEntity(Fixture fixture) + { + if (fixture.Body == null || fixture.Body.UserData == null) return null; + + var entity = fixture.Body.UserData as Entity; + if (entity != null) return entity; + + var limb = fixture.Body.UserData as Limb; + if (limb != null) return limb.character; + + return null; + } + + public void Update(float deltaTime) + { + foreach (Entity triggerer in triggerers) + { + foreach (StatusEffect effect in statusEffects) + { + if (triggerer is Character) + { + effect.Apply(effect.type, deltaTime, triggerer, (Character)triggerer); + } + else if (triggerer is Item) + { + effect.Apply(effect.type, deltaTime, triggerer, ((Item)triggerer).AllPropertyObjects); + } + } + + IDamageable damageable = triggerer as IDamageable; + if (damageable != null) + { + foreach (Attack attack in attacks) + { + attack.DoDamage(null, damageable, WorldPosition, deltaTime, false); + } + } + } + } + } +} diff --git a/Barotrauma/BarotraumaShared/Source/Screens/GameScreen.cs b/Barotrauma/BarotraumaShared/Source/Screens/GameScreen.cs index bb7673f51..efcf785fd 100644 --- a/Barotrauma/BarotraumaShared/Source/Screens/GameScreen.cs +++ b/Barotrauma/BarotraumaShared/Source/Screens/GameScreen.cs @@ -80,15 +80,13 @@ namespace Barotrauma #if CLIENT if (GameMain.GameSession != null) GameMain.GameSession.Update((float)deltaTime); - - BackgroundCreatureManager.Update((float)deltaTime, cam); - + GameMain.ParticleManager.Update((float)deltaTime); GameMain.LightManager.Update((float)deltaTime); #endif - if (Level.Loaded != null) Level.Loaded.Update((float)deltaTime); + if (Level.Loaded != null) Level.Loaded.Update((float)deltaTime, cam); #if CLIENT if (Character.Controlled != null && Character.Controlled.SelectedConstruction != null && Character.Controlled.CanInteractWith(Character.Controlled.SelectedConstruction))