www.pudn.com > coolMEMORY.rar > MemoryLogic.cpp


//----------------------------------------------------------------------------- 
// File: MemoryLogic.cpp 
//----------------------------------------------------------------------------- 
 
#include "AS\AS_Engine.h" 
#include "ModuleHeaders.h" 
 
 
// Variables: ***************************************************************** 
cGAME_CONFIG cGameConfig; // All the game configurations 
cSTYLE *pcCardStyle; // Pointer to the current card style in the game 
					 // configuration for an faster access 
cGAME_CARD *pcGameCard; // The game cards 
cGAME_INFO cGameInfo; // The game information 
AS_2D_VECTOR vPlayField[2]; // The play field min/max coords 
BOOL bGameFinished, // Is the game finished? 
	 bPressAnyKeyBlend, // For the blinking 'Press any key to continue' text 
	 bFlashBlend; // Should the screen be blended? 
float fGameFinishedBlend, // The blend value for the game finished screen 
	  fPressAnyKeyBlend,  // For the blinking 'Press any key to continue' text 
	  fFlashBlend, // For blending the screen 
	  fCupRot; // For the cup rotation: 
// The screen positions of the player information: 
INT2 iPlayerInfoPos[MAX_PLAYERS] = {{50, 460}, {500, 460}, {500, 100}, {50, 100}}; 
 
// The available card numbers: 
INT2 iCardDimensionStencil[11] =  
{ 
	{4, 3}, // 12 cards = 6 pairs 
	{4, 4}, // 16 cards = 8 pairs 
	{5, 4}, // 20 cards = 10 pairs 
	{6, 5}, // 30 cards = 15 pairs 
	{6, 6}, // 36 cards = 18 pairs 
	{7, 6}, // 42 cards = 21 pairs 
	{8, 7}, // 56 cards = 28 pairs 
	{8, 8}, // 64 cards = 32 pairs 
	{9, 8}, // 72 cards = 36 pairs 
	{10, 9}, // 90 cards = 45 pairs 
	{10, 10}, // 100 cards = 50 pairs 
}; 
 
// The camera position for each card dimension: 
FLOAT2 fCardDimensionCamera[11] = // [0] = Zoom,   [1] = y position 
{ 
	{-4.8f, -1.3f},  // 6 pairs 
	{-6.5f, -1.95f}, // 8 pairs 
	{-6.5f, -1.95f}, // 10 pairs 
	{-8.3f, -2.58f}, // 15 pairs 
	{-9.8f, -3.23f}, // 18 pairs 
	{-9.8f, -3.2f},  // 21 pairs 
	{-11.5f, -3.9f}, // 28 pairs 
	{-13.2f, -4.5f}, // 32 pairs 
	{-13.2f, -4.5f}, // 36 pairs 
	{-15.0f, -5.2f}, // 45 pairs 
	{-16.5f, -5.8f}, // 50 pairs 
}; 
 
FLOAT3 fCardVertices[8] =  
{ 
	{-0.5f, 0.5f, -0.05f}, 
	{0.5f, 0.5f, -0.05f}, 
	{0.5f, -0.5f, -0.05f}, 
	{-0.5f, -0.5f, -0.05f}, 
 
	{-0.5f, -0.5f, 0.05f}, 
	{0.5f, -0.5f, 0.05f}, 
	{0.5f, 0.5f, 0.05f}, 
	{-0.5f, 0.5f, 0.05f}, 
}; 
 
FLOAT2 fCardTexCoords[8] =  
{ 
	{0.0f, 1.0f}, 
	{1.0f, 1.0f}, 
	{1.0f, 0.0f}, 
	{0.0f, 0.0f}, 
 
	{1.0f, 0.0f}, 
	{0.0f, 0.0f}, 
	{0.0f, 1.0f}, 
	{1.0f, 1.0f}, 
}; 
/////////////////////////////////////////////////////////////////////////////// 
 
// Functions: ***************************************************************** 
void InitGameCards(void); 
void DestroyGameCards(void); 
void DrawGameCards(void); 
void PerformLightMapOnGameCarts(void); 
void CheckGameCards(void); 
void PerformLightMapOnGameCarts(void); 
void DrawTableBackground(void); 
void SetNextComputerSelectionTime(void); 
/////////////////////////////////////////////////////////////////////////////// 
 
 
// cSTYLE functions: ********************************************************** 
cSTYLE::cSTYLE(void) 
{ // begin cSTYLE::cSTYLE() 
	memset(this, 0, sizeof(cSTYLE)); 
} // end cSTYLE::cSTYLE() 
 
cSTYLE::~cSTYLE(void) 
{ // begin cSTYLE::~cSTYLE() 
	Destroy(); 
} // end cSTYLE::~cSTYLE() 
 
BOOL cSTYLE::Load(char *pbyFilename) 
{ // begin cSTYLE::Load() 
	char byCardTemp[256], byReadTemp[256], byInfoFile[256]; 
	AS_PROGRESS_WINDOW ProgressWindow; 
	AS_TEXTURE *pTextureT; 
	sCARD *psCardT; 
	int iCard, i; 
 
	ProgressWindow.CreateProgressWindow("Card sytle"); 
	ProgressWindow.SetTask("Loading..."); 
	ProgressWindow.SetProgress(0); 
		 
	_AS->WriteLogMessage("Load card style: %s", pbyFilename); 
	 
	// First, destroy the old card style: 
	Destroy(); 
 
	strcpy(byFolderName, pbyFilename); 
 
	// Get the absolute path: 
	sprintf(byFilename, "%s%s\\%s", _AS->byProgramPath, _AS->byCardStylesDirectory, pbyFilename); 
	sprintf(byInfoFile, "%s\\info.txt", byFilename); 
 
	// Get the style name: 
	sprintf(byReadTemp, "general_%s", _ASConfig->byLanguage); 
	GetPrivateProfileString(byReadTemp, "name", "Noname", byStyleName, 256, byInfoFile); 
 
	// Get the backside texture: 
	GetPrivateProfileString("general", "backside_texture", "Noname", byReadTemp, 256, byInfoFile); 
	sprintf(sTexture[0].byFilename, "%s\\%s", byFilename, byReadTemp); 
	GetPrivateProfileString("general", "side_texture", "Noname", byReadTemp, 256, byInfoFile); 
	sprintf(sTexture[1].byFilename, "%s\\%s", byFilename, byReadTemp); 
	GetPrivateProfileString("general", "environment_texture", "Noname", byReadTemp, 256, byInfoFile); 
	sprintf(sTexture[2].byFilename, "%s\\%s", byFilename, byReadTemp); 
	GetPrivateProfileString("general", "background_texture", "Noname", byReadTemp, 256, byInfoFile); 
	sprintf(sTexture[3].byFilename, "%s\\%s", byFilename, byReadTemp); 
	for(i = 0; i < 4; i++) 
	{ 
		_AS->WriteLogMessage("texture: %s", sTexture[i].byFilename); 
		ASLoadJpegRGB(&sTexture[i], sTexture[i].byFilename); 
		if(!sTexture[i].iWidth) 
			_AS->WriteLogMessage("Couldn't load that texture!"); 
	} 
	ProgressWindow.SetProgress(50); 
	 
	// Get the number of cards: 
	iCards = GetPrivateProfileInt("general", "cards", 0, byInfoFile); 
	if(iCards) 
	{ 
		sCard = (sCARD *) malloc(sizeof(sCARD)*iCards); 
		memset(sCard, 0, sizeof(sCARD)*iCards); 
	} 
	 
	// Load in the cards: 
	_AS->WriteLogMessage("Load cards:"); 
	for(iCard = 0; iCard < iCards; iCard++) 
	{ 
		sprintf(byCardTemp, "card_%d", iCard+1); 
		_AS->WriteLogMessage(byCardTemp); 
		psCardT = &sCard[iCard]; 
 
		// Load the texture: 
		pTextureT = &psCardT->Texture; 
		GetPrivateProfileString(byCardTemp, "texture", "", byReadTemp, 256, byInfoFile); 
		sprintf(pTextureT->byFilename, "%s\\%s", byFilename, byReadTemp); 
		_AS->WriteLogMessage("texture: %s", pTextureT->byFilename); 
		ASLoadJpegRGB(pTextureT, pTextureT->byFilename); 
		pTextureT->iID = iCard; 
		if(!pTextureT->iWidth) 
			_AS->WriteLogMessage("Couldn't load that texture!"); 
		// Load the sound: 
		GetPrivateProfileString(byCardTemp, "sound", "", byReadTemp, 256, byInfoFile); 
		sprintf(psCardT->Sound.byFilename, "%s\\%s", byFilename, byReadTemp); 
		if(ASLoadFmodSample(&psCardT->Sound, psCardT->Sound.byFilename, i)) 
			_AS->WriteLogMessage("Couldn't load this sound"); 
		 
		sprintf(byCardTemp, "card_%d_%s", iCard+1, _ASConfig->byLanguage); 
		 
		// Get its name: 
		GetPrivateProfileString(byCardTemp, "name", "", psCardT->byName, 256, byInfoFile); 
 
		// Get its description: 
		GetPrivateProfileString(byCardTemp, "description", "", psCardT->byDescription, cCARD_DESCRIPTION_LENGTH, byInfoFile); 
	} 
	 
	return FALSE; 
} // end cSTYLE::Load() 
 
void cSTYLE::Destroy(void) 
{ // begin cSTYLE::Destroy() 
	// Destroy all card style textures: 
	for(int i = 0; i < 4; i++) 
	{ 
		ASDestroyOpenGLTextures(1, &sTexture[i]); 
		ASDestroyTextures(1, &sTexture[i]); 
	} 
 
	// Destroy all card textures: 
	for(int iCard = 0; iCard < iCards; iCard++) 
	{ 
		ASDestroyOpenGLTextures(1, &sCard[iCard].Texture); 
		ASDestroyTextures(1, &sCard[iCard].Texture); 
		ASDestroyFmodSample(&sCard[iCard].Sound); 
	} 
 
	// Free card memory: 
	SAFE_DELETE(sCard); 
	 
	// Set all to null: 
	memset(this, 0, sizeof(cSTYLE)); 
} // end cSTYLE::Destroy() 
 
void cSTYLE::GenOpenGLTextures(void) 
{ // begin cSTYLE::GenOpenGLTextures() 
	AS_PROGRESS_WINDOW ProgressWindow; 
	AS_TEXTURE *pTextureT; 
 
	ProgressWindow.CreateProgressWindow("Card sytle"); 
	ProgressWindow.SetTask("Generate OpenGL  textures..."); 
	ProgressWindow.SetProgress(0); 
	 
	// Card style textures: 
	for(int i = 0; i < 4; i++) 
	{ 
		ProgressWindow.SetSubTask("%s", sTexture[i].byFilename); 
		ProgressWindow.SetProgress((UINT) (((float) i/4)*100)); 
		glGenTextures(1, &sTexture[i].iOpenGLID); 
		glBindTexture(GL_TEXTURE_2D, sTexture[i].iOpenGLID); 
		if(_ASConfig->bUseMipmaps) 
		{ 
			if(_ASConfig->bFastTexturing) 
			{ 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST); 
				gluBuild2DMipmaps(GL_TEXTURE_2D, 3, sTexture[i].iWidth, sTexture[i].iHeight, GL_RGB, GL_UNSIGNED_BYTE, sTexture[i].pbyData); 
			} 
			else 
			{ 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); 
				gluBuild2DMipmaps(GL_TEXTURE_2D, 3, sTexture[i].iWidth, sTexture[i].iHeight, GL_RGB, GL_UNSIGNED_BYTE, sTexture[i].pbyData); 
			} 
		} 
		else 
		{ 
			if(_ASConfig->bFastTexturing) 
			{ 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
				glTexImage2D(GL_TEXTURE_2D, 0, 3, sTexture[i].iWidth, sTexture[i].iHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, sTexture[i].pbyData); 
			} 
			else 
			{ 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
				glTexImage2D(GL_TEXTURE_2D, 0, 3, sTexture[i].iWidth, sTexture[i].iHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, sTexture[i].pbyData); 
			} 
		} 
	} 
	 
	// Card textures: 
	for(int iCard = 0; iCard < iCards; iCard++) 
	{ 
		pTextureT = &sCard[iCard].Texture; 
 
		ProgressWindow.SetSubTask("%s", pTextureT->byFilename); 
		ProgressWindow.SetProgress((UINT) (((float) i/iCards)*100)); 
		glGenTextures(1, &pTextureT->iOpenGLID); 
		glBindTexture(GL_TEXTURE_2D, pTextureT->iOpenGLID); 
		if(_ASConfig->bUseMipmaps) 
		{ 
			if(_ASConfig->bFastTexturing) 
			{ 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST); 
				gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pTextureT->iWidth, pTextureT->iHeight, GL_RGB, GL_UNSIGNED_BYTE, pTextureT->pbyData); 
			} 
			else 
			{ 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); 
				gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pTextureT->iWidth, pTextureT->iHeight, GL_RGB, GL_UNSIGNED_BYTE, pTextureT->pbyData); 
			} 
		} 
		else 
		{ 
			if(_ASConfig->bFastTexturing) 
			{ 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
				glTexImage2D(GL_TEXTURE_2D, 0, 3, pTextureT->iWidth, pTextureT->iHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pTextureT->pbyData); 
			} 
			else 
			{ 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
				glTexImage2D(GL_TEXTURE_2D, 0, 3, pTextureT->iWidth, pTextureT->iHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pTextureT->pbyData); 
			} 
		} 
	} 
} // end cSTYLE::GenOpenGLTextures() 
 
void cSTYLE::DestroyOpenGLTextures(void) 
{ // begin cSTYLE::DestroyOpenGLTextures() 
	AS_TEXTURE *pTextureT; 
 
	// Card style textures: 
	for(int i = 0; i < 4; i++) 
	{ 
		if(sTexture[i].pbyData) 
			glDeleteTextures(1, &sTexture[i].iOpenGLID); 
	} 
 
	// Card textures: 
	for(int iCard = 0; iCard < iCards; iCard++) 
	{ 
		pTextureT = &sCard[iCard].Texture; 
		if(!pTextureT || !pTextureT->pbyData) 
			continue; 
		glDeleteTextures(1, &pTextureT->iOpenGLID); 
	} 
} // end cSTYLE::DestroyOpenGLTextures() 
 
void cSTYLE::UpdateTextures(void) 
{ // begin cSTYLE::UpdateTextures() 
	DestroyOpenGLTextures(); 
	GenOpenGLTextures(); 
} // end cSTYLE::UpdateTextures() 
/////////////////////////////////////////////////////////////////////////////// 
 
 
// cGAME_CONFIG functions: **************************************************** 
cGAME_CONFIG::cGAME_CONFIG(void) 
{ // begin cGAME_CONFIG::cGAME_CONFIG() 
	memset(this, 0, sizeof(cGAME_CONFIG)); 
} // end cGAME_CONFIG::cGAME_CONFIG() 
 
void cGAME_CONFIG::SetStandart(void) 
{ // begin cGAME_CONFIG::SetStandart() 
	// Reset all: 
	memset(this, 0, sizeof(cGAME_CONFIG)); 
	 
	// Setup players: 
	iPlayers = 4; 
	PlayerType[0] = PLAYER_TYPE_HUMAN; 
	PlayerType[1] = PLAYER_TYPE_COMPUTER_NORMAL; 
	PlayerType[2] = PLAYER_TYPE_COMPUTER_EASY; 
	PlayerType[3] = PLAYER_TYPE_COMPUTER_CLEVER; 
 
	// Setup other: 
	bShowCardsAtBeginning = TRUE; 
	iBeginningShowTime = 5; 
	bTimeLimit = FALSE; 
	iTimeLimit = 120; 
	bThinkTimeLimit = TRUE; 
	iThinkTime = 10; 
	bErrorLimit = TRUE; 
	iErrors = 5; 
	iRounds = 1; 
	iCardDimension = 3; 
	iCardPairs = iCardDimensionStencil[iCardDimension][X]*iCardDimensionStencil[iCardDimension][Y]/2; 
 
	// Load the standart card script: 
	cStyle.Load(_AS->byStandartCardStyle); 
 
	StartMusic(_AS->byStandartMusic); 
} // end cGAME_CONFIG::SetStandart() 
 
void cGAME_CONFIG::LoadAdvancedSettings(char *pbyFilename) 
{ // begin cGAME_CONFIG::LoadAdvancedSettings() 
	char byTemp[256]; 
	int i, iTemp; 
	 
	if(!pbyFilename) 
		return; 
 
	// Game: 
	iPlayers = GetPrivateProfileInt("game", "players", 1, pbyFilename); 
	for(i = 0; i < 4; i++) 
	{ 
		sprintf(byTemp, "player_%d", i+1); 
		iTemp = GetPrivateProfileInt("game", byTemp, 1, pbyFilename); 
		switch(iTemp) 
		{ 
			case 0: PlayerType[i] = PLAYER_TYPE_HUMAN; break; 
			case 1: PlayerType[i] = PLAYER_TYPE_COMPUTER_EASY; break; 
			case 2: PlayerType[i] = PLAYER_TYPE_COMPUTER_NORMAL; break; 
			case 3: PlayerType[i] = PLAYER_TYPE_COMPUTER_CLEVER; break; 
		} 
	} 
	bShowCardsAtBeginning = GetPrivateProfileInt("game", "show_cards_at_beginning", 1, pbyFilename); 
	iBeginningShowTime = GetPrivateProfileInt("game", "beginning_show_time", 5, pbyFilename); 
	bTimeLimit = GetPrivateProfileInt("game", "is_time_limit", 0, pbyFilename); 
	iTimeLimit = GetPrivateProfileInt("game", "time_limit", 120, pbyFilename); 
	bThinkTimeLimit = GetPrivateProfileInt("game", "is_think_time_limit", 1, pbyFilename); 
	iThinkTime = GetPrivateProfileInt("game", "think_time_limit", 10, pbyFilename); 
	bErrorLimit = GetPrivateProfileInt("game", "is_error_limit", 1, pbyFilename); 
	iErrors = GetPrivateProfileInt("game", "error_limit", 5, pbyFilename); 
	iRounds = GetPrivateProfileInt("game", "rounds", 1, pbyFilename); 
	GetPrivateProfileString("game", "card_style", _AS->byStandartCardStyle, byTemp, MAX_PATH, pbyFilename); 
	cStyle.Load(byTemp); 
	GetPrivateProfileString("game", "music", _AS->byStandartMusic, byTemp, MAX_PATH, pbyFilename); 
	StartMusic(byTemp); 
} // end cGAME_CONFIG::LoadAdvancedSettings() 
 
void cGAME_CONFIG::SaveAdvancedSettings(char *pbyFilename) 
{ // begin cGAME_CONFIG::SaveAdvancedSettings() 
	int i, iTemp; 
	FILE *pFile; 
 
	if(!pbyFilename) 
		return; 
 
	// Save the current configurations: 
	pFile = fopen(pbyFilename, "wt"); 
	if(!pFile) 
		return; 
 
	// Game: 
	fprintf(pFile, "[game]\n"); 
    fprintf(pFile, "players=%d\n", iPlayers); 
	for(i = 0; i < 4; i++) 
	{ 
		switch(PlayerType[i]) 
		{ 
			case PLAYER_TYPE_HUMAN: iTemp = 0; break; 
			case PLAYER_TYPE_COMPUTER_EASY: iTemp = 1; break; 
			case PLAYER_TYPE_COMPUTER_NORMAL: iTemp = 2; break; 
			case PLAYER_TYPE_COMPUTER_CLEVER: iTemp = 3; break; 
		} 
	    fprintf(pFile, "player_%d=%d\n", i+1, iTemp); 
	} 
    fprintf(pFile, "show_cards_at_beginning=%d\n", bShowCardsAtBeginning); 
    fprintf(pFile, "beginning_show_time=%d\n", iBeginningShowTime); 
    fprintf(pFile, "is_time_limit=%d\n", bTimeLimit); 
    fprintf(pFile, "time_limit=%d\n", iTimeLimit); 
    fprintf(pFile, "is_think_time_limit=%d\n", bThinkTimeLimit); 
    fprintf(pFile, "think_time_limit=%d\n", iThinkTime); 
    fprintf(pFile, "is_error_limit=%d\n", bErrorLimit); 
    fprintf(pFile, "error_limit=%d\n", iErrors); 
    fprintf(pFile, "rounds=%d\n", iRounds); 
    fprintf(pFile, "card_style=%s\n", cStyle.byFolderName); 
    fprintf(pFile, "music=%s\n", byCurrentMusic); 
	fclose(pFile); 
	 
	return; 
} // end cGAME_CONFIG::SaveAdvancedSettings() 
/////////////////////////////////////////////////////////////////////////////// 
 
 
// cGAME_CARD functions: ****************************************************** 
void cGAME_CARD::Draw(BOOL bOnlyDeath) 
{ // begin cGAME_CARD::Draw() 
	int i; 
	 
	glColor3f(1.0f, 1.0f, 1.0f); 
	ASEnableLighting(); 
 
	if((bOnlyDeath && !bGoingDeath) || !bOnlyDeath && bGoingDeath) 
		return; 
	 
	// Setup position: 
	glPushMatrix(); 
	glTranslatef(vWorldPos.fX, vWorldPos.fY, vWorldPos.fZ); 
	glRotatef(vRot.fX, 1.0f, 0.0f, 0.0f); 
	glRotatef((float) (vRot.fY+180.0f+180.0f*fSelectionRotSmoothTime), 0.0f, 1.0f, 0.0f); 
	glRotatef(vRot.fZ, 0.0f, 0.0f, 1.0f); 
 
	// Draw the card: 
	if(_ASConfig->bMultitexturing) 
	{ 
		glActiveTextureARB(GL_TEXTURE1_ARB); 
		glColor3f(0.5f, 0.5f, 0.5f); 
		glBindTexture(GL_TEXTURE_2D, pcCardStyle->sTexture[2].iOpenGLID); 
		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); 
		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); 
		glEnable(GL_TEXTURE_2D); 
		glEnable(GL_TEXTURE_GEN_S); 
		glEnable(GL_TEXTURE_GEN_T); 
		glActiveTextureARB(GL_TEXTURE0_ARB); 
	} 
	if(bGoingDeath) 
	{ 
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
		glEnable(GL_BLEND); 
		glColor4f(1.0f, 1.0f, 1.0f, fSelectionRotSmoothTime); 
		float f = (1.0f-fSelectionRotSmoothTime)*2+1.0f; 
		glScalef(f, f, f); 
		glDepthMask(FALSE); 
	} 
	else 
		glColor3f(1.0f, 1.0f, 1.0f); 
 
	// Front side: 
	glBindTexture(GL_TEXTURE_2D, pcCardStyle->sCard[iCard].Texture.iOpenGLID); 
	glDrawArrays(GL_QUADS, 0, 4); 
 
	// Backside: 
	glBindTexture(GL_TEXTURE_2D, pcCardStyle->sTexture[0].iOpenGLID); 
	glDrawArrays(GL_QUADS, 4, 7); 
 
	// The four sides: 
	glBindTexture(GL_TEXTURE_2D, pcCardStyle->sTexture[1].iOpenGLID); 
	glBegin(GL_QUADS); 
 
		// Left: 
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 0.0f);  
		glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 0.0f);  
		glArrayElement(0); 
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f, 0.0f);  
		glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0f, 0.0f);  
		glArrayElement(3); 
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1.0f, 1.0f);  
		glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1.0f, 1.0f);  
		glArrayElement(4); 
		glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 1.0f);  
		glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 1.0f);  
		glArrayElement(7); 
 
		// Top: 
		glArrayElement(5); 
		glArrayElement(4); 
		glArrayElement(3); 
		glArrayElement(2); 
 
		// Right: 
		glArrayElement(6); 
		glArrayElement(5); 
		glArrayElement(2); 
		glArrayElement(1); 
 
		// Bottom: 
		glArrayElement(7); 
		glArrayElement(6); 
		glArrayElement(1); 
		glArrayElement(0); 
 
	glEnd(); 
 
	glActiveTextureARB(GL_TEXTURE1_ARB); 
	glDisable(GL_TEXTURE_2D); 
	glDisable(GL_TEXTURE_GEN_S); 
	glDisable(GL_TEXTURE_GEN_T); 
	glActiveTextureARB(GL_TEXTURE0_ARB); 
 
	// Now draw the selection bounding if the card is under the mouse or selected: 
	if(fSelectionColor[R] != 0.0f || fSelectionColor[G] != 0.0f || fSelectionColor[B] != 0.0f) 
	{ 
		glDisable(GL_LIGHTING); 
		glDisable(GL_CULL_FACE); 
		glEnable(GL_BLEND); 
		glDepthMask(FALSE); 
		FLOAT4 fColor = {fSelectionColor[R], fSelectionColor[G], fSelectionColor[B], fSelectionColor[A]}; 
		FLOAT4 fBlack = {0.0f, 0.0f, 0.0f, 0.0f}; 
		glBindTexture(GL_TEXTURE_2D, Caust1Texture[iSelectionAniStep].iOpenGLID); 
		for(i = 0; i < 2; i++) 
		{ 
			if(!i) 
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
			else 
				glBlendFunc(GL_SRC_ALPHA, GL_ONE); 
			glBegin(GL_QUADS); 
				// Left side: 
				glColor4fv(fBlack); 
				glTexCoord2f(0.0f, 0.0f); 
				glVertex3fv(vAniSelectionPoints[1][0].fV); 
				glTexCoord2f(1.0f, 0.0f); 
				glVertex3fv(vAniSelectionPoints[1][1].fV); 
				glColor4fv(fColor); 
				glTexCoord2f(1.0f, 1.0f); 
				glVertex2f(-0.5f, 0.0f); 
				glTexCoord2f(0.0f, 1.0f); 
				glVertex2f(-0.5f, -0.5f); 
				glColor4fv(fBlack); 
				glTexCoord2f(0.0f, 0.0f); 
				glVertex3fv(vAniSelectionPoints[1][1].fV); 
				glTexCoord2f(1.0f, 0.0f); 
				glVertex3fv(vAniSelectionPoints[1][2].fV); 
				glColor4fv(fColor); 
				glTexCoord2f(1.0f, 1.0f); 
				glVertex2f(-0.5f, 0.5f); 
				glTexCoord2f(0.0f, 1.0f); 
				glVertex2f(-0.5f, 0.0f); 
 
				// Top side: 
				glColor4fv(fColor); 
				glTexCoord2f(0.0f, 0.0f); 
				glVertex2f(-0.5f, -0.5f); 
				glTexCoord2f(1.0f, 0.0f); 
				glVertex2f(0.0f, -0.5f); 
				glColor4fv(fBlack); 
				glTexCoord2f(1.0f, 1.0f); 
				glVertex3fv(vAniSelectionPoints[1][3].fV); 
				glTexCoord2f(0.0f, 1.0f); 
				glVertex3fv(vAniSelectionPoints[1][0].fV); 
				glColor4fv(fColor); 
				glTexCoord2f(0.0f, 0.0f); 
				glVertex2f(0.0f, -0.5f); 
				glTexCoord2f(1.0f, 0.0f); 
				glVertex2f(0.5f, -0.5f); 
				glColor4fv(fBlack); 
				glTexCoord2f(1.0f, 1.0f); 
				glVertex3fv(vAniSelectionPoints[1][4].fV); 
				glTexCoord2f(0.0f, 1.0f); 
				glVertex3fv(vAniSelectionPoints[1][3].fV); 
 
				// Right side: 
				glColor4fv(fColor); 
				glTexCoord2f(0.0f, 0.0f); 
				glVertex2f(0.5f, -0.5f); 
				glTexCoord2f(1.0f, 0.0f); 
				glVertex2f(0.5f, 0.0f); 
				glColor4fv(fBlack); 
				glTexCoord2f(1.0f, 1.0f); 
				glVertex3fv(vAniSelectionPoints[1][5].fV); 
				glTexCoord2f(0.0f, 1.0f); 
				glVertex3fv(vAniSelectionPoints[1][4].fV); 
				glColor4fv(fColor); 
				glTexCoord2f(0.0f, 0.0f); 
				glVertex2f(0.5f, 0.0f); 
				glTexCoord2f(1.0f, 0.0f); 
				glVertex2f(0.5f, 0.5f); 
				glColor4fv(fBlack); 
				glTexCoord2f(1.0f, 1.0f); 
				glVertex3fv(vAniSelectionPoints[1][6].fV); 
				glTexCoord2f(0.0f, 1.0f); 
				glVertex3fv(vAniSelectionPoints[1][5].fV); 
 
				// Bottom side: 
				glColor4fv(fBlack); 
				glTexCoord2f(0.0f, 0.0f); 
				glVertex3fv(vAniSelectionPoints[1][2].fV); 
				glTexCoord2f(1.0f, 0.0f); 
				glVertex3fv(vAniSelectionPoints[1][7].fV); 
				glColor4fv(fColor); 
				glTexCoord2f(1.0f, 1.0f); 
				glVertex2f(0.0f, 0.5f); 
				glTexCoord2f(0.0f, 1.0f); 
				glVertex2f(-0.5f, 0.5f); 
				glColor4fv(fBlack); 
				glTexCoord2f(0.0f, 0.0f); 
				glVertex3fv(vAniSelectionPoints[1][7].fV); 
				glTexCoord2f(1.0f, 0.0f); 
				glVertex3fv(vAniSelectionPoints[1][6].fV); 
				glColor4fv(fColor); 
				glTexCoord2f(1.0f, 1.0f); 
				glVertex2f(0.5f, 0.5f); 
				glTexCoord2f(0.0f, 1.0f); 
				glVertex2f(0.0f, 0.5f); 
 
			glEnd(); 
		} 
 
		glDepthMask(TRUE); 
		ASEnableLighting(); 
		glEnable(GL_CULL_FACE); 
	} 
	glDisable(GL_BLEND); 
	glDepthMask(TRUE); 
	glBlendFunc(GL_SRC_ALPHA, GL_ONE); 
 
	glPopMatrix(); 
} // end cGAME_CARD::Draw() 
 
void cGAME_CARD::PerformLighmap(AS_DLIGHT cLight) 
{ // begin cGAME_CARD::PerformLighmap() 
	AS_3D_VECTOR vCardVerticesT[8]; 
	int i; 
	 
	for(i = 0; i < 8; i++) 
	{ 
		ASRotateVectorX(fCardVertices[i], vRot.fX, &vCardVerticesT[i].fV); 
		ASRotateVectorY(vCardVerticesT[i].fV, (float) (vRot.fY+180.0f+180.0f*fSelectionRotSmoothTime), &vCardVerticesT[i].fV); 
		ASRotateVectorZ(vCardVerticesT[i].fV, vRot.fZ, &vCardVerticesT[i].fV); 
		vCardVerticesT[i] *= 1.005f; 
		vCardVerticesT[i] += vWorldPos; 
	} 
 
	// Front side: 
	cLight.Light(vCardVerticesT[0], vCardVerticesT[1], vCardVerticesT[2]); 
	cLight.Light(vCardVerticesT[2], vCardVerticesT[3], vCardVerticesT[0]); 
 
	// Backside: 
	cLight.Light(vCardVerticesT[4], vCardVerticesT[5], vCardVerticesT[6]); 
	cLight.Light(vCardVerticesT[6], vCardVerticesT[7], vCardVerticesT[4]); 
} // end cGAME_CARD::PerformLighmap() 
 
void cGAME_CARD::Check(void) 
{ // begin cGAME_CARD::Check() 
	int i, i2; 
	 
	// Animate the texture of the selection bounding: 
	if(g_lGameTimer-lSelectionAniTime > 25 || g_lGameTimer-lSelectionAniTime < 0) 
	{ 
		lSelectionAniTime = g_lGameTimer; 
		iSelectionAniStep++; 
		if(iSelectionAniStep >= 32) 
			iSelectionAniStep = 0; 
	} 
 
	if(bGoingDeath) 
		vWorldPos.fZ -= (float) g_lDeltatime/500; 
 
	// Animate the selection bounding itself: 
	if(fSelectionColor[R] != 0.0f || fSelectionColor[G] != 0.0f || fSelectionColor[B] != 0.0f) 
	{ 
		for(i = 0; i < 8; i++) 
		{ 
			for(i2 = 0; i2 < 3; i2++) 
			{ 
				if(vAniSelectionPoints[NEW_POINT][i].fV[i2] > vAniSelectionPoints[LAST_POINT][i].fV[i2]) 
				{ 
					vAniSelectionPoints[POINT_VELOCITY][i].fV[i2] += (float) g_lDeltatime/50000; 
					vAniSelectionPoints[CURRENT_POINT][i].fV[i2] += vAniSelectionPoints[POINT_VELOCITY][i].fV[i2]/5; 
					if(vAniSelectionPoints[CURRENT_POINT][i].fV[i2] > vAniSelectionPoints[NEW_POINT][i].fV[i2]) 
					{ 
						goto GetNewPoint; 
					} 
				} 
				else 
				{ 
					vAniSelectionPoints[POINT_VELOCITY][i].fV[i2] -= (float) g_lDeltatime/50000; 
					vAniSelectionPoints[CURRENT_POINT][i].fV[i2] += vAniSelectionPoints[POINT_VELOCITY][i].fV[i2]/5; 
					if(vAniSelectionPoints[CURRENT_POINT][i].fV[i2] < vAniSelectionPoints[NEW_POINT][i].fV[i2]) 
					{ 
						goto GetNewPoint; 
					} 
				} 
				continue; 
			GetNewPoint: 
 
				vAniSelectionPoints[POINT_VELOCITY][i].fV[i2] *= 0.3f; 
				vAniSelectionPoints[LAST_POINT][i].fV[i2] = vAniSelectionPoints[CURRENT_POINT][i].fV[i2]; 
				 
				if(!(rand() % 2)) 
					vAniSelectionPoints[NEW_POINT][i].fV[i2] = vAniSelectionPoints[FIX_POINT][i].fV[i2]+((float) (rand() % 1000)/8000); 
				else 
					vAniSelectionPoints[NEW_POINT][i].fV[i2] = vAniSelectionPoints[FIX_POINT][i].fV[i2]-((float) (rand() % 1000)/8000); 
			} 
		} 
	} 
 
} // end cGAME_CARD::Check() 
/////////////////////////////////////////////////////////////////////////////// 
 
 
// cGAME_INFO functions: ****************************************************** 
void cGAME_INFO::Reset(void) 
{ // begin cGAME_INFO::Reset() 
	iSelectedCard[0] = iSelectedCard[1] = -1; 
	iCurrentPlayer = 0; 
	iCardPairsOnTable = cGameConfig.iCardPairs; 
	iCurrentRound = 0; 
	memset(sPlayerInfo, 0, sizeof(sPLAYER_INFO)*MAX_PLAYERS); 
	lTimeLimit = g_lGameTimer; 
	iTimeLimitPastSeconds = 0; 
} // end cGAME_INFO::Reset() 
 
void cGAME_INFO::ShowInfo(AS_WINDOW *pWindow) 
{ // begin cGAME_INFO::ShowInfo() 
	char byTemp[256]; 
	float fTime; 
	int i, i2, iCheck, iWinner, iY; 
 
	if(!Setup.bShowHud) 
		return; 
	 
	if(cGameInfo.bShowCardsAtBeginng) 
	{ // Show card show bar: 
		fTime = 1.0f-((float) cGameInfo.iShowCardsAtBeginningPastSeconds/cGameConfig.iBeginningShowTime); 
		glLoadIdentity(); 
		glDisable(GL_LIGHTING); 
		glDisable(GL_TEXTURE_2D); 
		glDisable(GL_DEPTH_TEST); 
		glTranslatef(-1.0f, -0.6f, -2.0f); 
		glRotatef(110.0f, 1.0f, 1.0f, 1.0f); 
		glColor4f(0.0f, 0.0f, 0.0f, 0.2f); 
		glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); 
		glBegin(GL_QUADS); 
			glVertex2f(-0.01f, -0.01f); 
			glVertex2f(1.0f*fTime+0.01f, -0.01f); 
			glVertex2f(1.0f*fTime+0.01f, 0.06f); 
			glVertex2f(-0.01f, 0.06f); 
		glEnd(); 
		glBlendFunc(GL_SRC_ALPHA, GL_ONE); 
		glColor4f(1.0f-fTime, 0.0f, fTime, 1.0f); 
		glBegin(GL_QUADS); 
			glVertex2f(0.0f, 0.0f); 
			glVertex2f(1.0f*fTime, 0.0f); 
			glVertex2f(1.0f*fTime, 0.05f); 
			glVertex2f(0.0f, 0.05f); 
		glEnd(); 
		glEnable(GL_TEXTURE_2D); 
		glEnable(GL_DEPTH_TEST); 
		glEnable(GL_BLEND); 
	} 
	else 
	{ 
		if(cGameConfig.bThinkTimeLimit) 
		{ // Show think time bar: 
			fTime = 1.0f-((float) cGameInfo.iThinkTimePastSeconds/cGameConfig.iThinkTime); 
			glLoadIdentity(); 
			glDisable(GL_LIGHTING); 
			glDisable(GL_TEXTURE_2D); 
			glDisable(GL_DEPTH_TEST); 
			glTranslatef(-1.0f, -0.6f, -2.0f); 
			glRotatef(110.0f, 1.0f, 1.0f, 1.0f); 
			glColor4f(0.0f, 0.0f, 0.0f, 0.2f); 
			glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); 
			glColor4f(0.0f, 0.0f, 0.0f, 0.2f); 
			glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); 
			glBegin(GL_QUADS); 
				glVertex2f(-0.01f, -0.01f); 
				glVertex2f(1.0f*fTime+0.01f, -0.01f); 
				glVertex2f(1.0f*fTime+0.01f, 0.06f); 
				glVertex2f(-0.01f, 0.06f); 
			glEnd(); 
			glBlendFunc(GL_SRC_ALPHA, GL_ONE); 
			glColor4f(1.0f-fTime, 0.0f, fTime, 1.0f); 
			glBegin(GL_QUADS); 
				glVertex2f(0.0f, 0.0f); 
				glVertex2f(1.0f*fTime, 0.0f); 
				glVertex2f(1.0f*fTime, 0.05f); 
				glVertex2f(0.0f, 0.05f); 
			glEnd(); 
			glEnable(GL_TEXTURE_2D); 
			glEnable(GL_DEPTH_TEST); 
			glEnable(GL_BLEND); 
		} 
	} 
	 
	if(cGameConfig.bTimeLimit) 
	{ // Show the time bar 
		fTime = 1.0f-((float) cGameInfo.iTimeLimitPastSeconds/cGameConfig.iTimeLimit); 
		glLoadIdentity(); 
		glDisable(GL_LIGHTING); 
		glDisable(GL_TEXTURE_2D); 
		glDisable(GL_DEPTH_TEST); 
		glTranslatef(-0.5f, 0.785f, -2.0f); 
		glColor4f(0.0f, 0.0f, 0.0f, 0.2f); 
		glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); 
		glBegin(GL_QUADS); 
			glVertex2f(-0.01f, -0.01f); 
			glVertex2f(1.0f*fTime+0.01f, -0.01f); 
			glVertex2f(1.0f*fTime+0.01f, 0.03f); 
			glVertex2f(-0.01f, 0.03f); 
		glEnd(); 
		glBlendFunc(GL_SRC_ALPHA, GL_ONE); 
		glColor4f(1.0f-fTime, 0.0f, fTime, 1.0f); 
		glBegin(GL_QUADS); 
			glVertex2f(0.0f, 0.0f); 
			glVertex2f(1.0f*fTime, 0.0f); 
			glVertex2f(1.0f*fTime, 0.02f); 
			glVertex2f(0.0f, 0.02f); 
		glEnd(); 
		glEnable(GL_TEXTURE_2D); 
		glEnable(GL_DEPTH_TEST); 
		glEnable(GL_BLEND); 
	} 
 
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f); 
 
	// Show the number of the current round: 
	if(cGameConfig.iRounds > 1) 
	{ 
		sprintf(byTemp, "%s: %d", T_Round, iCurrentRound+1); 
		pWindow->PrintAnimated(320, 450, byTemp, 0, 1.0f, fFontAni, 1); 
	} 
 
	for(i = 0; i < cGameConfig.iPlayers; i++) 
		ShowPlayerInfo(pWindow, i); 
 
	if(fGameFinishedBlend) 
	{ // Draw the game finished screen: 
		// Draw the dark blending quad: 
		glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); 
		glColor4f(0.1f, 0.1f, 0.1f, 1.1f-fGameFinishedBlend); 
		glDisable(GL_DEPTH_TEST); 
		glDisable(GL_TEXTURE_2D); 
		glDisable(GL_LIGHTING); 
		glLoadIdentity(); 
		glTranslatef(0.0f, 0.0f, -24.0f); 
		glBegin(GL_QUADS); 
			glVertex2f(-15.0f, -11.0f); 
			glVertex2f( 15.0f, -11.0f); 
			glVertex2f( 15.0f,  11.0f); 
			glVertex2f(-15.0f,  11.0f); 
		glEnd(); 
		glBlendFunc(GL_SRC_ALPHA, GL_ONE); 
		glEnable(GL_DEPTH_TEST); 
		glEnable(GL_TEXTURE_2D); 
 
		// Print the text: 
		glColor4f(1.0f, 1.0f, 1.0f, fGameFinishedBlend); 
		pWindow->PrintAnimated(320, 420, T_GameFinished, 0, 2.0f, fFontAni, 1); 
 
		pWindow->PrintAnimated(320, 380, T_Result, 0, 1.5f, fFontAni, 1); 
 
		if(cGameConfig.bTimeLimit) 
		{ 
			sprintf(byTemp, "%s: %d %s", T_GameDuration, cGameInfo.iTimeLimitPastSeconds-1, T_Seconds); 
			pWindow->PrintAnimated(320, 350, byTemp, 0, 1.0f, fFontAni, 1); 
		} 
 
		for(i = 0, iY = 300; i < cGameConfig.iPlayers; i++, iY -= 80) 
		{ 
			sprintf(byTemp, "%s %d:", T_Player, i+1); 
			pWindow->PrintAnimated(200, iY, byTemp, 0, 1.3f, fFontAni, 1); 
			sprintf(byTemp, "%s %d:", T_FoundCardPairs, cGameInfo.sPlayerInfo[i].iCardPairs); 
			pWindow->PrintAnimated(400, iY-20, byTemp, 0, 1.0f, fFontAni, 1); 
		} 
 
		glColor4f(1.0f, 1.0f, 1.0f, fPressAnyKeyBlend); 
		pWindow->PrintAnimated(320, 10, M_PressAnyKeyToContinue, 0, 1.0f, fFontAni, 1); 
 
		// Draw the cup: 
		glClear(GL_DEPTH_BUFFER_BIT); 
		glDisable(GL_BLEND); 
		glDisable(GL_CULL_FACE); 
		ASEnableLighting(); 
 
		// Get the winner: (if there is one...) 
		iWinner = -1; 
		if(cGameConfig.iPlayers == 1) 
			iWinner = 0; 
		else 
			for(i = 0; i < cGameConfig.iPlayers; i++) 
			{ 
				for(iCheck = 0, i2 = 0; i2 < cGameConfig.iPlayers; i2++) 
				{ 
					if(i == i2) 
						continue; 
					if(cGameInfo.sPlayerInfo[i].iCardPairs > cGameInfo.sPlayerInfo[i2].iCardPairs) 
						iCheck++; 
				} 
				if(iCheck == cGameConfig.iPlayers-1) 
				{ // This is our winner! 
					iWinner = i; 
					break; 
				} 
			} 
 
		if(iWinner != -1) 
		{ 
			glLoadIdentity(); 
			glTranslatef(-0.8f, 0.1f-0.29f*iWinner, -2.0f); 
			glRotatef(20.0f, 1.0f, 0.0f, 0.0f); 
			glRotatef(fCupRot, 0.0f, 1.0f, 0.0f); 
			glScalef(0.002f, 0.002f, 0.002f); 
			fCupRot += (float) g_lDeltatime/50; 
			glEnable(GL_TEXTURE_2D); 
			glColor4f(1.0f, 1.0f, 1.0f, fGameFinishedBlend); 
			glBindTexture(GL_TEXTURE_2D, GameTexture[2].iOpenGLID); 
			ASDrawMd2Frame(pCupModel, 0); 
 
			glEnable(GL_BLEND); 
			glEnable(GL_TEXTURE_GEN_S); 
			glEnable(GL_TEXTURE_GEN_T); 
			glColor4f(1.0f, 1.0f, 1.0f, fGameFinishedBlend-0.3f); 
			glBindTexture(GL_TEXTURE_2D, GameTexture[3].iOpenGLID); 
			ASDrawMd2Frame(pCupModel, 0); 
 
			glDisable(GL_TEXTURE_GEN_S); 
			glDisable(GL_TEXTURE_GEN_T); 
			glCullFace(GL_BACK); 
			glEnable(GL_CULL_FACE); 
		} 
 
	} 
	if(fFlashBlend) 
	{ // Blend the screen: 
		glColor4f(1.0f, 1.0f, 1.0f, fFlashBlend); 
		glDisable(GL_DEPTH_TEST); 
		glDisable(GL_TEXTURE_2D); 
		glDisable(GL_LIGHTING); 
		glLoadIdentity(); 
		glTranslatef(0.0f, 0.0f, -24.0f); 
		glBegin(GL_QUADS); 
			glVertex2f(-15.0f, -11.0f); 
			glVertex2f( 15.0f, -11.0f); 
			glVertex2f( 15.0f,  11.0f); 
			glVertex2f(-15.0f,  11.0f); 
		glEnd(); 
		glEnable(GL_DEPTH_TEST); 
		glEnable(GL_TEXTURE_2D); 
	} 
} // end cGAME_INFO::ShowInfo() 
 
void cGAME_INFO::ShowPlayerInfo(AS_WINDOW *pWindow, int iPlayer) 
{ // begin cGAME_INFO::ShowPlayerInfo() 
	char byTemp[256]; 
	INT2 iPlayerInfoPos[MAX_PLAYERS] = {{10, 450}, {440, 450}, {440, 20}, {10, 20}}; 
	 
	// Show  the number of the player: 
	sprintf(byTemp, "%d", iPlayer+1); 
	pWindow->PrintAnimated(iPlayerInfoPos[iPlayer][X], (int) (iPlayerInfoPos[iPlayer][Y]-(10.0f-10.0f*cos(sin(sPlayerInfo[iPlayer].fActiveBlend)*PI))), 
						   byTemp, 0, 1.0f+(float) (1.5f-1.5f*cos(sin(sPlayerInfo[iPlayer].fActiveBlend)*PI)), fFontAni, 1); 
 
	// Show the number of pairs this player has: 
	sprintf(byTemp, "%s: %d", T_CardPairs, sPlayerInfo[iPlayer].iCardPairs); 
	pWindow->PrintAnimated(iPlayerInfoPos[iPlayer][X]+30, iPlayerInfoPos[iPlayer][Y], 
						   byTemp, 0, 1.0f, fFontAni, 0); 
} // end cGAME_INFO::ShowPlayerInfo() 
 
void cGAME_INFO::Check(void) 
{ // begin cGAME_INFO::Check() 
	int i; 
	 
	// Screen blend: 
	if(bFlashBlend) 
	{ 
		fFlashBlend += (float) g_lDeltatime/1000; 
		if(fFlashBlend > 1.0f) 
		{ 
			fFlashBlend = 1.0f; 
			bFlashBlend = FALSE; 
		} 
	} 
	else 
	{ 
		fFlashBlend -= (float) g_lDeltatime/1000; 
		if(fFlashBlend < 0.0f) 
			fFlashBlend = 0.0f; 
	} 
 
	// Game finished: 
	if(bGameFinished) 
	{ 
		fGameFinishedBlend += (float) g_lDeltatime/1000; 
		if(fGameFinishedBlend > 1.0f) 
			fGameFinishedBlend = 1.0f; 
 
		// Animate the 'Press any key to continue' text: 
		if(!bPressAnyKeyBlend) 
		{ 
			fPressAnyKeyBlend += (float) g_lDeltatime/1000; 
			if(fPressAnyKeyBlend > 1.0f) 
			{ 
				fPressAnyKeyBlend = 1.0f; 
				bPressAnyKeyBlend = 1; 
			} 
		} 
		else 
		{ 
			fPressAnyKeyBlend -= (float) g_lDeltatime/1000; 
			if(fPressAnyKeyBlend < 0.0f) 
			{ 
				fPressAnyKeyBlend = 0.0f; 
				bPressAnyKeyBlend = 0; 
			} 
		} 
 
		if(ASIsKeyPressed()) 
			_AS->SetNextModule(MODULE_MENU); 
 
		return; 
	} 
	else 
	{ 
		fGameFinishedBlend -= (float) g_lDeltatime/1000; 
		if(fGameFinishedBlend < 0.0f) 
			fGameFinishedBlend = 0.0f; 
		fPressAnyKeyBlend -= (float) g_lDeltatime/1000; 
		if(fPressAnyKeyBlend < 0.0f) 
		{ 
			fPressAnyKeyBlend = 0.0f; 
			bPressAnyKeyBlend = 0; 
		} 
	} 
 
	// Check card beginning show: 
	if(bShowCardsAtBeginng) 
	{ 
		if(g_lGameTimer-lShowCardsAtBeginningTime > 1000) 
		{ 
			lShowCardsAtBeginningTime = g_lGameTimer; 
			iShowCardsAtBeginningPastSeconds++; 
			if(iShowCardsAtBeginningPastSeconds > cGameConfig.iBeginningShowTime) 
			{ 
				bShowCardsAtBeginng = FALSE; 
				lTimeLimit = lThinkTime = g_lGameTimer; 
			} 
		} 
 
		if(ASIsKeyPressed()) 
		{ 
			lTimeLimit = lThinkTime = g_lGameTimer; 
			bShowCardsAtBeginng = FALSE; 
		} 
 
		return; 
	} 
 
	// Check time limit: 
	if(cGameConfig.bTimeLimit) 
	{ 
		if(g_lGameTimer-cGameInfo.lTimeLimit > 1000) 
		{ 
			cGameInfo.lTimeLimit = g_lGameTimer; 
			cGameInfo.iTimeLimitPastSeconds++; 
			if(cGameInfo.iTimeLimitPastSeconds > cGameConfig.iTimeLimit) 
			{ // The time is out, the game is now finished: 
				cGameInfo.iCardPairsOnTable = 0; 
				cGameInfo.iSelectedCard[0] = cGameInfo.iSelectedCard[1] = -1; 
			} 
		} 
	} 
 
	// Check think time: 
	if(cGameConfig.bThinkTimeLimit && (cGameInfo.iSelectedCard[0] == -1 || 
	   cGameInfo.iSelectedCard[1] == -1)) 
	{ 
		if(g_lGameTimer-lThinkTime > 1000) 
		{ 
			lThinkTime = g_lGameTimer; 
			iThinkTimePastSeconds++; 
			if(iThinkTimePastSeconds > cGameConfig.iThinkTime) 
			{ // The think time is over: 
				if(cGameConfig.iPlayers == 1) 
				{ // There is only one player: 
					cGameInfo.iCardPairsOnTable = 0; 
					cGameInfo.iSelectedCard[0] = cGameInfo.iSelectedCard[1] = -1; 
 
					return; 
				} 
				  
				// Switch to the next player: 
				iThinkTimePastSeconds = 0; 
				cGameInfo.iCurrentPlayer++; 
				if(cGameInfo.iCurrentPlayer >= cGameConfig.iPlayers) 
					cGameInfo.iCurrentPlayer = 0; 
			} 
		} 
	} 
 
	// Check the players: 
	for(i = 0; i < cGameConfig.iPlayers; i++) 
	{ 
		if(i == iCurrentPlayer) 
		{ 
			sPlayerInfo[i].fActiveBlend += (float) g_lDeltatime/1000; 
			if(sPlayerInfo[i].fActiveBlend > 1.0f) 
				sPlayerInfo[i].fActiveBlend = 1.0f; 
		} 
		else 
		{ 
			sPlayerInfo[i].fActiveBlend -= (float) g_lDeltatime/1000; 
			if(sPlayerInfo[i].fActiveBlend < 0.0f) 
				sPlayerInfo[i].fActiveBlend = 0.0f; 
		} 
	} 
	CheckGameCards(); 
} // end cGAME_INFO::Check() 
/////////////////////////////////////////////////////////////////////////////// 
 
void InitGameCards(void) 
{ // begin InitGameCards() 
	cGAME_CARD *pcGameCardT; 
	INT2 *iCard; // [0] = Card   [1] = Still to spread 
	int i, i2, i3, iRemeber, iGetCard, iX, iY, iTemp; 
 
	// Get memory: 
	SAFE_DELETE(pcGameCard); 
	pcGameCard = (cGAME_CARD *) malloc(sizeof(cGAME_CARD)*cGameConfig.iCardPairs*2); 
 
	// Initialize the cards: 
	g_lGameTimer = 0; 
	vPlayField[MIN] = 1000; 
	vPlayField[MAX] = -1000; 
	for(i = 0, iY = 0; iY < iCardDimensionStencil[cGameConfig.iCardDimension][Y]; iY++) 
		for(iX = 0; iX < iCardDimensionStencil[cGameConfig.iCardDimension][X]; iX++, i++) 
		{ 
			pcGameCardT = &pcGameCard[i]; 
			memset(pcGameCardT, 0, sizeof(cGAME_CARD)); 
			pcGameCardT->iID = i; 
			pcGameCardT->iCard = -1; 
			pcGameCardT->bActive = TRUE; 
			pcGameCardT->vWorldPos.fX = iX*1.2f; 
			pcGameCardT->vWorldPos.fY = iY*1.2f;				 
			pcGameCardT->vWorldPos.fZ = 0.0f; 
			pcGameCardT->lSelectionAniTime = g_lGameTimer; 
			pcGameCardT->iSelectionAniStep = rand() % 32; 
			memset(pcGameCardT->fSelectionColor, 0, sizeof(FLOAT4)); 
 
			pcGameCardT->vAniSelectionPoints[0][0].fX = pcGameCardT->vAniSelectionPoints[1][0].fX = -0.7f; 
			pcGameCardT->vAniSelectionPoints[0][0].fY = pcGameCardT->vAniSelectionPoints[1][0].fY = -0.7f; 
			pcGameCardT->vAniSelectionPoints[0][1].fX = pcGameCardT->vAniSelectionPoints[1][1].fX = -0.7f; 
			pcGameCardT->vAniSelectionPoints[0][1].fY = pcGameCardT->vAniSelectionPoints[1][1].fY = 0.0f; 
			pcGameCardT->vAniSelectionPoints[0][2].fX = pcGameCardT->vAniSelectionPoints[1][2].fX = -0.7f; 
			pcGameCardT->vAniSelectionPoints[0][2].fY = pcGameCardT->vAniSelectionPoints[1][2].fY = 0.7f; 
			pcGameCardT->vAniSelectionPoints[0][3].fX = pcGameCardT->vAniSelectionPoints[1][3].fX = 0.0f; 
			pcGameCardT->vAniSelectionPoints[0][3].fY = pcGameCardT->vAniSelectionPoints[1][3].fY = -0.7f; 
			pcGameCardT->vAniSelectionPoints[0][4].fX = pcGameCardT->vAniSelectionPoints[1][4].fX = 0.7f; 
			pcGameCardT->vAniSelectionPoints[0][4].fY = pcGameCardT->vAniSelectionPoints[1][4].fY = -0.7f; 
			pcGameCardT->vAniSelectionPoints[0][5].fX = pcGameCardT->vAniSelectionPoints[1][5].fX = 0.7f; 
			pcGameCardT->vAniSelectionPoints[0][5].fY = pcGameCardT->vAniSelectionPoints[1][5].fY = 0.0f; 
			pcGameCardT->vAniSelectionPoints[0][6].fX = pcGameCardT->vAniSelectionPoints[1][6].fX = 0.7f; 
			pcGameCardT->vAniSelectionPoints[0][6].fY = pcGameCardT->vAniSelectionPoints[1][6].fY = 0.7f; 
			pcGameCardT->vAniSelectionPoints[0][7].fX = pcGameCardT->vAniSelectionPoints[1][7].fX = 0.0f; 
			pcGameCardT->vAniSelectionPoints[0][7].fY = pcGameCardT->vAniSelectionPoints[1][7].fY = 0.7f; 
 
			for(i3 = 0; i3 < 8; i3++) 
			{ 
				for(i2 = 0; i2 < 3; i2++) 
				{ 
					pcGameCardT->vAniSelectionPoints[LAST_POINT][i3].fV[i2] = pcGameCardT->vAniSelectionPoints[CURRENT_POINT][i3].fV[i2]; 
					 
					if(!(rand() % 2)) 
						pcGameCardT->vAniSelectionPoints[NEW_POINT][i3].fV[i2] = pcGameCardT->vAniSelectionPoints[FIX_POINT][i3].fV[i2]+(rand() % 1000)/10000; 
					else 
						pcGameCardT->vAniSelectionPoints[NEW_POINT][i3].fV[i2] = pcGameCardT->vAniSelectionPoints[FIX_POINT][i3].fV[i2]-(rand() % 1000)/10000; 
				} 
			} 
 
			// Updata min/max of the play field: 
			for(i2 = 0; i2 < 2; i2++) 
			{ 
				if(pcGameCardT->vWorldPos.fV[i2] < vPlayField[MIN].fV[i2]) 
					vPlayField[MIN].fV[i2] = pcGameCardT->vWorldPos.fV[i2]; 
				if(pcGameCardT->vWorldPos.fV[i2] > vPlayField[MAX].fV[i2]) 
					vPlayField[MAX].fV[i2] = pcGameCardT->vWorldPos.fV[i2]; 
			} 
		} 
	 
	vPlayField[MIN] -= 2.0f; 
	vPlayField[MAX] += 2.0f; 
 
	// Setup cards: 
	iCard = (INT2 *) malloc(sizeof(INT2)*cGameConfig.iCardPairs); 
	for(i = 0; i < cGameConfig.iCardPairs; i++) 
	{ 
		iCard[i][0] = -1; 
		iCard[i][1] = 2; 
	} 
	for(i = 0; i < cGameConfig.iCardPairs; i++) 
	{ 
		iCard[i][0] = rand() % pcCardStyle->iCards; 
		 
		// Check if another card has this number already: 
		for(i2 = 0; i2 < cGameConfig.iCardPairs; i2++) 
		{ 
			if(i != i2 && iCard[i][0] == iCard[i2][0]) 
				break; 
		} 
		if(i2 != cGameConfig.iCardPairs) 
		{ 
			i--; 
			continue; 
		} 
	} 
	 
	// Spread chosen cards: 
	for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
	{ 
		iTemp = rand() % cGameConfig.iCardPairs; 
		if(!iCard[iTemp][1]) 
		{ 
			i--; 
			continue; // Already awarded 
		} 
		iCard[iTemp][1]--; 
		pcGameCard[i].iCard = iCard[iTemp][0]; 
		cGameInfo.iError[i] = cGameConfig.iErrors; 
	} 
 
	free(iCard); 
 
	cGameInfo.iCardPairsOnTable = cGameConfig.iCardPairs; 
	g_lGameTimer = 0; 
	cGameInfo.iSelectedCard[0] = -1; 
	cGameInfo.iSelectedCard[1] = -1; 
	bGameFinished = FALSE; 
	fGameFinishedBlend = 0.0f; 
	fFlashBlend = 1.0f; 
	 
	// Clear the computer brains: 
	for(i = 0; i < 4; i++) 
		for(i2 = 0; i2 < MAX_CARD_PAIRS; i2++) 
			cGameInfo.sPlayerInfo[i].bComputerMemory[i2] = FALSE; 
	 
	if(cGameConfig.bShowCardsAtBeginning) 
	{ // Show the cards: 
		for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
			pcGameCard[i].fSelectionRotTime = pcGameCard[i].fSelectionRotSmoothTime = 1.0f; 
		cGameInfo.bShowCardsAtBeginng = TRUE; 
		cGameInfo.lShowCardsAtBeginningTime = g_lGameTimer; 
		cGameInfo.iShowCardsAtBeginningPastSeconds = 0; 
 
		// The computer player could hold some cards in their brain: 
		for(i = 0; i < 4; i++) 
		{ 
			// Get the number of cards the computer could remember on: 
			switch(cGameConfig.PlayerType[i]) 
			{ 
				case PLAYER_TYPE_COMPUTER_EASY: 
					// Get the number of cards the computer could remember on: 
					iRemeber = rand() % cGameConfig.iBeginningShowTime; 
				break; 
 
				case PLAYER_TYPE_COMPUTER_NORMAL: 
					iRemeber = 4+rand() % cGameConfig.iBeginningShowTime; 
				break; 
 
				case PLAYER_TYPE_COMPUTER_CLEVER: 
					iRemeber = 10+rand() % cGameConfig.iBeginningShowTime; 
				break; 
				 
				default: 
					continue; 
			} 
			for(i3 = 0, i2 = 0; i3 < iRemeber; i3++, i2++) 
			{ 
				if(i2 > 1000) 
					break; 
				iGetCard = rand() % (cGameConfig.iCardPairs*2); 
				if(cGameInfo.sPlayerInfo[i].bComputerMemory[iGetCard]) 
				{ 
					i3--; // Find another card! 
					continue; 
				} 
				cGameInfo.sPlayerInfo[i].bComputerMemory[iGetCard] = TRUE; 
				cGameInfo.sPlayerInfo[i].lComputerSeeTime[iGetCard] = g_lGameTimer; 
			} 
		} 
	} 
	cGameInfo.lThinkTime = g_lGameTimer; 
	cGameInfo.iThinkTimePastSeconds = 0; 
} // InitGameCards() 
 
void DestroyGameCards(void) 
{ // begin DestroyGameCards() 
	SAFE_DELETE(pcGameCard); 
} // end DestroyGameCards() 
 
void DrawGameCards(void) 
{ // begin DrawGameCards() 
	int i; 
 
	glEnable(GL_CULL_FACE); 
	 
	// Setup render stuff: 
	glEnableClientState(GL_VERTEX_ARRAY); 
	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
	glVertexPointer(3, GL_FLOAT, 0, fCardVertices); 
	glTexCoordPointer(2, GL_FLOAT, 0, fCardTexCoords); 
	glDisable(GL_BLEND); 
	if(_AS->bCompiledVertexArraySupported) 
		glLockArraysEXT(0, 8); 
	 
	// Draw only none transparent cards: 
	for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
	{ 
		if(!pcGameCard[i].bActive) 
			continue; 
		pcGameCard[i].Draw(false); 
	} 
 
	// Draw only transparent cards: (if they going death) 
	for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
	{ 
		if(!pcGameCard[i].bActive) 
			continue; 
		pcGameCard[i].Draw(true); 
	} 
	if(_AS->bCompiledVertexArraySupported) 
		glUnlockArraysEXT(); 
	glDisableClientState(GL_VERTEX_ARRAY); 
	glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
} // end DrawGameCards() 
 
void PerformLightMapOnGameCarts(void) 
{ // begin PerformLightMapOnGameCarts() 
	AS_DLIGHT cLight1; 
 
	if(!_ASConfig->bLightmaps || cGameConfig.PlayerType[cGameInfo.iCurrentPlayer] != PLAYER_TYPE_HUMAN) 
		return; 
 
	glEnable(GL_TEXTURE_2D); 
	glEnable(GL_BLEND); 
	glBindTexture(GL_TEXTURE_2D, GameTexture[1].iOpenGLID); 
	glDepthMask(FALSE); 
	glDisable(GL_LIGHTING); 
 
	cLight1.fRadius = 3.0f; 
	cLight1.vPos = vMouseWorldPos; 
	cLight1.vColor = 0.5f; 
	glBegin(GL_TRIANGLES); 
		for(int i = 0; i < cGameConfig.iCardPairs*2; i++) 
		{ 
			if(!pcGameCard[i].bActive) 
				continue; 
			pcGameCard[i].PerformLighmap(cLight1); 
		} 
	glEnd(); 
	glDepthMask(TRUE); 
} // end PerformLightMapOnGameCarts() 
 
void CheckGameCards(void) 
{ // begin CheckGameCards() 
	int i, i2, iCard, iTime; 
	cGAME_CARD *pcGameCardT; 
	sPLAYER_INFO *psPlayerT; 
 
	if(cGameInfo.bShowCardsAtBeginng) 
		return; 
 
	// Check if the game is finished: 
	if(cGameInfo.iCardPairsOnTable <= 0 && cGameInfo.iSelectedCard[0] == -1 && 
	   cGameInfo.iSelectedCard[1] == -1) 
	{ 
		if(cGameConfig.bTimeLimit && cGameInfo.iTimeLimitPastSeconds < cGameConfig.iTimeLimit) 
		{ 
			for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
				if(pcGameCard[i].bActive) 
					break; 
		} 
		else 
			i = cGameConfig.iCardPairs*2; 
		if(i == cGameConfig.iCardPairs*2) 
		{ // All cards are deactivated: 
			cGameInfo.iCurrentRound++;	 
			if(cGameInfo.iCurrentRound >= cGameConfig.iRounds ||  
			   (cGameConfig.bTimeLimit && cGameInfo.iTimeLimitPastSeconds > cGameConfig.iTimeLimit)) 
			{ // The game is now finished: 
				bGameFinished = TRUE; 
 
				return; 
			} 
			else 
			{ // Go into the next round: 
				bFlashBlend = TRUE; 
				if(fFlashBlend >= 1.0f) 
					InitGameCards(); 
				else 
					return; 
			} 
		} 
	} 
 
	// Reset all cards: 
	for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
		pcGameCard[i].bUnderMouse = FALSE; 
 
	// Select the card under the mouse: 
	for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
	{ 
		pcGameCardT = &pcGameCard[i]; 
		if(!pcGameCardT->bActive) 
			continue; 
		if(vMouseWorldPos.fX > pcGameCardT->vWorldPos.fX-0.5f && 
		   vMouseWorldPos.fX < pcGameCardT->vWorldPos.fX+0.5f && 
		   vMouseWorldPos.fY > pcGameCardT->vWorldPos.fY-0.5f && 
		   vMouseWorldPos.fY < pcGameCardT->vWorldPos.fY+0.5f && 
		   cGameConfig.PlayerType[cGameInfo.iCurrentPlayer] == PLAYER_TYPE_HUMAN) 
			pcGameCardT->bUnderMouse = TRUE; 
		if(pcGameCardT->bSelected) 
		{ 
			pcGameCardT->fSelectionColor[R] += (float) g_lDeltatime/300; 
			if(pcGameCardT->fSelectionColor[R] > 1.0f) 
				pcGameCardT->fSelectionColor[R] = 1.0f; 
			pcGameCardT->fSelectionColor[G] -= (float) g_lDeltatime/300; 
			if(pcGameCardT->fSelectionColor[G] < 0.4f) 
				pcGameCardT->fSelectionColor[G] = 0.4f; 
			pcGameCardT->fSelectionColor[B] -= (float) g_lDeltatime/300; 
			if(pcGameCardT->fSelectionColor[B] < 0.4f) 
				pcGameCardT->fSelectionColor[B] = 0.4f; 
			pcGameCardT->fSelectionColor[A] += (float) g_lDeltatime/300; 
			if(pcGameCardT->fSelectionColor[A] > 0.8f) 
				pcGameCardT->fSelectionColor[A] = 0.8f; 
			if(!pcGameCardT->fSelectionRotTime) 
			{ 
				ASPlayFmodSample(pClickOnCardSample, FSOUND_LOOP_OFF); 
				ASPlayFmodSample(pRotateCardSample, FSOUND_LOOP_OFF); 
				ShowSmallMessage(pcCardStyle->sCard[pcGameCardT->iCard].byName, 2000); 
				ASPlayFmodSample(&pcCardStyle->sCard[pcGameCardT->iCard].Sound, FSOUND_LOOP_OFF); 
			} 
			pcGameCardT->fSelectionRotTime += (float) g_lDeltatime/1000; 
			if(pcGameCardT->fSelectionRotTime > 1.0f) 
				pcGameCardT->fSelectionRotTime = 1.0f; 
		} 
		else 
		{ 
			if(pcGameCardT->fSelectionRotTime == 1.0f) 
				ASPlayFmodSample(pRotateCardSample, FSOUND_LOOP_OFF); 
			pcGameCardT->fSelectionRotTime -= (float) g_lDeltatime/1000; 
			if(pcGameCardT->fSelectionRotTime < 0.0f) 
				pcGameCardT->fSelectionRotTime = 0.0f; 
			if(pcGameCardT->bUnderMouse && !pcGameCardT->bGoingDeath) 
			{ 
				pcGameCardT->fSelectionColor[R] -= (float) g_lDeltatime/300; 
				if(pcGameCardT->fSelectionColor[R] < 0.2f) 
					pcGameCardT->fSelectionColor[R] = 0.2f; 
				pcGameCardT->fSelectionColor[G] += (float) g_lDeltatime/300; 
				if(pcGameCardT->fSelectionColor[G] > 1.0f) 
					pcGameCardT->fSelectionColor[G] = 1.0f; 
				pcGameCardT->fSelectionColor[B] -= (float) g_lDeltatime/300; 
				if(pcGameCardT->fSelectionColor[B] < 0.2f) 
					pcGameCardT->fSelectionColor[B] = 0.2f; 
				pcGameCardT->fSelectionColor[A] += (float) g_lDeltatime/300; 
				if(pcGameCardT->fSelectionColor[A] > 0.8f) 
					pcGameCardT->fSelectionColor[A] = 0.8f; 
			} 
			else 
			{ 
				for(i2 = 0; i2 < 4; i2++) 
				{ 
					pcGameCardT->fSelectionColor[i2] -= (float) g_lDeltatime/300; 
					if(pcGameCardT->fSelectionColor[i2] < 0.0f) 
						pcGameCardT->fSelectionColor[i2] = 0.0f; 
				} 
			} 
		} 
		 
		pcGameCardT->fSelectionRotSmoothTime = (float) (0.5f-0.5f*cos(sin(pcGameCardT->fSelectionRotTime*PId2)*PI)); 
 
		pcGameCardT->Check(); 
	} 
 
	if(cGameConfig.PlayerType[cGameInfo.iCurrentPlayer] == PLAYER_TYPE_HUMAN) 
	{ // Check if the player selects an game card: 
		if(CHECK_KEY(ASMouse.byButtons, 0)) 
		{ 
			for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
			{ 
				pcGameCardT = &pcGameCard[i]; 
				if(!pcGameCardT->bActive || !pcGameCardT->bUnderMouse || 
				   pcGameCardT->fSelectionRotSmoothTime != 0.0f) 
					continue; 
				pcGameCardT->bUnderMouse = FALSE; 
				if(cGameInfo.iSelectedCard[0] == -1) 
				{ // First card: 
					cGameInfo.iSelectedCard[0] = i; 
					pcGameCardT->bSelected = TRUE; 
					break; 
				} 
				else 
				{ // Second card: 
					if(cGameInfo.iSelectedCard[1] != -1 || cGameInfo.iSelectedCard[0] == i || 
					   pcGameCard[cGameInfo.iSelectedCard[0]].fSelectionRotSmoothTime != 1.0f) 
						continue; // This card is already selected! 
					cGameInfo.iSelectedCard[1] = i; 
					pcGameCardT->bSelected = TRUE; 
					break; 
				} 
			} 
		} 
	} 
	else 
	{ // Ok, the computer makes now an selection: 
		psPlayerT = &cGameInfo.sPlayerInfo[cGameInfo.iCurrentPlayer]; 
		if((cGameInfo.iSelectedCard[0] == -1 || cGameInfo.iSelectedCard[1] == -1) && 
		   (cGameInfo.iSelectedCard[0] == -1 || (cGameInfo.iSelectedCard[0] != -1 && 
		   pcGameCard[cGameInfo.iSelectedCard[0]].fSelectionRotSmoothTime >= 1.0f))) 
		{ // Select now the cards: 
			// Is it time to choose? 
			if(g_lGameTimer >= psPlayerT->lNextSelectionTime) 
			{ 
				SetNextComputerSelectionTime(); 
 
				// Does the computer knows an pair? 
				for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
				{ 
					if(!psPlayerT->bComputerMemory[i] || 
					   pcGameCard[i].bGoingDeath) 
						continue; 
					for(i2 = 0; i2 < cGameConfig.iCardPairs*2; i2++) 
					{ 
						if(i == i2 || !psPlayerT->bComputerMemory[i2] || 
						   pcGameCard[i2].bGoingDeath) 
							continue; 
						if(pcGameCard[i].iCard == pcGameCard[i2].iCard) 
						{ // Wow, he knows an pair, get it: 
							if(cGameInfo.iSelectedCard[0] == -1) 
							{ // Get the fist card: 
								cGameInfo.iSelectedCard[0] = i; 
								pcGameCard[i].bSelected = TRUE; 
							} 
							else 
							{ // Get the second card: 
								if(cGameInfo.iSelectedCard[0] == i2) 
								{ 
									cGameInfo.iSelectedCard[1] = i; 
									pcGameCard[i].bSelected = TRUE; 
								} 
								else 
								{ 
									cGameInfo.iSelectedCard[1] = i2; 
									pcGameCard[i2].bSelected = TRUE; 
								} 
							} 
							i = i2 = cGameConfig.iCardPairs*2; 
						} 
					} 
				} 
 
				// Ok, at the moment he knows no pair so get an card by random: 
				if(cGameInfo.iSelectedCard[0] == -1 && cGameInfo.iSelectedCard[1] == -1) 
				{ 
					for(i = 0; i < 1000; i++) 
					{ 
						iCard = rand() % (cGameConfig.iCardPairs*2); 
						if(!pcGameCard[iCard].bActive || psPlayerT->bComputerMemory[iCard]) 
							continue; // The player know this card already! 
						psPlayerT->bComputerMemory[iCard] = TRUE; 
						cGameInfo.iSelectedCard[0] = iCard; 
						pcGameCard[iCard].bSelected = TRUE; 
						break; 
					} 
					if(i == 1000) 
					{ 
						for(i = 0; i < 1000; i++) 
						{ 
							iCard = rand() % (cGameConfig.iCardPairs*2); 
							if(!pcGameCard[iCard].bActive) 
								continue; 
							cGameInfo.iSelectedCard[0] = iCard; 
							pcGameCard[iCard].bSelected = TRUE; 
							break; 
						} 
					} 
				} 
				else 
				{ 
					if(cGameInfo.iSelectedCard[0] != -1 && pcGameCard[cGameInfo.iSelectedCard[0]].fSelectionRotSmoothTime >= 1.0f && 
					   cGameInfo.iSelectedCard[1] == -1) 
					{ 
						for(i = 0; i < 1000; i++) 
						{ 
							iCard = rand() % (cGameConfig.iCardPairs*2); 
							if(iCard == 17) 
								iCard = iCard; 
							if(!pcGameCard[iCard].bActive || psPlayerT->bComputerMemory[iCard]) 
								continue; // The player know this card already! 
							psPlayerT->bComputerMemory[iCard] = TRUE; 
							cGameInfo.iSelectedCard[1] = iCard; 
							pcGameCard[iCard].bSelected = TRUE; 
							break; 
						} 
						if(i == 1000) 
						{ 
							for(i = 0; i < 1000; i++) 
							{ 
								iCard = rand() % (cGameConfig.iCardPairs*2); 
								if(!pcGameCard[iCard].bActive || cGameInfo.iSelectedCard[0] == iCard) 
									continue; 
								cGameInfo.iSelectedCard[1] = iCard; 
								pcGameCard[iCard].bSelected = TRUE; 
								break; 
							} 
						} 
					} 
				} 
			} 
		} 
	} 
 
	// Check the selected carts: 
	if(cGameInfo.iSelectedCard[0] != -1 && 
	   cGameInfo.iSelectedCard[1] != -1 && 
	   pcGameCard[cGameInfo.iSelectedCard[0]].fSelectionRotSmoothTime == 1.0f && 
	   pcGameCard[cGameInfo.iSelectedCard[1]].fSelectionRotSmoothTime == 1.0f) 
	{ // Two cards are selected and opened: 
		// The other computer player have a look at the cards, too: 
		for(i = 0; i < 4; i++) 
		{ 
			for(i2 = 0; i2 < 2; i2++) 
			{ 
				switch(cGameConfig.PlayerType[i]) 
				{ 
					case PLAYER_TYPE_COMPUTER_EASY: 
						if(!(rand() % 2)) 
							break; 
						cGameInfo.sPlayerInfo[i].bComputerMemory[cGameInfo.iSelectedCard[i2]] = TRUE; 
						cGameInfo.sPlayerInfo[i].lComputerSeeTime[cGameInfo.iSelectedCard[i2]] = g_lGameTimer; 
					break; 
 
					case PLAYER_TYPE_COMPUTER_NORMAL: case PLAYER_TYPE_COMPUTER_CLEVER: 
						cGameInfo.sPlayerInfo[i].bComputerMemory[cGameInfo.iSelectedCard[i2]] = TRUE; 
						cGameInfo.sPlayerInfo[i].lComputerSeeTime[cGameInfo.iSelectedCard[i2]] = g_lGameTimer; 
					break; 
 
					default: 
						continue; 
				} 
			} 
		} 
		 
		// Sometimes the computer forgets something: 
		for(i = 0; i < 4; i++) 
		{ 
			switch(cGameConfig.PlayerType[i]) 
			{ 
				case PLAYER_TYPE_COMPUTER_EASY: 
					for(i2 = 0; i2 < cGameConfig.iCardPairs*2; i2++) 
					{ 
						iTime = (int) ((5+g_lGameTimer-cGameInfo.sPlayerInfo[i].lComputerSeeTime[i2])/1000); 
						if(iTime < 0) 
							iTime = 0; 
						if(!(rand() % (1+iTime))) 
							cGameInfo.sPlayerInfo[i].bComputerMemory[i2] = FALSE; 
					} 
				break; 
 
				case PLAYER_TYPE_COMPUTER_NORMAL: 
					for(i2 = 0; i2 < cGameConfig.iCardPairs*2; i2++) 
					{ 
						iTime = (int) ((10+g_lGameTimer-cGameInfo.sPlayerInfo[i].lComputerSeeTime[i2])/1000); 
						if(iTime < 0) 
							iTime = 0; 
						if(!(rand() % (6+iTime))) 
							cGameInfo.sPlayerInfo[i].bComputerMemory[i2] = FALSE; 
					} 
				break; 
 
				case PLAYER_TYPE_COMPUTER_CLEVER: 
					for(i2 = 0; i2 < cGameConfig.iCardPairs*2; i2++) 
					{ 
						iTime = (int) ((15+g_lGameTimer-cGameInfo.sPlayerInfo[i].lComputerSeeTime[i2])/1000); 
						if(iTime < 0) 
							iTime = 0; 
						if(!(rand() % (12+iTime))) 
							cGameInfo.sPlayerInfo[i].bComputerMemory[i2] = FALSE; 
					} 
				break; 
 
				default: 
					continue; 
			} 
		} 
 
		// Does the player has found an card pair?? 
		if(pcGameCard[cGameInfo.iSelectedCard[0]].iCard == 
		   pcGameCard[cGameInfo.iSelectedCard[1]].iCard) 
		{ // Yep, he found a card pair! 
			ASPlayFmodSample(pPairFoundSample, FSOUND_LOOP_OFF); 
			pcGameCard[cGameInfo.iSelectedCard[0]].bGoingDeath = TRUE; 
			pcGameCard[cGameInfo.iSelectedCard[1]].bGoingDeath = TRUE; 
			 
			// Add this card pair to the players score: 
			cGameInfo.sPlayerInfo[cGameInfo.iCurrentPlayer].iCardPairs++; 
 
			cGameInfo.iCardPairsOnTable--; 
		} 
		else 
		{ // Nope, he doesn't found a card pair! 
			ASPlayFmodSample(pNoPairFoundSample, FSOUND_LOOP_OFF); 
			if(cGameConfig.bErrorLimit) 
			{ 
				for(i = 0; i < 2; i++) 
				{ 
					cGameInfo.iError[cGameInfo.iSelectedCard[i]]--; 
					if(cGameInfo.iError[cGameInfo.iSelectedCard[i]] <= 0) 
					{ // Delete this card pair: 
						for(i2 = 0; i2 < cGameConfig.iCardPairs*2; i2++) 
						{ 
							if(pcGameCard[i2].iCard == pcGameCard[cGameInfo.iSelectedCard[i]].iCard) 
							{ 
								pcGameCard[i2].bSelected = TRUE; 
								pcGameCard[i2].bGoingDeath = TRUE; 
								if(i != cGameInfo.iSelectedCard[i]) 
									pcGameCard[i2].fSelectionRotSmoothTime = 0.1f; 
							} 
						} 
						cGameInfo.iCardPairsOnTable--; 
					} 
				} 
			} 
			 
			// Next player: 
			cGameInfo.iCurrentPlayer++; 
			if(cGameInfo.iCurrentPlayer >= cGameConfig.iPlayers) 
				cGameInfo.iCurrentPlayer = 0; 
			SetNextComputerSelectionTime(); 
		} 
		cGameInfo.lThinkTime = g_lGameTimer; 
		cGameInfo.iThinkTimePastSeconds = 0; 
		pcGameCard[cGameInfo.iSelectedCard[0]].bSelected =  
		pcGameCard[cGameInfo.iSelectedCard[1]].bSelected = FALSE; 
	} 
 
	// Check selected cards: 
	for(i = 0; i < 2; i++) 
	{ 
		if(cGameInfo.iSelectedCard[i] == -1) 
			continue; 
		if(pcGameCard[cGameInfo.iSelectedCard[i]].bGoingDeath &&  
		   pcGameCard[cGameInfo.iSelectedCard[i]].fSelectionRotSmoothTime <= 0.0f) 
			cGameInfo.iSelectedCard[i] = -1; 
		else 
			if(!pcGameCard[cGameInfo.iSelectedCard[i]].bSelected && 
			   !pcGameCard[cGameInfo.iSelectedCard[i]].fSelectionRotSmoothTime) 
			{ 
				cGameInfo.iSelectedCard[0] = -1; 
				cGameInfo.iSelectedCard[1] = -1; 
				break; 
			} 
	} 
 
	// Check if an card is going death: 
	for(i = 0; i < cGameConfig.iCardPairs*2; i++) 
	{ 
		pcGameCardT = &pcGameCard[i]; 
		if(!pcGameCardT->bActive || !pcGameCardT->bGoingDeath) 
			continue; 
		if(pcGameCardT->fSelectionRotSmoothTime >= 1.0f) 
			pcGameCardT->bSelected = FALSE; 
		if(pcGameCardT->fSelectionRotSmoothTime <= 0.0f) 
			pcGameCardT->bActive = FALSE; 
	} 
} // end CheckGameCards() 
 
void DrawTableBackground(void) 
{ // begin DrawTableBackground() 
	// Draw the table background: 
	glEnable(GL_TEXTURE_2D); 
	glEnable(GL_BLEND); 
	glColor3f(1.0f, 1.0f, 1.0f); 
	glBindTexture(GL_TEXTURE_2D, pcCardStyle->sTexture[3].iOpenGLID); 
	glBegin(GL_QUADS); 
		glTexCoord2f(0.0f, 1.0f); 
		glVertex3f(vPlayField[MIN].fX-1.0f, vPlayField[MAX].fY+0.5f, 1.0f); 
		glTexCoord2f(1.0f, 1.0f); 
		glVertex3f(vPlayField[MAX].fX+1.0f, vPlayField[MAX].fY+0.5f, 1.0f); 
		glTexCoord2f(1.0f, 0.0f); 
		glVertex3f(vPlayField[MAX].fX+1.0f, vPlayField[MIN].fY-0.5f, 1.0f); 
		glTexCoord2f(0.0f, 0.0f); 
		glVertex3f(vPlayField[MIN].fX-1.0f, vPlayField[MIN].fY-0.5f, 1.0f); 
	glEnd(); 
 
	return; 
	// Perform the lightmap on it: 
	if(!_ASConfig->bLightmaps || cGameConfig.PlayerType[cGameInfo.iCurrentPlayer] != PLAYER_TYPE_HUMAN) 
		return; 
 
	AS_3D_VECTOR vField[4]; 
	AS_DLIGHT cLight1; 
 
	glEnable(GL_TEXTURE_2D); 
	glEnable(GL_BLEND); 
	glBindTexture(GL_TEXTURE_2D, GameTexture[1].iOpenGLID); 
	glDepthMask(FALSE); 
	glDisable(GL_LIGHTING); 
 
	cLight1.fRadius = 5.0f; 
	cLight1.vPos = vMouseWorldPos; 
	cLight1.vColor = 0.5f; 
	 
	vField[0].fX = vPlayField[MIN].fX-1.0f; 
	vField[0].fY = vPlayField[MIN].fY-0.5f; 
	vField[0].fZ = 1.0f; 
	vField[1].fX = vPlayField[MAX].fX+1.0f; 
	vField[1].fY = vPlayField[MIN].fY-0.5f; 
	vField[1].fZ = 1.0f; 
	vField[2].fX = vPlayField[MAX].fX+1.0f; 
	vField[2].fY = vPlayField[MAX].fY+0.5f; 
	vField[2].fZ = 1.0f; 
	vField[3].fX = vPlayField[MIN].fX-1.0f; 
	vField[3].fY = vPlayField[MAX].fY+0.5f; 
	vField[3].fZ = 1.0f; 
 
	glBegin(GL_TRIANGLES); 
		cLight1.Light(vField[2], vField[1], vField[0]); 
		cLight1.Light(vField[3], vField[2], vField[0]); 
	glEnd(); 
	 
	glDepthMask(TRUE); 
	glDisable(GL_BLEND); 
} // end DrawTableBackground() 
 
void SetNextComputerSelectionTime(void) 
{ // begin SetNextComputerSelectionTime() 
	switch(cGameConfig.PlayerType[cGameInfo.iCurrentPlayer]) 
	{ 
		case PLAYER_TYPE_COMPUTER_EASY: 
			cGameInfo.sPlayerInfo[cGameInfo.iCurrentPlayer].lNextSelectionTime = g_lGameTimer+1000+(rand() % 3000); 
		break; 
 
		case PLAYER_TYPE_COMPUTER_NORMAL: 
			cGameInfo.sPlayerInfo[cGameInfo.iCurrentPlayer].lNextSelectionTime = g_lGameTimer+1000+(rand() % 1500); 
		break; 
 
		case PLAYER_TYPE_COMPUTER_CLEVER: 
			cGameInfo.sPlayerInfo[cGameInfo.iCurrentPlayer].lNextSelectionTime = g_lGameTimer+1000+(rand() % 700); 
		break; 
	} 
} // end SetNextComputerSelectionTime()