From 9f078a8ace4b6a26ca8d552fda71644bc27ee06a Mon Sep 17 00:00:00 2001 From: Tim Sarbin Date: Sat, 8 Dec 2018 01:01:30 -0500 Subject: [PATCH] Added animations. Added walking/running. --- OpenDiablo2.Common/Models/MPQDCC.cs | 133 +++++++++++++-- OpenDiablo2.Common/Models/Mobs/PlayerState.cs | 2 +- OpenDiablo2.Common/Models/PlayerInfo.cs | 4 +- .../Models/PlayerLocationDetails.cs | 21 ++- OpenDiablo2.Core/GameState/GameState.cs | 4 +- OpenDiablo2.Core/Map Engine/MapEngine.cs | 23 ++- OpenDiablo2.GameServer/GameServer.cs | 6 +- OpenDiablo2.SDL2/SDL2CharacterRenderer.cs | 156 ++++++++++++++++-- OpenDiablo2.Scenes/Game.cs | 2 + OpenDiablo2.ServiceBus/SessionServer.cs | 3 +- 10 files changed, 301 insertions(+), 53 deletions(-) diff --git a/OpenDiablo2.Common/Models/MPQDCC.cs b/OpenDiablo2.Common/Models/MPQDCC.cs index e0856086..7790ab69 100644 --- a/OpenDiablo2.Common/Models/MPQDCC.cs +++ b/OpenDiablo2.Common/Models/MPQDCC.cs @@ -8,19 +8,26 @@ namespace OpenDiablo2.Common.Models { public sealed class MPQDCC { - public class PixelBufferEntry + public sealed class PixelBufferEntry { public byte[] Value; public int Frame; public int FrameCellIndex; } - public struct Cell + public sealed class Cell { public int Width; public int Height; public int XOffset; public int YOffset; + + public int LastWidth; + public int LastHeight; + public int LastXOffset; + public int LastYOffset; + + public byte[] PixelData; } public sealed class MPQDCCDirectionFrame @@ -59,7 +66,7 @@ namespace OpenDiablo2.Common.Models } - public void MakeCells(MPQDCCDirection direction) + public void CalculateCells(MPQDCCDirection direction) { var w = 4 - ((Box.Left - direction.Box.Left) % 4); // Width of the first column (in pixels) if ((Width - w) <= 1) @@ -131,7 +138,6 @@ namespace OpenDiablo2.Common.Models } public sealed class MPQDCCDirection { - const int DCC_MAX_PB_ENTRY = 8500; // But why is this the magic number? public int OutSizeCoded { get; private set; } public int CompressionFlags { get; private set; } public int Variable0Bits { get; private set; } @@ -166,14 +172,14 @@ namespace OpenDiablo2.Common.Models OptionalDataBits = crazyBitTable[bm.GetBits(4)]; CodedBytesBits = crazyBitTable[bm.GetBits(4)]; - Frames = new MPQDCCDirectionFrame[file.NumberOfFrames]; + Frames = new MPQDCCDirectionFrame[file.FramesPerDirection]; var minx = long.MaxValue; var miny = long.MaxValue; var maxx = long.MinValue; var maxy = long.MinValue; // Load the frame headers - for (var frameIdx = 0; frameIdx < file.NumberOfFrames; frameIdx++) + for (var frameIdx = 0; frameIdx < file.FramesPerDirection; frameIdx++) { Frames[frameIdx] = new MPQDCCDirectionFrame(bm, this); @@ -242,13 +248,20 @@ namespace OpenDiablo2.Common.Models var pixelCodeandDisplacement = new BitMuncher(bm); - CalculateCellOffsets(); + // Calculate the cells for the direction + CaculateCells(); + // Caculate the cells for each of the frames foreach (var frame in Frames) - frame.MakeCells(this); + frame.CalculateCells(this); + // Fill in the pixel buffer FillPixelBuffer(pixelCodeandDisplacement, equalCellsBitstream, pixelMaskBitstream, encodingTypeBitsream, rawPixelCodesBitstream); + // Generate the actual frame pixel data + GenerateFrames(file, pixelCodeandDisplacement); + + // Verify that everything we expected to read was actually read (sanity check)... if (equalCellsBitstream.BitsRead != EqualCellsBitstreamSize) throw new ApplicationException("Did not read the correct number of bits!"); @@ -264,13 +277,103 @@ namespace OpenDiablo2.Common.Models bm.SkipBits(pixelCodeandDisplacement.BitsRead); } + private void GenerateFrames(MPQDCC file, BitMuncher pcd) + { + var pbIdx = 0; + + foreach (var cell in Cells) + { + cell.LastWidth = -1; + cell.LastHeight = -1; + cell.PixelData = new byte[cell.Width * cell.Height]; + } + + + + var frameIndex = -1; + foreach (var frame in Frames) + { + frameIndex++; + var numberOfCells = frame.HorizontalCellCount * frame.VerticalCellCount; + + var c = -1; + foreach (var cell in frame.Cells) + { + c++; + var cellX = cell.XOffset / 4; + var cellY = cell.YOffset / 4; + var cellIndex = cellX + (cellY * HorizontalCellCount); + var bufferCell = Cells[cellIndex]; + + var pbe = PixelBuffer[pbIdx]; + if ((pbe.Frame != frameIndex) || (pbe.FrameCellIndex != c)) + { + // This buffer cell has an EqualCell bit set to 1, so copy the frame cell or clear it + + if ((cell.Width != bufferCell.LastWidth) || (cell.Height != bufferCell.LastHeight)) + { + // Different sizes + /// TODO: Clear the pixels of the frame cell + for (var i = 0; i < bufferCell.PixelData.Length; i++) + bufferCell.PixelData[i] = 0x00; + + } + else + { + // Same sizes + + // Copy the old frame cell into the new position + // blit(dir->bmp, dir->bmp, buff_cell->last_x0, buff_cell->last_y0, cell->x0, cell->y0, cell->w, cell->h ); + for (var i = 0; i < bufferCell.PixelData.Length; i++) + bufferCell.PixelData[i] = cell.PixelData[i]; + + + bufferCell.LastWidth = cell.LastWidth; + bufferCell.LastHeight = cell.LastHeight; + // Copy it again into the final frame image + // blit(cell->bmp, frm_bmp, 0, 0, cell->x0, cell->y0, cell->w, cell->h ); + } + } + else + { + if (pbe.Value[0] == pbe.Value[1]) + { + // Clear the frame + } + else + { + // Fill the frame cell with the pixels + var bitsToRead = (pbe.Value[1] == pbe.Value[2]) ? 1 : 2; + cell.PixelData = new byte[cell.Width * cell.Height]; + + for (var y = 0; y < cell.Height; y++) + { + for (var x = 0; x < cell.Width; x++) + { + var paletteIndex = pcd.GetBits(bitsToRead); + cell.PixelData[x + (y * cell.Width)] = pbe.Value[paletteIndex]; + } + } + } + + // Copy the frame cell into the frame + //blit(cell->bmp, frm_bmp, 0, 0, cell->x0, cell->y0, cell->w, cell->h ); + pbIdx++; + } + } + } + } + private static readonly int[] pixelMaskLookup = new int[] { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; private void FillPixelBuffer(BitMuncher pcd, BitMuncher ec, BitMuncher pm, BitMuncher et, BitMuncher rp) { UInt32 lastPixel = 0; - - PixelBuffer = new PixelBufferEntry[DCC_MAX_PB_ENTRY]; - for (var i = 0; i < DCC_MAX_PB_ENTRY; i++) + + var maxCellX = Frames.Sum(x => x.HorizontalCellCount); + var maxCellY = Frames.Sum(x => x.VerticalCellCount); + + PixelBuffer = new PixelBufferEntry[maxCellX * maxCellY]; + for (var i = 0; i < maxCellX * maxCellY; i++) PixelBuffer[i] = new PixelBufferEntry { Frame = -1, FrameCellIndex = -1, Value = new byte[4] }; var cellBuffer = new PixelBufferEntry[HorizontalCellCount * VerticalCellCount]; @@ -353,7 +456,7 @@ namespace OpenDiablo2.Common.Models pbIndex++; var newEntry = PixelBuffer[pbIndex]; var curIdx = decodedPixel - 1; - + for (int i = 0; i < 4; i++) { if ((pixelMask & (1 << i)) != 0) @@ -386,7 +489,7 @@ namespace OpenDiablo2.Common.Models } } - private void CalculateCellOffsets() + private void CaculateCells() { // Calculate the number of vertical and horizontal cells we need HorizontalCellCount = 1 + (Box.Width - 1) / 4; @@ -441,7 +544,7 @@ namespace OpenDiablo2.Common.Models public int Signature { get; private set; } public int Version { get; private set; } public int NumberOfDirections { get; private set; } - public int NumberOfFrames { get; private set; } + public int FramesPerDirection { get; private set; } public MPQDCCDirection[] Directions { get; private set; } public MPQDCC(byte[] data, Palette palette) @@ -453,7 +556,7 @@ namespace OpenDiablo2.Common.Models Version = bm.GetByte(); NumberOfDirections = bm.GetByte(); - NumberOfFrames = bm.GetInt32(); + FramesPerDirection = bm.GetInt32(); if (bm.GetInt32() != 1) throw new ApplicationException("This value isn't 1. It has to be 1."); diff --git a/OpenDiablo2.Common/Models/Mobs/PlayerState.cs b/OpenDiablo2.Common/Models/Mobs/PlayerState.cs index 72121dfe..f8ec3afc 100644 --- a/OpenDiablo2.Common/Models/Mobs/PlayerState.cs +++ b/OpenDiablo2.Common/Models/Mobs/PlayerState.cs @@ -16,7 +16,7 @@ namespace OpenDiablo2.Common.Models.Mobs public eMovementType MovementType { get; set; } = eMovementType.Stopped; // TODO: This needs to mess with MobMode somehow public eWeaponClass WeaponClass { get; set; } = eWeaponClass.HandToHand; // Temporary public eArmorType ArmorType { get; set; } = eArmorType.Lite; // Temporary - public eMobMode MobMode { get; set; } = eMobMode.PlayerNeutral; // Temporary + public eMobMode MobMode { get; set; } = eMobMode.PlayerTownWalk; // Temporary // Player character stats protected Stat Vitality; diff --git a/OpenDiablo2.Common/Models/PlayerInfo.cs b/OpenDiablo2.Common/Models/PlayerInfo.cs index 013b8a23..b06e0d6c 100644 --- a/OpenDiablo2.Common/Models/PlayerInfo.cs +++ b/OpenDiablo2.Common/Models/PlayerInfo.cs @@ -42,12 +42,12 @@ namespace OpenDiablo2.Common.Models result.Name = Encoding.UTF8.GetString(data, offset + 8, nameLength); result.LocationDetails = PlayerLocationDetails.FromBytes(data, offset + 8 + nameLength); var uidBytes = new byte[16]; - Array.Copy(data, offset + 8 + nameLength + PlayerLocationDetails.SizeInBytes + 1, uidBytes, 0, 16); + Array.Copy(data, offset + 8 + nameLength + PlayerLocationDetails.SizeInBytes, uidBytes, 0, 16); result.UID = new Guid(uidBytes); return result; } - public int SizeInBytes => 5 + Encoding.UTF8.GetByteCount(Name) + PlayerLocationDetails.SizeInBytes; + public int SizeInBytes => 8 + Encoding.UTF8.GetByteCount(Name) + PlayerLocationDetails.SizeInBytes + 16; } diff --git a/OpenDiablo2.Common/Models/PlayerLocationDetails.cs b/OpenDiablo2.Common/Models/PlayerLocationDetails.cs index 6af2cfaa..8dce61d6 100644 --- a/OpenDiablo2.Common/Models/PlayerLocationDetails.cs +++ b/OpenDiablo2.Common/Models/PlayerLocationDetails.cs @@ -12,6 +12,7 @@ namespace OpenDiablo2.Common.Models public float PlayerY { get; set; } public eMovementType MovementType { get; set; } public int MovementDirection { get; set; } + public float MovementSpeed { get; set; } // TODO: They may not be on the same 'anchor map'... public byte[] GetBytes() @@ -22,32 +23,40 @@ namespace OpenDiablo2.Common.Models result.AddRange(BitConverter.GetBytes((float)PlayerY)); result.AddRange(BitConverter.GetBytes((Int32)MovementDirection)); result.AddRange(BitConverter.GetBytes((byte)MovementType)); + result.AddRange(BitConverter.GetBytes((float)MovementSpeed)); return result.ToArray(); } public static PlayerLocationDetails FromBytes(byte[] data, int offset = 0) - => new PlayerLocationDetails + { + var result = new PlayerLocationDetails { PlayerId = BitConverter.ToInt32(data, offset + 0), PlayerX = BitConverter.ToSingle(data, offset + 4), PlayerY = BitConverter.ToSingle(data, offset + 8), MovementDirection = BitConverter.ToInt32(data, offset + 12), - MovementType = (eMovementType)data[offset + 16] + MovementType = (eMovementType)data[offset + 16], + MovementSpeed = BitConverter.ToSingle(data, offset + 18) }; - - public static int SizeInBytes => 17; + return result; + } + public static int SizeInBytes => 22; } public static class PlayerLocationDetailsExtensions { public static PlayerLocationDetails ToPlayerLocationDetails(this PlayerState source) - => new PlayerLocationDetails + { + var result = new PlayerLocationDetails { PlayerId = source.Id, PlayerX = source.GetPosition().X, PlayerY = source.GetPosition().Y, MovementType = source.MovementType, - MovementDirection = source.MovementDirection + MovementDirection = source.MovementDirection, + MovementSpeed = (float)(source.MovementType == eMovementType.Running ? source.GetRunVelocity() : source.GetWalkVeloicty()) / 4f }; + return result; + } } } diff --git a/OpenDiablo2.Core/GameState/GameState.cs b/OpenDiablo2.Core/GameState/GameState.cs index 75ac8fa9..e512a51d 100644 --- a/OpenDiablo2.Core/GameState/GameState.cs +++ b/OpenDiablo2.Core/GameState/GameState.cs @@ -434,8 +434,8 @@ namespace OpenDiablo2.Core.GameState_ var rads = (float)player.LocationDetails.MovementDirection * 22 * (float)Deg2Rad; - var moveX = (float)Math.Cos(rads) * seconds * 2f; - var moveY = (float)Math.Sin(rads) * seconds * 2f; + var moveX = (float)Math.Cos(rads) * seconds * player.LocationDetails.MovementSpeed; + var moveY = (float)Math.Sin(rads) * seconds * player.LocationDetails.MovementSpeed; player.LocationDetails.PlayerX += moveX; player.LocationDetails.PlayerY += moveY; diff --git a/OpenDiablo2.Core/Map Engine/MapEngine.cs b/OpenDiablo2.Core/Map Engine/MapEngine.cs index 37c99e54..6a191870 100644 --- a/OpenDiablo2.Core/Map Engine/MapEngine.cs +++ b/OpenDiablo2.Core/Map Engine/MapEngine.cs @@ -67,7 +67,11 @@ namespace OpenDiablo2.Core.Map_Engine foreach(var loc in playerLocationDetails) { var cr = characterRenderers.FirstOrDefault(x => x.LocationDetails.PlayerId == loc.PlayerId); + var newDirection = loc.MovementDirection != cr.LocationDetails.MovementDirection; + var stanceChanged = loc.MovementType != cr.LocationDetails.MovementType; cr.LocationDetails = loc; + if (newDirection || stanceChanged) + cr.ResetAnimationData(); } } @@ -135,20 +139,27 @@ namespace OpenDiablo2.Core.Map_Engine foreach (var cellInfo in gameState.GetMapCellInfo((int)ax, (int)ay, eRenderCellType.WallLower)) renderWindow.DrawMapCell(cellInfo, 320 + (int)px + (int)ox + xOffset, 210 + (int)py + (int)oy); - // TODO: We need to render the characters infront of, or behind the wall properly... - foreach (var character in characterRenderers.Where(x => Math.Truncate(x.LocationDetails.PlayerX) == ax && Math.Truncate(x.LocationDetails.PlayerY) == ay)) - character.Render(320 + (int)px + (int)ox + xOffset, 210 + (int)py + (int)oy); - - foreach (var cellInfo in gameState.GetMapCellInfo((int)ax, (int)ay, eRenderCellType.WallUpper)) renderWindow.DrawMapCell(cellInfo, 320 + (int)px + (int)ox + xOffset, 210 + (int)py + (int)oy); + // TODO: We need to render the characters infront of, or behind the wall properly... + if (ty == 1 && tx == 1) + { + foreach (var character in characterRenderers/*.Where(x => Math.Truncate(x.LocationDetails.PlayerX) == ax && Math.Truncate(x.LocationDetails.PlayerY) == ay)*/) + { + // TODO: Temporary hack + character.Render(400, 280); + } + } + foreach (var cellInfo in gameState.GetMapCellInfo((int)ax, (int)ay, eRenderCellType.Roof)) renderWindow.DrawMapCell(cellInfo, 320 + (int)px + (int)ox + xOffset, 210 + (int)py + (int)oy); - } } + + + } diff --git a/OpenDiablo2.GameServer/GameServer.cs b/OpenDiablo2.GameServer/GameServer.cs index 57c595a8..8af4e340 100644 --- a/OpenDiablo2.GameServer/GameServer.cs +++ b/OpenDiablo2.GameServer/GameServer.cs @@ -84,8 +84,10 @@ namespace OpenDiablo2.GameServer_ var rads = (float)player.MovementDirection * 22 * (float)Deg2Rad; - var moveX = (float)Math.Cos(rads) * seconds * 2f; - var moveY = (float)Math.Sin(rads) * seconds * 2f; + var speed = (float)(player.MovementType == eMovementType.Running ? player.GetRunVelocity() : player.GetWalkVeloicty()) / 4f; + + var moveX = (float)Math.Cos(rads) * seconds * speed; + var moveY = (float)Math.Sin(rads) * seconds * speed; player.X += moveX; player.Y += moveY; diff --git a/OpenDiablo2.SDL2/SDL2CharacterRenderer.cs b/OpenDiablo2.SDL2/SDL2CharacterRenderer.cs index c3afa382..21ba9947 100644 --- a/OpenDiablo2.SDL2/SDL2CharacterRenderer.cs +++ b/OpenDiablo2.SDL2/SDL2CharacterRenderer.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; +using System.Drawing; using System.Linq; +using OpenDiablo2.Common; using OpenDiablo2.Common.Enums; using OpenDiablo2.Common.Interfaces; using OpenDiablo2.Common.Interfaces.Drawing; @@ -10,6 +13,18 @@ namespace OpenDiablo2.SDL2_ { public sealed class SDL2CharacterRenderer : ICharacterRenderer { + sealed class DirectionCacheItem + { + public int Direction { get; set; } + public eMobMode MobMode { get; set; } + + public SDL.SDL_Rect[] SpriteRect { get; set; } + public IntPtr[] SpriteTexture { get; set; } + public int FramesToAnimate { get; set; } + public int AnimationSpeed { get; set; } + public int RenderFrameIndex { get; set; } + } + static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public Guid UID { get; set; } @@ -20,7 +35,10 @@ namespace OpenDiablo2.SDL2_ public eMobMode MobMode { get; set; } private IntPtr renderer; - private IntPtr tempTexture; + + private List directionCache = new List(); + DirectionCacheItem currentDirectionCache; + private float seconds; private readonly IResourceManager resourceManager; private readonly IPaletteProvider paletteProvider; @@ -28,6 +46,8 @@ namespace OpenDiablo2.SDL2_ private MPQCOF animationData; private MPQDCC[] layerData; + static readonly byte[] directionConversion = new byte[] { 3, 15, 4, 8, 0, 9, 5, 10, 1, 11, 6, 12, 2, 13, 7, 14 }; + public SDL2CharacterRenderer(IntPtr renderer, IResourceManager resourceManager, IPaletteProvider paletteProvider) { this.resourceManager = resourceManager; @@ -37,12 +57,34 @@ namespace OpenDiablo2.SDL2_ public void Render(int pixelOffsetX, int pixelOffsetY) { + if (currentDirectionCache == null) + return; + var destRect = new SDL.SDL_Rect + { + x = pixelOffsetX + currentDirectionCache.SpriteRect[currentDirectionCache.RenderFrameIndex].x, + y = pixelOffsetY + currentDirectionCache.SpriteRect[currentDirectionCache.RenderFrameIndex].y, + w = currentDirectionCache.SpriteRect[currentDirectionCache.RenderFrameIndex].w, + h = currentDirectionCache.SpriteRect[currentDirectionCache.RenderFrameIndex].h + }; + + SDL.SDL_RenderCopy(renderer, currentDirectionCache.SpriteTexture[currentDirectionCache.RenderFrameIndex], IntPtr.Zero, ref destRect); } public void Update(long ms) { + if (currentDirectionCache == null) + return; + seconds += ((float)ms / 1000f); + var animationSeg = (15f / (float)currentDirectionCache.AnimationSpeed); + while (seconds >= animationSeg) + { + seconds -= animationSeg; + currentDirectionCache.RenderFrameIndex++; + if (currentDirectionCache.RenderFrameIndex >= currentDirectionCache.FramesToAnimate) + currentDirectionCache.RenderFrameIndex = 0; + } } public void Dispose() @@ -52,6 +94,29 @@ namespace OpenDiablo2.SDL2_ public void ResetAnimationData() { + switch (LocationDetails.MovementType) + { + case eMovementType.Stopped: + MobMode = eMobMode.PlayerTownNeutral; + break; + case eMovementType.Walking: + MobMode = eMobMode.PlayerTownWalk; + break; + case eMovementType.Running: + MobMode = eMobMode.PlayerRun; + break; + default: + MobMode = eMobMode.PlayerNeutral; + break; + } + + currentDirectionCache = directionCache.FirstOrDefault(x => x.MobMode == MobMode && x.Direction == directionConversion[LocationDetails.MovementDirection]); + if (currentDirectionCache != null) + { + currentDirectionCache.RenderFrameIndex = 0; + seconds = 0f; + return; + } animationData = resourceManager.GetPlayerAnimation(Hero, WeaponClass, MobMode); if (animationData == null) @@ -72,35 +137,92 @@ namespace OpenDiablo2.SDL2_ private unsafe void CacheFrames() { - var dirIndex = 0; // TODO: Specify the real direction - var frameIndex = 0; + var cache = new DirectionCacheItem + { + MobMode = MobMode, + Direction = directionConversion[LocationDetails.MovementDirection] + }; - var dirAnimation = animationData.Animations[dirIndex]; - var framesToAnimate = dirAnimation.FramesPerDirection; + var palette = paletteProvider.PaletteTable[Palettes.Units]; + + var dirAnimation = animationData.Animations[0]; + cache.FramesToAnimate = dirAnimation.FramesPerDirection; + cache.AnimationSpeed = dirAnimation.AnimationSpeed; + cache.RenderFrameIndex = 0; + + var minX = Int32.MaxValue; + var minY = Int32.MaxValue; + var maxX = Int32.MinValue; + var maxY = Int32.MinValue; foreach (var layer in layerData) { - var direction = layer.Directions[dirIndex]; - var frame = direction.Frames[0]; - var texture = SDL.SDL_CreateTexture( - renderer, - SDL.SDL_PIXELFORMAT_ARGB8888, - (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, - frame.Width, - frame.Height - ); + minX = Math.Min(minX, layer.Directions[directionConversion[LocationDetails.MovementDirection]].Box.Left); + minY = Math.Min(minY, layer.Directions[directionConversion[LocationDetails.MovementDirection]].Box.Top); + maxX = Math.Max(maxX, layer.Directions[directionConversion[LocationDetails.MovementDirection]].Box.Right); + maxY = Math.Max(maxY, layer.Directions[directionConversion[LocationDetails.MovementDirection]].Box.Bottom); + } + var frameW = (maxX - minX) * 2; // Hack + var frameH = (maxY - minY) * 2; + cache.SpriteTexture = new IntPtr[cache.FramesToAnimate]; + cache.SpriteRect = new SDL.SDL_Rect[cache.FramesToAnimate]; + + for (var frameIndex = 0; frameIndex < cache.FramesToAnimate; frameIndex++) + { + var texture = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, frameW, frameH); IntPtr pixels; int pitch; SDL.SDL_LockTexture(texture, IntPtr.Zero, out pixels, out pitch); - + UInt32* data = (UInt32*)pixels; + + foreach (var layer in layerData) + { + var direction = layer.Directions[directionConversion[LocationDetails.MovementDirection]]; + var frame = direction.Frames[frameIndex]; + + foreach (var cell in frame.Cells) + { + if (cell.PixelData == null) + continue; // TODO: This isn't good + + for (int y = 0; y < cell.Height; y++) + { + for (int x = 0; x < cell.Width; x++) + { + // Index 0 is always transparent + var paletteIndex = cell.PixelData[x + (y * cell.Width)]; + + if (paletteIndex == 0) + continue; + + var color = palette.Colors[paletteIndex]; + var relativeX = (frame.XOffset - minX); + var relativeY = (frame.YOffset - minY); + + var offsetX = x + cell.XOffset + (frame.Box.X - minX); + var offsetY = y + cell.YOffset + (frame.Box.Y - minY); + if (offsetX < 0 || offsetX > frameW || offsetY < 0 || offsetY > frameH) + throw new ApplicationException("There is nothing we can do now."); + + data[offsetX + (offsetY * (pitch / 4))] = color; + } + } + } + } + SDL.SDL_UnlockTexture(texture); + SDL.SDL_SetTextureBlendMode(texture, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); + // TODO: Temporary code! + cache.SpriteTexture[frameIndex] = texture; + cache.SpriteRect[frameIndex] = new SDL.SDL_Rect { x = minX, y = minY, w = frameW, h = frameH }; - - tempTexture = texture; + directionCache.Add(cache); + currentDirectionCache = cache; } } + } } diff --git a/OpenDiablo2.Scenes/Game.cs b/OpenDiablo2.Scenes/Game.cs index c640052b..5042b09b 100644 --- a/OpenDiablo2.Scenes/Game.cs +++ b/OpenDiablo2.Scenes/Game.cs @@ -153,6 +153,8 @@ namespace OpenDiablo2.Scenes if (cursorDirection < 0) cursorDirection += 360; var actualDirection = (byte)(cursorDirection / 22); + if (actualDirection >= 16) + actualDirection -= 16; if (mouseInfoProvider.LeftMouseDown && (lastMovementType == eMovementType.Stopped || lastDirection != actualDirection)) { diff --git a/OpenDiablo2.ServiceBus/SessionServer.cs b/OpenDiablo2.ServiceBus/SessionServer.cs index 6cd2bfd7..78c266f5 100644 --- a/OpenDiablo2.ServiceBus/SessionServer.cs +++ b/OpenDiablo2.ServiceBus/SessionServer.cs @@ -110,16 +110,15 @@ namespace OpenDiablo2.ServiceBus private void OnMovementRequestHandler(int clientHash, byte direction, eMovementType movementType) { - // TODO: Actually move the player .... var player = gameServer.Players.FirstOrDefault(x => x.ClientHash == clientHash); if (player == null) return; - // TODO: The server needs to actually manage player movement... player.MovementDirection = direction; player.MovementType = movementType; player.MovementDirection = direction; + Send(new MFLocatePlayers(gameServer.Players.Select(x => x.ToPlayerLocationDetails()))); }