From 89dfed83afbb8272388940cd0b4b46b8b066153f Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 27 Jul 2017 12:03:55 -0400 Subject: [PATCH] Hacking UI is coming in. --- ShiftOS.Frontend/Apps/Network.cs | 228 ++++++++++++++++++ ShiftOS.Frontend/Commands.cs | 3 +- .../GraphicsSubsystem/GraphicsContext.cs | 10 +- .../GraphicsSubsystem/UIManager.cs | 4 +- ShiftOS.Frontend/MainMenu.cs | 17 ++ ShiftOS.Frontend/ShiftOS.Frontend.csproj | 1 + ShiftOS.Objects/Hackable.cs | 8 + ShiftOS_TheReturn/Hacking.cs | 66 +++++ 8 files changed, 327 insertions(+), 10 deletions(-) create mode 100644 ShiftOS.Frontend/Apps/Network.cs diff --git a/ShiftOS.Frontend/Apps/Network.cs b/ShiftOS.Frontend/Apps/Network.cs new file mode 100644 index 0000000..5cbc385 --- /dev/null +++ b/ShiftOS.Frontend/Apps/Network.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Xna.Framework; +using ShiftOS.Engine; +using ShiftOS.Frontend.GraphicsSubsystem; +using ShiftOS.Frontend.GUI; +using ShiftOS.Objects; +using static ShiftOS.Engine.SkinEngine; + +namespace ShiftOS.Frontend.Apps +{ + [WinOpen("network")] + [Launcher("Network", false, null, "Networking")] + [DefaultTitle("Network")] + public class Network : Control, IShiftOSWindow + { + private NetworkGUIState _state = NetworkGUIState.Listing; + private TextControl _title = new TextControl(); + private TextControl _subtitle = new TextControl(); + private TextControl _description = new TextControl(); + private ListBox _sysList = new ListBox(); + private Button _connect = new Button(); + private Button _disconnect = new Button(); + private HackableSystem _current = null; + + public Network() + { + Width = 720; + Height = 480; + AddControl(_title); + AddControl(_subtitle); + AddControl(_description); + AddControl(_sysList); + AddControl(_connect); + AddControl(_disconnect); + + _connect.Text = "Connect"; + _connect.AutoSize = true; + + _title.Font = LoadedSkin.HeaderFont; + _title.AutoSize = true; + _title.Text = "Network"; + + _subtitle.AutoSize = true; + _subtitle.Text = "Select a Digital Society system below to view information about it."; + _subtitle.Font = LoadedSkin.Header3Font; + + _sysList.DoubleClick += () => + { + if(_sysList.SelectedItem != null) + { + ProcedurallyGenerateWhatWillBringShiftOSBack(_sysList.SelectedItem as Hackable); + } + }; + _sysList.KeyEvent += (k) => + { + if (k.Key == Microsoft.Xna.Framework.Input.Keys.Enter) + { + if (_sysList.SelectedItem != null) + { + ProcedurallyGenerateWhatWillBringShiftOSBack(_sysList.SelectedItem as Hackable); + } + } + }; + _connect.Click += () => + { + ListPorts(); + }; + } + + public void ListPorts() + { + _state = NetworkGUIState.PortsList; + int portListStart = _sysList.Y; + int portHeight = 100; + for(int i = 0; i < _current.PortsToUnlock.Count; i++) + { + var portview = new PortView(_current.PortsToUnlock[i]); + portview.Width = _sysList.Width; + portview.X = _sysList.X; + portview.Y = portListStart + (portHeight * i); + portview.Height = portHeight; + AddControl(portview); + } + } + + public void OnLoad() + { + ListHackables(); + } + + bool doCountdown = false; + + public void ProcedurallyGenerateWhatWillBringShiftOSBack(Hackable hackable) + { + _state = NetworkGUIState.Information; + Hacking.InitHack(hackable); + doCountdown = Hacking.CurrentHackable.DoConnectionTimeout; + Hacking.CurrentHackable.DoConnectionTimeout = false; + _current = Hacking.CurrentHackable; + } + + public void ListHackables() + { + _state = NetworkGUIState.Listing; + _sysList.ClearItems(); + foreach(var hackable in Hacking.AvailableToHack.OrderBy(x=>x.FriendlyName)) + { + _sysList.AddItem(hackable); + } + } + + public void OnSkinLoad() + { + } + + public bool OnUnload() + { + return true; + } + + public void OnUpgrade() + { + } + + protected override void OnLayout(GameTime gameTime) + { + _title.X = 15; + _title.Y = 15; + + _subtitle.X = 15; + _subtitle.Y = _title.Y + _title.Height + 7; + + _description.Visible = (_current != null) && _state != NetworkGUIState.Listing; + _connect.Visible = (_current != null) && _state == NetworkGUIState.Information; + _disconnect.Visible = (_current != null) && _state == NetworkGUIState.Information; + _sysList.Visible = _state == NetworkGUIState.Listing; + + if (_sysList.Visible) + { + _sysList.X = 15; + _sysList.Y = _subtitle.Y + _subtitle.Height + 10; + _sysList.Width = this.Width - 30; + _sysList.Height = (Height - _sysList.Y - 15); + + _title.Text = "Network"; + _subtitle.Text = "Select a Digital Society system below to view information about it."; + + } + if (_current != null) + { + _title.Text = _current.Data.SystemName; + _subtitle.Text = _current.Data.FriendlyName; + if(_state == NetworkGUIState.Information) + { + _description.Visible = true; + _description.AutoSize = false; + _description.X = _sysList.X; + _description.Y = _sysList.Y; + _description.Width = _sysList.Width; + _description.Height = _sysList.Height - 50; + _description.Text = $@"System type: {_current.Data.SystemType} +Loot rarity: {_current.Data.LootRarity} + +{_current.Data.Description}"; + + _connect.Visible = true; + _connect.X = Width - _connect.Width - 15; + _connect.Y = _description.Y + _description.Height + 15; + + + } + } + base.OnLayout(gameTime); + } + + public class PortView : Control + { + private Port _port = null; + private Button _start = new Button(); + + public PortView(Port port) + { + _port = port; + _start.AutoSize = true; + _start.Text = "Connect"; + _start.Click += () => + { + ConnectionStarted?.Invoke(port); + }; + AddControl(_start); + } + + private bool unlocked = false; + + protected override void OnLayout(GameTime gameTime) + { + _start.Y = (Height - _start.Height) / 2; + _start.X = (Width - _start.Width) - 15; + unlocked = _port.Locks.Count > 0; + base.OnLayout(gameTime); + } + + protected override void OnPaint(GraphicsContext gfx) + { + gfx.Clear(LoadedSkin.ControlTextColor.ToMonoColor()); + gfx.DrawRectangle(1, 1, Width - 2, Height - 2, LoadedSkin.ControlColor.ToMonoColor()); + gfx.DrawString(_port.Name + " (" + _port.Value + ")", 15, 15, LoadedSkin.ControlTextColor.ToMonoColor(), LoadedSkin.Header3Font); + string _status = "Tier: " + _port.Tier.ToString(); + string lockstatus = (unlocked == true) ? "Unlocked" : $"{_port.Locks.Count} locks"; + _status += " - " + lockstatus; + gfx.DrawString(_status, 15, 15 + LoadedSkin.Header3Font.Height + 5, LoadedSkin.ControlTextColor.ToMonoColor(), LoadedSkin.MainFont); + } + + public event Action ConnectionStarted; + } + + public enum NetworkGUIState + { + Listing, + Information, + PortsList, + } + } +} diff --git a/ShiftOS.Frontend/Commands.cs b/ShiftOS.Frontend/Commands.cs index f3f81aa..1bf2d14 100644 --- a/ShiftOS.Frontend/Commands.cs +++ b/ShiftOS.Frontend/Commands.cs @@ -120,7 +120,8 @@ namespace ShiftOS.Frontend [Command("shutdown", description = "{DESC_SHUTDOWN}")] public static bool Shutdown() { - SaveSystem.SaveGame(); + if(Objects.ShiftFS.Utils.Mounts.Count > 0) + SaveSystem.SaveGame(); AppearanceManager.Exit(); return true; } diff --git a/ShiftOS.Frontend/GraphicsSubsystem/GraphicsContext.cs b/ShiftOS.Frontend/GraphicsSubsystem/GraphicsContext.cs index e75b00d..d8e447c 100644 --- a/ShiftOS.Frontend/GraphicsSubsystem/GraphicsContext.cs +++ b/ShiftOS.Frontend/GraphicsSubsystem/GraphicsContext.cs @@ -105,22 +105,16 @@ namespace ShiftOS.Frontend.GraphicsSubsystem { x += _startx; y += _starty; - var tex2 = new Texture2D(_graphicsDevice, 1, 1, false, SurfaceFormat.Color); - byte[] colordata = new byte[] { color.B, color.G, color.R, color.A }; - tex2.SetData(colordata); int distance = (int)Vector2.Distance(new Vector2(x, y), new Vector2(x1, y1)); float rotation = getRotation(x, y, x1, y1); - _spritebatch.Draw(tex2, new Rectangle(x, y, distance, thickness), null, color, rotation, Vector2.Zero, SpriteEffects.None, 0); + _spritebatch.Draw(UIManager.SkinTextures["PureWhite"], new Rectangle(x, y, distance, thickness), null, color, rotation, Vector2.Zero, SpriteEffects.None, 0); } public void DrawRectangle(int x, int y, int width, int height, Color color) { x += _startx; y += _starty; - var tex2 = new Texture2D(_graphicsDevice, 1, 1, false, SurfaceFormat.Color); - byte[] colordata = new byte[] { 255, 255, 255, 255 }; - tex2.SetData(colordata); - _spritebatch.Draw(tex2, new Rectangle(x, y, width, height), color); + _spritebatch.Draw(UIManager.SkinTextures["PureWhite"], new Rectangle(x, y, width, height), color); } public void DrawRectangle(int x, int y, int width, int height, Texture2D tex2) diff --git a/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs b/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs index 96ef3cb..43762cf 100644 --- a/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs +++ b/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs @@ -233,7 +233,9 @@ namespace ShiftOS.Frontend.GraphicsSubsystem SkinTextures.Add(colorfield.Name, tex2); } - + var pureWhite = new Texture2D(graphics, 1, 1); + pureWhite.SetData(new byte[] { 255, 255, 255, 255 }); + SkinTextures.Add("PureWhite", pureWhite); } diff --git a/ShiftOS.Frontend/MainMenu.cs b/ShiftOS.Frontend/MainMenu.cs index 12fb033..a6d987f 100644 --- a/ShiftOS.Frontend/MainMenu.cs +++ b/ShiftOS.Frontend/MainMenu.cs @@ -23,6 +23,8 @@ namespace ShiftOS.Frontend private TextControl _resDisplay = new TextControl(); private Button _optionsSave = new Button(); private CheckBox _fullscreen = new CheckBox(); + private Button _close = new Button(); + public MainMenu() { @@ -170,6 +172,7 @@ namespace ShiftOS.Frontend SaveOptions(); _menuTitle.Text = "Main Menu"; _campaign.Visible = true; + _close.Visible = true; _sandbox.Visible = true; _options.Visible = true; } @@ -182,6 +185,19 @@ namespace ShiftOS.Frontend _resIndex = _screenResolutions.Count - 1; } _fullscreen.Y = _sandbox.Y; + + _close.X = 30; + _close.Font = _campaign.Font; + _close.Y = _options.Y + _options.Font.Height + 15; + _close.Text = "Close"; + _close.Height = _campaign.Height; + _close.Width = _campaign.Width; + AddControl(_close); + _close.Click += () => + { + SaveSystem.IsSandbox = true; + ShiftOSCommands.Shutdown(); + }; } public void SaveOptions() @@ -199,6 +215,7 @@ namespace ShiftOS.Frontend _campaign.Visible = false; _sandbox.Visible = false; _options.Visible = false; + _close.Visible = false; var res = _screenResolutions[_resIndex]; _resDisplay.Text = $"{res.Width}x{res.Height}"; diff --git a/ShiftOS.Frontend/ShiftOS.Frontend.csproj b/ShiftOS.Frontend/ShiftOS.Frontend.csproj index 4e739f9..5d05320 100644 --- a/ShiftOS.Frontend/ShiftOS.Frontend.csproj +++ b/ShiftOS.Frontend/ShiftOS.Frontend.csproj @@ -44,6 +44,7 @@ + diff --git a/ShiftOS.Objects/Hackable.cs b/ShiftOS.Objects/Hackable.cs index 309ce87..4596d2d 100644 --- a/ShiftOS.Objects/Hackable.cs +++ b/ShiftOS.Objects/Hackable.cs @@ -14,10 +14,13 @@ namespace ShiftOS.Objects public string PasswordHint { get; set; } public string WelcomeMessage { get; set; } + public string Description { get; set; } + public int FirewallStrength { get; set; } public int LootRarity { get; set; } public int LootAmount { get; set; } public int ConnectionTimeoutLevel { get; set; } + public int LockTier { get; set; } public SystemType SystemType { get; set; } @@ -34,6 +37,11 @@ namespace ShiftOS.Objects return SystemName.ToLower().Replace(" ", "_"); } } + + public override string ToString() + { + return $"{FriendlyName} ({SystemName})"; + } } [Flags] diff --git a/ShiftOS_TheReturn/Hacking.cs b/ShiftOS_TheReturn/Hacking.cs index ea2d89b..8eb34b4 100644 --- a/ShiftOS_TheReturn/Hacking.cs +++ b/ShiftOS_TheReturn/Hacking.cs @@ -74,29 +74,66 @@ namespace ShiftOS.Engine { Value = 25, Name = "SMTP mailserver (unencrypted)", + Tier = hsys.Data.LockTier, + Locks = GetLocks(hsys.Data.LockTier, hsys.Data.FirewallStrength), }); if (data.SystemType.HasFlag(Objects.SystemType.FileServer)) hsys.PortsToUnlock.Add(new Port { Value = 22, Name = "File Transfer Protocol", + Tier = hsys.Data.LockTier, + Locks = GetLocks(hsys.Data.LockTier, hsys.Data.FirewallStrength), }); if (data.SystemType.HasFlag(Objects.SystemType.SSHServer)) hsys.PortsToUnlock.Add(new Port { Value = 21, Name = "ShiftSSH server", + Tier = hsys.Data.LockTier, + Locks = GetLocks(hsys.Data.LockTier, hsys.Data.FirewallStrength), }); if (data.SystemType.HasFlag(Objects.SystemType.Database)) hsys.PortsToUnlock.Add(new Port { Value = 3306, Name = "MySQL database", + Tier = hsys.Data.LockTier, + Locks = GetLocks(hsys.Data.LockTier, hsys.Data.FirewallStrength), }); CurrentHackable = hsys; } + public static List GetLocks(int tier, int fwallstrength) + { + var locks = new List(); + var lckTypes = new List(); + foreach(var lck in ReflectMan.Types.Where(x=>x.BaseType == typeof(PortLock))) + { + var lckAttrib = lck.GetCustomAttributes(false).FirstOrDefault(x => x is LockAttribute) as LockAttribute; + if(lckAttrib != null) + { + if(lckAttrib.Tier == tier) + { + lckTypes.Add(lck); + } + } + } + if (lckTypes.Count > 0) + { + var rnd = new Random(); + for (int i = 0; i < fwallstrength; i++) + { + int _typeindex = rnd.Next(lckTypes.Count); + var type = (PortLock)Activator.CreateInstance(lckTypes[_typeindex], lckTypes[_typeindex].GetCustomAttributes(false).FirstOrDefault(x => x is LockAttribute)); + lckTypes.RemoveAt(_typeindex); + locks.Add(type); + } + } + return locks; + } + public static void FailHack() { if (CurrentHackable == null) @@ -180,5 +217,34 @@ namespace ShiftOS.Engine { public string Name { get; set; } public int Value { get; set; } + public int Tier { get; set; } + public List Locks { get; set; } //not a hackmud thing i promise + } + + public abstract class PortLock + { + public PortLock(LockAttribute attrib) + { + Attribute = attrib; + } + + public LockAttribute Attribute { get; private set; } + + public abstract bool Evaluate(Dictionary args); + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple =false)] + public class LockAttribute : Attribute + { + public LockAttribute(string name, string company, int tier) + { + Name = name; + Company = company; + Tier = tier; + } + + public int Tier { get; private set; } + public string Name { get; private set; } + public string Company { get; private set; } } }