Esempio n. 1
0
void Triangle::computeForces(Vector3 &airVelocity)
{
	this->airVelocity = airVelocity;
	Vector3 velocity = (p1->velocity + p2->velocity + p3->velocity) / 3;

	Vector3 realVelocity = velocity - airVelocity;

	if (realVelocity.Mag() > 0)
	{
		Vector3 *one = new Vector3();
		Vector3 *two = new Vector3();
		one->Cross(p2->position - p1->position, p3->position - p1->position);
		two->Cross(p2->position - p1->position, p3->position - p1->position);
		one->Normalize();
		normal = *one;

		float a0 = 0.5 * two->Mag();
		float a = a0 * (realVelocity.Dot(normal) / realVelocity.Mag());

		Vector3 fAero = -0.5 * density * realVelocity.Mag2() *a *normal;

		Vector3 fAeroParticle = fAero / 3;

		if (!p1->pinned)
			p1->applyForce(fAeroParticle);
		if (!p2->pinned)
			p2->applyForce(fAeroParticle);
		if (!p3->pinned)
			p3->applyForce(fAeroParticle);

		delete one; 
		delete two; 		
	}
}
Vector3 Entity::PushFromCliffs( Vector3 const &pos, Vector3 const &oldPos )
{
    Vector3 horiz = ( pos - oldPos );
    horiz.y = 0.0;
    double horizDistance = horiz.Mag();
    double gradient = (pos.y - oldPos.y) / horizDistance;

    Vector3 result = pos;

    if( gradient > 1.0 )
    {
        double distance = 0.0;
        while( distance < 50.0 )
        {
            double angle = distance * 2.0 * M_PI;
            Vector3 offset( iv_cos(angle) * distance, 0.0, iv_sin(angle) * distance );
            Vector3 newPos = result + offset;
            newPos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( newPos.x, newPos.z );
            horiz = ( newPos - oldPos );
            horiz.y = 0.0;
            horizDistance = horiz.Mag();
            double newGradient = ( newPos.y - oldPos.y ) / horizDistance;
            if( newGradient < 1.0 )
            {
                result = newPos;
                break;
            }
            distance += 0.2;
        }
    }

    return result;
}
Esempio n. 3
0
void pTriangle::ComputeForce(Vector3 vair) {
    //find the tirangle velocity
    velocity = (p1->getVelocity() + p2->getVelocity() + p3->getVelocity()) / 3 ;
    //assume no air velocity for now
    Vector3 v = velocity - vair;
    
    Vector3 r1 = p1->getPosition();
    Vector3 r2 = p2->getPosition();
    Vector3 r3 = p3->getPosition();
    //find triangle unnormalized normal, n*
    Vector3 ra = (r2 - r1);
    Vector3 rb = (r3 - r1);
    Vector3 ncross;
    ncross.Cross(ra, rb);
    
    //constants
    float p = 1.225f;
    float cd = 1.225f;
    
    //force = -1/2 * p * |v|^2 * cd * a * n
    Vector3 v2an = ( (v.Mag()*v.Dot(ncross))/(2.0f*ncross.Mag()) ) * ncross;
    Vector3 aeroForce = (-1.0f/2.0f) * p * cd * v2an;
    aeroForce = aeroForce / 3;
    p1->ApplyForce(aeroForce);
    p2->ApplyForce(aeroForce);
    p3->ApplyForce(aeroForce);
    normal = ncross.Normalize();
}
Esempio n. 4
0
Quaternion RotationBetweenVectors3(Vector3 v1, Vector3 v2)
{
    const float epsilon = 0.0000001;

    double length1 = v1.Mag();
    double length2 = v2.Mag();
    double cosangle = (v1 * v2) / (length1 * length2);

    if (fabs(cosangle-1.0) < epsilon)
    {
        // near co-linear vectors
        return Quaternion(0.0, 0.0, 0.0, 1.0);
    }

    else if (fabs(cosangle+1.0) < epsilon)
    {
        // vectors are opposite, so we need to find an orthogonal vector to v1
        // around which to rotate

        Vector3 tmp;

        if (fabs(v1.x)<fabs(v1.y))
            if (fabs(v1.x)<fabs(v1.z))
                tmp = Vector3(1.0,0.0,0.0); // use x axis.
            else
                tmp = Vector3(0.0,0.0,1.0);
        else if (fabs(v1.y)<fabs(v1.z))
            tmp = Vector3(0.0,1.0,0.0);
        else
            tmp = Vector3(0.0,0.0,1.0);

        // find orthogonal axis.
        Vector3 axis = v2^tmp;
        axis.Normalize();

        // cos of half angle of PI is zero.
        return QuatFromAxis(axis, 0.0);
    }

    else {

        // this is the usual case: take a cross-product of v1 and v2
        // and that is the axis around which to rotate

        Vector3 axis = v1^v2;
        double angle = acos( cosangle );
        return QuatFromAxis(axis, angle);
    }
}
bool SoulDestroyer::SearchForRandomPosition()
{
    Vector3 toSpawnPoint = ( m_pos - m_spawnPoint );
    toSpawnPoint.y = 0.0;
    double distToSpawnPoint = toSpawnPoint.Mag();
    double chanceOfReturn = ( distToSpawnPoint / m_roamRange );
    if( chanceOfReturn >= 1.0 || syncfrand(1.0) <= chanceOfReturn )
    {
        // We have strayed too far from our spawn point
        // So head back there now       
        Vector3 targetPos = m_spawnPoint;
        targetPos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( targetPos.x, targetPos.z );
        targetPos.y += 100.0 + syncsfrand( 100.0 );
        
        Vector3 returnVector = ( targetPos - m_pos );
        returnVector.SetLength( 160.0 );
        m_targetPos = m_pos + returnVector;
    }
    else
    {
        double distance = 160.0;
        double angle = syncsfrand(2.0 * M_PI);

        m_targetPos = m_pos + Vector3( iv_sin(angle) * distance,
                                       0.0,
                                       iv_cos(angle) * distance );  
        m_targetPos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( m_targetPos.x, m_targetPos.z );
        m_targetPos.y += (100.0 + syncsfrand( 100.0 ));        
    }
    
    return true;
}
Esempio n. 6
0
void ParticleSystem::computePressure(){
    float h2 = h*h;
    
    for(int i = 0; i < NumParticles; i++){
        std::vector<Particle *> neighbors = GetNeighbors(Particles[i]);
        
        Vector3 pi = Particles[i]->getPosition();
        Vector3 vi = Particles[i]->getVelocity();
        float pressure_i = Particles[i]->getPressure();
        
        Vector3 sumPressure = Vector3(0, 0, 0);
        Vector3 sumViscosity = Vector3(0, 0, 0);
        for(int j = 0; j < neighbors.size(); j++){
            Vector3 pj = neighbors[j]->getPosition();
            Vector3 vj = neighbors[j]->getVelocity();
            float pressure_j = neighbors[j]->getPressure();
            float density_j = neighbors[j]->getDensity();
            
            Vector3 diff = pi - pj;
            float rad = diff.Mag();
            float rad2 = rad * rad;
            
            if(h2 > rad2 && EPSILON <= rad2){
                float sqr = h - rad;
                sumPressure += diff/rad * ((pressure_i+pressure_j)/(2*density_j)) * sqr * sqr;
                sumViscosity += (vj - vi)/density_j * sqr;
            }
        }
        
        Particles[i]->addForce(sumPressure * (float(particle_mass) * mSpikyKernel * -1.0f));
        Particles[i]->addForce(sumViscosity * float(fluid_viscosity*particle_mass)*mViscosityKernel);
        
    }
}
void Entity::FollowRoute()
{
	AppDebugAssert(m_routeId != -1);
	Route *route = g_app->m_location->m_levelFile->GetRoute(m_routeId);
    
    if( g_app->Multiplayer() ) route = g_app->m_location->m_routingSystem.GetRoute( m_routeId );

	if(!route)
    {
        m_routeId = -1;
        return;
    }

	if (m_routeWayPointId == -1)
	{
		m_routeWayPointId = 0;
	}

    WayPoint *waypoint = route->m_wayPoints.GetData(m_routeWayPointId);
    if( !waypoint )
    {
        m_routeId = -1;
        return;
    }

    SetWaypoint ( waypoint->GetPos() );
	Vector3 targetVect = waypoint->GetPos() - m_pos;

	m_spawnPoint = waypoint->GetPos();

    if (waypoint->m_type != WayPoint::TypeBuilding &&
        targetVect.Mag() < m_routeTriggerDistance )
	{

		m_routeWayPointId++;
		if (m_routeWayPointId >= route->m_wayPoints.Size())
		{
			m_routeWayPointId = -1;
			m_routeId = -1;
		}
	}

    //
    // If its a building instead of a 3D pos, this unit will never
    // get to the next waypoint.  A new unit is created when the unit
    // enters the teleport, and taht new unit will automatically
    // continue towards the next waypoint instead.
    //
}
Esempio n. 8
0
bool pTriangle::TestSegment(const Segment &s, Intersection &i) {
    Vector3 v0 = p1->getPosition();
    Vector3 v1 = p2->getPosition();
    Vector3 v2 = p3->getPosition();
    
    float da = (s.A - v0).Dot(normal);
    float db = (s.B - v0).Dot(normal);
    
    //on same side of triangle
    if (da > 0 && db > 0) return false;
    //inside, place on surface
    if (da < 0 && db < 0) return false;
    
    //avoid divide by 0
    if ((da - db) == 0) return false;
    Vector3 x = ((da*s.B)-(db*s.B)) / (da - db);
    
    //convert to barycentric coordinates
    Vector3 xPrime = x - v0;
    Vector3 e1 = v1 - v0;
    Vector3 e2 = v2 - v0;
    
    float denom = e1.Dot(e2);
    //avoid divide by 0
    if (denom == 0) return false;
    
    float alpha = (xPrime.Dot(e2)) / denom;
    float beta = (xPrime.Dot(e1)) / denom;
    
    if (alpha < 0 || beta < 0 || (alpha+beta) > 1) return false;
    
    Vector3 temp = s.B - v0;
    float d = temp.Dot(normal);
    if (d < 0) {
        //point is behind the triangle face
        d = -d;
        x = x * (1- d/x.Mag());
    }
    
    i.Position = x;
    i.Normal = normal;
    
    return true;
}
void Entity::AdvanceInWater( Unit *_unit )
{
    m_inWater += SERVER_ADVANCE_PERIOD;
    if( m_inWater > 10.0 /* && m_type != TypeInsertionSquadie */ )
    {
        ChangeHealth( -500 );
    }

    Vector3 targetPos;
    if( _unit )
    {
        targetPos = _unit->GetWayPoint();
        targetPos.y = 0.0;
        Vector3 offset = _unit->GetFormationOffset(Unit::FormationRectangle, m_id.GetIndex() );
        targetPos += offset;
    }

    if( targetPos != g_zeroVector )
    {
        Vector3 distance = targetPos - m_pos;
        distance.y = 0.0;
        m_vel = distance;
        m_vel.Normalise();
        m_front = m_vel;
        m_vel *= m_stats[StatSpeed] * 0.3;

        if (distance.Mag() < m_vel.Mag() * SERVER_ADVANCE_PERIOD)
        {                    
            m_vel = distance / SERVER_ADVANCE_PERIOD;
        }
    }

    m_vel.SetLength( 5.0 );
    m_pos += m_vel * SERVER_ADVANCE_PERIOD;
    m_pos.y = 0.0 - iv_sin(m_inWater * 3.0) - 4.0;

    double groundLevel = g_app->m_location->m_landscape.m_heightMap->GetValue(m_pos.x, m_pos.z);
    if( groundLevel > 0.0 )
    {
        m_inWater = -1;
    }
}
void SoundLibrary3dSoftware::CalcChannelVolumes(int _channelIndex, 
												float *_left, float *_right)
{
	SoftwareChannel *channel = &m_channels[_channelIndex];

    float calculatedVolume = -(5.0f - channel->m_volume * 0.5f);
    calculatedVolume += m_masterVolume * 0.001f;

	if( calculatedVolume < -10.0f ) calculatedVolume = -10.0f;
	if( calculatedVolume > 0.0f ) calculatedVolume = 0.0f;
	calculatedVolume = expf(calculatedVolume);

	if (channel->m_3DMode == SoundLibrary3d::Mode3dPositioned)
	{
		Vector3 to = channel->m_pos - m_listenerPos;
		float dist = to.Mag();
		// DEF: Fixes ambrosia bug # 1371
		// if distance equals zero we don't divide b/c we're right on top of the sound.
		if(dist != 0)
			to /= dist;
		// END DEF
		float dotRight = to * m_listenerRight;
		*_right = (dotRight + 1.0f) * 0.5f;
		*_left = 1.0f - *_right;

		if (dist > channel->m_minDist) 
		{
			float dropOff = channel->m_minDist / dist;
			*_left *= dropOff;
			*_right *= dropOff;
		}
	}
	else
	{
		*_left = 1.0f;
		*_right = 1.0f;
	}

	*_left *= calculatedVolume; 
	*_right *= calculatedVolume; 
}
bool SoulDestroyer::AdvanceToTargetPosition()
{
    double amountToTurn = SERVER_ADVANCE_PERIOD * 2.0;
    Vector3 targetDir = (m_targetPos - m_pos).Normalise();
    if( !m_targetEntity.IsValid() )
    {
        Vector3 right1 = m_front ^ m_up;    
        targetDir.RotateAround( right1 * iv_sin(GetNetworkTime() * 6.0) * 1.5 );
    }

    // Look ahead to see if we're about to hit the ground
    Vector3 forwardPos = m_pos + targetDir * 50.0;
    double landHeight = g_app->m_location->m_landscape.m_heightMap->GetValue(forwardPos.x, forwardPos.z);
    if( forwardPos.y <= landHeight )
    {
        targetDir = g_upVector;
    }

    Vector3 actualDir = m_front * (1.0 - amountToTurn) + targetDir * amountToTurn;
    actualDir.Normalise();
    double speed = m_stats[StatSpeed];
    speed = 130.0;
    
    Vector3 oldPos = m_pos;
    Vector3 newPos = m_pos + actualDir * speed * SERVER_ADVANCE_PERIOD;
    landHeight = g_app->m_location->m_landscape.m_heightMap->GetValue( newPos.x, newPos.z );
    //newPos.y = max( newPos.y, landHeight );
    
    Vector3 moved = newPos - oldPos;
    if( moved.Mag() > speed * SERVER_ADVANCE_PERIOD ) moved.SetLength( speed * SERVER_ADVANCE_PERIOD );
    newPos = m_pos + moved;

    m_pos = newPos;       
    m_vel = ( m_pos - oldPos ) / SERVER_ADVANCE_PERIOD;
    m_front = actualDir;
                
    Vector3 right = m_front ^ g_upVector;
    m_up = right ^ m_front;
    
    return ( m_pos - m_targetPos ).Mag() < 40.0;
}
void DrawGrid(Vector3 const &_camPos)
{
	float camPosMag = _camPos.Mag();
	int scale = log(camPosMag);
	float multiplier = exp(scale) * 0.1f;

	glScalef(multiplier, multiplier, multiplier);
	glColor3ub(99,99,99);
	glLineWidth(1.0f);
	glBegin(GL_LINES);
		for (int x = -10; x < 10; x++)
		{
			for (int y = -10; y < 10; y++)
			{
				glVertex3f(x, 0, y);
				glVertex3f(x+1, 0, y);
			}
		}
		for (int x = -10; x < 10; x++)
		{
			for (int y = -10; y < 10; y++)
			{
				glVertex3f(x, 0, y);
				glVertex3f(x, 0, y + 1);
			}
		}
	glEnd();
	glColor3ub(255,255,255);
	glLineWidth(2.0f);
	glBegin(GL_LINES);
		glVertex3f(-10, 0, 0);
		glVertex3f(10, 0, 0);
		glVertex3f(0, 0, -10);
		glVertex3f(0, 0, 10);
	glEnd();

	glScalef(1/multiplier, 1/multiplier, 1/multiplier);
}
bool OfficerOrders::Advance()
{
    if( m_arrivedTimer >= 0.0f )
    {
        // We are already here, so just fade out
        m_vel.Zero();
        m_arrivedTimer += SERVER_ADVANCE_PERIOD;
        if( m_arrivedTimer > 1.0f ) return true;
    }
    else
    {
        float speed = m_vel.Mag();
        speed *= 1.1f;
        speed = max( speed, 30.0f );
        speed = min( speed, 150.0f );

        Vector3 toWaypoint = ( m_wayPoint - m_pos );
        toWaypoint.y = 0.0f;
        float distance = toWaypoint.Mag();

        toWaypoint.Normalise();
        m_vel = toWaypoint * speed;
        Vector3 oldPos = m_pos;
        m_pos += m_vel * SERVER_ADVANCE_PERIOD;

        float landHeight = g_app->m_location->m_landscape.m_heightMap->GetValue( m_pos.x, m_pos.z );
        m_pos.y = landHeight + 2.0f;

        m_vel = ( m_pos - oldPos ) / SERVER_ADVANCE_PERIOD;

        g_app->m_particleSystem->CreateParticle( oldPos, g_zeroVector, Particle::TypeMuzzleFlash, 30.0f );

        if( m_vel.Mag() * SERVER_ADVANCE_PERIOD > distance ) m_arrivedTimer = 0.0f;
        if( distance < 3.0f ) m_arrivedTimer = 0.0f;
    }

    return false;
}
Esempio n. 14
0
Vector3 cartesianToSpherical(Vector3 v)
{
	// http://en.wikipedia.org/wiki/Spherical_coordinate_system
	// but modified, since ground ref is the XY plane

	double azim, elev, dist;
	
	dist = v.Mag();
	azim = atan2(v.y,v.x) - M_PI/2;

	// put in range of [-pi,pi]
	if (azim > M_PI)
		azim -= 2 * M_PI;
    else if (azim < -M_PI)
		azim += 2 * M_PI;
	
	if (dist > 0.000001)
		elev = M_PI/2 - acos(v.z/dist);
	else
		elev = 0.0;
	
	return Vector3(azim, elev, dist);
}
Vector3 Entity::PushFromEachOther( Vector3 const &_pos )
{
    Vector3 result = _pos;

    int numFound;
    g_app->m_location->m_entityGrid->GetNeighbours( s_neighbours, _pos.x, _pos.z, 2.0, &numFound );


    for( int i = 0; i < numFound; ++i )   
    {        
        WorldObjectId id = s_neighbours[i];
        if( !( id == m_id ) )
        {
            WorldObject *obj = g_app->m_location->GetEntity( id );
//            double distance = (obj->m_pos - thisPos).Mag();
//            while( distance < 1.0 )
//            {
//                Vector3 pushForce = (obj->m_pos - thisPos).Normalise() * 0.1;
//                if( obj->m_pos == thisPos ) pushForce = Vector3(0.0,0.0,1.0);
//                thisPos -= pushForce;                
//                distance = (obj->m_pos - thisPos).Mag();
//            }

            Vector3 diff = ( _pos - obj->m_pos );        
            double force = 0.1 / diff.Mag();
            diff.Normalise();        

            Vector3 thisDiff = ( diff * force );
            result += thisDiff;            
            
        }
    }

    result.y = g_app->m_location->m_landscape.m_heightMap->GetValue( result.x, result.z );
    return result;
}
void LocationEditor::Render()
{
    //
    // Render our buildings
	
	g_app->m_renderer->SetObjectLighting();
    LevelFile *levelFile = g_app->m_location->m_levelFile;
    for( int i = 0; i < levelFile->m_buildings.Size(); ++i )
    {
        if( levelFile->m_buildings.ValidIndex(i) )
        {
            Building *b = levelFile->m_buildings.GetData(i);
            b->Render(0.0);
        }
    } 
    g_app->m_renderer->UnsetObjectLighting();
	if (m_mode == ModeBuilding)
	{
		for( int i = 0; i < levelFile->m_buildings.Size(); ++i )
		{
			if( levelFile->m_buildings.ValidIndex(i) )
			{
				Building *b = levelFile->m_buildings.GetData(i);
				b->RenderAlphas(0.0);
				b->RenderLink();
			}
		}
	}


	// 
	// Render camera mounts

	{
		g_app->m_renderer->SetObjectLighting();
		Shape *camShape = g_app->m_resource->GetShape("camera.shp");
		Matrix34 mat;
		
		for (int i = 0; i < g_app->m_location->m_levelFile->m_cameraMounts.Size(); ++i)
		{
			CameraMount *mount = g_app->m_location->m_levelFile->m_cameraMounts[i];
			Vector3 camToMount = g_app->m_camera->GetPos() - mount->m_pos;
			if (camToMount.Mag() < 20.0) continue;
			mat.OrientFU(mount->m_front, mount->m_up);
			mat.pos = mount->m_pos;
			camShape->Render(0.0, mat);
		}
	    g_app->m_renderer->UnsetObjectLighting();
	}


    g_app->m_renderer->UnsetObjectLighting();


	// 
	// Render our instant units
	
	for (int i = 0; i < levelFile->m_instantUnits.Size(); ++i)
	{
		InstantUnit *iu = levelFile->m_instantUnits.GetData(i);
		RenderUnit(iu);
	}

	switch (m_mode)
	{
		case ModeLandTile:			RenderModeLandTile();				break;
		case ModeLandFlat:			RenderModeLandFlat();				break;
		case ModeBuilding:			RenderModeBuilding();				break;
		case ModeLight:													break;
		case ModeInstantUnit:		RenderModeInstantUnit();			break;
		case ModeCameraMount:		RenderModeCameraMount();			break;
	}

	
	//
	// Render axes

	float sizeX = g_app->m_location->m_landscape.GetWorldSizeX() / 2;
	float sizeZ = g_app->m_location->m_landscape.GetWorldSizeZ() / 2;
	RenderArrow(Vector3(10, 200, 0), Vector3(sizeX, 200, 0), 4.0);
	glBegin(GL_LINES);
		glVertex3f(sizeX,      250, 0);
		glVertex3f(sizeX + 90, 150, 0);
		glVertex3f(sizeX,      150, 0);
		glVertex3f(sizeX + 90, 250, 0);
	glEnd();
	glDisable(GL_BLEND);
	glDisable(GL_LINE_SMOOTH);

	RenderArrow(Vector3(0, 200, 10), Vector3(0, 200, sizeZ), 4.0);
	glBegin(GL_LINES);
		glVertex3f(0, 250, sizeZ);
		glVertex3f(0, 250, sizeZ + 90);
		glVertex3f(0, 250, sizeZ);
		glVertex3f(0, 150, sizeZ + 90);
		glVertex3f(0, 150, sizeZ);
		glVertex3f(0, 150, sizeZ + 90);
	glEnd();
	glDisable(GL_BLEND);
	glDisable(GL_LINE_SMOOTH);


    //
    // Render targetting crosshair

    g_app->m_renderer->SetupMatricesFor2D();
	glColor3ub(255,255,255);
    glLineWidth( 1.0 );
    glBegin( GL_LINES );
        glVertex2i( g_app->m_renderer->ScreenW()/2, g_app->m_renderer->ScreenH()/2 - 30 );
        glVertex2i( g_app->m_renderer->ScreenW()/2, g_app->m_renderer->ScreenH()/2 + 30 );

        glVertex2i( g_app->m_renderer->ScreenW()/2 - 30, g_app->m_renderer->ScreenH()/2 );
        glVertex2i( g_app->m_renderer->ScreenW()/2 + 30, g_app->m_renderer->ScreenH()/2 );
    glEnd();
    g_app->m_renderer->SetupMatricesFor3D();
    

	CHECK_OPENGL_STATE();
}
bool DustBall::Advance()
{
    double speed = DUSTBALL_SPEED;

    if( s_vortexPos != g_zeroVector )
    {
        /*double speed = DUSTBALL_SPEED / 5.0;
        speed /= (m_pos.y / 1000.0);
        speed = max( speed, 100.0 );
        speed = min( speed, 500.0 );
        Vector3 thisVortexPos = s_vortexPos;
        thisVortexPos.y = m_pos.y;
        Vector3 oldPos = m_pos;
        double amountToTurn = SERVER_ADVANCE_PERIOD * (1.0 / (m_pos.y / 1000.0));
        Vector3 targetDir = (thisVortexPos - m_pos).Normalise();
        Vector3 actualDir = m_vel.Normalise() * (1.0 - amountToTurn) + targetDir * amountToTurn;
        actualDir.Normalise();

        Vector3 newPos = m_pos + actualDir * speed * SERVER_ADVANCE_PERIOD;

        Vector3 moved = newPos - oldPos;
        if( moved.Mag() > speed * SERVER_ADVANCE_PERIOD ) moved.SetLength( speed * SERVER_ADVANCE_PERIOD );
        newPos = m_pos + moved;*/

        Vector3 vortexPos = s_vortexPos;

        double timeIndex = GetNetworkTime() + m_id.GetUniqueId() * 20;
        double radius = (300.0 * (m_pos.y / 1000.0) );

        Vector3 targetPos = vortexPos;
        targetPos.x += iv_cos( timeIndex ) * radius;
        targetPos.z += iv_sin( timeIndex ) * radius;
        targetPos.y = m_pos.y;

        Vector3 oldPos = m_pos;
        Vector3 actualDir = (targetPos - m_pos).Normalise();

        Vector3 newPos = m_pos + (actualDir * speed * SERVER_ADVANCE_PERIOD);
        Vector3 moved = newPos - oldPos;
        if( moved.Mag() > speed * SERVER_ADVANCE_PERIOD ) moved.SetLength( speed * SERVER_ADVANCE_PERIOD );
        
        m_pos = newPos;       
        m_vel = ( m_pos - oldPos ) / SERVER_ADVANCE_PERIOD;
    }
    else
    {
        Vector3 oldPos = m_pos;
        Vector3 target = m_pos + g_app->m_location->m_windDirection * 2000.0;

        double amountToTurn = SERVER_ADVANCE_PERIOD * 3.0;
        Vector3 targetDir = (target - m_pos).Normalise();
        Vector3 actualDir = m_vel.Normalise() * (1.0 - amountToTurn) + targetDir * amountToTurn;
        actualDir.Normalise();

        Vector3 newPos = m_pos + actualDir * speed * SERVER_ADVANCE_PERIOD;

        Vector3 moved = newPos - oldPos;
        if( moved.Mag() > speed * SERVER_ADVANCE_PERIOD ) moved.SetLength( speed * SERVER_ADVANCE_PERIOD );
        newPos = m_pos + moved;

        m_pos = newPos;       
        m_vel = ( m_pos - oldPos ) / SERVER_ADVANCE_PERIOD;
    }

    if( m_pos.x > g_app->m_location->m_landscape.GetWorldSizeX() ||
        m_pos.z > g_app->m_location->m_landscape.GetWorldSizeZ() ||
        m_pos.x < 0.0 ||
        m_pos.z < 0.0 )
    {
        return true;
    }

    return false;
}
void SoulDestroyer::Attack( Vector3 const &_pos )
{
    int numFound;
    g_app->m_location->m_entityGrid->GetEnemies( s_neighbours, _pos.x, _pos.z, SOULDESTROYER_DAMAGERANGE, &numFound, m_id.GetTeamId() );

    for( int i = 0; i < numFound; ++i )
    {
        WorldObjectId id = s_neighbours[i];
        Entity *entity = (Entity *) g_app->m_location->GetEntity( id );        
        bool killed = false;

        Vector3 pushVector = ( entity->m_pos - _pos );
        double distance = pushVector.Mag();       
        if( distance < SOULDESTROYER_DAMAGERANGE )
        {
            g_app->m_soundSystem->TriggerEntityEvent( this, "Attack" );

            pushVector.SetLength( SOULDESTROYER_DAMAGERANGE - distance );
                                        
            g_app->m_location->m_entityGrid->RemoveObject( id, entity->m_pos.x, entity->m_pos.z, entity->m_radius );
            entity->m_pos += pushVector;
            g_app->m_location->m_entityGrid->AddObject( id, entity->m_pos.x, entity->m_pos.z, entity->m_radius );
            
            bool dead = entity->m_dead;
            entity->ChangeHealth( (SOULDESTROYER_DAMAGERANGE - distance) * -50.0 );            
            if( !dead && entity->m_dead ) killed = true;
        }

        if( killed )
        {
            // Eat the spirit
            int spiritIndex = g_app->m_location->GetSpirit( id );
            if( spiritIndex != -1 )
            {
                g_app->m_location->m_spirits.RemoveData( spiritIndex );
                if( m_spirits.NumUsed() < SOULDESTROYER_MAXSPIRITS )
                {
                    m_spirits.PutData( (double) GetHighResTime() );
                }
                else
                {
                    // Doesnt need to be sync safe
                    int index = AppRandom() % SOULDESTROYER_MAXSPIRITS;
                    m_spirits.PutData( (double) GetHighResTime(), index );
                }
            }
            
			if(entity->m_type == TypeDarwinian )
            {
				// Create a zombie
				Zombie *zombie = new Zombie();
				zombie->m_pos = entity->m_pos;
				zombie->m_front = entity->m_front;
				zombie->m_up = g_upVector;
				zombie->m_up.RotateAround( zombie->m_front * syncsfrand(1) );
				zombie->m_vel = m_vel * 0.5;
				zombie->m_vel.y = 20.0 + syncfrand(25.0);
				int index = g_app->m_location->m_effects.PutData( zombie );
				zombie->m_id.Set( id.GetTeamId(), UNIT_EFFECTS, index, -1 );
				zombie->m_id.GenerateUniqueId();
			}
        }
    } 
}