www.pudn.com > Tetris.rar > CEngine.cpp


#include  
#include  
#include  
#include  
#include   
#include  
 
#include "CEngine.h" 
#include "CGameTimer.h" 
#include "CSplash.h" 
#include "CMenu.h" 
#include "CGameTetris.h" 
#include "TetrisAppUi.h" 
#include  
#include "Tetris.hrh" 
#include "TScore.h" 
// sound 
#include "CWaveLoader.h" 
#include "CSoundMixer.h" 
 
 
_LIT(KFileStore,"save.dat"); 
// construct and destruct 
 
// NewL() 
CEngine* CEngine::NewL( CGameTetris* aGame, CWindowGc& aGc, RWindow& aWindow, TDisplayMode aDisplayMode ) 
{ 
	CEngine* self = new( ELeave )CEngine(aGame, aGc, aWindow, aDisplayMode ); 
	CleanupStack::PushL( self ); 
	self->ConstructL(); 
	CleanupStack::Pop( self ); 
	return self; 
} 
 
// ~ 
CEngine::~CEngine() 
{ 
	if(iTimer) 
	{ 
		iTimer->Cancel(); 
		delete iTimer; 
	} 
 
	delete iBackBufferGc; 
	delete iBackBufferDevice; 
	delete iBackBufferBitmap;  
	delete iMenu; 
	delete iBitmapUtil; 
 
	delete iScoreTable; 
 
	// sound 
	delete iSound; 
	delete iSoundBg.iData; 
	delete iSoundGameOver.iData; 
	delete iSoundOnClick.iData; 
	delete iSoundMenu.iData; 
	delete iSoundClearRow.iData; 
	delete iSoundWellDone.iData; 
	delete iSoundLevelUp.iData; 
} 
 
// ConstructL() 
void CEngine::ConstructL() 
{ 
	// get the draw region 
	TPoint pos = iWindow.Position(); 
	TSize size = iWindow.Size(); 
	iDrawRect.SetRect(pos, size); 
 
	// Create a new bitmap with size of viewĄŻs rect and color depth of 
	// screen 
	iBackBufferBitmap = new(ELeave) CFbsBitmap(); 
	User::LeaveIfError(iBackBufferBitmap->Create(iDrawRect.Size(), iDisplayMode)); 
	 
	// Create bitmap device for the bitmap 
	iBackBufferDevice = CFbsBitmapDevice::NewL(iBackBufferBitmap); 
	 
	// Create graphics context for the bitmap 
	User::LeaveIfError(iBackBufferDevice->CreateContext(iBackBufferGc)); 
 
	iBitmapUtil = new(ELeave)TBitmapUtil(iBackBufferBitmap); 
	// Create a menu 
	iMenu = CMenu::NewL(iBackBufferGc); 
 
	iTimer = CGameTimer::NewL(*this); 
	iPause = ETrue; 
 
	// Load sound 
	CWavLoader* wavLoader = CWavLoader::NewLC(); 
 
	iSoundBg		= wavLoader->LoadL(_L("bg.wav")); 
	iSoundGameOver	= wavLoader->LoadL(_L("gameover.wav")); 
	iSoundOnClick	= wavLoader->LoadL(_L("click.wav")); 
	iSoundMenu		= wavLoader->LoadL(_L("menu.wav")); 
	iSoundClearRow	= wavLoader->LoadL(_L("cleanrow.wav")); 
	iSoundLevelUp	= wavLoader->LoadL(_L("levelup.wav")); 
	iSoundWellDone	= wavLoader->LoadL(_L("welldone.wav")); 
 
	CleanupStack::PopAndDestroy( wavLoader ); 
 
	// create sound mixer 
	iSound = CSoundMixer::NewL(); 
 
	// make iSoundBg repeat itself 
	iSoundBg.iRepEnd = iSoundBg.iLength; 
 
	//iSound->Play(iSoundBg, 0, 16000, 256); 
	 
	 
	// create score table 
	iScoreTable = new (ELeave) CArrayFixSeg(1); 
	ScoreLoadL(); 
 
	iGameState = ENewSplash; 
	//iGameState = EMenu; 
} 
 
// CEngine() 
CEngine::CEngine( CGameTetris* aGame, CWindowGc& aGc, RWindow& aWindow, TDisplayMode aDisplayMode ) 
			: iGame(aGame) 
			, iGc( aGc ) 
			, iWindow( aWindow ) 
			, iDisplayMode( aDisplayMode ) 
{} 
 
/////////////////////////////////////////////////////////////////////////////////// 
// Other Method  
 
// DoGameFrameL() 
TInt CEngine::DoGameFrameL() 
{ 
	// Prepare to Splash 
	if(iGameState == ENewSplash) 
	{ 
		if(!ShowSplash()) 
			iGameState = EMenu; 
	} 
 
	if(iGameState == EExit) 
	{ 
		if(!ShowSplash()) 
		{ 
			CTetrisAppUi* appUi = static_cast (CEikonEnv::Static()->AppUi()); 
			appUi->Quit(); 
			//User::Exit(0);	// this cann't check memory leak ,why create it ,i'm confused! 
		} 
	} 
 
	// Prepare for showing the menu, used for state changing. 
	if(iGameState == EMenu) 
	{ 
		// Stop bg music 
		iSound->Stop(0); 
		// set Menu running frequency 
		iTimer->SetTickTime(40000); 
		iGameState = EMenuRunning; 
	} 
 
	// Menu running 
	if(iGameState == EMenuRunning) 
	{	 
		// show main menu 
		TInt32 signal = iMenu->Command(iKey); 
 
		switch(signal) 
		{ 
			case 1 :	// quit 
			{ 
				iGameState = EExit; 
			}break; 
			case 2 :	// Start new game 
			{ 
				if(!iMusicOff) 
					iSound->Play(iSoundBg, 0, 16000, 64); 
				iGameState = ERunning; 
				iGame->iStateRunning = 0; 
				iTimer->SetTickTime(50000); 
			}break; 
			case 3 :	// continue game 
			{ 
				if(!iMusicOff) 
					iSound->Play(iSoundBg, 0, 16000, 64); 
				if(!iGame->iStateRunning) 
					return 1; 
				iGameState = ERunning; 
				iTimer->SetTickTime(50000); 
			}break; 
			case 4: 
			{ 
				iDisplayTop5 = 1; 
			}break; 
			case 5: 
			{ 
				iDisplayTop5 = 0; 
			}break; 
			case 11 :	// Set brick rotation 
			{ 
				if(iMenu->iSetting[0] == 0) 
 					iGame->iStateRotateDir = -1; 
				else 
					iGame->iStateRotateDir = 1; 
			}break; 
			case 12 :	// Set Sound 
			{ 
				if(iMenu->iSetting[1] == 2)		// set sound effect 
					iSoundEffectOff = 0; 
				else 
					iSoundEffectOff = 1; 
				if(iMenu->iSetting[2] == 4)		// set background music 
					iMusicOff = 0; 
				else 
					iMusicOff = 1; 
				iSound->SetVolume( (iMenu->iSetting[3] - 5) * 256 / 4 ); 
			}break; 
			case 13 :	// Set Difficult 
			{ 
				// start lines, scratching 
				iGame->iStateStartLines = static_cast ((iMenu->iSetting[4] - 10) * 5); 
				// Difficulty 
				iGame->iStateDifficulty = static_cast (iMenu->iSetting[5] - 14);	 
			}break; 
 
 
			default: 
			{ 
				iGc.Activate( iWindow ); 
				iMenu->Draw(); 
				iGc.BitBlt(iDrawRect.iTl, iBackBufferBitmap); 
				if(iDisplayTop5) 
					ScoreDisplay(); 
				iGc.Deactivate(); 
			}break; 
		} 
		 
		iKey = 0; 
	} 
	 
	// game over 
	if(iGameState == EGameOver) 
	{ 
		// show Txt "game over" and some other effects 
		// check if it is a new high score 
		// if it is, then prompt to input user's name 
		// else goto main menu directly 
 
		iBitmapUtil->Begin(TPoint(0, 0));		// lock the heap 
 
		TUint16* addr = (TUint16*)iBackBufferBitmap->DataAddress(); 
 
		// width and height in pixel  
		TInt width = iBackBufferBitmap->SizeInPixels().iWidth; 
		TInt height = iBackBufferBitmap->SizeInPixels().iHeight; 
	 
		if(!iControl) 
			DipBlackwhite(addr, width, height); 
		if(++iControl > 15) 
			DipEffect(addr, width, height); 
		iBitmapUtil->End();						// unlock the heap 
		 
		if(iControl == 35) 
		{ 
			iControl = 0;	 
			 
			iGameState = EMenu; 
 
			ScoreAddL(); 
 
			return 1; 
		} 
 
		iGc.Activate( iWindow ); 
		iGc.BitBlt(TPoint(0, 0), iBackBufferBitmap); 
		 
		const CFont* font; 
		font = CEikonEnv::Static()->LegendFont(); 
		iGc.UseFont(font); 
		iGc.SetPenColor(KRgbRed); 
		iGc.DrawText(_L("Game Over"), TPoint(65, 100)); 
		 
		iGc.DiscardFont(); 
		iGc.Deactivate(); 
 
		iKey = 0; 
	} 
 
	// running 
	if(iGameState == ERunning) 
	{ 
		TInt8	state = iGame->Run(); 
 
		if(state == 1)	// game over 
		{ 
			if(!iSoundEffectOff) 
				iSound->Play(iSoundGameOver, 1, 16000, 64); 
			iGameState = EGameOver; 
			return 1; 
		} 
		// draw screen 
		if(iGame->Command(iKey) || state == 2) 
		{ 
			iGc.Activate( iWindow ); 
	 
			iGame->Draw(iBackBufferGc); 
 
			iGc.BitBlt(iDrawRect.iTl, iBackBufferBitmap); 
 
			iGc.Deactivate(); 
		} 
		iKey = 0; 
 
		// play sound effect 
		if(!iSoundEffectOff) 
		{ 
			// only play one sound effect ,there is a priority 
			if(iGame->iStateLevelUp) 
			{ 
				iSound->Play(iSoundLevelUp, 1, 16000, 64); 
				iGame->iStateLevelUp = 0; 
				//return 1; 
			} 
			if(iGame->iStateWellDone) 
			{ 
				iSound->Play(iSoundWellDone, 2, 16000, 64); 
				iGame->iStateWellDone = 0; 
			} 
			if(iGame->iStateClearRow) 
			{ 
				iSound->Play(iSoundClearRow, 3, 16000, 64); 
				iGame->iStateClearRow = 0; 
				//return 1; 
			} 
		}	 
	} 
 
	return ETrue; 
} 
 
 
// Start() 
void CEngine::Start() 
{ 
	if( !iPause )  
		return; 
	iPause = EFalse; 
	iTimer->Start(); 
	iSound->Resume(); 
} 
 
// Stop() 
void CEngine::Stop() 
{ 
	if( iPause )  
		return; 
	iPause = ETrue; 
	iTimer->Cancel(); 
	iSound->Pause(); 
} 
 
// Pause() 
void CEngine::Pause() 
{ 
	if(iPause) 
		Start(); 
	else 
		Stop(); 
} 
 
 
// Command() 
void CEngine::Command(TInt aCommand) 
{ 
	if(aCommand == 'q') 
	{ 
		if(iGameState == ERunning || iGameState == EMenuRunning)	 
			iGameState = EMenu;	 
		else 
			return; 
	} 
 
	if(aCommand == '0' && iGameState == ERunning) 
		Pause(); 
 
	iKey = aCommand; 
 
	if(iSoundEffectOff) 
		return; 
 
	if(iGameState == EMenuRunning) 
	{ 
		switch(iKey) 
		{ 
			case EStdKeyDevice5: 
			case '5': 
			case 63557: 
			{ 
				iSound->Play(iSoundOnClick, 2, 16000, 64); 
			}break; 
			 
			case EKeyUpArrow :								// UP 
			case '2' : 
			case EKeyDownArrow :							// Down 
			case '8' : 
			case EKeyLeftArrow :							// Left 
			case '4' : 
			case EKeyRightArrow :							// Right 
			case '6' : 
			{ 
				iSound->Play(iSoundMenu, 3, 16000, 64); 
			}break; 
 
			default: 
				break; 
		} 
	} 
} 
 
// ShowSplash() 
TBool CEngine::ShowSplash() 
{ 
	if(!iSplash) 
	{ 
		iSplash = CSplash::NewL(iGc, iWindow); 
 
		iTimer->SetTickTime(100000); 
	} 
	else if(!iSplash->Draw()) 
	{ 
		delete iSplash; 
		iSplash = NULL; 
		return 0;			// stop splashing 
	} 
	return 1;				// keep splashing 
} 
 
// DipEffect() 
void CEngine::DipEffect(TUint16* aAddr, TInt aWidthInPixel, TInt aHeightInPixel) 
{ 
	TInt i, j; 
	TUint16* index; 
 
	for(i = 0; i < aHeightInPixel; i++) 
	{ 
		index = aAddr + aWidthInPixel * i;		// get address of each row 
		for(j = 0; j < aWidthInPixel; j++) 
		{ 
			TInt8 r = static_cast (*index  & 0x00f); 
            TInt8 g = static_cast ((*index & 0x0f0) >> 4); 
            TInt8 b = static_cast ((*index & 0xf00) >> 8); 
 
			r--; 
			g--; 
			b--; 
			 
			(r < 0) ? *index  = 0     : *index  = r; 
            (g < 0) ? *index &= 0xf0f : *index |= g << 4; 
            (b < 0) ? *index &= 0x0ff : *index |= b << 8; 
 
			//(r > 0xf) ? *index  = 0xf   : *index  = r; 
            //(g > 0xf) ? *index |= 0x0f0 : *index |= g << 4; 
            //(b > 0xf) ? *index |= 0xf00 : *index |= b << 8; 
 
			index ++; 
		} 
	} 
} 
 
 
void CEngine::DipBlackwhite(TUint16* aAddr, TInt aWidthInPixel, TInt aHeightInPixel) 
{ 
	TInt i, j; 
	TUint16* index; 
	for(i = 0; i < aHeightInPixel; i++) 
	{ 
		index = aAddr + aWidthInPixel * i;		// get address of each row 
		for(j = 0; j < aWidthInPixel; j++) 
		{ 
			*index = *index > 0x800 ? 0xfff : 0; 
 
			index ++; 
		} 
	} 
} 
 
// method deal with score 
 
void CEngine::ScoreLoadL() 
{ 
	// in my opinion, this can only be used in real handset, not emulator 
	TFileName fileName( KFileStore ); 
	CompleteWithAppPath( fileName ); 
 
	if(!BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), fileName)) 
	{ 
		ScoreSaveL(); 
		return; 
	} 
	CFileStore* store = CDirectFileStore::OpenLC(CEikonEnv::Static()->FsSession(), fileName, EFileRead); 
 
	RStoreReadStream stream; 
	stream.OpenLC(*store,store->Root()); 
 
  
	TScore sc; 
	TInt i, count=stream.ReadInt32L(); 
 
	for(i = 0; i < count; i++) 
	{ 
		stream >> sc; 
		iScoreTable->AppendL(sc); 
	} 
 
	CleanupStack::PopAndDestroy(2);		// (store and stream) 
} 
 
 
void CEngine::ScoreAddL() 
{ 
	// first clear score table 
	ScoreReset(); 
	// load score 
	ScoreLoadL();	 
	 
	// check if the score is a new Top5 score 
 	if(iScoreTable->Count() == TopNum)	// not full 
		if(iGame->iStateScore <= -iScoreTable->At(TopNum - 1).iValue) 
			return; 
	 
	TBuf<15>	name; 
 
	CAknTextQueryDialog* dialog = CAknTextQueryDialog::NewL(name); 
	if(!dialog->ExecuteLD(R_INPUT_USERNAME_DIALOG)) 
		return; 
 
	// new score 
	TScore	newScore(iGame->iStateScore, name); 
    // Insert the element in the Score table (using an Integer key on iValue) 
    TKeyArrayFix byScore(_FOFF(TScore, iValue), ECmpTInt); 
    iScoreTable->InsertIsqAllowDuplicatesL(newScore, byScore); 
    
    // Remove the last player from the table if necessary and compress the table 
    if(iScoreTable->Count() > TopNum) 
        iScoreTable->Delete(TopNum); 
    iScoreTable->Compress(); 
 
	// save the score 
	ScoreSaveL(); 
} 
 
 
 
void CEngine::ScoreSaveL() 
{ 
	// in my opinion, this can only be used in real handset, not emulator 
	TFileName fileName( KFileStore ); 
	CompleteWithAppPath( fileName ); 
 
	CFileStore* store = CDirectFileStore::ReplaceLC(CEikonEnv::Static()->FsSession(), fileName, EFileWrite); 
 
	store->SetTypeL(KDirectFileStoreLayoutUid); 
 
	// Create the hi-score stream 
	RStoreWriteStream stream; 
	TStreamId id = stream.CreateLC(*store); 
 
	// Write the number of score table entries in the store 
	TInt count= iScoreTable->Count(); 
	stream.WriteInt32L(count); 
 
	// Then write each entry 
	for(TInt i = 0; i < count; i++) 
	{ 
		stream << iScoreTable->At(i); 
	} 
 
	// Commit the changes to the stream 
	stream.CommitL(); 
	CleanupStack::PopAndDestroy(); 
 
	// Set the stream in the store and commit the store 
	store->SetRootL(id); 
	store->CommitL(); 
	CleanupStack::PopAndDestroy(); 
} 
 
void CEngine::ScoreDisplay() 
{ 
	// note this don't has iGc.Activate( iWindow ); & iGc.Deactivate(); 
	//iGc.Activate( iWindow ); 
	const CFont* font; 
	font = CEikonEnv::Static()->TitleFont(); 
	iGc.UseFont(font); 
	iGc.SetPenColor(KRgbWhite); 
	iGc.DrawText(_L("Top 5"), TPoint(75, 30)); 
 
	for(TInt i = 0; i < iScoreTable->Count(); i++) 
	{ 
		iGc.DrawText(iScoreTable->At(i).iName, TPoint(30, 60 + 30*i)); 
		TBuf16<10> score; 
		score.Num(-iScoreTable->At(i).iValue); 
		iGc.DrawText(score, TPoint(130, 60 + 30*i)); 
	} 
		 
	iGc.DiscardFont(); 
	//iGc.Deactivate(); 
} 
 
void CEngine::ScoreReset() 
{ 
	iScoreTable->Delete(0, iScoreTable->Count()); 
}