//Test for Sphere --> Sphere Collision
 public Contact Collides(Sphere sphere)
 {
     return base.Collides(this, sphere);
 }
        //Sphere --> Plane Collision Detection and Contact Info generation
        //Returns null if no collision, a contact object if a collision occurs
        protected Contact Collides(Sphere sphere, Plane plane)
        {
            //Remove the absolute value to allow full penetration of the sphere
            //float Distance = Vector3.Dot(plane.Normal, sphere.position - plane.position) / plane.Normal.Length();
            float Distance = Math.Abs(Vector3.Dot(plane.Normal, sphere.Position - plane.Position)) / plane.Normal.Length();

            if (Distance <= sphere.Radius)
            {
                Contact contact = new Contact();
                contact.ContactType = CollisionType.FaceFace;
                contact.ContactNormal = plane.Normal;
                contact.PenetrationDepth = sphere.Radius - Distance;
                contact.ContactPoint = sphere.Position - contact.ContactNormal * Distance;
                contact.DeepestPoint = sphere.Position - contact.ContactNormal * (Distance + contact.PenetrationDepth);

                return contact;
            }

            //No Collision
            return null;
        }
        //Sphere --> Box Collision Detection and Contact Info generation
        //Returns null if no collision, a contact object if a collision occurs
        protected Contact Collides(Sphere sphere, Box box)
        {
            Contact contact = new Contact();
            Vector3[] vertices = box.GetVertices();

            //Implementation based on pages 644-645 of Geometric Tools for Computer Graphics [Philip J. Schneider & David H. Eberly, Morgan Kaufmann]
            //Make sure the sphere is touching the box before continuing

            //Distance from sphere to each of the box vertices
            float[] VertexDistances = new float[8];

            //Compute distance
            for (int i = 0; i < vertices.Length; i++)
            {
                VertexDistances[i] = (vertices[i] - sphere.Position).Length();
            }

            //Obtain Minimum and Maximum values for X,Y,Z
            Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z);
            Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z);

            for (int i = 0; i < vertices.Length; i++)
            {
                if (min.X > vertices[i].X)
                    min.X = vertices[i].X;

                if (min.Y > vertices[i].Y)
                    min.Y = vertices[i].Y;

                if (min.Z > vertices[i].Z)
                    min.Z = vertices[i].Z;

                if (max.X < vertices[i].X)
                    max.X = vertices[i].X;

                if (max.Y < vertices[i].Y)
                    max.Y = vertices[i].Y;

                if (max.Z < vertices[i].Z)
                    max.Z = vertices[i].Z;
            }

            //Test for collision
            double dSquared = 0;

            if (sphere.Position.X < min.X)
            {
                dSquared += (float)Math.Pow((sphere.Position.X - min.X), 2);
            }
            else if (sphere.Position.X > max.X)
            {
                dSquared += (float)Math.Pow((sphere.Position.X - max.X), 2);
            }

            if (sphere.Position.Y < min.Y)
            {
                dSquared += (float)Math.Pow((sphere.Position.Y - min.Y), 2);
            }
            else if (sphere.Position.Y > max.Y)
            {
                dSquared += (float)Math.Pow((sphere.Position.Y - max.Y), 2);
            }

            if (sphere.Position.Z < min.Z)
            {
                dSquared += (float)Math.Pow((sphere.Position.Z - min.Z), 2);
            }
            else if (sphere.Position.Z > max.Z)
            {
                float test = sphere.Position.Z - max.Z;
                dSquared += (float)Math.Pow((sphere.Position.Z - max.Z), 2);
            }

            if (dSquared <= Math.Pow(sphere.Radius, 2))
            {

                #region Vertex-Face

                foreach (Vector3 vertex in vertices)
                {
                    float Distance = (sphere.Position - vertex).Length();

                    if (Distance <= sphere.Radius)
                    {
                        Vector3 midline = vertex - sphere.Position;
                        contact.ContactType = CollisionType.VertexFace;
                        contact.ContactNormal = -midline / midline.Length();
                        contact.ContactPoint = vertex;// sphere.position + (midline * sphere.Radius) / midline.Length();
                        contact.DeepestPoint = sphere.Position + (midline * sphere.Radius) / midline.Length();
                        contact.PenetrationDepth = ((vertex - contact.DeepestPoint)).Length();

                        return contact;
                    }
                }
                #endregion

                #region Face-Face

                Vector3[] normals = box.GetNormals();
                float[] Distances = new float[6];
                for (int i = 0; i < normals.Length; i++)
                {
                    Distances[i] = Vector3.Dot(normals[i], sphere.Position - (box.Position + (normals[i] * box.Size / 2))) / normals[i].Length();
                }

                int index = 0;

                //The number of faces whose normals are not pointing away from the sphere.
                int PositiveCount = 0;

                for (int i = 0; i < Distances.Length; i++)
                {
                    if (Distances[i] > 0)
                    {
                        if (Distances[i] <= sphere.Radius)
                        {
                            PositiveCount++;
                        }

                        if (Distances[index] > Distances[i] || Distances[index] < 0)
                        {
                            index = i;
                        }
                    }
                }

                if (Distances[index] <= sphere.Radius && PositiveCount == 1)
                {
                    contact = new Contact();
                    contact.ContactType = CollisionType.FaceFace;
                    contact.ContactNormal = normals[index];
                    contact.PenetrationDepth = sphere.Radius - Distances[index]; //+

                    contact.ContactPoint = sphere.Position - contact.ContactNormal * VertexDistances[index];
                    contact.DeepestPoint = sphere.Position - contact.ContactNormal * (sphere.Radius);

                    return contact;

                }

                #endregion

                #region Edge-Face

                float[] PointDistances = new float[12];
                Vector3[,] VertexPair = new Vector3[12, 2];

                //Front Vertices
                Vector3 x0 = sphere.Position;
                Vector3 x1 = VertexPair[0, 0] = vertices[0];
                Vector3 x2 = VertexPair[0, 1] = vertices[1];

                PointDistances[0] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[1, 0] = vertices[1];
                x2 = VertexPair[1, 1] = vertices[3];

                PointDistances[1] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[2, 0] = vertices[3];
                x2 = VertexPair[2, 1] = vertices[2];

                PointDistances[2] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[3, 0] = vertices[2];
                x2 = VertexPair[3, 1] = vertices[0];

                PointDistances[3] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                //Back Vertices
                x1 = VertexPair[4, 0] = vertices[4];
                x2 = VertexPair[4, 1] = vertices[5];

                PointDistances[4] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[5, 0] = vertices[5];
                x2 = VertexPair[5, 1] = vertices[7];

                PointDistances[5] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[6, 0] = vertices[7];
                x2 = VertexPair[6, 1] = vertices[6];

                PointDistances[6] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[7, 0] = vertices[6];
                x2 = VertexPair[7, 1] = vertices[4];

                PointDistances[7] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                //Side Vertices
                x1 = VertexPair[8, 0] = vertices[0];
                x2 = VertexPair[8, 1] = vertices[4];

                PointDistances[8] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[9, 0] = vertices[1];
                x2 = VertexPair[9, 1] = vertices[5];

                PointDistances[9] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[10, 0] = vertices[2];
                x2 = VertexPair[10, 1] = vertices[6];

                PointDistances[10] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                x1 = VertexPair[11, 0] = vertices[3];
                x2 = VertexPair[11, 1] = vertices[7];

                PointDistances[11] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length();

                index = 0;

                for (int i = 0; i < PointDistances.Length; i++)
                {
                    if (PointDistances[index] > PointDistances[i])
                    {
                        index = i;
                    }
                }

                if (PointDistances[index] < sphere.Radius)
                {
                    x1 = VertexPair[index, 0];
                    x2 = VertexPair[index, 1];

                    //Required to compute point on the line
                    float t = -Vector3.Dot((x1 - x0), (x2 - x1)) / (x2 - x1).LengthSquared();

                    Vector3 LinePoint = new Vector3(x1.X + (x2.X - x1.X) * t, x1.Y + (x2.Y - x1.Y) * t, x1.Z + (x2.Z - x1.Z) * t);
                    contact.ContactType = CollisionType.EdgeFace;
                    contact.ContactNormal = Vector3.Normalize(x0 - LinePoint);
                    contact.ContactPoint = LinePoint;
                    contact.DeepestPoint = x0 - contact.ContactNormal / contact.ContactNormal.Length() * sphere.Radius;
                    contact.PenetrationDepth = (contact.DeepestPoint - contact.ContactPoint).Length();

                    return contact;
                }
                #endregion

            }
            //No Contact found...
            return null;
        }
 public Contact Collides(Sphere sphere)
 {
     return base.Collides(sphere, this);
 }
        //Sphere --> Sphere Collision Detection and Contact Info generation
        //Returns null if no collision, a contact object if a collision occurs
        protected Contact Collides(Sphere sphere1, Sphere sphere2)
        {
            if ((sphere1.Position - sphere2.Position).Length() <= (sphere1.Radius + sphere2.Radius))
            {
                Contact contact = new Contact();
                contact.ContactType = CollisionType.FaceFace;
                contact.ContactNormal = (sphere1.Position - sphere2.Position) / (sphere1.Position - sphere2.Position).Length();
                Vector3 Midline = (sphere1.Position - sphere2.Position);
                contact.ContactPoint = sphere2.Position + (Midline / Midline.Length() * sphere2.Radius);

                contact.DeepestPoint = (sphere1.Position - (Midline / Midline.Length() * sphere1.Radius));
                contact.PenetrationDepth = sphere1.Radius + sphere2.Radius - Midline.Length();

                return contact;
            }

            //No Collision
            return null;
        }
 //Retrieve Objects nearby given Sphere in the Quad Tree and Superior layers of the quadrant if UpperLayerDepth > 0
 public void RetrieveNearbyObjects(Sphere sphere, ref List<Primitive> primitivesNearby, int UpperLayerDepth = 0)
 {
     RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, null);
 }
        //Retrieve Objects nearby given Sphere in the Quad Tree and Superior layers of the quadrant if UpperLayerDepth > 0
        public void RetrieveNearbyObjects(Sphere sphere, ref List<Primitive> primitivesNearby, int UpperLayerDepth, QuadTreeNode node, int DepthCounter = 0)
        {
            if (node == null)
                node = Head;

            //Process North-West Part
            if (node.Children[0] != null)
            {
                //If Sphere can be found inside the North West quadrant of the current quadrant or if this depth level should be covered, go inside
                if ((sphere.Position.X - sphere.Radius <= node.Position.X && sphere.Position.Z + sphere.Radius <= node.Position.Y) || (this.depth - DepthCounter) <= UpperLayerDepth)
                {
                    RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, node.Children[0], DepthCounter + 1);
                }
            }

            //Process North-East Part
            if (node.Children[1] != null)
            {
                //If Sphere can be found inside the North East quadrant of the current quadrant or if this depth level should be covered, go inside
                if ((sphere.Position.X + sphere.Radius >= node.Position.X && sphere.Position.Z + sphere.Radius <= node.Position.Y) || (this.depth - DepthCounter) <= UpperLayerDepth)
                {
                    RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, node.Children[1], DepthCounter + 1);
                }
            }

            //Process South-West Part
            if (node.Children[2] != null)
            {
                //If Sphere can be found inside the South West quadrant of the current quadrant or if this depth level should be covered, go inside
                if ((sphere.Position.X - sphere.Radius <= node.Position.X && sphere.Position.Z - sphere.Radius >= node.Position.Y) || (this.depth - DepthCounter) <= UpperLayerDepth)
                {
                    RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, node.Children[2], DepthCounter + 1);
                }
            }

            //Process South-East Part
            if (node.Children[3] != null)
            {
                //If Sphere can be found inside the South West quadrant of the current quadrant or if this depth level should be covered, go inside
                if ((sphere.Position.X + sphere.Radius >= node.Position.X && sphere.Position.Z - sphere.Radius >= node.Position.Y) || (this.depth - DepthCounter) <= UpperLayerDepth)
                {
                    RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, node.Children[3], DepthCounter + 1);
                }
            }

            //Return all primitives found in the node
            if (node.Primitives != null)
            {
                //Add all primitives found in the quadrant that aren't already in the list
                foreach (Primitive prim in node.Primitives)
                {
                    if (!primitivesNearby.Contains(prim))
                    {
                        primitivesNearby.Add(prim);
                    }
                }
            }
        }
        private void ResolveStaticCollision(Contact contact, Entity ent, Sphere sphere)
        {
            //-contact.ContactNormal * (Vector3.Dot(-contact.ContactNormal, ent.Velocity));
            Vector3 closingVelocity = contact.ContactNormal * contact.PenetrationDepth;

            //The Y axis vector value of the position should always remain zero.
            closingVelocity.Y = 0;
            ent.Position += closingVelocity;

            if (ent is Hero)
            {
                CastSoundWave(COLLISON_SOUND_RADIUS);
            }
        }
        //Return boxes that generate Quad Tree Grid. It is possible to filter lower levels and display only higher ones by setting UpperLayerDepth to a value > 0
        public List<Box> RetrieveBoundariesFromPosition(Sphere sphere, ref List<Box> boxes, int UpperLayerDepth = 0, QuadTreeNode node = null)
        {
            if (node == null)
                node = Head;

            if (boxes == null)
                boxes = new List<Box>();

            float nodeSize = (float)Math.Pow(2, UpperLayerDepth);

            //Make sure sphere fits in the current node and go deeper
            if (sphere.Radius * 2 < node.Size / nodeSize)
            {
                //Process North-West Part
                if (node.Children[0] != null)
                {
                    if (sphere.Position.X - sphere.Radius <= node.Position.X && sphere.Position.Z + sphere.Radius <= node.Position.Y)
                    {
                        RetrieveBoundariesFromPosition(sphere, ref boxes, UpperLayerDepth, node.Children[0]);
                    }
                }

                //Process North-East Part
                if (node.Children[1] != null)
                {
                    if (sphere.Position.X + sphere.Radius >= node.Position.X && sphere.Position.Z + sphere.Radius <= node.Position.Y)
                    {

                        RetrieveBoundariesFromPosition(sphere, ref boxes, UpperLayerDepth, node.Children[1]);
                    }
                }

                //Process South-West Part
                if (node.Children[2] != null)
                {
                    if (sphere.Position.X - sphere.Radius <= node.Position.X && sphere.Position.Z - sphere.Radius >= node.Position.Y)
                    {

                        RetrieveBoundariesFromPosition(sphere, ref boxes, UpperLayerDepth, node.Children[2]);
                    }
                }

                //Process South-East Part
                if (node.Children[3] != null)
                {
                    if (sphere.Position.X + sphere.Radius >= node.Position.X && sphere.Position.Z - sphere.Radius >= node.Position.Y)
                    {

                        RetrieveBoundariesFromPosition(sphere, ref boxes, UpperLayerDepth, node.Children[3]);
                    }
                }
            }

            //return box sized based on depth level
            boxes.Add(new Box(new Vector3(node.Position.X, 1.5f, node.Position.Y), new Vector3(0), new Vector3(node.Size * 2, 3, node.Size * 2)));

            return boxes;
        }
        //checking zombie to zombie collisions.
        //Model as a sphere (in reality just a cylinder but since all at same height it only checks for a circle radius around character
        private void checkZombietoZombie(Zombie z1, Zombie z2)
        {
            //creating appropriate shapes
            Sphere p1 = new Collisions.Sphere(z1.Position, z1.Velocity, z1.modelRadius);
            Sphere p2 = new Collisions.Sphere(z2.Position, z2.Velocity, z2.modelRadius);

            Contact c = p1.Collides(p2);

            if (c != null)
            {
                if (c.DeepestPoint.Length() > 0)
                {
                    z1.Position -= c.DeepestPoint - c.ContactPoint;
                    z2.Position += c.DeepestPoint - c.ContactPoint;
                }
            }
        }
        private void DoGunAttack(Weapon weapon, Entity actionCaster)
        {
            //do soundeffect attached
            if (weapon.weaponType == WeaponType.Handgun9mm)
            {
                if (Player.PowerupsList.Contains(silencer))
                {
                    sound.StopSilencer();
                    //need to check the time
                    sound.playSilencer();
                }
                else
                {
                    sound.Stopgun();
                    sound.playgun();
                }
            }
            if (weapon.weaponType == WeaponType.Magnum)
            {
                sound.StopMagnum();
                //need to check the time
                sound.playMagnum();
            }

            // find closest zombie, if any, in the line of fire and have him take the damage
            Ray ray = new Ray(actionCaster.Position, Vector3.Normalize(actionCaster.Velocity));
            Zombie closestVictim = null;
            float? closestIntersect = 100;
            foreach (Zombie z in zombies)
            {
                if ((z.Position - actionCaster.Position).Length() < weapon.Range)
                {
                    BoundingSphere bs = new BoundingSphere(z.Position, z.modelRadius);
                    float? intersection = ray.Intersects(bs);
                    if (intersection != null && intersection < closestIntersect)
                    {
                        closestIntersect = intersection;
                        closestVictim = z;
                    }
                }
            }

            // check if ray intersects nearby primitives from quad tree
            // if so, check if intersections are closer than the closest zombie intersection
            Sphere heroSphere = new Sphere(actionCaster.Position, actionCaster.Velocity, actionCaster.modelRadius);
            List<Primitive> primitives = new List<Primitive>();
            LevelQuadTree.RetrieveNearbyObjects(heroSphere, ref primitives);

            foreach (Box box in primitives)
            {
                BoundingBox bbox = new BoundingBox(
                    new Vector3(box.Position.X - box.Size.X / 2, box.Position.Y - box.Size.Y / 2, box.Position.Z - box.Size.Z / 2),
                    new Vector3(box.Position.X + box.Size.X / 2, box.Position.Y + box.Size.Y / 2, box.Position.Z + box.Size.Z / 2)
                );
                if (ray.Intersects(bbox) != null && ray.Intersects(bbox) < closestIntersect)
                    return;
            }
            if (closestVictim != null)
            {
                closestVictim.Alert(actionCaster as Hero);
                if (weapon.weaponType == WeaponType.Magnum && closestIntersect > 20)
                    closestVictim.TakeDamage(weapon.FirePower / 10);
                else if (weapon.weaponType == WeaponType.Magnum && closestIntersect > 10)
                    closestVictim.TakeDamage(weapon.FirePower / 5);
                else
                    closestVictim.TakeDamage(weapon.FirePower);
            }
        }
        //checking zombie to character
        private void checkZombietoPlayer(Zombie z)
        {
            Sphere p1 = new Collisions.Sphere(z.Position, z.Velocity, z.modelRadius);
            Sphere p2 = new Collisions.Sphere(Player.Position, Player.Velocity, Player.modelRadius);

            Contact c = p1.Collides(p2);

            if (c != null)
            {
                if (c.DeepestPoint.Length() > 0)
                {
                    if (Player.Stance == AnimationStance.Standing)//if standing, dont push player, only affect zombie
                    {
                        z.Position -= c.DeepestPoint - c.ContactPoint;
                        Player.Position += c.DeepestPoint - c.ContactPoint;
                    }
                    else//push player back when walking
                    {
                        z.Position -= c.DeepestPoint - c.ContactPoint;
                    }
                }
            }
        }
        // returns if there are any static obstructions between the two positions
        private bool CheckObstructions(Vector3 position, Vector3 destination)
        {
            Ray ray = new Ray(position, Vector3.Normalize(destination - position));
            Sphere sphere = new Sphere(position, Vector3.Zero, 1);
            List<Primitive> primitives = new List<Primitive>();
            LevelQuadTree.RetrieveNearbyObjects(sphere, ref primitives);

            foreach (Box box in primitives)
            {
                BoundingBox bbox = new BoundingBox(
                    new Vector3(box.Position.X - box.Size.X / 2, box.Position.Y - box.Size.Y / 2, box.Position.Z - box.Size.Z / 2),
                    new Vector3(box.Position.X + box.Size.X / 2, box.Position.Y + box.Size.Y / 2, box.Position.Z + box.Size.Z / 2)
                );
                if (ray.Intersects(bbox) != null)
                    return true;
            }
            return false;
        }
        private void CheckCollisions(bool Extinguisher)
        {
            #region Player collisions

            Sphere heroSphere = new Sphere(Player.Position, Player.Velocity, Player.modelRadius);
            List<Primitive> primitivesNearby = new List<Primitive>();
            LevelQuadTree.RetrieveNearbyObjects(heroSphere, ref primitivesNearby,2);

            /*foreach (Primitive bx in primitivesNearby)
            {
                if (!TotalNearbyBoxes.Contains(bx))
                    TotalNearbyBoxes.Add(bx);
            }*/

            Contact EndingContact = heroSphere.Collides(EscapeSpot);

            if (EndingContact != null && (Player.ItemsList.ContainsKey(key1) || Player.ItemsList.ContainsKey(key2)))
            {
                GameStates.GameStates.ZombieGameState = GameStates.GameStates.GameState.End;
            }

            primitivesNearby.AddRange(fireHazards);
            foreach (Primitive p in primitivesNearby)
            {
                Contact c = heroSphere.Collides(p as Box);
                if (c != null)
                {
                    ResolveStaticCollision(c, Player, heroSphere);
                    if(fireDamageDelay <=0)
                    {
                        if(((Box)p).Tag == "Fire1" || ((Box)p).Tag == "Fire2" || ((Box)p).Tag == "Fire3" || ((Box)p).Tag == "Fire4")
                        {
                            Player.TakeDamage(25);
                            fireDamageDelay = 5;
                        }
                    }
                }
            }

            if (Extinguisher)
            {
                Sphere ExtSphere = new Sphere(Player.Position + (Player.Velocity / Player.Velocity.Length()) * 20, Vector3.One, 10);

                for (int i = 0; i < fireHazards.Count;i++)
                {
                    Sphere boxSphere = new Sphere(fireHazards[i].Position, Vector3.One, fireHazards[i].Size.X / 2);

                    Contact contact = ExtSphere.Collides(boxSphere);
                    if (contact != null)
                    {
                        if (fireHazards[i].Tag == "Fire1")
                        {
                            FireEmitter.particleGroups[0].controller.LifeSpan -= 5;
                            if (FireEmitter.particleGroups[0].controller.LifeSpan <= 0)
                            {
                                FireEmitter.Stop();
                                fireHazards.Remove(fireHazards[i]);
                            }
                        }
                        if (fireHazards.Count > 0)
                        {
                            if (fireHazards[i].Tag == "Fire2")
                            {
                                FireEmitter2.particleGroups[0].controller.LifeSpan -= 5;
                                if (FireEmitter2.particleGroups[0].controller.LifeSpan <= 0)
                                {
                                    FireEmitter2.Stop();
                                    fireHazards.Remove(fireHazards[i]);
                                }
                            }
                            if (fireHazards[i].Tag == "Fire3")
                            {
                                FireEmitter3.particleGroups[0].controller.LifeSpan -= 5;
                                if (FireEmitter3.particleGroups[0].controller.LifeSpan <= 0)
                                {
                                    FireEmitter3.Stop();
                                    fireHazards.Remove(fireHazards[i]);
                                }
                            }
                            if (fireHazards[i].Tag == "Fire4")
                            {
                                FireEmitter4.particleGroups[0].controller.LifeSpan -= 5;
                                if (FireEmitter4.particleGroups[0].controller.LifeSpan <= 0)
                                {
                                    FireEmitter4.Stop();
                                    fireHazards.Remove(fireHazards[i]);
                                }
                            }
                        }
                    }
                }
            }

            #endregion

            #region Zombie collisions

            foreach (Zombie z in zombies)
            {
                // Check for zombies in sight radius and zombies who are not wandering
                if ((z.Position - Player.Position).Length() < SIGHT_RADIUS || z.BehaviouralState != BehaviourState.Wander)
                {
                    Sphere zombieSphere = new Sphere(z.Position, z.Velocity, z.modelRadius);
                    List<Primitive> primitives = new List<Primitive>();
                    LevelQuadTree.RetrieveNearbyObjects(zombieSphere, ref primitives);
                    primitives.AddRange(fireHazards);
                    foreach (Primitive p in primitives)
                    {
                        Contact c = zombieSphere.Collides(p as Box);
                        if (c != null)
                        {
                            if (z.BehaviouralState == BehaviourState.Wander)
                                z.Velocity = Vector3.Cross( z.Velocity, Vector3.Up);
                            ResolveStaticCollision(c, z, zombieSphere);
                        }
                    }
                }
            }

            #endregion

            foreach (Zombie z1 in zombies)
            {
                if ((z1.Position - Player.Position).Length() < SIGHT_RADIUS || z1.BehaviouralState != BehaviourState.Wander)
                {
                    checkZombietoPlayer(z1);
                    foreach (Zombie z2 in zombies)
                    {
                        if (!z2.Equals(z1) && ((z2.Position - Player.Position).Length() < SIGHT_RADIUS || z2.BehaviouralState != BehaviourState.Wander))
                        {
                            checkZombietoZombie(z1, z2);
                        }
                    }
                }
            }
            checkItemCollisions();
        }
 // Creates a bounding sphere with the specified radius. Any Zombie intersecting the
 // bounding sphere will be alerted to the Hero's presence
 private void CastSoundWave(float radius)
 {
     if (radius > 0)
     {
         Sphere soundSphere = new Sphere(Player.Position, new Vector3(), radius);
         foreach (Zombie z in zombies)
         {
             Sphere zs = new Sphere(z.Position, z.Velocity, z.modelRadius);
             if (zs.Collides(soundSphere) != null)
                 z.Alert(Player);
         }
     }
 }
        // get closest feasible pathfinding node to the given position
        public PathFinding.Node GetPathfindingNode(Vector3 position, Vector3 destination)
        {
            // perform super secret second purpose
            if (destination != Vector3.Up)
            {
                // if path between positions is clear, return origin, else return up vector
                if (CheckObstructions(position, destination))
                    return new PathFinding.Node(Vector3.Up);
                else
                    return new PathFinding.Node(Vector3.Zero);
            }
            List<PathFinding.Node> possibleMatches = new List<PathFinding.Node>();
            PathFinding.Node reachableNode = null;
            float distanceToNode = 100;

            LevelQuadTree.RetrieveNearbyObjects(position, ref possibleMatches, 2, null, 2);
            foreach (PathFinding.Node node in possibleMatches)
            {
                float separatingDistance = (node.position - position).Length();
                bool clearPath = true;

                Ray ray = new Ray(position, Vector3.Normalize(node.position - position));
                Sphere sphere = new Sphere(position, Vector3.Zero, 1);
                List<Primitive> primitives = new List<Primitive>();
                LevelQuadTree.RetrieveNearbyObjects(sphere, ref primitives);

                foreach (Box box in primitives)
                {
                    BoundingBox bbox = new BoundingBox(
                        new Vector3(box.Position.X - box.Size.X / 2, box.Position.Y - box.Size.Y / 2, box.Position.Z - box.Size.Z / 2),
                        new Vector3(box.Position.X + box.Size.X / 2, box.Position.Y + box.Size.Y / 2, box.Position.Z + box.Size.Z / 2)
                    );
                    if (ray.Intersects(bbox) != null && ray.Intersects(bbox) < separatingDistance)
                    {
                        clearPath = false;
                        break;
                    }
                }
                if (clearPath && distanceToNode > separatingDistance)
                {
                    distanceToNode = separatingDistance;
                    reachableNode = node;
                }
            }
            return reachableNode;
        }