mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-10-01 15:46:17 -04:00
Minor updates to map engine.
This commit is contained in:
parent
b1997963db
commit
dbd3e0b74f
19
OpenDiablo2.Common/Attributes/RandomizedMapAttribute.cs
Normal file
19
OpenDiablo2.Common/Attributes/RandomizedMapAttribute.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace OpenDiablo2.Common.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class RandomizedMapAttribute : Attribute
|
||||
{
|
||||
readonly string mapName;
|
||||
public string MapName => mapName;
|
||||
|
||||
public RandomizedMapAttribute(string mapName)
|
||||
{
|
||||
this.mapName = mapName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ namespace OpenDiablo2.Common.Enums
|
||||
Floor,
|
||||
WallNormal,
|
||||
WallLower,
|
||||
Shadow,
|
||||
Roof,
|
||||
MAX
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace OpenDiablo2.Common.Interfaces
|
||||
/// <returns>The <see cref="ImageSet"/> that was requested. Throw an exception if not found.</returns>
|
||||
ImageSet GetImageSet(string resourcePath);
|
||||
MPQFont GetMPQFont(string resourcePath);
|
||||
MPQDS1 GetMPQDS1(string resourcePath, LevelPreset level, LevelDetail levelDetail, LevelType levelType);
|
||||
MPQDS1 GetMPQDS1(string resourcePath, LevelPreset level, LevelType levelType);
|
||||
MPQDT1 GetMPQDT1(string resourcePath);
|
||||
Palette GetPalette(string paletteFile);
|
||||
MPQCOF GetPlayerAnimation(eHero hero, eWeaponClass weaponClass, eMobMode mobMode);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Interfaces.Mobs;
|
||||
using OpenDiablo2.Common.Models;
|
||||
@ -7,11 +8,11 @@ namespace OpenDiablo2.Common.Interfaces
|
||||
{
|
||||
public interface IEngineDataManager
|
||||
{
|
||||
List<LevelPreset> LevelPresets { get; }
|
||||
List<LevelType> LevelTypes { get; }
|
||||
List<LevelDetail> LevelDetails { get; }
|
||||
List<Item> Items { get; }
|
||||
Dictionary<eHero, ILevelExperienceConfig> ExperienceConfigs { get; }
|
||||
Dictionary<eHero, IHeroTypeConfig> HeroTypeConfigs { get; }
|
||||
ImmutableList<LevelDetail> Levels { get; }
|
||||
ImmutableList<LevelPreset> LevelPresets { get; }
|
||||
ImmutableList<LevelType> LevelTypes { get; }
|
||||
ImmutableList<Item> Items { get; }
|
||||
ImmutableDictionary<eHero, ILevelExperienceConfig> ExperienceConfigs { get; }
|
||||
ImmutableDictionary<eHero, IHeroTypeConfig> HeroTypeConfigs { get; }
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,13 @@ namespace OpenDiablo2.Common.Interfaces
|
||||
void Update(long ms);
|
||||
IEnumerable<MapCellInfo> GetMapCellInfo(int cellX, int cellY, eRenderCellType renderCellType);
|
||||
void UpdateMapCellInfo(int cellX, int cellY, eRenderCellType renderCellType, IEnumerable<MapCellInfo> mapCellInfo);
|
||||
MapInfo LoadMap(eLevelId levelId, Point origin);
|
||||
MapInfo LoadSubMap(int levelDefId, Point origin, MapInfo primaryMap, int subTile = -1);
|
||||
IMapInfo InsertMap(eLevelId levelId, IMapInfo parentMap = null);
|
||||
IMapInfo InsertMap(int levelId, Point origin, IMapInfo parentMap = null);
|
||||
IMapInfo InsertSubMap(int levelPresetId, int levelTypeId, Point origin, IMapInfo primaryMap, int subTile = -1);
|
||||
IMapInfo GetSubMapInfo(int levelPresetId, int levelTypeId, IMapInfo primaryMap, Point origin, int subTile = -1);
|
||||
void AddMap(IMapInfo map);
|
||||
int HasMap(int cellX, int cellY);
|
||||
IEnumerable<Size> GetMapSizes(int cellX, int cellY);
|
||||
void RemoveEverythingAt(int cellX, int cellY);
|
||||
}
|
||||
}
|
||||
|
11
OpenDiablo2.Common/Interfaces/IRandomizedMapGenerator.cs
Normal file
11
OpenDiablo2.Common/Interfaces/IRandomizedMapGenerator.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenDiablo2.Common.Models;
|
||||
|
||||
namespace OpenDiablo2.Common.Interfaces
|
||||
{
|
||||
public interface IRandomizedMapGenerator
|
||||
{
|
||||
void Generate(IMapInfo parentMap, Point location);
|
||||
}
|
||||
}
|
@ -9,189 +9,193 @@ namespace OpenDiablo2.Common.Models
|
||||
public sealed class LevelDetail
|
||||
{
|
||||
/// <summary>Internal level name</summary>
|
||||
public string Name { get; set; }
|
||||
public string Name { get; internal set; }
|
||||
|
||||
/// <summary>Level ID (Used in columns like VIS0-1)</summary>
|
||||
public int Id { get; set; }
|
||||
public int Id { get; internal set; }
|
||||
|
||||
/// <summary>Palette</summary>
|
||||
public int Pal { get; set; }
|
||||
public int Pal { get; internal set; }
|
||||
|
||||
/// <summary>Act</summary>
|
||||
public int Act { get; set; }
|
||||
public int Act { get; internal set; }
|
||||
|
||||
/// <summary>What layer the level is on (surface levels are always 0)</summary>
|
||||
public int Layer { get; set; }
|
||||
public int Layer { get; internal set; }
|
||||
|
||||
/// <summary>Horizontal size of the level</summary>
|
||||
public int SizeX { get; set; }
|
||||
public int SizeX { get; internal set; }
|
||||
|
||||
/// <summary>Vertical size of the level</summary>
|
||||
public int SizeY { get; set; }
|
||||
public int SizeY { get; internal set; }
|
||||
|
||||
/// <summary>Horizontal Placement Offset</summary>
|
||||
public int OffsetX { get; set; }
|
||||
public int OffsetX { get; internal set; }
|
||||
|
||||
/// <summary>Vertical placement offset</summary>
|
||||
public int OffsetY { get; set; }
|
||||
public int OffsetY { get; internal set; }
|
||||
|
||||
/// <summary>Special setting for levels that aren't random or preset (like Outer Cloister and Arcane Sancturary)</summary>
|
||||
public int Depend { get; set; }
|
||||
public int Depend { get; internal set; }
|
||||
|
||||
/// <summary>If true, it rains (or snows)</summary>
|
||||
public int Rain { get; set; }
|
||||
public int Rain { get; internal set; }
|
||||
|
||||
/// <summary>Unused</summary>
|
||||
public int Mud { get; set; }
|
||||
public int Mud { get; internal set; }
|
||||
|
||||
/// <summary>Perspective mode forced to off if set to 1</summary>
|
||||
public int NoPer { get; set; }
|
||||
public int NoPer { get; internal set; }
|
||||
|
||||
/// <summary>Level of sight drawing</summary>
|
||||
public int LOSDraw { get; set; }
|
||||
public int LOSDraw { get; internal set; }
|
||||
|
||||
/// <summary>Unknown</summary>
|
||||
public int FloorFilter { get; set; }
|
||||
public int FloorFilter { get; internal set; }
|
||||
|
||||
/// <summary>Unknown</summary>
|
||||
public int BlankScreen { get; set; }
|
||||
public int BlankScreen { get; internal set; }
|
||||
|
||||
/// <summary>For levels bordered with mountains or walls</summary>
|
||||
public int DrawEdges { get; set; }
|
||||
public int DrawEdges { get; internal set; }
|
||||
|
||||
/// <summary>Set to 1 if this is underground or inside</summary>
|
||||
public int IsInside { get; set; }
|
||||
public int IsInside { get; internal set; }
|
||||
|
||||
/// <summary> Setting for Level Generation: 1=Random Size, amount of rooms defined by LVLMAZE.TXT, 2=pre set map (example: catacombs lvl4) and 3=Random Area with preset size (wildernesses)</summary>
|
||||
public int DrlgType { get; set; }
|
||||
public int DrlgType { get; internal set; }
|
||||
|
||||
/// <summary>The level id to reference in lvltypes.txt</summary>
|
||||
public int LevelType { get; set; }
|
||||
public int LevelTypeId { get; internal set; }
|
||||
|
||||
/// <summary>Setting Regarding Level Type for lvlsub.txt (6=wilderness, 9=desert etc, -1=no subtype)</summary>
|
||||
public int SubType { get; set; }
|
||||
public int SubType { get; internal set; }
|
||||
|
||||
/// <summary></summary>
|
||||
public int SubTheme { get; set; }
|
||||
public int SubTheme { get; internal set; }
|
||||
|
||||
/// <summary></summary>
|
||||
public int SubWaypoint { get; set; }
|
||||
public int SubWaypoint { get; internal set; }
|
||||
|
||||
/// <summary></summary>
|
||||
public int SubShrine { get; set; }
|
||||
public int SubShrine { get; internal set; }
|
||||
|
||||
/// <summary>Entry/Exit to level #1-#8</summary>
|
||||
public int[] Vis0_7 { get; set; }
|
||||
public int[] Vis0_7 { get; internal set; }
|
||||
|
||||
/// <summary>ID into lvlwarp.txt</summary>
|
||||
public int[] Warp0_7 { get; set; }
|
||||
public int[] Warp0_7 { get; internal set; }
|
||||
|
||||
/// <summary>Light intensity (0-255)</summary>
|
||||
public int Intensity { get; set; }
|
||||
public int Intensity { get; internal set; }
|
||||
|
||||
/// <summary></summary>
|
||||
public int Red { get; set; }
|
||||
public int Red { get; internal set; }
|
||||
|
||||
/// <summary></summary>
|
||||
public int Green { get; set; }
|
||||
public int Green { get; internal set; }
|
||||
|
||||
/// <summary></summary>
|
||||
public int Blue { get; set; }
|
||||
public int Blue { get; internal set; }
|
||||
|
||||
/// <summary>Unknown</summary>
|
||||
public int Portal { get; set; }
|
||||
public int Portal { get; internal set; }
|
||||
|
||||
/// <summary>Settings for preset levels</summary>
|
||||
public int Position { get; set; }
|
||||
public int Position { get; internal set; }
|
||||
|
||||
/// <summary>If true, monster/creatures get saved/loaded instead of despawning.</summary>
|
||||
public int SaveMonsters { get; set; }
|
||||
public int SaveMonsters { get; internal set; }
|
||||
|
||||
/// <summary>Quest flags</summary>
|
||||
public int Quest { get; set; }
|
||||
public int Quest { get; internal set; }
|
||||
|
||||
/// <summary>Usually 2025, unknown</summary>
|
||||
public int WarpDist { get; set; }
|
||||
public int WarpDist { get; internal set; }
|
||||
|
||||
/// <summary>Level on Normal (controls the item level of items that drop from chests etc)</summary>
|
||||
public int MonLvl1 { get; set; }
|
||||
public int MonLvl1 { get; internal set; }
|
||||
|
||||
/// <summary>Level on Nightmare (controls the item level of items that drop from chests etc)</summary>
|
||||
public int MonLvl2 { get; set; }
|
||||
public int MonLvl2 { get; internal set; }
|
||||
|
||||
/// <summary> Level on Hell (controls the item level of items that drop from chests etc)</summary>
|
||||
public int MonLvl3 { get; set; }
|
||||
public int MonLvl3 { get; internal set; }
|
||||
|
||||
/// <summary>The Density of Monsters</summary>
|
||||
public int MonDen { get; set; }
|
||||
public int MonDen { get; internal set; }
|
||||
|
||||
/// <summary>Minimum Unique and Champion Monsters Spawned in this Level</summary>
|
||||
public int MonUMin { get; set; }
|
||||
public int MonUMin { get; internal set; }
|
||||
|
||||
/// <summary>Maximum Unique and Champion Monsters Spawned in this Level</summary>
|
||||
public int MonUMax { get; set; }
|
||||
public int MonUMax { get; internal set; }
|
||||
|
||||
/// <summary></summary>
|
||||
public int MonWndr { get; set; }
|
||||
public int MonWndr { get; internal set; }
|
||||
|
||||
/// <summary></summary>
|
||||
public int MonSpcWalk { get; set; }
|
||||
public int MonSpcWalk { get; internal set; }
|
||||
|
||||
/// <summary>How many different Species of Monsters can occur in this area (example: if you use M1-25 then set Mtot to 25 etc)</summary>
|
||||
public int Mtot { get; set; }
|
||||
public int Mtot { get; internal set; }
|
||||
|
||||
/// <summary>Monster Species 1-25 (use ID from MonStats.txt)</summary>
|
||||
public int[] M1_25 { get; set; }
|
||||
public int[] M1_25 { get; internal set; }
|
||||
|
||||
/// <summary>Spawned Species 1-25 (use ID from MonStats for Monsters which have eSpawnCol set to 2, related to M1-25, eg: if M1 Spawns S1 will Spawn)</summary>
|
||||
public int[] S1_25 { get; set; }
|
||||
public int[] S1_25 { get; internal set; }
|
||||
|
||||
/// <summary>How many different Species of Monsters can spawn as Uniques and Champions in this Area (works like Mtot)</summary>
|
||||
public int Utot { get; set; }
|
||||
public int Utot { get; internal set; }
|
||||
|
||||
/// <summary> Unique Species 1-25 (same as M1-M25 just for Monsters that you want to appear as Unique/Champions)</summary>
|
||||
public int[] U1_25 { get; set; }
|
||||
public int[] U1_25 { get; internal set; }
|
||||
|
||||
/// <summary>Critter Species 1-5 (For monsters set to 1 in the IsCritter Column in MonStats.txt)</summary>
|
||||
public int[] C1_5 { get; set; }
|
||||
public int[] C1_5 { get; internal set; }
|
||||
|
||||
/// <summary>Related to C1-5, eg: if you spawn a critter thru C1 then set this column to 30 etc. (function unknown)</summary>
|
||||
public int[] CA1_5 { get; set; }
|
||||
public int[] CA1_5 { get; internal set; }
|
||||
|
||||
/// <summary>Unknown</summary>
|
||||
public int[] CD1_5 { get; set; }
|
||||
public int[] CD1_5 { get; internal set; }
|
||||
|
||||
/// <summary>unknown</summary>
|
||||
public int Themes { get; set; }
|
||||
public int Themes { get; internal set; }
|
||||
|
||||
/// <summary>Referes to a entry in SoundEnviron.txt (for the Levels Music)</summary>
|
||||
public int SoundEnv { get; set; }
|
||||
public int SoundEnv { get; internal set; }
|
||||
|
||||
/// <summary>255=No way Point, other #'s Waypoint ID</summary>
|
||||
public int Waypoint { get; set; }
|
||||
public int Waypoint { get; internal set; }
|
||||
|
||||
/// <summary>String Code for the Display name of the Level</summary>
|
||||
public string LevelName { get; set; }
|
||||
public string LevelName { get; internal set; }
|
||||
|
||||
/// <summary>String Code for the Display name of a entrance to this Level</summary>
|
||||
public string LevelWarp { get; set; }
|
||||
public string LevelWarp { get; internal set; }
|
||||
|
||||
/// <summary>Which *.DC6 Title Image is loaded when you enter this area</summary>
|
||||
public string EntryFile { get; set; }
|
||||
public string EntryFile { get; internal set; }
|
||||
|
||||
/// <summary>Use the ID of the ObjectGroup you want to Spawn in this Area (from ObjectGroups.txt)</summary>
|
||||
public int[] ObjGrp0_7 { get; set; }
|
||||
public int[] ObjGrp0_7 { get; internal set; }
|
||||
|
||||
/// <summary>Object Spawn Possibility: the Chance for this object to occur (if you use ObjGrp0 then set ObjPrb0 to a value below 100)</summary>
|
||||
public int[] ObjPrb0_7 { get; set; }
|
||||
public int[] ObjPrb0_7 { get; internal set; }
|
||||
|
||||
/// <summary>Unused</summary>
|
||||
public bool Beta { get; set; }
|
||||
public bool Beta { get; internal set; }
|
||||
|
||||
public LevelPreset LevelPreset { get; internal set; }
|
||||
|
||||
public LevelType LevelType { get; internal set; }
|
||||
}
|
||||
|
||||
public static class LevelDetailHelper
|
||||
{
|
||||
public static LevelDetail ToLevelDetail(this string[] v)
|
||||
public static LevelDetail ToLevelDetail(this string[] v, IEnumerable<LevelPreset> levelPresets, IEnumerable<LevelType> levelTypes)
|
||||
{
|
||||
var result = new LevelDetail();
|
||||
int i = 0;
|
||||
@ -214,7 +218,7 @@ namespace OpenDiablo2.Common.Models
|
||||
result.DrawEdges = Convert.ToInt32(v[i++]);
|
||||
result.IsInside = Convert.ToInt32(v[i++]);
|
||||
result.DrlgType = Convert.ToInt32(v[i++]);
|
||||
result.LevelType = Convert.ToInt32(v[i++]);
|
||||
result.LevelTypeId = Convert.ToInt32(v[i++]);
|
||||
result.SubType = Convert.ToInt32(v[i++]);
|
||||
result.SubTheme = Convert.ToInt32(v[i++]);
|
||||
result.SubWaypoint = Convert.ToInt32(v[i++]);
|
||||
@ -265,8 +269,8 @@ namespace OpenDiablo2.Common.Models
|
||||
result.ObjPrb0_7 = new int[8];
|
||||
for (int j = 0; j < 5; j++) result.ObjPrb0_7[j] = Convert.ToInt32(v[i++]);
|
||||
result.Beta = Convert.ToInt32(v[i]) == 1;
|
||||
|
||||
|
||||
result.LevelPreset = levelPresets.FirstOrDefault(x => x.LevelId == result.Id);
|
||||
result.LevelType = levelTypes.FirstOrDefault(x => x.Id == result.LevelTypeId);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -9,30 +9,30 @@ namespace OpenDiablo2.Common.Models
|
||||
//
|
||||
public sealed class LevelPreset
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Def { get; set; }
|
||||
public int LevelId { get; set; }
|
||||
public bool Populate { get; set; }
|
||||
public int Logicals { get; set; }
|
||||
public int Outdoors { get; set; }
|
||||
public int Animate { get; set; }
|
||||
public int KillEdge { get; set; }
|
||||
public int FillBlanks { get; set; }
|
||||
public int SizeX { get; set; }
|
||||
public int SizeY { get; set; }
|
||||
public int AutoMap { get; set; }
|
||||
public int Scan { get; set; }
|
||||
public int Pops { get; set; }
|
||||
public int PopPad { get; set; }
|
||||
public int Files { get; set; }
|
||||
public string File1 { get; set; }
|
||||
public string File2 { get; set; }
|
||||
public string File3 { get; set; }
|
||||
public string File4 { get; set; }
|
||||
public string File5 { get; set; }
|
||||
public string File6 { get; set; }
|
||||
public UInt32 Dt1Mask { get; set; }
|
||||
public bool Beta { get; set; }
|
||||
public string Name { get; internal set; }
|
||||
public int Def { get; internal set; }
|
||||
public int LevelId { get; internal set; }
|
||||
public bool Populate { get; internal set; }
|
||||
public int Logicals { get; internal set; }
|
||||
public int Outdoors { get; internal set; }
|
||||
public int Animate { get; internal set; }
|
||||
public int KillEdge { get; internal set; }
|
||||
public int FillBlanks { get; internal set; }
|
||||
public int SizeX { get; internal set; }
|
||||
public int SizeY { get; internal set; }
|
||||
public int AutoMap { get; internal set; }
|
||||
public int Scan { get; internal set; }
|
||||
public int Pops { get; internal set; }
|
||||
public int PopPad { get; internal set; }
|
||||
public int Files { get; internal set; }
|
||||
public string File1 { get; internal set; }
|
||||
public string File2 { get; internal set; }
|
||||
public string File3 { get; internal set; }
|
||||
public string File4 { get; internal set; }
|
||||
public string File5 { get; internal set; }
|
||||
public string File6 { get; internal set; }
|
||||
public UInt32 Dt1Mask { get; internal set; }
|
||||
public bool Beta { get; internal set; }
|
||||
}
|
||||
|
||||
public static class LevelPresetHelper
|
||||
@ -63,7 +63,7 @@ namespace OpenDiablo2.Common.Models
|
||||
File5 = row[20],
|
||||
File6 = row[21],
|
||||
Dt1Mask = Convert.ToUInt32(row[22]),
|
||||
Beta = Convert.ToInt32(row[23]) == 1,
|
||||
Beta = Convert.ToInt32(row[23]) == 1
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
|
||||
namespace OpenDiablo2.Common.Models
|
||||
@ -96,7 +95,7 @@ namespace OpenDiablo2.Common.Models
|
||||
public MPQDS1Object[] Objects { get; internal set; }
|
||||
public MPQDS1Group[] Groups { get; internal set; }
|
||||
|
||||
public MPQDS1(Stream stream, LevelPreset level, LevelDetail levelDetail, LevelType levelType, IEngineDataManager engineDataManager, IResourceManager resourceManager)
|
||||
public MPQDS1(Stream stream, LevelPreset level, LevelType levelType, IEngineDataManager engineDataManager, IResourceManager resourceManager)
|
||||
{
|
||||
var br = new BinaryReader(stream);
|
||||
Version = br.ReadInt32();
|
||||
@ -295,6 +294,7 @@ namespace OpenDiablo2.Common.Models
|
||||
DT1s[i] = resourceManager.GetMPQDT1("data\\global\\tiles\\" + levelType.File[i].Replace("/", "\\"));
|
||||
}
|
||||
|
||||
|
||||
LookupTable = new List<DS1LookupTable>();
|
||||
foreach(var dt1 in DT1s.Where(x => x != null))
|
||||
{
|
||||
|
@ -4,15 +4,26 @@ using OpenDiablo2.Common.Enums;
|
||||
|
||||
namespace OpenDiablo2.Common.Models
|
||||
{
|
||||
public sealed class MapInfo
|
||||
public interface IMapInfo
|
||||
{
|
||||
public eLevelId LevelId { get; set; } = eLevelId.None;
|
||||
public MapInfo PrimaryMap { get; set; } = null;
|
||||
Dictionary<eRenderCellType, MapCellInfo[]> CellInfo { get; set; }
|
||||
MPQDS1 FileData { get; set; }
|
||||
Rectangle TileLocation { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MapInfo : IMapInfo
|
||||
{
|
||||
public int LevelId { get; set; } = (int)eLevelId.None;
|
||||
public MPQDS1 FileData { get; set; }
|
||||
public LevelPreset LevelPreset { get; set; }
|
||||
public LevelDetail LevelDetail { get; set; }
|
||||
public LevelType LevelType { get; set; }
|
||||
public Dictionary<eRenderCellType, MapCellInfo[]> CellInfo { get; set; }
|
||||
public Rectangle TileLocation { get; set; } = new Rectangle();
|
||||
}
|
||||
|
||||
public sealed class SubMapInfo : IMapInfo
|
||||
{
|
||||
public IMapInfo PrimaryMap { get; set; }
|
||||
public Dictionary<eRenderCellType, MapCellInfo[]> CellInfo { get; set; }
|
||||
public MPQDS1 FileData { get; set; }
|
||||
public Rectangle TileLocation { get; set; } = new Rectangle();
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ using OpenDiablo2.Common.Exceptions;
|
||||
using OpenDiablo2.Common.Interfaces.Mobs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@ -35,7 +36,7 @@ namespace OpenDiablo2.Common.Models.Mobs
|
||||
|
||||
public static class LevelExperienceConfigHelper
|
||||
{
|
||||
public static Dictionary<eHero, ILevelExperienceConfig> ToLevelExperienceConfigs(this string[][] data)
|
||||
public static ImmutableDictionary<eHero, ILevelExperienceConfig> ToLevelExperienceConfigs(this string[][] data)
|
||||
{
|
||||
Dictionary<eHero, ILevelExperienceConfig> result = new Dictionary<eHero, ILevelExperienceConfig>();
|
||||
for (int i = 1; i < data[0].Length; i++)
|
||||
@ -65,7 +66,7 @@ namespace OpenDiablo2.Common.Models.Mobs
|
||||
result.Add(herotype, new LevelExperienceConfig(expperlevel));
|
||||
}
|
||||
|
||||
return result;
|
||||
return result.ToImmutableDictionary();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Attributes\MessageFrameAttribute.cs" />
|
||||
<Compile Include="Attributes\RandomizedMapAttribute.cs" />
|
||||
<Compile Include="Attributes\SceneAttribute.cs" />
|
||||
<Compile Include="AutofacModule.cs" />
|
||||
<Compile Include="Enums\eItemContainerType.cs" />
|
||||
@ -90,6 +91,7 @@
|
||||
<Compile Include="Interfaces\IItemManager.cs" />
|
||||
<Compile Include="Extensions\MobManagerExtensions.cs" />
|
||||
<Compile Include="Interfaces\IGameServer.cs" />
|
||||
<Compile Include="Interfaces\IRandomizedMapGenerator.cs" />
|
||||
<Compile Include="Interfaces\MessageBus\ISessionEventProvider.cs" />
|
||||
<Compile Include="Interfaces\MessageBus\IMessageFrame.cs" />
|
||||
<Compile Include="Interfaces\MessageBus\ISessionManager.cs" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@ -18,78 +19,65 @@ namespace OpenDiablo2.Core
|
||||
|
||||
private readonly IMPQProvider mpqProvider;
|
||||
|
||||
public List<LevelPreset> LevelPresets { get; internal set; }
|
||||
public List<LevelType> LevelTypes { get; internal set; }
|
||||
public List<LevelDetail> LevelDetails { get; internal set; }
|
||||
public List<Item> Items { get; internal set; } = new List<Item>();
|
||||
public Dictionary<eHero, ILevelExperienceConfig> ExperienceConfigs { get; internal set; } = new Dictionary<eHero, ILevelExperienceConfig>();
|
||||
public Dictionary<eHero, IHeroTypeConfig> HeroTypeConfigs { get; internal set; } = new Dictionary<eHero, IHeroTypeConfig>();
|
||||
public ImmutableList<LevelDetail> Levels { get; internal set; }
|
||||
public ImmutableList<LevelPreset> LevelPresets { get; internal set; }
|
||||
public ImmutableList<LevelType> LevelTypes { get; internal set; }
|
||||
|
||||
public ImmutableList<Item> Items { get; internal set; }
|
||||
public ImmutableDictionary<eHero, ILevelExperienceConfig> ExperienceConfigs { get; internal set; }
|
||||
public ImmutableDictionary<eHero, IHeroTypeConfig> HeroTypeConfigs { get; internal set; }
|
||||
|
||||
public EngineDataManager(IMPQProvider mpqProvider)
|
||||
{
|
||||
this.mpqProvider = mpqProvider;
|
||||
|
||||
LoadLevelPresets();
|
||||
LoadLevelTypes();
|
||||
LoadLevelDetails();
|
||||
|
||||
LoadItemData();
|
||||
|
||||
LoadCharacterData();
|
||||
|
||||
Items = LoadItemData();
|
||||
}
|
||||
|
||||
private void LoadLevelTypes()
|
||||
|
||||
private void LoadLevelDetails()
|
||||
{
|
||||
log.Info("Loading level types");
|
||||
var data = mpqProvider
|
||||
LevelTypes = mpqProvider
|
||||
.GetTextFile(ResourcePaths.LevelType)
|
||||
.Skip(1)
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(x => x.Split('\t'))
|
||||
.Where(x => x.Count() == 36 && x[0] != "Expansion")
|
||||
.Select(x => x.ToLevelType());
|
||||
.Select(x => x.ToLevelType())
|
||||
.ToImmutableList();
|
||||
|
||||
LevelTypes = new List<LevelType>(data);
|
||||
}
|
||||
|
||||
private void LoadLevelPresets()
|
||||
{
|
||||
|
||||
log.Info("Loading level presets");
|
||||
var data = mpqProvider
|
||||
LevelPresets = mpqProvider
|
||||
.GetTextFile(ResourcePaths.LevelPreset)
|
||||
.Skip(1)
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(x => x.Split('\t'))
|
||||
.Where(x => x.Count() == 24 && x[0] != "Expansion")
|
||||
.Select(x => x.ToLevelPreset());
|
||||
|
||||
LevelPresets = new List<LevelPreset>(data);
|
||||
}
|
||||
|
||||
private void LoadLevelDetails()
|
||||
{
|
||||
.Select(x => x.ToLevelPreset())
|
||||
.ToImmutableList();
|
||||
|
||||
log.Info("Loading level details");
|
||||
var data = mpqProvider
|
||||
Levels = mpqProvider
|
||||
.GetTextFile(ResourcePaths.LevelDetails)
|
||||
.Skip(1)
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(x => x.Split('\t'))
|
||||
.Where(x => x.Count() > 80 && x[0] != "Expansion")
|
||||
.Select(x => x.ToLevelDetail());
|
||||
|
||||
LevelDetails = new List<LevelDetail>(data);
|
||||
.Select(x => x.ToLevelDetail(LevelPresets, LevelTypes))
|
||||
.ToImmutableList();
|
||||
}
|
||||
|
||||
private void LoadItemData()
|
||||
{
|
||||
var weaponData = LoadWeaponData();
|
||||
var armorData = LoadArmorData();
|
||||
var miscData = LoadMiscData();
|
||||
|
||||
Items.AddRange(weaponData);
|
||||
Items.AddRange(armorData);
|
||||
Items.AddRange(miscData);
|
||||
}
|
||||
private ImmutableList<Item> LoadItemData()
|
||||
=> new List<Item>()
|
||||
.Concat(LoadWeaponData())
|
||||
.Concat(LoadArmorData())
|
||||
.Concat(LoadMiscData())
|
||||
.ToImmutableList();
|
||||
|
||||
private IEnumerable<Weapon> LoadWeaponData()
|
||||
{
|
||||
@ -101,7 +89,7 @@ namespace OpenDiablo2.Core
|
||||
//.Where(x => !String.IsNullOrWhiteSpace(x[27]))
|
||||
.Select(x => x.ToWeapon());
|
||||
|
||||
return data;
|
||||
return data;
|
||||
}
|
||||
|
||||
private IEnumerable<Armor> LoadArmorData()
|
||||
@ -114,7 +102,7 @@ namespace OpenDiablo2.Core
|
||||
//.Where(x => !String.IsNullOrWhiteSpace(x[27]))
|
||||
.Select(x => x.ToArmor());
|
||||
|
||||
return data;
|
||||
return data;
|
||||
}
|
||||
|
||||
private IEnumerable<Misc> LoadMiscData()
|
||||
@ -127,38 +115,30 @@ namespace OpenDiablo2.Core
|
||||
//.Where(x => !String.IsNullOrWhiteSpace(x[27]))
|
||||
.Select(x => x.ToMisc());
|
||||
|
||||
return data;
|
||||
return data;
|
||||
}
|
||||
|
||||
private void LoadCharacterData()
|
||||
{
|
||||
LoadExperienceConfig();
|
||||
LoadHeroTypeConfig();
|
||||
ExperienceConfigs = LoadExperienceConfig();
|
||||
HeroTypeConfigs = LoadHeroTypeConfig();
|
||||
}
|
||||
|
||||
private void LoadExperienceConfig()
|
||||
{
|
||||
var data = mpqProvider
|
||||
private ImmutableDictionary<eHero, ILevelExperienceConfig> LoadExperienceConfig()
|
||||
=> mpqProvider
|
||||
.GetTextFile(ResourcePaths.Experience)
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(x => x.Split('\t'))
|
||||
.ToArray()
|
||||
.ToLevelExperienceConfigs();
|
||||
|
||||
ExperienceConfigs = data;
|
||||
}
|
||||
|
||||
private void LoadHeroTypeConfig()
|
||||
{
|
||||
var data = mpqProvider
|
||||
private ImmutableDictionary<eHero, IHeroTypeConfig> LoadHeroTypeConfig()
|
||||
=> mpqProvider
|
||||
.GetTextFile(ResourcePaths.CharStats)
|
||||
.Skip(1)
|
||||
.Where(x => !String.IsNullOrWhiteSpace(x))
|
||||
.Select(x => x.Split('\t'))
|
||||
.Where(x => x[0] != "Expansion")
|
||||
.ToDictionary(x => (eHero)Enum.Parse(typeof(eHero),x[0]), x => x.ToHeroTypeConfig());
|
||||
|
||||
HeroTypeConfigs = data;
|
||||
}
|
||||
.ToImmutableDictionary(x => (eHero)Enum.Parse(typeof(eHero), x[0]), x => x.ToHeroTypeConfig());
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,10 @@ namespace OpenDiablo2.Core.GameState_
|
||||
private readonly IMPQProvider mpqProvider;
|
||||
private readonly Func<IMapEngine> getMapEngine;
|
||||
private readonly Func<eSessionType, ISessionManager> getSessionManager;
|
||||
private readonly Func<string, IRandomizedMapGenerator> getRandomizedMapGenerator;
|
||||
|
||||
private float animationTime = 0f;
|
||||
private List<MapInfo> mapInfo;
|
||||
private List<IMapInfo> mapInfo;
|
||||
private readonly List<MapCellInfo> mapDataLookup = new List<MapCellInfo>();
|
||||
private ISessionManager sessionManager;
|
||||
|
||||
@ -57,7 +58,8 @@ namespace OpenDiablo2.Core.GameState_
|
||||
ISoundProvider soundProvider,
|
||||
IMPQProvider mpqProvider,
|
||||
Func<IMapEngine> getMapEngine,
|
||||
Func<eSessionType, ISessionManager> getSessionManager
|
||||
Func<eSessionType, ISessionManager> getSessionManager,
|
||||
Func<string, IRandomizedMapGenerator> getRandomizedMapGenerator
|
||||
)
|
||||
{
|
||||
this.sceneManager = sceneManager;
|
||||
@ -69,6 +71,7 @@ namespace OpenDiablo2.Core.GameState_
|
||||
this.renderWindow = renderWindow;
|
||||
this.soundProvider = soundProvider;
|
||||
this.mpqProvider = mpqProvider;
|
||||
this.getRandomizedMapGenerator = getRandomizedMapGenerator;
|
||||
|
||||
originalMouseCursor = renderWindow.MouseCursor;
|
||||
|
||||
@ -84,7 +87,7 @@ namespace OpenDiablo2.Core.GameState_
|
||||
sessionManager.OnPlayerInfo += OnPlayerInfo;
|
||||
sessionManager.OnFocusOnPlayer += OnFocusOnPlayer;
|
||||
|
||||
mapInfo = new List<MapInfo>();
|
||||
mapInfo = new List<IMapInfo>();
|
||||
sceneManager.ChangeScene(eSceneType.Game);
|
||||
|
||||
sessionManager.JoinGame(characterName, hero);
|
||||
@ -115,76 +118,102 @@ namespace OpenDiablo2.Core.GameState_
|
||||
new MapGenerator(this).Generate();
|
||||
}
|
||||
|
||||
public int HasMap(int cellX, int cellY)
|
||||
=> mapInfo.Count(z => (cellX >= z.TileLocation.Left) && (cellX < z.TileLocation.Right)
|
||||
&& (cellY >= z.TileLocation.Top) && (cellY < z.TileLocation.Bottom));
|
||||
|
||||
public IEnumerable<Size> GetMapSizes(int cellX, int cellY)
|
||||
=> mapInfo
|
||||
.Where(z => (cellX >= z.TileLocation.Left) && (cellX < z.TileLocation.Right) && (cellY >= z.TileLocation.Top) && (cellY < z.TileLocation.Bottom))
|
||||
.Select(x => x.TileLocation.Size);
|
||||
|
||||
public MapInfo LoadSubMap(int levelDefId, Point origin, MapInfo primaryMap, int subTile = -1)
|
||||
public void RemoveEverythingAt(int cellX, int cellY)
|
||||
=> mapInfo.RemoveAll(z => (cellX >= z.TileLocation.Left) && (cellX < z.TileLocation.Right) && (cellY >= z.TileLocation.Top) && (cellY < z.TileLocation.Bottom));
|
||||
|
||||
public IMapInfo GetSubMapInfo(int levelPresetId, int levelTypeId, IMapInfo primaryMap, Point origin, int subTile = -1)
|
||||
{
|
||||
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);
|
||||
var levelPreset = engineDataManager.LevelPresets.First(x => x.Def == levelPresetId);
|
||||
var levelType = engineDataManager.LevelTypes.First(x => x.Id == levelTypeId);
|
||||
|
||||
// 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);
|
||||
if (levelPreset.File1 != "0") mapNames.Add(levelPreset.File1);
|
||||
if (levelPreset.File2 != "0") mapNames.Add(levelPreset.File2);
|
||||
if (levelPreset.File3 != "0") mapNames.Add(levelPreset.File3);
|
||||
if (levelPreset.File4 != "0") mapNames.Add(levelPreset.File4);
|
||||
if (levelPreset.File5 != "0") mapNames.Add(levelPreset.File5);
|
||||
if (levelPreset.File6 != "0") mapNames.Add(levelPreset.File6);
|
||||
|
||||
|
||||
var random = new Random(Seed + origin.X + origin.Y);
|
||||
var mapName = "data\\global\\tiles\\" + mapNames[subTile == -1 ? random.Next(mapNames.Count) : subTile].Replace("/", "\\");
|
||||
var fileData = resourceManager.GetMPQDS1(mapName, level, levelDetails, levelType);
|
||||
var fileData = resourceManager.GetMPQDS1(mapName, levelPreset, levelType);
|
||||
|
||||
var result = new MapInfo
|
||||
var result = new SubMapInfo
|
||||
{
|
||||
LevelId = eLevelId.None,
|
||||
LevelPreset = level,
|
||||
LevelDetail = levelDetails,
|
||||
LevelType = levelType,
|
||||
FileData = fileData,
|
||||
PrimaryMap = primaryMap,
|
||||
CellInfo = new Dictionary<eRenderCellType, MapCellInfo[]>(),
|
||||
TileLocation = new Rectangle(origin, new Size(fileData.Width - 1, fileData.Height - 1))
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void AddMap(IMapInfo map) => mapInfo.Add(map);
|
||||
|
||||
public IMapInfo InsertSubMap(int levelPresetId, int levelTypeId, Point origin, IMapInfo primaryMap, int subTile = -1)
|
||||
{
|
||||
var result = GetSubMapInfo(levelPresetId, levelTypeId, primaryMap, origin, subTile);
|
||||
mapInfo.Add(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public MapInfo LoadMap(eLevelId levelId, Point origin)
|
||||
public IMapInfo InsertMap(eLevelId levelId, IMapInfo parentMap = null) => InsertMap((int)levelId, new Point(0, 0), parentMap);
|
||||
|
||||
public IMapInfo InsertMap(int levelId, Point origin, IMapInfo parentMap = null)
|
||||
{
|
||||
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);
|
||||
|
||||
var levelDetails = engineDataManager.Levels.First(x => x.Id == levelId);
|
||||
|
||||
if (levelDetails.LevelPreset == null)
|
||||
{
|
||||
// There is no preset level, so we must generate one
|
||||
var generator = getRandomizedMapGenerator(levelDetails.LevelName);
|
||||
|
||||
if (generator == null)
|
||||
throw new OpenDiablo2Exception($"Could not locate a map generator for '{levelDetails.LevelName}'.");
|
||||
|
||||
generator.Generate(parentMap, origin);
|
||||
|
||||
// There is no core map so we cannot return a value here. If anyone actually uses
|
||||
// this value on a generated map they are making a terrible mistake anyway...
|
||||
return null;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (levelDetails.LevelPreset.File1 != "0") mapNames.Add(levelDetails.LevelPreset.File1);
|
||||
if (levelDetails.LevelPreset.File2 != "0") mapNames.Add(levelDetails.LevelPreset.File2);
|
||||
if (levelDetails.LevelPreset.File3 != "0") mapNames.Add(levelDetails.LevelPreset.File3);
|
||||
if (levelDetails.LevelPreset.File4 != "0") mapNames.Add(levelDetails.LevelPreset.File4);
|
||||
if (levelDetails.LevelPreset.File5 != "0") mapNames.Add(levelDetails.LevelPreset.File5);
|
||||
if (levelDetails.LevelPreset.File6 != "0") mapNames.Add(levelDetails.LevelPreset.File6);
|
||||
|
||||
|
||||
var random = new Random(Seed);
|
||||
//var mapName = "data\\global\\tiles\\" + mapNames[random.Next(mapNames.Count)].Replace("/", "\\");
|
||||
// TEMP FOR TESTING
|
||||
// TODO: ***TEMP FOR TESTING
|
||||
var mapName = "data\\global\\tiles\\" + mapNames[0].Replace("/", "\\");
|
||||
MapName = level.Name;
|
||||
Act = levelType.Act;
|
||||
MapName = levelDetails.LevelPreset.Name;
|
||||
Act = levelDetails.LevelType.Act;
|
||||
|
||||
var fileData = resourceManager.GetMPQDS1(mapName, levelDetails.LevelPreset, levelDetails.LevelType);
|
||||
|
||||
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))
|
||||
@ -192,9 +221,13 @@ namespace OpenDiablo2.Core.GameState_
|
||||
|
||||
mapInfo.Add(result);
|
||||
|
||||
soundProvider.StopSong();
|
||||
soundProvider.LoadSong(mpqProvider.GetStream(ResourcePaths.GetMusicPathForLevel(levelId)));
|
||||
soundProvider.PlaySong();
|
||||
// Only change music if loading a 'core' map
|
||||
if (Enum.IsDefined(typeof(eLevelId), levelId))
|
||||
{
|
||||
soundProvider.StopSong();
|
||||
soundProvider.LoadSong(mpqProvider.GetStream(ResourcePaths.GetMusicPathForLevel((eLevelId)levelId)));
|
||||
soundProvider.PlaySong();
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
@ -218,7 +251,10 @@ namespace OpenDiablo2.Core.GameState_
|
||||
return map.FileData.FloorLayers
|
||||
.Select(floorLayer => GetMapCellInfo(map, cellX, cellY, floorLayer.Props[idx], eRenderCellType.Floor, 0))
|
||||
.Where(x => x != null);
|
||||
|
||||
case eRenderCellType.Shadow:
|
||||
return map.FileData.ShadowLayers
|
||||
.Select(shadowLayer => GetMapCellInfo(map, cellX, cellY, shadowLayer.Props[idx], eRenderCellType.Shadow, 0))
|
||||
.Where(x => x != null);
|
||||
case eRenderCellType.WallNormal:
|
||||
case eRenderCellType.WallLower:
|
||||
case eRenderCellType.Roof:
|
||||
@ -231,11 +267,11 @@ namespace OpenDiablo2.Core.GameState_
|
||||
}
|
||||
}
|
||||
|
||||
private MapInfo GetMap(ref int cellX, ref int cellY)
|
||||
private IMapInfo 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)
|
||||
var map = mapInfo.LastOrDefault(z => (x >= z.TileLocation.X) && (y >= z.TileLocation.Y)
|
||||
&& (x < z.TileLocation.Right) && (y < z.TileLocation.Bottom));
|
||||
if (map == null)
|
||||
{
|
||||
@ -268,7 +304,7 @@ namespace OpenDiablo2.Core.GameState_
|
||||
this.SelectedItem = item;
|
||||
}
|
||||
|
||||
private MapCellInfo GetMapCellInfo(MapInfo map, int cellX, int cellY, MPQDS1TileProps props, eRenderCellType cellType, byte orientation)
|
||||
private MapCellInfo GetMapCellInfo(IMapInfo map, int cellX, int cellY, MPQDS1TileProps props, eRenderCellType cellType, byte orientation)
|
||||
{
|
||||
if (props.Prop1 == 0)
|
||||
return null;
|
||||
@ -288,8 +324,8 @@ namespace OpenDiablo2.Core.GameState_
|
||||
|
||||
if (orientation == 0)
|
||||
{
|
||||
// Floor
|
||||
if (cellType != eRenderCellType.Floor)
|
||||
// Floor or Shadow
|
||||
if (cellType != eRenderCellType.Floor && cellType != eRenderCellType.Shadow)
|
||||
{
|
||||
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
|
||||
return null;
|
||||
@ -297,9 +333,12 @@ namespace OpenDiablo2.Core.GameState_
|
||||
}
|
||||
else if (orientation == 10 || orientation == 11)
|
||||
{
|
||||
// Special tile
|
||||
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
|
||||
return null;
|
||||
if (cellType != eRenderCellType.WallNormal)
|
||||
{
|
||||
// Special tile
|
||||
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (orientation == 14)
|
||||
{
|
||||
@ -339,12 +378,14 @@ namespace OpenDiablo2.Core.GameState_
|
||||
}
|
||||
|
||||
int frame = 0;
|
||||
var tiles = (map.PrimaryMap ?? map).FileData.LookupTable
|
||||
IEnumerable<MPQDT1Tile> tiles = Enumerable.Empty<MPQDT1Tile>();
|
||||
tiles = map.FileData.LookupTable
|
||||
.Where(x => x.MainIndex == main_index && x.SubIndex == sub_index && x.Orientation == orientation)
|
||||
.Select(x => x.TileRef);
|
||||
|
||||
if (!tiles.Any())
|
||||
if (tiles == null || !tiles.Any())
|
||||
{
|
||||
log.Error($"Could not find tile [{main_index}:{sub_index}:{orientation}]!");
|
||||
map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo { Ignore = true };
|
||||
return null;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
using OpenDiablo2.Common.Models;
|
||||
|
||||
namespace OpenDiablo2.Core.Map_Engine
|
||||
{
|
||||
@ -21,137 +22,36 @@ namespace OpenDiablo2.Core.Map_Engine
|
||||
|
||||
private void GenerateAct1Town()
|
||||
{
|
||||
var townMap = gameState.LoadMap(eLevelId.Act1_Town1, new Point(0, 0));
|
||||
//var wildBorder = 5; // (4-15)
|
||||
|
||||
Rectangle bloodMooreRect;
|
||||
|
||||
// 32-37 is grassy field?
|
||||
bool westExit = false;
|
||||
bool eastExit = false;
|
||||
bool southExit = false;
|
||||
bool northExit = false;
|
||||
var townMap = gameState.InsertMap((int)eLevelId.Act1_Town1, new Point(0, 0));
|
||||
Point bloodMoorOrigin;
|
||||
|
||||
if (townMap.FileData.MapFile.Contains("S1"))
|
||||
{
|
||||
var defId = 3; // Act 1 - Town 1 Transition S
|
||||
var borderMap = gameState.LoadSubMap(defId, new Point(0, townMap.FileData.Height - 2), townMap);
|
||||
borderMap.PrimaryMap = townMap;
|
||||
var borderMap = gameState.InsertSubMap(defId, 1, new Point(0, townMap.FileData.Height - 2), townMap);
|
||||
|
||||
var wilderness = gameState.LoadSubMap(defId, new Point(26, townMap.FileData.Height + borderMap.FileData.Height - 2), townMap);
|
||||
wilderness.PrimaryMap = townMap;
|
||||
gameState.InsertSubMap(defId, 1, new Point(26, townMap.FileData.Height + borderMap.FileData.Height - 2), townMap);
|
||||
|
||||
bloodMooreRect = new Rectangle(-40, townMap.FileData.Height + borderMap.FileData.Height + 4, 120, 80);
|
||||
southExit = true;
|
||||
bloodMoorOrigin = new Point(0, townMap.FileData.Height + borderMap.FileData.Height + 4);
|
||||
}
|
||||
else if (townMap.FileData.MapFile.Contains("E1"))
|
||||
{
|
||||
var defId = 2; // Act 1 - Town 1 Transition E
|
||||
var borderMap = gameState.LoadSubMap(defId, new Point(townMap.FileData.Width - 2, 0), townMap);
|
||||
borderMap.PrimaryMap = townMap;
|
||||
var borderMap = gameState.InsertSubMap(defId, 1, new Point(townMap.FileData.Width - 2, 0), townMap);
|
||||
|
||||
bloodMooreRect = new Rectangle(townMap.FileData.Width + borderMap.FileData.Width - 4, -40, 80, 120);
|
||||
eastExit = true;
|
||||
bloodMoorOrigin = new Point(townMap.FileData.Width + borderMap.FileData.Width - 4, 0);
|
||||
}
|
||||
else if (townMap.FileData.MapFile.Contains("W1"))
|
||||
{
|
||||
// West
|
||||
bloodMooreRect = new Rectangle(-120, 0, 120, townMap.FileData.Height);
|
||||
westExit = true;
|
||||
bloodMoorOrigin = new Point(-80, 0);
|
||||
}
|
||||
else // North
|
||||
{
|
||||
bloodMooreRect = new Rectangle(0, -120, townMap.FileData.Width - 8, 120);
|
||||
northExit = true;
|
||||
bloodMoorOrigin = new Point(-22, -80); // Align along the eastern edge
|
||||
}
|
||||
|
||||
// Generate the Blood Moore?
|
||||
for (var y = 0; y < bloodMooreRect.Height; y += 8)
|
||||
{
|
||||
for (var x = 0; x < bloodMooreRect.Width; x += 8)
|
||||
{
|
||||
var px = bloodMooreRect.Left + x;
|
||||
var py = bloodMooreRect.Top + y;
|
||||
|
||||
if ((x == 0) && (y == 0)) // North West
|
||||
{
|
||||
gameState.LoadSubMap((int)eWildBorder.NorthWest, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else if ((x == bloodMooreRect.Width - 9) && (y == 0)) // North East
|
||||
{
|
||||
gameState.LoadSubMap((int)eWildBorder.NorthEast, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else if ((x == bloodMooreRect.Width - 9) && (y == bloodMooreRect.Height - 9)) // South East
|
||||
{
|
||||
if (northExit)
|
||||
{
|
||||
gameState.LoadSubMap((int)eWildBorder.RiverUpper, new Point(bloodMooreRect.Left + x, bloodMooreRect.Top + y), townMap, 0);
|
||||
}
|
||||
else gameState.LoadSubMap((int)eWildBorder.SouthEast, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else if ((x == 0) && (y == bloodMooreRect.Height - 9)) // South West
|
||||
{
|
||||
if (northExit)
|
||||
{
|
||||
gameState.LoadSubMap((int)eWildBorder.West, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else gameState.LoadSubMap((int)eWildBorder.SouthWest, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else if ((x == 0) && ((y % 8) == 0)) // West
|
||||
{
|
||||
if (westExit)
|
||||
{
|
||||
gameState.LoadSubMap((int)eWildBorder.RiverUpper, new Point(px, py), townMap, 3);
|
||||
}
|
||||
else if (eastExit)
|
||||
{
|
||||
// TODO: Transition to town
|
||||
}
|
||||
else gameState.LoadSubMap((int)eWildBorder.West, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else if ((x == bloodMooreRect.Width - 9) && ((y % 8) == 0)) // East
|
||||
{
|
||||
if (westExit)
|
||||
{
|
||||
// TODO: Transition to town
|
||||
}
|
||||
if (northExit || eastExit)
|
||||
{
|
||||
gameState.LoadSubMap((int)eWildBorder.RiverUpper, new Point(px, py), townMap, 3);
|
||||
}
|
||||
else gameState.LoadSubMap((int)eWildBorder.East, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else if (((x % 8) == 0) && (y == 0)) // North
|
||||
{
|
||||
if (southExit)
|
||||
{
|
||||
|
||||
}
|
||||
else gameState.LoadSubMap((int)eWildBorder.North, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else if (((x % 8) == 0) && (y == (bloodMooreRect.Height - 9))) // South
|
||||
{
|
||||
if (northExit)
|
||||
{
|
||||
//var tileIdx = 31; // 8x8 fill
|
||||
//gameState.LoadSubMap(tileIdx, new Point(bloodMooreRect.Left + x, bloodMooreRect.Top + y), townMap);
|
||||
}
|
||||
else gameState.LoadSubMap((int)eWildBorder.South, new Point(px, py), townMap, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((x % 8) == 0) && ((y % 8)) == 0)
|
||||
{
|
||||
var tileIdx = 31; // 8x8 fill
|
||||
gameState.LoadSubMap(tileIdx, new Point(bloodMooreRect.Left + x, bloodMooreRect.Top + y), townMap, 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
gameState.InsertMap(2 /*Wilderness 1*/, bloodMoorOrigin, townMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,9 @@
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Runtime.Caching" />
|
||||
|
@ -48,9 +48,9 @@ namespace OpenDiablo2.Core
|
||||
public MPQFont GetMPQFont(string resourcePath)
|
||||
=> cache.AddOrGetExisting($"Font::{resourcePath}", () => MPQFont.LoadFromStream(mpqProvider.GetStream($"{resourcePath}.DC6"), mpqProvider.GetStream($"{resourcePath}.tbl")));
|
||||
|
||||
public MPQDS1 GetMPQDS1(string resourcePath, LevelPreset level, LevelDetail levelDetail, LevelType levelType)
|
||||
=> cache.AddOrGetExisting($"DS1::{resourcePath}::{level}::{levelDetail}::{levelType}", ()
|
||||
=> new MPQDS1(mpqProvider.GetStream(resourcePath), level, levelDetail, levelType, engineDataManager, this) { MapFile = resourcePath });
|
||||
public MPQDS1 GetMPQDS1(string resourcePath, LevelPreset level, LevelType levelType)
|
||||
=> cache.AddOrGetExisting($"DS1::{resourcePath}::{level}::{levelType}", ()
|
||||
=> new MPQDS1(mpqProvider.GetStream(resourcePath), level, levelType, engineDataManager, this) { MapFile = resourcePath });
|
||||
|
||||
public Palette GetPalette(string paletteFile)
|
||||
=> cache.AddOrGetExisting($"Palette::{paletteFile}", () =>
|
||||
|
@ -3,5 +3,6 @@
|
||||
<package id="Autofac" version="4.8.1" targetFramework="net461" />
|
||||
<package id="log4net" version="2.0.8" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="12.0.1" targetFramework="net461" />
|
||||
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
|
||||
<package id="Xabe.FFmpeg" version="3.1.4" targetFramework="net461" />
|
||||
</packages>
|
@ -39,6 +39,9 @@
|
||||
<HintPath>..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
|
@ -2,4 +2,5 @@
|
||||
<packages>
|
||||
<package id="Autofac" version="4.8.1" targetFramework="net461" />
|
||||
<package id="log4net" version="2.0.8" targetFramework="net461" />
|
||||
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
|
||||
</packages>
|
31
OpenDiablo2.MapGenerators/AutofacModule.cs
Normal file
31
OpenDiablo2.MapGenerators/AutofacModule.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Autofac;
|
||||
using OpenDiablo2.Common.Attributes;
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
|
||||
namespace OpenDiablo2.MapGenerators
|
||||
{
|
||||
public sealed class AutofacModule : Module
|
||||
{
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
log.Info("Configuring OpenDiablo2.MapGenerators service implementations.");
|
||||
|
||||
var types = ThisAssembly.GetTypes().Where(x => typeof(IRandomizedMapGenerator).IsAssignableFrom(x) && x.IsClass);
|
||||
foreach (var type in types)
|
||||
{
|
||||
var att = type.GetCustomAttributes(true).First(x => (x is RandomizedMapAttribute)) as RandomizedMapAttribute;
|
||||
builder
|
||||
.RegisterType(type)
|
||||
.Keyed<IRandomizedMapGenerator>(att.MapName)
|
||||
.InstancePerDependency();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
288
OpenDiablo2.MapGenerators/BloodMoor.cs
Normal file
288
OpenDiablo2.MapGenerators/BloodMoor.cs
Normal file
@ -0,0 +1,288 @@
|
||||
using OpenDiablo2.Common.Attributes;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Interfaces;
|
||||
using OpenDiablo2.Common.Models;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenDiablo2.MapGenerators
|
||||
{
|
||||
[RandomizedMap("Blood Moor")]
|
||||
public sealed class BloodMoor : IRandomizedMapGenerator
|
||||
{
|
||||
private readonly IGameState gameState;
|
||||
|
||||
private readonly LevelDetail levelDetail;
|
||||
|
||||
public BloodMoor(IGameState gameState, IEngineDataManager dataManager)
|
||||
{
|
||||
this.gameState = gameState;
|
||||
|
||||
levelDetail = dataManager.Levels.First(x => x.LevelName == "Blood Moor");
|
||||
}
|
||||
|
||||
public void Generate(IMapInfo parentMap, Point location)
|
||||
{
|
||||
|
||||
// Generate the area inside of the borders
|
||||
GenerateGeneralContents(location, parentMap);
|
||||
}
|
||||
|
||||
private void GenerateGeneralContents(Point location, IMapInfo parentMap)
|
||||
{
|
||||
bool northExit = location.Y < 0;
|
||||
bool southExit = location.Y > 0;
|
||||
bool westExit = location.X < 0;
|
||||
bool eastExit = location.X > 0;
|
||||
|
||||
|
||||
if (northExit)
|
||||
{
|
||||
GenerateSouthernTownEntrance(location, parentMap);
|
||||
GenerateEasternRiver(location, parentMap);
|
||||
GenerateWesternFence(location, parentMap);
|
||||
GenerateNorthernFence(location, parentMap);
|
||||
}
|
||||
FillCenterArea(location, parentMap);
|
||||
GeneratePointsOfInterests(location, parentMap);
|
||||
|
||||
#region old code
|
||||
//for (var y = 0; y < levelDetail.SizeY; y += 8)
|
||||
//{
|
||||
// for (var x = 0; x < levelDetail.SizeX; x += 8)
|
||||
// {
|
||||
// var px = location.X + x;
|
||||
// var py = location.Y + y;
|
||||
|
||||
// if ((x == 0) && (y == 0)) // North West
|
||||
// {
|
||||
// gameState.InsertSubMap((int)eWildBorder.NorthWest, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else if ((x == levelDetail.SizeX - 8) && (y == 0)) // North East
|
||||
// {
|
||||
// gameState.InsertSubMap((int)eWildBorder.NorthEast, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else if ((x == levelDetail.SizeX - 8) && (y == levelDetail.SizeY - 8)) // South East
|
||||
// {
|
||||
// if (northExit)
|
||||
// {
|
||||
// gameState.InsertSubMap((int)eWildBorder.RiverUpper, 2, new Point(location.X + x, location.Y + y), parentMap, 0);
|
||||
// }
|
||||
// else gameState.InsertSubMap((int)eWildBorder.SouthEast, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else if ((x == 0) && (y == levelDetail.SizeY - 8)) // South West
|
||||
// {
|
||||
// if (northExit)
|
||||
// {
|
||||
// gameState.InsertSubMap((int)eWildBorder.West, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else gameState.InsertSubMap((int)eWildBorder.SouthWest, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else if ((x == 0) && ((y % 8) == 0)) // West
|
||||
// {
|
||||
// if (westExit)
|
||||
// {
|
||||
// gameState.InsertSubMap((int)eWildBorder.RiverUpper, 2, new Point(px, py), parentMap, 3);
|
||||
// }
|
||||
// else if (eastExit)
|
||||
// {
|
||||
// // TODO: Transition to town
|
||||
// }
|
||||
// else gameState.InsertSubMap((int)eWildBorder.West, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else if ((x == levelDetail.SizeX - 8) && ((y % 8) == 0)) // East
|
||||
// {
|
||||
// if (westExit)
|
||||
// {
|
||||
// // TODO: Transition to town
|
||||
// }
|
||||
// if (northExit || eastExit)
|
||||
// {
|
||||
// gameState.InsertSubMap((int)eWildBorder.RiverUpper, 2, new Point(px, py), parentMap, 3);
|
||||
// }
|
||||
// else gameState.InsertSubMap((int)eWildBorder.East, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else if (((x % 8) == 0) && (y == 0)) // North
|
||||
// {
|
||||
// if (southExit)
|
||||
// {
|
||||
|
||||
// }
|
||||
// else gameState.InsertSubMap((int)eWildBorder.North, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else if (((x % 8) == 0) && (y == (levelDetail.SizeY - 8))) // South
|
||||
// {
|
||||
// if (northExit)
|
||||
// {
|
||||
// //var tileIdx = 31; // 8x8 fill
|
||||
// //gameState.InsertSubMap(tileIdx, new Point(bloodMooreRect.Left + x, bloodMooreRect.Top + y), townMap);
|
||||
// }
|
||||
// else gameState.InsertSubMap((int)eWildBorder.South, 2, new Point(px, py), parentMap, 0);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
|
||||
// //if (((x % 8) == 0) && ((y % 8)) == 0)
|
||||
// //{
|
||||
// // var tileIdx = 31; // 8x8 fill
|
||||
// // gameState.InsertSubMap(tileIdx, 2, new Point(px, py), parentMap, 0);
|
||||
// //}
|
||||
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
#endregion
|
||||
}
|
||||
|
||||
private void GenerateNorthernFence(Point location, IMapInfo parentMap)
|
||||
{
|
||||
|
||||
for (var x = location.X + 8; x < location.X + 64; x += 8)
|
||||
{
|
||||
gameState.InsertSubMap((int)eWildBorder.North, 2, new Point(x, location.Y), parentMap, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateWesternFence(Point location, IMapInfo parentMap)
|
||||
{
|
||||
gameState.InsertSubMap((int)eWildBorder.NorthWest, 2, new Point(location.X, location.Y), parentMap, 0);
|
||||
|
||||
for (var y = location.Y + 8; y < location.Y + 72; y += 8)
|
||||
{
|
||||
gameState.InsertSubMap((int)eWildBorder.West, 2, new Point(location.X, y), parentMap, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateEasternRiver(Point location, IMapInfo parentMap)
|
||||
{
|
||||
for (var y = location.Y + 8; y < location.Y + 72; y += 8)
|
||||
{
|
||||
gameState.InsertSubMap(26 /* River Upper */, 2, new Point(location.X + 62, y), parentMap, 3);
|
||||
gameState.InsertSubMap(27 /* River Lower */, 2, new Point(location.X + 70, y), parentMap, 3);
|
||||
}
|
||||
|
||||
// River near town
|
||||
gameState.InsertSubMap(26 /* River Upper */, 2, new Point(location.X + 62, location.Y + 72), parentMap, 2);
|
||||
gameState.InsertSubMap(27 /* River Lower */, 2, new Point(location.X + 70, location.Y + 72), parentMap, 2);
|
||||
|
||||
// River near the back
|
||||
gameState.InsertSubMap(26 /* River Upper */, 2, new Point(location.X + 62, location.Y), parentMap, 1);
|
||||
gameState.InsertSubMap(27 /* River Lower */, 2, new Point(location.X + 70, location.Y), parentMap, 1);
|
||||
}
|
||||
|
||||
private void GenerateSouthernTownEntrance(Point location, IMapInfo parentMap)
|
||||
{
|
||||
var random = new Random(gameState.Seed + location.X + location.Y);
|
||||
for (var x = location.X; x < location.X + 64; x += 8)
|
||||
{
|
||||
if (x == location.X) // Bottom left of the map
|
||||
gameState.InsertSubMap((int)eWildBorder.ClosedBoxBottomLeft, 2, new Point(x, location.Y + 72), parentMap);
|
||||
else if (x == location.X + 48) // Town exit
|
||||
gameState.InsertSubMap((int)eWildBorder.South, 2, new Point(x, location.Y + 72), parentMap, 3);
|
||||
else // Everything else
|
||||
gameState.InsertSubMap((int)eWildBorder.South, 2, new Point(x, location.Y + 72), parentMap, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void GeneratePointsOfInterests(Point location, IMapInfo parentMap)
|
||||
{
|
||||
var random = new Random(gameState.Seed + location.X + location.Y);
|
||||
|
||||
// Generate the cave
|
||||
while (true)
|
||||
{
|
||||
var rx = random.Next(8, levelDetail.SizeX - 16);
|
||||
var ry = random.Next(8, levelDetail.SizeY - 16);
|
||||
rx -= (rx % 8);
|
||||
ry -= (ry % 8);
|
||||
var caveX = rx + location.X;
|
||||
var caveY = ry + location.Y;
|
||||
/*
|
||||
// Don't generate a camp on something that's already generated
|
||||
var loc = gameState.GetMapSizes(caveX, caveY).First();
|
||||
|
||||
if (loc.Width != 8 || loc.Height != 8)
|
||||
continue;
|
||||
|
||||
gameState.RemoveEverythingAt(caveX, caveY);
|
||||
*/
|
||||
gameState.InsertSubMap(52/*cave entrance*/, 2, new Point(caveX, caveY), parentMap);
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate camps
|
||||
var campsToGenerate = 3;
|
||||
while (campsToGenerate > 0)
|
||||
{
|
||||
var rx = random.Next(8, levelDetail.SizeX - 16);
|
||||
var ry = random.Next(8, levelDetail.SizeY - 16);
|
||||
rx -= (rx % 8);
|
||||
ry -= (ry % 8);
|
||||
var campX = rx + location.X;
|
||||
var campY = ry + location.Y;
|
||||
/*
|
||||
// Don't generate a camp on something that's already generated
|
||||
var loc = gameState.GetMapSizes(campX, campY).First();
|
||||
|
||||
if (loc.Width != 8 || loc.Height != 8)
|
||||
continue;
|
||||
|
||||
gameState.RemoveEverythingAt(campX, campY);
|
||||
*/
|
||||
|
||||
if (gameState.HasMap(campX, campY) > 1)
|
||||
continue;
|
||||
|
||||
gameState.InsertSubMap(random.Next(42, 43 + 1), 2, new Point(campX, campY), parentMap);
|
||||
campsToGenerate--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int[] tileFillIds = new int[] { 29, 30, 31, 38, 39, 40, 41 };
|
||||
private void FillCenterArea(Point location, IMapInfo parentMap)
|
||||
{
|
||||
var rightEdge = levelDetail.SizeX - 8;
|
||||
var bottomEdge = levelDetail.SizeY - 8;
|
||||
|
||||
for (var y = 8; y < bottomEdge; y += 8)
|
||||
{
|
||||
for (var x = 8; x < rightEdge; x += 8)
|
||||
{
|
||||
var px = location.X + x;
|
||||
var py = location.Y + y;
|
||||
|
||||
// If this space is already filled, move on
|
||||
if (gameState.HasMap(px, py) > 0)
|
||||
continue;
|
||||
|
||||
// Generate filler
|
||||
var random = new Random(gameState.Seed + location.X + location.Y + x + y);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var tileIdx = tileFillIds[random.Next(0, tileFillIds.Count())];
|
||||
var info = gameState.GetSubMapInfo(tileIdx, 2, parentMap, new Point(location.X + x, location.Y + y));
|
||||
|
||||
// Make sure this tile actually fits here
|
||||
if (info.TileLocation.Right > (location.X + rightEdge) || info.TileLocation.Bottom > (location.Y + bottomEdge))
|
||||
continue;
|
||||
|
||||
if (info.TileLocation.Width == 16 && gameState.HasMap(px + 8, py) > 0)
|
||||
continue;
|
||||
|
||||
if (info.TileLocation.Height == 16 && gameState.HasMap(px, py + 8) > 0)
|
||||
continue;
|
||||
|
||||
// We found a tile that fits, so add it
|
||||
gameState.AddMap(info);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
OpenDiablo2.MapGenerators/OpenDiablo2.MapGenerators.csproj
Normal file
69
OpenDiablo2.MapGenerators/OpenDiablo2.MapGenerators.csproj
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{A3370223-A28B-45B8-AD79-C17EAD99AF36}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>OpenDiablo2.MapGenerators</RootNamespace>
|
||||
<AssemblyName>OpenDiablo2.MapGenerators</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Autofac, Version=4.8.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Autofac.4.8.1\lib\net45\Autofac.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AutofacModule.cs" />
|
||||
<Compile Include="BloodMoor.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenDiablo2.Common\OpenDiablo2.Common.csproj">
|
||||
<Project>{b743160e-a0bb-45dc-9998-967a85e50562}</Project>
|
||||
<Name>OpenDiablo2.Common</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
36
OpenDiablo2.MapGenerators/Properties/AssemblyInfo.cs
Normal file
36
OpenDiablo2.MapGenerators/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("OpenDiablo2.MapGenerators")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("OpenDiablo2.MapGenerators")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a3370223-a28b-45b8-ad79-c17ead99af36")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
6
OpenDiablo2.MapGenerators/packages.config
Normal file
6
OpenDiablo2.MapGenerators/packages.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Autofac" version="4.8.1" targetFramework="net461" />
|
||||
<package id="log4net" version="2.0.8" targetFramework="net461" />
|
||||
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
|
||||
</packages>
|
@ -62,7 +62,7 @@
|
||||
<Compile Include="SDL2Font.cs" />
|
||||
<Compile Include="SDL2Label.cs" />
|
||||
<Compile Include="SDL2MouseCursor.cs" />
|
||||
<Compile Include="SDL2MusicProvider.cs" />
|
||||
<Compile Include="SDL2SoundProvider.cs" />
|
||||
<Compile Include="SDL2RenderWindow.cs" />
|
||||
<Compile Include="SDL2Sprite.cs" />
|
||||
<Compile Include="SDL2Texture.cs" />
|
||||
|
@ -41,6 +41,8 @@ namespace OpenDiablo2.SDL2_
|
||||
return;
|
||||
|
||||
musicChannel = SDL_mixer.Mix_PlayChannel(-1, music, 1);
|
||||
//SDL_mixer.Mix_Volume(musicChannel, 64); // TODO: Customizable volume
|
||||
|
||||
}
|
||||
|
||||
public void LoadSong(Stream data)
|
||||
@ -79,7 +81,9 @@ namespace OpenDiablo2.SDL2_
|
||||
return -1;
|
||||
|
||||
var sound = SDL_mixer.Mix_QuickLoad_WAV(data);
|
||||
return SDL_mixer.Mix_PlayChannel(-1, sound, 0);
|
||||
var channel = SDL_mixer.Mix_PlayChannel(-1, sound, 0);
|
||||
//SDL_mixer.Mix_Volume(channel, 64); // TODO: Customizable volume
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void StopSfx(int channel)
|
@ -34,6 +34,9 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
@ -48,6 +51,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenDiablo2.Common\OpenDiablo2.Common.csproj">
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenDiablo2.Common.Enums;
|
||||
using OpenDiablo2.Common.Models;
|
||||
using OpenDiablo2.Core;
|
||||
@ -152,7 +153,7 @@ namespace OpenDiablo2.TestConsole
|
||||
}
|
||||
string path = words[0];
|
||||
string output = "public enum eLevelId\r\n{\r\nNone,\r\n";
|
||||
output += ELevelIdHelper.GenerateEnum(EngineDataMan.LevelPresets);
|
||||
output += ELevelIdHelper.GenerateEnum(EngineDataMan.Levels.Select(x => x.LevelPreset).Distinct().ToList());
|
||||
output += "}";
|
||||
File.WriteAllText(path, output);
|
||||
Console.WriteLine("Wrote eLevelIds enum to " + path + ".");
|
||||
|
4
OpenDiablo2.TestConsole/packages.config
Normal file
4
OpenDiablo2.TestConsole/packages.config
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
|
||||
</packages>
|
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2036
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28315.86
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2", "OpenDiablo2\OpenDiablo2.csproj", "{2B0CF1AC-06DD-4322-AE8B-FF8A8C70A3CD}"
|
||||
EndProject
|
||||
@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2.ServiceBus", "O
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2.GameServer", "OpenDiablo2.GameServer\OpenDiablo2.GameServer.csproj", "{C29A84E8-E708-4BE2-9946-202899B68E19}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDiablo2.MapGenerators", "OpenDiablo2.MapGenerators\OpenDiablo2.MapGenerators.csproj", "{A3370223-A28B-45B8-AD79-C17EAD99AF36}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@ -73,6 +75,10 @@ Global
|
||||
{C29A84E8-E708-4BE2-9946-202899B68E19}.Debug|x64.Build.0 = Debug|x64
|
||||
{C29A84E8-E708-4BE2-9946-202899B68E19}.Release|x64.ActiveCfg = Release|x64
|
||||
{C29A84E8-E708-4BE2-9946-202899B68E19}.Release|x64.Build.0 = Release|x64
|
||||
{A3370223-A28B-45B8-AD79-C17EAD99AF36}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A3370223-A28B-45B8-AD79-C17EAD99AF36}.Debug|x64.Build.0 = Debug|x64
|
||||
{A3370223-A28B-45B8-AD79-C17EAD99AF36}.Release|x64.ActiveCfg = Release|x64
|
||||
{A3370223-A28B-45B8-AD79-C17EAD99AF36}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -106,6 +106,10 @@
|
||||
<Project>{c29a84e8-e708-4be2-9946-202899b68e19}</Project>
|
||||
<Name>OpenDiablo2.GameServer</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\OpenDiablo2.MapGenerators\OpenDiablo2.MapGenerators.csproj">
|
||||
<Project>{a3370223-a28b-45b8-ad79-c17ead99af36}</Project>
|
||||
<Name>OpenDiablo2.MapGenerators</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\OpenDiablo2.Scenes\OpenDiablo2.Scenes.csproj">
|
||||
<Project>{05224fe7-293f-4184-b1d6-89f5171b60e0}</Project>
|
||||
<Name>OpenDiablo2.Scenes</Name>
|
||||
|
@ -118,6 +118,12 @@ namespace OpenDiablo2
|
||||
return (itemContainerType) => componentContext.Resolve<IItemContainer>(new NamedParameter("itemContainerLayout", ItemContainerLayout.Values[itemContainerType]));
|
||||
});
|
||||
|
||||
containerBuilder.Register<Func<string, IRandomizedMapGenerator>>(c =>
|
||||
{
|
||||
var componentContext = c.Resolve<IComponentContext>();
|
||||
return (levelName) => componentContext.ResolveKeyed<IRandomizedMapGenerator>(levelName);
|
||||
});
|
||||
|
||||
/* Uncomment the below if we support multiple textbox types
|
||||
containerBuilder.Register<Func<TextBox>>(c =>
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user