1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-16 12:35:22 +00:00

Refactored map generation logic

This commit is contained in:
Tim Sarbin 2018-11-27 23:09:10 -05:00
parent 1b2c7bc526
commit 5c7bba87d1
6 changed files with 167 additions and 132 deletions

View File

@ -9,6 +9,8 @@ namespace OpenDiablo2.Common.Enums
public enum eRenderCellType
{
Floor,
Wall
WallUpper,
WallLower,
Roof
}
}

View File

@ -10,7 +10,5 @@ namespace OpenDiablo2.Common.Interfaces
void Update(long ms);
void Render();
void NotifyMapChanged();
MapCellInfo GetMapCellInfo(Guid mapId, Guid tileId);
void SetMapCellInfo(Guid mapId, MapCellInfo cellInfo);
}
}

View File

@ -25,6 +25,7 @@ namespace OpenDiablo2.Common.Interfaces
IMouseCursor LoadCursor(ISprite sprite, int frame, Point hotspot);
void SetCursor(IMouseCursor mouseCursor);
void Draw(ILabel label);
void DrawMapCell(int xCell, int yCell, int xPixel, int yPixel, MPQDS1 mapData, int main_index, int sub_index, Palette palette, int orientation);
MapCellInfo CacheMapCell(MPQDT1Tile mapCell);
void DrawMapCell(MapCellInfo mapCellInfo, int xPixel, int yPixel);
}
}

View File

@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenDiablo2.Common.Interfaces;
namespace OpenDiablo2.Common.Models
@ -11,12 +7,14 @@ namespace OpenDiablo2.Common.Models
// Represents a single cell on a map
public sealed class MapCellInfo
{
public Guid TileId;
public int OffX;
public int OffY;
public int FrameWidth;
public int FrameHeight;
public Rectangle Rect;
public ITexture Texture;
public Guid TileId { get; set; }
public int AnimationId { get; set; }
public int OffX { get; set; }
public int OffY { get; set; }
public int FrameWidth { get; set; }
public int FrameHeight { get; set; }
public MPQDT1Tile Tile { get; set; }
public Rectangle Rect { get; set; }
public ITexture Texture { get; set; }
}
}

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenDiablo2.Common;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces;
using OpenDiablo2.Common.Models;
@ -81,12 +82,12 @@ namespace OpenDiablo2.Core.Map_Engine
var visualX = ((x - y) * (cellSizeX / 2)) - cOffX;
var visualY = ((x + y) * (cellSizeY / 2)) - cOffY;
DrawFloor(x, y, visualX, visualY);
DrawWall(x, y, visualX, visualY, false);
DrawWall(x, y, visualX, visualY, true);
DrawRoof(x, y, visualX, visualY);
// //DrawShadow(x, y, visualX, visualY);
// //DrawShadow(x, y, visualX, visualY);
}
}
@ -100,34 +101,26 @@ namespace OpenDiablo2.Core.Map_Engine
foreach (var wallLayer in gameState.MapData.WallLayers)
{
var wall = wallLayer.Props[x + (y * gameState.MapData.Width)];
var orientation = wallLayer.Orientations[x + (y * gameState.MapData.Width)].Orientation1;
var idx = x + (y * gameState.MapData.Width);
if (orientation != 15) // Only 15 (roof)
var cellInfo = GetMapCellInfo(
gameState.MapData.Id, cx, cy, wallLayer.Props[idx],
eRenderCellType.Roof,
wallLayer.Orientations[idx]);
if (cellInfo == null)
return;
if (wall.Prop1 == 0)
continue;
if ((wall.Prop4 & 0x80) > 0)
{
if (orientation != 10 && orientation != 11)
return;
}
var sub_index = wall.Prop2;
var main_index = (wall.Prop3 >> 4) + ((wall.Prop4 & 0x03) << 4);
var lt = gameState.MapData.LookupTable.First(z => z.MainIndex == main_index && z.SubIndex == sub_index && z.Orientation == orientation);
renderWindow.DrawMapCell(x, y, cx, cy - lt.TileRef.RoofHeight, gameState.MapData, main_index, sub_index, gameState.CurrentPalette, orientation);
renderWindow.DrawMapCell(cellInfo, cx, cy);
}
}
private void DrawShadow(int x, int y, int visualX, int visualY)
{
}
private void DrawFloor(int x, int y, int visualX, int visualY)
{
if (visualX < -160 || visualX > 800 || visualY < -120 || visualY > 650)
@ -142,16 +135,13 @@ namespace OpenDiablo2.Core.Map_Engine
var idx = x + (y * gameState.MapData.Width);
if (idx >= floorLayer.Props.Length)
break;
var floor = floorLayer.Props[idx];
if (floor.Prop1 == 0)
continue;
var cellInfo = GetMapCellInfo(gameState.MapData.Id, cx, cy, floorLayer.Props[idx], eRenderCellType.Floor);
var sub_index = floor.Prop2;
var main_index = (floor.Prop3 >> 4) + ((floor.Prop4 & 0x03) << 4);
if (cellInfo == null)
return;
renderWindow.DrawMapCell(x, y, cx, cy, gameState.MapData, main_index, sub_index, gameState.CurrentPalette, 0);
renderWindow.DrawMapCell(cellInfo, cx, cy);
}
}
@ -163,31 +153,17 @@ namespace OpenDiablo2.Core.Map_Engine
foreach (var wallLayer in gameState.MapData.WallLayers)
{
var wall = wallLayer.Props[x + (y * gameState.MapData.Width)];
var orientation = wallLayer.Orientations[x + (y * gameState.MapData.Width)].Orientation1;
var idx = x + (y * gameState.MapData.Width);
var cellInfo = GetMapCellInfo(
gameState.MapData.Id, cx, cy, wallLayer.Props[idx],
upper ? eRenderCellType.WallUpper : eRenderCellType.WallLower,
wallLayer.Orientations[idx]);
if (wall.Prop1 == 0)
continue;
if (upper && orientation <= 15)
if (cellInfo == null)
return;
if (orientation == 10 || orientation == 11)
return; // TODO: Support special walls
if ((wall.Prop4 & 0x80) > 0)
{
if (orientation != 10 && orientation != 11)
return;
}
var sub_index = wall.Prop2;
var main_index = (wall.Prop3 >> 4) + ((wall.Prop4 & 0x03) << 4);
var lt = gameState.MapData.LookupTable.First(z => z.MainIndex == main_index && z.SubIndex == sub_index && z.Orientation == orientation);
renderWindow.DrawMapCell(x, y, cx, cy + 80, gameState.MapData, main_index, sub_index, gameState.CurrentPalette, orientation);
renderWindow.DrawMapCell(cellInfo, cx, cy);
}
}
@ -201,20 +177,124 @@ namespace OpenDiablo2.Core.Map_Engine
}
public MapCellInfo GetMapCellInfo(Guid mapId, Guid tileId)
private MapCellInfo GetMapCellInfo(
Guid mapId,
int cellX,
int cellY,
MPQDS1TileProps props,
eRenderCellType cellType,
MPQDS1WallOrientationTileProps wallOrientations = null
)
{
if (!mapDataLookup.ContainsKey(mapId))
var sub_index = props.Prop2;
var main_index = (props.Prop3 >> 4) + ((props.Prop4 & 0x03) << 4);
var orientation = 0;
if (cellType == eRenderCellType.Floor)
{
// Floors can't have rotations, should we blow up here?
if (props.Prop1 == 0)
return null;
}
if (cellType == eRenderCellType.Roof)
{
if (orientation != 15) // Only 15 (roof)
return null;
if (props.Prop1 == 0)
return null;
if ((props.Prop4 & 0x80) > 0)
{
if (orientation != 10 && orientation != 11)
return null;
}
}
if (cellType == eRenderCellType.WallUpper || cellType == eRenderCellType.WallLower)
{
orientation = wallOrientations.Orientation1;
if (props.Prop1 == 0)
return null;
// < 15 shouldn't happen for upper wall types, should we even check for this?
if (cellType == eRenderCellType.WallUpper && orientation <= 15)
return null;
// TODO: Support special walls
if (orientation == 10 || orientation == 11)
return null;
// This is also a thing apparently
if ((props.Prop4 & 0x80) > 0)
{
if (orientation != 10 && orientation != 11)
return null;
}
}
int frame = 0;
var tiles = gameState.MapData.LookupTable
.Where(x => x.MainIndex == main_index && x.SubIndex == sub_index && x.Orientation == orientation)
.Select(x => x.TileRef);
if (!tiles.Any())
throw new ApplicationException("Invalid tile id found!");
MPQDT1Tile tile = null;
if (tiles.First().Animated)
{
#if DEBUG
if (!tiles.All(x => x.Animated))
throw new ApplicationException("Some tiles are animated and some aren't...");
// TODO: Animated tiles
#endif
}
else
{
if (tiles.Count() > 0)
{
var totalRarity = tiles.Sum(q => q.RarityOrFrameIndex);
var random = new Random(gameState.Seed + cellX + (gameState.MapData.Width * cellY));
var x = random.Next(totalRarity);
var z = 0;
foreach (var t in tiles)
{
z += t.RarityOrFrameIndex;
if (x <= z)
{
tile = t;
break;
}
}
if (tile.Animated)
throw new ApplicationException("Why are we randomly finding an animated tile? Something's wrong here.");
}
else tile = tiles.First();
}
// This WILL happen to you
if (tile.Width == 0 || tile.Height == 0)
return null;
return mapDataLookup[mapId].FirstOrDefault(x => x.TileId == tileId);
}
public void SetMapCellInfo(Guid mapId, MapCellInfo cellInfo)
{
if (!mapDataLookup.ContainsKey(mapId))
mapDataLookup[mapId] = new List<MapCellInfo>();
mapDataLookup[mapId].Add(cellInfo);
var result = mapDataLookup[mapId].FirstOrDefault(x => x.TileId == tile.Id && x.AnimationId == frame);
if (result != null)
return result;
var mapCellInfo = renderWindow.CacheMapCell(tile);
mapDataLookup[mapId].Add(mapCellInfo);
return mapCellInfo;
}
}
}

View File

@ -281,55 +281,12 @@ namespace OpenDiablo2.SDL2_
SDL.SDL_RenderCopy(renderer, lbl.texture, IntPtr.Zero, ref destRect);
}
public unsafe void DrawMapCell(int xCell, int yCell, int xPixel, int yPixel, MPQDS1 mapData, int main_index, int sub_index, Palette palette, int orientation)
public unsafe MapCellInfo CacheMapCell(MPQDT1Tile mapCell)
{
var tiles = mapData.LookupTable.Where(x =>
x.MainIndex == main_index &&
x.SubIndex == sub_index &&
(orientation == -1 || x.Orientation == orientation)).Select(x => x.TileRef);
if (!tiles.Any())
throw new ApplicationException("Invalid tile id found!");
// TODO: This isn't good.. should be remembered in the map engine layer
MPQDT1Tile tile = null;
if (tiles.Count() > 0)
{
var totalRarity = tiles.Sum(q => q.RarityOrFrameIndex);
var random = new Random(gameState.Seed + xCell + (mapData.Width * yCell));
var x = random.Next(totalRarity);
var z = 0;
foreach (var t in tiles)
{
z += t.RarityOrFrameIndex;
if (x <= z)
{
tile = t;
break;
}
}
}
else tile = tiles.First();
// This WILL happen to you
if (tile.Width == 0 || tile.Height == 0)
return;
var mapCellInfo = getMapEngine().GetMapCellInfo(mapData.Id, tile.Id); ;
if (mapCellInfo != null)
{
var xd = new SDL.SDL_Rect { x = xPixel - mapCellInfo.OffX, y = yPixel - mapCellInfo.OffY, w = mapCellInfo.FrameWidth, h = mapCellInfo.FrameHeight };
var xs = mapCellInfo.Rect.ToSDL2Rect();
SDL.SDL_RenderCopy(renderer, ((SDL2Texture)mapCellInfo.Texture).Pointer, ref xs, ref xd);
return;
}
var minX = tile.Blocks.Min(x => x.PositionX);
var minY = tile.Blocks.Min(x => x.PositionY);
var maxX = tile.Blocks.Max(x => x.PositionX + 32);
var maxY = tile.Blocks.Max(x => x.PositionY + 32);
var minX = mapCell.Blocks.Min(x => x.PositionX);
var minY = mapCell.Blocks.Min(x => x.PositionY);
var maxX = mapCell.Blocks.Max(x => x.PositionX + 32);
var maxY = mapCell.Blocks.Max(x => x.PositionY + 32);
var diffX = maxX - minX;
var diffY = maxY - minY;
@ -345,12 +302,9 @@ namespace OpenDiablo2.SDL2_
var texId = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, frameSize.Width, frameSize.Height);
SDL.SDL_SetTextureBlendMode(texId, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
if (SDL.SDL_LockTexture(texId, IntPtr.Zero, out IntPtr pixels, out int pitch) != 0)
{
log.Error("Could not lock texture for map rendering");
return;
}
throw new ApplicationException("Could not lock texture for map rendering");
try
{
UInt32* data = (UInt32*)pixels;
@ -361,7 +315,7 @@ namespace OpenDiablo2.SDL2_
data[i] = 0x0;
foreach (var block in tile.Blocks)
foreach (var block in mapCell.Blocks)
{
var index = block.PositionX + offX + ((block.PositionY + offy) * pitchChange);
var xx = 0;
@ -372,7 +326,7 @@ namespace OpenDiablo2.SDL2_
{
if (colorIndex == 0)
continue;
var color = palette.Colors[colorIndex];
var color = gameState.CurrentPalette.Colors[colorIndex];
if (color > 0)
data[index] = color;
@ -398,21 +352,23 @@ namespace OpenDiablo2.SDL2_
SDL.SDL_UnlockTexture(texId);
}
var lookup = new MapCellInfo
return new MapCellInfo
{
FrameHeight = frameSize.Height,
FrameWidth = frameSize.Width,
OffX = offX,
OffY = offy,
Rect = srcRect.ToRectangle(),
TileId = tile.Id,
TileId = mapCell.Id,
Texture = new SDL2Texture { Pointer = texId }
};
}
getMapEngine().SetMapCellInfo(mapData.Id, lookup);
var dr = new SDL.SDL_Rect { x = xPixel - lookup.OffX, y = yPixel - lookup.OffY, w = lookup.FrameWidth, h = lookup.FrameHeight };
SDL.SDL_RenderCopy(renderer, texId, ref srcRect, ref dr);
public void DrawMapCell(MapCellInfo mapCellInfo, int xPixel, int yPixel)
{
var srcRect = new SDL.SDL_Rect { x = 0, y = 0, w = mapCellInfo.FrameWidth, h = Math.Abs(mapCellInfo.FrameHeight) };
var destRect = new SDL.SDL_Rect { x = xPixel - mapCellInfo.OffX, y = yPixel - mapCellInfo.OffY, w = mapCellInfo.FrameWidth, h = mapCellInfo.FrameHeight};
SDL.SDL_RenderCopy(renderer, (mapCellInfo.Texture as SDL2Texture).Pointer, ref srcRect, ref destRect);
}
public unsafe IMouseCursor LoadCursor(ISprite sprite, int frame, Point hotspot)