//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkWynter.Engine.Utilities { #region Using Statements using System; using System.Collections.Generic; 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; using System.Diagnostics; #endregion using Globals; using Physics; using ObjectLib; using GameObjects; public class TerrainModRequest { public float modValue; public int modRadius; public Enums_Engine.TerrainModType type; public Vector3 startPos; public Vector3 endPos; public Vector3 blockLength; public Vector3 iterator; public Vector3 direction; public Vector3 perpVector; public float numberOfSteps; public Vector3 currPosition; public float currentStep=0; public int keyTimer = 0; public Stopwatch stopWatch; public TerrainModRequest(int timer, float modificationValue, Vector3 startingPosition,Vector3 endingPosition, int modificationRadius, Enums_Engine.TerrainModType blendType) { keyTimer = timer; modValue = modificationValue; startPos = startingPosition; currPosition = startingPosition; endPos = endingPosition; modRadius = modificationRadius; type = blendType; direction = (endingPosition - startingPosition); direction.Normalize(); Vector3 upVector = direction + new Vector3(0, 1, 0); perpVector = Vector3.Cross(direction, upVector); blockLength = new Vector3(modRadius+1, modRadius+1, modRadius+1); Vector3 itor = (endingPosition - startingPosition) / blockLength; numberOfSteps = itor.Length(); blockLength *= direction; stopWatch = new Stopwatch(); stopWatch.Start(); } /// /// /// /// /// /// public Vector3 calculatePosition() { currPosition += blockLength; currentStep++; return currPosition; } } /// /// MajikWand allows the user to look at and grab both terrain and standard GameObjects. /// It is the basis of our terrainMod algorithm, and is being expanded to something like a "gravity-gun". /// public class MajikWand { List activeRequests = new List(); List undoRequests = new List(); public static int activeRequestCount = 0; public void Update(ObjectLibrary objectLibrary) { for (int i = 0; i < activeRequests.Count; i++) { if (activeRequests[i].currentStep > activeRequests[i].numberOfSteps) { DarkWynterEngine.majikWand.undoRequests.Add(activeRequests[i]); activeRequests.RemoveAt(i); continue; } // If elapsed time has passed if ((float)activeRequests[i].keyTimer < activeRequests[i].stopWatch.ElapsedMilliseconds) { // Reset timer activeRequests[i].stopWatch.Reset(); activeRequests[i].stopWatch.Start(); // Get current modification position based on ___ Vector3 currPos = activeRequests[i].calculatePosition(); // Update currPos using timer objectLibrary.terrain.ModifyTerrain(activeRequests[i].modValue, currPos, activeRequests[i].modRadius, activeRequests[i].type); // Play audio for each human foreach (Player player in DarkWynter.Engine.DarkWynterEngine.objectLibrary.humans) { if (player.IsAlive()) { DarkWynter.Engine.Audio.Audio.Play3D_LoopTrack( new DarkWynter.Engine.Audio.Cue3D( "TerrainMod"), activeRequests[i].startPos * Statics_Engine.TerrainSettings.terrainScaleFactor, player.mass.currentPosition); } } } } activeRequestCount = activeRequests.Count; } /// /// Raise or lower the terrain where the player is looking. /// /// Amount to modify terrain height. /// We need the Terrain and Players. public static void TerrainMod(TerrainModRequest request) { // ============== ??Move this function to ObjLib?? ================ DarkWynterEngine.majikWand.activeRequests.Add(request); } public static void ReverseTerrainMod(int value) { if (DarkWynterEngine.majikWand.undoRequests.Count != 0) { TerrainModRequest reverseRequest = DarkWynterEngine.majikWand.undoRequests [DarkWynterEngine.majikWand.undoRequests.Count - 1]; // Reset itor and start pos reverseRequest.currPosition = reverseRequest.startPos; reverseRequest.currentStep = 0; // Set height to zero reverseRequest.modValue = value; MajikWand.TerrainMod(reverseRequest); } } /// /// Get the terrain point that the majikwand is pointing at. /// /// Object Library contains the terrain. /// Player that owns the majikwand. /// Target point on terrain public Vector3 LookAtTerrainPoint(ObjectLibrary objectLibrary, Player player) { Vector3 playerPosition = new Vector3(); Vector3 lastTempPosition = new Vector3(-1.0f); Vector3 lookDirection = new Vector3(); Vector3 finalPoint = new Vector3(-1.0f); lookDirection = player.mass.normalVector + Vector3.Zero; // Get copies of the current position and normal vector playerPosition = player.mass.currentPosition + Vector3.Zero; // Reset target object player.targetObject = Enums_Engine.ObjectType.NONE; // Increment a ray until the Y value projects beneath the surface of the terrain. Then get the closest vertex by flooring the X and Z // values for (int i = 0; i < Statics_Engine.PlayerSettings.TERRAIN_MOD_RANGE; i++) { playerPosition += lookDirection; // Bounds checking if (playerPosition.X < 0 || playerPosition.X >= Statics_Engine.TerrainSettings.collisionMapSize || playerPosition.Z >= Statics_Engine.TerrainSettings.collisionMapSize || playerPosition.Z < 0) { continue; } lastTempPosition = playerPosition; // Check if the current search Y point is below the corresponding Y in collision height data if (playerPosition.Y < objectLibrary.terrain.GetTerrainHeight((int)playerPosition.X / Statics_Engine.TerrainSettings.terrainScaleFactor, (int)playerPosition.Z / Statics_Engine.TerrainSettings.terrainScaleFactor)) { // Store the values in the vector and set targetObject player.targetObject = Enums_Engine.ObjectType.TERRAIN; finalPoint.X = (int)(playerPosition.X / Statics_Engine.TerrainSettings.terrainScaleFactor); finalPoint.Z = (int)(playerPosition.Z / Statics_Engine.TerrainSettings.terrainScaleFactor); finalPoint.Y = objectLibrary.terrain.GetTerrainHeight((int)playerPosition.X / Statics_Engine.TerrainSettings.terrainScaleFactor, (int)playerPosition.Z / Statics_Engine.TerrainSettings.terrainScaleFactor); if (player.terrainModEnabled) { if (player.terrainModTarget == Vector3.Zero) { player.terrainModTarget = finalPoint; } else { finalPoint = player.terrainModTarget; } } return finalPoint; } } // We didn't find any matching point if (finalPoint.X < 0) { // Check if the player is looking downwards if (lookDirection.Y < 0.2f) { // Ensure that the last position is non-negative if (lastTempPosition.X > 0) { // Set target object and values in the vector player.targetObject = Enums_Engine.ObjectType.TERRAIN; finalPoint.X = (int)(lastTempPosition.X / Statics_Engine.TerrainSettings.terrainScaleFactor); finalPoint.Z = (int)(lastTempPosition.Z / Statics_Engine.TerrainSettings.terrainScaleFactor); finalPoint.Y = objectLibrary.terrain.GetTerrainHeight((int)lastTempPosition.X / Statics_Engine.TerrainSettings.terrainScaleFactor, (int)lastTempPosition.Z / Statics_Engine.TerrainSettings.terrainScaleFactor); } } } if (player.terrainModEnabled) { if (player.terrainModTarget == Vector3.Zero) { player.terrainModTarget = finalPoint; } else { finalPoint = player.terrainModTarget; } } return finalPoint; } /// /// Get the terrain point that the majikwand is pointing at. /// /// Object Library contains the terrain. /// Player that owns the majikwand. /// Object currently being targeted public Vector3 LookAtObject(ObjectLibrary objectLibrary, Player player) { Vector3 tempPosition = new Vector3(); Vector3 lastTempPosition = new Vector3(-1.0f); Vector3 lookDirection = new Vector3(); Vector3 finalPoint = new Vector3(-1.0f); // Get copies of the current position and normal vector tempPosition = player.mass.currentPosition + Vector3.Zero; lookDirection = player.mass.normalVector + Vector3.Zero; // Reset target object player.targetObject = Enums_Engine.ObjectType.NONE; //Statics.lookupMapTemp.GetCollisionObjects( // Increment a ray until the Y value projects beneath the surface of the terrain. Then get the closest vertex by flooring the X and Z // values for (int i = 0; i < Statics_Engine.PlayerSettings.TERRAIN_MOD_RANGE; i++) { tempPosition += lookDirection; // Bounds checking if (tempPosition.X < 0 || tempPosition.X >= Statics_Engine.TerrainSettings.collisionMapSize || tempPosition.Z >= Statics_Engine.TerrainSettings.collisionMapSize || tempPosition.Z < 0) { continue; } lastTempPosition = tempPosition; LinkedList massList = new LinkedList(); // Statics.lookupMap.GetListXZ((int)tempPosition.X / Statics.TerrainSettings.terrainScaleFactor, // (int)tempPosition.Z / Statics.TerrainSettings.terrainScaleFactor); // Check the lookup map to see if it has any information stored for that location if (massList.Count != 0) { // We have hit something, based on the object id set the targetObject to the correct type and store the object index (in the // lookup map) in one of the three vector components int j = 0; // Parse through the particles we have found foreach (Mass testMass in massList) { if (testMass != null && testMass.gameObjectPointer != null) { // Check if the particle position and the current search position match (or are close) if (Vector3.Distance(testMass.currentPosition, tempPosition) <= testMass.boundingVolume.radius) { player.targetObject = testMass.objectType; // Store the X, Z value and the index from the lookupmap in the vector and return it finalPoint = new Vector3(tempPosition.X, (float)j, tempPosition.Z); return finalPoint; } } j++; } } //check for players foreach (Player otherPlayer in objectLibrary.humans) { if (otherPlayer.IsAlive() && otherPlayer != player) { // Check if the player's position and the current search position match (or are close) if (Vector3.Distance(otherPlayer.mass.currentPosition, tempPosition) <= otherPlayer.mass.boundingVolume.radius) { player.targetObject = otherPlayer.mass.objectType; // Store the X, Z value and the index of the player in the vector and return it finalPoint = new Vector3(tempPosition.X, (float)otherPlayer.playerIndex, tempPosition.Z); return finalPoint; } } } foreach (Player otherPlayer in objectLibrary.bots) { if (otherPlayer.IsAlive()) { // Check if the player's position and the current search position match (or are close) if (Vector3.Distance(otherPlayer.mass.currentPosition, tempPosition) <= otherPlayer.mass.boundingVolume.radius) { player.targetObject = otherPlayer.mass.objectType; // Store the X, Z value and the index of the player in the vector and return it finalPoint = new Vector3(tempPosition.X, (float)otherPlayer.playerIndex, tempPosition.Z); return finalPoint; } } } // Check if the current search Y point is below the corresponding Y in collision height data if (tempPosition.Y < objectLibrary.terrain.GetTerrainHeight((int)tempPosition.X / Statics_Engine.TerrainSettings.terrainScaleFactor, (int)tempPosition.Z / Statics_Engine.TerrainSettings.terrainScaleFactor)) { // We have hit the terrain and not found any objects, so return -1 return new Vector3(-1.0f); } } // We didn't find any objects in our range so return -1 return new Vector3(-1.0f); } } }