/*********************************************************************
	PROGRAM: WCDBRK2.C

	PURPOSE: Code Break game

	AUTHOR:  Ken Fogel
		 Omnibus Systems
		 8108 Norfolk Road
		 Cote St-Luc, Qu‚bec
		 Canada   H4X 1A3
		 (514) 487-1565
		 CompuServe: 74646,2157

	REVISION: June 1, 1991 - Version 2
									 Full Colour/Bitmaps

				 April 22, 1991 - Version 1.01
				 April 15, 1991 - Version 1

*********************************************************************/

#include <windows.h>	       /* required for all Windows applications */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "wcdbrk2.h"        /* specific to this program */

HANDLE  hInst;		          /* current instance */
HWND	  hGameGrid[10][4];   /* array of buttons */
int	  board[10][4];	    /* array of guesses */
int	  code[4];	          /* secret code */
char	  clues[10][4];	    /* array of clues */
int	  cur_round;	       /* current row */
int     cur_column;         /* current column */
char	  str[80];	          /* general purpose string */
HWND    DidIGetItRight;
BOOL    Setup;
BITMAP  Bitmap;
HBITMAP hOldBitmap;
HBITMAP hBoardmap;
HBITMAP hBlclpegmap;
HBITMAP hWhclpegmap;
HBITMAP hPegBoardmap;
LPSTR   lpPegs[8] = {"Bluepeg","Dkpupeg","Grenpeg","Ltblpeg",
							 "Oranpeg","Purppeg","Redpeg","Yellpeg"};
HBITMAP hPegs[8];
int iXpos,iYpos;
int curcolour = 0;
int prevcolour = -1;
int winstate;

/*********************************************************************/

int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HANDLE hInstance;			    /* current instance */
HANDLE hPrevInstance;		 /* previous instance */
LPSTR lpCmdLine;			    /* command line */
int nCmdShow;				    /* show-window type (open/icon) */
{
	MSG msg;				       /* message */

	Setup = FALSE;

	if (!hPrevInstance)			           /* Other instances of app running? */
		if (!InitApplication(hInstance))	  /* Initialize shared things */
			return (FALSE);		           /* Exits if unable to initialize */

	/* Perform initializations that apply to a specific instance */

	if (!InitInstance(hInstance, nCmdShow))
		return (FALSE);


	/* Aquire and dispatch messages until a WM_QUIT message is recieved */

	while (GetMessage(&msg,	              /* message structure */
							NULL,	 /* handle of window recieving the message */
							NULL,	 /* lowest message to examine */
							NULL))	 /* highest message to examine */
	{
		TranslateMessage(&msg);	 /* Translates virtual key codes */
		DispatchMessage(&msg);	 /* Dispatches message to window */
	}
	return(msg.wParam);  /* Returns the value from PostQuitMessage */
}

/*********************************************************************/

BOOL InitApplication(hInstance)
HANDLE hInstance;			  /* current instance */
{
	WNDCLASS wc;

	/* Fill in window class structure with parameters that describe the */
	/* main window. */

	wc.style = CS_DBLCLKS;   /* Class style(s). */
	wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for */
											/* windows of this class */
	wc.cbClsExtra = 0;		      /* No per-class extra data */
	wc.cbWndExtra = 0;		      /* No per-window extra data */
	wc.hInstance = hInstance;	   /* Application that owns the class. */
	wc.hIcon = LoadIcon(hInstance, "Wcdbrk2");
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = "WndCdBrkMenu";   /* Name of menu resource in .RC file */
	wc.lpszClassName = "WndCdBrkWClass";/* Name used in call to CreateWindow */

	/* Register the window class and return success/failure code */

	return (RegisterClass(&wc));

}

/*********************************************************************/

BOOL InitInstance(hInstance, nCmdShow)
HANDLE hInstance;		       /* Current instance identifier */
int    nCmdShow;		       /* Param for first ShowWindow() call */
{
	HWND hWnd;			       /* Main window handle */

	hInst = hInstance;

	/* Create a main window for this application instance */

	hWnd = CreateWindow(
		 "WndCdBrkWClass",         /* See RegisterClass() call */
		 "Code Breaker II",      /* Text for window title bar */
		 /* The following line creates a window which can be */
		 /* minimized to an icon and moved but not re-sized  */
		 WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,
		 120,                      /* Initial column */
		 30,                       /* Initial row    */
		 230,                      /* Width          */
		 435,                      /* Height         */
		 NULL,			            /* Overlapped windows have no parent */
		 NULL,			            /* Use the window class menu */
		 hInstance,		            /* This instance owns this window */
		 NULL			               /* Pointer not needed */
		 );

	/* If window could not be created, return "failure" */

	if (!hWnd)
		return (FALSE);

	/* Make the window visible; update its client area; and return "success" */

	ShowWindow(hWnd, nCmdShow);	 /* Show the window */
	UpdateWindow(hWnd);		       /* Sends WM_PAINT message */

	return (TRUE);		 /* Returns the value from POSTQUITMESSAGE */

}

/*********************************************************************/

long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam)
HWND hWnd;				      /* window handle */
unsigned message;			   /* type of message */
WORD wParam;				   /* additional information */
LONG lParam;				   /* additional information */
{
	FARPROC     lpProcAbout;	       /* pointer to the "About" function */
	int x,y;


	switch (message)
	{
		case WM_CREATE:
			if (!Setup)    /* Do this only once */
			{
				hBoardmap   = LoadBitmap(hInst,"Board");
				hPegBoardmap = LoadBitmap(hInst,"Pegboard");
				hBlclpegmap = LoadBitmap(hInst,"Blclpeg");
				hWhclpegmap = LoadBitmap(hInst,"Whclpeg");
				for (x=0;x<8;x++)
					hPegs[x] = LoadBitmap(hInst,lpPegs[x]);
				if(!bMakeGameButtons(hWnd))
				{
					MessageBox(hWnd,"Failure to create buttons!",NULL,
								  MB_OK | MB_ICONHAND);
				}
				Setup = TRUE;
			}
			vInitialize();
			vMakecode();
			break;

		case WM_LBUTTONUP:          /* Mouse button was pressed */
			iXpos = LOWORD(lParam);
			iYpos = HIWORD(lParam);
			if (bCheckPosition(hWnd))
			{
				board[cur_round][cur_column] = curcolour;
				vPutPeg(hWnd,curcolour,cur_round,cur_column);
			}
			break;

		case WM_PAINT:              /* Time to repaint */
			vBasicScreen(hWnd);
			vMarkColour(hWnd);
			for (x=0;x<=cur_round;x++)
			{
				for (y=0;y<4;y++)
					vPutPeg(hWnd,board[x][y],x,y);
				vDoClues(hWnd,x);
			}
			if (winstate == 1)
				vDoWin(hWnd);
			else
				if (winstate == 2)
					vDoLoose(hWnd);

			break;


		case WM_COMMAND:	     /* message: command from application menu */
			switch(wParam)
			{
				case DIDIGETITRIGHT:
					if (!winstate)    /* If won or lost ignore commands */
					{
						if (!bCheckfill()) break;
						if (bCheckguess(cur_round))
						{
							vDoWin(hWnd);
							break;
						}
						else
						{
							vDoClues(hWnd,cur_round);
							cur_round++;
							if (cur_round == 10) /* You loose */
								vDoLoose(hWnd);
						}
					}
					break;

				case IDM_ABOUT:
					lpProcAbout = MakeProcInstance(About, hInst);

					DialogBox(hInst, 		   /* current instance */
								 "AboutBox",   /* resource to use */
								 hWnd,			/* parent handle */
								 lpProcAbout);	/* About() instance address */

					FreeProcInstance(lpProcAbout);
					break;

				case IDM_NEW:  /* Let's play again */
				  InvalidateRect(hWnd, NULL, TRUE);
				  SendMessage(hWnd,WM_CREATE,NULL,NULL);
				  break;

				case IDM_GIVEUP:
					vDoLoose(hWnd);
					break;

				case IDM_HELP:
					lpProcAbout = MakeProcInstance(About, hInst);

					DialogBox(hInst, 		   /* current instance */
								 "HelpBox",   /* resource to use */
								 hWnd,			/* parent handle */
								 lpProcAbout);	/* About() instance address */

					FreeProcInstance(lpProcAbout);
					break;

				default:		       /* Lets Windows process it */
					return (DefWindowProc(hWnd, message, wParam, lParam));
			}
			break;

		case WM_DESTROY:			/* message: window being destroyed */
			DeleteObject(hBoardmap);
			DeleteObject(hPegBoardmap);
			DeleteObject(hBlclpegmap);
			DeleteObject(hWhclpegmap);
			for (x=0;x<8;x++)
				DeleteObject(hPegs[x]);
			PostQuitMessage(0);
			break;

		default:				/* Passes it on if unprocessed */
			return (DefWindowProc(hWnd, message, wParam, lParam));
	}
	return (NULL);
}

/*********************************************************************/

BOOL FAR PASCAL About(hDlg, message, wParam, lParam)
HWND hDlg;				       /* window handle of the dialog box */
unsigned message;			    /* type of message */
WORD wParam;				    /* message-specific information */
LONG lParam;
{
	switch (message)
	{
		case WM_INITDIALOG:		      /* message: initialize dialog box */
			return (TRUE);

		case WM_COMMAND:			      /* message: received a command */
			if (wParam == IDOK ||		/* "OK" box selected ? */
			  wParam == IDCANCEL)	   /* System menu close command ? */
			{
				EndDialog(hDlg, TRUE);	/* Exits the dialog box */
				return (TRUE);
			}
			break;
	}
	return (FALSE);
}

/*****************/
/* Clear the board and the clues for a new game */
void vInitialize(void)
{
	int x,y;

	for(x=0;x<=9;x++)
		for(y=0;y<=3;y++)
		{
			board[x][y] = -1;
			clues[x][y] = ' ';
		}
	cur_round = 0;
	winstate = 0;
	return;
}

/*****************/
/* Scramble the position of clues */
void vScrambleclues(int round)
{
	int x,y=0,signal=1;
	char tempclues[4]={'\0','\0','\0','\0'};

	while (signal)
	{
		x=(rand() % 4);
		if (tempclues[x]=='\0')
		{
			tempclues[x] = clues[round][y];
			y++;
			if (y>3) signal = 0;
		}
	}
	for(x=0;x <=3;x++)
		clues[round][x]=tempclues[x];
	return;
}

/*****************/
/* Check the guess for clues or win */
BOOL bCheckguess(int round)
{
	int x,y=0;
	int tempcode[4], temp[4];

	for(x=0;x<=3;x++)                   /* prepare temporary arrays */
	{
		temp[x]=board[round][x];
		tempcode[x]=code[x];
		clues[round][x] = ' ';
	}

	for(x=0;x<=3;x++)							/* check for perfect match */
		if (temp[x] == tempcode[x])
		{
			clues[round][x]='1';
			temp[x]=0;
			tempcode[x]=-1;
			y++;
		}

	if (y==4) return(TRUE);

	for(x=0;x<=3;x++)							/* check for right colour */
		for(y=0;y<=3;y++)						/*   wrong position       */
		{
			if (tempcode[x]==temp[y])
			{
				clues[round][y] = '0';
				temp[y] = 0;
				tempcode[x] = -1;
				break;
			}
		}
	vScrambleclues(round);
	return(FALSE);
}

/*****************/
/* Make sure all the buttons were clicked */
BOOL bCheckfill(void)
{
	int x;

	for(x=0;x<=3;x++)
		if (board[cur_round][x] == -1)
			return(FALSE);
	return(TRUE);
}

/*****************/
/* Generate the secret code */
void vMakecode(void)
{
	int x;
	time_t t;

	srand((unsigned) time(&t));

	for(x=0;x<=3;x++)
		code[x]= (rand() % 8);

	return;
}

/***********************/
/* Create the buttons on screen */
BOOL bMakeGameButtons(HWND hWnd)
{

	if (DidIGetItRight != NULL) DestroyWindow(DidIGetItRight);
	DidIGetItRight = CreateWindow("Button",
											"Did I Get It Right?",
											BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
											10, 350, 168, 20,
											hWnd,
											DIDIGETITRIGHT,
											hInst,
											NULL);
	if (!DidIGetItRight)
		return(FALSE);
	ShowWindow(DidIGetItRight, SW_SHOW);
	UpdateWindow(DidIGetItRight);
	return(TRUE);
}

/*******************************/
/* The basic game board setup  */
/*******************************/
void vBasicScreen(HWND hWnd)
{
	HDC hDC,hMemoryDC;
	PAINTSTRUCT ps;
	int x,y;

	hDC = BeginPaint(hWnd, &ps);
	hMemoryDC = CreateCompatibleDC(hDC);

	hOldBitmap = SelectObject(hMemoryDC,hBoardmap);        /* Game board */
	GetObject(hBoardmap, sizeof(BITMAP), (LPSTR) &Bitmap);
	BitBlt(hDC,10,10,Bitmap.bmWidth, Bitmap.bmHeight,
			 hMemoryDC,0,0,SRCCOPY);

	hOldBitmap = SelectObject(hMemoryDC,hPegBoardmap);     /* Peg board  */
	GetObject(hPegBoardmap, sizeof(BITMAP), (LPSTR) &Bitmap);
	BitBlt(hDC,190,154,Bitmap.bmWidth, Bitmap.bmHeight,
			 hMemoryDC,0,0,SRCCOPY);

	y = 158;
	for (x=0;x<8;x++)                                      /* Pegs       */
	{
		hOldBitmap=SelectObject(hMemoryDC,hPegs[x]);
		GetObject(hPegs[x], sizeof(BITMAP), (LPSTR) &Bitmap);
		BitBlt(hDC,194,y,Bitmap.bmWidth, Bitmap.bmHeight,
				 hMemoryDC,0,0,SRCCOPY);
		y += 23;
	}

	SelectObject(hMemoryDC, hOldBitmap);
	DeleteDC(hMemoryDC);
	ReleaseDC(hWnd, hDC);
	EndPaint(hWnd, &ps);

	return;
}

/***************************************/
/* Check where mouse was clicked and   */
/* decide if a peg was selected or a   */
/* position on the board was selected. */
/***************************************/
BOOL bCheckPosition(HWND hWnd)
{
	int x,y,z,row=-1;
	BOOL recX = FALSE;
	BOOL recY = FALSE;

	if ((iYpos<=344-(cur_round*30)) && (iYpos>=314-(cur_round*30)))
	{
		recY = TRUE;
		z = 0;
		for(x=16;x<=118;x+=27)
		{
			if ((iXpos>=x) && (iXpos<=(x+27)))
			{
				recX = TRUE;
				break;
			}
			z++;
		}
	}
	if ((recX) && (recY))
	{
		cur_column = z;
		return(TRUE);
	}
	else
	{
		for(y=0;y<=7;y++)
		{
			if ((iYpos>=(y*23+158)) && (iYpos<=(y*23+181)))
			{
				row = y;
				break;
			}
		}
		if ((row > -1) && ((iXpos>=194) && (iXpos<=218)))
		{
			curcolour = row;
			vMarkColour(hWnd);
		}
	}

	return(FALSE);
}
/********************************/
/* Place the selected peg at the*/
/* appropriate position         */
/********************************/
void vPutPeg(HWND hWnd, int colour, int round, int column)
{
	HDC hDC,hMemoryDC;

	if (board[round][column] == -1) return;
	hDC = GetDC(hWnd);
	hMemoryDC = CreateCompatibleDC(hDC);
	hOldBitmap = SelectObject(hMemoryDC,hPegs[colour]);
	GetObject(hPegs[colour], sizeof(BITMAP), (LPSTR) &Bitmap);
	BitBlt(hDC,column*27+16,314-round*30,Bitmap.bmWidth, Bitmap.bmHeight,
			 hMemoryDC,0,0,SRCCOPY);

	DeleteDC(hMemoryDC);
	ReleaseDC(hWnd, hDC);

	return;
}

/**************************/
/* Display the secret code*/
/**************************/
void vShowCode(HWND hWnd)
{
	int x;
	HDC hDC,hMemoryDC;

	hDC = GetDC(hWnd);
	hMemoryDC = CreateCompatibleDC(hDC);
	for (x=0;x<4;x++)
	{
		hOldBitmap = SelectObject(hMemoryDC,hPegs[code[x]]);
		GetObject(hPegs[code[x]], sizeof(BITMAP), (LPSTR) &Bitmap);
		BitBlt(hDC,x*27+16,15,Bitmap.bmWidth, Bitmap.bmHeight,
				 hMemoryDC,0,0,SRCCOPY);
	}

	DeleteDC(hMemoryDC);
	ReleaseDC(hWnd, hDC);
	return;
}

/***************************/
/* Winner's routine        */
/***************************/
void vDoWin(HWND hWnd)
{
	HDC         hDC;

	vShowCode(hWnd);

	hDC = GetDC(hWnd);
	SetTextColor(hDC,RGB(0,255,0));
	SetBkMode(hDC,TRANSPARENT);
	strcpy(str,"WIN!");
	TextOut(hDC,130,18,str,strlen(str));
	ReleaseDC(hWnd, hDC);
	winstate = 1;
	return;
}

/***************************/
/* Looser's routine        */
/***************************/
void vDoLoose(HWND hWnd)
{
	HDC         hDC;

	vShowCode(hWnd);

	hDC = GetDC(hWnd);
	SetTextColor(hDC,RGB(255,0,0));
	SetBkMode(hDC,TRANSPARENT);
	strcpy(str,"LOOSE!");
	TextOut(hDC,125,18,str,strlen(str));
	ReleaseDC(hWnd, hDC);
	winstate = 2;

	return;
}
/*************************/
/* Display the clue pegs */
/*************************/
void vDoClues(HWND hWnd, int round)
{
	int x,y=0;
	HDC hDC,hMemoryDC;
	hDC = GetDC(hWnd);
	hMemoryDC = CreateCompatibleDC(hDC);
	for (x=0;x<4;x++)
	{
		if (clues[round][x] == '1')
		{
			hOldBitmap = SelectObject(hMemoryDC,hWhclpegmap);
			GetObject(hWhclpegmap, sizeof(BITMAP), (LPSTR) &Bitmap);
			BitBlt(hDC,y*12+125,320-(round*30),Bitmap.bmWidth, Bitmap.bmHeight,
					 hMemoryDC,0,0,SRCCOPY);
			y++;
		}
		else
			if (clues[round][x] =='0')
			{
				hOldBitmap = SelectObject(hMemoryDC,hBlclpegmap);
				GetObject(hBlclpegmap, sizeof(BITMAP), (LPSTR) &Bitmap);
				BitBlt(hDC,y*12+125,320-(round*30),Bitmap.bmWidth, Bitmap.bmHeight,
						 hMemoryDC,0,0,SRCCOPY);
				y++;
			}
	}

	DeleteDC(hMemoryDC);
	ReleaseDC(hWnd, hDC);
	return;
}

/*******************************/
/* Mark the selected colour    */
/*******************************/
void vMarkColour(HWND hWnd)
{
	HDC         hDC;

	hDC = GetDC(hWnd);
	if (prevcolour != -1)
	{
		SetTextColor(hDC,GetBkColor(hDC));
		SetBkMode(hDC,TRANSPARENT);
		strcpy(str,"*");
		TextOut(hDC,220,prevcolour*23+165,str,strlen(str));
	}
	SetTextColor(hDC,RGB(0,0,0));
	SetBkMode(hDC,TRANSPARENT);
	strcpy(str,"*");
	TextOut(hDC,220,curcolour*23+165,str,strlen(str));
	prevcolour = curcolour;

	ReleaseDC(hWnd, hDC);
	return;
}
