/***********************************************************************
 * maingame.C
 *  
 *    Main Game
 *
 *
 * Toby Opferman Copyright (c) 2003
 *
 ***********************************************************************/
 
 
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <taudio.h>
#include <gdi.h>
#include <gif.h>
#include <leveleng.h>
#include <progress.h>
#include "game.h"
#include "gameres.h"
#include "gameinternal.h"
#include "levelone.h"



 /***********************************************************************
  * Prototypes
  ***********************************************************************/
void Game_InitializeWorkerThread(HPROGRESS hProgress, PVOID pContext);
void Game_Debug(char *pszFormatString, ...);
void GameTitle_HandleMenuCommands(PGAME_INTERNAL pGameInternal, USHORT Command, LPARAM lParam);
void GameTitle_ToggleMusic(PGAME_INTERNAL pGameInternal);
void GameTitle_ToggleSound(PGAME_INTERNAL pGameInternal);
void GameTitle_LoadLevelOne(PGAME_INTERNAL pGameInternal);
void GameTitle_Shutdown(PGAME_INTERNAL pGameInternal);

 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
HGAME Game_Init(HWND hWnd, HINSTANCE hInstance)
{
	PGAME_INTERNAL pGameInternal = NULL;
	HDC hScreen;
	HDC hTitle;

	pGameInternal = (PGAME_INTERNAL)LocalAlloc(LMEM_ZEROINIT, sizeof(GAME_INTERNAL));

	srand((int)time(NULL));

	if(pGameInternal)
	{
	    pGameInternal->GameOptions.EnableMusic        = TRUE;
     	pGameInternal->GameOptions.EnableSoundEffects = TRUE;
		pGameInternal->hWnd      = hWnd;
		pGameInternal->hInstance = hInstance;
		pGameInternal->GameState = GameTitle;

		pGameInternal = (PGAME_INTERNAL)Progress_QuickProgressBar(NULL, hInstance, IDD_PROGRESS_DLG, (PVOID)pGameInternal, NULL, Game_InitializeWorkerThread, FLAG_WORKER_CONTEXT_CURRENT_THREAD);

		if(pGameInternal)
		{
			pGameInternal->TitleData.TitleFaded = TRUE;
			TAudio_PlaySound(pGameInternal->TitleData.hTAudioBackground, 0);
			GDI_ClearVideoBuffer(pGameInternal->GameScreen.hGameScreen);
		}
	}

	return pGameInternal;
}


 /***********************************************************************
  * Game_InitializeWorkerThread
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void Game_InitializeWorkerThread(HPROGRESS hProgress, PVOID pContext)
{
	 PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)pContext;
	 PPROGRESS_DATA pProgressData;
	 BOOL StatusIsSuccess = TRUE;
	 UINT PercentageComplete = 0;

	 pProgressData = g_ProgressMap[pGameInternal->GameState];

	 while(PercentageComplete < 100 && StatusIsSuccess)
	 {
		 PercentageComplete += pProgressData->ProgressPercentage;
		 Progress_Advance(hProgress, 0, pProgressData->pszProgressMessage);

		 if(pProgressData->pfnWorkerFunction)
		 {
			 StatusIsSuccess = pProgressData->pfnWorkerFunction(pGameInternal);
		 }

		 if(StatusIsSuccess)
		 {
	 		 Progress_Advance(hProgress, pProgressData->ProgressPercentage, NULL);
			 pProgressData++;
		 }
	 }

	 if(StatusIsSuccess == FALSE)
	 {
		 Progress_Advance(hProgress, 0, pProgressData->pszErrorMessage);
		 Sleep(5000);
		 Game_Close((HGAME)pGameInternal);
		 pGameInternal = NULL;
	 }

	 Progress_CompleteAndCloseQuickWithReturn(hProgress, (PVOID)pGameInternal);
}

 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void Game_Close(HGAME hGame)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;

	LocalFree(pGameInternal);
}



 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void Game_HandleKeyRelease(HGAME hGame, UINT vKey)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;

	switch(pGameInternal->GameState)
	{
		case LevelOne:
			 GameLevel1_HandleKeyUp(pGameInternal, vKey);
			 break;
	}
}




 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void Game_HandleKeyPress(HGAME hGame, UINT vKey)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;

	switch(pGameInternal->GameState)
	{
		case LevelOne:
			 GameLevel1_HandleKeyDown(pGameInternal, vKey);
			 break;
	}
}


 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
HDC Game_GetGameDc(HGAME hGame)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;

    return GDI_GetDC(pGameInternal->GameScreen.hGameScreen);
}

 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void Game_ReleaseGameDc(HGAME hGame, HDC hGameDC)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;
	GDI_ReleaseDC(pGameInternal->GameScreen.hGameScreen);
}

 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
BOOL Game_MessageLoop(HGAME hGame)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;
	BOOL bContinue = TRUE;

	/*
	 * In title mode we do not need a busy loop so take
	 * control of the message loop and prevent exit from this function.
	 */
	if(pGameInternal->GameState == GameTitle)
	{
		 MSG Msg;
		 BOOL bThunkMessageLoop = TRUE;

		 while(bThunkMessageLoop)
		 {
			if(GetMessage(&Msg, 0, 0, 0) > 0)
			{
				if(Msg.message == WM_SWITCH_GAME_STATE)
				{
					bThunkMessageLoop = FALSE;
				}

				TranslateMessage(&Msg);
				DispatchMessage(&Msg);
			}
			else
			{
				bThunkMessageLoop = FALSE;
				bContinue         = FALSE;
			}
		 }
	}
	else
	{
		 MSG Msg;
		 BOOL bThunkMessageLoop = TRUE;

		 SetTimer(pGameInternal->hWnd, 1, 1000/30, NULL);

		 while(bThunkMessageLoop)
		 {
			if(GetMessage(&Msg, 0, 0, 0) > 0)
			{
				if(Msg.message == WM_SWITCH_GAME_STATE)
				{
					bThunkMessageLoop = FALSE;
				}

				TranslateMessage(&Msg);
				DispatchMessage(&Msg);

				switch(pGameInternal->GameState)
				{
					case LevelOne:
						 bContinue = GameLevel1_GameLoop(pGameInternal);
						 break;
				}

			}
			else
			{
				bThunkMessageLoop = FALSE;
				bContinue         = FALSE;
			}
		 }

		 KillTimer(pGameInternal->hWnd, 1);
	}

	return bContinue;
}

 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
void Game_DispatchMenuSelections(HGAME hGame, UINT uiMenuSelection)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;
}

 /***********************************************************************
  * Game_Init
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
BOOL Game_FadeTitleScreen(HGAME hGame)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;
	UCHAR *ScreenBuffer;
	UCHAR *TitleBuffer;
	UINT Index = 0;
    
	if(pGameInternal->TitleData.TitleFaded == TRUE)
	{
		pGameInternal->TitleData.TitleFaded = FALSE;

		ScreenBuffer = GDI_BeginPaint(pGameInternal->GameScreen.hGameScreen);
		TitleBuffer = GDI_BeginPaint(pGameInternal->TitleData.hTitleScreen);

		while(Index < GAME_WIDTH*GAME_HEIGHT*4)
		{
			if(*ScreenBuffer != *TitleBuffer)
			{
				pGameInternal->TitleData.TitleFaded = TRUE;
				*ScreenBuffer = *ScreenBuffer + 1;

				if(*ScreenBuffer > *TitleBuffer)
				{
					*ScreenBuffer = *TitleBuffer;
				}
			}
			ScreenBuffer++;
			TitleBuffer++;
			Index++;
		}

		GDI_EndPaint(pGameInternal->TitleData.hTitleScreen);
		GDI_EndPaint(pGameInternal->GameScreen.hGameScreen);

		if(pGameInternal->TitleData.TitleFaded == FALSE && pGameInternal->GameOptions.EnableSoundEffects)
		{
			TAudio_PlaySound(pGameInternal->TitleData.hTAudioAmeliaWelcome, 0);
		}
	}
    
	return pGameInternal->TitleData.TitleFaded;
}

 /***********************************************************************
  * Game_GenericLoadGif
  *  
  *    
  *
  * Parameters
  *     
  * 
  * Return Value
  *     
  *
  ***********************************************************************/
HGDI Game_GenericLoadGif(PCHAR pszImageName, UINT uiImageNumber)
{
	HGDI hGdi;
	HGIF hGif;
	UINT Width;
	UINT Height;
	PCHAR ScreenBuffer;

	hGif = Gif_Open(pszImageName);

	if(hGif)
	{
		Width  = Gif_GetImageWidth(hGif, uiImageNumber);
    	Height = Gif_GetImageHeight(hGif, uiImageNumber);

		hGdi = GDI_Init(NULL, Width, Height);

		if(hGdi)
		{
			ScreenBuffer = GDI_BeginPaint(hGdi);
			Gif_GetImage32bpp(hGif, uiImageNumber, ScreenBuffer);
			GDI_EndPaint(hGdi);
		}

		Gif_Close(hGif);
	}

	return hGdi;
}

/***********************************************************************
 * Game_Debug
 *  
 *    Debug Shit
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
 void Game_Debug(char *pszFormatString, ...)
 {
     char DebugString[256];
     va_list vl;

     va_start(vl, pszFormatString);
     vsprintf(DebugString, pszFormatString, vl);
     va_end(vl);

     OutputDebugStringA(DebugString);
 }



/***********************************************************************
 * GameTitle_LoadTitleGif
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL GameTitle_LoadTitleGif(PGAME_INTERNAL pGameInternal)
{
	BOOL Status = TRUE;

    pGameInternal->TitleData.hTitleScreen = Game_GenericLoadGif(TITLE_SCREEN_GIF, 0);

	if(pGameInternal->TitleData.hTitleScreen == NULL)
	{
		Status = FALSE;
	}

	return Status;
}


/***********************************************************************
 * GameTitle_LoadTitleGif
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL GameTitle_LoadTitleAudio(PGAME_INTERNAL pGameInternal)
{
	BOOL Status = FALSE;
    char *pszTitleBackgroundMusic = "title.wav";
    char *pszAmeliaWelcome = "welcome.wav";

    pGameInternal->TitleData.hTAudioBackground = TAudio_Init(&pszTitleBackgroundMusic, 1, FLAG_LOOP_SOUND);

	if(pGameInternal->TitleData.hTAudioBackground)
	{
    	 pGameInternal->TitleData.hTAudioAmeliaWelcome = TAudio_Init(&pszAmeliaWelcome, 1, 0);

		 if(pGameInternal->TitleData.hTAudioAmeliaWelcome)
		 {
			 Status = TRUE;
		 }
	}

	return Status;
}

/***********************************************************************
 * GameTitle_LoadTitleGif
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL GameTitle_CreateGameScreen(PGAME_INTERNAL pGameInternal)
{
	BOOL Status = FALSE;

    pGameInternal->GameScreen.hGameScreen = GDI_Init(NULL, GAME_WIDTH, GAME_HEIGHT);

    if(pGameInternal->GameScreen.hGameScreen)
    {
		Status = TRUE;
    }

	return Status;
}


/***********************************************************************
 * Game_HandleMenuCommands
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void Game_HandleMenuCommands(HGAME hGame, USHORT Command, LPARAM lParam)
{
	PGAME_INTERNAL pGameInternal = (PGAME_INTERNAL)hGame;

	switch(pGameInternal->GameState)
	{
	    case GameTitle:
             GameTitle_HandleMenuCommands(pGameInternal, Command, lParam);
			 break;

	    case LevelOne:
             GameLevel1_HandleMenuCommands(pGameInternal, Command, lParam);
			 break;
	}
}



/***********************************************************************
 * GameTitle_HandleMenuCommands
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void GameTitle_HandleMenuCommands(PGAME_INTERNAL pGameInternal, USHORT Command, LPARAM lParam)
{
	switch(Command)
	{
		case IDM_MUSIC:
			 GameTitle_ToggleMusic(pGameInternal);
			 break;
		case IDM_SOUND:
			 GameTitle_ToggleSound(pGameInternal);
			 break;

		case IDM_ABOUT:
			 break;

		case IDM_NEW_GAME:
			 GameTitle_LoadLevelOne(pGameInternal);
			 break;

		case IDM_EXIT:
			 SendMessage(pGameInternal->hWnd, WM_CLOSE, 0, 0);
			 break;
	}
}

/***********************************************************************
 * GameTitle_ToggleMusic
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void GameTitle_ToggleMusic(PGAME_INTERNAL pGameInternal)
{
	
	if(pGameInternal->GameOptions.EnableMusic)
	{
		CheckMenuItem(GetMenu(pGameInternal->hWnd), IDM_MUSIC, MF_UNCHECKED);
		TAudio_PauseSound(pGameInternal->TitleData.hTAudioBackground);
		pGameInternal->GameOptions.EnableMusic = FALSE;
	}
	else
	{
		CheckMenuItem(GetMenu(pGameInternal->hWnd), IDM_MUSIC, MF_CHECKED);
		TAudio_PlaySound(pGameInternal->TitleData.hTAudioBackground, 0);
		pGameInternal->GameOptions.EnableMusic = TRUE;
	}
}



/***********************************************************************
 * GameTitle_ToggleSound
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void GameTitle_ToggleSound(PGAME_INTERNAL pGameInternal)
{
	if(pGameInternal->GameOptions.EnableSoundEffects)
	{
		CheckMenuItem(GetMenu(pGameInternal->hWnd), IDM_SOUND, MF_UNCHECKED);
		pGameInternal->GameOptions.EnableSoundEffects = FALSE;
	}
	else
	{
		CheckMenuItem(GetMenu(pGameInternal->hWnd), IDM_SOUND, MF_CHECKED);
		pGameInternal->GameOptions.EnableSoundEffects = TRUE;
	}
}

/***********************************************************************
 * GameTitle_LoadLevelOne
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void GameTitle_LoadLevelOne(PGAME_INTERNAL pGameInternal)
{
	pGameInternal->GameState = LevelOne;

	pGameInternal = (PGAME_INTERNAL)Progress_QuickProgressBar(NULL, pGameInternal->hInstance, IDD_PROGRESS_DLG, (PVOID)pGameInternal, NULL, Game_InitializeWorkerThread, FLAG_WORKER_CONTEXT_CURRENT_THREAD);

	if(pGameInternal == NULL)
	{
		ExitProcess(0);
	}

	GameTitle_Shutdown(pGameInternal);

	if(pGameInternal->GameOptions.EnableMusic)
	{
    	TAudio_PlaySound(pGameInternal->LevelOneData.hTAudioBackground, 0);
	}

	PostMessage(pGameInternal->hWnd, WM_SWITCH_GAME_STATE, 0, 0);
	
}


/***********************************************************************
 * GameTitle_Shutdown
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
void GameTitle_Shutdown(PGAME_INTERNAL pGameInternal)
{
	pGameInternal->TitleData.TitleFaded = FALSE;

	if(pGameInternal->GameOptions.EnableMusic)
	{
		TAudio_PauseSound(pGameInternal->TitleData.hTAudioBackground);
	}
}
	
    
/***********************************************************************
 * Game_GenericLoadSprite
 *  
 *    
 *
 *    
 *
 * Parameters
 *     Debug
 *
 * Return Value
 *     Nothing
 *
 ***********************************************************************/
BOOL Game_GenericLoadSprite(PSPRITE_DATA pSprite, char *pszImages[], UINT NumberOfImages)
{
	BOOL Status = FALSE;
	UINT Index = 1;
	UINT SpriteIndex = 0;

    pSprite->NumberOfAnimations = NumberOfImages;
	pSprite->phAnimations = (HGDI *)LocalAlloc(LMEM_ZEROINIT, sizeof(HGDI)*(NumberOfImages - 1));

	if(pSprite->phAnimations)
	{
		if(pszImages[0] != NULL)
		{
			pSprite->hStanding = Game_GenericLoadGif(pszImages[0], 0);
		}

		if(pSprite->hStanding || pszImages[0] == NULL)
		{
			Status = TRUE;
			pSprite->StartNumberUp = INVALID_SPRITE_INDEX;

			if(Status && pszImages[Index])
			{
    			pSprite->StartNumberUp = SpriteIndex;

				for(;pszImages[Index] && Status; Index++, SpriteIndex++)
				{
					pSprite->phAnimations[SpriteIndex] = Game_GenericLoadGif(pszImages[Index], 0);
					if(pSprite->phAnimations[SpriteIndex] == NULL)
					{
						Status = FALSE;
					}
				}

			}

			Index++;
			pSprite->StartNumberDown = INVALID_SPRITE_INDEX;

			if(Status && pszImages[Index])
			{
				pSprite->StartNumberDown = SpriteIndex;
				for(;pszImages[Index] && Status; Index++, SpriteIndex++)
				{
					pSprite->phAnimations[SpriteIndex] = Game_GenericLoadGif(pszImages[Index], 0);
					if(pSprite->phAnimations[SpriteIndex] == NULL)
					{
						Status = FALSE;
					}
				}
			}

			Index++;
			pSprite->StartNumberLeft = INVALID_SPRITE_INDEX;

			if(Status && pszImages[Index])
			{
				pSprite->StartNumberLeft = SpriteIndex;
				for(;pszImages[Index] && Status; Index++, SpriteIndex++)
				{
					pSprite->phAnimations[SpriteIndex] = Game_GenericLoadGif(pszImages[Index], 0);
					if(pSprite->phAnimations[SpriteIndex] == NULL)
					{
						Status = FALSE;
					}
				}
			}

			Index++;
			pSprite->StartNumberRight = INVALID_SPRITE_INDEX;

			if(Status && pszImages[Index])
			{
				pSprite->StartNumberRight = SpriteIndex;
				for(;pszImages[Index] && Status; Index++, SpriteIndex++)
				{
					pSprite->phAnimations[SpriteIndex] = Game_GenericLoadGif(pszImages[Index], 0);
					if(pSprite->phAnimations[SpriteIndex] == NULL)
					{
						Status = FALSE;
					}
				}
			}
     	}
	}

	return Status;
}
