Esempio n. 1
0
const char *FindCaseInsensitive ( const char *_fullPath )
{

    if ( !_fullPath )
        return NULL;

    static char retval[PATH_MAX];
    char *dir = NULL, *file = NULL;

    if ( (dir = GetDirectoryPart(_fullPath)) != NULL )
    {
        // Make our own copy of the result, since GetDirectoryPart
        // and GetFilenamePart use the same variable for temp
        // storage.
        dir = newStr(dir);
    }
    if ( !dir )
    {
        // No directory provided. Assume working directory.
        file = newStr(_fullPath);
    } else {
        // Kill the last slash
        dir[strlen(dir) - 1] = '\0';
        file = newStr(GetFilenamePart(_fullPath));
    }
    LList <char *> *files = ListDirectory(dir, file);

    delete [] dir; delete [] file; dir = file = NULL;

    // We shouldn't have found more than one match.
    AppAssert(files->Size() <= 1);

    // No results, so maybe the file does not exist.
    if ( files->Size() == 0 )
       return _fullPath;

    // Copy the corrected path back, and prepare to return it.
    memset ( retval, 0, sizeof ( retval ) );
    AppAssert ( strlen ( files->GetData(0) ) < PATH_MAX );
    strcpy ( retval, files->GetData(0) );

    // Negate the possibility of a memory access violation.
    // This way, we can simply strcpy the result inline without
    // worrying about a buffer overflow.
    AppAssert(strlen(retval) == strlen(_fullPath));

    while ( files->Size() )
	{
		char *data = files->GetData(0);
		files->RemoveData(0);
		delete [] data;
	}

    delete files;

    return retval;
}
void EclRender ()
{

    bool maximiseRender = false;

    //
    // Render any maximised Window?

    if( strcmp( maximisedWindow, "None" ) != 0 )
    {
        EclWindow *maximised = EclGetWindow( maximisedWindow );
        if( maximised )
        {
            clearDraw ( maximised->m_x, maximised->m_y, maximised->m_w, maximised->m_h );
            maximised->Render( true );
            maximiseRender = true;
        }
        else
        {
            EclUnMaximise();
        }
    }

    if( !maximiseRender )
    {

        //
        // Clear all dirty rectangle areas

        if ( clearDraw )
        {
            for( int i = 0; i < dirtyrects.Size(); ++i )
            {
                DirtyRect *dr = dirtyrects.GetData(i);
                clearDraw ( dr->m_x, dr->m_y, dr->m_width, dr->m_height );
            }
        }

        //
        // Draw all dirty buttons

        for ( int i = windows.Size() - 1; i >= 0; --i )
        {
            EclWindow *window = windows.GetData(i);
            if ( window->m_dirty ) {
                bool hasFocus = ( strcmp ( window->m_name, windowFocus ) == 0 );
                window->Render( hasFocus );
                //window->m_dirty = false;
            }
        }

    }

}
void LocationEditor::RenderModeCameraMount()
{
	RGBAColour bright(255,255,0);
	RGBAColour dim(90,90,0);

	LList <CameraAnimation*> *list = &g_app->m_location->m_levelFile->m_cameraAnimations;
	for (int i = 0; i < list->Size(); ++i)
	{
		CameraAnimation *anim = list->GetData(i);
		CamAnimNode *lastNode = anim->m_nodes.GetData(0);
		for (int j = 1; j < anim->m_nodes.Size(); ++j)
		{
			CamAnimNode *node = anim->m_nodes.GetData(j);
			if (stricmp(node->m_mountName, MAGIC_MOUNT_NAME_START_POS) == 0 ||
				stricmp(lastNode->m_mountName, MAGIC_MOUNT_NAME_START_POS) == 0)
			{
				continue;
			}

			CameraMount *mount1 = g_app->m_location->m_levelFile->GetCameraMount(lastNode->m_mountName);
			CameraMount *mount2 = g_app->m_location->m_levelFile->GetCameraMount(node->m_mountName);
			if (i == m_selectionId)
			{
				RenderArrow(mount1->m_pos, mount2->m_pos, 1.0, bright);
			}
			else
			{
				RenderArrow(mount1->m_pos, mount2->m_pos, 1.0, dim);
			}

			lastNode = node;
		}
	}
}
int	LocationEditor::IsPosInLandTile(Vector3 const &pos)
{
	Landscape *land = &g_app->m_location->m_landscape;
	LList<LandscapeTile *> *tiles = &g_app->m_location->m_levelFile->m_landscape.m_tiles;
	int smallestId = -1;
	int smallestSize = INT_MAX;

	for (int i = 0; i < tiles->Size(); ++i)
	{
		LandscapeTile *tile = tiles->GetData(i);
		float worldX = tile->m_posX;
		float worldZ = tile->m_posZ;
		float sizeX = tile->m_size;
		float sizeZ = tile->m_size;
		if (pos.x > worldX &&
			pos.x < worldX + sizeX &&
			pos.z > worldZ &&
			pos.z < worldZ + sizeZ) 
		{
			if (tile->m_size < smallestSize)
			{
				smallestId = i;
				smallestSize = tile->m_size;
			}
		}
	}

	return smallestId;
}
void Officer::SetWaypoint( Vector3 const &_wayPoint )
{
		m_wayPoint = _wayPoint;
		m_state = StateToWaypoint;

        //
        // If we clicked near a teleport, tell the officer to go into it
        m_wayPointTeleportId = -1;
        LList<int> *nearbyBuildings = g_app->m_location->m_obstructionGrid->GetBuildings( _wayPoint.x, _wayPoint.z );
        for( int i = 0; i < nearbyBuildings->Size(); ++i )
        {
            int buildingId = nearbyBuildings->GetData(i);
            Building *building = g_app->m_location->GetBuilding( buildingId );
            if( building->m_type == Building::TypeRadarDish ||
                building->m_type == Building::TypeBridge )
            {
                float distance = ( building->m_pos - _wayPoint ).Mag();
                Teleport *teleport = (Teleport *) building;
                if( distance < 5.0f && teleport->Connected() )
                {
                    m_wayPointTeleportId = building->m_id.GetUniqueId();
                    Vector3 entrancePos, entranceFront;
                    teleport->GetEntrance( entrancePos, entranceFront );
                    m_wayPoint = entrancePos;
                    break;
                }
            }
        }
}
void LanguageTable::LoadLanguages()
{
    //
    // Clear out all known languages

    m_languages.EmptyAndDelete();


    //
    // Explore the data/language directory, looking for languages

    LList<char *> *files = g_fileSystem->ListArchive( "data/language/", "*.txt", false );

    for( int i = 0; i < files->Size(); ++i )
    {
        char *thisFile = files->GetData(i);

        Language *lang = new Language();

		snprintf( lang->m_name, sizeof(lang->m_name), thisFile );
		lang->m_name[ sizeof(lang->m_name) - 1 ] = '\0';
		for( char *curName = lang->m_name; *curName; curName++ )
		{
			if( *curName == '.' )
			{
				*curName = '\0';
				break;
			}
		}
		strcpy( lang->m_caption, lang->m_name );

        snprintf( lang->m_path, sizeof(lang->m_path), "data/language/%s", thisFile );
		lang->m_path[ sizeof(lang->m_path) - 1 ] = '\0';

        LoadLanguageCaption( lang );

		if( m_onlyDefaultLanguageSelectable && stricmp( m_defaultLanguage, lang->m_name ) != 0 )
		{
			lang->m_selectable = false;
		}
		else
		{
			lang->m_selectable = true;
		}

        m_languages.PutData( lang );

        AppDebugOut( "Found language '%s' with caption '%s' in '%s'\n", 
                     lang->m_name, 
                     lang->m_caption, 
                     lang->m_path );
    }

    files->EmptyAndDelete();
    delete files;
}
Esempio n. 7
0
char *SoundParameter::GetLinkName( int _type )
{
    if( _type == -1 ) return "Nothing";

    LList<char *> properties;
    g_soundSystem->m_interface->ListProperties( &properties );

    AppDebugAssert( _type >= 0 && _type < properties.Size() );
    return properties[_type];
}
Esempio n. 8
0
void EclRender ()
{

    bool maximiseRender = false;

    //
    // Render any maximised Window?

    if( strcmp( maximisedWindow, "None" ) != 0 )
    {
        EclWindow *maximised = EclGetWindow( maximisedWindow );
        if( maximised )
        {
            maximised->Render( true );
            maximiseRender = true;
        }
        else
        {
            EclUnMaximise();
        }
    }

    if( !maximiseRender )
    {
        for ( int i = windows.Size() - 1; i >= 0; --i )
        {
            EclWindow *window = windows.GetData(i);
            bool hasFocus = ( strcmp ( window->m_name, windowFocus ) == 0 );
            
            START_PROFILE( window->m_name );
            window->Render( hasFocus );
            END_PROFILE( window->m_name );
        }
    }


    //
    // Render the tooltip

    if( tooltipTimer > 0.0f && tooltipCallback )
    {
        EclWindow *window = EclGetWindow();
        if( window )
        {
            EclButton *button = window->GetButton( EclGetCurrentButton() );
            {
                if( button )
                {
                    float timer = GetHighResTime() - tooltipTimer;
                    tooltipCallback( window, button, timer );
                }
            }
        }
    }
}
int EclGetWindowIndex ( char *name )
{
    for ( int i = 0; i < windows.Size(); ++i )
    {
        EclWindow *window = windows.GetData(i);
        if ( strcmp ( window->m_name, name ) == 0 )
            return i;
    }

    return -1;
}
int Entity::EnterTeleports( int _requiredId )
{
    LList<int> *buildings = g_app->m_location->m_obstructionGrid->GetBuildings( m_pos.x, m_pos.z );
    
    for( int i = 0; i < buildings->Size(); ++i )
    {
        int buildingId = buildings->GetData(i);
        if( _requiredId != -1 && _requiredId != buildingId )
        {
            // We are only permitted to enter building with id _requiredId
            continue;
        }

        Building *building = g_app->m_location->GetBuilding( buildingId );
        AppDebugAssert( building );
        
        if( building->m_type == Building::TypeRadarDish  )
        {
            RadarDish *radarDish = (RadarDish *) building;
            Vector3 entrancePos, entranceFront;
            radarDish->GetEntrance( entrancePos, entranceFront );
            double range = ( m_pos - entrancePos ).Mag();
            if( radarDish->ReadyToSend() &&                             
                range < 15.0 &&
                m_front * entranceFront < 0.0 )
            {
                WorldObjectId id(m_id);
                radarDish->EnterTeleport( id );
                g_app->m_soundSystem->TriggerEntityEvent( this, "EnterTeleport" );
                return buildingId;
            }
        }
        else if( building->m_type == Building::TypeBridge )
        {
            Bridge *bridge = (Bridge *) building;
            Vector3 entrancePos, entranceFront;
            if( bridge->GetEntrance( entrancePos, entranceFront ) )
            {
                double range = ( m_pos - bridge->m_pos ).Mag();
                if( bridge->ReadyToSend() &&
                    range < 25.0 &&
                    m_front * entranceFront < 0.0 )
                {
                    WorldObjectId id( m_id );
                    bridge->EnterTeleport( id );
                    g_app->m_soundSystem->TriggerEntityEvent( this, "EnterTeleport" );
                    return buildingId;
                }
            }
        }        
    }

    return -1;
}
void EclDirtyRectangle ( int x, int y, int w, int h )
{
    DirtyRect *dr = new DirtyRect(x, y, w, h);
    dirtyrects.PutData( dr );

    for ( int i = 0; i < windows.Size(); ++i )
    {
        EclWindow *window = windows.GetData(i);
        if ( EclRectangleOverlap( x, y, w, h, window->m_x, window->m_y, window->m_w, window->m_h ) )
            EclDirtyWindow ( window );
    }
}
Esempio n. 12
0
void FileSystem::ParseArchives( const char *_dir, const char *_filter )
{
    LList<char *> *results = ListDirectory( _dir, _filter, false );
    for( int i = 0; i < results->Size(); ++i )
    {
        char fullFilename[512];
        snprintf( fullFilename, sizeof(fullFilename), "%s%s", _dir, results->GetData( i ) );
        fullFilename[ sizeof(fullFilename) - 1 ] = '\0';
        ParseArchive( fullFilename );
    }
    results->EmptyAndDelete();
    delete results;
}
Esempio n. 13
0
void EclUpdate ()
{

    //
    // Update all windows

    for ( int i = 0; i < windows.Size(); ++i )
    {
        EclWindow *window = windows.GetData(i);
        window->Update();
    }

}
void EclResetDirtyRectangles ()
{
    while ( dirtyrects.GetData(0) )
    {
        DirtyRect *dr = dirtyrects.GetData(0);
        delete dr;
        dirtyrects.RemoveData(0);
    }    

    for ( int i = 0; i < windows.Size(); ++i )
    {
        EclWindow *window = windows.GetData(i);
        window->m_dirty = false;
    }
}
Esempio n. 15
0
EclWindow *EclGetWindow ( int x, int y )
{

    for ( int i = 0; i < windows.Size(); ++i )
    {
        EclWindow *window = windows.GetData(i);
        if ( x >= window->m_x && x <= window->m_x + window->m_w &&
             y >= window->m_y && y <= window->m_y + window->m_h )
        {
            return window;
        }
    }

    return NULL;
}
Esempio n. 16
0
int SoundParameter::GetLinkType( char *_name )
{
    LList<char *> properties;
    g_soundSystem->m_interface->ListProperties( &properties );

    for( int i = 0; i < properties.Size(); ++i )
    {
        if( stricmp( properties[i], _name ) == 0 )
        {
            return i;
        }
    }

    return -1;
}
void NewsScreenInterface::ClickNewsButton ( Button *button )
{

	int index;
	sscanf ( button->name, "news_story %d", &index );

	index += baseoffset;

	// Dirty the old button

	char oldname [128];
	UplinkSnprintf ( oldname, sizeof ( oldname ), "news_story %d", currentselect - baseoffset );
	EclDirtyButton ( oldname );

	CompanyUplink *cu = (CompanyUplink *) game->GetWorld ()->GetCompany ( "Uplink" );
	UplinkAssert ( cu );

	if ( cu->GetNews (index) ) {

		currentselect = index;
        
	    // Reset the offset so the player can read it from line 1
        ScrollBox *scrollBox = ScrollBox::GetScrollBox( "news_details" );
        if ( scrollBox ) {
            scrollBox->SetCurrentIndex( 0 );

            char *newDetails = cu->GetNews (index)->GetDetails();
            Button *detailsButton = EclGetButton ( "news_details box" );
            UplinkAssert (detailsButton);
        	LList <char *> *wrappedtext = wordwraptext ( newDetails, detailsButton->width );
			if ( wrappedtext ) {
				scrollBox->SetNumItems( wrappedtext->Size() );
				if ( wrappedtext->ValidIndex (0) && wrappedtext->GetData (0) )
					delete [] wrappedtext->GetData(0);
				delete wrappedtext;
			}
			else {
				scrollBox->SetNumItems( 0 );
			}
        }

		EclRegisterCaptionChange ( "news_details box", cu->GetNews (index)->GetDetails (), 2000 );

	}
	
}
Esempio n. 18
0
void Authentication_RequestStatus( char *_key, int _keyId, char *_ip )
{
    //
    // Does the key already exist in our list?

    s_authResultsMutex.Lock();

    AuthenticationResult *result = NULL;

    for( int i = 0; i < s_authResults.Size(); ++i )
    {
        AuthenticationResult *authResult = s_authResults[i];
        if( strcmp(authResult->m_authKey, _key) == 0 )
        {
            result = authResult;
            break;
        }
    }

    //
    // Add the key to our list if required

    if( !result )
    {
        result = new AuthenticationResult();
        strcpy( result->m_authKey, _key );
        result->m_keyId = _keyId;
        if( _ip ) strcpy( result->m_ip, _ip );
        else      strcpy( result->m_ip, "unknown" );
        
        s_authResults.PutData( result );
    }
    
    s_authResultsMutex.Unlock();    


    //
    // Start the authorisation thread if required

    if( !s_authThreadRunning )
    {
        s_authThreadRunning = true;
        NetStartThread( AuthenticationThread );
    }
}
void GameMenu::CreateMenu()
{
    g_app->m_renderer->StartFadeIn(0.25f);
    // close all currently open windows
    LList<EclWindow *> *windows = EclGetWindows();
	while (windows->Size() > 0) {
		EclWindow *w = windows->GetData(0);
		EclRemoveWindow(w->m_name);
	}

    // create the actual menu window
    EclRegisterWindow( new GameMenuWindow() );

    // set the camera to a position with a good view of the internet
    g_app->m_camera->RequestMode(Camera::ModeMainMenu);
    g_app->m_camera->SetDebugMode(Camera::DebugModeNever);
    g_app->m_camera->SetTarget(Vector3(-900000, 3000000, 397000), Vector3(0,0.5f,-1));
    g_app->m_camera->CutToTarget();

    if( g_app->m_tutorial )
    {
        // its possible that the player has loaded the prologue, then returned to the main menu
        // if so, delete the tutorial
        delete g_app->m_tutorial;
        g_app->m_tutorial = NULL;
    }

    if( g_app->m_demoEndSequence )
    {
        delete g_app->m_demoEndSequence;
        g_app->m_demoEndSequence = NULL;
    }

    /*if( g_app->m_multiwinia )
    {
        delete g_app->m_multiwinia;
        g_app->m_multiwinia = NULL;
    }*/

    g_app->m_gameMode = App::GameModeNone;

    m_menuCreated = true;
}
Esempio n. 20
0
int Authentication_GetStatus( char *_key )
{
    int result = AuthenticationUnknown;

    s_authResultsMutex.Lock();

    for( int i = 0; i < s_authResults.Size(); ++i )
    {
        AuthenticationResult *authResult = s_authResults[i];
        if( strcmp(authResult->m_authKey, _key) == 0 )
        {
            result = authResult->m_authResult;
            break;
        }
    }

    s_authResultsMutex.Unlock();

    return result;
}
void LocationEditor::RenderModeLandFlat()
{
	Vector3 mousePos3D = g_app->m_userInput->GetMousePos3d();
	Landscape *land = &g_app->m_location->m_landscape;

	// Highlight any flatten area under our mouse cursor
	LList<LandscapeFlattenArea *> *areas = &g_app->m_location->m_levelFile->m_landscape.m_flattenAreas;
	for (int i = 0; i < areas->Size(); ++i)
	{
		if (i == m_selectionId) continue;

		LandscapeFlattenArea *area = areas->GetData(i);
		float worldX = area->m_centre.x;
		float worldZ = area->m_centre.z;
		float sizeX = area->m_size;
		float sizeY = area->m_centre.y;
		float sizeZ = area->m_size;
		float x = area->m_centre.x;
		float y = area->m_centre.y;
		float z = area->m_centre.z;
		float s = area->m_size * 2.0;
		Vector3 centre(x, y, z);

		RenderCube(centre, s, y + 20, s, RGBAColour(128,255,128,99));
	}

	if (m_selectionId != -1)
	{
		LandscapeDef *landscapeDef = &(g_app->m_location->m_levelFile->m_landscape);
		LandscapeFlattenArea *areaDef = g_app->m_location->m_levelFile->m_landscape.m_flattenAreas.GetData(m_selectionId);
		float x = areaDef->m_centre.x;
		float y = areaDef->m_centre.y;
		float z = areaDef->m_centre.z;
		float s = areaDef->m_size * 2.0;
		Vector3 centre(x, y, z);

		RenderCube(centre, s, y + 20, s, RGBAColour(128,255,128,255));
	}
	
	CHECK_OPENGL_STATE();
}
Esempio n. 22
0
const char *FindCaseInsensitive( char *_fullPath )
{
    AppAssert(strlen(_fullPath) < PATH_MAX);
    
    static char pathSoFar[PATH_MAX];
    pathSoFar[0] = '\0';
    
    while (true) {
        char *delimiter;
        
        // Skip to the next / or end-of-string
        for (delimiter = (char *)_fullPath; *delimiter && *delimiter != '/'; delimiter++);
        
        char component[PATH_MAX];
        AppAssert ( strlen(_fullPath) < PATH_MAX );
        strcpy( component, _fullPath );
        component[delimiter - _fullPath] = '\0';
    
        // Search for a match
        LList<char *> *matches = ListDirectory( pathSoFar, component, true );
        bool found = false;
    
        if (matches->Size() > 0) {
            strcpy(pathSoFar, matches->GetData( 0 ));
            found = true;
        }
    
        matches->EmptyAndDelete();
    
        // Failed to find a match, just return the original
        if (!found)
            return _fullPath;
        
        // Got to the end of the path, return it
        if (!*delimiter) 
            return pathSoFar;
        
        _fullPath = delimiter + 1;
    }
}
int	LocationEditor::IsPosInFlattenArea(Vector3 const &pos)
{
	LList<LandscapeFlattenArea *> *areas = &g_app->m_location->m_levelFile->m_landscape.m_flattenAreas;
	Landscape *land = &g_app->m_location->m_landscape;

	for (int i = 0; i < areas->Size(); ++i)
	{
		LandscapeFlattenArea *area = areas->GetData(i);
		float halfSize = area->m_size;
		float size = halfSize * 2.0;
		float worldX = area->m_centre.x - halfSize;
		float worldZ = area->m_centre.z - halfSize;
		if (pos.x > worldX &&
			pos.x < worldX + size &&
			pos.z > worldZ &&
			pos.z < worldZ + size) 
		{
			return i;
		}
	}

	return -1;
}
Esempio n. 24
0
void Authentication_SetStatus( char *_key, int _keyId, int _status )
{
    bool authChanged = false;

    s_authResultsMutex.Lock();

    AuthenticationResult *result = NULL;

    for( int i = 0; i < s_authResults.Size(); ++i )
    {
        AuthenticationResult *authResult = s_authResults[i];
        if( strcmp(authResult->m_authKey, _key) == 0 )
        {
            result = authResult;
            break;
        }
    }

    if( !result )
    {
        result = new AuthenticationResult();
        strcpy( result->m_authKey, _key );
        s_authResults.PutData( result );
    }

    if( result->m_authResult != _status )
    {
        char *authString = Authentication_GetStatusString(_status);
        AppDebugOut( "Received Authentication : %s : (keyID %d) : %s\n", _key, _keyId, authString );
    }

    result->m_authResult = _status;
    result->m_keyId = _keyId;

    s_authResultsMutex.Unlock();
}
Esempio n. 25
0
void AlliancesWindow::Update()
{   
    //
    // Build a list of all teams;

    LList<Team *> teams;
    for( int i = 0; i < g_app->GetWorld()->m_teams.Size(); ++i )
    {
        Team *team = g_app->GetWorld()->m_teams[i];
        teams.PutData( team );
    }


    //
    // Now put the other teams in, in alliance order

    int currentIndex = 0;

    while( teams.Size() > 0 )
    {
        Team *baseTeam = teams[0];
        m_teamOrder[currentIndex] = baseTeam->m_teamId;
        ++currentIndex;
        teams.RemoveData(0);

        for( int i = 0; i < teams.Size(); ++i )
        {
            Team *possibleAlly = teams[i];
            if( possibleAlly->m_allianceId == baseTeam->m_allianceId )
            {
                m_teamOrder[currentIndex] = possibleAlly->m_teamId;
                ++currentIndex;
                teams.RemoveData(i);
                --i;
            }
        }
    }

    //
    // Are there any votes we can see?
    
    for( int i = 0; i < MAX_TEAMS; ++i )
    {
        m_votes[i] = -1;
    }    

    currentIndex = 0;
    
    for( int i = 0; i < g_app->GetWorld()->m_votingSystem.m_votes.Size(); ++i )
    {
        if( g_app->GetWorld()->m_votingSystem.m_votes.ValidIndex(i) )
        {
            Vote *vote = g_app->GetWorld()->m_votingSystem.m_votes[i];
            if( vote->m_result == Vote::VoteUnknown &&
                vote->CanSeeVote( g_app->GetWorld()->m_myTeamId ) )
            {
                m_votes[currentIndex] = i;
                ++currentIndex;
            }
        }
    }


    //
    // Make sure we are the right size
   
    m_h = 120 + g_app->GetWorld()->m_teams.Size() * 42;
    m_h += currentIndex * 45;    

    if( currentIndex > 0 ) m_h += 10;
    
    m_h = max(m_h, 300 );

    GetButton("Close")->m_y = m_h - 25;
}
Esempio n. 26
0
void Nuke::FindTarget( int team, int targetTeam, int launchedBy, Fixed range, Fixed *longitude, Fixed *latitude, int *objectId )
{
    START_PROFILE("Nuke::FindTarget");
    
    WorldObject *launcher = g_app->GetWorld()->GetWorldObject(launchedBy);
    if( !launcher ) 
    {
        END_PROFILE("Nuke::FindTarget");
        return;
    }

    LList<int> validTargets;
        
    for( int i = 0; i < g_app->GetWorld()->m_objects.Size(); ++i )
    {
        if( g_app->GetWorld()->m_objects.ValidIndex(i) )
        {
            WorldObject *obj = g_app->GetWorld()->m_objects[i];
            if( obj->m_teamId == targetTeam &&
                obj->m_seen[team] &&
                !obj->IsMovingObject() )
            {
                Fixed distanceSqd = g_app->GetWorld()->GetDistanceSqd( launcher->m_longitude, launcher->m_latitude, obj->m_longitude, obj->m_latitude);
                if( distanceSqd <= range * range )
                {                    
                    int numTargetedNukes = CountTargetedNukes( team, obj->m_longitude, obj->m_latitude );
                    
                    if( (obj->m_type == WorldObject::TypeRadarStation && numTargetedNukes < 2 ) ||
                        (obj->m_type != WorldObject::TypeRadarStation && numTargetedNukes < 4 ) )
                    {
                        validTargets.PutData(obj->m_objectId);
                    }
                }
            }
        }
    }

    if( validTargets.Size() > 0 )
    {
        int targetId = syncrand() % validTargets.Size();
        int objIndex = validTargets[ targetId ];
        WorldObject *obj = g_app->GetWorld()->GetWorldObject(objIndex);
        if( obj )
        {
            *longitude = obj->m_longitude;
            *latitude = obj->m_latitude;
            *objectId = obj->m_objectId;
            END_PROFILE("Nuke::FindTarget");
            return;
        }
    }

    Team *friendlyTeam = g_app->GetWorld()->GetTeam( team );

    int maxPop = 500000;        // Don't bother hitting cities with less than 0.5M survivors

    for( int i = 0; i < g_app->GetWorld()->m_cities.Size(); ++i )
    {
        if( g_app->GetWorld()->m_cities.ValidIndex(i) )
        {
            City *city = g_app->GetWorld()->m_cities[i];

            if( !g_app->GetWorld()->IsFriend( city->m_teamId, team) && 
				g_app->GetWorld()->GetDistanceSqd( city->m_longitude, city->m_latitude, launcher->m_longitude, launcher->m_latitude) <= range * range)               
            {
                int numTargetedNukes = CountTargetedNukes(team, city->m_longitude, city->m_latitude);
                int estimatedPop = City::GetEstimatedPopulation( team, i, numTargetedNukes );
                if( estimatedPop > maxPop )
                {
                    maxPop = estimatedPop;
                    *longitude = city->m_longitude;
                    *latitude = city->m_latitude;
                    *objectId = -1;
                }
            }
        }
    }
    
    END_PROFILE("Nuke::FindTarget");
}
void NewsScreenInterface::DrawDetails ( Button *button, bool highlighted, bool clicked )
{

	UplinkAssert (button);

	int screenheight = app->GetOptions ()->GetOptionValue ( "graphics_screenheight" );
	glScissor ( button->x, screenheight - (button->y + button->height), button->width, button->height );	
	glEnable ( GL_SCISSOR_TEST );

	// Get the offset

	char name_base [128];
	sscanf ( button->name, "%s", name_base );
    ScrollBox *scrollBox = ScrollBox::GetScrollBox( name_base );
    if ( !scrollBox ) return;
    int offset = scrollBox->currentIndex;
	
	// Draw the button

	glBegin ( GL_QUADS );
		SetColour ( "PanelBackgroundA" );       glVertex2i ( button->x, button->y + button->height );
		SetColour ( "PanelBackgroundB" );       glVertex2i ( button->x, button->y );
		SetColour ( "PanelBackgroundA" );       glVertex2i ( button->x + button->width, button->y );
		SetColour ( "PanelBackgroundB" );       glVertex2i ( button->x + button->width, button->y + button->height );
	glEnd ();

	SetColour ( "PanelBorder" );
	border_draw ( button );


	// Draw the text

	int maxnumlines = (button->height - 10 ) / 15;

	SetColour ( "DefaultText" );

	LList <char *> *wrappedtext = wordwraptext ( button->caption, button->width );

	if ( wrappedtext ) {

		for ( int i = offset; i < wrappedtext->Size (); ++i ) {

			if ( i > maxnumlines + offset )
				break;

			int xpos = button->x + 10;
			int	ypos = button->y + 10 + (i-offset) * 15;

			GciDrawText ( xpos, ypos, wrappedtext->GetData (i), HELVETICA_10 );

		}

		//DeleteLListData ( wrappedtext );							// Only delete first entry - since there is only one string really
		if ( wrappedtext->ValidIndex (0) && wrappedtext->GetData (0) )
			delete [] wrappedtext->GetData (0);
		delete wrappedtext;

	}

	glDisable ( GL_SCISSOR_TEST );
	
}
Esempio n. 28
0
static NetCallBackRetType AuthenticationThread(void *ignored)
{
#ifdef WAN_PLAY_ENABLED

    //
    // Every few seconds request the next key to be authenticated

    while( true )
    {
        NetSleep( PERIOD_AUTHENTICATION_RETRY );

        if( MetaServer_IsConnected() )
        {
            char unknownKey[256];
            char clientIp[256];
            int  keyId = -1;
            bool unknownKeyFound = false;

            //
            // Look for a key that isnt yet authenticated

            s_authResultsMutex.Lock();
            for( int i = 0; i < s_authResults.Size(); ++i )
            {
                AuthenticationResult *authResult = s_authResults[i];
                if( authResult->m_authResult == AuthenticationUnknown &&
                    authResult->m_numTries < 5 )
                {
                    strcpy( unknownKey, authResult->m_authKey );
                    strcpy( clientIp, authResult->m_ip );
                    keyId = authResult->m_keyId;
                    authResult->m_numTries++;
                    unknownKeyFound = true;
                    break;
                }
            }        
            s_authResultsMutex.Unlock();
    
        
            //
            // Check the key out

            if( unknownKeyFound )
            {
                int basicResult = Authentication_SimpleKeyCheck(unknownKey);
                if( basicResult < 0 )
                {
                    // The key is in the wrong format
                    Authentication_SetStatus( unknownKey, keyId, basicResult );
                    char *resultString = Authentication_GetStatusString(basicResult);
                    AppDebugOut( "Key failed basic check : %s (result=%s)\n", unknownKey, resultString );
                }
                else if( Authentication_IsDemoKey(unknownKey) )
                {
                    // This is a demo key, and has passed the simple check
                    // Assume its valid from now on
                    Authentication_SetStatus( unknownKey, -1, AuthenticationAccepted );
                    AppDebugOut( "Auth Key accepted as DEMOKEY : %s\n", unknownKey );
                }
                else
                {
                    // Request a proper auth check from the metaserver
                    Directory directory;
                    directory.SetName( NET_METASERVER_MESSAGE );
                    directory.CreateData( NET_METASERVER_COMMAND, NET_METASERVER_REQUEST_AUTH );
                    directory.CreateData( NET_METASERVER_AUTHKEY, unknownKey );
                    directory.CreateData( NET_METASERVER_AUTHKEYID, keyId );
                    directory.CreateData( NET_METASERVER_GAMENAME, APP_NAME );
                    directory.CreateData( NET_METASERVER_GAMEVERSION, APP_VERSION );
                    
                    if( strcmp(clientIp, "unknown") != 0 )
                    {
                        directory.CreateData( NET_METASERVER_IP, clientIp );
                    }

                    MetaServer_SendToMetaServer( &directory );

                    AppDebugOut( "Requesting authentication of key %s\n", unknownKey );
                }
            }
        }
    }

#endif
    
    return 0;
}
void LocationEditor::RenderModeLandTile()
{
	Vector3 mousePos3D = g_app->m_userInput->GetMousePos3d();
	Landscape *land = &g_app->m_location->m_landscape;

	// Highlight any tile under our mouse cursor
	LList<LandscapeTile *> *tiles = &g_app->m_location->m_levelFile->m_landscape.m_tiles;
	for (int i = 0; i < tiles->Size(); ++i)
	{
		if (i == m_selectionId) continue;

		LandscapeTile *tile = tiles->GetData(i);
		float worldX = tile->m_posX - tile->m_heightMap->m_cellSizeX;
		float worldZ = tile->m_posZ - tile->m_heightMap->m_cellSizeY;
		float sizeX = tile->m_size;
		float sizeY = tile->m_desiredHeight - tile->m_outsideHeight;
		float sizeZ = tile->m_size;
		if (mousePos3D.x > worldX &&
			mousePos3D.x < worldX + sizeX &&
			mousePos3D.z > worldZ &&
			mousePos3D.z < worldZ + sizeZ) 
		{
			Vector3 centre(worldX, tile->m_outsideHeight, worldZ);
			centre.x += sizeX * 0.5;
			centre.y += sizeY * 0.5;
			centre.z += sizeZ * 0.5;
			RenderCube(centre, sizeX, sizeY, sizeZ, RGBAColour(128,255,128,99));
		}
	}

    // Render guide grids

    if( EclGetWindow("editor_guidegrid") )
    {
        glEnable( GL_LINE_SMOOTH );
        glEnable( GL_BLEND );

	    if (m_selectionId != -1)
	    {
            LandscapeTile *tile = tiles->GetData(m_selectionId);

            if( tile->m_guideGrid &&
                tile->m_guideGrid->GetNumColumns() > 0 )
            {
                float gridCellSize = tile->m_size / (float) (tile->m_guideGrid->GetNumColumns()+1);
                for( int x = 0; x < tile->m_guideGrid->GetNumColumns()-1; ++x )
                {
                    for( int z = 0; z < tile->m_guideGrid->GetNumColumns()-1; ++z )
                    {                    
                        float value1 = tile->m_desiredHeight * (tile->m_guideGrid->GetData( x, z ) / 256.0);
                        float value2 = tile->m_desiredHeight * (tile->m_guideGrid->GetData( x+1, z ) / 256.0 );
                        float value3 = tile->m_desiredHeight * (tile->m_guideGrid->GetData( x+1, z+1 ) / 256.0 );
                        float value4 = tile->m_desiredHeight * (tile->m_guideGrid->GetData( x, z+1 ) / 256.0 );
                 
                        float tileX = tile->m_posX + (x+1) * gridCellSize;
                        float tileZ = tile->m_posZ + (z+1) * gridCellSize;
                        float tileW = gridCellSize;
                        float tileH = gridCellSize;

                        glDisable( GL_DEPTH_TEST );
                        glLineWidth( 1.0 );
                        glColor4f( 1.0, 0.0, 0.0, 0.2 );
                        glBegin( GL_LINE_LOOP );
                            glVertex3f( tileX, tile->m_posY + value1, tileZ );
                            glVertex3f( tileX + tileW, tile->m_posY + value2, tileZ );
                            glVertex3f( tileX + tileW, tile->m_posY + value3, tileZ + tileH );
                            glVertex3f( tileX, tile->m_posY + value4, tileZ + tileH );
                        glEnd();

                        glEnable( GL_DEPTH_TEST );
                        glColor4f( 1.0, 0.0, 0.0, 0.8 );
                        glLineWidth( 3.0 );
                        glBegin( GL_LINE_LOOP );
                            glVertex3f( tileX, tile->m_posY + value1, tileZ );
                            glVertex3f( tileX + tileW, tile->m_posY + value2, tileZ );
                            glVertex3f( tileX + tileW, tile->m_posY + value3, tileZ + tileH );
                            glVertex3f( tileX, tile->m_posY + value4, tileZ + tileH );
                        glEnd();

                    }
                }
            }
        }

        glDisable( GL_BLEND );
        glEnable( GL_DEPTH_TEST );
    }

    
	// Render a green box around the currently selected tile (if any)
	if (m_selectionId != -1)
	{
        LandscapeTile *tile = tiles->GetData(m_selectionId);
        float x = tile->m_posX - tile->m_heightMap->m_cellSizeX;
        float y = tile->m_outsideHeight;
        float z = tile->m_posZ - tile->m_heightMap->m_cellSizeY;
        float sX = tile->m_size;
        float sY = tile->m_desiredHeight - tile->m_outsideHeight;
		float sZ = tile->m_size;
		Vector3 centre(x, y, z);
		centre.x += sX * 0.5;
		centre.y += sY * 0.5;
		centre.z += sZ * 0.5;
		RenderCube(centre, sX, sY, sZ, RGBAColour(128,255,128));

        if( m_newLandscapeX != tile->m_posX ||
            m_newLandscapeZ != tile->m_posZ )
        {
            x = m_newLandscapeX;
			y = 1.0;
            z = m_newLandscapeZ;
            glColor3ub( 0, 0, 255 );
            glBegin( GL_LINE_LOOP );
                glVertex3f( x, y, z );
                glVertex3f( x + sX, y, z );
                glVertex3f( x + sX, y, z + sZ );
                glVertex3f( x, y, z + sZ );
            glEnd();
        }
	}
    
	CHECK_OPENGL_STATE();
}
void RocketStatusPanel::Render()
{
    //
    // Determine our rocket status

    EscapeRocket *rocket = GetMyRocket();
    if( !rocket ) return;

    Team *team = g_app->m_location->m_teams[ m_teamId ];
    if( !team ) return;

    float fuelPercent = rocket->m_fuel / 100.0f;
    int darwiniansInside = rocket->m_passengers;

    if( rocket->m_damage > m_lastDamage )
    {
        m_damageTimer = GetHighResTime();
    }
    m_lastDamage = rocket->m_damage;

    if( fuelPercent > 1.0f ) fuelPercent = 1.0f;

    double refuelRate = rocket->m_fuel - m_previousFuelLevel;
    m_previousFuelLevel = rocket->m_fuel;

    float h = m_w * 1.5f;
    glShadeModel( GL_SMOOTH );


    //
    // Background team colour

    glColor4ub( team->m_colour.r*0.2f, team->m_colour.g*0.2f, team->m_colour.b*0.2f, 200 );

    glBegin( GL_QUADS );
        glVertex2f( m_x, m_y );
        glVertex2f( m_x + m_w, m_y );
        glVertex2f( m_x + m_w, m_y + h );
        glVertex2f( m_x, m_y + h );
    glEnd();


    //
    // Refueling effect

    float fuelBase = m_y + h * 0.97f;
    float fuelFullH = h * 0.95f;
    float fuelH = fuelFullH * fuelPercent;
    int refuelAlpha = 128;

    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    glEnable        ( GL_TEXTURE_2D );
    glBindTexture   ( GL_TEXTURE_2D, g_app->m_resource->GetTexture( "textures/laser.bmp" ) );
    glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
    glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );


    if( fuelPercent < 1.0f )
    {
        glColor4ub( team->m_colour.r, team->m_colour.g, team->m_colour.b, refuelAlpha );

        float texY = fuelPercent * -100 + 0.5f;
        float texH = 1.0f;

        glBegin( GL_QUADS );
            glTexCoord2f(0,texY);       glVertex2f( m_x, fuelBase );
            glTexCoord2f(1,texY);       glVertex2f( m_x + m_w, fuelBase );
            glTexCoord2f(1,texY+texH);  glVertex2f( m_x + m_w, fuelBase - fuelFullH );
            glTexCoord2f(0,texY+texH);  glVertex2f( m_x, fuelBase - fuelFullH );
        glEnd();

    }


    //
    // Fuel level

    glBindTexture   ( GL_TEXTURE_2D, g_app->m_resource->GetTexture( "textures/laser-long.bmp" ) );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    int fuelAlpha = 200;

    glBegin( GL_QUADS );
        glColor4ub( 0,0,0, fuelAlpha );
        glTexCoord2f( 0, 0.3f );       glVertex2f( m_x, fuelBase );
        glTexCoord2f( 0, 0.7f );       glVertex2f( m_x + m_w, fuelBase );
        
        glColor4ub( team->m_colour.r, team->m_colour.g, team->m_colour.b, fuelAlpha );
        glTexCoord2f( 1, 0.7f );       glVertex2f( m_x + m_w, fuelBase - fuelH );
        glTexCoord2f( 1, 0.3f );       glVertex2f( m_x, fuelBase - fuelH );
    glEnd();

    glDisable( GL_TEXTURE_2D );


    //
    // Shadow above fuel level

    glBegin( GL_QUADS );
        glColor4ub( 0,0,0, fuelAlpha*0.5f );
        glVertex2f( m_x, fuelBase - fuelH );
        glVertex2f( m_x + m_w, fuelBase - fuelH );
        glColor4ub( 0,0,0, 0 );
        glVertex2f( m_x + m_w, fuelBase - fuelH - h * 0.05f );
        glVertex2f( m_x, fuelBase - fuelH - 10 - h * 0.05f );
    glEnd();


    //
    // Rocket bitmap overlay

    glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );

    glBlendFunc     ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    glEnable        ( GL_TEXTURE_2D );
    glBindTexture   ( GL_TEXTURE_2D, g_app->m_resource->GetTexture( "icons/rocketstatuspanel.bmp" ) );
    
    glBegin( GL_QUADS );
        glTexCoord2i(0,1);      glVertex2f( m_x, m_y );
        glTexCoord2i(1,1);      glVertex2f( m_x + m_w, m_y );
        glTexCoord2i(1,0);      glVertex2f( m_x + m_w, m_y + h );
        glTexCoord2i(0,0);      glVertex2f( m_x, m_y + h );
    glEnd();
    
    glDisable       ( GL_TEXTURE_2D );



    //
    // Damage effect

    glColor4f( 1.0f, 1.0f, 1.0f, rocket->m_damage/100.0f );

    glBlendFunc     ( GL_SRC_ALPHA, GL_ONE );
    glEnable        ( GL_TEXTURE_2D );
    glBindTexture   ( GL_TEXTURE_2D, g_app->m_resource->GetTexture( "icons/rocketcracked.bmp" ) );

    glBegin( GL_QUADS );
    glTexCoord2i(0,1);      glVertex2f( m_x, m_y );
    glTexCoord2i(1,1);      glVertex2f( m_x + m_w, m_y );
    glTexCoord2i(1,0);      glVertex2f( m_x + m_w, m_y + h );
    glTexCoord2i(0,0);      glVertex2f( m_x, m_y + h );
    glEnd();

    glDisable       ( GL_TEXTURE_2D );



    //
    // Darwinians inside
    
    glBlendFunc     ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    if( fuelPercent >= 1.0f || darwiniansInside > 0 )
    {
        float dwX = m_x + m_w * 0.25f;
        float dwW = m_w * 0.45f;
        float dwY = m_y + h * 0.225f;
        float dwH = h * 0.55f;
        float s = h * 0.04f;
        int astronautAlpha = 255;

        glEnable        ( GL_TEXTURE_2D );
        glBindTexture   ( GL_TEXTURE_2D, g_app->m_resource->GetTexture( "sprites/darwinian.bmp" ) );

        for( int i = 99; i >= 0; i-- )
        {
            int xIndex = ( i % 10 );
            int yIndex = 9 - int( i / 10 );
            float xPos = dwX + dwW * xIndex/10;
            float yPos = dwY + dwH * yIndex/10;

            if( yIndex % 2 == 0 ) xPos += dwW/20.0f;

            RGBAColour astronautCol = team->m_colour;
            astronautCol.AddWithClamp( RGBAColour(50,50,50,255) );
            astronautCol.a = astronautAlpha;

            if( i <  darwiniansInside )     glColor4ub( team->m_colour.r, team->m_colour.g, team->m_colour.b, astronautAlpha );
            else                            glColor4ub( team->m_colour.r*0.3f, team->m_colour.g*0.3f, team->m_colour.b*0.3f, astronautAlpha*0.2f );

            Vector3 pos( xPos+s/2.0f, yPos+s/2.0f, 0 );
            pos.x += sinf(i + GetHighResTime()) * 1.0f;
            pos.y += cosf(i + i + GetHighResTime()) * 1.0f;

            Vector3 offset( -s/2.0f, -s, 0 );
            
            glBegin( GL_QUADS );
                glTexCoord2f(0,1);      glVertex2dv( (pos+offset).GetData() );      offset.RotateAroundZ(0.5f * M_PI);
                glTexCoord2f(1,1);      glVertex2dv( (pos+offset).GetData() );      offset.RotateAroundZ(0.5f * M_PI);
                glTexCoord2f(1,0);      glVertex2dv( (pos+offset).GetData() );      offset.RotateAroundZ(0.5f * M_PI);
                glTexCoord2f(0,0);      glVertex2dv( (pos+offset).GetData() );      offset.RotateAroundZ(0.5f * M_PI);
            glEnd();
        }

        glDisable( GL_TEXTURE_2D );
    }


    //
    // Engine effect

    if( rocket->m_state == EscapeRocket::StateReady ||
        rocket->m_state == EscapeRocket::StateCountdown ||
        rocket->m_state == EscapeRocket::StateFlight)
    {
        float flameX = m_x + m_w * 0.35f;
        float flameY = m_y + h * 0.8f;
        float flameW = m_w * 0.3f;
        float flameH = m_w * 0.3f;

        glBlendFunc     ( GL_SRC_ALPHA, GL_ONE );

        glEnable( GL_TEXTURE_2D );
        glBindTexture( GL_TEXTURE_2D, g_app->m_resource->GetTexture("textures/muzzleflash.bmp" ) );

        if( fmodf( GetHighResTime()*30, 1.0f ) < 0.5f ) glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
        else                                             glColor4f( 1.0f, 1.0f, 1.0f, 0.2f );

        glBegin( GL_QUADS );
            glTexCoord2i(0,0);      glVertex2f( flameX, flameY );
            glTexCoord2i(0,1);      glVertex2f( flameX+flameW, flameY );
            glTexCoord2i(1,1);      glVertex2f( flameX+flameW, flameY+flameH );
            glTexCoord2i(1,0);      glVertex2f( flameX, flameY+flameH );
        glEnd();

        glDisable( GL_TEXTURE_2D );
    }


    //
    // Captions at the bottom
    // Determine our caption

    float mainCaptionY = m_y + h * 0.6f;
    float mainCaptionH = h * 0.05f;
    float mainCaptionG = mainCaptionH * 0.1f;

    bool timeFlashEffect = (fmodf( GetHighResTime() * 2, 1.0f ) > 0.55f);

    UnicodeString caption;
    RGBAColour captionColour(255,255,255,255);

    if( GetHighResTime() - m_damageTimer < 10.0f && 
        rocket->m_state != EscapeRocket::StateExploding )
    {
        char damage[256];
        sprintf( damage, "%d%%", int(rocket->m_damage) );
        caption = LANGUAGEPHRASE("multiwinia_rr_status_c");
        caption.ReplaceStringFlag( L'T', damage );

        captionColour.Set(255,0,0,255);  
        if( timeFlashEffect ) captionColour.a *= 0.5f;
    }
    else if( rocket->m_state == EscapeRocket::StateCountdown )
    {        
        char captionC[256];
        sprintf( captionC, "%d", (int)rocket->m_countdown + 1 );
        caption = captionC;
        mainCaptionH *= 4;
    }
    else if( rocket->m_state == EscapeRocket::StateFlight )
    {
        caption = LANGUAGEPHRASE("multiwinia_rr_status_d" );
        mainCaptionH *= 1.5f;
        if( timeFlashEffect ) captionColour.a *= 0.25f;
    }
    else if( rocket->m_state == EscapeRocket::StateExploding )
    {
        caption = LANGUAGEPHRASE("multiwinia_rr_status_e" );
        if( timeFlashEffect ) captionColour.a *= 0.25f;
    }
    else if( fuelPercent >= 1.0f && darwiniansInside < 5 )
    {
        caption = LANGUAGEPHRASE("multiwinia_rr_status_b");
        if( timeFlashEffect ) captionColour.a *= 0.25f;
    } 
    else if( rocket->m_refuelRate < 0.05f && fuelPercent < 0.01f )
    {
        caption = LANGUAGEPHRASE("multiwinia_rr_status_a");        
        if( timeFlashEffect ) captionColour.a *= 0.25f;
    }
    else if( fuelPercent < 1.0f )
    {
        char captionC[256];
        sprintf( captionC, "%2.1f%%", fuelPercent * 100 );
        
        caption = LANGUAGEPHRASE("multiwinia_rr_status_f");
        caption.ReplaceStringFlag( L'T', captionC );

        captionColour.a *= 0.75f;
    }
       


    //
    // Render our caption

    if( caption.Length() )
    {
        LList<UnicodeString *> *wrapped = WordWrapText( caption, 1000, mainCaptionH, false, false );

        for( int i = 0; i < wrapped->Size(); ++i )
        {
            UnicodeString *thisString = wrapped->GetData(i);

            glColor4ub( captionColour.a, captionColour.a, captionColour.a, 0 );
            g_titleFont.SetRenderOutline(true);
            g_titleFont.DrawText2DCentre( m_x + m_w/2, mainCaptionY, mainCaptionH, *thisString );

            glColor4ubv( captionColour.GetData() );
            g_titleFont.SetRenderOutline(false);
            g_titleFont.DrawText2DCentre( m_x + m_w/2, mainCaptionY, mainCaptionH, *thisString );

            mainCaptionY += mainCaptionH;
            mainCaptionY += mainCaptionG;
        }

        wrapped->EmptyAndDelete();
        delete wrapped;
    }


    //
    // White border

    glColor4f( 1.0f, 1.0f, 1.0f, 0.2f );

    glBegin( GL_LINE_LOOP );
        glVertex2f( m_x, m_y );
        glVertex2f( m_x + m_w, m_y );
        glVertex2f( m_x + m_w, m_y + h );
        glVertex2f( m_x, m_y + h );
    glEnd();

    glShadeModel( GL_FLAT );
}