From 1cf621d9f63dbfc1d76f38eed5d76729499b7879 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Fri, 6 Apr 2018 08:24:54 +1000 Subject: [PATCH] Redo setting inventory order to make more sense --- ClassicalSharp/2D/GuiElement.cs | 42 +++++- .../2D/Screens/Menu/ClickableScreen.cs | 27 +++- .../2D/Screens/Menu/EditHotkeyScreen.cs | 42 +++--- .../2D/Screens/Menu/SaveLevelScreen.cs | 1 - ClassicalSharp/2D/Screens/Screen.cs | 58 -------- ClassicalSharp/2D/Widgets/TableWidget.cs | 30 +++- ClassicalSharp/2D/Widgets/Widget.cs | 56 ------- ClassicalSharp/ClassicalSharp.csproj | 4 +- ClassicalSharp/Game/GuiInterface.cs | 1 + ClassicalSharp/Game/InputHandler.cs | 1 + ClassicalSharp/Game/Inventory.cs | 116 ++++----------- ClassicalSharp/Mode/Creative.cs | 1 + ClassicalSharp/Mode/IGameMode.cs | 2 +- ClassicalSharp/Mode/Survival.cs | 1 + ClassicalSharp/Network/Protocols/BlockDefs.cs | 2 +- ClassicalSharp/Network/Protocols/CPE.cs | 4 +- ClassicalSharp/Network/Protocols/Classic.cs | 1 + ClassicalSharp/Program.cs | 1 + src/Client/Inventory.c | 139 +++++------------- src/Client/Menus.c | 113 +++++++++++++- src/Client/Widgets.c | 1 + 21 files changed, 294 insertions(+), 349 deletions(-) delete mode 100644 ClassicalSharp/2D/Screens/Screen.cs delete mode 100644 ClassicalSharp/2D/Widgets/Widget.cs diff --git a/ClassicalSharp/2D/GuiElement.cs b/ClassicalSharp/2D/GuiElement.cs index 672366bc8..6504f21de 100644 --- a/ClassicalSharp/2D/GuiElement.cs +++ b/ClassicalSharp/2D/GuiElement.cs @@ -1,7 +1,6 @@ // Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; -using ClassicalSharp.Gui.Widgets; -using ClassicalSharp.GraphicsAPI; +using System.Drawing; using OpenTK.Input; namespace ClassicalSharp.Gui { @@ -10,10 +9,7 @@ namespace ClassicalSharp.Gui { public abstract class GuiElement : IDisposable { protected Game game; - - public GuiElement(Game game) { - this.game = game; - } + public GuiElement(Game game) { this.game = game; } public abstract void Init(); @@ -49,4 +45,38 @@ namespace ClassicalSharp.Gui { return x >= recX && y >= recY && x < recX + width && y < recY + height; } } + + /// Represents a container of widgets and other 2D elements. + /// May cover the entire game window. + public abstract class Screen : GuiElement { + + public Screen(Game game) : base(game) { } + + public bool HandlesAllInput, BlocksWorld, HidesHud, RenderHudOver; + + public abstract void OnResize(int width, int height); + + protected abstract void ContextLost(); + + protected abstract void ContextRecreated(); + } + + /// Represents an individual 2D gui component. + public abstract class Widget : GuiElement { + + public Widget(Game game) : base(game) { } + + public ClickHandler MenuClick; + public bool Active, Disabled; + public int X, Y, Width, Height; + public Anchor HorizontalAnchor, VerticalAnchor; + public int XOffset, YOffset; + + public Rectangle Bounds { get { return new Rectangle(X, Y, Width, Height); } } + + public virtual void Reposition() { + X = CalcPos(HorizontalAnchor, XOffset, Width, game.Width); + Y = CalcPos(VerticalAnchor, YOffset, Height, game.Height); + } + } } diff --git a/ClassicalSharp/2D/Screens/Menu/ClickableScreen.cs b/ClassicalSharp/2D/Screens/Menu/ClickableScreen.cs index 07bed53a5..5548109e1 100644 --- a/ClassicalSharp/2D/Screens/Menu/ClickableScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/ClickableScreen.cs @@ -52,7 +52,7 @@ namespace ClassicalSharp.Gui.Screens { } return -1; } - + protected ButtonWidget MakeBack(bool toGame, Font font, ClickHandler onClick) { int width = game.UseClassicOptions ? 400 : 200; return MakeBack(width, toGame ? "Back to game" : "Cancel", 25, font, onClick); @@ -65,5 +65,30 @@ namespace ClassicalSharp.Gui.Screens { protected static void SwitchOptions(Game g, Widget w) { g.Gui.SetNewScreen(new OptionsGroupScreen(g)); } protected static void SwitchPause(Game g, Widget w) { g.Gui.SetNewScreen(new PauseScreen(g)); } + + + protected static void DisposeWidgets(T[] widgets) where T : Widget { + if (widgets == null) return; + + for (int i = 0; i < widgets.Length; i++) { + if (widgets[i] != null) widgets[i].Dispose(); + } + } + + protected static void RepositionWidgets(T[] widgets) where T : Widget { + if (widgets == null) return; + + for (int i = 0; i < widgets.Length; i++) { + if (widgets[i] != null) widgets[i].Reposition(); + } + } + + protected static void RenderWidgets(T[] widgets, double delta) where T : Widget { + if (widgets == null) return; + + for (int i = 0; i < widgets.Length; i++) { + if (widgets[i] != null) widgets[i].Render(delta); + } + } } } \ No newline at end of file diff --git a/ClassicalSharp/2D/Screens/Menu/EditHotkeyScreen.cs b/ClassicalSharp/2D/Screens/Menu/EditHotkeyScreen.cs index 8853c7e1b..feb275a6d 100644 --- a/ClassicalSharp/2D/Screens/Menu/EditHotkeyScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/EditHotkeyScreen.cs @@ -12,7 +12,7 @@ namespace ClassicalSharp.Gui.Screens { const int keyI = 0, modifyI = 1, actionI = 2; HotkeyList hotkeys; Hotkey curHotkey, origHotkey; - Widget focusWidget; + int selectedI = -1; static FastColour grey = new FastColour(150, 150, 150); public EditHotkeyScreen(Game game, Hotkey original) : base(game) { @@ -41,7 +41,7 @@ namespace ClassicalSharp.Gui.Screens { if (key == Key.Escape) { game.Gui.SetNewScreen(null); return true; - } else if (focusWidget != null) { + } else if (selectedI >= 0) { FocusKeyDown(key); return true; } @@ -84,7 +84,7 @@ namespace ClassicalSharp.Gui.Screens { public override void Dispose() { game.Keyboard.KeyRepeat = false; - focusWidget = null; + selectedI = -1; base.Dispose(); } @@ -98,7 +98,7 @@ namespace ClassicalSharp.Gui.Screens { curHotkey.StaysOpen = !curHotkey.StaysOpen; string staysOpen = curHotkey.StaysOpen ? "ON" : "OFF"; staysOpen = "Input stays open: " + staysOpen; - SetButton(widgets[3], staysOpen); + SetButton(3, staysOpen); } void SaveChangesClick(Game game, Widget widget) { @@ -126,50 +126,50 @@ namespace ClassicalSharp.Gui.Screens { } void BaseKeyClick(Game game, Widget widget) { - focusWidget = widgets[keyI]; - SetButton(widgets[keyI], "Key: press a key.."); + selectedI = keyI; + SetButton(keyI, "Key: press a key.."); supressNextPress = true; } void ModifiersClick(Game game, Widget widget) { - focusWidget = widgets[modifyI]; - SetButton(widgets[modifyI], "Modifiers: press a key.."); + selectedI = modifyI; + SetButton(modifyI, "Modifiers: press a key.."); supressNextPress = true; } void FocusKeyDown(Key key) { - if (focusWidget == widgets[keyI]) { + if (selectedI == keyI) { curHotkey.BaseKey = key; - SetButton(widgets[keyI], "Key: " + curHotkey.BaseKey); + SetButton(keyI, "Key: " + curHotkey.BaseKey); supressNextPress = true; - } else if (focusWidget == widgets[modifyI]) { + } else if (selectedI == modifyI) { if (key == Key.ControlLeft || key == Key.ControlRight) curHotkey.Flags |= 1; else if (key == Key.ShiftLeft || key == Key.ShiftRight) curHotkey.Flags |= 2; else if (key == Key.AltLeft || key == Key.AltRight) curHotkey.Flags |= 4; else curHotkey.Flags = 0; string flags = HotkeyListScreen.MakeFlagsString(curHotkey.Flags); - SetButton(widgets[modifyI], "Modifiers:" + flags); + SetButton(modifyI, "Modifiers:" + flags); supressNextPress = true; } - focusWidget = null; + selectedI = -1; } void LostFocus() { - if (focusWidget == null) return; + if (selectedI == -1) return; - if (focusWidget == widgets[keyI]) { - SetButton(widgets[keyI], "Key: " + curHotkey.BaseKey); - } else if (focusWidget == widgets[modifyI]) { + if (selectedI == keyI) { + SetButton(keyI, "Key: " + curHotkey.BaseKey); + } else if (selectedI == modifyI) { string flags = HotkeyListScreen.MakeFlagsString(curHotkey.Flags); - SetButton(widgets[modifyI], "Modifiers:" + flags); + SetButton(modifyI, "Modifiers:" + flags); } - focusWidget = null; + selectedI = -1; supressNextPress = false; } - void SetButton(Widget widget, string text) { - ((ButtonWidget)widget).SetText(text); + void SetButton(int i, string text) { + ((ButtonWidget)widgets[i]).SetText(text); } } } diff --git a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs index 3c77eee1d..65b3eca27 100644 --- a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs @@ -58,7 +58,6 @@ namespace ClassicalSharp.Gui.Screens { } protected override void ContextLost() { - input.Dispose(); DisposeDescWidget(); base.ContextLost(); } diff --git a/ClassicalSharp/2D/Screens/Screen.cs b/ClassicalSharp/2D/Screens/Screen.cs deleted file mode 100644 index 21f49bbc5..000000000 --- a/ClassicalSharp/2D/Screens/Screen.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 -using System; -using ClassicalSharp.Gui.Widgets; -using OpenTK.Input; - -namespace ClassicalSharp.Gui.Screens { - /// Represents a container of widgets and other 2D elements. - /// May cover the entire game window. - public abstract class Screen : GuiElement { - - public Screen(Game game) : base(game) { - } - - /// Whether this screen handles all mouse and keyboard input. - /// This prevents the client from interacting with the world. - public bool HandlesAllInput; - - /// Whether this screen completely and opaquely covers the game world behind it. - public bool BlocksWorld; - - /// Whether this screen hides the normal in-game hud. - public bool HidesHud; - - /// Whether the normal in-game hud should be drawn over the top of this screen. - public bool RenderHudOver; - - /// Called when the game window is resized. - public abstract void OnResize(int width, int height); - - protected abstract void ContextLost(); - - protected abstract void ContextRecreated(); - - protected static void DisposeWidgets(T[] widgets) where T : Widget { - if (widgets == null) return; - - for (int i = 0; i < widgets.Length; i++) { - if (widgets[i] != null) widgets[i].Dispose(); - } - } - - protected static void RepositionWidgets(T[] widgets) where T : Widget { - if (widgets == null) return; - - for (int i = 0; i < widgets.Length; i++) { - if (widgets[i] != null) widgets[i].Reposition(); - } - } - - protected static void RenderWidgets(T[] widgets, double delta) where T : Widget { - if (widgets == null) return; - - for (int i = 0; i < widgets.Length; i++) { - if (widgets[i] != null) widgets[i].Render(delta); - } - } - } -} \ No newline at end of file diff --git a/ClassicalSharp/2D/Widgets/TableWidget.cs b/ClassicalSharp/2D/Widgets/TableWidget.cs index 9ce40e657..e78f0fd4c 100644 --- a/ClassicalSharp/2D/Widgets/TableWidget.cs +++ b/ClassicalSharp/2D/Widgets/TableWidget.cs @@ -206,6 +206,7 @@ namespace ClassicalSharp.Gui.Widgets { public void MakeDescTex(BlockID block) { game.Graphics.DeleteTexture(ref descTex); + if (block == Block.Air) return; UpdateBlockInfoString(block); string value = buffer.ToString(); @@ -218,8 +219,13 @@ namespace ClassicalSharp.Gui.Widgets { int totalElements = 0; BlockID[] map = game.Inventory.Map; - for (int i = 0; i < map.Length; i++) { + for (int i = 0; i < map.Length;) { + if ((i % ElementsPerRow) == 0 && RowEmpty(i)) { + i += ElementsPerRow; continue; + } + if (Show(map[i])) { totalElements++; } + i++; } totalRows = Utils.CeilDiv(totalElements, ElementsPerRow); @@ -228,13 +234,28 @@ namespace ClassicalSharp.Gui.Widgets { Elements = new BlockID[totalElements]; int index = 0; - for (int i = 0; i < map.Length; i++) { + for (int i = 0; i < map.Length;) { + if ((i % ElementsPerRow) == 0 && RowEmpty(i)) { + i += ElementsPerRow; continue; + } + if (Show(map[i])) { Elements[index++] = map[i]; } + i++; } } + bool RowEmpty(int i) { + BlockID[] map = game.Inventory.Map; + int max = Math.Min(i + ElementsPerRow, map.Length); + + for (int j = i; j < max; j++) { + if (map[j] != Block.Air) return false; + } + return true; + } + bool Show(BlockID block) { - if (block == Block.Air) return false; + //if (block == Block.Air) return false; if (block < Block.CpeCount) { int count = game.SupportsCPEBlocks ? Block.CpeCount : Block.OriginalCount; @@ -271,7 +292,7 @@ namespace ClassicalSharp.Gui.Widgets { if (scroll.HandlesMouseDown(mouseX, mouseY, button)) { return true; - } else if (SelectedIndex != -1) { + } else if (SelectedIndex != -1 && Elements[SelectedIndex] != Block.Air) { game.Inventory.Selected = Elements[SelectedIndex]; PendingClose = true; return true; @@ -300,6 +321,7 @@ namespace ClassicalSharp.Gui.Widgets { void ScrollRelative(int delta) { int startIndex = SelectedIndex; + SelectedIndex += delta; if (SelectedIndex < 0) SelectedIndex -= delta; if (SelectedIndex >= Elements.Length) SelectedIndex -= delta; diff --git a/ClassicalSharp/2D/Widgets/Widget.cs b/ClassicalSharp/2D/Widgets/Widget.cs deleted file mode 100644 index 876e98a33..000000000 --- a/ClassicalSharp/2D/Widgets/Widget.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 -using System; -using System.Drawing; -using OpenTK.Input; - -namespace ClassicalSharp.Gui.Widgets { - /// Represents an individual 2D gui component. - public abstract class Widget : GuiElement { - - public Widget(Game game) : base(game) { - HorizontalAnchor = Anchor.Min; - VerticalAnchor = Anchor.Min; - } - - /// Whether this widget is currently being moused over. - public bool Active; - - /// Whether this widget is prevented from being interacted with. - public bool Disabled; - - /// Invoked when this widget is clicked on. Can be null. - public ClickHandler MenuClick; - - /// Horizontal coordinate of top left corner in pixels. - public int X; - - /// Vertical coordinate of top left corner in pixels. - public int Y; - - /// Horizontal length of widget's bounds in pixels. - public int Width; - - /// Vertical length of widget's bounds in pixels. - public int Height; - - /// Specifies the horizontal reference point for when the widget is resized. - public Anchor HorizontalAnchor; - - /// Specifies the vertical reference point for when the widget is resized. - public Anchor VerticalAnchor; - - /// Horizontal offset from the reference point in pixels. - public int XOffset; - - /// Vertical offset from the reference point in pixels. - public int YOffset; - - /// Specifies the boundaries of the widget in pixels. - public Rectangle Bounds { get { return new Rectangle(X, Y, Width, Height); } } - - public virtual void Reposition() { - X = CalcPos(HorizontalAnchor, XOffset, Width, game.Width); - Y = CalcPos(VerticalAnchor, YOffset, Height, game.Height); - } - } -} diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index 298010514..3ec25f2c4 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -4,7 +4,7 @@ {BEB1C785-5CAD-48FF-A886-876BF0A318D4} Debug AnyCPU - WinExe + Exe ClassicalSharp ClassicalSharp v2.0 @@ -114,7 +114,6 @@ - @@ -132,7 +131,6 @@ - diff --git a/ClassicalSharp/Game/GuiInterface.cs b/ClassicalSharp/Game/GuiInterface.cs index f41b0c0db..4386feecb 100644 --- a/ClassicalSharp/Game/GuiInterface.cs +++ b/ClassicalSharp/Game/GuiInterface.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using ClassicalSharp.Events; using ClassicalSharp.GraphicsAPI; +using ClassicalSharp.Gui; using ClassicalSharp.Gui.Screens; using ClassicalSharp.Renderers; diff --git a/ClassicalSharp/Game/InputHandler.cs b/ClassicalSharp/Game/InputHandler.cs index dc81f58d8..ac3e02d8e 100644 --- a/ClassicalSharp/Game/InputHandler.cs +++ b/ClassicalSharp/Game/InputHandler.cs @@ -1,6 +1,7 @@ // Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; using ClassicalSharp.Entities; +using ClassicalSharp.Gui; using ClassicalSharp.Gui.Screens; using ClassicalSharp.Hotkeys; using OpenTK; diff --git a/ClassicalSharp/Game/Inventory.cs b/ClassicalSharp/Game/Inventory.cs index a0744d90c..9f90a8601 100644 --- a/ClassicalSharp/Game/Inventory.cs +++ b/ClassicalSharp/Game/Inventory.cs @@ -92,78 +92,46 @@ namespace ClassicalSharp { public BlockID[] Map; public void SetDefaultMapping() { - for (int i = 0; i < Map.Length; i++) Map[i] = (BlockID)i; for (int i = 0; i < Map.Length; i++) { - BlockID mapping = DefaultMapping(i); - if (game.PureClassic && IsHackBlock(mapping)) mapping = Block.Air; - if (mapping != i) Map[i] = mapping; + Map[i] = DefaultMapping(i); } } - BlockID DefaultMapping(int i) { - if (i >= Block.CpeCount || i == Block.Air) return Block.Air; - if (!game.ClassicMode) return (BlockID)i; - - if (i >= 25 && i <= 40) { - return (BlockID)(Block.Red + (i - 25)); - } - if (i >= 18 && i <= 21) { - return (BlockID)(Block.Dandelion + (i - 18)); - } - - switch (i) { - // First row - case 3: return Block.Cobblestone; - case 4: return Block.Brick; - case 5: return Block.Dirt; - case 6: return Block.Wood; - - // Second row - case 12: return Block.Log; - case 13: return Block.Leaves; - case 14: return Block.Glass; - case 15: return Block.Slab; - case 16: return Block.MossyRocks; - case 17: return Block.Sapling; - - // Third row - case 22: return Block.Sand; - case 23: return Block.Gravel; - case 24: return Block.Sponge; - - // Fifth row - case 41: return Block.CoalOre; - case 42: return Block.IronOre; - case 43: return Block.GoldOre; - case 44: return Block.DoubleSlab; - case 45: return Block.Iron; - case 46: return Block.Gold; - case 47: return Block.Bookshelf; - case 48: return Block.TNT; - } - return (BlockID)i; - } + static BlockID[] classicTable = new BlockID[] { + Block.Stone, Block.Cobblestone, Block.Brick, Block.Dirt, Block.Wood, Block.Log, Block.Leaves, Block.Glass, Block.Slab, + Block.MossyRocks, Block.Sapling, Block.Dandelion, Block.Rose, Block.BrownMushroom, Block.RedMushroom, Block.Sand, Block.Gravel, Block.Sponge, + Block.Red, Block.Orange, Block.Yellow, Block.Lime, Block.Green, Block.Teal, Block.Aqua, Block.Cyan, Block.Blue, + Block.Indigo, Block.Violet, Block.Magenta, Block.Pink, Block.Black, Block.Gray, Block.White, Block.CoalOre, Block.IronOre, + Block.GoldOre, Block.Iron, Block.Gold, Block.Bookshelf, Block.TNT, Block.Obsidian, + }; + static BlockID[] classicHacksTable = new BlockID[] { + Block.Stone, Block.Grass, Block.Cobblestone, Block.Brick, Block.Dirt, Block.Wood, Block.Bedrock, Block.Water, Block.StillWater, Block.Lava, + Block.StillLava, Block.Log, Block.Leaves, Block.Glass, Block.Slab, Block.MossyRocks, Block.Sapling, Block.Dandelion, Block.Rose, Block.BrownMushroom, + Block.RedMushroom, Block.Sand, Block.Gravel, Block.Sponge, Block.Red, Block.Orange, Block.Yellow, Block.Lime, Block.Green, Block.Teal, + Block.Aqua, Block.Cyan, Block.Blue, Block.Indigo, Block.Violet, Block.Magenta, Block.Pink, Block.Black, Block.Gray, Block.White, + Block.CoalOre, Block.IronOre, Block.GoldOre, Block.DoubleSlab, Block.Iron, Block.Gold, Block.Bookshelf, Block.TNT, Block.Obsidian, + }; - static bool IsHackBlock(BlockID b) { - return b == Block.DoubleSlab || b == Block.Bedrock || - b == Block.Grass || BlockInfo.IsLiquid[b]; + BlockID DefaultMapping(int slot) { + if (game.PureClassic) { + if (slot < 9 * 4 + 6) return classicTable[slot]; + } else if (game.ClassicMode) { + if (slot < 10 * 4 + 9) return classicHacksTable[slot]; + } else if (slot < Block.MaxCpeBlock) { + return (BlockID)(slot + 1); + } + return Block.Air; } public void AddDefault(BlockID block) { - if (block >= Block.CpeCount || DefaultMapping(block) == block) { - Map[block] = block; - return; + if (block >= Block.CpeCount) { + Map[block - 1] = block; return; } - for (int i = 0; i < Block.CpeCount; i++) { - if (DefaultMapping(i) != block) continue; - Map[i] = block; return; - } - } - - public void Reset(BlockID block) { - for (int i = 0; i < Map.Length; i++) { - if (Map[i] == block) Map[i] = DefaultMapping(i); + for (int slot = 0; slot < Block.MaxCpeBlock; slot++) { + if (DefaultMapping(slot) != block) continue; + Map[slot] = block; + return; } } @@ -172,29 +140,5 @@ namespace ClassicalSharp { if (Map[i] == block) Map[i] = Block.Air; } } - - public void Insert(int i, BlockID block) { - if (Map[i] == block) return; - // Need to push the old block to a different slot if different block - if (Map[i] != Block.Air) PushToFreeSlots(i); - - Map[i] = block; - } - - void PushToFreeSlots(int i) { - BlockID block = Map[i]; - // The slot was already pushed out in the past - // TODO: find a better way of fixing this - for (int j = 1; j < Map.Length; j++) { - if (j != i && Map[j] == block) return; - } - - for (int j = block; j < Map.Length; j++) { - if (Map[j] == Block.Air) { Map[j] = block; return; } - } - for (int j = 1; j < block; j++) { - if (Map[j] == Block.Air) { Map[j] = block; return; } - } - } } } diff --git a/ClassicalSharp/Mode/Creative.cs b/ClassicalSharp/Mode/Creative.cs index 6c3cc0b30..35cc59cdf 100644 --- a/ClassicalSharp/Mode/Creative.cs +++ b/ClassicalSharp/Mode/Creative.cs @@ -1,6 +1,7 @@ // Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; using ClassicalSharp.Gui.Screens; +using ClassicalSharp.Gui; using ClassicalSharp.Gui.Widgets; using OpenTK.Input; using BlockID = System.UInt16; diff --git a/ClassicalSharp/Mode/IGameMode.cs b/ClassicalSharp/Mode/IGameMode.cs index 21fd42f39..6c3dfcef9 100644 --- a/ClassicalSharp/Mode/IGameMode.cs +++ b/ClassicalSharp/Mode/IGameMode.cs @@ -1,6 +1,6 @@ // Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; -using ClassicalSharp.Gui.Widgets; +using ClassicalSharp.Gui; using OpenTK.Input; using BlockID = System.UInt16; diff --git a/ClassicalSharp/Mode/Survival.cs b/ClassicalSharp/Mode/Survival.cs index 193a2c42c..f293811b7 100644 --- a/ClassicalSharp/Mode/Survival.cs +++ b/ClassicalSharp/Mode/Survival.cs @@ -2,6 +2,7 @@ using System; using ClassicalSharp.Entities; using ClassicalSharp.Entities.Mobs; +using ClassicalSharp.Gui; using ClassicalSharp.Gui.Screens; using ClassicalSharp.Gui.Widgets; using OpenTK; diff --git a/ClassicalSharp/Network/Protocols/BlockDefs.cs b/ClassicalSharp/Network/Protocols/BlockDefs.cs index 93cf3e8b0..188b4e654 100644 --- a/ClassicalSharp/Network/Protocols/BlockDefs.cs +++ b/ClassicalSharp/Network/Protocols/BlockDefs.cs @@ -43,7 +43,7 @@ namespace ClassicalSharp.Network.Protocols { OnBlockUpdated(block, didBlockLight); BlockInfo.UpdateCulling(block); - game.Inventory.Reset(block); + game.Inventory.Remove(block); if (block < Block.CpeCount) { game.Inventory.AddDefault(block); } diff --git a/ClassicalSharp/Network/Protocols/CPE.cs b/ClassicalSharp/Network/Protocols/CPE.cs index 376a97454..0a8c07ff9 100644 --- a/ClassicalSharp/Network/Protocols/CPE.cs +++ b/ClassicalSharp/Network/Protocols/CPE.cs @@ -406,8 +406,8 @@ namespace ClassicalSharp.Network.Protocols { BlockID order = reader.ReadBlock(); game.Inventory.Remove(block); - if (order != 255) { - game.Inventory.Insert(order, block); + if (order != 255 && order != 0) { + game.Inventory.Map[order - 1] = block; } } diff --git a/ClassicalSharp/Network/Protocols/Classic.cs b/ClassicalSharp/Network/Protocols/Classic.cs index 1a0cb1e15..6f6a4937f 100644 --- a/ClassicalSharp/Network/Protocols/Classic.cs +++ b/ClassicalSharp/Network/Protocols/Classic.cs @@ -1,5 +1,6 @@ // Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; +using ClassicalSharp.Gui; using ClassicalSharp.Gui.Screens; using ClassicalSharp.Entities; using OpenTK; diff --git a/ClassicalSharp/Program.cs b/ClassicalSharp/Program.cs index b1e703a6f..2416e0737 100644 --- a/ClassicalSharp/Program.cs +++ b/ClassicalSharp/Program.cs @@ -99,6 +99,7 @@ namespace ClassicalSharp { internal static void CleanupMainDirectory() { string mapPath = Path.Combine(Program.AppDirectory, "maps"); + Console.WriteLine(mapPath); if (!Directory.Exists(mapPath)) Directory.CreateDirectory(mapPath); diff --git a/src/Client/Inventory.c b/src/Client/Inventory.c index 3c086bf9d..0e91a0398 100644 --- a/src/Client/Inventory.c +++ b/src/Client/Inventory.c @@ -41,130 +41,59 @@ void Inventory_SetSelectedBlock(BlockID block) { Event_RaiseVoid(&UserEvents_HeldBlockChanged); } -bool Inventory_IsHackBlock(BlockID b) { - return b == BLOCK_DOUBLE_SLAB || b == BLOCK_BEDROCK || b == BLOCK_GRASS || Block_IsLiquid[b]; -} +BlockID inv_classicTable[] = { + BLOCK_STONE, BLOCK_COBBLE, BLOCK_BRICK, BLOCK_DIRT, BLOCK_WOOD, BLOCK_LOG, BLOCK_LEAVES, BLOCK_GLASS, BLOCK_SLAB, + BLOCK_MOSSY_ROCKS, BLOCK_SAPLING, BLOCK_DANDELION, BLOCK_ROSE, BLOCK_BROWN_SHROOM, BLOCK_RED_SHROOM, BLOCK_SAND, BLOCK_GRAVEL, BLOCK_SPONGE, + BLOCK_RED, BLOCK_ORANGE, BLOCK_YELLOW, BLOCK_LIME, BLOCK_GREEN, BLOCK_TEAL, BLOCK_AQUA, BLOCK_CYAN, BLOCK_BLUE, + BLOCK_INDIGO, BLOCK_VIOLET, BLOCK_MAGENTA, BLOCK_PINK, BLOCK_BLACK, BLOCK_GRAY, BLOCK_WHITE, BLOCK_COAL_ORE, BLOCK_IRON_ORE, + BLOCK_GOLD_ORE, BLOCK_IRON, BLOCK_GOLD, BLOCK_BOOKSHELF, BLOCK_TNT, BLOCK_OBSIDIAN, +}; +BlockID inv_classicHacksTable[] = { + BLOCK_STONE, BLOCK_GRASS, BLOCK_COBBLE, BLOCK_BRICK, BLOCK_DIRT, BLOCK_WOOD, BLOCK_BEDROCK, BLOCK_WATER, BLOCK_STILL_WATER, BLOCK_LAVA, + BLOCK_STILL_LAVA, BLOCK_LOG, BLOCK_LEAVES, BLOCK_GLASS, BLOCK_SLAB, BLOCK_MOSSY_ROCKS, BLOCK_SAPLING, BLOCK_DANDELION, BLOCK_ROSE, BLOCK_BROWN_SHROOM, + BLOCK_RED_SHROOM, BLOCK_SAND, BLOCK_GRAVEL, BLOCK_SPONGE, BLOCK_RED, BLOCK_ORANGE, BLOCK_YELLOW, BLOCK_LIME, BLOCK_GREEN, BLOCK_TEAL, + BLOCK_AQUA, BLOCK_CYAN, BLOCK_BLUE, BLOCK_INDIGO, BLOCK_VIOLET, BLOCK_MAGENTA, BLOCK_PINK, BLOCK_BLACK, BLOCK_GRAY, BLOCK_WHITE, + BLOCK_COAL_ORE, BLOCK_IRON_ORE, BLOCK_GOLD_ORE, BLOCK_DOUBLE_SLAB, BLOCK_IRON, BLOCK_GOLD, BLOCK_BOOKSHELF, BLOCK_TNT, BLOCK_OBSIDIAN, +}; -BlockID Inventory_DefaultMapping(Int32 i) { -#if USE16_BIT - if ((i >= Block_CpeCount && i < 256) || i == BLOCK_AIR) return BLOCK_AIR; -#else - if (i >= BLOCK_CPE_COUNT || i == BLOCK_AIR) return BLOCK_AIR; -#endif - if (!Game_ClassicMode) return (BlockID)i; - - if (i >= 25 && i <= 40) { - return (BlockID)(BLOCK_RED + (i - 25)); +BlockID Inventory_DefaultMapping(int slot) { + if (Game_PureClassic) { + if (slot < 9 * 4 + 6) return inv_classicTable[slot]; + } else if (Game_ClassicMode) { + if (slot < 10 * 4 + 9) return inv_classicHacksTable[slot]; + } else if (slot < BLOCK_MAX_CPE) { + return (BlockID)(slot + 1); } - if (i >= 18 && i <= 21) { - return (BlockID)(BLOCK_DANDELION + (i - 18)); - } - - switch (i) { - /* First row */ - case 3: return BLOCK_COBBLE; - case 4: return BLOCK_BRICK; - case 5: return BLOCK_DIRT; - case 6: return BLOCK_WOOD; - - /* Second row */ - case 12: return BLOCK_LOG; - case 13: return BLOCK_LEAVES; - case 14: return BLOCK_GLASS; - case 15: return BLOCK_SLAB; - case 16: return BLOCK_MOSSY_ROCKS; - case 17: return BLOCK_SAPLING; - - /* Third row */ - case 22: return BLOCK_SAND; - case 23: return BLOCK_GRAVEL; - case 24: return BLOCK_SPONGE; - - /* Fifth row */ - case 41: return BLOCK_COAL_ORE; - case 42: return BLOCK_IRON_ORE; - case 43: return BLOCK_GOLD_ORE; - case 44: return BLOCK_DOUBLE_SLAB; - case 45: return BLOCK_IRON; - case 46: return BLOCK_GOLD; - case 47: return BLOCK_BOOKSHELF; - case 48: return BLOCK_TNT; - } - return (BlockID)i; + return BLOCK_AIR; } void Inventory_SetDefaultMapping(void) { - Int32 i; - for (i = 0; i < Array_Elems(Inventory_Map); i++) { - Inventory_Map[i] = (BlockID)i; - } - for (i = 0; i < Array_Elems(Inventory_Map); i++) { - BlockID mapping = Inventory_DefaultMapping(i); - if (Game_PureClassic && Inventory_IsHackBlock(mapping)) { - mapping = BLOCK_AIR; - } - if (mapping != i) Inventory_Map[i] = mapping; + Int32 slot; + for (slot = 0; slot < Array_Elems(Inventory_Map); slot++) { + Inventory_Map[slot] = Inventory_DefaultMapping(slot); } } void Inventory_AddDefault(BlockID block) { - if (block >= BLOCK_CPE_COUNT || Inventory_DefaultMapping(block) == block) { - Inventory_Map[block] = block; - return; + if (block >= BLOCK_CPE_COUNT) { + Inventory_Map[block - 1] = block; return; } - Int32 i; - for (i = 0; i < BLOCK_CPE_COUNT; i++) { - if (Inventory_DefaultMapping(i) != block) continue; - Inventory_Map[i] = block; + Int32 slot; + for (slot = 0; slot < BLOCK_MAX_CPE; slot++) { + if (Inventory_DefaultMapping(slot) != block) continue; + Inventory_Map[slot] = block; return; } } -void Inventory_Reset(BlockID block) { - Int32 i; - for (i = 0; i < Array_Elems(Inventory_Map); i++) { - if (Inventory_Map[i] != block) continue; - Inventory_Map[i] = Inventory_DefaultMapping(i); - } -} - void Inventory_Remove(BlockID block) { - Int32 i; - for (i = 0; i < Array_Elems(Inventory_Map); i++) { - if (Inventory_Map[i] != block) continue; - Inventory_Map[i] = BLOCK_AIR; + Int32 slot; + for (slot = 0; slot < Array_Elems(Inventory_Map); slot++) { + if (Inventory_Map[slot] == block) Inventory_Map[slot] = BLOCK_AIR; } } -void Inventory_PushToFreeSlots(Int32 i) { - BlockID block = Inventory_Map[i]; - Int32 j; - /* The slot was already pushed out in the past - TODO: find a better way of fixing this */ - for (j = 1; j < Array_Elems(Inventory_Map); j++) { - if (j != i && Inventory_Map[j] == block) return; - } - - for (j = block; j < Array_Elems(Inventory_Map); j++) { - if (Inventory_Map[j] == BLOCK_AIR) { - Inventory_Map[j] = block; return; - } - } - for (j = 1; j < block; j++) { - if (Inventory_Map[j] == BLOCK_AIR) { - Inventory_Map[j] = block; return; - } - } -} - -void Inventory_Insert(Int32 i, BlockID block) { - if (Inventory_Map[i] == block) return; - /* Need to push the old block to a different slot if different block. */ - if (Inventory_Map[i] != BLOCK_AIR) Inventory_PushToFreeSlots(i); - Inventory_Map[i] = block; -} - void Inventory_ResetState(void) { Inventory_SetDefaultMapping(); Inventory_CanChangeHeldBlock = true; diff --git a/src/Client/Menus.c b/src/Client/Menus.c index 96a86439f..52b5644f8 100644 --- a/src/Client/Menus.c +++ b/src/Client/Menus.c @@ -81,10 +81,10 @@ void Menu_MakeDefaultBack(ButtonWidget* widget, bool toGame, FontDesc* font, Wid Int32 width = Game_UseClassicOptions ? 400 : 200; if (toGame) { String msg = String_FromConst("Back to game"); - Screen_MakeBack(widget, width, &msg, 25, font, onClick); + Menu_MakeBack(widget, width, &msg, 25, font, onClick); } else { String msg = String_FromConst("Cancel"); - Screen_MakeBack(widget, width, &msg, 25, font, onClick); + Menu_MakeBack(widget, width, &msg, 25, font, onClick); } } @@ -217,7 +217,7 @@ void ListScreen_ContextRecreated(void* obj) { ListScreen_Make(screen, 5, -220, 0, &lArrow, ListScreen_MoveBackwards); String rArrow = String_FromConst(">"); ListScreen_Make(screen, 6, 220, 0, &rArrow, ListScreen_MoveForwards); - Screen_MakeDefaultBack(&screen->Buttons[7], false, &screen->Font, Menu_SwitchPause); + Menu_MakeDefaultBack(&screen->Buttons[7], false, &screen->Font, Menu_SwitchPause); screen->Widgets[0] = (Widget*)(&screen->Title); for (i = 0; i < FILES_SCREEN_BUTTONS; i++) { @@ -495,7 +495,7 @@ bool PauseScreen_HandlesKeyDown(GuiElement* elem, Key key) { Screen* PauseScreen_MakeInstance(void) { PauseScreen* screen = &PauseScreen_Instance; - MenuScreen_MakeInstance(&screen->Base, screen->Widgets, Array_Elems(screen->Buttons), PauseScreen_ContextRecreated); + MenuScreen_MakeInstance(&screen->Base, screen->Widgets, Array_Elems(screen->Widgets), PauseScreen_ContextRecreated); PauseScreen_VTABLE = *screen->Base.VTABLE; screen->Base.VTABLE = &PauseScreen_VTABLE; @@ -504,3 +504,108 @@ Screen* PauseScreen_MakeInstance(void) { screen->Base.VTABLE->HandlesKeyDown = PauseScreen_HandlesKeyDown; return screen; } + + +typedef struct OptionsGroupScreen_ { + MenuScreen Base; + Widget* Widgets[9]; + ButtonWidget Buttons[8]; + TextWidget Desc; + Int32 SelectedI; +} OptionsGroupScreen; + +GuiElementVTABLE OptionsGroupScreen_VTABLE; +OptionsGroupScreen OptionsGroupScreen_Instance; +Screen* OptionsGroupScreen_MakeInstance(void) { + OptionsGroupScreen* screen = &OptionsGroupScreen_Instance; + MenuScreen_MakeInstance(&screen->Base, screen->Widgets, Array_Elems(screen->Widgets), OptionsGroupScreen_ContextRecreated); + OptionsGroupScreen_VTABLE = *screen->Base.VTABLE; + screen->Base.VTABLE = &OptionsGroupScreen_VTABLE; + + screen->Base.VTABLE->Init = OptionsGroupScreen_Init; + screen->Base.VTABLE->Free = OptionsGroupScreen_Free; + screen->Base.VTABLE->HandlesMouseMove = OptionsGroupScreen_HandlesMouseMove; + /* Pause screen key down behaviour is same for options group screen*/ + screen->Base.VTABLE->HandlesKeyDown = PauseScreen_HandlesKeyDown; + + screen->SelectedI = -1; + return screen; +} + + +void OptionsGroupScreen_Init(GuiElement* elem) { + MenuScreen_Init(elem); + game.Events.HackPermissionsChanged += CheckHacksAllowed; + titleFont = new Font(game.FontName, 16, FontStyle.Bold); + regularFont = new Font(game.FontName, 16); + ContextRecreated(); +} + +void OptionsGroupScreen_ContextRecreated(void* obj) { + OptionsGroupScreen* screen = (OptionsGroupScreen*)obj; + widgets = new Widget[]{ + Make(-1, -100, "Misc options...", SwitchMiscOptions), + Make(-1, -50, "Gui options...", SwitchGuiOptions), + Make(-1, 0, "Graphics options...", SwitchGfxOptions), + Make(-1, 50, "Controls...", SwitchControls), + Make(1, -50, "Hacks settings...", SwitchHacksOptions), + Make(1, 0, "Env settings...", SwitchEnvOptions), + Make(1, 50, "Nostalgia options...", SwitchNostalgiaOptions), + MakeBack(false, titleFont, SwitchPause), + null, // description text widget placeholder + }; + + if (screen->SelectedI >= 0) { + MakeDescWidget(descriptions[selectedI]); + } + CheckHacksAllowed(null, null); +} + + static void SwitchMiscOptions(Game g, Widget w) { g.Gui.SetNewScreen(new MiscOptionsScreen(g)); } + static void SwitchGuiOptions(Game g, Widget w) { g.Gui.SetNewScreen(new GuiOptionsScreen(g)); } + static void SwitchGfxOptions(Game g, Widget w) { g.Gui.SetNewScreen(new GraphicsOptionsScreen(g)); } + static void SwitchControls(Game g, Widget w) { g.Gui.SetNewScreen(new NormalKeyBindingsScreen(g)); } + static void SwitchHacksOptions(Game g, Widget w) { g.Gui.SetNewScreen(new HacksSettingsScreen(g)); } + static void SwitchEnvOptions(Game g, Widget w) { g.Gui.SetNewScreen(new EnvSettingsScreen(g)); } + static void SwitchNostalgiaOptions(Game g, Widget w) { g.Gui.SetNewScreen(new NostalgiaScreen(g)); } + + void CheckHacksAllowed(object sender, EventArgs e) { + widgets[5].Disabled = !game.LocalPlayer.Hacks.CanAnyHacks; // env settings + } + + void MakeDescWidget(string text) { + widgets[widgets.Length - 1] = TextWidget.Create(game, text, regularFont) + .SetLocation(Anchor.Centre, Anchor.Centre, 0, 100); + } + + ButtonWidget Make(int dir, int y, string text, ClickHandler onClick) { + return ButtonWidget.Create(game, 300, text, titleFont, onClick) + .SetLocation(Anchor.Centre, Anchor.Centre, dir * 160, y); + } + + bool OptionsGroupScreen_HandlesMouseMove(GuiElement* elem, Int32 x, Int32 y) { + int i = HandleMouseMove(widgets, mouseX, mouseY); + if (i == -1 || i == selectedI) return true; + if (i >= Array_Elems(OptionsGroupScreen_descs)) return true; + + selectedI = i; + Widget desc = widgets[widgets.Length - 1]; + if (desc != null) desc.Dispose(); + MakeDescWidget(descriptions[i]); + return true; + } + +void OptionsGroupScreen_Free(GuiElement* elem) { + MenuScreen_Free(elem); + game.Events.HackPermissionsChanged -= CheckHacksAllowed; +} + +const UInt8* OptionsGroupScreen_descs[7] = { + "&eMusic/Sound, view bobbing, and more", + "&eChat options, gui scale, font settings, and more", + "&eFPS limit, view distance, entity names/shadows", + "&eSet key bindings, bind keys to act as mouse clicks", + "&eHacks allowed, jump settings, and more", + "&eEnv colours, water level, weather, and more", + "&eSettings for resembling the original classic", +}; \ No newline at end of file diff --git a/src/Client/Widgets.c b/src/Client/Widgets.c index 30fe7e5be..b46b8b67d 100644 --- a/src/Client/Widgets.c +++ b/src/Client/Widgets.c @@ -576,6 +576,7 @@ void TableWidget_RecreateDescTex(TableWidget* widget) { void TableWidget_MakeDescTex(TableWidget* widget, BlockID block) { Gfx_DeleteTexture(&widget->DescTex.ID); + if (block == BLOCK_AIR) return; UInt8 descBuffer[String_BufferSize(STRING_SIZE * 2)]; String desc = String_InitAndClearArray(descBuffer);