namespace DarkWynter.Engine.Init { #region Using Statements using System; using System.Xml; using System.Diagnostics; using System.Threading; using System.Collections.Generic; using System.IO; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; #endregion using Audio; using Globals; using ObjectLib; using Init; using GameObjects; /// /// The base class used in the XML layer of the architecture. /// XML loads several configuration files, parses their main structure, and stores the nodes in public variables that are accessed by the rest of the program. /// public static class XML { /// /// Content check boolean. If content is loaded, set to true. /// public static bool contentInstalled = true; /// /// Gets the current working directory for file access /// /// public static String GetWorkingDirectory() { String curDir = Directory.GetCurrentDirectory(); // String workDir = curDir.Substring(0, curDir.IndexOf("bin\\x86\\Debug")); return curDir; } #region GameObjectTypes /// /// Contains all the Type definitions for GameObjects /// public static List gameObjectTypes; /// /// Create an GameObject using the "type" string included in the XmlNode. /// User-Defined types can be added to the engine by inheriting from GameObjectTypes /// and overloading it's CreateGameobjectType method. This method must create a new /// GameObject and assign it to the incoming GameObject. Creation of the GameObject /// by the overloaded User-Defined class should use a case statement to decide what /// kind of GameObject to create based on the Xml-based "type" parameter. /// /// A blank GameObject to replace with User-Defined GameObject. /// Returns true if GameObject was successfully created. public static bool CreateGameObjectType(ref GameObject gameObject) { // Loop through engine and game layer types for (int i = 0; i < gameObjectTypes.Count; i++) { // Try and create the gameObject bool found = gameObjectTypes[i].CreateGameObjectType(ref gameObject); if (found) { return true; } } return false; } #endregion #region User Preferences /// /// Loads xml System settings from SystemSettings.xml. /// public static void LoadUserPreferences() { try { // Load physics, music, and fog XmlDocument reader = new XmlDocument(); reader.Load("_xml/UserSettings/UserSettings.xml"); XmlNodeList allNodes = reader.ChildNodes; foreach (XmlNode settingsNode in allNodes) { if (settingsNode.Name == "SystemSettings") { XmlNodeList settingsNodes = settingsNode.ChildNodes; foreach (XmlNode node in settingsNodes) { if (node.Name == "EnableShadowMap1") { string value = node.Attributes["value"].Value; if (value == "Yes") { Statics_Engine.SystemSettings.enableShadowMap1 = true; } else { Statics_Engine.SystemSettings.enableShadowMap1 = false; } } else if (node.Name == "EnableShadowMap2") { string value = node.Attributes["value"].Value; if (value == "Yes") { Statics_Engine.SystemSettings.enableShadowMap2 = true; } else { Statics_Engine.SystemSettings.enableShadowMap2 = false; } } else if (node.Name == "EnableTerrainBumpMapping") { string value = node.Attributes["value"].Value; if (value == "Yes") { Statics_Engine.SystemSettings.enableTerrainBumpMapping = true; } else { Statics_Engine.SystemSettings.enableTerrainBumpMapping = false; } } else if (node.Name == "EnableTerrainMultiTexturing") { string value = node.Attributes["value"].Value; if (value == "Yes") { Statics_Engine.SystemSettings.enableTerrainMultiTexturing = true; } else { Statics_Engine.SystemSettings.enableTerrainMultiTexturing = false; } } else if (node.Name == "NumberOfTerrainTextures") { int value = int.Parse(node.Attributes["value"].Value); if (value == 4) { Statics_Engine.SystemSettings.numberOfTerrainTextures = 4; } else if (value == 3) { Statics_Engine.SystemSettings.numberOfTerrainTextures = 3; } else { Statics_Engine.SystemSettings.numberOfTerrainTextures = 2; } } else if (node.Name == "SingleLightSource") { string value = node.Attributes["value"].Value; if (value == "Yes") { Statics_Engine.SystemSettings.singleLightSource = true; } else { Statics_Engine.SystemSettings.singleLightSource = false; } } else if (node.Name == "MusicEnabled") { string value = node.Attributes["value"].Value; if (value == "Yes") { Statics_Engine.SystemSettings.music = true; } else { Statics_Engine.SystemSettings.music = false; } } else if (node.Name == "SoundEffects") { string value = node.Attributes["value"].Value; if (value == "Yes") { Statics_Engine.SystemSettings.soundFX = true; } else { Statics_Engine.SystemSettings.soundFX = false; } } } } } } catch { XML.contentInstalled = false; System.Diagnostics.Debug.WriteLine("Error reading xml"); //throw new Exception("Error reading XML"); } } /// /// Saves xml System settings in SystemSettings.xml. /// public static void SaveUserPreferences() { XmlTextWriter settingsFile = new XmlTextWriter( "_xml/UserSettings/UserSettings.xml", null); settingsFile.Formatting = Formatting.Indented; settingsFile.WriteStartDocument(); settingsFile.WriteStartElement("SystemSettings"); settingsFile.WriteStartElement("EnableShadowMap1"); if (Statics_Engine.SystemSettings.enableShadowMap1) { settingsFile.WriteAttributeString("value", "Yes"); } else { settingsFile.WriteAttributeString("value", "No"); } settingsFile.WriteEndElement(); settingsFile.WriteStartElement("EnableShadowMap2"); if (Statics_Engine.SystemSettings.enableShadowMap2) { settingsFile.WriteAttributeString("value", "Yes"); } else { settingsFile.WriteAttributeString("value", "No"); } settingsFile.WriteEndElement(); settingsFile.WriteStartElement("EnableTerrainBumpMapping"); if (Statics_Engine.SystemSettings.enableTerrainBumpMapping) { settingsFile.WriteAttributeString("value", "Yes"); } else { settingsFile.WriteAttributeString("value", "No"); } settingsFile.WriteEndElement(); settingsFile.WriteStartElement("EnableTerrainMultiTexturing"); if (Statics_Engine.SystemSettings.enableTerrainMultiTexturing) { settingsFile.WriteAttributeString("value", "Yes"); } else { settingsFile.WriteAttributeString("value", "No"); } settingsFile.WriteEndElement(); settingsFile.WriteStartElement("NumberOfTerrainTextures"); if (Statics_Engine.SystemSettings.numberOfTerrainTextures == 4) { settingsFile.WriteAttributeString("value", "4"); } else if (Statics_Engine.SystemSettings.numberOfTerrainTextures == 3) { settingsFile.WriteAttributeString("value", "3"); } else { settingsFile.WriteAttributeString("value", "2"); } settingsFile.WriteEndElement(); settingsFile.WriteStartElement("SingleLightSource"); if (Statics_Engine.SystemSettings.singleLightSource) { settingsFile.WriteAttributeString("value", "Yes"); } else { settingsFile.WriteAttributeString("value", "No"); } settingsFile.WriteEndElement(); settingsFile.WriteStartElement("MusicEnabled"); if (Statics_Engine.SystemSettings.music) { settingsFile.WriteAttributeString("value", "Yes"); } else { settingsFile.WriteAttributeString("value", "No"); } settingsFile.WriteEndElement(); settingsFile.WriteStartElement("SoundEffects"); if (Statics_Engine.SystemSettings.soundFX) { settingsFile.WriteAttributeString("value", "Yes"); } else { settingsFile.WriteAttributeString("value", "No"); } settingsFile.WriteEndElement(); settingsFile.WriteEndElement(); settingsFile.WriteEndDocument(); settingsFile.Flush(); settingsFile.Close(); } #endregion #region Player Data /// /// Contains the name, modelPath, texturePath, bumpTexturePath, /// and scale information for a character. /// public struct ModelInfo { /// /// User friendly name of character. /// public string name; /// /// Path to model file. /// public string modelPath; /// /// Path to texture file. /// public string texPath; /// /// Path to bump texture file. /// public string bumpPath; /// /// Model scale. /// public Vector3 scale; /// /// Model animated or not /// public bool animated; } /// /// List of instantiations of the PlayerInfo struct, contained in PlayerModels.xml. /// public static List playerInfo; /// /// Loads availible Players from PlayerInfo.xml and stores them in the PlayerInfo list. /// public static void LoadPlayerIndex() { /// This is wrong and hardcoded - need to go back and make it so that it uses the level that it is on version of the /// characters on the board - bad commentary I know /// JASON!!!! HELP PLEASE ;-) string playerXMLFile = "_xml/LevelEdit/" + levelInfo[Statics_Engine.PlayerSettings.PlayerLevelIndexLoad].name + ".xml"; List modelNames = new List(); playerInfo = new List(); int index = 0; //setup the player scrolling //GameMenuImageScroller scroller = (GameMenuImageScroller) menuSystem.playerSetup.GetMenu().GetMenuElement(0); //scroller.Clear(); try { // Load physics, music, and fog XmlDocument reader = new XmlDocument(); reader.Load(playerXMLFile); XmlNodeList allNodes = reader.ChildNodes; foreach (XmlNode playerNode in allNodes) { if (playerNode.Name == "CharacterModels") { XmlNodeList playerNodes = playerNode.ChildNodes; foreach (XmlNode node in playerNodes) { if (node.Name == "Model") { ModelInfo player = new ModelInfo(); player.name = node.Attributes["name"].Value; modelNames.Add(player.name); player.modelPath = node.Attributes["model"].Value; player.texPath = node.Attributes["texture"].Value; player.bumpPath = node.Attributes["bumpTexture"].Value; player.scale = new Vector3(float.Parse(node.Attributes["maxScale"].Value)); string value = node.Attributes["animated"].Value; if (value == "Yes") { player.animated = true; } else { player.animated = false; } playerInfo.Add(player); index++; //scroller.AddNew(player.name, // Statics.SystemSettings.content.Load("Content/_textures/patient" + index), // Statics.SystemSettings.content.Load("Content/_textures/patient" + index)); } } } } } catch { System.Diagnostics.Debug.WriteLine("Error reading xml"); throw new Exception("Error reading XML"); } } #endregion #region Level Data public static string levelName; public static string locationMapName; public static float vertMapToLocMapRelate; public static float terrainModWidth; /// /// Contains the name, description, and filepath for each level. /// public struct LevelInfo { /// /// User friendly name for level. /// public string name; /// /// User friendly description for level. /// public string description; /// /// Filepath of the level xml, which contains all xml data for that level. /// public string filepath; } /// /// List of availible levels contained in _Levels.xml /// public static List levelInfo; /// /// Current level index /// public static int levelInfoIndex = 0; /// /// All nodes contained in the currently loaded level xml file /// public static XmlNode levelNodes; /// /// Environment settings include level size and other dependent parameters /// We set these here to eliminate load-order dependencies in load sequence. /// public static List environmentProperties; /// /// Xml Data defining Engine Environment Info /// public static List soloObjects; /// /// Contains all GameObject instances before Load /// public static List locationMapObjects; /// /// Loads availible Levels from _Levels.xml and stores them in the LevelInfo list. /// public static void LoadLevelIndex() { string LevelXMLFile = "_xml/LevelEdit/_Levels.xml"; levelInfo = new List(); try { // Load physics, music, and fog XmlDocument reader = new XmlDocument(); reader.Load(LevelXMLFile); XmlNodeList allNodes = reader.ChildNodes; foreach (XmlNode levelNode in allNodes) { if (levelNode.Name == "levels") { XmlNodeList levelNodes = levelNode.ChildNodes; foreach (XmlNode node in levelNodes) { if (node.Name == "level") { LevelInfo level = new LevelInfo(); level.name = node.Attributes["name"].Value; level.filepath = node.Attributes["xmlFile"].Value; level.description = node.Attributes["description"].Value; levelInfo.Add(level); } } } } } catch { XML.contentInstalled = false; System.Diagnostics.Debug.WriteLine("Error reading xml"); //throw new Exception("Error reading XML"); } } /// /// Uses information from the selected LevelInfo node to load an xml file that describes the level. /// Each node is parsed from the main structure and stored in the GameObjectInfo struct. /// GameObjects then access these nodes to load themselves. /// /// Xml level description file stored in LevelInfo node. public static void LoadLevel(string xmlFileName) { // (Re) Initialize LevelNodes if (locationMapObjects != null) locationMapObjects.Clear(); locationMapObjects = new List(); // Read the Level File try { XmlDocument reader = new XmlDocument(); String fileLocation = xmlFileName; reader.Load(fileLocation); // Get all outer nodes (incl xml version info and level) XmlNodeList allNodes = reader.ChildNodes; foreach (XmlNode levelNode in allNodes) { // If level definition if (levelNode.Name == "level") { levelNodes = levelNode; // Parse Level environmentProperties = LoadEnvironment(levelNode); LoadProperties(levelNode); soloObjects = LoadObjects_Indiv(levelNode); locationMapObjects = LoadObjects_LocationMap(levelNode); } } } catch { System.Diagnostics.Debug.WriteLine("Error reading xml: " + xmlFileName); // throw new Exception("Error reading XML"); } // Start Game Timer Statics_Engine.LevelSettings.gameTimer = new Stopwatch(); Statics_Engine.LevelSettings.gameTimer.Start(); } private static void LoadProperties(XmlNode levelNode) { // Get Level and LocationMap names levelName = levelNode.Attributes["name"].Value; locationMapName = levelNode.Attributes["locationMap"].Value; // Cycle through XmlNodes for (int loadCount = 0; loadCount < levelNode.ChildNodes.Count; loadCount++) { XmlNode node = levelNode.ChildNodes[loadCount]; if (node.Name == "Terrain") { Texture2D terrain = Statics_Engine.SystemSettings.content.Load(node.Attributes["heightmap"].Value); Statics_Engine.TerrainSettings.vertexMapSize = terrain.Width; } } // Calculate the vertexmap/locationmap ratio for use in the for loop below vertMapToLocMapRelate = Statics_Engine.TerrainSettings.vertexMapSize / float.Parse(levelNode.Attributes["locationMapSize"].Value); // Create a ruler 1 terrain mod long (distance between verticies terrainModWidth = Statics_Engine.TerrainSettings.terrainScaleFactor * vertMapToLocMapRelate; } private static List LoadEnvironment(XmlNode levelNode) { List properties = new List(); // Cycle through XmlNodes for (int loadCount = 0; loadCount < levelNode.ChildNodes.Count; loadCount++) { XmlNode node = levelNode.ChildNodes[loadCount]; // Audio if (node.Name == "Music") { Audio.LoadXML(node); } // Dimensions else if (node.Name == "Dimensions") { Statics_Engine.TerrainSettings.terrainScaleFactor = int.Parse(node.Attributes["scale"].Value); } // Physics else if (node.Name == "Physics") { Statics_Engine.GameSettings.accelDueToGravity = new Vector3(0.0f, Statics_Engine.GameSettings.gravityForce, 0.0f); Statics_Engine.GameSettings.gravityForce = float.Parse(node.Attributes["gravity"].Value); Statics_Engine.LevelSettings.TERRAIN_FRICTION = float.Parse(node.Attributes["friction"].Value); } // Fog else if (node.Name == "Fog") { Statics_Engine.LevelSettings.fogDensity = float.Parse(node.Attributes["density"].Value); Statics_Engine.LevelSettings.fogStart = float.Parse(node.Attributes["startfog"].Value); Statics_Engine.LevelSettings.fogEnd = float.Parse(node.Attributes["endfog"].Value); Statics_Engine.LevelSettings.fogColor[0] = float.Parse(node.Attributes["red"].Value); Statics_Engine.LevelSettings.fogColor[1] = float.Parse(node.Attributes["green"].Value); Statics_Engine.LevelSettings.fogColor[2] = float.Parse(node.Attributes["blue"].Value); Statics_Engine.LevelSettings.fogColor[3] = float.Parse(node.Attributes["alpha"].Value); } } return properties; } private static List LoadObjects_Indiv(XmlNode levelNode) { List gameObjects = new List(); // Check each Object Node for a match for (int nodeCount = 0; nodeCount < levelNode.ChildNodes.Count; nodeCount++) { XmlNode node = levelNode.ChildNodes[nodeCount]; // If Node contains x,y,z coordinates if (node.Attributes != null && node.Attributes["x"] != null && node.Attributes["z"] != null) { // Get the Node's color value float x = float.Parse(node.Attributes["x"].Value); float y = 255.0f; float z = float.Parse(node.Attributes["z"].Value); float w = 255.0f; // Clone node to get a new pointer XmlNode cloneNode = node.Clone(); // Create Object or continue GameObject gameObject = new GameObject(new Load(cloneNode, new Vector4(x, y, z, w))); if (!CreateGameObjectType(ref gameObject)) { continue; } // Read by ObjectLibrary::Load gameObjects.Add(gameObject); } } return gameObjects; } private static List LoadObjects_LocationMap(XmlNode levelNode) { List gameObjects = new List(); // Linearize pixels in location map Texture2D locationMap = Statics_Engine.SystemSettings.content.Load(locationMapName); Color[] pixels = new Color[locationMap.Width * locationMap.Width]; locationMap.GetData(pixels); // Process Pixels from LocationMap for (int pixelCount = 0; pixelCount < pixels.Length; pixelCount++) { Color currentPixel = pixels[pixelCount]; // Skip this pixel if blank, or empty if (currentPixel == Color.Black || currentPixel == Color.White) continue; // Check each Object Node for a match for (int nodeCount = 0; nodeCount < levelNode.ChildNodes.Count; nodeCount++) { // If node contains r,g,b coordinates if (levelNode.ChildNodes[nodeCount].Attributes != null && levelNode.ChildNodes[nodeCount].Attributes["red"] != null && levelNode.ChildNodes[nodeCount].Attributes["green"] != null && levelNode.ChildNodes[nodeCount].Attributes["blue"] != null) { // Get the Node's color value float r = float.Parse(levelNode.ChildNodes[nodeCount].Attributes["red"].Value); float g = float.Parse(levelNode.ChildNodes[nodeCount].Attributes["green"].Value); float b = float.Parse(levelNode.ChildNodes[nodeCount].Attributes["blue"].Value); // If Node color matches Pixel... if (r == currentPixel.R && g == currentPixel.G && b == currentPixel.B) { // Get 2D Position from 1D array // Y is set during GameObject.Load() Vector4 startPosition = new Vector4(((int)pixelCount / locationMap.Width) * terrainModWidth, 0.0f, (pixelCount % locationMap.Width) * terrainModWidth, 0.0f); // Get Node XmlNode cloneNode = levelNode.ChildNodes[nodeCount].Clone(); // Create Object or continue GameObject gameObject = new GameObject(new Load(cloneNode, startPosition)); if (!CreateGameObjectType(ref gameObject)) { continue; } // Read by ObjectLibrary::Load gameObjects.Add(gameObject); break; } } } } return gameObjects; } #endregion #region Survey Data /// /// G2L Pre, Post, and Survey list /// public static List SurveyList; /// /// Loads xml System settings from WhileLoopsPrePostSurvey.xml. /// public static void LoadSurvey(string fileName) { SurveyList = new List(); try { // Load physics, music, and fog XmlDocument reader = new XmlDocument(); reader.Load(fileName); XmlNodeList allNodes = reader.ChildNodes; foreach (XmlNode settingsNode in allNodes) { if (settingsNode.Name == "QuestionSet") { XmlNodeList settingsNodes = settingsNode.ChildNodes; foreach (XmlNode node in settingsNodes) { if (node.Name == "ProblemSet") { SurveyList.Add(node); } } } } } catch { System.Diagnostics.Debug.WriteLine("Error reading xml"); throw new Exception("Error reading XML"); } } #endregion #region G2L Challenges /// /// Contains all the quest instructions for a particular quest /// public static List ChallengeNodes; // G2L Stuff - can be converted later public static void LoadQuestInfo() { // Read the Quest File try { ChallengeNodes = new List(); XmlDocument reader = new XmlDocument(); String fileLocation = "_xml/QuestSettings/WhileLoops.xml"; reader.Load(fileLocation); // Get all outer nodes (incl xml version info and level) XmlNodeList allNodes = reader.ChildNodes; foreach (XmlNode questNode in allNodes) { // If level definition if (questNode.Name == "QuestSet") { foreach (XmlNode problemSetNode in questNode) { // Post problems for GameForm to access if (problemSetNode.Name == "ProblemSet") { ChallengeNodes.Add(problemSetNode); } } } } } catch { System.Diagnostics.Debug.WriteLine("Error reading xml"); //throw new Exception("Error reading XML"); } } #endregion } }