diff --git a/Subsurface/Camera.cs b/Subsurface/Camera.cs index 30f5842d8..662fdb27b 100644 --- a/Subsurface/Camera.cs +++ b/Subsurface/Camera.cs @@ -162,6 +162,8 @@ namespace Subsurface if (Keyboard.GetState().IsKeyDown(Keys.Right)) moveCam.X += moveSpeed; if (Keyboard.GetState().IsKeyDown(Keys.Down)) moveCam.Y -= moveSpeed; if (Keyboard.GetState().IsKeyDown(Keys.Up)) moveCam.Y += moveSpeed; + + Zoom = MathHelper.Clamp(Zoom + PlayerInput.ScrollWheelSpeed / 1000.0f, 0.1f, 2.0f); } else { diff --git a/Subsurface/Characters/AI/EnemyAIController.cs b/Subsurface/Characters/AI/EnemyAIController.cs index 8044270f4..9b3aafbf7 100644 --- a/Subsurface/Characters/AI/EnemyAIController.cs +++ b/Subsurface/Characters/AI/EnemyAIController.cs @@ -219,9 +219,9 @@ namespace Subsurface //check if there's a wall between the target and the character Vector2 rayStart = character.animController.limbs[0].SimPosition; Vector2 rayEnd = selectedTarget.Position; - Body closestBody = Map.CheckVisibility(rayStart, rayEnd); + Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd); - if (Map.LastPickedFraction == 1.0f || closestBody == null) + if (Submarine.LastPickedFraction == 1.0f || closestBody == null) { wallAttackPos = Vector2.Zero; return; @@ -230,11 +230,11 @@ namespace Subsurface Structure wall = closestBody.UserData as Structure; if (wall == null) { - wallAttackPos = Map.LastPickedPosition; + wallAttackPos = Submarine.LastPickedPosition; } else { - int sectionIndex = wall.FindSectionIndex(ConvertUnits.ToDisplayUnits(Map.LastPickedPosition)); + int sectionIndex = wall.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition)); float sectionDamage = wall.SectionDamage(sectionIndex); for (int i = sectionIndex - 2; i <= sectionIndex + 2; i++) @@ -377,7 +377,7 @@ namespace Subsurface Vector2 rayStart = character.animController.limbs[0].SimPosition; Vector2 rayEnd = target.Position; - Body closestBody = Map.CheckVisibility(rayStart, rayEnd); + Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd); Structure closestStructure = (closestBody == null) ? null : closestBody.UserData as Structure; //if (targetCharacter != null) diff --git a/Subsurface/Characters/AI/SteeringManager.cs b/Subsurface/Characters/AI/SteeringManager.cs index 0b6337300..7a371dcc2 100644 --- a/Subsurface/Characters/AI/SteeringManager.cs +++ b/Subsurface/Characters/AI/SteeringManager.cs @@ -32,7 +32,7 @@ namespace Subsurface { this.host = host; - wanderAngle = ToolBox.RandomFloat(0.0f, MathHelper.TwoPi); + wanderAngle = ToolBox.RandomFloatLocal(0.0f, MathHelper.TwoPi); } public void SteeringSeek(Vector2 target, float speed = 1.0f) @@ -90,7 +90,7 @@ namespace Subsurface float angleChange = 1.5f; - wanderAngle += ToolBox.RandomFloat(0.0f, 1.0f) * angleChange - angleChange * 0.5f; + wanderAngle += ToolBox.RandomFloatLocal(0.0f, 1.0f) * angleChange - angleChange * 0.5f; Vector2 newSteering = circleCenter + displacement; float steeringSpeed = (newSteering + host.Steering).Length(); @@ -113,7 +113,7 @@ namespace Subsurface if (rayCastTimer <= 0.0f) { rayCastTimer = RayCastInterval; - Body closestBody = Map.CheckVisibility(host.Position, ahead); + Body closestBody = Submarine.CheckVisibility(host.Position, ahead); if (closestBody == null) { avoidSteering = Vector2.Zero; @@ -124,7 +124,7 @@ namespace Subsurface Structure closestStructure = closestBody.UserData as Structure; if (closestStructure!=null) { - Vector2 obstaclePosition = Map.LastPickedPosition; + Vector2 obstaclePosition = Submarine.LastPickedPosition; if (closestStructure.IsHorizontal) { obstaclePosition.Y = closestStructure.SimPosition.Y; @@ -134,7 +134,7 @@ namespace Subsurface obstaclePosition.X = closestStructure.SimPosition.X; } - avoidSteering = Vector2.Normalize(Map.LastPickedPosition - obstaclePosition); + avoidSteering = Vector2.Normalize(Submarine.LastPickedPosition - obstaclePosition); } } diff --git a/Subsurface/Characters/Character.cs b/Subsurface/Characters/Character.cs index b84404b8a..a8470820f 100644 --- a/Subsurface/Characters/Character.cs +++ b/Subsurface/Characters/Character.cs @@ -769,13 +769,13 @@ namespace Subsurface for (int i = 0; i < 10; i++) { Particle p = Game1.particleManager.CreateParticle("waterblood", - torso.SimPosition + new Vector2(ToolBox.RandomFloat(-0.5f, 0.5f), ToolBox.RandomFloat(-0.5f, 0.5f)), + torso.SimPosition + new Vector2(ToolBox.RandomFloatLocal(-0.5f, 0.5f), ToolBox.RandomFloatLocal(-0.5f, 0.5f)), Vector2.Zero); if (p!=null) p.Size *= 2.0f; Game1.particleManager.CreateParticle("bubbles", torso.SimPosition, - new Vector2(ToolBox.RandomFloat(-0.5f, 0.5f), ToolBox.RandomFloat(-1.0f,0.5f))); + new Vector2(ToolBox.RandomFloatLocal(-0.5f, 0.5f), ToolBox.RandomFloatLocal(-1.0f,0.5f))); } foreach (var joint in animController.limbJoints) diff --git a/Subsurface/Characters/Limb.cs b/Subsurface/Characters/Limb.cs index 39e57402f..d62f04b3f 100644 --- a/Subsurface/Characters/Limb.cs +++ b/Subsurface/Characters/Limb.cs @@ -314,7 +314,7 @@ namespace Subsurface Game1.particleManager.CreateParticle("blood", SimPosition, - particleVel * ToolBox.RandomFloat(1.0f, 3.0f)); + particleVel * ToolBox.RandomFloatLocal(1.0f, 3.0f)); } for (int i = 0; i < bloodAmount / 2; i++) diff --git a/Subsurface/Characters/Ragdoll.cs b/Subsurface/Characters/Ragdoll.cs index 48809eb49..932776d19 100644 --- a/Subsurface/Characters/Ragdoll.cs +++ b/Subsurface/Characters/Ragdoll.cs @@ -462,7 +462,7 @@ namespace Subsurface //limb isn't in any room -> it's in the water limb.inWater = true; } - else if (limbHull.Volume>0.0f && Map.RectContains(limbHull.Rect, limbPosition)) + else if (limbHull.Volume>0.0f && Submarine.RectContains(limbHull.Rect, limbPosition)) { if (limbPosition.Y < limbHull.Surface) diff --git a/Subsurface/Content/Items/Diving/divinggear.xml b/Subsurface/Content/Items/Diving/divinggear.xml index 0c5b41dc6..d3923ec3e 100644 --- a/Subsurface/Content/Items/Diving/divinggear.xml +++ b/Subsurface/Content/Items/Diving/divinggear.xml @@ -40,7 +40,7 @@ - + diff --git a/Subsurface/DebugConsole.cs b/Subsurface/DebugConsole.cs index 660b7f103..e1b5043e5 100644 --- a/Subsurface/DebugConsole.cs +++ b/Subsurface/DebugConsole.cs @@ -197,6 +197,10 @@ namespace Subsurface case "editchar": Game1.EditCharacterScreen.Select(); break; + case "freecamera": + Character.Controlled = null; + Game1.GameScreen.Cam.TargetPos = Vector2.Zero; + break; case "editwater": case "water": if (Game1.Client== null) @@ -205,7 +209,8 @@ namespace Subsurface } break; case "generatelevel": - Game1.Level = new Level(Game1.localRandom.Next(), 20, 500, 500); + Game1.Level = new Level(100, 500,500, 50); + Game1.Level.Generate(100.0f); break; case "fowenabled": case "fow": @@ -218,12 +223,12 @@ namespace Subsurface break; case "savemap": if (commands.Length < 2) break; - Map.SaveCurrent("Content/SavedMaps/" + commands[1]); + Submarine.SaveCurrent("Content/SavedMaps/" + commands[1]); NewMessage("map saved", Color.Green); break; case "loadmap": if (commands.Length < 2) break; - Map.Load("Content/SavedMaps/" + commands[1]); + Submarine.Load("Content/SavedMaps/" + commands[1]); break; case "savegame": SaveUtil.SaveGame(SaveUtil.SaveFolder+"save"); diff --git a/Subsurface/Events/MonsterEvent.cs b/Subsurface/Events/MonsterEvent.cs index 6702dc2f2..7544fddc2 100644 --- a/Subsurface/Events/MonsterEvent.cs +++ b/Subsurface/Events/MonsterEvent.cs @@ -32,8 +32,8 @@ namespace Subsurface for (int i = 0; i < amount; i++) { Vector2 position = (randomWayPoint == null) ? Vector2.Zero : randomWayPoint.SimPosition; - position.X += ToolBox.RandomFloat(-0.5f,0.5f); - position.Y += ToolBox.RandomFloat(-0.5f,0.5f); + position.X += ToolBox.RandomFloatLocal(-0.5f,0.5f); + position.Y += ToolBox.RandomFloatLocal(-0.5f,0.5f); monsters[i] = new Character(characterFile, position); } } diff --git a/Subsurface/GUI/GUI.cs b/Subsurface/GUI/GUI.cs index f53eedb3c..9408588f0 100644 --- a/Subsurface/GUI/GUI.cs +++ b/Subsurface/GUI/GUI.cs @@ -7,7 +7,13 @@ using Microsoft.Xna.Framework.Input; namespace Subsurface { [Flags] - public enum Alignment { CenterX = 1, Left = 2, Right = 4, CenterY = 8, Top = 16, Bottom = 32 } + public enum Alignment + { + CenterX = 1, Left = 2, Right = 4, CenterY = 8, Top = 16, Bottom = 32 , + TopRight = (Top | Right), TopLeft = (Top | Left), TopCenter = (CenterX | Top), + Center = (CenterX | CenterY), + BottomRight = (Bottom | Right), BottomLeft = (Bottom | Left), BottomCenter = (CenterX | Bottom) + } class GUIMessage @@ -258,15 +264,15 @@ namespace Subsurface public static void Draw(float deltaTime, SpriteBatch spriteBatch, Camera cam) { - //spriteBatch.DrawString(font, - // "FPS: " + (int)Game1.frameCounter.AverageFramesPerSecond - // + " - render: "+Game1.renderTimeElapsed, - // new Vector2(10, 10), Color.White); + spriteBatch.DrawString(font, + "FPS: " + (int)Game1.frameCounter.AverageFramesPerSecond + + " - render: " + Game1.renderTimeElapsed, + new Vector2(10, 10), Color.White); - //spriteBatch.DrawString(font, - // "Physics: " + Game1.world.UpdateTime - // + " - bodies: " + Game1.world.BodyList.Count, - // new Vector2(10, 30), Color.White); + spriteBatch.DrawString(font, + "Physics: " + Game1.world.UpdateTime + + " - bodies: " + Game1.world.BodyList.Count, + new Vector2(10, 30), Color.White); if (Character.Controlled != null && cam!=null) Character.Controlled.DrawHud(spriteBatch, cam); diff --git a/Subsurface/Game1.cs b/Subsurface/Game1.cs index 0dc69062c..847a4062d 100644 --- a/Subsurface/Game1.cs +++ b/Subsurface/Game1.cs @@ -15,10 +15,12 @@ namespace Subsurface /// class Game1 : Game { - GraphicsDeviceManager graphics; + public static GraphicsDeviceManager graphics; static int graphicsWidth, graphicsHeight; static SpriteBatch spriteBatch; + public static GraphicsDevice CurrGraphicsDevice; + public static FrameCounter frameCounter; public static readonly Version version = Assembly.GetEntryAssembly().GetName().Version; @@ -46,7 +48,7 @@ namespace Subsurface public static Random localRandom; public static Random random; - private Stopwatch renderTimer; + //private Stopwatch renderTimer; public static int renderTimeElapsed; @@ -55,6 +57,7 @@ namespace Subsurface get { return GameScreen.Cam; } } + public static int GraphicsWidth { get { return graphicsWidth; } @@ -68,7 +71,7 @@ namespace Subsurface public Game1() { graphics = new GraphicsDeviceManager(this); - + graphicsWidth = 1280; graphicsHeight = 720; @@ -76,13 +79,13 @@ namespace Subsurface graphics.PreferredBackBufferWidth = graphicsWidth; graphics.PreferredBackBufferHeight = graphicsHeight; Content.RootDirectory = "Content"; - + //graphics.SynchronizeWithVerticalRetrace = false; //graphics.ApplyChanges(); frameCounter = new FrameCounter(); - renderTimer = new Stopwatch(); + //renderTimer = new Stopwatch(); IsMouseVisible = true; @@ -107,6 +110,8 @@ namespace Subsurface { base.Initialize(); + CurrGraphicsDevice = GraphicsDevice; + particleManager = new ParticleManager("Content/Particles/prefabs.xml", Cam); GameMode.Init(); @@ -145,7 +150,7 @@ namespace Subsurface AmbientSoundManager.Init("Content/Sounds/Sounds.xml"); - Map.PreloadMaps("Content/SavedMaps"); + Submarine.Preload("Content/SavedMaps"); GameScreen = new GameScreen(graphics.GraphicsDevice); MainMenuScreen = new MainMenuScreen(this); LobbyScreen = new LobbyScreen(); @@ -209,7 +214,7 @@ namespace Subsurface /// protected override void Draw(GameTime gameTime) { - renderTimer.Restart(); + //renderTimer.Restart(); double deltaTime = gameTime.ElapsedGameTime.TotalSeconds; @@ -217,8 +222,8 @@ namespace Subsurface Screen.Selected.Draw(deltaTime, GraphicsDevice, spriteBatch); - renderTimeElapsed = (int)renderTimer.Elapsed.Ticks; - renderTimer.Stop(); + //renderTimeElapsed = (int)renderTimer.Elapsed.Ticks; + //renderTimer.Stop(); } protected override void OnExiting(object sender, EventArgs args) diff --git a/Subsurface/GameSession/GameSession.cs b/Subsurface/GameSession/GameSession.cs index 6762a6f45..e2dab348a 100644 --- a/Subsurface/GameSession/GameSession.cs +++ b/Subsurface/GameSession/GameSession.cs @@ -27,15 +27,29 @@ namespace Subsurface private string savePath; - private Map selectedMap; + private Submarine submarine; - public GameSession(Map selectedMap, GameModePreset gameModePreset) - :this(selectedMap, gameModePreset.Instantiate()) + private Level level; + + public Map map; + + public Level Level + { + get { return level; } + } + + public Submarine Submarine + { + get { return submarine; } + } + + public GameSession(Submarine submarine, GameModePreset gameModePreset) + :this(submarine, gameModePreset.Instantiate()) { } - public GameSession(Map selectedMap, GameMode gameMode = null) + public GameSession(Submarine selectedMap, GameMode gameMode = null) { taskManager = new TaskManager(this); @@ -43,6 +57,8 @@ namespace Subsurface guiRoot = new GUIFrame(new Rectangle(0,0,Game1.GraphicsWidth,Game1.GraphicsWidth), Color.Transparent); + map = new Map(Game1.random.Next(), 500); + int width = 350, height = 100; if (Game1.Client!=null || Game1.Server!=null) { @@ -67,7 +83,7 @@ namespace Subsurface //startTime = DateTime.Now; //endTime = startTime + gameDuration; - this.selectedMap = selectedMap; + this.submarine = selectedMap; //if (!save) return; @@ -75,7 +91,7 @@ namespace Subsurface } - public GameSession(Map selectedMap, string savePath, string filePath) + public GameSession(Submarine selectedMap, string savePath, string filePath) : this(selectedMap) { XDocument doc = ToolBox.TryLoadXml(filePath); @@ -95,14 +111,31 @@ namespace Subsurface this.savePath = savePath; } + public void StartShift(TimeSpan duration, Level level) + { + + if (Submarine.Loaded != submarine) submarine.Load(); + + level.Generate(submarine==null ? 100.0f : Math.Max(Submarine.Borders.Width, Submarine.Borders.Height)); + + this.level = level; + + StartShift(duration, 1); + } + public void StartShift(TimeSpan duration, int scriptedEventCount = 1) { //if (crewManager.characterInfos.Count == 0) return; - if (Map.Loaded!=selectedMap) selectedMap.Load(); + if (Submarine.Loaded!=submarine) submarine.Load(); if (gameMode!=null) gameMode.Start(duration); + if (level!=null) + { + submarine.Move(level.StartPosition - submarine.Center, 1.0f); + } + //crewManager.StartShift(); taskManager.StartShift(scriptedEventCount); } @@ -122,7 +155,7 @@ namespace Subsurface SaveUtil.SaveGame(savePath); } - + taskManager.EndShift(); //gameMode.End(); diff --git a/Subsurface/Items/Components/Door.cs b/Subsurface/Items/Components/Door.cs index aa6bd1cbd..459cba8cd 100644 --- a/Subsurface/Items/Components/Door.cs +++ b/Subsurface/Items/Components/Door.cs @@ -215,7 +215,7 @@ namespace Subsurface.Items.Components { base.Move(amount); - LinkedGap.Move(amount); + //LinkedGap.Move(amount); body.SetTransform(body.Position + ConvertUnits.ToSimUnits(amount), 0.0f); diff --git a/Subsurface/Items/Components/MiniMap.cs b/Subsurface/Items/Components/MiniMap.cs index aa41886c1..1f501484d 100644 --- a/Subsurface/Items/Components/MiniMap.cs +++ b/Subsurface/Items/Components/MiniMap.cs @@ -41,12 +41,12 @@ namespace Subsurface.Items.Components Rectangle miniMap = new Rectangle(x + 20, y + 40, width - 40, height - 60); - float size = Math.Min((float)miniMap.Width / (float)Map.Borders.Width, (float)miniMap.Height / (float)Map.Borders.Height); + float size = Math.Min((float)miniMap.Width / (float)Submarine.Borders.Width, (float)miniMap.Height / (float)Submarine.Borders.Height); foreach (Hull hull in Hull.hullList) { Rectangle hullRect = new Rectangle( - miniMap.X + (int)((hull.Rect.X - Map.Borders.X) * size), - miniMap.Y - (int)((hull.Rect.Y - Map.Borders.Y) * size), + miniMap.X + (int)((hull.Rect.X - Submarine.Borders.X) * size), + miniMap.Y - (int)((hull.Rect.Y - Submarine.Borders.Y) * size), (int)(hull.Rect.Width * size), (int)(hull.Rect.Height * size)); @@ -71,8 +71,8 @@ namespace Subsurface.Items.Components if (c.animController.CurrentHull!=null) continue; Rectangle characterRect = new Rectangle( - miniMap.X + (int)((c.Position.X - Map.Borders.X) * size), - miniMap.Y - (int)((c.Position.Y - Map.Borders.Y) * size), + miniMap.X + (int)((c.Position.X - Submarine.Borders.X) * size), + miniMap.Y - (int)((c.Position.Y - Submarine.Borders.Y) * size), 5, 5); GUI.DrawRectangle(spriteBatch, characterRect, Color.White, true); diff --git a/Subsurface/Items/Components/RepairTool.cs b/Subsurface/Items/Components/RepairTool.cs index 9571498ba..f781bbf33 100644 --- a/Subsurface/Items/Components/RepairTool.cs +++ b/Subsurface/Items/Components/RepairTool.cs @@ -109,8 +109,8 @@ namespace Subsurface.Items.Components ignoredBodies.Add(limb.body.FarseerBody); } - Body targetBody = Map.PickBody(TransformedBarrelPos, targetPosition, ignoredBodies); - pickedPosition = Map.LastPickedPosition; + Body targetBody = Submarine.PickBody(TransformedBarrelPos, targetPosition, ignoredBodies); + pickedPosition = Submarine.LastPickedPosition; if (targetBody==null || targetBody.UserData==null) return true; diff --git a/Subsurface/Items/Components/Signal/ConnectionPanel.cs b/Subsurface/Items/Components/Signal/ConnectionPanel.cs index 884c82285..a331234a5 100644 --- a/Subsurface/Items/Components/Signal/ConnectionPanel.cs +++ b/Subsurface/Items/Components/Signal/ConnectionPanel.cs @@ -6,8 +6,7 @@ using System.Xml.Linq; namespace Subsurface.Items.Components { class ConnectionPanel : ItemComponent - { - + { public List connections; Character user; @@ -31,10 +30,20 @@ namespace Subsurface.Items.Components } } - public override void Move(Vector2 amount) - { - base.Move(amount); - } + //public override void Move(Vector2 amount) + //{ + // base.Move(amount); + + // foreach (Connection c in connections) + // { + // foreach (Wire w in c.wires) + // { + // if (w == null) continue; + + // w.Move + // } + // } + //} public override void DrawHUD(SpriteBatch spriteBatch, Character character) { diff --git a/Subsurface/Items/Components/Signal/Wire.cs b/Subsurface/Items/Components/Signal/Wire.cs index b2ce301cf..f00bc8503 100644 --- a/Subsurface/Items/Components/Signal/Wire.cs +++ b/Subsurface/Items/Components/Signal/Wire.cs @@ -35,6 +35,15 @@ namespace Subsurface.Items.Components connections = new Connection[2]; } + public override void Move(Vector2 amount) + { + amount = FarseerPhysics.ConvertUnits.ToDisplayUnits(amount); + for (int i = 0; i h.Rect.X && rect.X + rect.Width < h.Rect.X+h.Rect.Width && @@ -250,20 +250,20 @@ namespace Subsurface pos.Y = ConvertUnits.ToSimUnits(MathHelper.Clamp(lowerSurface, rect.Y-rect.Height, rect.Y)); Game1.particleManager.CreateParticle("watersplash", - new Vector2(pos.X, pos.Y - ToolBox.RandomFloat(0.0f, 0.1f)), - new Vector2(flowForce.X * ToolBox.RandomFloat(0.005f, 0.007f), flowForce.Y * ToolBox.RandomFloat(0.005f, 0.007f))); + new Vector2(pos.X, pos.Y - ToolBox.RandomFloatLocal(0.0f, 0.1f)), + new Vector2(flowForce.X * ToolBox.RandomFloatLocal(0.005f, 0.007f), flowForce.Y * ToolBox.RandomFloatLocal(0.005f, 0.007f))); - pos.Y = ConvertUnits.ToSimUnits(ToolBox.RandomFloat(lowerSurface, rect.Y - rect.Height)); + pos.Y = ConvertUnits.ToSimUnits(ToolBox.RandomFloatLocal(lowerSurface, rect.Y - rect.Height)); Game1.particleManager.CreateParticle("bubbles", pos, flowForce / 200.0f); } else { pos.Y += Math.Sign(flowForce.Y) * ConvertUnits.ToSimUnits(rect.Height / 2.0f); - for (int i = 0; i < rect.Width; i += (int)ToolBox.RandomFloat(80, 100)) + for (int i = 0; i < rect.Width; i += (int)ToolBox.RandomFloatLocal(80, 100)) { - pos.X = ConvertUnits.ToSimUnits(ToolBox.RandomFloat(rect.X, rect.X+rect.Width)); + pos.X = ConvertUnits.ToSimUnits(ToolBox.RandomFloatLocal(rect.X, rect.X+rect.Width)); Subsurface.Particles.Particle splash = Game1.particleManager.CreateParticle("watersplash", pos, - new Vector2(flowForce.X * ToolBox.RandomFloat(0.005f, 0.008f), flowForce.Y * ToolBox.RandomFloat(0.005f, 0.008f))); + new Vector2(flowForce.X * ToolBox.RandomFloatLocal(0.005f, 0.008f), flowForce.Y * ToolBox.RandomFloatLocal(0.005f, 0.008f))); if (splash!=null) splash.Size = splash.Size * MathHelper.Clamp(rect.Width / 50.0f, 0.8f, 4.0f); diff --git a/Subsurface/Map/Hull.cs b/Subsurface/Map/Hull.cs index 5cc7c7af6..c35bb3cf0 100644 --- a/Subsurface/Map/Hull.cs +++ b/Subsurface/Map/Hull.cs @@ -150,8 +150,8 @@ namespace Subsurface public override bool Contains(Vector2 position) { - return (Map.RectContains(rect, position) && - !Map.RectContains(new Rectangle(rect.X + 8, rect.Y - 8, rect.Width - 16, rect.Height - 16), position)); + return (Submarine.RectContains(rect, position) && + !Submarine.RectContains(new Rectangle(rect.X + 8, rect.Y - 8, rect.Width - 16, rect.Height - 16), position)); } public int GetWaveIndex(Vector2 position) @@ -189,7 +189,7 @@ namespace Subsurface if (EditWater) { Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); - if (Map.RectContains(rect, position)) + if (Submarine.RectContains(rect, position)) { if (PlayerInput.LeftButtonDown()) { @@ -210,7 +210,7 @@ namespace Subsurface for (int i = 0; i < waveY.Length; i++) { float maxDelta = Math.Max(Math.Abs(rightDelta[i]), Math.Abs(leftDelta[i])); - if (maxDelta > ToolBox.RandomFloat(0.2f,10.0f)) + if (maxDelta > ToolBox.RandomFloatLocal(0.2f,10.0f)) { Game1.particleManager.CreateParticle("mist", ConvertUnits.ToSimUnits(new Vector2(rect.X + WaveWidth * i,surface + waveY[i])), @@ -390,12 +390,12 @@ namespace Subsurface { if (guess != null && hullList.Contains(guess)) { - if (Map.RectContains(guess.rect, position)) return guess; + if (Submarine.RectContains(guess.rect, position)) return guess; } foreach (Hull w in hullList) { - if (Map.RectContains(w.rect, position)) return w; + if (Submarine.RectContains(w.rect, position)) return w; } return null; diff --git a/Subsurface/Map/Level.cs b/Subsurface/Map/Level.cs index 0c6715bfe..9851ce1f0 100644 --- a/Subsurface/Map/Level.cs +++ b/Subsurface/Map/Level.cs @@ -6,109 +6,548 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; +using System.Diagnostics; using Voronoi2; namespace Subsurface { class Level { + public static Level Loaded + { + get { return loaded; } + } + + static Level loaded; + private int seed; - List bodies; + private int siteInterval; + + const int gridCellWidth = 1000; + List[,] cellGrid; + + //List bodies; List cells; - public Level(int seed, int siteCount, int width, int height) + BasicEffect basicEffect; + + private VertexPositionColor[] vertices; + private VertexBuffer vertexBuffer; + + private Vector2 startPosition; + private Vector2 endPosition; + + Rectangle borders; + + public Vector2 StartPosition + { + get { return startPosition; } + } + + public Level(int seed, int width, int height, int siteInterval) { this.seed = seed; - Voronoi voronoi = new Voronoi(1.0); + this.siteInterval = siteInterval; - List sites = new List(); - Random rand = new Random(seed); + borders = new Rectangle(0, 0, width, height); + } - for (int i = 0; i < siteCount; i++) + public static Level CreateRandom() + { + return new Level(100, 100000, 40000, 2000); + } + + public void Generate(float minWidth) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + Game1.random = new Random(seed); + + if (loaded != this && loaded != null) { - sites.Add(new PointF((float)(rand.NextDouble() * width), (float)(rand.NextDouble() * width))); + loaded.Unload(); } - List graphEdges = MakeVoronoiGraph(sites, voronoi, width, height); + loaded = this; + Voronoi voronoi = new Voronoi(1.0); + + List sites = new List(); + Random rand = new Random(seed); + + float siteVariance = siteInterval * 0.8f; + for (int x = siteInterval/2; x < borders.Width; x += siteInterval) + { + for (int y = siteInterval / 2; y < borders.Height; y += siteInterval) + { + sites.Add(new Vector2( + x + (float)(Game1.random.NextDouble() - 0.5) * siteVariance, + y + (float)(Game1.random.NextDouble() - 0.5) * siteVariance)); + } + } + + Stopwatch sw2 = new Stopwatch(); + sw2.Start(); + + List graphEdges = voronoi.MakeVoronoiGraph(sites, borders.Width, borders.Height); + + + Debug.WriteLine("MakeVoronoiGraph: " + sw2.ElapsedMilliseconds + " ms"); + sw2.Restart(); + + cellGrid = new List[borders.Width / gridCellWidth, borders.Height / gridCellWidth]; + for (int x = 0; x < borders.Width / gridCellWidth; x++) + { + for (int y = 0; y < borders.Height / gridCellWidth; y++) + { + cellGrid[x, y] = new List(); + } + } + + //construct voronoi cells based on the graph edges cells = new List(); foreach (GraphEdge ge in graphEdges) { - for (int i = 0; i<2; i++) + for (int i = 0; i < 2; i++) { - Site site = (i==0) ? ge.site1 : ge.site2; - VoronoiCell cell = cells.Find(c => c.site == site); + Site site = (i == 0) ? ge.site1 : ge.site2; + + VoronoiCell cell = cellGrid[ + (int)Math.Floor(site.coord.x / gridCellWidth), + (int)Math.Floor(site.coord.y / gridCellWidth)].Find(c => c.site == site); + if (cell == null) { cell = new VoronoiCell(site); + cellGrid[(int)Math.Floor(cell.Center.X / gridCellWidth), (int)Math.Floor(cell.Center.Y / gridCellWidth)].Add(cell); cells.Add(cell); } - if (!cell.edges.Contains(ge)) cell.edges.Add(ge); + + if (ge.cell1 == null) + { + ge.cell1 = cell; + } + else + { + ge.cell2 = cell; + } + cell.edges.Add(ge); + } + } + + Debug.WriteLine("find cells: " + sw2.ElapsedMilliseconds + " ms"); + sw2.Restart(); + + //generate a path from the left edge of the map to right edge + Rectangle pathBorders = new Rectangle( + borders.X + (int)minWidth, borders.Y + (int)minWidth, + borders.Right - (int)minWidth, borders.Y + borders.Height - (int)minWidth); + + List pathCells = GeneratePath( + new Vector2((int)minWidth, Game1.random.Next((int)minWidth, borders.Height - (int)minWidth)), + new Vector2(borders.Width - (int)minWidth, Game1.random.Next((int)minWidth, borders.Height - (int)minWidth)), + cells, pathBorders, minWidth); + + + //generate a couple of random paths + for (int i = 0; i < Game1.random.Next() % 3; i++ ) + { + pathBorders = new Rectangle( + borders.X + siteInterval * 2, borders.Y - siteInterval * 2, + borders.Right - siteInterval * 2, borders.Y + borders.Height - siteInterval * 2); + + Vector2 start = pathCells[Game1.random.Next(1,pathCells.Count-2)].Center; + Vector2 end = new Vector2(ToolBox.RandomFloat(pathBorders.X, pathBorders.Right), ToolBox.RandomFloat(pathBorders.Y, pathBorders.Bottom)); + + pathCells.AddRange + ( + GeneratePath( start,end, cells, pathBorders, 0.0f) + ); + } + + Debug.WriteLine("path: " + sw2.ElapsedMilliseconds + " ms"); + sw2.Restart(); + + startPosition = pathCells[0].Center; + endPosition = pathCells[pathCells.Count - 1].Center; + + foreach (VoronoiCell cell in pathCells) + { + cells.Remove(cell); + } + + GenerateLevel(cells); + + Debug.WriteLine("Generatelevel: " + sw2.ElapsedMilliseconds + " ms"); + sw2.Restart(); + + vertexBuffer = new VertexBuffer(Game1.CurrGraphicsDevice, VertexPositionColor.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); + + vertexBuffer.SetData(vertices); + + basicEffect = new BasicEffect(Game1.CurrGraphicsDevice); + basicEffect.VertexColorEnabled = true; + + Debug.WriteLine("Generated a map with "+sites.Count+" sites in "+sw.ElapsedMilliseconds+" ms"); + } + + private List GeneratePath(Vector2 start, Vector2 end, List cells, Microsoft.Xna.Framework.Rectangle limits, float minWidth, float wanderAmount = 0.3f) + { + + Stopwatch sw2 = new Stopwatch(); + sw2.Start(); + + //how heavily the path "steers" towards the endpoint + //lower values will cause the path to "wander" more, higher will make it head straight to the end + wanderAmount = MathHelper.Clamp(wanderAmount, 0.0f, 1.0f); + + List pathCells = new List(); + + VoronoiCell currentCell = cells[FindCellIndex(start)]; + pathCells.Add(currentCell); + + VoronoiCell endCell = cells[FindCellIndex(end)]; + + do + { + int edgeIndex = 0; + + //steer towards target + if (Game1.random.NextDouble()>wanderAmount) + { + for (int i = 0; i < currentCell.edges.Count; i++) + { + if (!IsIntersecting(currentCell.Center, end, currentCell.edges[i].point1, currentCell.edges[i].point2)) continue; + edgeIndex = i; + break; + } + } + //choose random edge (ignoring ones where the adjacent cell is outside limits) + else + { + List allowedEdges = new List(); + + foreach(GraphEdge edge in currentCell.edges) + { + if (!limits.Contains(edge.AdjacentCell(currentCell).Center)) continue; + + allowedEdges.Add(edge); + } + edgeIndex = (allowedEdges.Count==0) ? + 0 : currentCell.edges.IndexOf(allowedEdges[Game1.random.Next() % allowedEdges.Count]); + } + + currentCell = currentCell.edges[edgeIndex].AdjacentCell(currentCell); + + + pathCells.Add(currentCell); + + } while (currentCell!=endCell); + + Debug.WriteLine("genpath: " + sw2.ElapsedMilliseconds + " ms"); + sw2.Restart(); + + List removedCells = GetTooCloseCells(pathCells, minWidth); + foreach (VoronoiCell removedCell in removedCells) + { + if (pathCells.Contains(removedCell)) continue; + pathCells.Add(removedCell); + } + + Debug.WriteLine("gettooclose: " + sw2.ElapsedMilliseconds + " ms"); + sw2.Restart(); + + return pathCells; + } + + private List GetTooCloseCells(List emptyCells, float minDistance) + { + List tooCloseCells = new List(); + + Vector2 position = emptyCells[0].Center; + + if (minDistance == 0.0f) return tooCloseCells; + + float step = 100.0f; + + int targetCellIndex = 1; + + minDistance *= 0.5f; + do + { + for (int x = -1; x<=1; x++) + { + for (int y = -1; y <= 1; y++) + { + if (x == 0 && y == 0) continue; + Vector2 cornerPos = position + new Vector2(x*minDistance, y*minDistance); + + int cellIndex = FindCellIndex(cornerPos); + if (cellIndex == -1) continue; + if (!tooCloseCells.Contains(cells[cellIndex])) + { + tooCloseCells.Add(cells[cellIndex]); + } + } + } + + position += Vector2.Normalize(emptyCells[targetCellIndex].Center - position) * step; + + if (Vector2.Distance(emptyCells[targetCellIndex].Center, position) < step * 2.0f) targetCellIndex++; + + } while (Vector2.Distance(position, emptyCells[emptyCells.Count - 1].Center) > step*2.0f); + + return tooCloseCells; + } + + /// + /// check whether line from a to b is intersecting with line from c to b + /// + bool IsIntersecting(Vector2 a, Vector2 b, Vector2 c, Vector2 d) + { + float denominator = ((b.X - a.X) * (d.Y - c.Y)) - ((b.Y - a.Y) * (d.X - c.X)); + float numerator1 = ((a.Y - c.Y) * (d.X - c.X)) - ((a.X - c.X) * (d.Y - c.Y)); + float numerator2 = ((a.Y - c.Y) * (b.X - a.X)) - ((a.X - c.X) * (b.Y - a.Y)); + + if (denominator == 0) return numerator1 == 0 && numerator2 == 0; + + float r = numerator1 / denominator; + float s = numerator2 / denominator; + + return (r >= 0 && r <= 1) && (s >= 0 && s <= 1); + } + + /// + /// find the index of the cell which the point is inside + /// (actually finds the cell whose center is closest, but it's always the correct cell assuming the point is inside the borders of the diagram) + /// + private int FindCellIndex(Vector2 position) + { + float closestDist = 0.0f; + VoronoiCell closestCell = null; + + int gridPosX = (int)Math.Floor(position.X / gridCellWidth); + int gridPosY = (int)Math.Floor(position.Y / gridCellWidth); + + int searchOffset = 1; + + for (int x = Math.Max(gridPosX-searchOffset,0); x<=Math.Min(gridPosX+searchOffset, cellGrid.GetLength(0)-1); x++) + { + for (int y = Math.Max(gridPosY-searchOffset,0); y<=Math.Min(gridPosY+searchOffset, cellGrid.GetLength(1)-1); y++) + { + for (int i = 0; i < cellGrid[x,y].Count; i++) + { + float dist = Vector2.Distance(cellGrid[x, y][i].Center, position); + if (closestDist != 0.0f && dist > closestDist) continue; + + closestDist = dist; + closestCell = cellGrid[x, y][i]; + } } } - bodies = new List(); + + return cells.IndexOf(closestCell); + } + + private void GenerateLevel(List cells) + { + List verticeList = new List(); + //bodies = new List(); + + + List tempVertices = new List(); + + int n = 0; foreach (VoronoiCell cell in cells) { - //List of vectors defining my custom poly - List vlist = new List(); + n = (n + 30) % 255; + + tempVertices.Clear(); foreach (GraphEdge ge in cell.edges) { - if (!vlist.Contains(ge.point1)) vlist.Add(ge.point1); - if (!vlist.Contains(ge.point2)) vlist.Add(ge.point2); + if (ge.point1 == ge.point2) continue; + if (!tempVertices.Contains(ge.point1)) tempVertices.Add(ge.point1); + if (!tempVertices.Contains(ge.point2)) tempVertices.Add(ge.point2); } - if (vlist.Count < 3) continue; + if (tempVertices.Count < 3) continue; + + int triangleCount = tempVertices.Count - 2; - for (int i = 0; i < vlist.Count; i++ ) + tempVertices.Sort(new CompareCCW(cell.Center)); + + int lastIndex = 1; + for (int i = 0; i < triangleCount; i++ ) { - vlist[i] = ConvertUnits.ToSimUnits(vlist[i]); + List triangleVertices = new List(); + + triangleVertices.Add(tempVertices[0]); + for (int j = lastIndex; j<=lastIndex+1; j++) + { + triangleVertices.Add(tempVertices[j]); + } + lastIndex += 1; + + foreach (Vector2 vertex in triangleVertices) + { + verticeList.Add(new VertexPositionColor(new Vector3(vertex, 0.0f), Color.LightGray*0.8f));//new Color(n,(n*2)%255,(n*3)%255)*0.5f)); + } + + bool isSame = false; + if (triangleVertices[0].Y == triangleVertices[1].Y && triangleVertices[1].Y == triangleVertices[2].Y) isSame = true; + if (triangleVertices[0].X == triangleVertices[1].X && triangleVertices[1].X == triangleVertices[2].X) isSame = true; + + if (isSame) continue; + + CreateBody(cell, triangleVertices); } - //get farseer 'vertices' from vectors - Vertices _shapevertices = new Vertices(vlist); - _shapevertices.Sort(new CompareCCW(cell.Center)); - - //feed vertices array to BodyFactory.CreatePolygon to get a new farseer polygonal body - Body _newBody = BodyFactory.CreatePolygon(Game1.world, _shapevertices, 15); - _newBody.BodyType = BodyType.Static; - _newBody.CollisionCategories = Physics.CollisionWall; - - bodies.Add(_newBody); } + + vertices = verticeList.ToArray(); + + //return bodies; } - List MakeVoronoiGraph(List sites, Voronoi voronoi, int width, int height) + private void CreateBody(VoronoiCell cell, List bodyVertices) { - double[] xVal = new double[sites.Count]; - double[] yVal = new double[sites.Count]; - for (int i = 0; i < sites.Count; i++) + for (int i = 0; i < bodyVertices.Count; i++) { - xVal[i] = sites[i].X; - yVal[i] = sites[i].Y; + bodyVertices[i] = ConvertUnits.ToSimUnits(bodyVertices[i]); } - return voronoi.generateVoronoi(xVal, yVal, 0, width, 0, height); + //get farseer 'vertices' from vectors + Vertices _shapevertices = new Vertices(bodyVertices); + //_shapevertices.Sort(new CompareCCW(cell.Center)); + + //feed vertices array to BodyFactory.CreatePolygon to get a new farseer polygonal body + Body _newBody = BodyFactory.CreatePolygon(Game1.world, _shapevertices, 15); + _newBody.BodyType = BodyType.Static; + _newBody.CollisionCategories = Physics.CollisionWall; + + cell.bodies.Add(_newBody); } - public void Render(SpriteBatch spriteBatch) + + Vector2 position; + public void Move(Vector2 amount, float deltaTime) { + amount = amount * deltaTime; + position += amount; + + amount = ConvertUnits.ToSimUnits(amount); + foreach (VoronoiCell cell in cells) + { + foreach (Body b in cell.bodies) + { + b.SetTransform(b.Position+amount, b.Rotation); + } + } + + } + + + + public void SetObserverPosition(Vector2 position) + { + position = position - this.position; + int gridPosX = (int)Math.Floor(position.X / gridCellWidth); + int gridPosY = (int)Math.Floor(position.Y / gridCellWidth); + int searchOffset = 1; + + for (int x = 0; x < cellGrid.GetLength(0); x++) + { + for (int y = 0; y (PrimitiveType.TriangleList, vertices, 0, (int)Math.Floor(vertices.Length / 3.0f)); + } + + private void Unload() + { + foreach (VoronoiCell cell in cells) + { + foreach (Body b in cell.bodies) + { + Game1.world.RemoveBody(b); + } + } + + + //bodies = null; + + vertices = null; + + cells = null; + + vertexBuffer.Dispose(); + vertexBuffer = null; + } + } + class CompareCCW : IComparer { private Vector2 center; @@ -119,24 +558,24 @@ namespace Subsurface } public int Compare(Vector2 a, Vector2 b) { - if (a.X - center.X >= 0 && b.X - center.X < 0) return 1; - if (a.X - center.X < 0 && b.X - center.X >= 0) return -1; + if (a.X - center.X >= 0 && b.X - center.X < 0) return -1; + if (a.X - center.X < 0 && b.X - center.X >= 0) return 1; if (a.X - center.X == 0 && b.X - center.X == 0) { - if (a.Y - center.Y >= 0 || b.Y - center.Y >= 0) return Math.Sign(a.Y - b.Y); - return Math.Sign(b.Y - a.Y); + if (a.Y - center.Y >= 0 || b.Y - center.Y >= 0) return Math.Sign(b.Y-a.Y); + return Math.Sign(a.Y-b.Y); } // compute the cross product of vectors (center -> a) x (center -> b) float det = (a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y); - if (det < 0) return 1; - if (det > 0) return -1; + if (det < 0) return -1; + if (det > 0) return 1; // points a and b are on the same line from the center // check which point is closer to the center float d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y); float d2 = (b.X - center.X) * (b.X - center.X) + (b.Y - center.Y) * (b.Y - center.Y); - return Math.Sign(d1 - d2); + return Math.Sign(d2-d1); } } diff --git a/Subsurface/Map/Location.cs b/Subsurface/Map/Location.cs new file mode 100644 index 000000000..f71f91d16 --- /dev/null +++ b/Subsurface/Map/Location.cs @@ -0,0 +1,37 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Subsurface +{ + class Location + { + string name; + + Vector2 mapPosition; + + public string Name + { + get { return name; } + } + + public Vector2 MapPosition + { + get { return mapPosition; } + } + + public Location(string name, Vector2 mapPosition) + { + this.name = name; + + this.mapPosition = mapPosition; + } + + public static Location CreateRandom(Vector2 position) + { + return new Location("Location " + (Game1.random.Next() % 10000), position); + } + } +} diff --git a/Subsurface/Map/Map.cs b/Subsurface/Map/Map.cs index 0ac4f41f1..91216ace7 100644 --- a/Subsurface/Map/Map.cs +++ b/Subsurface/Map/Map.cs @@ -1,539 +1,239 @@ -using FarseerPhysics; -using FarseerPhysics.Collision; -using FarseerPhysics.Dynamics; -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Reflection; -using System.Xml.Linq; +using System.Text; +using Voronoi2; namespace Subsurface { - public enum Direction : byte - { - None = 0, Left = 1, Right = 2 - } - class Map { - static string MapFolder; - MapHash mapHash; + private List levels; - public static List SavedMaps = new List(); + private List locations; - private static Map loaded; - - //public static Map Loaded - //{ - // get { return loaded; } - // set { loaded = value; } - //} - - - public static readonly Vector2 gridSize = new Vector2(16.0f, 16.0f); - - private static Vector2 lastPickedPosition; - private static float lastPickedFraction; - - private Rectangle borders; - - private string filePath; - private string name; - - public string Name - { - get { return name; } - } - - public static Vector2 LastPickedPosition - { - get { return lastPickedPosition; } - } - - public static float LastPickedFraction - { - get { return lastPickedFraction; } - } - - public MapHash MapHash - { - get - { - if (mapHash != null) return mapHash; - - XDocument doc = OpenDoc(filePath); - mapHash = new MapHash(doc); - - return mapHash; - } - } - - public static Map Loaded - { - get { return loaded; } - } - - public static Rectangle Borders - { - get - { - return (loaded==null) ? Rectangle.Empty : loaded.borders; - } - } - - public string FilePath - { - get { return filePath; } - } - - public static void Draw(SpriteBatch spriteBatch, bool editing = false) - { - for (int i = 0; i < MapEntity.mapEntityList.Count(); i++ ) - { - MapEntity.mapEntityList[i].Draw(spriteBatch, editing); - } - } - - public static void DrawFront(SpriteBatch spriteBatch, bool editing = false) - { - for (int i = 0; i < MapEntity.mapEntityList.Count(); i++) - { - if (MapEntity.mapEntityList[i].sprite == null || MapEntity.mapEntityList[i].sprite.Depth < 0.5f) - MapEntity.mapEntityList[i].Draw(spriteBatch, editing); - } - } - - public static void DrawBack(SpriteBatch spriteBatch, bool editing = false) - { - - for (int i = 0; i < MapEntity.mapEntityList.Count(); i++) - { - if (MapEntity.mapEntityList[i].sprite == null || MapEntity.mapEntityList[i].sprite.Depth >= 0.5f) - MapEntity.mapEntityList[i].Draw(spriteBatch, editing); - } - } - - public static Vector2 MouseToWorldGrid(Camera cam) - { - Vector2 position = new Vector2(PlayerInput.GetMouseState.X, PlayerInput.GetMouseState.Y); - position = cam.ScreenToWorld(position); - - return VectorToWorldGrid(position); - } - - public static Vector2 VectorToWorldGrid(Vector2 position) - { - position.X = (float)Math.Floor(Convert.ToDouble(position.X / gridSize.X)) * gridSize.X; - position.Y = (float)Math.Ceiling(Convert.ToDouble(position.Y / gridSize.Y)) * gridSize.Y; - - return position; - } - - - public static Rectangle AbsRect(Vector2 pos, Vector2 size) - { - if (size.X < 0.0f) - { - pos.X += size.X; - size.X = -size.X; - } - if (size.Y < 0.0f) - { - pos.Y -= size.Y; - size.Y = -size.Y; - } - - return new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y); - } - - public static bool RectContains(Rectangle rect, Vector2 pos) - { - return (pos.X > rect.X && pos.X < rect.X + rect.Width - && pos.Y < rect.Y && pos.Y > rect.Y - rect.Height); - } - - public static bool RectsOverlap(Rectangle rect1, Rectangle rect2, bool inclusive=true) - { - if (inclusive) - { - return !(rect1.X > rect2.X + rect2.Width || rect1.X + rect1.Width < rect2.X || - rect1.Y < rect2.Y - rect2.Height || rect1.Y - rect1.Height > rect2.Y); - } - else - { - return !(rect1.X >= rect2.X + rect2.Width || rect1.X + rect1.Width <= rect2.X || - rect1.Y <= rect2.Y - rect2.Height || rect1.Y - rect1.Height >= rect2.Y); - } - - } + private List connections; - public static Body PickBody(Vector2 rayStart, Vector2 rayEnd, List ignoredBodies = null) + private int seed; + private int size; + + private Location currentLocation; + private Location selectedLocation; + + public Map(int seed, int size) { - float closestFraction = 1.0f; - Body closestBody = null; - Game1.world.RayCast((fixture, point, normal, fraction) => - { - if (fixture == null || fixture.CollisionCategories == Category.None) return -1; - if (ignoredBodies != null && ignoredBodies.Contains(fixture.Body)) return -1; + this.seed = seed; - Structure structure = fixture.Body.UserData as Structure; - if (structure != null && (structure.IsPlatform || !structure.HasBody)) return -1; + this.size = size; - if (fraction < closestFraction) - { - closestFraction = fraction; - if (fixture.Body!=null) closestBody = fixture.Body; - } - return fraction; - } - , rayStart, rayEnd); + levels = new List(); - lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction; - lastPickedFraction = closestFraction; - return closestBody; - } + locations = new List(); + connections = new List(); - public static Body CheckVisibility(Vector2 rayStart, Vector2 rayEnd) - { - Body closestBody = null; - float closestFraction = 1.0f; + GenerateLocations(); - if (Vector2.Distance(rayStart,rayEnd)<0.01f) - { - closestFraction = 0.01f; - return null; - } - - Game1.world.RayCast((fixture, point, normal, fraction) => - { - if (fixture == null || fixture.CollisionCategories != Physics.CollisionWall) return -1; - - Structure structure = fixture.Body.UserData as Structure; - if (structure != null) - { - if (structure.IsPlatform || structure.StairDirection != Direction.None) return -1; - int sectionIndex = structure.FindSectionIndex(ConvertUnits.ToDisplayUnits(point)); - if (sectionIndex > -1 && structure.SectionHasHole(sectionIndex)) return -1; - } - - if (fraction < closestFraction) - { - closestBody = fixture.Body; - closestFraction = fraction; - } - return closestFraction; - } - , rayStart, rayEnd); - - - lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction; - lastPickedFraction = closestFraction; - return closestBody; - } - - public static Body PickBody(Vector2 point) - { - Body foundBody = null; - AABB aabb = new AABB(point, point); - - Game1.world.QueryAABB(p => - { - foundBody = p.Body; - - return true; - - }, ref aabb); - - return foundBody; - } - - public static bool InsideWall(Vector2 point) - { - Body foundBody = PickBody(point); - if (foundBody==null) return false; - - Structure wall = foundBody.UserData as Structure; - if (wall == null || wall.IsPlatform) return false; - - return true; - } - - - public void Save() - { - SaveAs(filePath); - } - - public void SaveAs(string filePath) - { - //if (filePath=="") + //for (int i = 0; i<10; i++) //{ - // DebugConsole.ThrowError("No save file selected"); - // return; + // Vector2 pos = new Vector2((float)Game1.random.NextDouble() * size, (float)Game1.random.NextDouble() * size); + + // Location location = + // locations.Add(location); //} - XDocument doc = new XDocument(new XElement((XName)name)); - foreach (MapEntity e in MapEntity.mapEntityList) - { - e.Save(doc); - } + //for (int i = 0; i < 10; i++) + //{ - mapHash = new MapHash(doc); - doc.Root.Add(new XAttribute("md5hash", mapHash.MD5Hash)); + // int closestIndex = 0; + // float closestDistance = 0.0f; + // for (int j = 0; j<10; j++) + // { + // if (j == i) continue; - try - { - SaveUtil.CompressStringToFile(filePath, doc.ToString()); - } - catch (Exception e) - { - DebugConsole.ThrowError("Saving map ''" + filePath + "'' failed!", e); - } + // //ignore if already connected + // bool alreadyConnected = false; + // foreach (LocationConnection connection in connections) + // { + // if (connection.Locations.Contains(locations[i]) && connection.Locations.Contains(locations[j])) + // { + // alreadyConnected = true; + // break; + // } + // } + // if (alreadyConnected) continue; - //doc.Save(filePath); + // float dist = Vector2.Distance(locations[i].MapPosition, locations[j].MapPosition); + // if (closestDistance > 0.0f && dist > closestDistance) continue; + + // closestDistance = dist; + // closestIndex = j; + // } + + + // connections.Add(new LocationConnection(locations[i], locations[closestIndex], level)); + //} + + currentLocation = locations[0]; } - public static void SaveCurrent(string savePath) + private void GenerateLocations() { - if (loaded==null) + Voronoi voronoi = new Voronoi(0.5f); + + List sites = new List(); + for (int i = 0; i < 50; i++) { - loaded = new Map(savePath); - return; + sites.Add(new Vector2((float)Game1.random.NextDouble() * size, (float)Game1.random.NextDouble() * size)); } - - loaded.SaveAs(savePath); - } - - public static void PreloadMaps(string mapFolder) - { - MapFolder = mapFolder; - - //string[] mapFilePaths; - Unload(); - SavedMaps.Clear(); - - if (!Directory.Exists(MapFolder)) - { - try - { - Directory.CreateDirectory(MapFolder); - } - catch - { - - DebugConsole.ThrowError("Directory ''Content/SavedMaps'' not found and creating the directory failed."); - return; - } - } - - string[] mapFilePaths; - - try - { - mapFilePaths = Directory.GetFiles(MapFolder); - } - catch (Exception e) - { - DebugConsole.ThrowError("Couldn't open directory ''Content/SavedMaps''!", e); - return; - } - - foreach (string mapPath in mapFilePaths) - { - //Map savedMap = new Map(mapPath); - SavedMaps.Add(new Map(mapPath)); - } - } - - public Map(string filePath, string mapHash="") - { - this.filePath = filePath; - try - { - name = Path.GetFileNameWithoutExtension(filePath); - } - catch (Exception e) - { - DebugConsole.ThrowError("Error loading map " + filePath + "!", e); - } - - - if (mapHash != "") - { - this.mapHash = new MapHash(mapHash); - } - else - { - //XDocument doc = OpenDoc(filePath); - - //string md5Hash = ToolBox.GetAttributeString(doc.Root, "md5hash", ""); - //if (md5Hash == "" || md5Hash.Length < 16) - //{ - // DebugConsole.ThrowError("Couldn't find a valid MD5 hash in the map file"); - //} - - //this.mapHash = new MapHash(md5Hash); - } - - } - - private XDocument OpenDoc(string file) - { - XDocument doc = null; - string extension = ""; - - try - { - extension = Path.GetExtension(file); - } - catch - { - DebugConsole.ThrowError("Couldn't load map ''" + file + "! (Unrecognized file extension)"); - return null; - } - - if (extension == ".gz") - { - Stream stream = SaveUtil.DecompressFiletoStream(file); - if (stream == null) - { - DebugConsole.ThrowError("Loading map ''" + file + "'' failed!"); - return null; - } - - try - { - stream.Position = 0; - doc = XDocument.Load(stream); //ToolBox.TryLoadXml(file); - stream.Close(); - stream.Dispose(); - } - - catch - { - DebugConsole.ThrowError("Loading map ''" + file + "'' failed!"); - return null; - } - } - else if (extension == ".xml") - { - try - { - doc = XDocument.Load(file); - } - - catch - { - DebugConsole.ThrowError("Loading map ''" + file + "'' failed!"); - return null; - } - } - else - { - DebugConsole.ThrowError("Couldn't load map ''" + file + "! (Unrecognized file extension)"); - return null; - } - - return doc; - } - - public void Load() - { - //string file = filePath; - - XDocument doc = OpenDoc(filePath); - if (doc == null) return; - - foreach (XElement element in doc.Root.Elements()) - { - string typeName = element.Name.ToString(); - - Type t; - try - { - // Get the type of a specified class. - t = Type.GetType("Subsurface." + typeName + ", Subsurface", true, true); - if (t == null) - { - DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type ''" + typeName + "''."); - continue; - } - } - catch (Exception e) - { - DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type ''" + typeName + "''.", e); - continue; - } - - try - { - MethodInfo loadMethod = t.GetMethod("Load"); - loadMethod.Invoke(t, new object[] { element }); - } - catch (Exception e) - { - DebugConsole.ThrowError("Could not find the method ''Load'' in " + t + ".", e); - } - - } - - borders = new Rectangle(0, 0, 1, 1); - foreach (Hull hull in Hull.hullList) - { - if (hull.Rect.X < borders.X || borders.X == 0) borders.X = hull.Rect.X; - if (hull.Rect.Y > borders.Y || borders.Y == 0) borders.Y = hull.Rect.Y; - - if (hull.Rect.X + hull.Rect.Width > borders.X + borders.Width) borders.Width = hull.Rect.X + hull.Rect.Width - borders.X; - if (hull.Rect.Y - hull.Rect.Height < borders.Y - borders.Height) borders.Height = borders.Y - (hull.Rect.Y - hull.Rect.Height); - } - - MapEntity.LinkAll(); - foreach (Item item in Item.itemList) - { - foreach (ItemComponent ic in item.components) - { - ic.OnMapLoaded(); - } - } - - loaded = this; - } - - public static Map Load(string file) - { - Unload(); - - Map map = new Map(file); - map.Load(); - - return map; + List edges = voronoi.MakeVoronoiGraph(sites, size, size); + sites.Clear(); + foreach (GraphEdge edge in edges) + { + if (edge.point1 == edge.point2) continue; + + Location[] newLocations = new Location[2]; + newLocations[0] = locations.Find(l => l.MapPosition == edge.point1 || l.MapPosition == edge.point2); + newLocations[1] = locations.Find(l => l != newLocations[0] && (l.MapPosition == edge.point1 || l.MapPosition == edge.point2)); + + for (int i = 0; i < 2; i++) + { + if (newLocations[i] != null) continue; + + Vector2[] points = new Vector2[] { edge.point1, edge.point2 }; + + int positionIndex = Game1.random.Next(0, 1); + + Vector2 position = points[positionIndex]; + if (newLocations[1 - i] != null && newLocations[1 - i].MapPosition == position) position = points[1 - positionIndex]; + + newLocations[i] = Location.CreateRandom(position); + locations.Add(newLocations[i]); + } + + connections.Add(new LocationConnection(newLocations[0], newLocations[1], Level.CreateRandom())); + } + + float minDistance = 50.0f; + for (int i = connections.Count - 1; i >= 0; i--) + { + LocationConnection connection = connections[i]; + + if (Vector2.Distance(connection.Locations[0].MapPosition, connection.Locations[1].MapPosition) > minDistance) continue; + + locations.Remove(connection.Locations[0]); + connections.Remove(connection); + + foreach (LocationConnection connection2 in connections) + { + if (connection2.Locations[0] == connection.Locations[0]) connection2.Locations[0] = connection.Locations[1]; + if (connection2.Locations[1] == connection.Locations[0]) connection2.Locations[1] = connection.Locations[1]; + } + } + } - public static void Unload() + public void Draw(SpriteBatch spriteBatch, Rectangle rect) { - if (loaded == null) return; - loaded.Clear(); - loaded = null; - } + GUI.DrawRectangle(spriteBatch, rect, Color.DarkBlue, true); - private void Clear() + Vector2 scale = new Vector2((float)rect.Width/ size, (float)rect.Height/size); + + float maxDist = 20.0f; + float closestDist = 0.0f; + Location highlightedLocation = null; + foreach (Location location in locations) + { + Vector2 pos = location.MapPosition * scale; + GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X + (int)pos.X, rect.Y + (int)pos.Y, 5, 5), Color.White, true); + + if (currentLocation == location) + { + GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X + (int)pos.X - 4, rect.Y + (int)pos.Y - 4, 5+8, 5+8), Color.Red, false); + } + + float dist = Vector2.Distance(PlayerInput.MousePosition, new Vector2(rect.X + pos.X, rect.Y + pos.Y)); + if (dist < maxDist && (highlightedLocation == null || dist < closestDist)) + { + closestDist = dist; + highlightedLocation = location; + } + } + + if (highlightedLocation!=null) + { + Vector2 pos = highlightedLocation.MapPosition * scale; + spriteBatch.DrawString(GUI.font, highlightedLocation.Name, pos + new Vector2(rect.X - 50, rect.Y), Color.White); + GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X + (int)pos.X - 4, rect.Y + (int)pos.Y - 4, 5 + 8, 5 + 8), Color.White, false); + } + + if (selectedLocation != null) + { + Vector2 pos = selectedLocation.MapPosition * scale; + spriteBatch.DrawString(GUI.font, selectedLocation.Name, pos + new Vector2(rect.X - 50, rect.Y), Color.White); + GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X + (int)pos.X - 4, rect.Y + (int)pos.Y - 4, 5 + 8, 5 + 8), Color.White, false); + } + + Vector2 rectCorner = new Vector2(rect.X, rect.Y); + foreach (LocationConnection connection in connections) + { + GUI.DrawLine(spriteBatch, + connection.Locations[0].MapPosition * scale + rectCorner, + connection.Locations[1].MapPosition * scale + rectCorner, Color.LightGray); + + if (highlightedLocation!=currentLocation && + connection.Locations.Contains(highlightedLocation) && connection.Locations.Contains(currentLocation)) + { + GUI.DrawLine(spriteBatch, + connection.Locations[0].MapPosition * scale + rectCorner +Vector2.One, + connection.Locations[1].MapPosition * scale + rectCorner + Vector2.One, Color.White); + + if (PlayerInput.LeftButtonClicked()) + if(selectedLocation!=highlightedLocation && highlightedLocation!=null) + { + //currentLocation = highlightedLocation; + Game1.LobbyScreen.SelectLocation(highlightedLocation, connection); + selectedLocation = highlightedLocation; + } + } + + if (selectedLocation != currentLocation && + (connection.Locations.Contains(selectedLocation) && connection.Locations.Contains(currentLocation))) + { + GUI.DrawLine(spriteBatch, + connection.Locations[0].MapPosition * scale + rectCorner + Vector2.One, + connection.Locations[1].MapPosition * scale + rectCorner + Vector2.One, Color.White); + + } + } + + } + } + + + class LocationConnection + { + Location[] locations; + Level level; + + public Location[] Locations { - if (Game1.GameScreen.Cam != null) Game1.GameScreen.Cam.TargetPos = Vector2.Zero; - - Entity.RemoveAll(); - - PhysicsBody.list.Clear(); - - Ragdoll.list.Clear(); - - Game1.world.Clear(); + get { return locations; } } + public Level Level + { + get { return level; } + } + + public LocationConnection(Location location1, Location location2, Level level) + { + locations = new Location[] { location1, location2 }; + this.level = level; + } } } diff --git a/Subsurface/Map/MapEntity.cs b/Subsurface/Map/MapEntity.cs index 34cfdbf1a..69837ac9b 100644 --- a/Subsurface/Map/MapEntity.cs +++ b/Subsurface/Map/MapEntity.cs @@ -117,7 +117,7 @@ namespace Subsurface public virtual bool Contains(Vector2 position) { - return (Map.RectContains(rect, position)); + return (Submarine.RectContains(rect, position)); } public virtual void Draw(SpriteBatch spriteBatch, bool editing) {} @@ -216,7 +216,7 @@ namespace Subsurface //mouse released -> move the entities to the new position of the mouse Vector2 moveAmount = position - startMovingPos; - moveAmount = Map.VectorToWorldGrid(moveAmount); + moveAmount = Submarine.VectorToWorldGrid(moveAmount); if (moveAmount != Vector2.Zero) { @@ -235,7 +235,7 @@ namespace Subsurface selectionSize.Y = selectionPos.Y - position.Y; List newSelection = new List();// FindSelectedEntities(selectionPos, selectionSize); - if (Math.Abs(selectionSize.X) > Map.gridSize.X || Math.Abs(selectionSize.Y) > Map.gridSize.Y) + if (Math.Abs(selectionSize.X) > Submarine.gridSize.X || Math.Abs(selectionSize.Y) > Submarine.gridSize.Y) { newSelection = FindSelectedEntities(selectionPos, selectionSize); } @@ -315,7 +315,7 @@ namespace Subsurface if (startMovingPos != Vector2.Zero) { Vector2 moveAmount = position - startMovingPos; - moveAmount = Map.VectorToWorldGrid(moveAmount); + moveAmount = Submarine.VectorToWorldGrid(moveAmount); moveAmount.Y = -moveAmount.Y; //started moving the selected entities if (moveAmount != Vector2.Zero) @@ -358,7 +358,7 @@ namespace Subsurface List foundEntities = new List(); foreach (MapEntity e in mapEntityList) { - if (Map.RectContains(e.rect, pos)) foundEntities.Add(e); + if (Submarine.RectContains(e.rect, pos)) foundEntities.Add(e); } return foundEntities; } @@ -367,7 +367,7 @@ namespace Subsurface { foreach (MapEntity e in mapEntityList) { - if (Map.RectContains(e.rect, pos)) return e; + if (Submarine.RectContains(e.rect, pos)) return e; } return null; } @@ -379,11 +379,11 @@ namespace Subsurface { List foundEntities = new List(); - Rectangle selectionRect = Map.AbsRect(pos, size); + Rectangle selectionRect = Submarine.AbsRect(pos, size); foreach (MapEntity e in mapEntityList) { - if (Map.RectsOverlap(selectionRect, e.rect)) + if (Submarine.RectsOverlap(selectionRect, e.rect)) foundEntities.Add(e); } diff --git a/Subsurface/Map/MapEntityPrefab.cs b/Subsurface/Map/MapEntityPrefab.cs index e3cf2210f..0f596b3b5 100644 --- a/Subsurface/Map/MapEntityPrefab.cs +++ b/Subsurface/Map/MapEntityPrefab.cs @@ -73,23 +73,23 @@ namespace Subsurface public virtual void UpdatePlacing(SpriteBatch spriteBatch, Camera cam) { - Vector2 placeSize = Map.gridSize; + Vector2 placeSize = Submarine.gridSize; if (placePosition == Vector2.Zero) { if (PlayerInput.GetMouseState.LeftButton == ButtonState.Pressed) - placePosition = Map.MouseToWorldGrid(cam); + placePosition = Submarine.MouseToWorldGrid(cam); } else { - Vector2 position = Map.MouseToWorldGrid(cam); + Vector2 position = Submarine.MouseToWorldGrid(cam); if (resizeHorizontal) placeSize.X = position.X - placePosition.X; if (resizeVertical) placeSize.Y = placePosition.Y - position.Y; - Rectangle newRect = Map.AbsRect(placePosition, placeSize); - newRect.Width = (int)Math.Max(newRect.Width, Map.gridSize.X); - newRect.Height = (int)Math.Max(newRect.Height, Map.gridSize.Y); + Rectangle newRect = Submarine.AbsRect(placePosition, placeSize); + newRect.Width = (int)Math.Max(newRect.Width, Submarine.gridSize.X); + newRect.Height = (int)Math.Max(newRect.Height, Submarine.gridSize.Y); if (PlayerInput.GetMouseState.LeftButton == ButtonState.Released) { diff --git a/Subsurface/Map/MapHash.cs b/Subsurface/Map/Md5Hash.cs similarity index 86% rename from Subsurface/Map/MapHash.cs rename to Subsurface/Map/Md5Hash.cs index e82fa2a03..5e3d71dca 100644 --- a/Subsurface/Map/MapHash.cs +++ b/Subsurface/Map/Md5Hash.cs @@ -1,14 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; +using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Xml.Linq; namespace Subsurface { - class MapHash + class Md5Hash { private string md5Hash; private string shortHash; @@ -29,14 +26,14 @@ namespace Subsurface } } - public MapHash(string md5Hash) + public Md5Hash(string md5Hash) { this.md5Hash = md5Hash; shortHash = GetShortHash(md5Hash); } - public MapHash(XDocument doc) + public Md5Hash(XDocument doc) { string docString = Regex.Replace(doc.ToString(), @"\s+", ""); // step 1, calculate MD5 hash from input diff --git a/Subsurface/Map/Structure.cs b/Subsurface/Map/Structure.cs index 0bb628ef3..f3ce6dc14 100644 --- a/Subsurface/Map/Structure.cs +++ b/Subsurface/Map/Structure.cs @@ -111,7 +111,7 @@ namespace Subsurface Vector2 simAmount = ConvertUnits.ToSimUnits(amount); foreach (Body b in bodies) { - b.SetTransform(b.Position + simAmount, 0.0f); + b.SetTransform(b.Position + simAmount, b.Rotation); } } @@ -203,15 +203,15 @@ namespace Subsurface bodies = new List(); Body newBody = BodyFactory.CreateRectangle(Game1.world, - ConvertUnits.ToSimUnits(rect.Width * Math.Sqrt(2.0) - Map.gridSize.X), + ConvertUnits.ToSimUnits(rect.Width * Math.Sqrt(2.0) - Submarine.gridSize.X), ConvertUnits.ToSimUnits(10), 1.5f); newBody.BodyType = BodyType.Static; Vector2 stairPos = new Vector2(Position.X, rect.Y - rect.Height + rect.Width / 2.0f); stairPos += new Vector2( - (StairDirection == Direction.Right) ? -Map.gridSize.X*1.5f : Map.gridSize.X*1.5f, - - Map.gridSize.Y*2.0f); + (StairDirection == Direction.Right) ? -Submarine.gridSize.X*1.5f : Submarine.gridSize.X*1.5f, + - Submarine.gridSize.Y*2.0f); newBody.Position = ConvertUnits.ToSimUnits(stairPos); diff --git a/Subsurface/Map/StructurePrefab.cs b/Subsurface/Map/StructurePrefab.cs index 4da137408..b353cccf8 100644 --- a/Subsurface/Map/StructurePrefab.cs +++ b/Subsurface/Map/StructurePrefab.cs @@ -109,7 +109,7 @@ namespace Subsurface public override void UpdatePlacing(SpriteBatch spriteBatch, Camera cam) { - Vector2 position = Map.MouseToWorldGrid(cam); + Vector2 position = Submarine.MouseToWorldGrid(cam); //Vector2 placeSize = size; Rectangle newRect = new Rectangle((int)position.X, (int)position.Y, (int)size.X, (int)size.Y); @@ -118,7 +118,7 @@ namespace Subsurface if (placePosition == Vector2.Zero) { if (PlayerInput.GetMouseState.LeftButton == ButtonState.Pressed) - placePosition = Map.MouseToWorldGrid(cam); + placePosition = Submarine.MouseToWorldGrid(cam); newRect.X = (int)position.X; newRect.Y = (int)position.Y; @@ -131,7 +131,7 @@ namespace Subsurface if (resizeHorizontal) placeSize.X = position.X - placePosition.X; if (resizeVertical) placeSize.Y = placePosition.Y - position.Y; - newRect = Map.AbsRect(placePosition, placeSize); + newRect = Submarine.AbsRect(placePosition, placeSize); //newRect.Width = (int)Math.Max(newRect.Width, Map.gridSize.X); //newRect.Height = (int)Math.Max(newRect.Height, Map.gridSize.Y); diff --git a/Subsurface/Map/Submarine.cs b/Subsurface/Map/Submarine.cs new file mode 100644 index 000000000..5b6722236 --- /dev/null +++ b/Subsurface/Map/Submarine.cs @@ -0,0 +1,564 @@ +using FarseerPhysics; +using FarseerPhysics.Collision; +using FarseerPhysics.Dynamics; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml.Linq; + +namespace Subsurface +{ + public enum Direction : byte + { + None = 0, Left = 1, Right = 2 + } + + class Submarine + { + static string SaveFolder; + Md5Hash hash; + + public static List SavedSubmarines = new List(); + + private static Submarine loaded; + + //public static Map Loaded + //{ + // get { return loaded; } + // set { loaded = value; } + //} + + + public static readonly Vector2 gridSize = new Vector2(16.0f, 16.0f); + + private static Vector2 lastPickedPosition; + private static float lastPickedFraction; + + private Rectangle borders; + + private string filePath; + private string name; + + public string Name + { + get { return name; } + } + + public static Vector2 LastPickedPosition + { + get { return lastPickedPosition; } + } + + public static float LastPickedFraction + { + get { return lastPickedFraction; } + } + + public Md5Hash Hash + { + get + { + if (hash != null) return hash; + + XDocument doc = OpenDoc(filePath); + hash = new Md5Hash(doc); + + return hash; + } + } + + public static Submarine Loaded + { + get { return loaded; } + } + + public static Rectangle Borders + { + get + { + return (loaded==null) ? Rectangle.Empty : loaded.borders; + } + } + + public Vector2 Center + { + get { return new Vector2(borders.X+borders.Width/2, borders.Y - borders.Height/2); } + } + + public string FilePath + { + get { return filePath; } + } + + public static void Draw(SpriteBatch spriteBatch, bool editing = false) + { + for (int i = 0; i < MapEntity.mapEntityList.Count(); i++ ) + { + MapEntity.mapEntityList[i].Draw(spriteBatch, editing); + } + } + + public static void DrawFront(SpriteBatch spriteBatch, bool editing = false) + { + for (int i = 0; i < MapEntity.mapEntityList.Count(); i++) + { + if (MapEntity.mapEntityList[i].sprite == null || MapEntity.mapEntityList[i].sprite.Depth < 0.5f) + MapEntity.mapEntityList[i].Draw(spriteBatch, editing); + } + } + + public static void DrawBack(SpriteBatch spriteBatch, bool editing = false) + { + for (int i = 0; i < MapEntity.mapEntityList.Count(); i++) + { + if (MapEntity.mapEntityList[i].sprite == null || MapEntity.mapEntityList[i].sprite.Depth >= 0.5f) + MapEntity.mapEntityList[i].Draw(spriteBatch, editing); + } + } + + public static Vector2 MouseToWorldGrid(Camera cam) + { + Vector2 position = new Vector2(PlayerInput.GetMouseState.X, PlayerInput.GetMouseState.Y); + position = cam.ScreenToWorld(position); + + return VectorToWorldGrid(position); + } + + public static Vector2 VectorToWorldGrid(Vector2 position) + { + position.X = (float)Math.Floor(Convert.ToDouble(position.X / gridSize.X)) * gridSize.X; + position.Y = (float)Math.Ceiling(Convert.ToDouble(position.Y / gridSize.Y)) * gridSize.Y; + + return position; + } + + + public static Rectangle AbsRect(Vector2 pos, Vector2 size) + { + if (size.X < 0.0f) + { + pos.X += size.X; + size.X = -size.X; + } + if (size.Y < 0.0f) + { + pos.Y -= size.Y; + size.Y = -size.Y; + } + + return new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y); + } + + public static bool RectContains(Rectangle rect, Vector2 pos) + { + return (pos.X > rect.X && pos.X < rect.X + rect.Width + && pos.Y < rect.Y && pos.Y > rect.Y - rect.Height); + } + + public static bool RectsOverlap(Rectangle rect1, Rectangle rect2, bool inclusive=true) + { + if (inclusive) + { + return !(rect1.X > rect2.X + rect2.Width || rect1.X + rect1.Width < rect2.X || + rect1.Y < rect2.Y - rect2.Height || rect1.Y - rect1.Height > rect2.Y); + } + else + { + return !(rect1.X >= rect2.X + rect2.Width || rect1.X + rect1.Width <= rect2.X || + rect1.Y <= rect2.Y - rect2.Height || rect1.Y - rect1.Height >= rect2.Y); + } + } + + public void Move(Vector2 amount, float deltaTime) + { + if (amount == Vector2.Zero) return; + + Level.Loaded.Move(-amount, deltaTime); + + //foreach (MapEntity e in Structure.mapEntityList) + //{ + // e.Move(amount); + //} + + //amount = ConvertUnits.ToSimUnits(amount*deltaTime); + //foreach (Character c in Character.characterList) + //{ + // if (c.animController.CurrentHull != null) continue; + // foreach (Limb l in c.animController.limbs) + // { + // l.body.SetTransform(l.body.Position - amount, l.body.Rotation); + // } + //} + } + + public static Body PickBody(Vector2 rayStart, Vector2 rayEnd, List ignoredBodies = null) + { + float closestFraction = 1.0f; + Body closestBody = null; + Game1.world.RayCast((fixture, point, normal, fraction) => + { + if (fixture == null || fixture.CollisionCategories == Category.None) return -1; + if (ignoredBodies != null && ignoredBodies.Contains(fixture.Body)) return -1; + + Structure structure = fixture.Body.UserData as Structure; + if (structure != null && (structure.IsPlatform || !structure.HasBody)) return -1; + + if (fraction < closestFraction) + { + closestFraction = fraction; + if (fixture.Body!=null) closestBody = fixture.Body; + } + return fraction; + } + , rayStart, rayEnd); + + lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction; + lastPickedFraction = closestFraction; + return closestBody; + } + + + public static Body CheckVisibility(Vector2 rayStart, Vector2 rayEnd) + { + Body closestBody = null; + float closestFraction = 1.0f; + + if (Vector2.Distance(rayStart,rayEnd)<0.01f) + { + closestFraction = 0.01f; + return null; + } + + Game1.world.RayCast((fixture, point, normal, fraction) => + { + if (fixture == null || fixture.CollisionCategories != Physics.CollisionWall) return -1; + + Structure structure = fixture.Body.UserData as Structure; + if (structure != null) + { + if (structure.IsPlatform || structure.StairDirection != Direction.None) return -1; + int sectionIndex = structure.FindSectionIndex(ConvertUnits.ToDisplayUnits(point)); + if (sectionIndex > -1 && structure.SectionHasHole(sectionIndex)) return -1; + } + + if (fraction < closestFraction) + { + closestBody = fixture.Body; + closestFraction = fraction; + } + return closestFraction; + } + , rayStart, rayEnd); + + + lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction; + lastPickedFraction = closestFraction; + return closestBody; + } + + public static Body PickBody(Vector2 point) + { + Body foundBody = null; + AABB aabb = new AABB(point, point); + + Game1.world.QueryAABB(p => + { + foundBody = p.Body; + + return true; + + }, ref aabb); + + return foundBody; + } + + public static bool InsideWall(Vector2 point) + { + Body foundBody = PickBody(point); + if (foundBody==null) return false; + + Structure wall = foundBody.UserData as Structure; + if (wall == null || wall.IsPlatform) return false; + + return true; + } + + + public void Save() + { + SaveAs(filePath); + } + + public void SaveAs(string filePath) + { + //if (filePath=="") + //{ + // DebugConsole.ThrowError("No save file selected"); + // return; + //} + XDocument doc = new XDocument(new XElement((XName)name)); + + foreach (MapEntity e in MapEntity.mapEntityList) + { + e.Save(doc); + } + + hash = new Md5Hash(doc); + doc.Root.Add(new XAttribute("md5hash", hash.MD5Hash)); + + try + { + SaveUtil.CompressStringToFile(filePath, doc.ToString()); + } + catch (Exception e) + { + DebugConsole.ThrowError("Saving submarine ''" + filePath + "'' failed!", e); + } + + + //doc.Save(filePath); + } + + public static void SaveCurrent(string savePath) + { + if (loaded==null) + { + loaded = new Submarine(savePath); + return; + } + + loaded.SaveAs(savePath); + } + + public static void Preload(string folder) + { + SaveFolder = folder; + + //string[] mapFilePaths; + Unload(); + SavedSubmarines.Clear(); + + if (!Directory.Exists(SaveFolder)) + { + try + { + Directory.CreateDirectory(SaveFolder); + } + catch + { + + DebugConsole.ThrowError("Directory ''"+SaveFolder+"'' not found and creating the directory failed."); + return; + } + } + + string[] filePaths; + + try + { + filePaths = Directory.GetFiles(SaveFolder); + } + catch (Exception e) + { + DebugConsole.ThrowError("Couldn't open directory ''" + SaveFolder + "''!", e); + return; + } + + foreach (string path in filePaths) + { + //Map savedMap = new Map(mapPath); + SavedSubmarines.Add(new Submarine(path)); + } + } + + public Submarine(string filePath, string hash="") + { + this.filePath = filePath; + try + { + name = Path.GetFileNameWithoutExtension(filePath); + } + catch (Exception e) + { + DebugConsole.ThrowError("Error loading map " + filePath + "!", e); + } + + + if (hash != "") + { + this.hash = new Md5Hash(hash); + } + else + { + //XDocument doc = OpenDoc(filePath); + + //string md5Hash = ToolBox.GetAttributeString(doc.Root, "md5hash", ""); + //if (md5Hash == "" || md5Hash.Length < 16) + //{ + // DebugConsole.ThrowError("Couldn't find a valid MD5 hash in the map file"); + //} + + //this.mapHash = new MapHash(md5Hash); + } + + } + + private XDocument OpenDoc(string file) + { + XDocument doc = null; + string extension = ""; + + try + { + extension = Path.GetExtension(file); + } + catch + { + DebugConsole.ThrowError("Couldn't load submarine ''" + file + "! (Unrecognized file extension)"); + return null; + } + + if (extension == ".gz") + { + Stream stream = SaveUtil.DecompressFiletoStream(file); + if (stream == null) + { + DebugConsole.ThrowError("Loading submarine ''" + file + "'' failed!"); + return null; + } + + try + { + stream.Position = 0; + doc = XDocument.Load(stream); //ToolBox.TryLoadXml(file); + stream.Close(); + stream.Dispose(); + } + + catch + { + DebugConsole.ThrowError("Loading submarine ''" + file + "'' failed!"); + return null; + } + } + else if (extension == ".xml") + { + try + { + doc = XDocument.Load(file); + } + + catch + { + DebugConsole.ThrowError("Loading submarine ''" + file + "'' failed!"); + return null; + } + } + else + { + DebugConsole.ThrowError("Couldn't load submarine ''" + file + "! (Unrecognized file extension)"); + return null; + } + + return doc; + } + + public void Load() + { + //string file = filePath; + + XDocument doc = OpenDoc(filePath); + if (doc == null) return; + + foreach (XElement element in doc.Root.Elements()) + { + string typeName = element.Name.ToString(); + + Type t; + try + { + // Get the type of a specified class. + t = Type.GetType("Subsurface." + typeName + ", Subsurface", true, true); + if (t == null) + { + DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type ''" + typeName + "''."); + continue; + } + } + catch (Exception e) + { + DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type ''" + typeName + "''.", e); + continue; + } + + try + { + MethodInfo loadMethod = t.GetMethod("Load"); + loadMethod.Invoke(t, new object[] { element }); + } + catch (Exception e) + { + DebugConsole.ThrowError("Could not find the method ''Load'' in " + t + ".", e); + } + + } + + borders = new Rectangle(0, 0, 1, 1); + foreach (Hull hull in Hull.hullList) + { + if (hull.Rect.X < borders.X || borders.X == 0) borders.X = hull.Rect.X; + if (hull.Rect.Y > borders.Y || borders.Y == 0) borders.Y = hull.Rect.Y; + + if (hull.Rect.X + hull.Rect.Width > borders.X + borders.Width) borders.Width = hull.Rect.X + hull.Rect.Width - borders.X; + if (hull.Rect.Y - hull.Rect.Height < borders.Y - borders.Height) borders.Height = borders.Y - (hull.Rect.Y - hull.Rect.Height); + } + + MapEntity.LinkAll(); + foreach (Item item in Item.itemList) + { + foreach (ItemComponent ic in item.components) + { + ic.OnMapLoaded(); + } + } + + loaded = this; + } + + public static Submarine Load(string file) + { + Unload(); + + Submarine sub = new Submarine(file); + sub.Load(); + + return sub; + + } + + public static void Unload() + { + if (loaded == null) return; + loaded.Clear(); + loaded = null; + } + + private void Clear() + { + if (Game1.GameScreen.Cam != null) Game1.GameScreen.Cam.TargetPos = Vector2.Zero; + + Entity.RemoveAll(); + + PhysicsBody.list.Clear(); + + Ragdoll.list.Clear(); + + Game1.world.Clear(); + } + + } +} diff --git a/Subsurface/Map/Voronoi.cs b/Subsurface/Map/Voronoi.cs index 8b8e0ed16..3b456efbb 100644 --- a/Subsurface/Map/Voronoi.cs +++ b/Subsurface/Map/Voronoi.cs @@ -972,5 +972,17 @@ namespace Voronoi2 return true; } + public List MakeVoronoiGraph(List sites, int width, int height) + { + double[] xVal = new double[sites.Count]; + double[] yVal = new double[sites.Count]; + for (int i = 0; i < sites.Count; i++) + { + xVal[i] = sites[i].X; + yVal[i] = sites[i].Y; + } + return generateVoronoi(xVal, yVal, 0, width, 0, height); + } + } // Voronoi Class End } // namespace Voronoi2 End \ No newline at end of file diff --git a/Subsurface/Map/VoronoiElements.cs b/Subsurface/Map/VoronoiElements.cs index 3728524d9..7b5aa49a6 100644 --- a/Subsurface/Map/VoronoiElements.cs +++ b/Subsurface/Map/VoronoiElements.cs @@ -50,7 +50,9 @@ */ +using FarseerPhysics.Dynamics; using Microsoft.Xna.Framework; +using Subsurface; using System; using System.Collections.Generic; @@ -119,6 +121,8 @@ namespace Voronoi2 public List edges; public Site site; + public List bodies; + public Vector2 Center { get { return new Vector2((float)site.coord.x, (float)site.coord.y); } @@ -127,6 +131,8 @@ namespace Voronoi2 public VoronoiCell(Site site) { edges = new List(); + + bodies = new List(); this.site = site; } } @@ -135,6 +141,23 @@ namespace Voronoi2 { public Vector2 point1, point2; public Site site1, site2; + public VoronoiCell cell1, cell2; + + public VoronoiCell AdjacentCell(VoronoiCell cell) + { + if (cell1==cell) + { + return cell2; + } + else if (cell2==cell) + { + return cell1; + } + else + { + return null; + } + } } // للترتيب diff --git a/Subsurface/Map/WayPoint.cs b/Subsurface/Map/WayPoint.cs index cb8b17421..5abea6130 100644 --- a/Subsurface/Map/WayPoint.cs +++ b/Subsurface/Map/WayPoint.cs @@ -68,7 +68,7 @@ namespace Subsurface if (e.GetType()!=typeof(WayPoint)) continue; if (e == this) continue; - if (!Map.RectContains(e.Rect, position)) continue; + if (!Submarine.RectContains(e.Rect, position)) continue; linkedTo.Add(e); e.linkedTo.Add(this); @@ -123,7 +123,7 @@ namespace Subsurface Rectangle rect = new Rectangle( int.Parse(element.Attribute("x").Value), int.Parse(element.Attribute("y").Value), - (int)Map.gridSize.X, (int)Map.gridSize.Y); + (int)Submarine.gridSize.X, (int)Submarine.gridSize.Y); WayPoint w = new WayPoint(rect); diff --git a/Subsurface/Networking/GameClient.cs b/Subsurface/Networking/GameClient.cs index e3108b808..4ec335a25 100644 --- a/Subsurface/Networking/GameClient.cs +++ b/Subsurface/Networking/GameClient.cs @@ -240,7 +240,7 @@ namespace Subsurface.Networking TimeSpan duration = new TimeSpan(0,(int)durationMinutes,0); //int gameModeIndex = inc.ReadInt32(); - Game1.GameSession = new GameSession(Map.Loaded); + Game1.GameSession = new GameSession(Submarine.Loaded); Game1.GameSession.StartShift(duration, 1); myCharacter = ReadCharacterData(inc); @@ -323,7 +323,7 @@ namespace Subsurface.Networking public void EndGame(string endMessage) { - Map.Unload(); + Submarine.Unload(); Game1.NetLobbyScreen.Select(); diff --git a/Subsurface/Networking/GameServer.cs b/Subsurface/Networking/GameServer.cs index d57040920..27097b277 100644 --- a/Subsurface/Networking/GameServer.cs +++ b/Subsurface/Networking/GameServer.cs @@ -270,7 +270,7 @@ namespace Subsurface.Networking int seed = DateTime.Now.Millisecond; Game1.random = new Random(seed); - Map selectedMap = Game1.NetLobbyScreen.SelectedMap as Map; + Submarine selectedMap = Game1.NetLobbyScreen.SelectedMap as Submarine; //selectedMap.Load(); @@ -307,7 +307,7 @@ namespace Subsurface.Networking msg.Write(seed); msg.Write(Game1.NetLobbyScreen.SelectedMap.Name); - msg.Write(Game1.NetLobbyScreen.SelectedMap.MapHash.MD5Hash); + msg.Write(Game1.NetLobbyScreen.SelectedMap.Hash.MD5Hash); msg.Write(Game1.NetLobbyScreen.GameDuration.TotalMinutes); @@ -339,7 +339,7 @@ namespace Subsurface.Networking public void EndGame(string endMessage) { - Map.Unload(); + Submarine.Unload(); gameStarted = false; diff --git a/Subsurface/Particles/Particle.cs b/Subsurface/Particles/Particle.cs index cc17f32e7..17fea5eb3 100644 --- a/Subsurface/Particles/Particle.cs +++ b/Subsurface/Particles/Particle.cs @@ -66,7 +66,7 @@ namespace Subsurface.Particles velocity = speed; - this.rotation = rotation + ToolBox.RandomFloat(prefab.startRotationMin, prefab.startRotationMax); + this.rotation = rotation + ToolBox.RandomFloatLocal(prefab.startRotationMin, prefab.startRotationMax); prevRotation = rotation; float rand = (float)Game1.localRandom.NextDouble(); @@ -132,7 +132,7 @@ namespace Subsurface.Particles } else { - if (Map.InsideWall(new Vector2(drawPosition.X, -drawPosition.Y))) + if (Submarine.InsideWall(new Vector2(drawPosition.X, -drawPosition.Y))) { return false; } diff --git a/Subsurface/Particles/ParticleManager.cs b/Subsurface/Particles/ParticleManager.cs index ad65a31c0..967b18409 100644 --- a/Subsurface/Particles/ParticleManager.cs +++ b/Subsurface/Particles/ParticleManager.cs @@ -61,7 +61,7 @@ namespace Subsurface.Particles public Particle CreateParticle(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation=0.0f) { - if (!Map.RectContains(cam.WorldView, ConvertUnits.ToDisplayUnits(position))) return null; + if (!Submarine.RectContains(cam.WorldView, ConvertUnits.ToDisplayUnits(position))) return null; if (particleCount >= MaxParticles) return null; if (particles[particleCount] == null) particles[particleCount] = new Particle(); diff --git a/Subsurface/SaveUtil.cs b/Subsurface/SaveUtil.cs index beef366c4..a4651ee82 100644 --- a/Subsurface/SaveUtil.cs +++ b/Subsurface/SaveUtil.cs @@ -23,7 +23,7 @@ namespace Subsurface //Directory.CreateDirectory(Path.GetDirectoryName(filePath) + "\\temp"); - Map.Loaded.SaveAs(tempPath + "\\map.gz"); + Submarine.Loaded.SaveAs(tempPath + "\\map.gz"); Game1.GameSession.Save(tempPath + "\\gamesession.xml"); //Game1.GameSession.crewManager.Save(directory+"\\crew.xml"); @@ -39,7 +39,7 @@ namespace Subsurface DecompressToDirectory(filePath, tempPath, null); - Map selectedMap = Map.Load(tempPath +"\\map.gz"); + Submarine selectedMap = Submarine.Load(tempPath +"\\map.gz"); Game1.GameSession = new GameSession(selectedMap, filePath, tempPath + "\\gamesession.xml"); Directory.Delete(tempPath, true); diff --git a/Subsurface/Screens/EditCharacterScreen.cs b/Subsurface/Screens/EditCharacterScreen.cs index d5e05605e..4b115ddd3 100644 --- a/Subsurface/Screens/EditCharacterScreen.cs +++ b/Subsurface/Screens/EditCharacterScreen.cs @@ -140,7 +140,7 @@ namespace Subsurface null, null, null, null, cam.Transform); - Map.Draw(spriteBatch, true); + Submarine.Draw(spriteBatch, true); spriteBatch.End(); diff --git a/Subsurface/Screens/EditMapScreen.cs b/Subsurface/Screens/EditMapScreen.cs index bce806af2..2b66d4d05 100644 --- a/Subsurface/Screens/EditMapScreen.cs +++ b/Subsurface/Screens/EditMapScreen.cs @@ -229,7 +229,7 @@ namespace Subsurface graphics.Clear(new Color(0.051f, 0.149f, 0.271f, 1.0f)); - Map.Draw(spriteBatch, true); + Submarine.Draw(spriteBatch, true); if (!characterMode) { diff --git a/Subsurface/Screens/GameScreen.cs b/Subsurface/Screens/GameScreen.cs index 6d7a8ee63..51b09b751 100644 --- a/Subsurface/Screens/GameScreen.cs +++ b/Subsurface/Screens/GameScreen.cs @@ -57,16 +57,16 @@ namespace Subsurface AmbientSoundManager.Update(); - //Vector2 targetMovement = Vector2.Zero; - //if (PlayerInput.KeyDown(Keys.I)) targetMovement.Y += 1.0f; - //if (PlayerInput.KeyDown(Keys.K)) targetMovement.Y -= 1.0f; - //if (PlayerInput.KeyDown(Keys.J)) targetMovement.X -= 1.0f; - //if (PlayerInput.KeyDown(Keys.L)) targetMovement.X += 1.0f; + if (Game1.GameSession.Level!=null) + { + Vector2 targetMovement = Vector2.Zero; + if (PlayerInput.KeyDown(Keys.I)) targetMovement.Y += 1.0f; + if (PlayerInput.KeyDown(Keys.K)) targetMovement.Y -= 1.0f; + if (PlayerInput.KeyDown(Keys.J)) targetMovement.X -= 1.0f; + if (PlayerInput.KeyDown(Keys.L)) targetMovement.X += 1.0f; - //foreach (MapEntity e in Structure.mapEntityList) - //{ - // e.Move(targetMovement); - //} + Game1.GameSession.Submarine.Move(targetMovement*1000.0f, (float)deltaTime); + } if (Game1.GameSession!=null) Game1.GameSession.Update((float)deltaTime); //EventManager.Update(gameTime); @@ -170,8 +170,8 @@ namespace Subsurface if (y<0) { - backgroundTop.SourceRect = new Rectangle(x, y, 1024, 1024); - backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(Game1.GraphicsWidth, Math.Min(1024 - y, Game1.GraphicsHeight)), + backgroundTop.SourceRect = new Rectangle(x, y, 1024, Math.Min(-y,1024)); + backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(Game1.GraphicsWidth, Math.Min(-y, Game1.GraphicsHeight)), Vector2.Zero, Color.White); } } @@ -183,10 +183,8 @@ namespace Subsurface BlendState.AlphaBlend, null, null, null, null, cam.Transform); - - if (Game1.Level!=null) Game1.Level.Render(spriteBatch); - Map.DrawBack(spriteBatch); + Submarine.DrawBack(spriteBatch); foreach (Character c in Character.characterList) c.Draw(spriteBatch); @@ -257,10 +255,18 @@ namespace Subsurface null, null, null, null, cam.Transform); - Map.DrawFront(spriteBatch); - + Submarine.DrawFront(spriteBatch); + spriteBatch.End(); + if (Game1.GameSession != null && Game1.GameSession.Level != null) + { + Game1.GameSession.Level.Render(graphics, cam); + Game1.GameSession.Level.SetObserverPosition(cam.WorldViewCenter); + } + + if (Game1.Level != null) Game1.Level.Render(graphics, cam); + LightManager.DrawFow(graphics,cam); } } diff --git a/Subsurface/Screens/LobbyScreen.cs b/Subsurface/Screens/LobbyScreen.cs index 508569e85..42a25bee0 100644 --- a/Subsurface/Screens/LobbyScreen.cs +++ b/Subsurface/Screens/LobbyScreen.cs @@ -9,10 +9,12 @@ namespace Subsurface { class LobbyScreen : Screen { + enum PanelTab { Crew = 0, Map = 1, Hire = 2 } + GUIFrame leftPanel; GUIFrame[] rightPanel; - GUIFrame shiftPanel; + GUIButton startButton; int selectedRightPanel; @@ -26,6 +28,8 @@ namespace Subsurface Character previewCharacter; + Level selectedLevel; + public LobbyScreen() { Rectangle panelRect = new Rectangle( @@ -44,62 +48,55 @@ namespace Subsurface "", Color.Transparent, Color.White, Alignment.Left, leftPanel); moneyText.TextGetter = GetMoney; - GUIButton button = new GUIButton(new Rectangle(0, 60, 100, 30), "Crew", GUI.style, Alignment.CenterX, leftPanel); - button.UserData = 0; + + + GUIButton button = new GUIButton(new Rectangle(0, 60, 100, 30), "Map", GUI.style, Alignment.Left, leftPanel); + button.UserData = PanelTab.Map; button.OnClicked = SelectRightPanel; - button = new GUIButton(new Rectangle(0, 100, 100, 30), "Hire", GUI.style, Alignment.CenterX, leftPanel); - button.UserData = 1; + button = new GUIButton(new Rectangle(0, 100, 100, 30), "Crew", GUI.style, Alignment.Left, leftPanel); + button.UserData = PanelTab.Crew; button.OnClicked = SelectRightPanel; - //-------------------------------------- + button = new GUIButton(new Rectangle(0, 140, 100, 30), "Hire", GUI.style, Alignment.Left, leftPanel); + button.UserData = PanelTab.Hire; + button.OnClicked = SelectRightPanel; + + //--------------------------------------------------------------- + //--------------------------------------------------------------- panelRect = new Rectangle( panelRect.X + panelRect.Width + (int)(GUI.style.largePadding.X), - panelRect.Y, + (int)GUI.style.largePadding.Y, Game1.GraphicsWidth - panelRect.Width - (int)(GUI.style.largePadding.X * 3.0f), - (int)(Game1.GraphicsHeight * 0.3f) - (int)(GUI.style.largePadding.Y * 1.5f)); + Game1.GraphicsHeight - (int)(GUI.style.largePadding.Y * 2)); - shiftPanel = new GUIFrame(panelRect, GUI.style.backGroundColor); - shiftPanel.Padding = GUI.style.smallPadding; + rightPanel = new GUIFrame[3]; - GUITextBlock dayText = new GUITextBlock(new Rectangle(0, 0, 200, 25), - "", Color.Transparent, Color.White, Alignment.Left, shiftPanel); - dayText.TextGetter = GetDay; + rightPanel[(int)PanelTab.Crew] = new GUIFrame(panelRect, GUI.style.backGroundColor); + rightPanel[(int)PanelTab.Crew].Padding = GUI.style.smallPadding; - GUIProgressBar progressBar = new GUIProgressBar(new Rectangle(0, 30, 200, 20), Color.Green, 0.0f, shiftPanel); - progressBar.ProgressGetter = GetWeekProgress; + new GUITextBlock(new Rectangle(0, 0, 200, 25), "Crew:", Color.Transparent, Color.White, Alignment.Left, rightPanel[(int)PanelTab.Crew]); - - button = new GUIButton(new Rectangle(0,0,100,30), "Start", GUI.style, - (Alignment.Right | Alignment.Bottom), shiftPanel); - button.OnClicked = StartShift; - - //--------------------------------------------------------------- - //--------------------------------------------------------------- - - rightPanel = new GUIFrame[2]; - - panelRect = new Rectangle( - panelRect.X, - panelRect.Y + panelRect.Height + (int)(GUI.style.largePadding.Y), - panelRect.Width, - (int)(Game1.GraphicsHeight * 0.7f) - (int)(GUI.style.largePadding.Y * 1.5f)); - - rightPanel[0] = new GUIFrame(panelRect, GUI.style.backGroundColor); - rightPanel[0].Padding = GUI.style.smallPadding; - - new GUITextBlock(new Rectangle(0, 0, 200, 25), "Crew:", Color.Transparent, Color.White, Alignment.Left, rightPanel[0]); - - characterList = new GUIListBox(new Rectangle(0, 30, 300, 0), Color.White, rightPanel[0]); + characterList = new GUIListBox(new Rectangle(0, 30, 300, 0), Color.White, rightPanel[(int)PanelTab.Crew]); characterList.OnSelected = SelectCharacter; //--------------------------------------- - rightPanel[1] = new GUIFrame(panelRect, GUI.style.backGroundColor); - rightPanel[1].Padding = GUI.style.smallPadding; + rightPanel[(int)PanelTab.Map] = new GUIFrame(panelRect, GUI.style.backGroundColor); + rightPanel[(int)PanelTab.Map].Padding = GUI.style.smallPadding; - hireList = new GUIListBox(new Rectangle(0, 30, 300, 0), Color.White, Alignment.Left, rightPanel[1]); + startButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", GUI.style, + Alignment.BottomRight, rightPanel[(int)PanelTab.Map]); + startButton.OnClicked = StartShift; + startButton.Enabled = false; + + //--------------------------------------- + + rightPanel[(int)PanelTab.Hire] = new GUIFrame(panelRect, GUI.style.backGroundColor); + rightPanel[(int)PanelTab.Hire].Padding = GUI.style.smallPadding; + + hireList = new GUIListBox(new Rectangle(0, 30, 300, 0), Color.White, Alignment.Left, rightPanel[(int)PanelTab.Hire]); hireList.OnSelected = HireCharacter; } @@ -168,7 +165,22 @@ namespace Subsurface previewCharacter.animController.UpdateAnim((float)Physics.step); Game1.world.Step((float)Physics.step); } + } + public void SelectLocation(Location location, LocationConnection connection) + { + GUIComponent locationPanel = rightPanel[(int)PanelTab.Map].GetChild("selectedlocation"); + + if (locationPanel != null) rightPanel[(int)PanelTab.Map].RemoveChild(locationPanel); + + locationPanel = new GUIFrame(new Rectangle(0, 0, rightPanel[(int)PanelTab.Map].Rect.Width / 2 - 40, 190), Color.Transparent, rightPanel[(int)PanelTab.Map]); + locationPanel.UserData = "selectedlocation"; + + new GUITextBlock(new Rectangle(0,0,100,20), location.Name, Color.Transparent, Color.White, Alignment.TopLeft, locationPanel); + + startButton.Enabled = true; + + selectedLevel = connection.Level; } private void UpdateCharacterLists() @@ -220,7 +232,7 @@ namespace Subsurface leftPanel.Update((float)deltaTime); rightPanel[selectedRightPanel].Update((float)deltaTime); - shiftPanel.Update((float)deltaTime); + //shiftPanel.Update((float)deltaTime); } public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) @@ -239,10 +251,17 @@ namespace Subsurface spriteBatch.Begin(); leftPanel.Draw(spriteBatch); - shiftPanel.Draw(spriteBatch); rightPanel[selectedRightPanel].Draw(spriteBatch); + if (selectedRightPanel == (int)PanelTab.Map) + { + Game1.GameSession.map.Draw(spriteBatch, new Rectangle( + rightPanel[selectedRightPanel].Rect.Right - 20 - 400, + rightPanel[selectedRightPanel].Rect.Y + 20, + 400, 400)); + } + GUI.Draw((float)deltaTime, spriteBatch, null); spriteBatch.End(); @@ -352,7 +371,7 @@ namespace Subsurface private bool StartShift(GUIButton button, object selection) { - Game1.GameSession.StartShift(TimeSpan.Zero); + Game1.GameSession.StartShift(TimeSpan.Zero, selectedLevel); Game1.GameScreen.Select(); return true; diff --git a/Subsurface/Screens/MainMenu.cs b/Subsurface/Screens/MainMenu.cs index 5e442a034..5a8361e8f 100644 --- a/Subsurface/Screens/MainMenu.cs +++ b/Subsurface/Screens/MainMenu.cs @@ -64,7 +64,7 @@ namespace Subsurface new GUITextBlock(new Rectangle(0, 30, 0, 30), "Selected map:", Color.Transparent, Color.Black, Alignment.Left, menuTabs[(int)Tabs.NewGame]); mapList = new GUIListBox(new Rectangle(0, 60, 200, 400), Color.White, menuTabs[(int)Tabs.NewGame]); - foreach (Map map in Map.SavedMaps) + foreach (Submarine map in Submarine.SavedSubmarines) { GUITextBlock textBlock = new GUITextBlock( new Rectangle(0, 0, 0, 25), @@ -76,7 +76,7 @@ namespace Subsurface textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); textBlock.UserData = map; } - if (Map.SavedMaps.Count > 0) mapList.Select(Map.SavedMaps[0]); + if (Submarine.SavedSubmarines.Count > 0) mapList.Select(Submarine.SavedSubmarines[0]); button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", GUI.style, Alignment.Right | Alignment.Bottom, menuTabs[(int)Tabs.NewGame]); @@ -173,7 +173,7 @@ namespace Subsurface private bool StartGame(GUIButton button, object obj) { - Map selectedMap = mapList.SelectedData as Map; + Submarine selectedMap = mapList.SelectedData as Submarine; if (selectedMap == null) return false; Game1.GameSession = new GameSession(selectedMap, GameModePreset.list.Find(gm => gm.Name == "Single Player")); diff --git a/Subsurface/Screens/NetLobbyScreen.cs b/Subsurface/Screens/NetLobbyScreen.cs index d2e304ce3..3336027b9 100644 --- a/Subsurface/Screens/NetLobbyScreen.cs +++ b/Subsurface/Screens/NetLobbyScreen.cs @@ -30,9 +30,9 @@ namespace Subsurface public bool isServer; - public Map SelectedMap + public Submarine SelectedMap { - get { return mapList.SelectedData as Map; } + get { return mapList.SelectedData as Submarine; } } @@ -135,9 +135,9 @@ namespace Subsurface mapList.OnSelected = SelectMap; mapList.Enabled = (Game1.Server!=null); - if (Map.SavedMaps.Count>0) + if (Submarine.SavedSubmarines.Count>0) { - foreach (Map map in Map.SavedMaps) + foreach (Submarine map in Submarine.SavedSubmarines) { GUITextBlock textBlock = new GUITextBlock( new Rectangle(0, 0, 0, 25), @@ -245,10 +245,10 @@ namespace Subsurface { if (Game1.Server != null) Game1.Server.UpdateNetLobby(obj); - Map map = (Map)obj; + Submarine map = (Submarine)obj; //map already loaded - if (Map.Loaded!=null && map.FilePath == Map.Loaded.FilePath) return true; + if (Submarine.Loaded!=null && map.FilePath == Submarine.Loaded.FilePath) return true; map.Load(); @@ -281,13 +281,13 @@ namespace Subsurface Game1.GameScreen.Cam.MoveCamera((float)deltaTime); Vector2 pos = new Vector2( - Map.Borders.X + Map.Borders.Width / 2, - Map.Borders.Y - Map.Borders.Height / 2); + Submarine.Borders.X + Submarine.Borders.Width / 2, + Submarine.Borders.Y - Submarine.Borders.Height / 2); camAngle += (float)deltaTime / 10.0f; Vector2 offset = (new Vector2( - (float)Math.Cos(camAngle) * (Map.Borders.Width / 2.0f), - (float)Math.Sin(camAngle) * (Map.Borders.Height / 2.0f))); + (float)Math.Cos(camAngle) * (Submarine.Borders.Width / 2.0f), + (float)Math.Sin(camAngle) * (Submarine.Borders.Height / 2.0f))); pos += offset * 0.8f; @@ -466,7 +466,7 @@ namespace Subsurface public void WriteData(NetOutgoingMessage msg) { - Map selectedMap = mapList.SelectedData as Map; + Submarine selectedMap = mapList.SelectedData as Submarine; if (selectedMap==null) { @@ -476,7 +476,7 @@ namespace Subsurface else { msg.Write(Path.GetFileName(selectedMap.Name)); - msg.Write(selectedMap.MapHash.MD5Hash); + msg.Write(selectedMap.Hash.MD5Hash); } msg.Write(modeList.SelectedIndex); @@ -486,7 +486,7 @@ namespace Subsurface public bool TrySelectMap(string mapName, string md5Hash) { - Map map = Map.SavedMaps.Find(m => m.Name == mapName); + Submarine map = Submarine.SavedSubmarines.Find(m => m.Name == mapName); if (map==null) { DebugConsole.ThrowError("The map ''" + mapName + "'' has been selected by the server."); @@ -495,10 +495,10 @@ namespace Subsurface } else { - if (map.MapHash.MD5Hash!=md5Hash) + if (map.Hash.MD5Hash!=md5Hash) { DebugConsole.ThrowError("Your version of the map file ''"+map.Name+"'' doesn't match the server's version!"); - DebugConsole.ThrowError("Your file: "+map.Name+"(MD5 hash : "+map.MapHash.MD5Hash+")"); + DebugConsole.ThrowError("Your file: "+map.Name+"(MD5 hash : "+map.Hash.MD5Hash+")"); DebugConsole.ThrowError("Server's file: " + mapName + "(MD5 hash : " + md5Hash + ")"); return false; } diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 11d227d65..34f6dd413 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -127,7 +127,9 @@ - + + + @@ -161,7 +163,7 @@ - + diff --git a/Subsurface/ToolBox.cs b/Subsurface/ToolBox.cs index 57b9bdd3d..e2d183aa4 100644 --- a/Subsurface/ToolBox.cs +++ b/Subsurface/ToolBox.cs @@ -25,10 +25,20 @@ namespace Subsurface public static float RandomFloat(float minimum, float maximum) { - return (float)Game1.localRandom.NextDouble() * (maximum - minimum) + minimum; + return (float)Game1.random.NextDouble() * (maximum - minimum) + minimum; } public static int RandomInt(int minimum, int maximum) + { + return Game1.random.Next(maximum - minimum) + minimum; + } + + public static float RandomFloatLocal(float minimum, float maximum) + { + return (float)Game1.localRandom.NextDouble() * (maximum - minimum) + minimum; + } + + public static int RandomIntLocal(int minimum, int maximum) { return Game1.localRandom.Next(maximum - minimum) + minimum; } diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 83392413f..ccbf38e72 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ