From 2ef92c4af018560cba331d654032e8b1980c649d Mon Sep 17 00:00:00 2001 From: Regalis Date: Tue, 16 Jun 2015 22:53:02 +0300 Subject: [PATCH 1/2] Moved CrewManager & HireManager to a separate single player GameMode, bleeding decreases health --- Subsurface/Characters/Character.cs | 125 +++++++----- Subsurface/Characters/CharacterInfo.cs | 7 +- .../Content/Characters/Crawler/crawler.xml | 2 +- .../TigerThresher/tigerthresher.xml | 2 +- Subsurface/Content/Items/Weapons/weapons.xml | 2 +- Subsurface/DebugConsole.cs | 9 +- Subsurface/GUI/GUIComponent.cs | 2 +- Subsurface/GUI/GUIListBox.cs | 16 +- Subsurface/GUI/GUIMessageBox.cs | 13 +- Subsurface/GameSession/CrewManager.cs | 14 +- Subsurface/GameSession/GameMode.cs | 70 +++++-- Subsurface/GameSession/GameSession.cs | 159 +++++---------- Subsurface/GameSession/SinglePlayerMode.cs | 155 +++++++++++++++ Subsurface/GameSession/TraitorMode.cs | 7 +- Subsurface/Items/Components/Signal/Wire.cs | 8 +- Subsurface/Map/Map.cs | 16 +- Subsurface/SaveUtil.cs | 30 +-- Subsurface/Screens/LobbyScreen.cs | 185 +++++++++++++++--- Subsurface/Screens/MainMenu.cs | 92 +++++++-- Subsurface/Screens/NetLobbyScreen.cs | 24 +-- Subsurface/Subsurface.csproj | 1 + Subsurface_Solution.v12.suo | Bin 279552 -> 291328 bytes 22 files changed, 656 insertions(+), 283 deletions(-) create mode 100644 Subsurface/GameSession/SinglePlayerMode.cs diff --git a/Subsurface/Characters/Character.cs b/Subsurface/Characters/Character.cs index cb5f938dc..b84404b8a 100644 --- a/Subsurface/Characters/Character.cs +++ b/Subsurface/Characters/Character.cs @@ -79,7 +79,7 @@ namespace Subsurface protected float soundInterval; private float bleeding; - private float blood; + //private float blood; private Sound[] sounds; //which AIstate each sound is for @@ -152,15 +152,15 @@ namespace Subsurface } } - public float Blood - { - get { return blood; } - set - { - blood = MathHelper.Clamp(value, 0.0f, 100.0f); - if (blood == 0.0f) Kill(); - } - } + //public float Blood + //{ + // get { return blood; } + // set + // { + // blood = MathHelper.Clamp(value, 0.0f, 100.0f); + // if (blood == 0.0f) Kill(); + // } + //} public Item[] SelectedItems { @@ -286,20 +286,20 @@ namespace Subsurface IsNetworkPlayer = isNetworkPlayer; oxygen = 100.0f; - blood = 100.0f; + //blood = 100.0f; aiTarget = new AITarget(this); properties = ObjectProperty.GetProperties(this); + info = characterInfo==null ? new CharacterInfo(file) : characterInfo; + XDocument doc = ToolBox.TryLoadXml(file); if (doc == null) return; - + speciesName = ToolBox.GetAttributeString(doc.Root, "name", "Unknown"); isHumanoid = ToolBox.GetAttributeBool(doc.Root, "humanoid", false); - - info = characterInfo ?? new CharacterInfo(file); - + if (isHumanoid) { animController = new HumanoidAnimController(this, doc.Root.Element("ragdoll")); @@ -427,7 +427,11 @@ namespace Subsurface /// public void ControlLocalPlayer(Camera cam, bool moveCam = true) { - if (isDead) return; + //if (isDead) + //{ + + // return; + //} Limb head = animController.GetLimb(LimbType.Head); @@ -522,7 +526,16 @@ namespace Subsurface public void Update(Camera cam, float deltaTime) { - if (isDead) return; + if (isDead) + { + if (controlled == this) + { + cam.Zoom = MathHelper.Lerp(cam.Zoom, 1.5f, 0.1f); + cam.TargetPos = ConvertUnits.ToDisplayUnits(animController.limbs[0].SimPosition); + cam.OffsetAmount = 0.0f; + } + return; + } if (PressureProtection==0.0f && (animController.CurrentHull == null || animController.CurrentHull.LethalPressure >= 100.0f)) @@ -568,7 +581,7 @@ namespace Subsurface //foreach (Limb limb in animController.limbs) //{ - Blood = blood - bleeding * deltaTime; + Health = health - bleeding * deltaTime; //} if (aiController != null) aiController.Update(deltaTime); @@ -591,18 +604,24 @@ namespace Subsurface aiTarget.SightRange += torso.LinearVelocity.Length() * 500.0f; } } - + public void Draw(SpriteBatch spriteBatch) { animController.Draw(spriteBatch); if (IsNetworkPlayer) { - Vector2 pos = new Vector2(Position.X, -Position.Y - 50.0f) - GUI.font.MeasureString(info.name) * 0.5f; - spriteBatch.DrawString(GUI.font, info.name, pos - new Vector2(1.0f, 1.0f), Color.Black); - spriteBatch.DrawString(GUI.font, info.name, pos, Color.White); + Vector2 namePos = new Vector2(Position.X, -Position.Y - 80.0f) - GUI.font.MeasureString(info.name) * 0.5f; + spriteBatch.DrawString(GUI.font, info.name, namePos - new Vector2(1.0f, 1.0f), Color.Black); + spriteBatch.DrawString(GUI.font, info.name, namePos, Color.White); } + if (this == Character.controlled) return; + + Vector2 healthBarPos = new Vector2(Position.X - 50, -Position.Y - 50.0f); + GUI.DrawRectangle(spriteBatch, new Rectangle((int)healthBarPos.X-2, (int)healthBarPos.Y-2, 100+4, 15+4), Color.Black, false); + GUI.DrawRectangle(spriteBatch, new Rectangle((int)healthBarPos.X, (int)healthBarPos.Y, (int)(100.0f*(health/maxHealth)), 15), Color.Red, true); + //spriteBatch.DrawString(GUI.font, ID.ToString(), ConvertUnits.ToDisplayUnits(animController.limbs[0].Position), Color.White); //GUI.DrawLine(spriteBatch, ConvertUnits.ToDisplayUnits(animController.limbs[0].SimPosition.X, animController.limbs[0].SimPosition.Y), // ConvertUnits.ToDisplayUnits(animController.limbs[0].SimPosition.X, animController.limbs[0].SimPosition.Y) + @@ -610,7 +629,7 @@ namespace Subsurface } - private static GUIProgressBar drowningBar, bloodBar; + private static GUIProgressBar drowningBar, healthBar; public void DrawHud(SpriteBatch spriteBatch, Camera cam) { if (drowningBar==null) @@ -618,19 +637,16 @@ namespace Subsurface int width = 100, height = 20; drowningBar = new GUIProgressBar(new Rectangle(20, Game1.GraphicsHeight/2, width, height), Color.Blue, 1.0f); - bloodBar = new GUIProgressBar(new Rectangle(20, Game1.GraphicsHeight / 2 + 30, width, height), Color.Red, 1.0f); + healthBar = new GUIProgressBar(new Rectangle(20, Game1.GraphicsHeight / 2 + 30, width, height), Color.Red, 1.0f); } drowningBar.BarSize = Controlled.Oxygen / 100.0f; - if (drowningBar.BarSize < 1.0f) - drowningBar.Draw(spriteBatch); + if (drowningBar.BarSize < 0.95f) drowningBar.Draw(spriteBatch); - bloodBar.BarSize = Blood / 100.0f; - if (bloodBar.BarSize < 1.0f) - bloodBar.Draw(spriteBatch); + healthBar.BarSize = health / maxHealth; + if (healthBar.BarSize < 1.0f) healthBar.Draw(spriteBatch); - if (Controlled.Inventory != null) - Controlled.Inventory.Draw(spriteBatch); + if (Controlled.Inventory != null) Controlled.Inventory.Draw(spriteBatch); if (closestItem!=null) { @@ -773,29 +789,6 @@ namespace Subsurface { if (isDead) return; - //if the game is run by a client, characters are only killed when the server says so - if (Game1.Client != null) - { - if (networkMessage) - { - new NetworkEvent(NetworkEventType.KillCharacter, ID, true); - } - else - { - return; - } - } - - if (Game1.Server != null) - { - new NetworkEvent(NetworkEventType.KillCharacter, ID, false); - } - - if (Game1.GameSession!=null && Game1.GameSession.crewManager != null) - { - Game1.GameSession.crewManager.KillCharacter(this); - } - isDead = true; animController.movement = Vector2.Zero; animController.TargetMovement = Vector2.Zero; @@ -820,6 +813,30 @@ namespace Subsurface joint.MotorEnabled = false; joint.MaxMotorTorque = 0.0f; } + + + //if the game is run by a client, characters are only killed when the server says so + if (Game1.Client != null) + { + if (networkMessage) + { + new NetworkEvent(NetworkEventType.KillCharacter, ID, true); + } + else + { + return; + } + } + + if (Game1.Server != null) + { + new NetworkEvent(NetworkEventType.KillCharacter, ID, false); + } + + if (Game1.GameSession != null) + { + Game1.GameSession.KillCharacter(this); + } } public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data) diff --git a/Subsurface/Characters/CharacterInfo.cs b/Subsurface/Characters/CharacterInfo.cs index 17f4177e2..c6c583cce 100644 --- a/Subsurface/Characters/CharacterInfo.cs +++ b/Subsurface/Characters/CharacterInfo.cs @@ -89,12 +89,16 @@ namespace Subsurface public CharacterInfo(XElement element) { - name = element.Name.ToString(); + name = ToolBox.GetAttributeString(element, "name", "unnamed"); string genderStr = ToolBox.GetAttributeString(element, "gender", "male").ToLower(); gender = (genderStr == "male") ? Gender.Male : Gender.Female; + file = ToolBox.GetAttributeString(element, "file", ""); + salary = ToolBox.GetAttributeInt(element, "salary", 1000); + + headSpriteId = ToolBox.GetAttributeInt(element, "headspriteid", 1); } public virtual XElement Save(XElement parentElement) @@ -103,6 +107,7 @@ namespace Subsurface componentElement.Add( new XAttribute("name", name), + new XAttribute("file", file), new XAttribute("gender", gender == Gender.Male ? "male" : "female"), new XAttribute("salary", salary), new XAttribute("headspriteid", headSpriteId)); diff --git a/Subsurface/Content/Characters/Crawler/crawler.xml b/Subsurface/Content/Characters/Crawler/crawler.xml index c2151cd42..dd5fce2a4 100644 --- a/Subsurface/Content/Characters/Crawler/crawler.xml +++ b/Subsurface/Content/Characters/Crawler/crawler.xml @@ -26,7 +26,7 @@ - + diff --git a/Subsurface/Content/Characters/TigerThresher/tigerthresher.xml b/Subsurface/Content/Characters/TigerThresher/tigerthresher.xml index 321b558a0..6a0aae69a 100644 --- a/Subsurface/Content/Characters/TigerThresher/tigerthresher.xml +++ b/Subsurface/Content/Characters/TigerThresher/tigerthresher.xml @@ -15,7 +15,7 @@ - + diff --git a/Subsurface/Content/Items/Weapons/weapons.xml b/Subsurface/Content/Items/Weapons/weapons.xml index fe3d8c847..d73e3941c 100644 --- a/Subsurface/Content/Items/Weapons/weapons.xml +++ b/Subsurface/Content/Items/Weapons/weapons.xml @@ -11,7 +11,7 @@ - + diff --git a/Subsurface/DebugConsole.cs b/Subsurface/DebugConsole.cs index 772eb006c..6bac7d957 100644 --- a/Subsurface/DebugConsole.cs +++ b/Subsurface/DebugConsole.cs @@ -148,8 +148,13 @@ namespace Subsurface { WayPoint spawnPoint = WayPoint.GetRandom(WayPoint.SpawnType.Human); Character.Controlled = new Character("Content/Characters/Human/human.xml", (spawnPoint == null) ? Vector2.Zero : spawnPoint.SimPosition); - if (Game1.GameSession != null) Game1.GameSession.crewManager.AddCharacter(Character.Controlled); - if (Game1.GameSession != null) Game1.GameSession.crewManager.SelectCharacter(Character.Controlled); + if (Game1.GameSession != null) + { + SinglePlayerMode mode = Game1.GameSession.gameMode as SinglePlayerMode; + if (mode == null) break; + mode.crewManager.AddCharacter(Character.Controlled); + mode.crewManager.SelectCharacter(Character.Controlled); + } } else { diff --git a/Subsurface/GUI/GUIComponent.cs b/Subsurface/GUI/GUIComponent.cs index bea9cc29b..c21a4dd73 100644 --- a/Subsurface/GUI/GUIComponent.cs +++ b/Subsurface/GUI/GUIComponent.cs @@ -242,7 +242,7 @@ namespace Subsurface if (children.Contains(child)) children.Remove(child); } - public void ClearChildren() + public virtual void ClearChildren() { children.Clear(); } diff --git a/Subsurface/GUI/GUIListBox.cs b/Subsurface/GUI/GUIListBox.cs index 8f5db6ddc..92e1ff62a 100644 --- a/Subsurface/GUI/GUIListBox.cs +++ b/Subsurface/GUI/GUIListBox.cs @@ -28,7 +28,10 @@ namespace Subsurface public object SelectedData { - get { return (selected == null) ? null : selected.UserData; } + get + { + return (selected == null) ? null : selected.UserData; + } } public int SelectedIndex @@ -166,12 +169,19 @@ namespace Subsurface } + public override void ClearChildren() + { + base.ClearChildren(); + selected = null; + } + public override void RemoveChild(GUIComponent child) { base.RemoveChild(child); - UpdateScrollBarSize(); - + if (selected == child) selected = null; + + UpdateScrollBarSize(); } private void ShowScrollBar() diff --git a/Subsurface/GUI/GUIMessageBox.cs b/Subsurface/GUI/GUIMessageBox.cs index 1676c778f..de5f4dfd8 100644 --- a/Subsurface/GUI/GUIMessageBox.cs +++ b/Subsurface/GUI/GUIMessageBox.cs @@ -13,12 +13,12 @@ namespace Subsurface //public OnClickedHandler OnClicked; //GUIFrame frame; - GUIButton[] buttons; + public GUIButton[] Buttons; public GUIMessageBox(string header, string text) : this(header, text, new string[] {"OK"}) { - this.buttons[0].OnClicked = OkClicked; + this.Buttons[0].OnClicked = Close; } public GUIMessageBox(string header, string text, string[] buttons, Alignment textAlignment = (Alignment.Left | Alignment.Top)) @@ -37,22 +37,21 @@ namespace Subsurface new GUITextBlock(new Rectangle(0, 30, 0, DefaultHeight - 70), text, Color.Transparent, Color.White, textAlignment, this, true); int x = 0; - this.buttons = new GUIButton[buttons.Length]; + this.Buttons = new GUIButton[buttons.Length]; for (int i = 0; i < buttons.Length; i++) { - this.buttons[i] = new GUIButton(new Rectangle(x, 0, 150, 30), buttons[i], GUI.style, Alignment.Left | Alignment.Bottom, this); + this.Buttons[i] = new GUIButton(new Rectangle(x, 0, 150, 30), buttons[i], GUI.style, Alignment.Left | Alignment.Bottom, this); - x += this.buttons[i].Rect.Width + 20; + x += this.Buttons[i].Rect.Width + 20; } messageBoxes.Enqueue(this); } - private bool OkClicked(GUIButton button, object obj) + public bool Close(GUIButton button, object obj) { messageBoxes.Dequeue(); return true; - } } } diff --git a/Subsurface/GameSession/CrewManager.cs b/Subsurface/GameSession/CrewManager.cs index ea3d019e0..631306fe2 100644 --- a/Subsurface/GameSession/CrewManager.cs +++ b/Subsurface/GameSession/CrewManager.cs @@ -77,16 +77,16 @@ namespace Subsurface characterInfos.Add(character.info); } - GUIFrame frame = new GUIFrame(new Rectangle(0,0,0,40), Color.Transparent, listBox); + GUIFrame frame = new GUIFrame(new Rectangle(0, 0, 0, 40), Color.Transparent, listBox); frame.UserData = character; frame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f); frame.HoverColor = Color.LightGray * 0.5f; frame.SelectedColor = Color.Gold * 0.5f; - string name = character.info.name.Replace(' ','\n'); + string name = character.info.name.Replace(' ', '\n'); GUITextBlock textBlock = new GUITextBlock( - new Rectangle(40,0,0,25), + new Rectangle(40, 0, 0, 25), name, Color.Transparent, Color.White, Alignment.Left, @@ -94,7 +94,7 @@ namespace Subsurface frame); textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f); - new GUIImage(new Rectangle(-10,-10,0,0), character.animController.limbs[0].sprite, Alignment.Left, frame); + new GUIImage(new Rectangle(-10, -10, 0, 0), character.animController.limbs[0].sprite, Alignment.Left, frame); } public void Update(float deltaTime) @@ -106,7 +106,11 @@ namespace Subsurface { GUIComponent characterBlock = listBox.GetChild(killedCharacter) as GUIComponent; if (characterBlock != null) characterBlock.Color = Color.DarkRed * 0.5f; - + + if (characters.Find(c => !c.IsDead)==null) + { + Game1.GameSession.EndShift(null, null); + } } public void StartShift() diff --git a/Subsurface/GameSession/GameMode.cs b/Subsurface/GameSession/GameMode.cs index ab7e72f67..45ab79427 100644 --- a/Subsurface/GameSession/GameMode.cs +++ b/Subsurface/GameSession/GameMode.cs @@ -1,19 +1,53 @@ -using System; +using Microsoft.Xna.Framework.Graphics; +using System; using System.Collections.Generic; +using System.Reflection; namespace Subsurface { + class GameModePreset + { + public static List list = new List(); + + public ConstructorInfo Constructor; + public string Name; + public bool IsSinglePlayer; + + public GameModePreset(string name, Type type, bool isSinglePlayer = false) + { + this.Name = name; + //Constructor = constructor; + + + Constructor = type.GetConstructor(new Type[] { typeof(GameModePreset) }); + + IsSinglePlayer = isSinglePlayer; + + list.Add(this); + } + + public GameMode Instantiate() + { + object[] lobject = new object[] { this }; + return(GameMode)Constructor.Invoke(lobject); + } + } + class GameMode { - public static List list = new List(); + public static List presetList = new List(); //TimeSpan duration; protected DateTime startTime; protected DateTime endTime; + //public readonly bool IsSinglePlayer; + protected bool isRunning; - protected string name; + //protected string name; + + protected GameModePreset preset; private string endMessage; @@ -32,9 +66,14 @@ namespace Subsurface get { return isRunning; } } + public bool IsSinglePlayer + { + get { return preset.IsSinglePlayer; } + } + public string Name { - get { return name; } + get { return preset.Name; } } public string EndMessage @@ -42,13 +81,16 @@ namespace Subsurface get { return endMessage; } } - public GameMode(string name) + public GameMode(GameModePreset preset) { - this.name = name; + this.preset = preset; - list.Add(this); + //list.Add(this); } + public virtual void Draw(SpriteBatch spriteBatch) + { } + public virtual void Start(TimeSpan duration) { startTime = DateTime.Now; @@ -59,7 +101,7 @@ namespace Subsurface isRunning = true; } - public virtual void Update() + public virtual void Update(float deltaTime) { if (!isRunning) return; @@ -69,7 +111,7 @@ namespace Subsurface } } - public void End(string endMessage = "") + public virtual void End(string endMessage = "") { isRunning = false; @@ -80,8 +122,14 @@ namespace Subsurface public static void Init() { - new GameMode("Sandbox"); - new TraitorMode("Traitor"); + new GameModePreset("Single Player", typeof(SinglePlayerMode), true); + new GameModePreset("SandBox", typeof(GameMode), false); + new GameModePreset("Traitor", typeof(TraitorMode), false); + + + //new SinglePlayerMode("Single Player", true); + //new GameMode("Sandbox"); + //new TraitorMode("Traitor"); } } } diff --git a/Subsurface/GameSession/GameSession.cs b/Subsurface/GameSession/GameSession.cs index 6dda2ee69..a1b98ea42 100644 --- a/Subsurface/GameSession/GameSession.cs +++ b/Subsurface/GameSession/GameSession.cs @@ -13,8 +13,7 @@ namespace Subsurface class GameSession { public readonly TaskManager taskManager; - public readonly CrewManager crewManager; - public readonly HireManager hireManager; + protected DateTime startTime; protected DateTime endTime; @@ -34,23 +33,20 @@ namespace Subsurface private Map selectedMap; - private int day; + - public int Day + public GameSession(Map selectedMap, TimeSpan gameDuration, GameModePreset gameModePreset) + :this(selectedMap, gameDuration, gameModePreset.Instantiate()) { - get { return day; } + } public GameSession(Map selectedMap, TimeSpan gameDuration, GameMode gameMode = null) { taskManager = new TaskManager(this); - crewManager = new CrewManager(); - hireManager = new HireManager(); savePath = SaveUtil.CreateSavePath(SaveUtil.SaveFolder); - hireManager.GenerateCharacters("Content/Characters/Human/human.xml", 10); - guiRoot = new GUIFrame(new Rectangle(0,0,Game1.GraphicsWidth,Game1.GraphicsWidth), Color.Transparent); int width = 350, height = 100; @@ -75,10 +71,12 @@ namespace Subsurface } timerBar = new GUIProgressBar(new Rectangle(Game1.GraphicsWidth - 120, 20, 100, 25), Color.Gold, 0.0f, guiRoot); - - + this.gameMode = gameMode; - if (this.gameMode != null) this.gameMode.Start(Game1.NetLobbyScreen.GameDuration); + //if (gameMode != null && !gameMode.IsSinglePlayer) + //{ + // gameMode.Start(Game1.NetLobbyScreen.GameDuration); + //} startTime = DateTime.Now; endTime = startTime + gameDuration; @@ -88,53 +86,38 @@ namespace Subsurface //if (!save) return; //CreateSaveFile(selectedMapFile); - - day = 1; + } - public GameSession(string filePath) - : this(null, new TimeSpan(0,0,0,0)) + public GameSession(Map selectedMap, string savePath, string filePath) + : this(selectedMap, new TimeSpan(0,0,0,0)) { XDocument doc = ToolBox.TryLoadXml(filePath); if (doc == null) return; - day = ToolBox.GetAttributeInt(doc.Root,"day",1); + //gameMode = GameModePreset.list.Find(gm => gm.Name == "Single Player").Instantiate(); + + //day = ToolBox.GetAttributeInt(doc.Root,"day",1); foreach (XElement subElement in doc.Root.Elements()) { - if (subElement.Name.ToString().ToLower()=="crew") - { - crewManager = new CrewManager(subElement); - } + if (subElement.Name.ToString().ToLower() != "gamemode") continue; + + gameMode = new SinglePlayerMode(subElement); } - savePath = filePath; - } - - public bool TryHireCharacter(CharacterInfo characterInfo) - { - if (crewManager.Money < characterInfo.salary) return false; - - hireManager.availableCharacters.Remove(characterInfo); - crewManager.characterInfos.Add(characterInfo); - - crewManager.Money -= characterInfo.salary; - - return true; - } - - public string GetMoney() - { - return ("Money: " + crewManager.Money); + this.savePath = savePath; } public void StartShift(int scriptedEventCount = 1) { - if (crewManager.characterInfos.Count == 0) return; + //if (crewManager.characterInfos.Count == 0) return; if (Map.Loaded!=selectedMap) selectedMap.Load(); - crewManager.StartShift(); + gameMode.Start(TimeSpan.Zero); + + //crewManager.StartShift(); taskManager.StartShift(scriptedEventCount); } @@ -148,76 +131,30 @@ namespace Subsurface } else if (Game1.Client==null) - { - StringBuilder sb = new StringBuilder(); - List casualties = crewManager.characters.FindAll(c => c.IsDead); - - if (casualties.Any()) - { - sb.Append("Casualties: \n"); - foreach (Character c in casualties) - { - sb.Append(" - " + c.info.name + "\n"); - } - } - else - { - sb.Append("No casualties!"); - } - - new GUIMessageBox("Day #" + day + " is over!\n", sb.ToString()); - - - //if (saveFile == null) return false; - - //Map.Loaded.SaveAs(saveFile); - - crewManager.EndShift(); - + { Game1.LobbyScreen.Select(); - day++; - } - - for (int i = Character.characterList.Count - 1; i >= 0; i--) - { - Character.characterList.RemoveAt(i); + SaveUtil.SaveGame(savePath); } taskManager.EndShift(); + gameMode.End(); return true; } - private void CreateSaveFile(string mapName) + + public void KillCharacter(Character character) { - //string path = "Content/Data/Saves/"; + SinglePlayerMode singlePlayerMode = gameMode as SinglePlayerMode; + if (singlePlayerMode == null) return; + singlePlayerMode.crewManager.KillCharacter(character); + } - //if (!Directory.Exists(path)) - //{ - // Directory.CreateDirectory(path); - //} - - //string name = Path.GetFileNameWithoutExtension(mapName); - //string extension = Path.GetExtension(mapName); - - //int i = 0; - //while (File.Exists(path + name + i + extension)) - //{ - // i++; - //} - - //saveFile = path + name + i+extension; - - - //try - //{ - // File.Copy(mapName, saveFile); - //} - //catch (Exception e) - //{ - // DebugConsole.ThrowError("Copying map file ''" + mapName + "'' to ''" + saveFile + "'' failed", e); - //} + public bool LoadPrevious(GUIButton button, object obj) + { + SaveUtil.LoadGame(savePath); + return true; } public bool EnterChatMessage(GUITextBox textBox, string message) @@ -237,7 +174,7 @@ namespace Subsurface return true; } - + public void NewChatMessage(string text, Color color) { GUITextBlock msg = new GUITextBlock(new Rectangle(0, 0, 0, 20), text, @@ -252,20 +189,20 @@ namespace Subsurface chatBox.RemoveChild(chatBox.children.First()); } } - + public void Update(float deltaTime) { taskManager.Update(deltaTime); - if (endShiftButton!=null) endShiftButton.Enabled = !taskManager.CriticalTasks; - + //if (endShiftButton!=null) endShiftButton.Enabled = !taskManager.CriticalTasks; + endShiftButton.Enabled = true; guiRoot.Update(deltaTime); - crewManager.Update(deltaTime); + //endShiftButton.Update(deltaTime); //textBox.Update(deltaTime); - if (gameMode != null) gameMode.Update(); + if (gameMode != null) gameMode.Update(deltaTime); double duration = (endTime - startTime).TotalSeconds; double elapsedTime = (DateTime.Now-startTime).TotalSeconds; @@ -288,9 +225,11 @@ namespace Subsurface public void Draw(SpriteBatch spriteBatch) { guiRoot.Draw(spriteBatch); - crewManager.Draw(spriteBatch); + //crewManager.Draw(spriteBatch); taskManager.Draw(spriteBatch); + gameMode.Draw(spriteBatch); + //chatBox.Draw(spriteBatch); //textBox.Draw(spriteBatch); @@ -304,7 +243,11 @@ namespace Subsurface XDocument doc = new XDocument( new XElement((XName)"Gamesession")); - doc.Root.Add(new XAttribute("day", day)); + ((SinglePlayerMode)gameMode).Save(doc.Root); + + //doc.Root.Add(new XAttribute("day", day)); + + //crewManager.Save(doc.Root); try { diff --git a/Subsurface/GameSession/SinglePlayerMode.cs b/Subsurface/GameSession/SinglePlayerMode.cs new file mode 100644 index 000000000..678dae8c2 --- /dev/null +++ b/Subsurface/GameSession/SinglePlayerMode.cs @@ -0,0 +1,155 @@ +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Subsurface +{ + class SinglePlayerMode : GameMode + { + public readonly CrewManager crewManager; + public readonly HireManager hireManager; + + private int day; + + public int Day + { + get { return day; } + } + + bool crewDead; + private float endTimer; + + public SinglePlayerMode(GameModePreset preset) + : base(preset) + { + crewManager = new CrewManager(); + hireManager = new HireManager(); + + hireManager.GenerateCharacters("Content/Characters/Human/human.xml", 10); + + day = 1; + } + + public SinglePlayerMode(XElement element) + : this(GameModePreset.list.Find(gm => gm.Name == "Single Player")) + { + day = ToolBox.GetAttributeInt(element,"day",1); + + foreach (XElement subElement in element.Elements()) + { + if (subElement.Name.ToString().ToLower() != "crew") continue; + + crewManager = new CrewManager(subElement); + } + } + + public override void Start(TimeSpan duration) + { + endTimer = 5.0f; + + crewManager.StartShift(); + } + + public bool TryHireCharacter(CharacterInfo characterInfo) + { + if (crewManager.Money < characterInfo.salary) return false; + + hireManager.availableCharacters.Remove(characterInfo); + crewManager.characterInfos.Add(characterInfo); + + crewManager.Money -= characterInfo.salary; + + return true; + } + + public string GetMoney() + { + return ("Money: " + crewManager.Money); + } + + + public override void Draw(SpriteBatch spriteBatch) + { + crewManager.Draw(spriteBatch); + + //chatBox.Draw(spriteBatch); + //textBox.Draw(spriteBatch); + + //timerBar.Draw(spriteBatch); + + //if (Game1.Client == null) endShiftButton.Draw(spriteBatch); + } + + public override void Update(float deltaTime) + { + crewManager.Update(deltaTime); + + if (!crewDead) + { + if (crewManager.characters.Find(c => !c.IsDead) == null) + { + crewDead = true; + } + } + else + { + endTimer -= deltaTime; + + if (endTimer <= 0.0f) End(""); + } + } + + public override void End(string endMessage = "") + { + StringBuilder sb = new StringBuilder(); + List casualties = crewManager.characters.FindAll(c => c.IsDead); + + if (casualties.Count == crewManager.characters.Count) + { + sb.Append("Your entire crew has died!"); + + var msgBox = new GUIMessageBox("GG", sb.ToString(), new string[] { "Load game", "Quit" }); + msgBox.Buttons[0].OnClicked += Game1.GameSession.LoadPrevious; + msgBox.Buttons[0].OnClicked += msgBox.Close; + msgBox.Buttons[1].OnClicked = Game1.LobbyScreen.QuitToMainMenu; + msgBox.Buttons[1].OnClicked += msgBox.Close; + } + else + { + if (casualties.Any()) + { + sb.Append("Casualties: \n"); + foreach (Character c in casualties) + { + sb.Append(" - " + c.info.name + "\n"); + } + } + else + { + sb.Append("No casualties!"); + } + + new GUIMessageBox("Day #" + day + " is over!\n", sb.ToString()); + + day++; + } + + crewManager.EndShift(); + for (int i = Character.characterList.Count-1; i>=0; i--) + { + Character.characterList.RemoveAt(i); + } + } + + public void Save(XElement element) + { + element.Add(new XAttribute("day", day)); + + crewManager.Save(element); + + } + } +} diff --git a/Subsurface/GameSession/TraitorMode.cs b/Subsurface/GameSession/TraitorMode.cs index e114f9fbb..c8f1b066b 100644 --- a/Subsurface/GameSession/TraitorMode.cs +++ b/Subsurface/GameSession/TraitorMode.cs @@ -9,8 +9,8 @@ namespace Subsurface Client traitor; Client target; - public TraitorMode(string name) - : base(name) + public TraitorMode(GameModePreset preset) + : base(preset) { } @@ -23,9 +23,8 @@ namespace Subsurface target = null; } - public override void Update() + public override void Update(float deltaTime) { - if (!isRunning) return; if (DateTime.Now >= endTime) diff --git a/Subsurface/Items/Components/Signal/Wire.cs b/Subsurface/Items/Components/Signal/Wire.cs index 56553d701..b2ce301cf 100644 --- a/Subsurface/Items/Components/Signal/Wire.cs +++ b/Subsurface/Items/Components/Signal/Wire.cs @@ -224,10 +224,10 @@ namespace Subsurface.Items.Components { if (nodes.Count == 0) return; - for (int i = 0; i < nodes.Count; i++) - { - GUI.DrawRectangle(spriteBatch, new Rectangle((int)nodes[i].X, (int)-nodes[i].Y, 5, 5), Color.DarkGray, true, wireSprite.Depth - 0.01f); - } + //for (int i = 0; i < nodes.Count; i++) + //{ + // GUI.DrawRectangle(spriteBatch, new Rectangle((int)nodes[i].X, (int)-nodes[i].Y, 5, 5), Color.DarkGray, true, wireSprite.Depth - 0.01f); + //} for (int i = 1; i < nodes.Count; i++) { diff --git a/Subsurface/Map/Map.cs b/Subsurface/Map/Map.cs index 64dd2ca72..05d67c70c 100644 --- a/Subsurface/Map/Map.cs +++ b/Subsurface/Map/Map.cs @@ -275,8 +275,7 @@ namespace Subsurface // DebugConsole.ThrowError("No save file selected"); // return; //} - XDocument doc = new XDocument( - new XElement((XName)name)); + XDocument doc = new XDocument(new XElement((XName)name)); foreach (MapEntity e in MapEntity.mapEntityList) { @@ -290,9 +289,9 @@ namespace Subsurface { SaveUtil.CompressStringToFile(filePath, doc.ToString()); } - catch + catch (Exception e) { - DebugConsole.ThrowError("Saving map ''" + filePath + "'' failed!"); + DebugConsole.ThrowError("Saving map ''" + filePath + "'' failed!", e); } @@ -505,12 +504,14 @@ namespace Subsurface loaded = this; } - public static void Load(string file) + public static Map Load(string file) { Unload(); Map map = new Map(file); map.Load(); + + return map; } @@ -528,9 +529,8 @@ namespace Subsurface if (Game1.GameScreen.Cam != null) Game1.GameScreen.Cam.TargetPos = Vector2.Zero; Entity.RemoveAll(); - - if (Game1.GameSession!=null) - Game1.GameSession.crewManager.EndShift(); + + if (Game1.GameSession != null) Game1.GameSession.EndShift(null, null); PhysicsBody.list.Clear(); diff --git a/Subsurface/SaveUtil.cs b/Subsurface/SaveUtil.cs index 397d46e52..beef366c4 100644 --- a/Subsurface/SaveUtil.cs +++ b/Subsurface/SaveUtil.cs @@ -9,36 +9,40 @@ namespace Subsurface { class SaveUtil { - public const string SaveFolder = "Content/SavedMaps/"; + public const string SaveFolder = "Content/Data/Saves/"; public delegate void ProgressDelegate(string sMessage); - public static void SaveGame(string directory) + public static void SaveGame(string savePath) { - if (Directory.Exists(directory)) + string tempPath = Path.GetDirectoryName(savePath) + "\\temp"; + if (!Directory.Exists(tempPath)) { - Directory.Delete(directory, true); + Directory.CreateDirectory(tempPath); } - Directory.CreateDirectory(directory); + //Directory.CreateDirectory(Path.GetDirectoryName(filePath) + "\\temp"); - Map.Loaded.SaveAs(directory+"\\map.gz"); + Map.Loaded.SaveAs(tempPath + "\\map.gz"); - Game1.GameSession.Save(directory+"\\gamesession.xml"); + Game1.GameSession.Save(tempPath + "\\gamesession.xml"); //Game1.GameSession.crewManager.Save(directory+"\\crew.xml"); - CompressDirectory(directory, directory+".save", null); + CompressDirectory(tempPath, savePath, null); - Directory.Delete(directory, true); + Directory.Delete(tempPath, true); } public static void LoadGame(string filePath) { - DecompressToDirectory(filePath+".save", Path.GetDirectoryName(filePath)+"\\temp", null); + string tempPath = Path.GetDirectoryName(filePath) + "\\temp"; - Map.Load(Path.GetDirectoryName(filePath) + "\\temp\\map.gz"); - Game1.GameSession = new GameSession(Path.GetDirectoryName(filePath) + "\\temp\\gamesession.gz"); + DecompressToDirectory(filePath, tempPath, null); + Map selectedMap = Map.Load(tempPath +"\\map.gz"); + Game1.GameSession = new GameSession(selectedMap, filePath, tempPath + "\\gamesession.xml"); + + Directory.Delete(tempPath, true); } public static string CreateSavePath(string saveFolder, string fileName="save") @@ -57,7 +61,7 @@ namespace Subsurface i++; } - return saveFolder + fileName + i + extension; + return saveFolder + fileName + i; } public static void CompressStringToFile(string fileName, string value) diff --git a/Subsurface/Screens/LobbyScreen.cs b/Subsurface/Screens/LobbyScreen.cs index f2233466a..7b573ff33 100644 --- a/Subsurface/Screens/LobbyScreen.cs +++ b/Subsurface/Screens/LobbyScreen.cs @@ -1,4 +1,7 @@ -using Microsoft.Xna.Framework; +using FarseerPhysics; +using FarseerPhysics.Dynamics; +using FarseerPhysics.Factories; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Subsurface @@ -15,6 +18,13 @@ namespace Subsurface GUIListBox characterList; GUIListBox hireList; + SinglePlayerMode gameMode; + + Body previewPlatform; + Hull previewHull; + + Character previewCharacter; + public LobbyScreen() { Rectangle panelRect = new Rectangle( @@ -81,14 +91,14 @@ namespace Subsurface 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.OnSelected = SelectCharacter; //--------------------------------------- rightPanel[1] = new GUIFrame(panelRect, GUI.style.backGroundColor); rightPanel[1].Padding = GUI.style.smallPadding; - hireList = new GUIListBox(new Rectangle(0, 30, 300, 0), Color.White, Alignment.Left, rightPanel[1]); - + hireList = new GUIListBox(new Rectangle(0, 30, 300, 0), Color.White, Alignment.Left, rightPanel[1]); hireList.OnSelected = HireCharacter; } @@ -96,16 +106,74 @@ namespace Subsurface { base.Select(); + gameMode = Game1.GameSession.gameMode as SinglePlayerMode; + //Map.Unload(); - UpdateCharacterLists(); - + UpdateCharacterLists(); + } + + public override void Deselect() + { + base.Deselect(); + + if (previewPlatform != null) + { + Game1.world.RemoveBody(previewPlatform); + previewPlatform = null; + } + + if (previewHull != null) + { + previewHull.Remove(); + previewHull = null; + } + + if (previewCharacter != null) + { + previewCharacter.Remove(); + previewCharacter = null; + } + } + + private void CreatePreviewCharacter() + { + if (previewCharacter != null) previewCharacter.Remove(); + + Vector2 pos = new Vector2(1000.0f, 1000.0f); + + previewCharacter = new Character(characterList.SelectedData as CharacterInfo, pos); + + previewCharacter.animController.isStanding = true; + + if (previewPlatform == null) + { + Body platform = BodyFactory.CreateRectangle(Game1.world, 3.0f, 1.0f, 5.0f); + platform.SetTransform(new Vector2(pos.X, pos.Y - 3.5f), 0.0f); + platform.IsStatic = true; + } + + if (previewHull == null) + { + pos = ConvertUnits.ToDisplayUnits(pos); + previewHull = new Hull(new Rectangle((int)pos.X - 100, (int)pos.Y + 100, 200, 500)); + } + + Physics.Alpha = 1.0f; + + for (int i = 0; i < 500; i++) + { + previewCharacter.animController.Update((float)Physics.step); + previewCharacter.animController.UpdateAnim((float)Physics.step); + Game1.world.Step((float)Physics.step); + } + } private void UpdateCharacterLists() { characterList.ClearChildren(); - foreach (CharacterInfo c in Game1.GameSession.crewManager.characterInfos) + foreach (CharacterInfo c in gameMode.crewManager.characterInfos) { GUITextBlock textBlock = new GUITextBlock( new Rectangle(0, 0, 0, 25), @@ -114,10 +182,11 @@ namespace Subsurface Alignment.Left, characterList); textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); + textBlock.UserData = c; } hireList.ClearChildren(); - foreach (CharacterInfo c in Game1.GameSession.hireManager.availableCharacters) + foreach (CharacterInfo c in gameMode.hireManager.availableCharacters) { GUIFrame frame = new GUIFrame( new Rectangle(0, 0, 0, 25), @@ -156,8 +225,8 @@ namespace Subsurface public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) { - if (characterList.CountChildren != Game1.GameSession.crewManager.characterInfos.Count - || hireList.CountChildren != Game1.GameSession.hireManager.availableCharacters.Count) + if (characterList.CountChildren != gameMode.crewManager.characterInfos.Count + || hireList.CountChildren != gameMode.hireManager.availableCharacters.Count) { UpdateCharacterLists(); } @@ -168,10 +237,6 @@ namespace Subsurface spriteBatch.Begin(); - - //ConstructionPrefab.list[5].sprite.Draw(spriteBatch, Vector2.Zero, new Vector2(10.0f, 1.0f), Color.White); - - leftPanel.Draw(spriteBatch); shiftPanel.Draw(spriteBatch); @@ -180,6 +245,26 @@ namespace Subsurface GUI.Draw((float)deltaTime, spriteBatch, null); spriteBatch.End(); + + if (characterList.SelectedData != null) + { + if (previewCharacter != null) + { + Vector2 position = new Vector2(characterList.Rect.Right + 100, characterList.Rect.Y + 25.0f); + + Vector2 pos = previewCharacter.Position; + pos.Y = -pos.Y; + Matrix transform = Matrix.CreateTranslation(new Vector3(-pos + position, 0.0f)); + + spriteBatch.Begin(SpriteSortMode.BackToFront, null, null, null, null, null, transform); + previewCharacter.Draw(spriteBatch); + spriteBatch.End(); + } + else + { + CreatePreviewCharacter(); + } + } } public bool SelectRightPanel(GUIButton button, object selection) @@ -189,49 +274,93 @@ namespace Subsurface return true; } + //private void CreatePreviewCharacter() + //{ + // if (Game1.Client.Character != null) Game1.Client.Character.Remove(); + + // Vector2 pos = new Vector2(1000.0f, 1000.0f); + + // Character character = new Character(Game1.Client.CharacterInfo, pos); + + // Game1.Client.Character = character; + + // character.animController.isStanding = true; + + // if (previewPlatform == null) + // { + // Body platform = BodyFactory.CreateRectangle(Game1.world, 3.0f, 1.0f, 5.0f); + // platform.SetTransform(new Vector2(pos.X, pos.Y - 2.5f), 0.0f); + // platform.IsStatic = true; + // } + + // if (previewPlatform == null) + // { + // pos = ConvertUnits.ToDisplayUnits(pos); + // new Hull(new Rectangle((int)pos.X - 100, (int)pos.Y + 100, 200, 200)); + // } + + // Physics.Alpha = 1.0f; + + // for (int i = 0; i < 500; i++) + // { + // character.animController.Update((float)Physics.step); + // character.animController.UpdateAnim((float)Physics.step); + // Game1.world.Step((float)Physics.step); + // } + //} + private string GetMoney() { - return "Money: " + ((Game1.GameSession == null) ? "" : Game1.GameSession.crewManager.Money.ToString()); + return "Money: " + ((Game1.GameSession == null) ? "" : gameMode.crewManager.Money.ToString()); } private string GetDay() { - return "Day #" + ((Game1.GameSession == null) ? "" : Game1.GameSession.Day.ToString()); + return "Day #" + ((Game1.GameSession == null) ? "" : gameMode.Day.ToString()); } private float GetWeekProgress() { if (Game1.GameSession == null) return 0.0f; - return (float)((Game1.GameSession.Day - 1) % 7) / 7.0f; + return (float)((gameMode.Day - 1) % 7) / 7.0f; + } + + private bool SelectCharacter(object selection) + { + CharacterInfo characterInfo = selection as CharacterInfo; + if (characterInfo == null) return false; + + if (Character.Controlled != null && characterInfo == Character.Controlled.info) return false; + + CreatePreviewCharacter(); + + return false; } private bool HireCharacter(object selection) { - CharacterInfo characterInfo; - try { characterInfo = (CharacterInfo)selection; } - catch { return false; } - + CharacterInfo characterInfo = selection as CharacterInfo; if (characterInfo == null) return false; - Game1.GameSession.TryHireCharacter(characterInfo); + gameMode.TryHireCharacter(characterInfo); return false; } private bool StartShift(GUIButton button, object selection) - { - - //Map.Load(Game1.GameSession.SaveFile); - + { Game1.GameSession.StartShift(); - - //EventManager.StartShift(); - Game1.GameScreen.Select(); return true; } + + public bool QuitToMainMenu(GUIButton button, object selection) + { + Game1.MainMenuScreen.Select(); + return true; + } } } diff --git a/Subsurface/Screens/MainMenu.cs b/Subsurface/Screens/MainMenu.cs index 7e9ef24f1..da30e75e1 100644 --- a/Subsurface/Screens/MainMenu.cs +++ b/Subsurface/Screens/MainMenu.cs @@ -2,16 +2,19 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Subsurface.Networking; +using System.IO; namespace Subsurface { class MainMenuScreen : Screen { - enum Tabs { Main = 0, NewGame = 1, JoinServer = 2} + enum Tabs { Main = 0, NewGame = 1, LoadGame = 2, JoinServer = 3 } GUIFrame[] menuTabs; GUIListBox mapList; + GUIListBox saveList; + GUITextBox nameBox; GUITextBox ipBox; @@ -21,7 +24,7 @@ namespace Subsurface public MainMenuScreen(Game1 game) { - menuTabs = new GUIFrame[3]; + menuTabs = new GUIFrame[Enum.GetValues(typeof(Tabs)).Length]; Rectangle panelRect = new Rectangle( Game1.GraphicsWidth / 2 - 250, @@ -32,17 +35,23 @@ namespace Subsurface menuTabs[(int)Tabs.Main].Padding = GUI.style.smallPadding; GUIButton button = new GUIButton(new Rectangle(0, 0, 0, 30), "New Game", GUI.style, Alignment.CenterX, menuTabs[(int)Tabs.Main]); - button.OnClicked = NewGameClicked; + button.UserData = (int)Tabs.NewGame; + button.OnClicked = SelectTab; //button.Enabled = false; - button = new GUIButton(new Rectangle(0, 60, 0, 30), "Join Server", GUI.style, Alignment.CenterX, menuTabs[(int)Tabs.Main]); - button.OnClicked = JoinServerClicked; + button = new GUIButton(new Rectangle(0, 60, 0, 30), "Load Game", GUI.style, Alignment.CenterX, menuTabs[(int)Tabs.Main]); + button.UserData = (int)Tabs.LoadGame; + button.OnClicked = SelectTab; - button = new GUIButton(new Rectangle(0, 120, 0, 30), "Host Server", GUI.style, Alignment.CenterX, menuTabs[(int)Tabs.Main]); + button = new GUIButton(new Rectangle(0, 120, 0, 30), "Join Server", GUI.style, Alignment.CenterX, menuTabs[(int)Tabs.Main]); + button.UserData = (int)Tabs.JoinServer; + button.OnClicked = SelectTab; + + button = new GUIButton(new Rectangle(0, 180, 0, 30), "Host Server", GUI.style, Alignment.CenterX, menuTabs[(int)Tabs.Main]); button.OnClicked = HostServerClicked; //button.Enabled = false; - button = new GUIButton(new Rectangle(0, 180, 0, 30), "Quit", GUI.style, Alignment.CenterX, menuTabs[(int)Tabs.Main]); + button = new GUIButton(new Rectangle(0, 240, 0, 30), "Quit", GUI.style, Alignment.CenterX, menuTabs[(int)Tabs.Main]); button.OnClicked = QuitClicked; //---------------------------------------------------------------------- @@ -53,7 +62,7 @@ namespace Subsurface new GUITextBlock(new Rectangle(0, 0, 0, 30), "New Game", Color.Transparent, Color.Black, Alignment.CenterX, menuTabs[(int)Tabs.NewGame]); 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[1]); + mapList = new GUIListBox(new Rectangle(0, 60, 200, 400), Color.White, menuTabs[(int)Tabs.NewGame]); foreach (Map map in Map.SavedMaps) { @@ -73,6 +82,34 @@ namespace Subsurface button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", GUI.style, Alignment.Right | Alignment.Bottom, menuTabs[(int)Tabs.NewGame]); button.OnClicked = StartGame; + //---------------------------------------------------------------------- + + menuTabs[(int)Tabs.LoadGame] = new GUIFrame(panelRect, GUI.style.backGroundColor); + menuTabs[(int)Tabs.LoadGame].Padding = GUI.style.smallPadding; + + new GUITextBlock(new Rectangle(0, 0, 0, 30), "Load Game", Color.Transparent, Color.Black, Alignment.CenterX, menuTabs[(int)Tabs.LoadGame]); + + + string[] saveFiles = Directory.GetFiles(SaveUtil.SaveFolder, "*.save"); + + //new GUITextBlock(new Rectangle(0, 30, 0, 30), "Selected map:", Color.Transparent, Color.Black, Alignment.Left, menuTabs[(int)Tabs.NewGame]); + saveList = new GUIListBox(new Rectangle(0, 60, 200, 400), Color.White, menuTabs[(int)Tabs.LoadGame]); + + foreach (string saveFile in saveFiles) + { + GUITextBlock textBlock = new GUITextBlock( + new Rectangle(0, 0, 0, 25), + saveFile, + GUI.style, + Alignment.Left, + Alignment.Left, + saveList); + textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); + textBlock.UserData = saveFile; + } + + button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", GUI.style, Alignment.Right | Alignment.Bottom, menuTabs[(int)Tabs.LoadGame]); + button.OnClicked = LoadGame; //---------------------------------------------------------------------- @@ -95,18 +132,12 @@ namespace Subsurface } - private bool NewGameClicked(GUIButton button, object obj) + private bool SelectTab(GUIButton button, object obj) { - selectedTab = (int)Tabs.NewGame; + selectedTab = (int)obj; return true; } - - private bool JoinServerClicked(GUIButton button, object obj) - { - selectedTab = (int)Tabs.JoinServer; - return true; - } - + private bool HostServerClicked(GUIButton button, object obj) { Game1.NetLobbyScreen.isServer = true; @@ -142,18 +173,39 @@ namespace Subsurface private bool StartGame(GUIButton button, object obj) { - Map selectedMap = mapList.SelectedData as Map; if (selectedMap == null) return false; - - Game1.GameSession = new GameSession(selectedMap, TimeSpan.Zero); + Game1.GameSession = new GameSession(selectedMap, TimeSpan.Zero, GameModePreset.list.Find(gm => gm.Name == "Single Player")); Game1.LobbyScreen.Select(); return true; } + private bool LoadGame(GUIButton button, object obj) + { + + string saveFile = saveList.SelectedData as string; + if (string.IsNullOrWhiteSpace(saveFile)) return false; + + try + { + SaveUtil.LoadGame(saveFile); + } + catch (Exception e) + { + DebugConsole.ThrowError("Loading map ''"+saveFile+"'' failed", e); + return false; + } + + + Game1.LobbyScreen.Select(); + + return true; + } + + private bool JoinServer(GUIButton button, object obj) { if (string.IsNullOrEmpty(nameBox.Text)) return false; diff --git a/Subsurface/Screens/NetLobbyScreen.cs b/Subsurface/Screens/NetLobbyScreen.cs index 4992832d9..d2e304ce3 100644 --- a/Subsurface/Screens/NetLobbyScreen.cs +++ b/Subsurface/Screens/NetLobbyScreen.cs @@ -36,9 +36,9 @@ namespace Subsurface } - public GameMode SelectedMode + public GameModePreset SelectedMode { - get { return modeList.SelectedData as GameMode; } + get { return modeList.SelectedData as GameModePreset; } } public TimeSpan GameDuration @@ -161,8 +161,10 @@ namespace Subsurface modeList.Enabled = (Game1.Server != null); //modeList.OnSelected = new GUIListBox.OnSelectedHandler(SelectEvent); - foreach (GameMode mode in GameMode.list) + foreach (GameModePreset mode in GameModePreset.list) { + if (mode.IsSinglePlayer) continue; + GUITextBlock textBlock = new GUITextBlock( new Rectangle(0, 0, 0, 25), mode.Name, @@ -192,8 +194,8 @@ namespace Subsurface modeList.OnSelected = Game1.Server.UpdateNetLobby; durationBar.OnMoved = Game1.Server.UpdateNetLobby; - if (mapList.CountChildren > 0) mapList.Select(Map.SavedMaps[0]); - if (GameMode.list.Count > 0) modeList.Select(GameMode.list[0]); + if (mapList.CountChildren > 0) mapList.Select(0); + if (GameModePreset.list.Count > 0) modeList.Select(0); } else { @@ -319,9 +321,9 @@ namespace Subsurface Vector2 pos = Game1.Client.Character.Position; pos.Y = -pos.Y; - Matrix transform = Matrix.CreateTranslation(new Vector3(-pos+position, 0.0f)); - - spriteBatch.Begin(SpriteSortMode.BackToFront, null,null,null,null,null,transform); + Matrix transform = Matrix.CreateTranslation(new Vector3(-pos + position, 0.0f)); + + spriteBatch.Begin(SpriteSortMode.BackToFront, null, null, null, null, null, transform); Game1.Client.Character.Draw(spriteBatch); spriteBatch.End(); } @@ -386,10 +388,10 @@ namespace Subsurface platform.IsStatic = true; } - if (previewPlatform==null) + if (previewHull==null) { pos = ConvertUnits.ToDisplayUnits(pos); - new Hull(new Rectangle((int)pos.X - 100, (int)pos.Y + 100, 200, 200)); + previewHull = new Hull(new Rectangle((int)pos.X - 100, (int)pos.Y + 100, 200, 200)); } Physics.Alpha = 1.0f; @@ -473,7 +475,7 @@ namespace Subsurface } else { - msg.Write(Path.GetFileName(selectedMap.FilePath)); + msg.Write(Path.GetFileName(selectedMap.Name)); msg.Write(selectedMap.MapHash.MD5Hash); } diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 35706e91c..97d8e02d9 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -71,6 +71,7 @@ + diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index b61cebe5ae2863ef0d94656f25ebff8beda5e86a..62606192a817994e4cab53434bcefa4f7ce97fb9 100644 GIT binary patch delta 17247 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 From 24ba9b1b98ed0530bbdc863617ee0f1deb67f6a3 Mon Sep 17 00:00:00 2001 From: Regalis Date: Fri, 19 Jun 2015 11:53:31 +0300 Subject: [PATCH 2/2] GameMode/CrewManager bugfixes, fabricators --- .../Content/Items/Fabricators/fabricator.png | Bin 0 -> 2133 bytes .../Content/Items/Fabricators/fabricators.xml | 24 ++ .../Content/Items/{ => Weapons}/railgun.ogg | Bin .../Content/Items/{ => Weapons}/railgun.xml | 0 .../Items/{ => Weapons}/railgunbarrel.png | Bin .../Items/{ => Weapons}/railgunbase.png | Bin .../Items/{ => Weapons}/railguncontroller.png | Bin .../Items/{ => Weapons}/railgunloader.png | Bin .../Items/{ => Weapons}/railgunshell.png | Bin Subsurface/GUI/GUIComponent.cs | 10 + Subsurface/GameSession/GameMode.cs | 34 ++- Subsurface/GameSession/GameSession.cs | 48 ++-- Subsurface/GameSession/SinglePlayerMode.cs | 21 +- Subsurface/GameSession/TraitorMode.cs | 2 + Subsurface/Items/Components/Container.cs | 72 +++--- Subsurface/Items/Components/Fabricator.cs | 216 ++++++++++++++++++ Subsurface/Items/Inventory.cs | 38 ++- Subsurface/Items/Item.cs | 6 + Subsurface/Items/ItemInventory.cs | 7 +- Subsurface/Map/Map.cs | 4 - Subsurface/Networking/GameClient.cs | 4 +- Subsurface/Networking/GameServer.cs | 5 +- Subsurface/Screens/LobbyScreen.cs | 3 +- Subsurface/Screens/MainMenu.cs | 2 +- Subsurface/Subsurface.csproj | 22 +- Subsurface_Solution.v12.suo | Bin 291328 -> 274944 bytes 26 files changed, 420 insertions(+), 98 deletions(-) create mode 100644 Subsurface/Content/Items/Fabricators/fabricator.png create mode 100644 Subsurface/Content/Items/Fabricators/fabricators.xml rename Subsurface/Content/Items/{ => Weapons}/railgun.ogg (100%) rename Subsurface/Content/Items/{ => Weapons}/railgun.xml (100%) rename Subsurface/Content/Items/{ => Weapons}/railgunbarrel.png (100%) rename Subsurface/Content/Items/{ => Weapons}/railgunbase.png (100%) rename Subsurface/Content/Items/{ => Weapons}/railguncontroller.png (100%) rename Subsurface/Content/Items/{ => Weapons}/railgunloader.png (100%) rename Subsurface/Content/Items/{ => Weapons}/railgunshell.png (100%) create mode 100644 Subsurface/Items/Components/Fabricator.cs diff --git a/Subsurface/Content/Items/Fabricators/fabricator.png b/Subsurface/Content/Items/Fabricators/fabricator.png new file mode 100644 index 0000000000000000000000000000000000000000..e82943efb3a04add5766915f64b9d54fdf284c29 GIT binary patch literal 2133 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1SEZ8zRdwrjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qt-4D7EwT^vIy;@(c(IBAYKU&~je?;d`!r4L>G zWGssd-q-oonQ+~nad)q5riaJTb$o0rbuY6Q=+y7FT3;V4d&%}d;$3E$Yd~r(vqyf{ zy{e91!XK6I@B8xpe*JGvp4_Rursik9GaTpnY^!Qnk_KpS1->YtW#+*)RJA=;W}^YvoLSq?td+s4T&I6R@V9>} zucycVDX9I-=jnIwhJIbcpP=3HKX&rl|MSwfY(1sOC6&1Mwq9R^1RGnfXzbbO2QhXv zl`o##{rRFjl?L+952V!n_#JHj{o(QWm#WJHFg=OI)$8jU?D{MWR?93}Ab4%}+eaO( zi3u0NE?(V}n)kGWc{8Rbo`sDnAI>2Yx0lVxAY=85tb0b=i;gr_KC6Dtkjo29zehKo zS*x>WPSU#natVuDrw5<;dcVHO%<9nro6mde8GaW&DX%+-nR5D-_kZSY17$wlVr_Ss z8KHcE7dY0(F-uBp2`w?rpBZflGT`oiCXh*MiaMIyBHn*{eB%9|riEzva`klwXg&fb z!SglW_c!z+(&Ar>PuBYr5Dt%gD!|(N;g#uxM#pH^@XynBPF3bRV|@Rwe!^lPL#tgQ zqvdO!eczvR`Vznr12v~(^~}So*$R+i1mctQedT-?t^s`PSyYAP z(U||X2i&;zm(O^;pZ!M0!>1y}f4?(G>!OAobIz6zMO{1pRX6mC#rYXtujk)zaX<|D ze~De;fn%yfMG;rpJI1&bJk0)n2haRf&zKL1WZVw@-x9wPqT2QV_teA(CpBm6{Lk`s zGXa17o&P}_s+zrGp%IUbC9CoG`3q_Z1;c;gx}^}+{&ESme~fO%i-QuD-IfFC5aTMp zGpzpGm-C~&`md?$g|MUHz({XpS3hHX;WqP{<(hH3B!Mw~XdAFhk8Z78_j5k;huLN6 z&cM_ms8g(cye)B_HZZ?JP61NmD literal 0 HcmV?d00001 diff --git a/Subsurface/Content/Items/Fabricators/fabricators.xml b/Subsurface/Content/Items/Fabricators/fabricators.xml new file mode 100644 index 000000000..ee84049cd --- /dev/null +++ b/Subsurface/Content/Items/Fabricators/fabricators.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Subsurface/Content/Items/railgun.ogg b/Subsurface/Content/Items/Weapons/railgun.ogg similarity index 100% rename from Subsurface/Content/Items/railgun.ogg rename to Subsurface/Content/Items/Weapons/railgun.ogg diff --git a/Subsurface/Content/Items/railgun.xml b/Subsurface/Content/Items/Weapons/railgun.xml similarity index 100% rename from Subsurface/Content/Items/railgun.xml rename to Subsurface/Content/Items/Weapons/railgun.xml diff --git a/Subsurface/Content/Items/railgunbarrel.png b/Subsurface/Content/Items/Weapons/railgunbarrel.png similarity index 100% rename from Subsurface/Content/Items/railgunbarrel.png rename to Subsurface/Content/Items/Weapons/railgunbarrel.png diff --git a/Subsurface/Content/Items/railgunbase.png b/Subsurface/Content/Items/Weapons/railgunbase.png similarity index 100% rename from Subsurface/Content/Items/railgunbase.png rename to Subsurface/Content/Items/Weapons/railgunbase.png diff --git a/Subsurface/Content/Items/railguncontroller.png b/Subsurface/Content/Items/Weapons/railguncontroller.png similarity index 100% rename from Subsurface/Content/Items/railguncontroller.png rename to Subsurface/Content/Items/Weapons/railguncontroller.png diff --git a/Subsurface/Content/Items/railgunloader.png b/Subsurface/Content/Items/Weapons/railgunloader.png similarity index 100% rename from Subsurface/Content/Items/railgunloader.png rename to Subsurface/Content/Items/Weapons/railgunloader.png diff --git a/Subsurface/Content/Items/railgunshell.png b/Subsurface/Content/Items/Weapons/railgunshell.png similarity index 100% rename from Subsurface/Content/Items/railgunshell.png rename to Subsurface/Content/Items/Weapons/railgunshell.png diff --git a/Subsurface/GUI/GUIComponent.cs b/Subsurface/GUI/GUIComponent.cs index c21a4dd73..a2fbf255c 100644 --- a/Subsurface/GUI/GUIComponent.cs +++ b/Subsurface/GUI/GUIComponent.cs @@ -133,6 +133,16 @@ namespace Subsurface keyboardDispatcher = new KeyboardDispatcher(window); } + public T GetChild() + { + foreach (GUIComponent child in children) + { + if (child is T) return (T)(object)child; + } + + return default(T); + } + public GUIComponent GetChild(object obj) { foreach (GUIComponent child in children) diff --git a/Subsurface/GameSession/GameMode.cs b/Subsurface/GameSession/GameMode.cs index 45ab79427..5be3b8bfa 100644 --- a/Subsurface/GameSession/GameMode.cs +++ b/Subsurface/GameSession/GameMode.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Reflection; @@ -37,12 +38,17 @@ namespace Subsurface { public static List presetList = new List(); - //TimeSpan duration; + TimeSpan duration; protected DateTime startTime; protected DateTime endTime; //public readonly bool IsSinglePlayer; + private GUIProgressBar timerBar; + + + + protected bool isRunning; //protected string name; @@ -85,16 +91,25 @@ namespace Subsurface { this.preset = preset; + //list.Add(this); } public virtual void Draw(SpriteBatch spriteBatch) - { } + { + if (timerBar != null) timerBar.Draw(spriteBatch); + } public virtual void Start(TimeSpan duration) { startTime = DateTime.Now; - endTime = startTime + duration; + if (duration!=TimeSpan.Zero) + { + endTime = startTime + duration; + this.duration = duration; + + timerBar = new GUIProgressBar(new Rectangle(Game1.GraphicsWidth - 120, 20, 100, 25), Color.Gold, 0.0f, null); + } endMessage = "The round has ended!"; @@ -105,10 +120,15 @@ namespace Subsurface { if (!isRunning) return; - if (DateTime.Now >= endTime) + if (duration!=TimeSpan.Zero) { - End(endMessage); + double elapsedTime = (DateTime.Now - startTime).TotalSeconds; + timerBar.BarSize = (float)(elapsedTime / duration.TotalSeconds); } + //if (DateTime.Now >= endTime) + //{ + // End(endMessage); + //} } public virtual void End(string endMessage = "") @@ -119,7 +139,7 @@ namespace Subsurface Game1.GameSession.EndShift(null, null); } - + public static void Init() { new GameModePreset("Single Player", typeof(SinglePlayerMode), true); diff --git a/Subsurface/GameSession/GameSession.cs b/Subsurface/GameSession/GameSession.cs index a1b98ea42..6762a6f45 100644 --- a/Subsurface/GameSession/GameSession.cs +++ b/Subsurface/GameSession/GameSession.cs @@ -15,8 +15,8 @@ namespace Subsurface public readonly TaskManager taskManager; - protected DateTime startTime; - protected DateTime endTime; + //protected DateTime startTime; + //protected DateTime endTime; public readonly GameMode gameMode; @@ -25,23 +25,17 @@ namespace Subsurface private GUIListBox chatBox; private GUITextBox textBox; - private GUIProgressBar timerBar; - - private GUIButton endShiftButton; - private string savePath; - private Map selectedMap; - - + private Map selectedMap; - public GameSession(Map selectedMap, TimeSpan gameDuration, GameModePreset gameModePreset) - :this(selectedMap, gameDuration, gameModePreset.Instantiate()) + public GameSession(Map selectedMap, GameModePreset gameModePreset) + :this(selectedMap, gameModePreset.Instantiate()) { } - public GameSession(Map selectedMap, TimeSpan gameDuration, GameMode gameMode = null) + public GameSession(Map selectedMap, GameMode gameMode = null) { taskManager = new TaskManager(this); @@ -63,23 +57,15 @@ namespace Subsurface Color.White * 0.5f, Color.Black, Alignment.Bottom, Alignment.Left, guiRoot); textBox.OnEnter = EnterChatMessage; } - - if (Game1.Client==null) - { - endShiftButton = new GUIButton(new Rectangle(Game1.GraphicsWidth - 240, 20, 100, 25), "End shift", Color.White, Alignment.Left | Alignment.Top, guiRoot); - endShiftButton.OnClicked = EndShift; - } - - timerBar = new GUIProgressBar(new Rectangle(Game1.GraphicsWidth - 120, 20, 100, 25), Color.Gold, 0.0f, guiRoot); - + this.gameMode = gameMode; //if (gameMode != null && !gameMode.IsSinglePlayer) //{ // gameMode.Start(Game1.NetLobbyScreen.GameDuration); //} - startTime = DateTime.Now; - endTime = startTime + gameDuration; + //startTime = DateTime.Now; + //endTime = startTime + gameDuration; this.selectedMap = selectedMap; @@ -90,7 +76,7 @@ namespace Subsurface } public GameSession(Map selectedMap, string savePath, string filePath) - : this(selectedMap, new TimeSpan(0,0,0,0)) + : this(selectedMap) { XDocument doc = ToolBox.TryLoadXml(filePath); if (doc == null) return; @@ -109,13 +95,13 @@ namespace Subsurface this.savePath = savePath; } - public void StartShift(int scriptedEventCount = 1) + public void StartShift(TimeSpan duration, int scriptedEventCount = 1) { //if (crewManager.characterInfos.Count == 0) return; if (Map.Loaded!=selectedMap) selectedMap.Load(); - gameMode.Start(TimeSpan.Zero); + if (gameMode!=null) gameMode.Start(duration); //crewManager.StartShift(); taskManager.StartShift(scriptedEventCount); @@ -138,7 +124,7 @@ namespace Subsurface } taskManager.EndShift(); - gameMode.End(); + //gameMode.End(); return true; } @@ -194,7 +180,7 @@ namespace Subsurface { taskManager.Update(deltaTime); //if (endShiftButton!=null) endShiftButton.Enabled = !taskManager.CriticalTasks; - endShiftButton.Enabled = true; + //endShiftButton.Enabled = true; guiRoot.Update(deltaTime); @@ -204,9 +190,9 @@ namespace Subsurface if (gameMode != null) gameMode.Update(deltaTime); - double duration = (endTime - startTime).TotalSeconds; - double elapsedTime = (DateTime.Now-startTime).TotalSeconds; - timerBar.BarSize = (float)(elapsedTime / Math.Max(duration, 1.0)); + //double duration = (endTime - startTime).TotalSeconds; + //double elapsedTime = (DateTime.Now-startTime).TotalSeconds; + //timerBar.BarSize = (float)(elapsedTime / Math.Max(duration, 1.0)); if (PlayerInput.KeyHit(Keys.Tab)) { diff --git a/Subsurface/GameSession/SinglePlayerMode.cs b/Subsurface/GameSession/SinglePlayerMode.cs index 678dae8c2..d644d04ae 100644 --- a/Subsurface/GameSession/SinglePlayerMode.cs +++ b/Subsurface/GameSession/SinglePlayerMode.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Linq; @@ -12,6 +13,8 @@ namespace Subsurface public readonly CrewManager crewManager; public readonly HireManager hireManager; + private GUIButton endShiftButton; + private int day; public int Day @@ -28,6 +31,9 @@ namespace Subsurface crewManager = new CrewManager(); hireManager = new HireManager(); + endShiftButton = new GUIButton(new Rectangle(Game1.GraphicsWidth - 240, 20, 100, 25), "End shift", Color.White, Alignment.Left | Alignment.Top); + endShiftButton.OnClicked = EndShift; + hireManager.GenerateCharacters("Content/Characters/Human/human.xml", 10); day = 1; @@ -73,8 +79,11 @@ namespace Subsurface public override void Draw(SpriteBatch spriteBatch) { + base.Draw(spriteBatch); + crewManager.Draw(spriteBatch); + endShiftButton.Draw(spriteBatch); //chatBox.Draw(spriteBatch); //textBox.Draw(spriteBatch); @@ -85,8 +94,12 @@ namespace Subsurface public override void Update(float deltaTime) { + base.Update(deltaTime); + crewManager.Update(deltaTime); + endShiftButton.Update(deltaTime); + if (!crewDead) { if (crewManager.characters.Find(c => !c.IsDead) == null) @@ -102,7 +115,7 @@ namespace Subsurface } } - public override void End(string endMessage = "") + private bool EndShift(GUIButton button, object obj) { StringBuilder sb = new StringBuilder(); List casualties = crewManager.characters.FindAll(c => c.IsDead); @@ -142,6 +155,10 @@ namespace Subsurface { Character.characterList.RemoveAt(i); } + + Game1.GameSession.EndShift(null, null); + + return true; } public void Save(XElement element) diff --git a/Subsurface/GameSession/TraitorMode.cs b/Subsurface/GameSession/TraitorMode.cs index c8f1b066b..f93b5e054 100644 --- a/Subsurface/GameSession/TraitorMode.cs +++ b/Subsurface/GameSession/TraitorMode.cs @@ -25,6 +25,8 @@ namespace Subsurface public override void Update(float deltaTime) { + base.Update(deltaTime); + if (!isRunning) return; if (DateTime.Now >= endTime) diff --git a/Subsurface/Items/Components/Container.cs b/Subsurface/Items/Components/Container.cs index 288470e32..e3aa1a386 100644 --- a/Subsurface/Items/Components/Container.cs +++ b/Subsurface/Items/Components/Container.cs @@ -13,25 +13,13 @@ namespace Subsurface.Items.Components public ItemInventory inventory; //how many items can be contained - private int capacity; - - private bool hideItems; - private bool drawInventory; - - //the position of the first item in the container - private Vector2 itemPos; - - //item[i].Pos = itemPos + itemInterval*i - private Vector2 itemInterval; - - private float itemRotation; - [HasDefaultValue(5, false)] public int Capacity { get { return capacity; } set { capacity = Math.Max(value, 1); } } + private int capacity; [HasDefaultValue(true, false)] public bool HideItems @@ -39,6 +27,7 @@ namespace Subsurface.Items.Components get { return hideItems; } set { hideItems = value; } } + private bool hideItems; [HasDefaultValue(false, false)] public bool DrawInventory @@ -46,6 +35,25 @@ namespace Subsurface.Items.Components get { return drawInventory; } set { drawInventory = value; } } + private bool drawInventory; + + //the position of the first item in the container + [HasDefaultValue("0.0,0.0", false)] + public string ItemPos + { + get { return ToolBox.Vector2ToString(itemPos); } + set { itemPos = ToolBox.ParseToVector2(value); } + } + private Vector2 itemPos; + + //item[i].Pos = itemPos + itemInterval*i + [HasDefaultValue("0.0,0.0", false)] + public string ItemInterval + { + get { return ToolBox.Vector2ToString(itemInterval); } + set { itemInterval = ToolBox.ParseToVector2(value); } + } + private Vector2 itemInterval; [HasDefaultValue(0.0f, false)] public float ItemRotation @@ -53,25 +61,33 @@ namespace Subsurface.Items.Components get { return itemRotation; } set { itemRotation = value; } } + private float itemRotation; - [HasDefaultValue("0.0,0.0", false)] - public string ItemPos - { - get { return ToolBox.Vector2ToString(itemPos); } - set { itemPos = ToolBox.ParseToVector2(value); } - } - [HasDefaultValue("0.0,0.0", false)] - public string ItemInterval + [HasDefaultValue("0.5,0.9", false)] + public string HudPos { - get { return ToolBox.Vector2ToString(itemInterval); } - set { itemInterval = ToolBox.ParseToVector2(value); } + get { return ToolBox.Vector2ToString(hudPos); } + set + { + hudPos = ToolBox.ParseToVector2(value); + //inventory.CenterPos = hudPos; + } } - + private Vector2 hudPos; + + [HasDefaultValue(5, false)] + public int SlotsPerRow + { + get { return slotsPerRow; } + set { slotsPerRow = value; } + } + private int slotsPerRow; + public ItemContainer(Item item, XElement element) : base (item, element) { - inventory = new ItemInventory(this, capacity); + inventory = new ItemInventory(this, capacity, hudPos, slotsPerRow); containableItems = new List(); //itemPos = ToolBox.GetAttributeVector2(element, "ItemPos", Vector2.Zero); @@ -99,6 +115,7 @@ namespace Subsurface.Items.Components public bool CanBeContained(Item item) { + if (containableItems.Count == 0) return true; return (containableItems.Find(x => x.MatchesItem(item)) != null); } @@ -182,10 +199,7 @@ namespace Subsurface.Items.Components public override bool Pick(Character picker) { - if (picker == null) return false; - //picker.SelectedConstruction = item; - - return true; + return (picker != null); } diff --git a/Subsurface/Items/Components/Fabricator.cs b/Subsurface/Items/Components/Fabricator.cs new file mode 100644 index 000000000..398799724 --- /dev/null +++ b/Subsurface/Items/Components/Fabricator.cs @@ -0,0 +1,216 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Subsurface.Items.Components +{ + class FabricableItem + { + //public static List list = new List(); + + //public readonly string[] FabricatorTags; + + public readonly ItemPrefab TargetItem; + + public readonly List RequiredItems; + + public readonly float RequiredTime; + + + //ListOrSomething requiredLevels + + public FabricableItem(XElement element) + { + string name = ToolBox.GetAttributeString(element, "name", "").ToLower(); + + TargetItem = ItemPrefab.list.Find(ip => ip.Name.ToLower() == name) as ItemPrefab; + if (TargetItem == null) + { + DebugConsole.ThrowError("Error in Fabricable Item! Item ''" + element.Name + "'' not found."); + return; + } + + RequiredItems = new List(); + + string[] requiredItemNames = ToolBox.GetAttributeString(element, "requireditems", "").Split(','); + foreach (string requiredItemName in requiredItemNames) + { + ItemPrefab requiredItem = ItemPrefab.list.Find(ip => ip.Name.ToLower() == requiredItemName.Trim().ToLower()) as ItemPrefab; + if (requiredItem == null) continue; + RequiredItems.Add(requiredItem); + } + + RequiredTime = ToolBox.GetAttributeFloat(element, "requiredtime", 1.0f); + } + } + + class Fabricator : ItemComponent + { + List fabricableItems; + + GUIListBox itemList; + + GUIFrame selectedItemFrame; + + FabricableItem fabricatedItem; + float timeUntilReady; + + public Fabricator(Item item, XElement element) + : base(item, element) + { + fabricableItems = new List(); + + foreach (XElement subElement in element.Elements()) + { + if (subElement.Name.ToString() != "fabricableitem") continue; + + FabricableItem fabricableItem = new FabricableItem(subElement); + if (fabricableItem.TargetItem != null) fabricableItems.Add(fabricableItem); + + } + + int width = 400, height = 300; + itemList = new GUIListBox(new Rectangle(Game1.GraphicsWidth / 2 - width / 2, Game1.GraphicsHeight / 2 - height / 2, width, height), Color.White * 0.7f); + itemList.OnSelected = SelectItem; + //structureList.CheckSelected = MapEntityPrefab.GetSelected; + + foreach (FabricableItem fi in fabricableItems) + { + Color color = ((itemList.CountChildren % 2) == 0) ? Color.White : Color.LightGray; + + //GUIFrame frame = new GUIFrame(new Rectangle(0, 0, 0, 50), Color.Transparent, itemList); + //frame.UserData = fi; + //frame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f); + //frame.Color = color; + //frame.HoverColor = Color.Gold * 0.2f; + //frame.SelectedColor = Color.Gold * 0.5f; + + GUITextBlock textBlock = new GUITextBlock( + new Rectangle(0, 0, 0, 25), + fi.TargetItem.Name, + color, Color.Black, + Alignment.Left, + Alignment.Left, + itemList); + textBlock.UserData = fi; + textBlock.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f); + + //if (fi.TargetItem.sprite != null) + //{ + // GUIImage img = new GUIImage(new Rectangle(0, 0, 40, 40), fi.TargetItem.sprite, Alignment.Left, frame); + // img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f); + //} + } + } + + private bool SelectItem(object obj) + { + FabricableItem targetItem = obj as FabricableItem; + if (targetItem == null) return false; + + int width = 200, height = 150; + selectedItemFrame = new GUIFrame(new Rectangle(Game1.GraphicsWidth / 2 - width / 2, itemList.Rect.Bottom+20, width, height), Color.Black*0.8f); + selectedItemFrame.Padding = GUI.style.smallPadding; + + if (targetItem.TargetItem.sprite != null) + { + GUIImage img = new GUIImage(new Rectangle(0, 0, 40, 40), targetItem.TargetItem.sprite, Alignment.CenterX, selectedItemFrame); + img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f); + + string text = targetItem.TargetItem.Name + "\n"; + text += "Required items:\n"; + foreach (ItemPrefab ip in targetItem.RequiredItems) + { + text += " - " + ip.Name + "\n"; + } + text += "Required time: "+targetItem.RequiredTime+" s"; + + GUITextBlock textBlock = new GUITextBlock( + new Rectangle(0, 0, 0, 25), + text, + Color.Transparent, Color.White, + Alignment.CenterX | Alignment.CenterY, + Alignment.Left, + selectedItemFrame); + + GUIButton button = new GUIButton(new Rectangle(0,0,100,20), "Create", Color.White, Alignment.CenterX | Alignment.Bottom, selectedItemFrame); + button.OnClicked = StartFabricating; + button.UserData = targetItem; + + + } + + return true; + } + + public override bool Pick(Character picker) + { + return (picker != null); + } + + private bool StartFabricating(GUIButton button, object obj) + { + GUIComponent listElement = itemList.GetChild(obj); + + listElement.Color = Color.Green; + itemList.Enabled = false; + + fabricatedItem = obj as FabricableItem; + isActive = true; + + timeUntilReady = fabricatedItem.RequiredTime; + + return true; + } + + public override void Update(float deltaTime, Camera cam) + { + timeUntilReady -= deltaTime; + + if (timeUntilReady > 0.0f) return; + + ItemContainer container = item.GetComponent(); + foreach (ItemPrefab ip in fabricatedItem.RequiredItems) + { + var requiredItem = Array.Find(container.inventory.items, it => it != null && it.Prefab == ip); + container.inventory.RemoveItem(requiredItem); + } + + new Item(fabricatedItem.TargetItem, item.Position); + + isActive = false; + fabricatedItem = null; + } + + public override void DrawHUD(SpriteBatch spriteBatch, Character character) + { + FabricableItem targetItem = itemList.SelectedData as FabricableItem; + if (targetItem != null) + { + selectedItemFrame.GetChild().Enabled = true; + + ItemContainer container = item.GetComponent(); + foreach (ItemPrefab ip in targetItem.RequiredItems) + { + if (Array.Find(container.inventory.items, it => it != null && it.Prefab == ip) != null) continue; + selectedItemFrame.GetChild().Enabled = false; + break; + } + } + + + itemList.Update(0.016f); + itemList.Draw(spriteBatch); + + if (selectedItemFrame != null) + { + selectedItemFrame.Update(0.016f); + selectedItemFrame.Draw(spriteBatch); + } + } + } +} diff --git a/Subsurface/Items/Inventory.cs b/Subsurface/Items/Inventory.cs index 5893628b7..10d19af36 100644 --- a/Subsurface/Items/Inventory.cs +++ b/Subsurface/Items/Inventory.cs @@ -10,20 +10,44 @@ namespace Subsurface { class Inventory : Entity { + public static Item draggingItem; + public static Item doubleClickedItem; + + private int slotsPerRow; + + public int SlotsPerRow + { + set { slotsPerRow = Math.Max(1, value); } + } + protected int capacity; - public static Item draggingItem; + public Vector2 CenterPos + { + get { return centerPos; } + set + { + centerPos = value; + centerPos.X *= Game1.GraphicsWidth; + centerPos.Y *= Game1.GraphicsHeight; + } + } - public static Item doubleClickedItem; + private Vector2 centerPos; protected int selectedSlot; public Item[] items; - public Inventory(int capacity) + public Inventory(int capacity, Vector2? centerPos = null, int slotsPerRow=5) { this.capacity = capacity; + + this.slotsPerRow = slotsPerRow; + items = new Item[capacity]; + + CenterPos = (centerPos==null) ? new Vector2(0.5f, 0.5f) : (Vector2)centerPos; } public int FindIndex(Item item) @@ -132,13 +156,11 @@ namespace Subsurface int rectWidth = 40, rectHeight = 40; int spacing = 10; - - int slotsPerRow = 5; - + int rows = (int)Math.Ceiling((double)capacity / slotsPerRow); - int startX = Game1.GraphicsWidth / 2 - (rectWidth * slotsPerRow + spacing * (slotsPerRow - 1)) / 2; - int startY = (int)(Game1.GraphicsHeight * 0.9) - rows*(spacing+rectHeight); + int startX = (int)centerPos.X - (rectWidth * slotsPerRow + spacing * (slotsPerRow - 1)) / 2; + int startY = (int)centerPos.Y - rows * (spacing + rectHeight); Rectangle slotRect = new Rectangle(startX, startY, rectWidth, rectHeight); Rectangle draggingItemSlot = slotRect; diff --git a/Subsurface/Items/Item.cs b/Subsurface/Items/Item.cs index f1c69953e..3bb86d37c 100644 --- a/Subsurface/Items/Item.cs +++ b/Subsurface/Items/Item.cs @@ -166,6 +166,12 @@ namespace Subsurface } + public Item(ItemPrefab itemPrefab, Vector2 position) + : this(new Rectangle((int)position.X, (int)position.Y, (int)itemPrefab.sprite.size.X, (int)itemPrefab.sprite.size.Y), itemPrefab) + { + + } + public Item(Rectangle newRect, ItemPrefab itemPrefab) { prefab = itemPrefab; diff --git a/Subsurface/Items/ItemInventory.cs b/Subsurface/Items/ItemInventory.cs index 5cdf85cf7..5fd589516 100644 --- a/Subsurface/Items/ItemInventory.cs +++ b/Subsurface/Items/ItemInventory.cs @@ -1,4 +1,5 @@ -using Subsurface.Items.Components; +using Microsoft.Xna.Framework; +using Subsurface.Items.Components; namespace Subsurface { @@ -6,8 +7,8 @@ namespace Subsurface { ItemContainer container; - public ItemInventory(ItemContainer container, int capacity) - : base(capacity) + public ItemInventory(ItemContainer container, int capacity, Vector2? centerPos = null, int slotsPerRow = 5) + : base(capacity, centerPos, slotsPerRow) { this.container = container; } diff --git a/Subsurface/Map/Map.cs b/Subsurface/Map/Map.cs index 05d67c70c..0ac4f41f1 100644 --- a/Subsurface/Map/Map.cs +++ b/Subsurface/Map/Map.cs @@ -524,14 +524,10 @@ namespace Subsurface private void Clear() { - filePath = ""; - if (Game1.GameScreen.Cam != null) Game1.GameScreen.Cam.TargetPos = Vector2.Zero; Entity.RemoveAll(); - if (Game1.GameSession != null) Game1.GameSession.EndShift(null, null); - PhysicsBody.list.Clear(); Ragdoll.list.Clear(); diff --git a/Subsurface/Networking/GameClient.cs b/Subsurface/Networking/GameClient.cs index eae49a78e..e3108b808 100644 --- a/Subsurface/Networking/GameClient.cs +++ b/Subsurface/Networking/GameClient.cs @@ -240,8 +240,8 @@ namespace Subsurface.Networking TimeSpan duration = new TimeSpan(0,(int)durationMinutes,0); //int gameModeIndex = inc.ReadInt32(); - Game1.GameSession = new GameSession(Map.Loaded, duration); - Game1.GameSession.StartShift(1); + Game1.GameSession = new GameSession(Map.Loaded); + Game1.GameSession.StartShift(duration, 1); myCharacter = ReadCharacterData(inc); Character.Controlled = myCharacter; diff --git a/Subsurface/Networking/GameServer.cs b/Subsurface/Networking/GameServer.cs index 8704f091b..d57040920 100644 --- a/Subsurface/Networking/GameServer.cs +++ b/Subsurface/Networking/GameServer.cs @@ -9,7 +9,6 @@ namespace Subsurface.Networking { class GameServer : NetworkMember { - // Server object NetServer Server; // Configuration object @@ -275,8 +274,8 @@ namespace Subsurface.Networking //selectedMap.Load(); - Game1.GameSession = new GameSession(selectedMap, Game1.NetLobbyScreen.GameDuration, Game1.NetLobbyScreen.SelectedMode); - Game1.GameSession.StartShift(1); + Game1.GameSession = new GameSession(selectedMap, Game1.NetLobbyScreen.SelectedMode); + Game1.GameSession.StartShift(Game1.NetLobbyScreen.GameDuration, 1); //EventManager.SelectEvent(Game1.netLobbyScreen.SelectedEvent); foreach (Client client in connectedClients) diff --git a/Subsurface/Screens/LobbyScreen.cs b/Subsurface/Screens/LobbyScreen.cs index 7b573ff33..508569e85 100644 --- a/Subsurface/Screens/LobbyScreen.cs +++ b/Subsurface/Screens/LobbyScreen.cs @@ -3,6 +3,7 @@ using FarseerPhysics.Dynamics; using FarseerPhysics.Factories; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using System; namespace Subsurface { @@ -351,7 +352,7 @@ namespace Subsurface private bool StartShift(GUIButton button, object selection) { - Game1.GameSession.StartShift(); + Game1.GameSession.StartShift(TimeSpan.Zero); Game1.GameScreen.Select(); return true; diff --git a/Subsurface/Screens/MainMenu.cs b/Subsurface/Screens/MainMenu.cs index da30e75e1..5e442a034 100644 --- a/Subsurface/Screens/MainMenu.cs +++ b/Subsurface/Screens/MainMenu.cs @@ -176,7 +176,7 @@ namespace Subsurface Map selectedMap = mapList.SelectedData as Map; if (selectedMap == null) return false; - Game1.GameSession = new GameSession(selectedMap, TimeSpan.Zero, GameModePreset.list.Find(gm => gm.Name == "Single Player")); + Game1.GameSession = new GameSession(selectedMap, GameModePreset.list.Find(gm => gm.Name == "Single Player")); Game1.LobbyScreen.Select(); diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 97d8e02d9..19d88f624 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -78,6 +78,7 @@ + @@ -303,6 +304,13 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + Designer + PreserveNewest @@ -435,22 +443,22 @@ PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest @@ -585,7 +593,7 @@ PreserveNewest - + PreserveNewest diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 62606192a817994e4cab53434bcefa4f7ce97fb9..dcfebe70664f2612937303845eda5c42152c22dc 100644 GIT binary patch delta 13032 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 delta 18069 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 r3&QzQ^=}