mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-02 06:36:28 -05:00
Refactored map generation logic
This commit is contained in:
parent
1b2c7bc526
commit
5c7bba87d1
@ -9,6 +9,8 @@ namespace OpenDiablo2.Common.Enums
|
||||
public enum eRenderCellType
|
||||
{
|
||||
Floor,
|
||||
Wall
|
||||
WallUpper,
|
||||
WallLower,
|
||||
Roof
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user