void Officer::RenderFlag( float _predictionTime )
{
    float timeIndex = g_gameTime + m_id.GetUniqueId() * 10;
    float size = 20.0f;

    Vector3 up = g_upVector;
    Vector3 front = m_front * -1;
    front.y = 0;
    front.Normalise();

    if( m_orders != OrderNone )
    {
        up.RotateAround( front * sinf(timeIndex*2) * 0.3f );
    }

    Vector3 entityUp = g_upVector;
    Vector3 entityRight(m_front ^ entityUp);
    Vector3 entityFront = entityUp ^ entityRight;
    Matrix34 mat( entityFront, entityUp, m_pos + m_vel * _predictionTime );
    Vector3 flagPos = m_flagMarker->GetWorldMatrix(mat).pos;

    int texId = -1;
    if      ( m_orders == OrderNone )                   texId = g_app->m_resource->GetTexture( "icons/banner_none.bmp" );
    else if ( m_orders == OrderGoto )                   texId = g_app->m_resource->GetTexture( "icons/banner_goto.bmp" );
    else if ( m_orders == OrderFollow && !m_absorb )    texId = g_app->m_resource->GetTexture( "icons/banner_follow.bmp" );
    else if ( m_orders == OrderFollow && m_absorb )     texId = g_app->m_resource->GetTexture( "icons/banner_absorb.bmp" );

    m_flag.SetTexture( texId );
    m_flag.SetPosition( flagPos );
    m_flag.SetOrientation( front, up );
    m_flag.SetSize( size );
    m_flag.Render();
}
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 FeedingTube::RenderSignal( double _predictionTime, double _radius, double _alpha )
{
	START_PROFILE( "Signal");

    FeedingTube *receiver = (FeedingTube *) g_app->m_location->GetBuilding( m_receiverId );
    if( !receiver ) return;

    Vector3 startPos = GetStartPoint();
    Vector3 endPos = GetEndPoint();
    Vector3 delta = endPos - startPos;
    Vector3 deltaNorm = delta;
    deltaNorm.Normalise();

    double distance = (startPos - endPos).Mag();
    double numRadii = 20.0;
    int numSteps = int( distance / 200.0 );
    numSteps = max( 1, numSteps );

    glEnable            (GL_TEXTURE_2D);

    gglActiveTextureARB  (GL_TEXTURE0_ARB);
    glBindTexture	    (GL_TEXTURE_2D, g_app->m_resource->GetTexture("textures/laserfence.bmp", true, true));
	glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    glTexEnvf           (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
    glTexEnvf           (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);        
    glEnable            (GL_TEXTURE_2D);

    gglActiveTextureARB  (GL_TEXTURE1_ARB);
    glBindTexture	    (GL_TEXTURE_2D, g_app->m_resource->GetTexture("textures/radarsignal.bmp", true, true));
	glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    glTexEnvf           (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
    glTexEnvf           (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); 
    glEnable            (GL_TEXTURE_2D);

    glDisable           (GL_CULL_FACE);
    glBlendFunc         (GL_SRC_ALPHA, GL_ONE);
    glEnable            (GL_BLEND);
    glDepthMask         (false);
    glColor4f           (1.0,1.0,1.0,_alpha);            
    
    glMatrixMode        (GL_MODELVIEW);
    glTranslatef        ( startPos.x, startPos.y, startPos.z );    
	Vector3 dishFront   = GetForwardsClippingDir(_predictionTime, receiver);
    double eqn1[4]      = { dishFront.x, dishFront.y, dishFront.z, -1.0 };
    glClipPlane         (GL_CLIP_PLANE0, eqn1 );


    Vector3 receiverPos = receiver->GetDishPos( _predictionTime );
    Vector3 receiverFront = receiver->GetForwardsClippingDir( _predictionTime, this );
    glTranslatef        ( -startPos.x, -startPos.y, -startPos.z );
    glTranslatef        ( receiverPos.x, receiverPos.y, receiverPos.z );

    double eqn2[4]      = { receiverFront.x, receiverFront.y, receiverFront.z, -1.0 };
    glClipPlane         (GL_CLIP_PLANE1, eqn2 );
    glTranslatef        ( -receiverPos.x, -receiverPos.y, -receiverPos.z );


	//RenderArrow(startPos, startPos + dishFront * 100, 2.0, RGBAColour( 0, 255, 0, 255 ) );
	//RenderArrow(endPos, endPos + receiverFront * 100, 2.0, RGBAColour( 255, 0, 0, 255 ) );
	//RenderArrow(startPos, endPos, 2.0 );

    glTranslatef        ( startPos.x, startPos.y, startPos.z );    

    glEnable            (GL_CLIP_PLANE0);
    glEnable            (GL_CLIP_PLANE1);

    double texXInner = -g_gameTime/_radius;
    double texXOuter = -g_gameTime;

    //double texXInner = -1.0/_radius;
    //double texXOuter = -1.0;
	if (true) {
    glBegin( GL_QUAD_STRIP );

    for( int s = 0; s < numSteps; ++s )
    {
        Vector3 deltaFrom = 1.2 * delta * (double) s / (double) numSteps;
        Vector3 deltaTo = 1.2 * delta * (double) (s+1) / (double) numSteps;
        
        Vector3 currentPos = (-delta*0.1) + Vector3(0,_radius,0);
        
        for( int r = 0; r <= numRadii; ++r )
        {   
            gglMultiTexCoord2fARB    ( GL_TEXTURE0_ARB, texXInner, r/numRadii );
            gglMultiTexCoord2fARB    ( GL_TEXTURE1_ARB, texXOuter, r/numRadii );        
            glVertex3dv             ( (currentPos + deltaFrom).GetData() );
    
            gglMultiTexCoord2fARB    ( GL_TEXTURE0_ARB, texXInner+10.0/(double)numSteps, (r)/numRadii );
            gglMultiTexCoord2fARB    ( GL_TEXTURE1_ARB, texXOuter+distance/(200.0 *(double)numSteps), (r)/numRadii );
            glVertex3dv             ( (currentPos + deltaTo).GetData() );
    
            currentPos.RotateAround( deltaNorm * ( 2.0 * M_PI / (double) numRadii ) );
        }

        texXInner += 10.0 / (double) numSteps;
        texXOuter += distance/(200.0 * (double) numSteps);
    }

    glEnd();
	}
    glTranslatef        ( -startPos.x, -startPos.y, -startPos.z );

    glDisable           (GL_CLIP_PLANE0);
    glDisable           (GL_CLIP_PLANE1);
    glDepthMask         (true);
    glDisable           (GL_BLEND);
    glBlendFunc         (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable            (GL_CULL_FACE);

    gglActiveTextureARB  (GL_TEXTURE1_ARB);
    glDisable           (GL_TEXTURE_2D);
    glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

    gglActiveTextureARB  (GL_TEXTURE0_ARB);
    glDisable           (GL_TEXTURE_2D);
    glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri	    (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
    glTexEnvf           (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

	END_PROFILE( "Signal");
}
bool Nuke::AdvanceToTarget()
{
    double remainingDistance = (m_targetPos - m_pos).Mag();
    double fractionDistance = 1 - remainingDistance / m_totalDistance;

    //fractionDistance = max(fractionDistance, 0.1 );

    int direction = 1;
    /*if( m_subPos.x < g_app->m_location->m_landscape.GetWorldSizeX() / 2.0f &&
        m_subPos.z < g_app->m_location->m_landscape.GetWorldSizeZ() / 2.0f)
    {
        direction = -1;
    }*/
    Vector3 subPos = m_subPos;
    double heightFactor = ( subPos - m_targetPos ).Mag() / 3.0;
    Vector3 front = (m_targetPos - m_pos).Normalise();  
    double fractionNorth = 5 * m_pos.y / ( heightFactor );
    fractionNorth = max( fractionNorth, 2.0 );
    
    Vector3 d = (m_targetPos - subPos).Normalise();
    subPos.y = 0.0f;
    Vector3 r = (d ^ g_upVector).Normalise();
    front.RotateAround( r * (M_PI / (direction * fractionNorth ) ));
    front.RotateAround( r * fractionDistance * (-direction * (M_PI/fractionNorth)));

   /* if( front.y < 0.0f && fractionDistance < 0.5f )
    {
        // we're pointing down when we shouldnt be, change direction
        front = (m_targetPos - m_pos).Normalise(); 
        front.RotateAround( r * (M_PI / (-1 * fractionNorth)));
        front.RotateAround( r * fractionDistance * ((M_PI/fractionNorth)));

    }
    */

    //front.RotateAroundZ( M_PI / (fractionNorth) );
    //front.RotateAroundZ( fractionDistance * (-1 * M_PI/fractionNorth) );

    m_vel = Vector3(front * (m_stats[StatSpeed]/2 + m_stats[StatSpeed]/2 * fractionDistance * fractionDistance));
       
    m_pos = m_pos + m_vel * SERVER_ADVANCE_PERIOD;
    double newDistance = ( m_targetPos - m_pos ).Mag();
    m_front = front;

    if( m_pos.y > 150.0 && !m_armed )
    {
        m_armed = true;
    }

    if( (m_pos - m_targetPos).Mag() < 5.0 * g_gameTimer.GetGameSpeed() )
    {
        // explode!
        Vector3 pos = m_pos;
        pos.y = g_app->m_location->m_landscape.m_heightMap->GetValue( m_targetPos.x, m_targetPos.z );

		if( g_app->m_multiwinia->m_coopMode && m_id.GetTeamId() == g_app->m_globalWorld->m_myTeamId )
        {
            // Wrong Game Achievement check
            for( int i = 0; i < g_app->m_location->m_buildings.Size(); ++i )
            {
                if( g_app->m_location->m_buildings.ValidIndex(i) )
                {
                    Building *b = g_app->m_location->m_buildings[i];
                    if( b->m_type == Building::TypeSpawnPoint )
                    {
                        if( ( m_targetPos - b->m_pos ).Mag() < 120.0f )
                        {
                            if( g_app->m_location->IsFriend( m_id.GetTeamId(), b->m_id.GetTeamId() ) )
                            {
                                g_app->GiveAchievement( App::DarwiniaAchievementWrongGame );
                                g_app->m_location->SetCurrentMessage( LANGUAGEPHRASE("dialog_wronggame") );
                                break;
                            }
                        }
                    }
                }
            }
        }

        m_numDeaths = g_app->m_location->Bang( pos, 50.0f, 100.0f );

        g_app->m_soundSystem->TriggerEntityEvent( this, "Explode" );
        m_exploded = true;
        m_casualtyMessageTimer = 5.0f;

        g_app->m_location->m_teams[m_id.GetTeamId()]->m_teamKills += m_numDeaths;
        return true;
    }
    
    return false;  
}