//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkMatterEngine.GameObjects { #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.Xml; using System.Diagnostics; using Xclna.Xna.Animation; #endregion using Physics; using Globals; using ObjectLibrary; using Xml; using Utilities; using Audio; using Controllers; using Weapons; /// /// Player Is Hit... /// public struct Hit { public Vector3 POI; // Point of impact storage public int type; // Type of hit public Quaternion pitchyaw; // Pitch and Yaw public float step; // Steps in the animation } public class Player : GameObject { #region Attributes protected bool fireElementSelected = false; // Player using fire protected bool waterElementSelected = false; // Player using water protected bool earthElementSelected = false; // Player using earth protected bool airElementSelected = false; // Player using wind public bool terrainModEnabled = false; // Player using terrainMod public Enums.ObjectType targetObject; protected List hitWhere = new List(); private Enums.AttackType activeShield = Enums.AttackType.NONE; protected Enums.AttackType lastModeSelected = Enums.AttackType.NONE; //protected Enums.PlayerState currentState = Enums.PlayerState.NORMAL; private Model shieldModel; private GameObject gameObject; public PlayerSounds pSounds; // Physics public Vector3 lookAtPoint = new Vector3(); //public Sensor collisionSensor; // Animation private ModelAnimator animator; private AnimationController idle; private AnimationController walk; private AnimationController die; private AnimationController currentAnimation; // Controller public Controller playerController = new Controller(); public bool controlsInverted = false; // Invert controller private Stopwatch mannaIncrement = new Stopwatch(); private Stopwatch RateOfFire = new Stopwatch(); private Stopwatch energyStabalizeTimer = new Stopwatch(); public Stopwatch respawnTimer = new Stopwatch(); private Stopwatch spawnDoneTimer = new Stopwatch(); // player immortal after spawn public int playerIndex; // Player ID number public float health; // Player health public float manna; // Player manna public int killedBy = -1; public int kills; public int attackMagnitude = 30; protected int attackTemperature = 30; public int numberOfKeysFound = 0; public Vector3 spawnPosition = new Vector3(); public float spawnHeight = 0; public Vector3 terrainModTarget = Vector3.Zero; private bool firingEnergyBeam = false; private float[] materialDiffuse = { 1.0f, 1.0f, 1.0f, 1.0f }; private Matrix initialTransform = new Matrix(); private MajikWand majikWand = new MajikWand(); #endregion #region Methods public Player() : base() { Init(); } public Player(int playerNumber) { playerIndex = playerNumber; Init(); } private void Init() { mass.velocity = new Vector3(0, 0, 0); mass.mass = 10.0f; mass.scale = new Vector3(1.0f); mass.energy = 0.0f; mass.staticFrictionCoefficient = 0.25f; mass.dynamicFrictionCoefficient = 0.35f; mass.COR = 0.6f; mass.objectHeight = Statics.PlayerSettings.DEFAULT_PLAYER_HEIGHT; mass.lastMaxHeight = 0; mass.boundingVolume = new BoundingVolume(new BoundingSphere(new Vector3(10, 20, 10), 10.0f)); // Don't override the controller by default playerController.gameInput.manualOverride = false; //All player variables need to be reset health = 100; manna = 100; //collisionSensor = new Sensor(); //collisionSensor.ownerPointer = this; } public override bool Load(XmlNode node, ObjectLibrary objectLibrary) { //base.Load( node); // Audio pSounds = new PlayerSounds(); //Load Effect effect = Statics.content.Load("__Engine/Draw/ElementalGPU"); // TEMP HARDCODED - REPLACE WITH XML LOADING XML.PlayerInfo playerInfo; playerInfo.name = "septasoul"; playerInfo.modelPath = "_models/ss3"; playerInfo.texPath = "_textures/septasoulTexture"; playerInfo.bumpPath = "_textures/septasoulTexture_bump"; playerInfo.scale = new Vector3(10.0f); // END HACK =================== // Load Textures textureList.Clear(); textureList.Add(Statics.content.Load(playerInfo.texPath)); textureList.Add(Statics.content.Load(playerInfo.bumpPath)); // Load Animated Model model = Statics.content.Load(playerInfo.modelPath); mass.scale = playerInfo.scale; foreach (ModelMesh mesh in model.Meshes) { for (int i = 0; i < mesh.MeshParts.Count; i++) { ModelMeshPart part = mesh.MeshParts[i]; part.Effect = effect.Clone(Statics.graphics.GraphicsDevice); } } // Create Animators animator = new ModelAnimator(model); idle = new AnimationController(animator.Animations["idle"]); walk = new AnimationController(animator.Animations["walk"]); die = new AnimationController(animator.Animations["die"]); RunController(animator, idle); // Create Animation Transforms if (playerInfo.name == "dojoboy" || playerInfo.name == "dojogirl") { initialTransform = Matrix.CreateRotationY((float)(-Math.PI / 2.0f)) * Matrix.CreateTranslation(new Vector3(0, -Statics.PlayerSettings.DEFAULT_PLAYER_HEIGHT / 2.0f, 0)); } else if (playerInfo.name == "bunny") { initialTransform = Matrix.CreateTranslation(new Vector3(0, Statics.PlayerSettings.DEFAULT_PLAYER_HEIGHT, 0)); } else if (playerInfo.name == "fish") { initialTransform = Matrix.CreateRotationY((float)(-Math.PI)) * Matrix.CreateTranslation(new Vector3(0, -Statics.PlayerSettings.DEFAULT_PLAYER_HEIGHT / 2.0f + 5, 0)); } else { initialTransform = Matrix.Identity; } // Load non-animated Model shieldModel = Statics.content.Load("_models/Shield"); foreach (ModelMesh mesh in shieldModel.Meshes) { for (int i = 0; i < mesh.MeshParts.Count; i++) { // Add effect to mesh mesh.MeshParts[i].Effect = effect; } } textureList.Add(Statics.content.Load("_textures/RockQuartz")); textureList.Add(Statics.content.Load("_textures/EarthParticleLava")); textureList.Add(Statics.content.Load("_textures/Water")); textureList.Add(Statics.content.Load("_textures/AirParticleCold")); // Reset the Rate of Fire limiter RateOfFire = new Stopwatch(); RateOfFire.Start(); energyStabalizeTimer = new Stopwatch(); energyStabalizeTimer.Start(); mannaIncrement = new Stopwatch(); mannaIncrement.Start(); kills = 0; killedBy = -1; terrainModEnabled = false; earthElementSelected = true; fireElementSelected = false; waterElementSelected = false; airElementSelected = false; lastModeSelected = Enums.AttackType.EARTH; //relies on the x,z being set somewhere else.. try { int x = (int)(Statics.collisionMapSize * float.Parse(node.Attributes["startx"].Value)); int z = (int)(Statics.collisionMapSize * float.Parse(node.Attributes["startz"].Value)); spawnHeight = objectLibrary.terrain.GetTerrainHeight(x / Statics.terrainScaleFactor, z / Statics.terrainScaleFactor); SetSpawnPoint(new Vector3(x, spawnHeight + Statics.PlayerSettings.DEFAULT_PLAYER_HEIGHT, z)); } catch { System.Diagnostics.Debug.WriteLine("Error reading player attributes"); return false; } mass.boundingVolume.UpdateSphere(mass.currentPosition); return true; } #region UpdateCalls private void RunController(ModelAnimator animator, AnimationController controller) { foreach (BonePose p in animator.BonePoses) { p.CurrentController = (IAnimationController)controller; p.CurrentBlendController = null; } currentAnimation = controller; } private void UpdateController(ObjectLibrary objectLibrary) { lookAtPoint = new Vector3(); //currentAnimation.Update(Statics.elementalGameTime); if (currentAnimation != idle) { RunController(animator, idle); } // Rotation Controls if (playerController.gameInput.playerRotation != Vector2.Zero) { if (controlsInverted) { mass.Rotate(-playerController.gameInput.playerRotation.Y, playerController.gameInput.playerRotation.X); } else { mass.Rotate(playerController.gameInput.playerRotation.Y, playerController.gameInput.playerRotation.X); } if (terrainModEnabled) { terrainModTarget = Vector3.Zero; } } // Translation Controls if (playerController.gameInput.playerMotion != Vector2.Zero) { mass.MovePlayer(playerController.gameInput.playerMotion.Y, playerController.gameInput.playerMotion.X); if (terrainModEnabled) { terrainModTarget = Vector3.Zero; } RunController(animator, walk); } // Zoom Control if (playerController.gameInput.zoomAmount != 0.0f) { Statics.zoomFactor += playerController.gameInput.zoomAmount; if (Statics.zoomFactor < 1.0f) Statics.zoomFactor = 1.0f; else if (Statics.zoomFactor > 5.0f) Statics.zoomFactor = 5.0f; } // Cutoff point for what the player can do while dead....... if (IsAlive() == false) { RunController(animator, die); return; } // Incrementaly regenerate players manna if (mannaIncrement.ElapsedMilliseconds >= Statics.PlayerSettings.MANNA_INCREMENT_RATE) { mannaIncrement.Reset(); mannaIncrement.Start(); ChangeManna(+2); } // Player fall damage applied if (mass.fallingDamageMultiplier != 0.0f) { ChangeHealth(-mass.fallingDamageMultiplier * Statics.PlayerSettings.FALLING_HEALTH_LOSS, objectLibrary); mass.fallingDamageMultiplier = 0.0f; if (IsAlive() == false) { Kill(playerIndex, objectLibrary); // Killed himself if (playerIndex < 4) { ((Human)this).SetKilledByInfo("SPLAT!!!"); } } } // Toggle movement type if (playerController.gameInput.movementTypeToggle) { if (mass.movementType == Enums.MovementType.WALK) { mass.movementType = Enums.MovementType.HOVER; } else { mass.movementType = Enums.MovementType.WALK; mass.totalForce = Vector3.Zero; mass.velocity = Vector3.Zero; } } // Set Mass and Energy of Attack attackMagnitude += playerController.gameInput.massChangeDelta; attackTemperature += playerController.gameInput.thermalChangeDelta; if (attackMagnitude < 1) { attackMagnitude = 1; } else if (attackMagnitude > 100) { attackMagnitude = 100; } if (attackTemperature < 0) { attackTemperature = 0; } else if (attackTemperature > 100) { attackTemperature = 100; } // Check for Attack request from user if (playerController.gameInput.terrainModToggle) { terrainModEnabled = !terrainModEnabled; } if (terrainModEnabled && playerController.gameInput.attack != 0) { playerController.gameInput.attackMode = Enums.AttackMode.TERRAIN_MOD; } else if (playerController.gameInput.attackAmount > 0) { playerController.gameInput.attackMode = Enums.AttackMode.ATTACK; } else { playerController.gameInput.attackMode = Enums.AttackMode.NONE; } // Set the LookAt point if (terrainModEnabled) { lookAtPoint = majikWand.LookAtTerrainPoint(objectLibrary,this); if (lookAtPoint.X < 0.0f) { lookAtPoint = new Vector3(0.0f, 500.0f, 0.0f); } } // Player Attack if (playerController.gameInput.attack != 0) { // Does player have enough manna? if (manna > Statics.PlayerSettings.ATTACK_MANNA_COST) { // Is terrainMod switch on if (playerController.gameInput.attackMode == Enums.AttackMode.TERRAIN_MOD) { if (ChangeManna(-Math.Abs(playerController.gameInput.attack) * 0.1f)) { if (targetObject == Enums.ObjectType.TERRAIN) { majikWand.TerrainMod(playerController.gameInput.attack, objectLibrary, this); } } } // must be an attack or defend else { // Check if fire button was used if (manna > playerController.gameInput.attack / 2.0f) { if (fireElementSelected) { if (ChangeManna(-Statics.PlayerSettings.ENERGY_BEAM_MANNA_COST)) { // Play audio for each human foreach (Human human in objectLibrary.humans) { if (human.IsAlive()) { Audio.FireAttack(pSounds, mass.currentPosition, human.mass.currentPosition); } } // Fire Attack //UseEnergyBeam(objectLibrary, playerController.gameInput.attack); Attack_Bullet(Bullet.BulletType.Water, objectLibrary); firingEnergyBeam = true; } } } else { firingEnergyBeam = false; } // Check if particle Attack was initiated if (playerController.gameInput.attackAmount > 0.0f && manna > Statics.PlayerSettings.ATTACK_MANNA_COST) { // AND make sure they are not shielding at the same time if (playerController.gameInput.defendAmount == 0.0f) { // Attack if (earthElementSelected) { Attack_Grenade(Particle.ParticleType.Earth, objectLibrary); } else if (waterElementSelected) { Attack_Grenade(Particle.ParticleType.Water, objectLibrary); } else if (airElementSelected) { Attack_Grenade(Particle.ParticleType.Air, objectLibrary); } } } // Player uses shield if (playerController.gameInput.defendAmount > 0.0f && manna > Statics.PlayerSettings.SHIELD_MANNA_COST) { //Set player's shield to last element selected switch (lastModeSelected) { case Enums.AttackType.WIND: activeShield = Enums.AttackType.WIND; break; case Enums.AttackType.EARTH: activeShield = Enums.AttackType.EARTH; break; case Enums.AttackType.WATER: activeShield = Enums.AttackType.WATER; break; case Enums.AttackType.FIRE: case Enums.AttackType.NONE: activeShield = Enums.AttackType.NONE; break; } } else { activeShield = Enums.AttackType.NONE; } } } } // If triggers not pressed at all else { activeShield = Enums.AttackType.NONE; } // See if player is jumping if (playerController.gameInput.jump) { if (CheckPlayerOnTerrain(objectLibrary) == false) { mass.AddForce(new Vector3(0, Statics.PlayerSettings.IN_AIR_JUMP_CONSTANT, 0)); } else { mass.AddForce(new Vector3(0, Statics.PlayerSettings.JUMP_CONSTANT, 0)); } RunController(animator, die); } // See if player changed the Element mode if (playerController.gameInput.modeSwitch != Enums.AttackType.NONE) { switch (playerController.gameInput.modeSwitch) { case Enums.AttackType.WIND: { airElementSelected = true;// !airElementSelected; if (airElementSelected) { // Disable earth and water earthElementSelected = false; waterElementSelected = false; fireElementSelected = false; lastModeSelected = Enums.AttackType.WIND; } else { lastModeSelected = Enums.AttackType.NONE; } } break; case Enums.AttackType.EARTH: { earthElementSelected = true;// !earthElementSelected; if (earthElementSelected) { // Disable air and water airElementSelected = false; waterElementSelected = false; fireElementSelected = false; lastModeSelected = Enums.AttackType.EARTH; } else { lastModeSelected = Enums.AttackType.NONE; } } break; case Enums.AttackType.FIRE: { fireElementSelected = true;// !fireElementSelected; airElementSelected = false; waterElementSelected = false; earthElementSelected = false; if (fireElementSelected) { lastModeSelected = Enums.AttackType.FIRE; } else { lastModeSelected = Enums.AttackType.NONE; } } break; case Enums.AttackType.WATER: { waterElementSelected = true;// !waterElementSelected; if (waterElementSelected) { // Disable earth and air earthElementSelected = false; airElementSelected = false; fireElementSelected = false; lastModeSelected = Enums.AttackType.WATER; } else { lastModeSelected = Enums.AttackType.NONE; } } break; case Enums.AttackType.TERRAIN: { lastModeSelected = Enums.AttackType.TERRAIN; } break; } } // Check the player's overall velocity if (mass.velocity.Length() > Statics.PlayerSettings.MAX_VELOCITY) { // If NOT falling //if (Math.Abs(mass.velocity.Y) < Math.Abs(mass.velocity.X) || Math.Abs(mass.velocity.Y) < Math.Abs(mass.velocity.Z)) //{ mass.velocity.Normalize(); mass.velocity *= Statics.PlayerSettings.MAX_VELOCITY; //} } } public override void Update(ref ObjectLibrary objectLibrary) { if (energyStabalizeTimer.ElapsedMilliseconds > 3000) { //update player's energy value if (mass.energy < 0.0f) { mass.ChangeEnergy(0.01f); } else if (mass.energy > 0.0f) { mass.ChangeEnergy(-0.01f); } energyStabalizeTimer.Reset(); energyStabalizeTimer.Start(); } if (currentAnimation != null) { currentAnimation.Update(Statics.elementalGameTime); } animator.Update(); UpdateController(objectLibrary); mass.UpdatePosition(); mass.isMoving = true; //if (mass.isMoving && !Statics.dynamicList.Contains(mass)) //{ // Statics.dynamicList.Add(mass); //} mass.boundingVolume.UpdateSphere(mass.currentPosition); Vector3 sensorDistance; if (mass.movementType == Enums.MovementType.WALK) { sensorDistance = mass.sensorDirection + Vector3.Zero; } else { sensorDistance = mass.velocity + Vector3.Zero; } if (sensorDistance.Length() > Statics.PlayerSettings.MAX_SENSOR_DISTANCE) { sensorDistance.Normalize(); sensorDistance = sensorDistance * Statics.PlayerSettings.MAX_SENSOR_DISTANCE; } //collisionSensor.mass.SetPosition(mass.currentPosition + sensorDistance, // mass.currentPosition + sensorDistance * 1.5f); if (spawnDoneTimer.IsRunning) { if (spawnDoneTimer.ElapsedMilliseconds >= Statics.PlayerSettings.SPAWN_DONE_DELAY) { spawnDoneTimer.Stop(); spawnDoneTimer.Reset(); } } // Play audio for each human foreach (Human human in objectLibrary.humans) { if (human.IsAlive()) { if (playerController.gameInput.playerMotion.Length() > 0) { Audio.Walking(pSounds, mass.currentPosition, human.mass.currentPosition); } if (playerController.gameInput.jump) { Audio.Jump(pSounds, mass.currentPosition, human.mass.currentPosition); } } } } #endregion #region Draw Calls public override void Draw(ModelManager modelManager, string technique) { // Did we die?? if (IsAlive() == false) { return; } //check spawn done delay if (spawnDoneTimer.IsRunning) { float ratio = (float)spawnDoneTimer.ElapsedMilliseconds / (float)Statics.PlayerSettings.SPAWN_DONE_DELAY; SetDiffuseAlpha(ratio); } else { SetDiffuseAlpha(255); } // Calculate ObjectSpace(Rotation) and WorldSpace(Translation) Transformation Matrix matrix = initialTransform * Matrix.CreateScale(mass.scale) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); DrawAnimation(); } public void DrawEnergyBeam(ObjectLibrary objectLibrary) { if (fireElementSelected == true && playerController.gameInput.attack != 0.0f && manna > -playerController.gameInput.attack / 2.0f) { Vector3 startPosition = mass.currentPosition + mass.perpVector + mass.normalVector - mass.upVector * 3; Vector3 targetPosition; float[] diffuse = { 1, 1, 1, 1 }; // Get the particles information from LookAtPoint and store it in the local vector3 lookAtPoint Vector3 lookPoint = majikWand.LookAtObject(objectLibrary, this); // Check if the target object was Earth if (targetObject == Enums.ObjectType.PARTICLE) { targetPosition = mass.currentPosition + mass.normalVector * lookPoint.Length(); } else { targetPosition = mass.currentPosition + mass.normalVector * Statics.PlayerSettings.TERRAIN_MOD_RANGE; } matrix = Matrix.Identity; ShaderParameters.World.SetValue(matrix); ShaderParameters.materialDiffuse.SetValue(diffuse); //fire texture ShaderParameters.modelTexture1.SetValue(textureList[4]); //water texture ShaderParameters.modelTexture2.SetValue(textureList[3]); //should interpolate ShaderParameters.particleEnergyValue.SetValue((playerController.gameInput.attack / 2.0f) + 0.5f); VertexPositionTexture[] list = new VertexPositionTexture[6]; float size = 1.0f; list[0].Position = startPosition - mass.perpVector * size;// new Vector3(-size, 0, 0); //list[0].Color = new Color(0, 0, 0); list[0].TextureCoordinate = new Vector2(0, 1); list[1].Position = targetPosition - mass.perpVector * size + mass.normalVector * size;// new Vector3(-size, 0, size); //list[1].Color = new Color(0, 255, 0); list[1].TextureCoordinate = new Vector2(0, 0); list[2].Position = targetPosition + mass.perpVector * size + mass.normalVector * size;//new Vector3(size, 0, size); //list[2].Color = new Color(0, 0, 255); list[2].TextureCoordinate = new Vector2(1, 0); list[3].Position = list[0].Position;//new Vector3(-size, 0, 0); //list[3].Color = new Color(255, 255, 255); list[3].TextureCoordinate = list[0].TextureCoordinate; list[4].Position = list[2].Position;//new Vector3(size, 0, size); //list[4].Color = new Color(0, 0, 0); list[4].TextureCoordinate = list[2].TextureCoordinate; list[5].Position = startPosition + mass.normalVector * size;//new Vector3(0, 0, size); //list[5].Color = new Color(0, 100, 0); list[5].TextureCoordinate = new Vector2(1, 1); // Technique effect.CurrentTechnique = effect.Techniques["EnergyBeamShaderMain"]; effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); Statics.graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, list, 0, 2); pass.End(); } effect.End(); } } public void DrawShield() { //if (activeShield != Enums.ShieldType.NO_SHIELD) // HACK: THIS IS TO SEE THE PLAYER AT ALL TIMES if (true) { matrix = Matrix.CreateScale(mass.boundingVolume.radius * 5) * Matrix.CreateTranslation(mass.currentPosition); ShaderParameters.World.SetValue(matrix); ShaderParameters.modelTexture1.SetValue(textureList[4]); switch (activeShield) { case Enums.AttackType.EARTH: { ShaderParameters.modelTexture1.SetValue(textureList[2]); break; } case Enums.AttackType.FIRE: { ShaderParameters.modelTexture1.SetValue(textureList[3]); break; } case Enums.AttackType.WATER: { ShaderParameters.modelTexture1.SetValue(textureList[4]); break; } case Enums.AttackType.WIND: { ShaderParameters.modelTexture1.SetValue(textureList[5]); break; } } // Draw the shield model base.DrawTriStrips(shieldModel, "ShieldShaderMain"); } } public void DrawAnimation() { try { animator.world = matrix; animator.Update(); currentAnimation.Update(Statics.elementalGameTime); int index = 0; // Update all the effects with the palette and world and draw the meshes for (int i = 0; i < animator.numMeshes; i++) { // Get the mesh ModelMesh mesh = model.Meshes[i]; // The starting index for the modelEffects array int effectStartIndex = index; if (animator.palette[i] != null && animator.matrixPaletteParams[index] != null) { foreach (Effect effect in mesh.Effects) { animator.worldParams[index].SetValue(matrix); animator.matrixPaletteParams[index].SetValue(animator.palette[i]); index++; } } else { foreach (Effect effect in mesh.Effects) { animator.worldParams[index].SetValue(animator.pose[mesh.ParentBone.Index] * matrix); index++; } } int numParts = mesh.MeshParts.Count; GraphicsDevice device = mesh.VertexBuffer.GraphicsDevice; device.Indices = mesh.IndexBuffer; for (int j = 0; j < numParts; j++) { ModelMeshPart currentPart = mesh.MeshParts[j]; if (currentPart.NumVertices == 0 || currentPart.PrimitiveCount == 0) continue; Effect currentEffect = animator.modelEffects[effectStartIndex + j]; if (animator.palette[i] != null && animator.matrixPaletteParams[i] != null) { currentEffect.CurrentTechnique = currentEffect.Techniques["SkinnedPlayerShaderMain"]; } else { currentEffect.CurrentTechnique = currentEffect.Techniques["PlayerShaderMain"]; } currentEffect.Parameters["modelTexture1"].SetValue(textureList[0]); currentEffect.Parameters["bumpTexture1"].SetValue(textureList[1]); // Lighting currentEffect.Parameters["shininess"].SetValue(7000.0f); currentEffect.Parameters["particleEnergyValue"].SetValue((mass.energy / 2.0f) + 0.5f); currentEffect.Parameters["playerIsDead"].SetValue(!IsAlive()); currentEffect.Parameters["ViewProj"].SetValue(Statics.matrixView * Statics.matrixProjection); currentEffect.Parameters["EyePostion"].SetValue(Matrix.Invert(Statics.matrixView)); currentEffect.Parameters["lightPosition0"].SetValue(Statics.LevelSettings.lightPosition1); currentEffect.Parameters["lightAmbient0"].SetValue(Statics.LevelSettings.lightAmbient1); currentEffect.Parameters["lightDiffuse0"].SetValue(Statics.LevelSettings.lightDiffuse1); currentEffect.Parameters["lightSpecular0"].SetValue(Statics.LevelSettings.lightSpecular1); if (Statics.SystemSettings.singleLightSource) { currentEffect.Parameters["lightPosition1"].SetValue(Statics.LevelSettings.lightPosition1); currentEffect.Parameters["lightAmbient1"].SetValue(Statics.LevelSettings.lightAmbient1); currentEffect.Parameters["lightDiffuse1"].SetValue(Statics.LevelSettings.lightDiffuse1); currentEffect.Parameters["lightSpecular1"].SetValue(Statics.LevelSettings.lightSpecular1); } else { currentEffect.Parameters["lightPosition1"].SetValue(Statics.LevelSettings.lightPosition2); currentEffect.Parameters["lightAmbient1"].SetValue(Statics.LevelSettings.lightAmbient2); currentEffect.Parameters["lightDiffuse1"].SetValue(Statics.LevelSettings.lightDiffuse2); currentEffect.Parameters["lightSpecular1"].SetValue(Statics.LevelSettings.lightSpecular2); } currentEffect.Parameters["materialDiffuse"].SetValue(materialDiffuse); device.VertexDeclaration = currentPart.VertexDeclaration; device.Vertices[0].SetSource(mesh.VertexBuffer, currentPart.StreamOffset, currentPart.VertexStride); currentEffect.Begin(); EffectPassCollection passes = currentEffect.CurrentTechnique.Passes; int numPasses = passes.Count; for (int k = 0; k < numPasses; k++) { EffectPass pass = passes[k]; pass.Begin(); device.DrawIndexedPrimitives(PrimitiveType.TriangleList, currentPart.BaseVertex, 0, currentPart.NumVertices, currentPart.StartIndex, currentPart.PrimitiveCount); pass.End(); } currentEffect.End(); } } } catch (NullReferenceException) { throw new InvalidOperationException("The effects on the model for a " + "ModelAnimator were changed without calling ModelAnimator.InitializeEffectParams()."); } catch (InvalidCastException) { throw new InvalidCastException("ModelAnimator has thrown an InvalidCastException. This is " + "likely because the model uses too many bones for the matrix palette. The default palette size " + "is 56 for windows and 40 for Xbox."); } } public void DrawAIVision(Matrix view, Matrix proj, float playerIndex) { try { matrix = initialTransform * Matrix.CreateScale(mass.scale) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); animator.world = matrix; int index = 0; // Update all the effects with the palette and world and draw the meshes for (int i = 0; i < animator.numMeshes; i++) { ModelMesh mesh = model.Meshes[i]; // The starting index for the modelEffects array int effectStartIndex = index; if (animator.palette[i] != null && animator.matrixPaletteParams[index] != null) { foreach (Effect effect in mesh.Effects) { animator.worldParams[index].SetValue(matrix); animator.matrixPaletteParams[index].SetValue(animator.palette[i]); index++; } } else { foreach (Effect effect in mesh.Effects) { animator.worldParams[index].SetValue(animator.pose[mesh.ParentBone.Index] * matrix); index++; } } int numParts = mesh.MeshParts.Count; GraphicsDevice device = mesh.VertexBuffer.GraphicsDevice; device.Indices = mesh.IndexBuffer; for (int j = 0; j < numParts; j++) { ModelMeshPart currentPart = mesh.MeshParts[j]; if (currentPart.NumVertices == 0 || currentPart.PrimitiveCount == 0) continue; Effect currentEffect = animator.modelEffects[effectStartIndex + j]; currentEffect.CurrentTechnique = currentEffect.Techniques["AI_Vision_PlayerShaderMain"]; currentEffect.Parameters["ViewProj"].SetValue(view * proj); currentEffect.Parameters["playerIndex"].SetValue(playerIndex); device.VertexDeclaration = currentPart.VertexDeclaration; device.Vertices[0].SetSource(mesh.VertexBuffer, currentPart.StreamOffset, currentPart.VertexStride); currentEffect.Begin(); EffectPassCollection passes = currentEffect.CurrentTechnique.Passes; int numPasses = passes.Count; for (int k = 0; k < numPasses; k++) { EffectPass pass = passes[k]; pass.Begin(); device.DrawIndexedPrimitives(PrimitiveType.TriangleList, currentPart.BaseVertex, 0, currentPart.NumVertices, currentPart.StartIndex, currentPart.PrimitiveCount); pass.End(); } currentEffect.End(); } } } catch (NullReferenceException) { throw new InvalidOperationException("The effects on the model for a " + "ModelAnimator were changed without calling ModelAnimator.InitializeEffectParams()."); } catch (InvalidCastException) { throw new InvalidCastException("ModelAnimator has thrown an InvalidCastException. This is " + "likely because the model uses too many bones for the matrix palette. The default palette size " + "is 56 for windows and 40 for Xbox."); } } #endregion #region Set the Player's color. public void SetDiffuseRed(float red) { materialDiffuse[0] = (1.0f * red) / 255.0f; } public void SetDiffuseGreen(float green) { materialDiffuse[1] = (1.0f * green) / 255.0f; } public void SetDiffuseBlue(float blue) { materialDiffuse[2] = (1.0f * blue) / 255.0f; } public void SetDiffuseAlpha(float alpha) { materialDiffuse[3] = alpha; } private float[] GetDiffuseColor() { return materialDiffuse; } #endregion #region Life, death, and taxes public bool IsHuman() { if (playerIndex < 4) { return true; } return false; } public bool IsAlive() { return (health > 0); } private bool ChangeManna(float diff) { if (manna + diff < 0) { //don't have enough return false; } manna += diff; if (manna < 0) { manna = 0; } else if (manna > 100) { manna = 100; } return true; } public void ChangeHealth(float diff, ObjectLibrary objectLibrary) { if (spawnDoneTimer.IsRunning) { return; } if (diff < 0) { // Play audio for each human foreach (Human human in objectLibrary.humans) { if (human.IsAlive()) { Audio.Hit(pSounds, mass.currentPosition, human.mass.currentPosition); } } } health += diff; if (health < 0) { health = 0; } else if (health > 100) { health = 100; } } private void Kill(int killerID) { killedBy = killerID; //Begin their respawn timer respawnTimer.Reset(); respawnTimer.Start(); } private void Kill(int killerID, ObjectLibrary objectLibrary) { Kill(killerID); AssignKillCredit( objectLibrary); } public void AssignKillCredit(ObjectLibrary objectLibrary) { // They were alive going into this method if they come out dead then // We know someone killed them and can assign credit // If the player did not suicide find out who killed them if (killedBy != playerIndex) { if (killedBy < 4) { // Find the killer who is human for (int i = 0; i < objectLibrary.humans.Count; i++) { // Assign credit to the killer if (killedBy == objectLibrary.humans[i].playerIndex) { objectLibrary.humans[i].kills++; } } } else { // Find the bot that killed for (int i = 0; i < objectLibrary.bots.Count; i++) { // Assign credit to the killer if (killedBy == objectLibrary.bots[i].playerIndex) { objectLibrary.bots[i].kills++; } } } } else { kills--; } } public void SetSpawnPoint(Vector3 spawn) { spawnPosition = Vector3.Zero + spawn; mass.SetPosition(spawnPosition, new Vector3(Statics.collisionMapSize / 2, 0, Statics.collisionMapSize / 2)); } public void SpawnPlayer() { // Remove from map //Statics.lookupMap.RemoveLast(this.mass); //Statics.lookupMap.RemoveCurrent(this.mass); mass.velocity = Vector3.Zero; mass.totalForce = Vector3.Zero; spawnPosition.Y = spawnHeight + Statics.PlayerSettings.DEFAULT_PLAYER_HEIGHT; mass.SetPosition(spawnPosition, new Vector3(Statics.collisionMapSize / 2, 0, Statics.collisionMapSize / 2)); mass.boundingVolume = new BoundingVolume(new BoundingSphere( new Vector3(spawnPosition.X, Statics.PlayerSettings.DEFAULT_PLAYER_HEIGHT / 2.0f, spawnPosition.Z), mass.scale.Y/2)); health = 100; manna = 100; killedBy = -1; activeShield = Enums.AttackType.NONE; // Reset the Rate of Fire limiter RateOfFire.Reset(); RateOfFire.Start(); energyStabalizeTimer.Reset(); energyStabalizeTimer.Start(); mannaIncrement = new Stopwatch(); mannaIncrement.Start(); //stop the respawn timer respawnTimer.Stop(); respawnTimer.Reset(); //start the invincibility timer spawnDoneTimer.Reset(); spawnDoneTimer.Start(); //Statics.lookupMap.SetPosition(this.mass); } public bool PlayerHitByParticle(Particle particle, ObjectLibrary objectLibrary) { if ((particle.hasCollided != playerIndex && particle.ownerID != playerIndex) || (particle.hurtOwner == true && particle.ownerID == playerIndex)) { // We know player is hit... determine which direction Vector3 toParticle = new Vector3(particle.mass.currentPosition.X - mass.currentPosition.X, particle.mass.currentPosition.Y - mass.currentPosition.Y, particle.mass.currentPosition.Z - mass.currentPosition.Z); Vector3 playerLook = new Vector3(mass.normalVector.X, 0, mass.normalVector.Z); playerLook.Normalize(); Vector3 cross = Vector3.Cross(toParticle, playerLook); if (cross.Y < 0) { hitWhere.Add(Enums.HitWhere.LEFT); } else { hitWhere.Add(Enums.HitWhere.RIGHT); } // Player shielded properly.. no damage and absorbs the particle if ((activeShield == Enums.AttackType.EARTH && particle.particleType == Particle.ParticleType.Earth) || (activeShield == Enums.AttackType.WATER && particle.particleType == Particle.ParticleType.Water) || (activeShield == Enums.AttackType.WIND && particle.particleType == Particle.ParticleType.Air)) { // Correct shield -> player absorbs manna ChangeManna(Statics.PlayerSettings.SHIELD_MANNA_GAIN * particle.mass.mass); if (IsHuman()) { ((Human)this).ShowMannaIndicator(); } //Get rid of it altogether //Statics.lookupMap.RemoveLast(particle.mass); //Statics.lookupMap.RemoveCurrent(particle.mass); //if (Statics.lookupMap.DynamicContains(particle.mass)) //{ // Statics.lookupMap.RemoveDynamic(particle.mass); //} particle.mass.ClearValues(); particle.mass.deadObject = true; return true; } else { // Wrong shield -> player loses health ChangeHealth(DamageCalculations(particle.mass, mass), objectLibrary); // If tornado.. apply random force! if (particle.particleType == Particle.ParticleType.Air) { mass.AddForce(new Vector3(0, particle.mass.mass * 100000, 0)); } // If the player is dead and they haven't been assigned who killed them then do so if (!IsAlive() && killedBy == -1) { Kill(particle.ownerID); if (playerIndex < 4) { //Its a human.. set its killedby HUD info ((Human)this).SetKilledByInfo(particle); } } } particle.hasCollided = playerIndex; particle.hasCollidedTimer = Stopwatch.StartNew(); } return false; } private float DamageCalculations(Mass particleMass, Mass playerMass) { float damage = 0.0f; Particle particle = ((Particle)particleMass.gameObjectPointer); // ~ about between 0 and 1 for slow to fast float particleVelocityRatio = particleMass.velocity.Length() / 2000.0f; // Velocity.Length() range~ // Earth: 200-1600 // Water: 400-1700 // Air: 500-1700 // Particle type based damage modifier if (particle.particleType == Particle.ParticleType.Earth) { if (particleMass.energy > 0.3f) { //lava hurts more if (particleMass.velocity.Length() < 50) { //its slower.. it hurts more? damage = 25.0f; } else { damage = 10.0f; } } else { //frozen rock and rock are the same damage = 5.0f + particleVelocityRatio; } } else if (particle.particleType == Particle.ParticleType.Water) { if (particleMass.energy > 0.5f) { //boiling water hurts alot if (particleMass.velocity.Length() < 50) { damage = 25.0f; } else { damage = 20.0f; } } else if (particleMass.energy < 0.0f) { //frozen ice hurts a bit more damage = 3.0f + particleVelocityRatio; } else { //regular water doesn't hurt that much if (particleMass.velocity.Length() < 50) { //slow water doesn't hurt damage = 0.0f; } else { damage = 10.0f; } } } else //air particle is all the same { damage = 0.1f + particleVelocityRatio; } float totalDamage = -damage * (1 + (particleMass.mass / 5.0f)) * Statics.PlayerSettings.DIRECT_HEALTH_LOSS; Debug.WriteLine("Particle type=" + particle.particleType.ToString() + ",mass=" + particleMass.mass + ", vRatio=" + particleVelocityRatio + ", v=" + particleMass.velocity.Length() + " damage=" + damage + "...total= " + totalDamage + ".... energy=" + particleMass.energy); return totalDamage; } #endregion #region Player Abilities private void UseEnergyBeam(ObjectLibrary objectLibrary, float elementUse) { Vector3 lookAtPoint = new Vector3(-1.0f); // Get the particles information from LookAtPoint and store it in the local vector3 lookAtPoint lookAtPoint = majikWand.LookAtObject(objectLibrary, this); // Check if the target object was a particle or a player if (targetObject == Enums.ObjectType.PARTICLE || targetObject == Enums.ObjectType.PLAYER) { if (targetObject == Enums.ObjectType.PARTICLE) { // Reference the particle from lookupMap LinkedList linkedList = new LinkedList(); //Statics.lookupMap.GetListXZ((int)lookAtPoint.X / Statics.terrainScaleFactor, //(int)lookAtPoint.Z / Statics.terrainScaleFactor); int j = 0; foreach (Mass massObj in linkedList) { if (j == (int)lookAtPoint.Y) { gameObject = massObj.gameObjectPointer; break; } j++; } } else //its a player { if ((int)lookAtPoint.Y < 4) { //its a human gameObject = objectLibrary.humans[(int)lookAtPoint.Y]; } else { //its a bot gameObject = objectLibrary.bots[(int)lookAtPoint.Y - 4]; } } if (gameObject == null) { //didn't find it.. probably won't happen but just in case return; } // Expel or absorb energy float cost = 0; if (elementUse < 0) { if (targetObject == Enums.ObjectType.PARTICLE) { //absorb manna from particle cost = -Statics.PlayerSettings.PARTICLE_ABSORB_MANNA_COST * -elementUse; } else { //absorb health from player cost = -Statics.PlayerSettings.PLAYER_ABSORB_MANNA_COST * -elementUse; } } else { //expel cost = -Statics.PlayerSettings.EXPEL_MANNA_COST * elementUse; } if (targetObject == Enums.ObjectType.PARTICLE) { if (Math.Abs(gameObject.mass.energy) <= 1.0f && ChangeManna(cost)) { float dEnergy = elementUse; //If we use dpad: float dEnergy = (particleThermalValue - 37) / 40.0f; gameObject.mass.ChangeEnergy(dEnergy * 0.01f); if (gameObject.mass.objectType == Enums.ObjectType.PARTICLE) { ((Particle)gameObject).ownerID = playerIndex; } gameObject.mass.isChanging = true; if (elementUse < 0) { //add manna ChangeManna(Statics.PlayerSettings.PARTICLE_ABSORB_MANNA_GAIN * -elementUse); if (IsHuman()) { ((Human)this).ShowMannaIndicator(); } } } } else { if (Math.Abs(gameObject.mass.energy) <= 1.0f && ChangeManna(cost)) { float dEnergy = elementUse; //If we use dpad: float dEnergy = (particleThermalValue - 37) / 40.0f; gameObject.mass.ChangeEnergy(dEnergy * 0.01f); if (elementUse < 0) { //add health from player ChangeHealth(Statics.PlayerSettings.PLAYER_ABSORB_HEALTH_GAIN * -elementUse, objectLibrary); ((Player)gameObject).ChangeHealth(-Statics.PlayerSettings.PLAYER_ABSORB_HEALTH_GAIN * -elementUse, objectLibrary); } else { //hurt player ((Player)gameObject).ChangeHealth(-Statics.PlayerSettings.EXPEL_HEALTH_LOSS * elementUse, objectLibrary); } //check if we killed the player if (((Player)gameObject).IsAlive() == false) { ((Player)gameObject).Kill(playerIndex, objectLibrary); if (((Player)gameObject).IsHuman()) { //set killed info on screen for human string s; if (IsHuman()) { s = "Player " + (playerIndex + 1); } else { s = "Bot " + (playerIndex + 1); } ((Human)gameObject).SetKilledByInfo("ZAPPED by " + s); } } } } } } private void Attack_Grenade(Particle.ParticleType type, ObjectLibrary objectLibrary) { // Enable shooting again if Rate Of Fire timer returns greater than the static fire rate if (RateOfFire.Elapsed.TotalMilliseconds > Statics.PlayerSettings.RATE_OF_FIRE + ((float)attackMagnitude * 10.0f)) { // Reset the rate of fire counter RateOfFire.Reset(); RateOfFire.Start(); // Charge Manna if (ChangeManna(-Statics.PlayerSettings.ATTACK_MANNA_COST * ((attackMagnitude + attackTemperature) / 10.0f))) { // Start the attack objectLibrary.Attack_Grenade(playerIndex, type, mass.currentPosition + 5 * mass.normalVector, mass.normalVector, attackMagnitude, attackTemperature); } } } private void Attack_Bullet(Bullet.BulletType type, ObjectLibrary objectLibrary) { // Enable shooting again if Rate Of Fire timer returns greater than the static fire rate if (RateOfFire.Elapsed.TotalMilliseconds > Statics.PlayerSettings.RATE_OF_FIRE + ((float)attackMagnitude * 10.0f)) { // Reset the rate of fire counter RateOfFire.Reset(); RateOfFire.Start(); // Charge Manna if (ChangeManna(-Statics.PlayerSettings.ATTACK_MANNA_COST * ((attackMagnitude + attackTemperature) / 10.0f))) { // Start the attack objectLibrary.Attack_Bullet(playerIndex, type, mass.currentPosition + 5 * mass.normalVector, mass.normalVector, attackMagnitude, attackTemperature); } } } public bool CheckPlayerOnTerrain(ObjectLibrary objectLibrary) { base.GetObjectHeight(objectLibrary.terrain); // Get difference between average and player if (heightDifference < 0.0f) { // In the Air return false; } else { // On the Ground return true; } } #endregion #region Collision Responses /// /// Add Player specific responses to an object to object collision involving this and collidedObject. /// Uses collidedObject.collisionWithPlayerResponse to determine health and manna bonuses and damage. /// /// /// /// public override bool ObjectCollisionResponse(GameObject collidedObject, Vector3 resultantForce, ObjectLibrary objectLibrary) { // collidedObject will be absorbed by the player so we don't need to calculate collision forces switch (collidedObject.collisionWithPlayerResponse) { case Enums.CollisionResponses.HEALTHBONUS: ChangeHealth((collidedObject.collisionMultiplier * resultantForce.Length()) * 1.0f, objectLibrary); break; case Enums.CollisionResponses.HEALTHLOSS: mass.AddForce(resultantForce); ChangeHealth((collidedObject.collisionMultiplier * resultantForce.Length()) * -1.0f, objectLibrary); break; case Enums.CollisionResponses.MANNABONUS: ChangeManna(collidedObject.collisionMultiplier * 1.0f); break; case Enums.CollisionResponses.MANNALOSS: mass.AddForce(resultantForce); ChangeManna(collidedObject.collisionMultiplier * -1.0f); break; case Enums.CollisionResponses.NONE: mass.AddForce(resultantForce); break; } // Player did not absorb the colliding object return false; } /// /// Add Player specific responses to an object to terrain collision involving this /// /// public override void TerrainCollisionResponse(Terrain terrain) { base.GetObjectHeight(terrain); // Add Gravity if terrain and player are touching if (heightDifference < 0.0f) { mass.AddForce(mass.mass * Statics.accelDueToGravity); } else if (heightDifference > 0.0f) { // Call base first base.TerrainCollisionResponse(terrain); if (totalForce.Y > 0.0f) { totalForce.Y = 0.0f; } if (velocity.Y > 0.0f) { velocity.Y = 0.0f; } #region Walk // Ground pushing up to negate gravity if (mass.movementType == Enums.MovementType.WALK) { //only if its NOT a wall if (heightDifference < Statics.PlayerSettings.DEFAULT_PLAYER_HEIGHT) { //just set their height! mass.currentPosition.Y = totalHeight + (mass.objectHeight / 2); } else { mass.KickBack(5.0f); } } #endregion #region Hover else if (mass.movementType == Enums.MovementType.HOVER) { if (velocityTangentialComponent.Length() < 2.5f) { mass.totalForce = Vector3.Zero; mass.acceleration = Vector3.Zero; mass.velocity = Vector3.Zero; } else { // Add terrain rebound force to object mass.AddForce((heightDifference * terrain.playerSurfaceTension * surfaceNormal) - (new Vector3(0.0f, totalForce.Y, 0.0f) + new Vector3(0.0f, velocity.Y * mass.mass / Statics.dt, 0.0f))); // Pass everything to friction (friction coefficients, the normal force on the body and the direction of friction) mass.AddFriction(mass.dynamicFrictionCoefficient + terrain.mass.dynamicFrictionCoefficient, (gravityNormalComponent * mass.mass), velocityTangentialComponent); } } #endregion mass.lastMaxHeight = 0; } } #endregion #endregion } }