1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-10-10 04:04:32 -04:00
OpenDiablo2/OpenDiablo2.Core/GameState/GameState.cs

408 lines
16 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenDiablo2.Common.Enums;
using OpenDiablo2.Common.Interfaces;
2018-11-24 03:07:41 -05:00
using OpenDiablo2.Common.Models;
namespace OpenDiablo2.Core.GameState_
{
public sealed class GameState : IGameState
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly ISceneManager sceneManager;
2018-11-24 03:07:41 -05:00
private readonly IResourceManager resourceManager;
private readonly IPaletteProvider paletteProvider;
private readonly IEngineDataManager engineDataManager;
private readonly IRenderWindow renderWindow;
private readonly Func<IMapEngine> getMapEngine;
private float animationTime = 0f;
private List<MapInfo> mapInfo;
private List<MapCellInfo> mapDataLookup = new List<MapCellInfo>();
// TODO: Break this out further so we can support multiple maps---------------------------------------------
//private MPQDS1 _mapDataTemp, _mapDataTemp2;
//private Dictionary<Guid, List<MapCellInfo>> mapDataLookup = new Dictionary<Guid, List<MapCellInfo>>();
//private Dictionary<Guid, List<MapCellInfo>> mapDataLookup2 = new Dictionary<Guid, List<MapCellInfo>>();
// ---------------------------------------------------------------------------------------------------------
public int Act { get; private set; }
public string MapName { get; private set; }
public Palette CurrentPalette => paletteProvider.PaletteTable[$"ACT{Act}"];
2018-11-25 14:15:13 -05:00
public int Seed { get; internal set; }
public GameState(
ISceneManager sceneManager,
IResourceManager resourceManager,
IPaletteProvider paletteProvider,
IEngineDataManager engineDataManager,
IRenderWindow renderWindow,
Func<IMapEngine> getMapEngine
)
{
this.sceneManager = sceneManager;
2018-11-24 03:07:41 -05:00
this.resourceManager = resourceManager;
this.paletteProvider = paletteProvider;
this.getMapEngine = getMapEngine;
this.engineDataManager = engineDataManager;
this.renderWindow = renderWindow;
2018-11-25 14:15:13 -05:00
}
public void Initialize(string characterName, eHero hero)
{
2018-11-25 14:15:13 -05:00
var random = new Random();
Seed = random.Next();
sceneManager.ChangeScene("Game");
// Initialize our first village
// TODO: Loading may make this 'fun'..
mapInfo = new List<MapInfo>();
(new MapGenerator(this)).Generate();
// TODO: We need a map generator here...
/*
{
// TODO: TEMP CODE AHEAD!
var transId = nw ? 3 : 2;
var level = engineDataManager.LevelPresets.First(x => x.Def == (int)transId);
var levelDetails = engineDataManager.LevelDetails.First(x => x.Id == level.LevelId);
var levelType = engineDataManager.LevelTypes.First(x => x.Id == levelDetails.LevelType);
// Some maps have variations, so lets pick a random one
var mapNames = new List<string>();
if (level.File1 != "0") mapNames.Add(level.File1);
if (level.File2 != "0") mapNames.Add(level.File2);
if (level.File3 != "0") mapNames.Add(level.File3);
if (level.File4 != "0") mapNames.Add(level.File4);
if (level.File5 != "0") mapNames.Add(level.File5);
if (level.File6 != "0") mapNames.Add(level.File6);
var random = new Random(Seed);
var mapName = "data\\global\\tiles\\" + mapNames[random.Next(mapNames.Count())].Replace("/", "\\");
_mapDataTemp2 = resourceManager.GetMPQDS1(mapName, level, levelDetails, levelType);
}
*/
}
public MapInfo LoadSubMap(int levelDefId, Point origin)
{
var level = engineDataManager.LevelPresets.First(x => x.Def == levelDefId);
var levelDetails = engineDataManager.LevelDetails.First(x => x.Id == level.LevelId);
var levelType = engineDataManager.LevelTypes.First(x => x.Id == levelDetails.LevelType);
// Some maps have variations, so lets pick a random one
var mapNames = new List<string>();
if (level.File1 != "0") mapNames.Add(level.File1);
if (level.File2 != "0") mapNames.Add(level.File2);
if (level.File3 != "0") mapNames.Add(level.File3);
if (level.File4 != "0") mapNames.Add(level.File4);
if (level.File5 != "0") mapNames.Add(level.File5);
if (level.File6 != "0") mapNames.Add(level.File6);
var random = new Random(Seed);
var mapName = "data\\global\\tiles\\" + mapNames[random.Next(mapNames.Count())].Replace("/", "\\");
var fileData = resourceManager.GetMPQDS1(mapName, level, levelDetails, levelType);
var result = new MapInfo
{
LevelId = eLevelId.None,
LevelPreset = level,
LevelDetail = levelDetails,
LevelType = levelType,
FileData = fileData,
CellInfo = new Dictionary<eRenderCellType, MapCellInfo[]>(),
TileLocation = new Rectangle(origin, new Size(fileData.Width - 1, fileData.Height - 1))
};
mapInfo.Add(result);
return result;
}
public MapInfo LoadMap(eLevelId levelId, Point origin)
{
var level = engineDataManager.LevelPresets.First(x => x.LevelId == (int)levelId);
var levelDetails = engineDataManager.LevelDetails.First(x => x.Id == level.LevelId);
var levelType = engineDataManager.LevelTypes.First(x => x.Id == levelDetails.LevelType);
// Some maps have variations, so lets pick a random one
var mapNames = new List<string>();
if (level.File1 != "0") mapNames.Add(level.File1);
if (level.File2 != "0") mapNames.Add(level.File2);
if (level.File3 != "0") mapNames.Add(level.File3);
if (level.File4 != "0") mapNames.Add(level.File4);
if (level.File5 != "0") mapNames.Add(level.File5);
if (level.File6 != "0") mapNames.Add(level.File6);
2018-11-25 14:15:13 -05:00
var random = new Random(Seed);
var mapName = "data\\global\\tiles\\" + mapNames[random.Next(mapNames.Count())].Replace("/", "\\");
MapName = level.Name;
2018-11-25 14:15:13 -05:00
Act = levelType.Act;
var fileData = resourceManager.GetMPQDS1(mapName, level, levelDetails, levelType);
var result = new MapInfo
{
LevelId = levelId,
LevelPreset = level,
LevelDetail = levelDetails,
LevelType = levelType,
FileData = fileData,
CellInfo = new Dictionary<eRenderCellType, MapCellInfo[]>(),
TileLocation = new Rectangle(origin, new Size(fileData.Width - 1, fileData.Height - 1))
};
mapInfo.Add(result);
return result;
}
public IEnumerable<MapCellInfo> GetMapCellInfo(int cellX, int cellY, eRenderCellType renderCellType)
{
var map = GetMap(ref cellX, ref cellY);
if (map == null)
return new List<MapCellInfo>();
if (cellY >= map.FileData.Height || cellX >= map.FileData.Width)
return new List<MapCellInfo>(); // Temporary code
var idx = cellX + (cellY * map.FileData.Width);
switch (renderCellType)
{
case eRenderCellType.Floor:
return map.FileData.FloorLayers
.Select(floorLayer => GetMapCellInfo(map, cellX, cellY, floorLayer.Props[idx], eRenderCellType.Floor))
.Where(x => x != null);
case eRenderCellType.WallUpper:
case eRenderCellType.WallLower:
case eRenderCellType.Roof:
return map.FileData.WallLayers
.Select(wallLayer => GetMapCellInfo(map, cellX, cellY, wallLayer.Props[idx], renderCellType, wallLayer.Orientations[idx]))
.Where(x => x != null);
default:
throw new ApplicationException("Unknown render cell type!");
}
}
private MapInfo GetMap(ref int cellX, ref int cellY)
{
var x = cellX;
var y = cellY;
var map = mapInfo.FirstOrDefault(z => (x >= z.TileLocation.X) && (y >= z.TileLocation.Y)
&& (x < z.TileLocation.Right) && (y < z.TileLocation.Bottom));
if (map == null)
{
return null;
}
cellX -= map.TileLocation.X;
cellY -= map.TileLocation.Y;
return map;
}
public void UpdateMapCellInfo(int cellX, int cellY, eRenderCellType renderCellType, IEnumerable<MapCellInfo> mapCellInfo)
{
}
private MapCellInfo GetMapCellInfo(
MapInfo map,
int cellX,
int cellY,
MPQDS1TileProps props,
eRenderCellType cellType,
MPQDS1WallOrientationTileProps wallOrientations = null
)
{
if (!map.CellInfo.ContainsKey(cellType))
{
map.CellInfo[cellType] = new MapCellInfo[map.FileData.Width * map.FileData.Height];
}
var cellInfo = map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)];
if (cellInfo != null)
return cellInfo.Ignore ? null : cellInfo;
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)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
}
if (cellType == eRenderCellType.Roof)
{
if (orientation != 15) // Only 15 (roof)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
if (props.Prop1 == 0)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
if ((props.Prop4 & 0x80) > 0)
{
if (orientation != 10 && orientation != 11)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
}
}
if (cellType == eRenderCellType.WallUpper || cellType == eRenderCellType.WallLower)
{
orientation = wallOrientations.Orientation1;
if (props.Prop1 == 0)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
// < 15 shouldn't happen for upper wall types, should we even check for this?
if (cellType == eRenderCellType.WallUpper && orientation <= 15)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
// TODO: Support special walls
if (orientation == 10 || orientation == 11)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
// This is also a thing apparently
if ((props.Prop4 & 0x80) > 0)
{
if (orientation != 10 && orientation != 11)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
}
}
int frame = 0;
var tiles = (map.PrimaryMap ?? map).FileData.LookupTable
.Where(x => x.MainIndex == main_index && x.SubIndex == sub_index && x.Orientation == orientation)
.Select(x => x.TileRef);
if (!tiles.Any())
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
//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...");
#endif
var frameIndex = (int)Math.Floor(tiles.Count() * animationTime);
tile = tiles.ElementAt(frameIndex);
}
else
{
if (tiles.Count() > 0)
{
var totalRarity = tiles.Sum(q => q.RarityOrFrameIndex);
var random = new Random(Seed + cellX + (map.FileData.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)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null;
}
if (tile.BlockDataLength == 0)
{
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
return null; // Why is this a thing?
}
var mapCellInfo = mapDataLookup.FirstOrDefault(x => x.Tile.Id == tile.Id && x.AnimationId == frame);
if (mapCellInfo == null)
{
mapCellInfo = renderWindow.CacheMapCell(tile);
mapDataLookup.Add(mapCellInfo);
switch (cellType)
{
case eRenderCellType.WallUpper:
case eRenderCellType.WallLower:
mapCellInfo.OffY -= 80;
break;
}
}
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = mapCellInfo;
return mapCellInfo;
}
public void Update(long ms)
{
animationTime += ((float)ms / 1000f);
animationTime -= (float)Math.Truncate(animationTime);
}
}
}