diff --git a/Ambermoon.Core/Game.cs b/Ambermoon.Core/Game.cs index 87f74261..afc5170b 100644 --- a/Ambermoon.Core/Game.cs +++ b/Ambermoon.Core/Game.cs @@ -798,7 +798,8 @@ internal void OpenPartyMember(int slot) #endregion #region Character info layout.FillArea(new Rect(208, 49, 96, 80), Color.LightGray, false); - layout.AddSprite(new Rect(208, 49, 32, 34), Graphics.PortraitOffset + partyMember.PortraitIndex - 1, 49); + layout.AddSprite(new Rect(208, 49, 32, 34), Graphics.PortraitBackgroundOffset, 50, 1); + layout.AddSprite(new Rect(208, 49, 32, 34), Graphics.PortraitOffset + partyMember.PortraitIndex - 1, 49, 2); #endregion // TODO } diff --git a/Ambermoon.Core/UI/ItemGrid.cs b/Ambermoon.Core/UI/ItemGrid.cs index fe0edebf..dcbe8c29 100644 --- a/Ambermoon.Core/UI/ItemGrid.cs +++ b/Ambermoon.Core/UI/ItemGrid.cs @@ -8,6 +8,9 @@ namespace Ambermoon.UI { // TODO: disabled state // TODO: memorize scrollbar positions for inventories + // Note: The items are automatically updated in inventories, + // chests, etc as the UIItems use the same ItemSlot instances + // and modify them directly. internal class ItemGrid { const int SlotWidth = 16; @@ -127,13 +130,13 @@ public int DropItem(int slot, UIItem item) { item.Dragged = false; items[slot] = item; - items[slot].Position = slotPositions[slot]; + item.Position = slotPositions[slot - ScrollOffset]; return 0; } else if (itemSlot.Item.Empty || itemSlot.Item.ItemIndex == item.Item.ItemIndex) { int remaining = itemSlot.Item.Add(item.Item); - items[slot].Update(false); + itemSlot.Update(false); if (remaining == 0) item.Destroy(); @@ -145,8 +148,8 @@ public int DropItem(int slot, UIItem item) else { itemSlot.Item.Exchange(item.Item); - items[slot].Update(true); - items[slot].Position = slotPositions[slot]; // Important to re-position amount display if added + itemSlot.Update(true); + itemSlot.Position = itemSlot.Position; // Important to re-position amount display if added item.Update(true); return itemSlot.Item.Amount; } @@ -253,7 +256,7 @@ public void LeftMouseUp(Position position) scrollbar?.LeftMouseUp(); } - public bool Click(Game game, Position position, Layout.DraggedItem draggedItem, + public bool Click(Position position, Layout.DraggedItem draggedItem, out Layout.DraggedItem pickedUpItem, bool leftMouseButton, ref CursorType cursorType) { pickedUpItem = draggedItem; diff --git a/Ambermoon.Core/UI/Layout.cs b/Ambermoon.Core/UI/Layout.cs index f118cf12..14ca30cf 100644 --- a/Ambermoon.Core/UI/Layout.cs +++ b/Ambermoon.Core/UI/Layout.cs @@ -257,7 +257,6 @@ public static DraggedItem FromExternal(ItemGrid itemGrid, int slotIndex, UIItem public LayoutType Type { get; private set; } readonly Game game; - readonly IRenderView renderView; readonly ILayerSprite sprite; readonly ITextureAtlas textureAtlasBackground; readonly ITextureAtlas textureAtlasForeground; @@ -269,12 +268,12 @@ public static DraggedItem FromExternal(ItemGrid itemGrid, int slotIndex, UIItem readonly List filledAreas = new List(); readonly List fadeEffects = new List(); readonly List additionalSprites = new List(); - internal IRenderView RenderView => renderView; + internal IRenderView RenderView { get; } public Layout(Game game, IRenderView renderView) { this.game = game; - this.renderView = renderView; + this.RenderView = renderView; textureAtlasBackground = TextureAtlasManager.Instance.GetOrCreate(Layer.UIBackground); textureAtlasForeground = TextureAtlasManager.Instance.GetOrCreate(Layer.UIForeground); sprite = renderView.SpriteFactory.Create(320, 163, 0, 0, false, true) as ILayerSprite; @@ -331,16 +330,16 @@ public void SetPortrait(int slot, uint portrait) } else { - var sprite = portraitBackgrounds[slot] ??= renderView.SpriteFactory.Create(32, 34, 0, 0, false, true, 0); - sprite.Layer = renderView.GetLayer(Layer.UIForeground); + var sprite = portraitBackgrounds[slot] ??= RenderView.SpriteFactory.Create(32, 34, 0, 0, false, true, 0); + sprite.Layer = RenderView.GetLayer(Layer.UIForeground); sprite.X = Global.PartyMemberPortraitAreas[slot].Left; sprite.Y = Global.PartyMemberPortraitAreas[slot].Top; sprite.TextureAtlasOffset = textureAtlasForeground.GetOffset(Graphics.PortraitBackgroundOffset); sprite.PaletteIndex = 50; sprite.Visible = true; - sprite = portraits[slot] ??= renderView.SpriteFactory.Create(32, 34, 0, 0, false, true, 1); - sprite.Layer = renderView.GetLayer(Layer.UIForeground); + sprite = portraits[slot] ??= RenderView.SpriteFactory.Create(32, 34, 0, 0, false, true, 1); + sprite.Layer = RenderView.GetLayer(Layer.UIForeground); sprite.X = Global.PartyMemberPortraitAreas[slot].Left; sprite.Y = Global.PartyMemberPortraitAreas[slot].Top; sprite.TextureAtlasOffset = textureAtlasForeground.GetOffset(Graphics.PortraitOffset + portrait - 1); @@ -349,14 +348,15 @@ public void SetPortrait(int slot, uint portrait) } } - public void AddSprite(Rect rect, uint textureIndex, byte paletteIndex) + public void AddSprite(Rect rect, uint textureIndex, byte paletteIndex, byte displayLayer = 0) { - var sprite = renderView.SpriteFactory.Create(rect.Size.Width, rect.Size.Height, 0, 0, false, true); + var sprite = RenderView.SpriteFactory.Create(rect.Size.Width, rect.Size.Height, 0, 0, false, true) as ILayerSprite; sprite.TextureAtlasOffset = textureAtlasForeground.GetOffset(textureIndex); + sprite.DisplayLayer = displayLayer; sprite.X = rect.Left; sprite.Y = rect.Top; sprite.PaletteIndex = paletteIndex; - sprite.Layer = renderView.GetLayer(Layer.UIForeground); + sprite.Layer = RenderView.GetLayer(Layer.UIForeground); sprite.Visible = true; additionalSprites.Add(sprite); } @@ -370,12 +370,12 @@ public void Set80x80Picture(Data.Enumerations.Picture80x80 picture) } else { - var sprite = sprite80x80Picture ??= renderView.SpriteFactory.Create(80, 80, 0, 0, false, true); + var sprite = sprite80x80Picture ??= RenderView.SpriteFactory.Create(80, 80, 0, 0, false, true); sprite.TextureAtlasOffset = textureAtlasForeground.GetOffset(Graphics.Pics80x80Offset + (uint)(picture - 1)); sprite.X = Global.LayoutX + 16; sprite.Y = Global.LayoutY + 6; sprite.PaletteIndex = 49; - sprite.Layer = renderView.GetLayer(Layer.UIForeground); + sprite.Layer = RenderView.GetLayer(Layer.UIForeground); sprite.Visible = true; } } @@ -394,9 +394,9 @@ public void AddItemGrid(ItemGrid itemGrid) IColoredRect CreateArea(Rect rect, Color color, bool topMost) { - var coloredRect = renderView.ColoredRectFactory.Create(rect.Size.Width, rect.Size.Height, + var coloredRect = RenderView.ColoredRectFactory.Create(rect.Size.Width, rect.Size.Height, color, (byte)(topMost ? 255 : 0)); - coloredRect.Layer = renderView.GetLayer(topMost ? Layer.Popup : Layer.UIBackground); + coloredRect.Layer = RenderView.GetLayer(topMost ? Layer.Popup : Layer.UIBackground); coloredRect.X = rect.Left; coloredRect.Y = rect.Top; coloredRect.Visible = true; @@ -447,19 +447,6 @@ public void Update() } } - void SyncInventory(Position position, DraggedItem droppedItem, ItemGrid itemGrid, Game game) - { - var currentInventory = game.GetPartyMember(game.CurrentInventoryIndex.Value).Inventory; - var slot = itemGrid.SlotFromPosition(position).Value; - currentInventory.Slots[slot].Replace(itemGrid.GetItem(slot)); - - if (droppedItem.SourcePlayer != null) - { - var sourceInventory = game.GetPartyMember(droppedItem.SourcePlayer.Value).Inventory; - sourceInventory.Slots[droppedItem.SourceSlot]?.Clear(); // TODO: what if only parts have been dragged? - } - } - public void KeyDown(Key key, KeyModifiers keyModifiers) { switch (key) @@ -504,11 +491,8 @@ public bool Click(Position position, MouseButtons buttons, ref CursorType cursor foreach (var itemGrid in itemGrids) { // TODO: If stacked it should ask for amount with left mouse - if (itemGrid.Click(game, position, draggedItem, out DraggedItem pickedUpItem, true, ref cursorType)) + if (itemGrid.Click(position, draggedItem, out DraggedItem pickedUpItem, true, ref cursorType)) { - DraggedItem dropped = (draggedItem != null && (pickedUpItem == null || pickedUpItem != draggedItem || - pickedUpItem.Item.Item.Amount != draggedItem.Item.Item.Amount)) ? draggedItem : null; - if (pickedUpItem != null) { draggedItem = pickedUpItem; @@ -518,12 +502,6 @@ public bool Click(Position position, MouseButtons buttons, ref CursorType cursor else DropItem(); - if (dropped != null && IsInventory) - { - // sync grid with inventory - SyncInventory(position, dropped, itemGrid, game); - } - return true; } } @@ -534,7 +512,7 @@ public bool Click(Position position, MouseButtons buttons, ref CursorType cursor { foreach (var itemGrid in itemGrids) { - if (itemGrid.Click(game, position, null, out DraggedItem pickedUpItem, false, ref cursorType)) + if (itemGrid.Click(position, null, out DraggedItem pickedUpItem, false, ref cursorType)) { if (pickedUpItem != null) { diff --git a/Ambermoon.Data.Common/Graphic.cs b/Ambermoon.Data.Common/Graphic.cs index 153dfa98..3852e01b 100644 --- a/Ambermoon.Data.Common/Graphic.cs +++ b/Ambermoon.Data.Common/Graphic.cs @@ -57,6 +57,15 @@ public Graphic(int width, int height, byte colorIndex) Array.Fill(Data, colorIndex); } + public void ReplaceColor(byte oldColorIndex, byte newColorIndex) + { + for (int i = 0; i < Data.Length; ++i) + { + if (Data[i] == oldColorIndex) + Data[i] = newColorIndex; + } + } + public void AddOverlay(uint x, uint y, Graphic overlay) { if (!overlay.IndexedGraphic || !IndexedGraphic) diff --git a/Ambermoon.Data.Legacy/GraphicProvider.cs b/Ambermoon.Data.Legacy/GraphicProvider.cs index d056b1e4..b6ef61a2 100644 --- a/Ambermoon.Data.Legacy/GraphicProvider.cs +++ b/Ambermoon.Data.Legacy/GraphicProvider.cs @@ -246,6 +246,17 @@ void LoadGraphic(IDataReader graphicDataReader) { var graphic = new Graphic(); reader.ReadGraphic(graphic, graphicDataReader, info); + if (type == GraphicType.Portrait) + { + // These need special care. It appears that they use color index + // 25 for "transparent" areas but this is magenta in the palettes + // I've seen. Black parts (like for the eyes) use color index 0 + // which is treated as transparent in all other images. + // But there is a really dark gray at color index 26 so we replace + // color 0 with color 26 and then 25 with color 0. + graphic.ReplaceColor(0, 26); + graphic.ReplaceColor(25, 0); + } graphicList.Add(graphic); } } diff --git a/Ambermoon.net/Ambermoon.net.csproj b/Ambermoon.net/Ambermoon.net.csproj index b4ad1031..1124820b 100644 --- a/Ambermoon.net/Ambermoon.net.csproj +++ b/Ambermoon.net/Ambermoon.net.csproj @@ -5,7 +5,7 @@ netcoreapp3.1 Ambermoon win-x64;linux-x64 - 1.0.14 + 1.0.15 diff --git a/README.md b/README.md index 276295b6..a0b1527a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # Ambermoon.net +Version 1.0.15 brings a lot of cool new stuff: +- Equipment (for now you can equip everything though) +- Inventory and equipment is loaded from savegame +- You can put items into chests or exchange them between party members +- Scrollbars +- Portrait backgrounds and portrait in inventory +- A lot of bugfixes and minor improvements + Version 1.0.14 brings items and inventory to the game. Even drag&drop works. Missing is the ability to equip items or drag only a partial amount. Version 1.0.13 is out now. It has a bunch of new features like: @@ -25,9 +33,9 @@ I got some questions of how to run the game: Version | OS --- | --- +[1.0.15](https://github.com/Pyrdacor/Ambermoon.net/releases/download/v1.0.15/Ambermoon.net-Windows.zip) | Windows 64bit [1.0.14](https://github.com/Pyrdacor/Ambermoon.net/releases/download/v1.0.14/Ambermoon.net-Windows.zip) | Windows 64bit [1.0.13](https://github.com/Pyrdacor/Ambermoon.net/releases/download/v1.0.13/Ambermoon.net-Windows.zip) | Windows 64bit -[1.0.12](https://github.com/Pyrdacor/Ambermoon.net/releases/download/v1.0.12/Ambermoon.net-Windows.zip) | Windows 64bit Older releases can be found [here](https://github.com/Pyrdacor/Ambermoon.net/releases). Other platforms will follow. @@ -92,6 +100,7 @@ F1-F6 | Open inventory of party member 1-6 ## Change log +- Version 1.0.15: Added equipment, scrollbars, improved item dragging, many bugfixes - Version 1.0.14: Added inventory and item drag&drop - Version 1.0.13: Moving with mouse, map transition fading effect, chest items, change tile events, portraits, initial savegame used - Version 1.0.12: Added cursors, added first version of chest map events