//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// 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.engine.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.engine.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.engine.majikWand.activeRequests.Add(request);
}
public static void ReverseTerrainMod(int value)
{
if (DarkWynterEngine.engine.majikWand.undoRequests.Count != 0)
{
TerrainModRequest reverseRequest = DarkWynterEngine.engine.majikWand.undoRequests
[DarkWynterEngine.engine.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);
}
}
}