//Inserts a smaller scenes nav grid into a larger grid. private void InsertSceneGridIntoMultiSceneGrid(ref byte[,] Grid, Scene scene, int offsetx, int offsety) { byte[,] smallgrid = scene.NavMesh.WalkGrid; for (int X = 0; X < scene.NavMesh.SquaresCountX; X++) { for (int Y = 0; Y < scene.NavMesh.SquaresCountY; Y++) { Grid[X + offsetx, Y + offsety] = smallgrid[X, Y]; } } }
public List<Vector3D> FindPath(Actor actor, Vector3D Start, Vector3D Destination) { _baseX = 0; _baseY = 0; // reset to 0 // Should only be null first time a path is requested. if (_curScene == null) { _curScene = actor.CurrentScene; if(!listOfPathFinderInstances.TryGetValue(_curScene.SceneSNO.Id,out mPathFinder)) // Attempts to pull the pathfinder which matches the scenes SNO from the patherlist { mPathFinder = new PathFinderFast(_curScene.NavMesh.WalkGrid); // Create a new pather, using the current scenes grid. listOfPathFinderInstances.TryAdd(_curScene.SceneSNO.Id, mPathFinder); // add it to our patherlist, with the SNO as key. } InitPathFinder(); } // Checks if our path start location is inside current scene, if it isnt, we reset curScene and set mPathfinder to the corrent grid. if (!_curScene.Bounds.IntersectsWith(new System.Windows.Rect(Start.X, Start.Y, 1, 1))) { _curScene = actor.CurrentScene;// TODO- THIS CAN RETURN PARENT RATHER THAN SUBSCENE - DarkLotus if (!listOfPathFinderInstances.TryGetValue(_curScene.SceneSNO.Id, out mPathFinder)) { mPathFinder = new PathFinderFast(_curScene.NavMesh.WalkGrid); listOfPathFinderInstances.TryAdd(_curScene.SceneSNO.Id, mPathFinder); } InitPathFinder(); } _baseX = _curScene.Position.X; //Our base location for working out world > SceneLocal coordinates. _baseY = _curScene.Position.Y; // Path's start and destination are both in same scene. if (_curScene.Bounds.IntersectsWith(new System.Windows.Rect(Destination.X, Destination.Y, 1, 1))) { _destScene = _curScene; } else { //Builds a new grid on the fly containing both the start and destination scenes. This is not really optimal, but its a trade off. // Keeping grids Scene based means they can be used cross game even when laid out different in a seperate world. This keeps memory usage down substantially. // Also limited to a max distance of scene > scene. Again this keeps memory usage low. _destScene = _curScene.World.QuadTree.Query<Scene>(new System.Windows.Rect(Destination.X, Destination.Y, 1, 1)).FirstOrDefault(); mPathFinder = new PathFinderFast(BuildOutOfSceneGrid(_curScene, _destScene, ref _baseX, ref _baseY)); InitPathFinder(); } //2.5f is because Scene navmesh's are based on 96x96 for a 240x240 scene - Darklotus _startSceneLocal.X = (int)((Start.X - _baseX) / 2.5f); _startSceneLocal.Y = (int)((Start.Y - _baseY) / 2.5f); _destinationSceneLocal.X = (int)((Destination.X - _baseX) / 2.5f); _destinationSceneLocal.Y = (int)((Destination.Y - _baseY) / 2.5f); //Possibily add a check to ensure start/dest local coords are valid. Unneeded so far. nodePathList = mPathFinder.FindPath(_startSceneLocal, _destinationSceneLocal); // The actual pathfind request, the path is found here. vectorPathList.Clear(); // Clear the previous path. if (nodePathList == null) { //TODO: Sometimes Mobs are require to spawn outside current walkable boundaries, with the current implementation //Pathfinder is unable to return a valid path if the mob is outside this boundaries. //This is just a hackish way to force a path over the mob. Logger.Debug("Pathfinding forced hack activated due Mob outside walkable area"); vectorPathList.Insert(0, new Vector3D(Destination.X,Destination.Y,Destination.Z)); return vectorPathList; }// No Path Found. if (nodePathList.Count < 1) { return vectorPathList; } // Safety net Incase start/dest are the same. for (int i = 0; i < nodePathList.Count; i++) { // Convert the path into world coordinates for use in Movement. // TODO Objectpool maybe? vectorPathList.Insert(0, new Vector3D(nodePathList[i].X * 2.5f + _baseX, nodePathList[i].Y * 2.5f + _baseY, 0)); } //new System.Threading.Thread(c => System.Windows.Forms.Application.Run(new PatherDebug.PatherDebug(actor, vectorPathList))).Start(); return vectorPathList; }
public static World Generate(Game game, int worldSNO) { if (!MPQStorage.Data.Assets[SNOGroup.Worlds].ContainsKey(worldSNO)) { Logger.Error("Can't find a valid world definition for sno: {0}", worldSNO); return(null); } var worldAsset = MPQStorage.Data.Assets[SNOGroup.Worlds][worldSNO]; var worldData = (Mooege.Common.MPQ.FileFormats.World)worldAsset.Data; if (worldData.IsGenerated) { Logger.Error("World {0} [{1}] is a dynamic world! Can't generate dynamic worlds yet!", worldAsset.Name, worldAsset.SNOId); return(null); } var world = new World(game, worldSNO); var levelAreas = new Dictionary <int, List <Scene> >(); // Create a clusterID => Cluster Dictionary var clusters = new Dictionary <int, Mooege.Common.MPQ.FileFormats.SceneCluster>(); foreach (var cluster in worldData.SceneClusterSet.SceneClusters) { clusters[cluster.ClusterId] = cluster; } // Scenes are not aligned to (0, 0) but apparently need to be -farmy float minX = worldData.SceneParams.SceneChunks.Min(x => x.PRTransform.Vector3D.X); float minY = worldData.SceneParams.SceneChunks.Min(x => x.PRTransform.Vector3D.Y); // Count all occurences of each cluster /fasbat var clusterCount = new Dictionary <int, int>(); foreach (var sceneChunk in worldData.SceneParams.SceneChunks) { var cID = sceneChunk.SceneSpecification.ClusterID; if (cID != -1 && clusters.ContainsKey(cID)) // Check for wrong clusters /fasbat { if (!clusterCount.ContainsKey(cID)) { clusterCount[cID] = 0; } clusterCount[cID]++; } } // For each cluster generate a list of randomly selected subcenes /fasbat var clusterSelected = new Dictionary <int, List <Mooege.Common.MPQ.FileFormats.SubSceneEntry> >(); foreach (var cID in clusterCount.Keys) { var selected = new List <Mooege.Common.MPQ.FileFormats.SubSceneEntry>(); clusterSelected[cID] = selected; var count = clusterCount[cID]; foreach (var group in clusters[cID].SubSceneGroups) // First select from each subscene group /fasbat { for (int i = 0; i < group.I0 && count > 0; i++, count--) //TODO Rename I0 to requiredCount? /fasbat { var subSceneEntry = RandomHelper.RandomItem(group.Entries, entry => entry.Probability); selected.Add(subSceneEntry); } if (count == 0) { break; } } while (count > 0) // Fill the rest with defaults /fasbat { var subSceneEntry = RandomHelper.RandomItem(clusters[cID].Default.Entries, entry => entry.Probability); selected.Add(subSceneEntry); count--; } } foreach (var sceneChunk in worldData.SceneParams.SceneChunks) { var position = sceneChunk.PRTransform.Vector3D - new Vector3D(minX, minY, 0); var scene = new Scene(world, position, sceneChunk.SNOHandle.Id, null) { MiniMapVisibility = SceneMiniMapVisibility.Revealed, RotationW = sceneChunk.PRTransform.Quaternion.W, RotationAxis = sceneChunk.PRTransform.Quaternion.Vector3D, SceneGroupSNO = -1 }; // If the scene has a subscene (cluster ID is set), choose a random subscenes from the cluster load it and attach it to parent scene /farmy if (sceneChunk.SceneSpecification.ClusterID != -1) { if (!clusters.ContainsKey(sceneChunk.SceneSpecification.ClusterID)) { Logger.Warn("Referenced clusterID {0} not found for chunk {1} in world {2}", sceneChunk.SceneSpecification.ClusterID, sceneChunk.SNOHandle.Id, worldSNO); } else { var entries = clusterSelected[sceneChunk.SceneSpecification.ClusterID]; // Select from our generated list /fasbat Mooege.Common.MPQ.FileFormats.SubSceneEntry subSceneEntry = null; if (entries.Count > 0) { //subSceneEntry = entries[RandomHelper.Next(entries.Count - 1)]; subSceneEntry = RandomHelper.RandomItem <Mooege.Common.MPQ.FileFormats.SubSceneEntry>(entries, entry => 1); // TODO Just shuffle the list, dont random every time. /fasbat entries.Remove(subSceneEntry); } else { Logger.Error("No SubScenes defined for cluster {0} in world {1}", sceneChunk.SceneSpecification.ClusterID, world.DynamicID); } Vector3D pos = FindSubScenePosition(sceneChunk); // TODO According to BoyC, scenes can have more than one subscene, so better enumerate over all subscenepositions /farmy if (pos == null) { Logger.Error("No scene position marker for SubScenes of Scene {0} found", sceneChunk.SNOHandle.Id); } else { var subScenePosition = scene.Position + pos; var subscene = new Scene(world, subScenePosition, subSceneEntry.SNOScene, scene) { MiniMapVisibility = SceneMiniMapVisibility.Revealed, RotationW = sceneChunk.PRTransform.Quaternion.W, RotationAxis = sceneChunk.PRTransform.Quaternion.Vector3D, Specification = sceneChunk.SceneSpecification }; scene.Subscenes.Add(subscene); subscene.LoadMarkers(); } } } scene.Specification = sceneChunk.SceneSpecification; scene.LoadMarkers(); // add scene to level area dictionary foreach (var levelArea in scene.Specification.SNOLevelAreas) { if (levelArea != -1) { if (!levelAreas.ContainsKey(levelArea)) { levelAreas.Add(levelArea, new List <Scene>()); } levelAreas[levelArea].Add(scene); } } } loadLevelAreas(levelAreas, world); return(world); }
// Builds a 2x2 grid containing the start/dest location hopefully. If start/dest are further apart the grid will not contain both. // This does not take into account subscenes - needs to be fixed - DarkLotus private byte[,] BuildOutOfSceneGrid(Scene s1, Scene s2, ref float basex, ref float basey) { // This really isnt optimal but its worked in my test cases, only alternative i could think was loading the entire world into a grid, but thats 4k x 4k and would require duplicating as each world is random - DarkLotus if (s1.SceneSNO.Id == s2.SceneSNO.Id) { return s1.NavMesh.WalkGrid; } //Logger.Debug("Start scene " + s1.SceneSNO.Name + " dest scene " + s2.SceneSNO.Name); byte[,] grid = new byte[256, 256]; // should use 512,512 as there is a scene larger than 128x128. -DarkLotus //Work out if start or dest scene has lowest X/Y to use as our 0,0 for our new 2x2 scene grid. if (s1.Position.X < s2.Position.X) { basex = s1.Position.X; } else if (s1.Position.X >= s2.Position.X) { basex = s2.Position.X; } if (s1.Position.Y < s2.Position.Y) { basey = s1.Position.Y; } else if (s1.Position.Y >= s2.Position.Y) { basey = s2.Position.Y; } foreach (var s in s1.World.QuadTree.Query<Scene>(new Circle(basex + 5, basey + 5, 1f))) { //Logger.Debug("Inserting Scene: " + s.SceneSNO.Name + " at offset: 0/0"); InsertSceneGridIntoMultiSceneGrid(ref grid, s, 0, 0); } foreach (var s in s1.World.QuadTree.Query<Scene>(new Circle(basex + (float)s1.Size.Width + 10, basey + 10, 1f))) { //Logger.Debug("Inserting Scene: " + s.SceneSNO.Name + " at offset: " + s1.Size.Width + "/0"); InsertSceneGridIntoMultiSceneGrid(ref grid, s, (int)(s1.Size.Width / 2.5), 0); } foreach (var s in s1.World.QuadTree.Query<Scene>(new Circle(basex + 10, basey + (float)s1.Size.Height + 10, 1f))) { //Logger.Debug("Inserting Scene: " + s.SceneSNO.Name + " at offset: 0/" + s1.Size.Width); InsertSceneGridIntoMultiSceneGrid(ref grid, s, 0, (int)(s1.Size.Height / 2.5)); } foreach (var s in s1.World.QuadTree.Query<Scene>(new Circle(basex + (float)s1.Size.Width + 10, basey + (float)s1.Size.Height + 10, 1f))) { //Logger.Debug("Inserting Scene: " + s.SceneSNO.Name + " at offset: " + s1.Size.Width + "/" + s1.Size.Height); InsertSceneGridIntoMultiSceneGrid(ref grid, s, (int)(s1.Size.Width / 2.5), (int)(s1.Size.Height / 2.5)); } return grid; }
private Scene CreateScene(Identifier iden, World world, Scene parent) { int i = 0; Scene scene = new Scene(world, iden.GetInt(i++).Value, parent); scene.MiniMapVisibility = 2; if (!SNODatabase.Instance.IsOfGroup(scene.SceneSNO, SNOGroup.Scenes)) { Logger.Warn("SceneSNO {0} doesn't appear to be a valid SNO ID..", scene.SceneSNO); } if (parent != null) parent.Subscenes.Add(scene); scene.SceneSpec = new SceneSpecification { CellZ = iden.GetInt(i++).Value, Cell = new IVector2D { X = iden.GetInt(i++).Value, Y = iden.GetInt(i++).Value }, arSnoLevelAreas = new int[4] { iden.GetInt(i++).Value, iden.GetInt(i++).Value, iden.GetInt(i++).Value, iden.GetInt(i++).Value }, snoPrevWorld = iden.GetInt(i++).Value, Field4 = iden.GetInt(i++).Value, snoPrevLevelArea = iden.GetInt(i++).Value, snoNextWorld = iden.GetInt(i++).Value, Field7 = iden.GetInt(i++).Value, snoNextLevelArea = iden.GetInt(i++).Value, snoMusic = iden.GetInt(i++).Value, snoCombatMusic = iden.GetInt(i++).Value, snoAmbient = iden.GetInt(i++).Value, snoReverb = iden.GetInt(i++).Value, snoWeather = iden.GetInt(i++).Value, snoPresetWorld = iden.GetInt(i++).Value, Field15 = iden.GetInt(i++).Value, Field16 = iden.GetInt(i++).Value, Field17 = iden.GetInt(i++).Value, Field18 = iden.GetInt(i++).Value, tCachedValues = new SceneCachedValues { Field0 = iden.GetInt(i++).Value, Field1 = iden.GetInt(i++).Value, Field2 = iden.GetInt(i++).Value, Field3 = new AABB { Min = new Vector3D { X = iden.GetFloat(i++).Value, Y = iden.GetFloat(i++).Value, Z = iden.GetFloat(i++).Value }, Max = new Vector3D { X = iden.GetFloat(i++).Value, Y = iden.GetFloat(i++).Value, Z = iden.GetFloat(i++).Value }, }, Field4 = new AABB { Min = new Vector3D { X = iden.GetFloat(i++).Value, Y = iden.GetFloat(i++).Value, Z = iden.GetFloat(i++).Value }, Max = new Vector3D { X = iden.GetFloat(i++).Value, Y = iden.GetFloat(i++).Value, Z = iden.GetFloat(i++).Value }, }, Field5 = new int[4] { iden.GetInt(i++).Value, iden.GetInt(i++).Value, iden.GetInt(i++).Value, iden.GetInt(i++).Value }, Field6 = iden.GetInt(i++).Value }, }; scene.RotationAxis.X = iden.GetFloat(i++).Value; scene.RotationAxis.Y = iden.GetFloat(i++).Value; scene.RotationAxis.Z = iden.GetFloat(i++).Value; scene.RotationAmount = iden.GetFloat(i++).Value; scene.Position.X = iden.GetFloat(i++).Value; scene.Position.Y = iden.GetFloat(i++).Value; scene.Position.Z = iden.GetFloat(i++).Value; scene.SceneGroupSNO = iden.GetInt(i++).Value; //scene.AppliedLabels = new int[0]; return scene; }
public static World Generate(Game game, int worldSNO) { if (!MPQStorage.Data.Assets[SNOGroup.Worlds].ContainsKey(worldSNO)) { Logger.Error("Can't find a valid world definition for sno: {0}", worldSNO); return null; } var worldAsset = MPQStorage.Data.Assets[SNOGroup.Worlds][worldSNO]; var worldData = (Mooege.Common.MPQ.FileFormats.World)worldAsset.Data; if (worldData.IsGenerated) { Logger.Error("World {0} [{1}] is a dynamic world! Can't generate proper dynamic worlds yet!", worldAsset.Name, worldAsset.SNOId); GenerateRandomDungeon(worldSNO, worldData); } var world = new World(game, worldSNO); var levelAreas = new Dictionary<int, List<Scene>>(); // Create a clusterID => Cluster Dictionary var clusters = new Dictionary<int, Mooege.Common.MPQ.FileFormats.SceneCluster>(); foreach (var cluster in worldData.SceneClusterSet.SceneClusters) clusters[cluster.ClusterId] = cluster; // Scenes are not aligned to (0, 0) but apparently need to be -farmy float minX = worldData.SceneParams.SceneChunks.Min(x => x.PRTransform.Vector3D.X); float minY = worldData.SceneParams.SceneChunks.Min(x => x.PRTransform.Vector3D.Y); // Count all occurences of each cluster /fasbat var clusterCount = new Dictionary<int, int>(); foreach (var sceneChunk in worldData.SceneParams.SceneChunks) { var cID = sceneChunk.SceneSpecification.ClusterID; if (cID != -1 && clusters.ContainsKey(cID)) // Check for wrong clusters /fasbat { if (!clusterCount.ContainsKey(cID)) clusterCount[cID] = 0; clusterCount[cID]++; } } // For each cluster generate a list of randomly selected subcenes /fasbat var clusterSelected = new Dictionary<int, List<Mooege.Common.MPQ.FileFormats.SubSceneEntry>>(); foreach (var cID in clusterCount.Keys) { var selected = new List<Mooege.Common.MPQ.FileFormats.SubSceneEntry>(); clusterSelected[cID] = selected; var count = clusterCount[cID]; foreach (var group in clusters[cID].SubSceneGroups) // First select from each subscene group /fasbat { for (int i = 0; i < group.I0 && count > 0; i++, count--) //TODO Rename I0 to requiredCount? /fasbat { var subSceneEntry = RandomHelper.RandomItem(group.Entries, entry => entry.Probability); selected.Add(subSceneEntry); } if (count == 0) break; } while (count > 0) // Fill the rest with defaults /fasbat { var subSceneEntry = RandomHelper.RandomItem(clusters[cID].Default.Entries, entry => entry.Probability); selected.Add(subSceneEntry); count--; } } foreach (var sceneChunk in worldData.SceneParams.SceneChunks) { var position = sceneChunk.PRTransform.Vector3D - new Vector3D(minX, minY, 0); var scene = new Scene(world, position, sceneChunk.SNOHandle.Id, null) { MiniMapVisibility = true, RotationW = sceneChunk.PRTransform.Quaternion.W, RotationAxis = sceneChunk.PRTransform.Quaternion.Vector3D, SceneGroupSNO = -1 }; // If the scene has a subscene (cluster ID is set), choose a random subscenes from the cluster load it and attach it to parent scene /farmy if (sceneChunk.SceneSpecification.ClusterID != -1) { if (!clusters.ContainsKey(sceneChunk.SceneSpecification.ClusterID)) { Logger.Warn("Referenced clusterID {0} not found for chunk {1} in world {2}", sceneChunk.SceneSpecification.ClusterID, sceneChunk.SNOHandle.Id, worldSNO); } else { var entries = clusterSelected[sceneChunk.SceneSpecification.ClusterID]; // Select from our generated list /fasbat Mooege.Common.MPQ.FileFormats.SubSceneEntry subSceneEntry = null; if (entries.Count > 0) { //subSceneEntry = entries[RandomHelper.Next(entries.Count - 1)]; subSceneEntry = RandomHelper.RandomItem<Mooege.Common.MPQ.FileFormats.SubSceneEntry>(entries, entry => 1); // TODO Just shuffle the list, dont random every time. /fasbat entries.Remove(subSceneEntry); } else Logger.Error("No SubScenes defined for cluster {0} in world {1}", sceneChunk.SceneSpecification.ClusterID, world.DynamicID); Vector3D pos = FindSubScenePosition(sceneChunk); // TODO According to BoyC, scenes can have more than one subscene, so better enumerate over all subscenepositions /farmy if (pos == null) { Logger.Error("No scene position marker for SubScenes of Scene {0} found", sceneChunk.SNOHandle.Id); } else { var subScenePosition = scene.Position + pos; var subscene = new Scene(world, subScenePosition, subSceneEntry.SNOScene, scene) { MiniMapVisibility = true, RotationW = sceneChunk.PRTransform.Quaternion.W, RotationAxis = sceneChunk.PRTransform.Quaternion.Vector3D, Specification = sceneChunk.SceneSpecification }; scene.Subscenes.Add(subscene); subscene.LoadMarkers(); } } } scene.Specification = sceneChunk.SceneSpecification; scene.LoadMarkers(); // add scene to level area dictionary foreach (var levelArea in scene.Specification.SNOLevelAreas) { if (levelArea != -1) { if (!levelAreas.ContainsKey(levelArea)) levelAreas.Add(levelArea, new List<Scene>()); levelAreas[levelArea].Add(scene); } } } loadLevelAreas(levelAreas, world); return world; }
// Removing public void RemoveScene(Scene obj) { if (obj.DynamicID == 0 || !HasScene(obj.DynamicID)) throw new Exception(String.Format("Object has an invalid ID or was not present (ID = {0})", obj.DynamicID)); this.Scenes.Remove(obj.DynamicID); //this.Scenes.Remove(obj); }
private int SceneSorter(Scene x, Scene y) { if (x.World.DynamicID != y.World.DynamicID) return unchecked((int)x.World.DynamicID) - unchecked((int)y.World.DynamicID); if (x.ParentChunkID != y.ParentChunkID) return unchecked((int)x.ParentChunkID) - unchecked((int)y.ParentChunkID); return 0; }
public Scene(World world, int sceneSNO, Scene parent) : base(world, world.NewSceneID) { this.Scale = 1.0f; this.RotationAmount = 0.0f; this.Subscenes = new List<Scene>(); this.SceneSNO = sceneSNO; this.Parent = parent; this.AppliedLabels = new int[0]; this.World.AddScene(this); }
// Adding public void AddScene(Scene obj) { if (obj.DynamicID == 0 || HasScene(obj.DynamicID)) throw new Exception(String.Format("Object has an invalid ID or was already present (ID = {0})", obj.DynamicID)); this.Scenes.Add(obj.DynamicID, obj); //this.Scenes.Add(obj); }
/// <summary> /// Removes given scene from world. /// </summary> /// <param name="scene">The scene to remove.</param> public void RemoveScene(Scene scene) { if (scene.DynamicID == 0 || !HasScene(scene.DynamicID)) throw new Exception(String.Format("Object has an invalid ID or was not present (ID = {0})", scene.DynamicID)); Scene remotedScene; this.Scenes.TryRemove(scene.DynamicID, out remotedScene); // remove it from scenes collection. this.QuadTree.Remove(scene); // remove from quad-tree too. }
/// <summary> /// Adds given scene to world. /// </summary> /// <param name="scene">The scene to add.</param> public void AddScene(Scene scene) { if (scene.DynamicID == 0 || HasScene(scene.DynamicID)) throw new Exception(String.Format("Object has an invalid ID or was already present (ID = {0})", scene.DynamicID)); this.Scenes.TryAdd(scene.DynamicID, scene); // add to scenes collection. this.QuadTree.Insert(scene); // add it to quad-tree too. }
private int SceneSorter(Scene x, Scene y) { if (x.SceneData.WorldID != y.SceneData.WorldID) return x.SceneData.WorldID - y.SceneData.WorldID; if (x.SceneData.ParentChunkID != y.SceneData.ParentChunkID) return x.SceneData.ParentChunkID - y.SceneData.ParentChunkID; return 0; }
public void AddScene(string Line) { string[] data = Line.Split(' '); int SceneID=int.Parse(data[46]); Scene s = GetScene(SceneID); if (s != null) return; s = new Scene(); s.ID = SceneID; s.SceneData = new RevealSceneMessage(data.Skip(2).ToArray(),WorldID); Scenes.Add(s); }
/// <summary> /// Creates a new scene and adds it to given world. /// </summary> /// <param name="world">The parent world.</param> /// <param name="position">The position.</param> /// <param name="snoId">SNOId for the scene.</param> /// <param name="parent">The parent scene if any.</param> public Scene(World world, Vector3D position, int snoId, Scene parent) : base(world, world.NewSceneID) { this.SNOId = snoId; this.Parent = parent; this.Subscenes = new List<Scene>(); this.Scale = 1.0f; this.AppliedLabels = new int[0]; this.LoadSceneData(); // load data from mpqs. this.Position = position; this.Bounds = new Rect(this.Position.X, this.Position.Y, this.NavZone.V0.X * this.NavZone.Float0, this.NavZone.V0.Y * this.NavZone.Float0); // the scene bounds. this.World.AddScene(this); // add scene to the world. }