// CSBwin.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
#include "UI.h"
#include "dispatch.h"
#include "objects.h"
#include "CSB.h"
#include "data.h"

#define MAX_LOADSTRING 100

i16 trace = -1;
CSB_UI_MESSAGE csbMessage;
extern i32 screenSize;
extern bool BeginRecordOK;
extern bool ItemsRemainingOK;
extern bool PlayfileIsOpen(void);
extern bool RecordfileIsOpen(void);
extern bool TimerTraceActive;
extern bool AttackTraceActive;
extern i32 NoSpeedLimit;
extern i32 GameMode;
extern i32 MostRecentlyAdjustedSkills[2];
extern i32 LatestSkillValues[2];
extern XLATETYPE latestScanType;
extern XLATETYPE latestCharType;
extern i32 latestCharp1;
extern i32 latestScanp1;
extern i32 latestScanp2;
extern i32 latestScanXlate;
extern i32 latestCharXlate;
extern unsigned char *encipheredDataFile;

char *parentFolder(char *folderName, char *endName);

char *helpMessage = "CSBWin looks in three places for files:\n"
                    " 1) The default directory\n"
                    " 2) The parent of the default directory\n"
                    " 3) The directory of CSBWin.exe\n"
                    "      Searched in order 1, 2, 3\n\n."
                    "The default directory can be spcified in two ways:\n"
                    " 1) The command line   directory=\"c:\\My Games\\DM\\\"\n"
                    " 2) The config.txt file   directory \"c:\\My Games\\DM\\\"\n\n"
                    "      The quotes are necessary if the name contains spaces.\n"
                    "      The config.txt file overrides the command line\n"
                    "      except (of course) when searching for config.txt\n\n"
                    "If no default directory is specified then the only\n"
                    "directory searched will be the directory containing CSBWin.exe.\n\n"
                    "Whenever a file is created it will be created in the first of\n"
                    "the three directories that is specified.  So new files will go\n"
                    "into the default directory unless none is specified, in which\n"
                    "case they will go into the CSBWin.exe directory";

int WindowWidth = 652;
int WindowHeight = 460;
int WindowX = 0;
int WindowY = 0;
bool fullscreenRequested = false;
bool fullscreenActive = false;

i32 line = 0;

// Global Variables:
HINSTANCE hInst;								// current instance
HWND hWnd; // Global
TCHAR szTitle[MAX_LOADSTRING];								// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];								// The title bar text
TCHAR szCSBVersion[MAX_LOADSTRING];

// Foward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, i32);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

char *GetField(char *pCol, char *field, char term)
{
  int col;
  while (*pCol == ' ') pCol++;
  col = 0;
  field[col] = 0;
  while ( col<80 )
  {
    if (*pCol == 0) return pCol;
    if (*pCol == term) return pCol;
    if ( (term == '=') && (*pCol == ' ') ) return pCol;
    field[col] = *pCol;
    pCol++;
    col++;
    field[col] = 0;
  };
  return pCol;
}

char *ParseOption(char *pCol, char *key, char *value)
{
  pCol = GetField(pCol, key, '=');
  strupr(key);
  value[0] = 0;
  if (*pCol == '=') 
  {
    if (pCol[1] == '"')
    {
      pCol = GetField(pCol+2, value, '"');
    }
    else
    {
      pCol = GetField(pCol+1, value, ' ');
    };
  }
  return pCol+1;
}

i32 APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE /*hPrevInstance*/,
                     LPSTR     /*lpCmdLine*/,
                     i32       nCmdShow)
{
 	// TODO: Place code here.
	MSG msg;
	HACCEL hAccelTable;

  if (encipheredDataFile != NULL)
  memcpy(encipheredDataFile, WinMain, 64);

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_CSBWIN, szWindowClass, MAX_LOADSTRING);
	LoadString(hInstance, IDS_VERSION, szCSBVersion, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow)) 
	{
		return FALSE;
	}

  speedTable[SPEED_GLACIAL].vblPerTick = 1000;
  speedTable[SPEED_MOLASSES].vblPerTick = 55;
  speedTable[SPEED_VERYSLOW].vblPerTick = 33;
  speedTable[SPEED_SLOW].vblPerTick = 22;
  speedTable[SPEED_NORMAL].vblPerTick = 15;
  speedTable[SPEED_FAST].vblPerTick = 11;
  speedTable[SPEED_QUICK].vblPerTick = 7;


	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_CSBWIN);

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return msg.wParam;
}

void ProcessCommandLine(void)
{
  char *lpCmdLine;
  char *pCol, *command;
  char term;
  char key[81], value[81];
  lpCmdLine = GetCommandLine();
  term = ' ';
  pCol = lpCmdLine;
  if (*pCol == '"')
  {
    pCol++;
    term = '"';
  };
  command = pCol;
  while (*pCol != 0)
  {
    if (*pCol == term) break;
    pCol++;
  };
  root = parentFolder(command, pCol);
  pCol = lpCmdLine;
  if (pCol[0] == '"')
  {
    pCol = GetField(lpCmdLine+1, key, '"')+1;
  }
  else
  {
   pCol = GetField(lpCmdLine, key, ' ');
  };
  while (*pCol != 0)
  {
    pCol = ParseOption(pCol, key, value);
    if (key[0] != 0) UI_ProcessOption(key, value);
  };
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage is only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
  LOGBRUSH background = {BS_SOLID, RGB(0,0,0), 0};
  HBRUSH hBrush = CreateBrushIndirect(&background);
	WNDCLASSEX wcex;

  ProcessCommandLine();
  if (!fullscreenRequested)
  {
	  wcex.cbSize = sizeof(WNDCLASSEX); 

	  wcex.style			= CS_HREDRAW | CS_VREDRAW;
	  wcex.lpfnWndProc	= (WNDPROC)WndProc;
	  wcex.cbClsExtra		= 0;
	  wcex.cbWndExtra		= 0;
	  wcex.hInstance		= hInstance;
	  wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_CSBWIN);
	  wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	  wcex.hbrBackground	= hBrush;
	  wcex.lpszMenuName	= (LPCSTR)IDC_CSBWIN;
	  wcex.lpszClassName	= szWindowClass;
	  wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
  }
  else
  {

	  wcex.cbSize = sizeof(WNDCLASSEX); 

  	wcex.style			= 0;
  	wcex.lpfnWndProc	= (WNDPROC)WndProc;
  	wcex.cbClsExtra		= 0;
  	wcex.cbWndExtra		= 0;
  	wcex.hInstance		= hInstance;
  	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_CSBWIN);
  	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
  	wcex.hbrBackground	= hBrush;
  	wcex.lpszMenuName	= NULL;
  	wcex.lpszClassName	= szWindowClass;
  	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
  };
	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HANDLE, i32)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, i32 nCmdShow)
{
   //HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   if (!fullscreenRequested)
   {
      hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      WindowX, WindowY, 
      WindowWidth, WindowHeight, 
      NULL, NULL, hInstance, NULL);
   }
   else
   {
      hWnd = CreateWindow(szWindowClass, "",WS_POPUP,
      0, 0, 
      GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN) , 
      NULL, NULL, hInstance, NULL);
   };
   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   SetTimer(hWnd, 1, 50, NULL);
   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
i32 delta[60];
i32 prevms = -1;
i32 slot;
void display(void);
extern ui32 VBLInterruptCount;
extern ui32 CheckVBLCount;
extern ui32 STBLTCount;
extern i32 GameTime;

bool cursorIsShowing = true;


HDC hdc;
LRESULT CALLBACK WndProc(HWND _hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	i32 wmId, wmEvent;
	PAINTSTRUCT ps;
	TCHAR szHello[MAX_LOADSTRING];
  ASSERT( (hWnd==0) || (hWnd==_hWnd) );
  hWnd = _hWnd;
  char msg[100];
	LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

  static i32 x,y;
  static bool inWindow;

  int size;

  if (trace >= 0) fprintf(GETFILE(trace),"msg=");
  if (trace >= 0) fflush(GETFILE(trace));

  switch (message) 
	{
		case WM_COMMAND:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_COMMAND\n");
			wmId    = LOWORD(wParam); 
			wmEvent = HIWORD(wParam); 
			// Parse the menu selections:
			switch (wmId)
			{
				case IDM_ABOUT:
				    DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
				    break;
        case IDM_HELP:
            UI_MessageBox(helpMessage, "Help", MESSAGE_OK);
            break;
				case IDM_EXIT:
            if (trace >= 0) CLOSE(trace);
            trace = -1;
				    DestroyWindow(hWnd);
				    break;
        case IDC_Normal:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_NORMAL;
            csbMessage.p2 = 2; //2-(screenSize==1); //new value
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_Double:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_DOUBLE;
            csbMessage.p2 = 2; //2-(screenSize==2); //new value
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_Triple:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_TRIPLE;
            csbMessage.p2 = 2; //2-(screenSize==3); //new value
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_Quadruple:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_QUADRUPLE;
            csbMessage.p2 = 2; //2-(screenSize==4); //new value
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_QuickPlay:
            if (!PlayfileIsOpen()) break;
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_QUICKPLAY;
            csbMessage.p2 = (NoSpeedLimit!=0) ? 0 : 1;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_Glacial:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_CLOCK;
            csbMessage.p2 = SPEED_GLACIAL;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_Molasses:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_CLOCK;
            csbMessage.p2 = SPEED_MOLASSES;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_VerySlow:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_CLOCK;
            csbMessage.p2 = SPEED_VERYSLOW;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_Slow:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_CLOCK;
            csbMessage.p2 = SPEED_SLOW;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_Normal:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_CLOCK;
            csbMessage.p2 = SPEED_NORMAL;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_Fast:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_CLOCK;
            csbMessage.p2 = SPEED_FAST;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_Quick:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_CLOCK;
            csbMessage.p2 = SPEED_QUICK;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_PlayerClock:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_PLAYERCLOCK;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_DMRULES:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_DMRULES;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDM_ExtraTicks:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_EXTRATICKS;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_Record:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_RECORD;
            csbMessage.p2 = 1;
            if (RecordfileIsOpen()) csbMessage.p2 = 0;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_TimerTrace:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_TIMERTRACE;
            csbMessage.p2 = 1;
            if (TimerTraceActive) csbMessage.p2 = 0;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_AttackTrace:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_ATTACKTRACE;
            csbMessage.p2 = 1;
            if (AttackTraceActive) csbMessage.p2 = 0;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_ItemsRemaining:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_ITEMSREMAINING;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_NonCSBItemsRemaining:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_NONCSBITEMSREMAINING;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_Playback:
            csbMessage.type = UIM_SETOPTION;
            csbMessage.p1 = OPT_PLAYBACK;
            csbMessage.p2 = 1;
            if (PlayfileIsOpen()) csbMessage.p2 = 0;
            if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
            {
              PostQuitMessage(0);
              break;
            };
            break;
        case IDC_DispatchTrace:
            if (trace >= 0) 
            {
              CLOSE(trace);
              trace = -1;
              break;
            };
            trace = CREATE("trace.log","w");
            break;
				default:
				    return DefWindowProc(hWnd, message, wParam, lParam);
			};
			break;
		case WM_PAINT:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_PAINT\n");
      if (trace >= 0) fflush(GETFILE(trace));
		  hdc = BeginPaint(hWnd, &ps);
      if (  (!fullscreenActive) && (screenSize == 1)
          ||(fullscreenActive && (videoSegSize[4]!=0)) )
      {
        line++;
        line = line%10;
        switch(line)
        {
        case 0:
          sprintf(msg,"vblint = %u",VBLInterruptCount);
          break;
        case 1:
          sprintf(msg,"chkvbl = %u",CheckVBLCount);
          break;
        case 2:
          sprintf(msg,"STblt = %u",STBLTCount);
          break;
        case 3:
          sprintf(msg,"Time = %u",GameTime);
          break;
        case 4:
          sprintf(msg,
                  "Skill[%d]=0x%08x      ",
                  MostRecentlyAdjustedSkills[0],
                  LatestSkillValues[0]);
          break;
        case 5:
          sprintf(msg,
                  "Skill[%d]=0x%08x      ",
                  MostRecentlyAdjustedSkills[1],
                  LatestSkillValues[1]);
          break;
        case 6:
          switch (latestCharType)
          {
          case TYPEIGNORED: 
            sprintf(msg, "%04x key --> Ignored                         ", latestCharp1);
            break;
          case TYPEKEY:
            sprintf(msg, "%04x key --> Translated %08x", latestCharp1, latestCharXlate);
            break;
          };
          break;
        case 7:
          switch (latestScanType)
          {
          case TYPESCAN:
          case TYPEIGNORED:
            sprintf(msg, "%08x mscan --> Ignored                        ",latestScanp1);
            break;
          case TYPEMSCANL:
            sprintf(msg, "%08x mscan --> Translated to %08x L",latestScanp1,latestScanXlate);
            break;
          case TYPEMSCANR:
            sprintf(msg, "%08x mscan --> Translated to %08x R",latestScanp1,latestScanXlate);
            break;
          default:
            sprintf(msg,"                                              ");
          };
          break;    
        case 8:
          switch (latestScanType)
          {
          case TYPEMSCANL:
          case TYPEIGNORED:
          case TYPEMSCANR:
            sprintf(msg, "%08x scan --> Ignored                        ",latestScanp2);
            break;
          case TYPESCAN:
            sprintf(msg, "%08x scan --> Translated to %08x", latestScanp2,latestScanXlate);
            break;
          default:
            sprintf(msg,"                                              ");
          };
          break;    
        case 9:
          sprintf(msg,"Total Moves = %d",totalMoveCount);
          break;
        };
        {
          int x, y;
          x = 325;
          y = 25;
          if (fullscreenActive)
          {
            x = videoSegX[4];
            y = videoSegY[4];
          };
          y += 15 *line;
          TextOut(hdc,x,y,msg,strlen(msg));
        };
      };
      csbMessage.type=UIM_PAINT;
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			EndPaint(hWnd, &ps);
      hdc = 0;
			break;
    case WM_TIMER:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_TIMER");
      if (trace >= 0) fflush(GETFILE(trace));
      csbMessage.type=UIM_TIMER;
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
      if (trace >= 0) fprintf(GETFILE(trace),"   Returned\n");
      if (trace >= 0) fflush(GETFILE(trace));
      break;
		case WM_DESTROY:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_DESTROY\n");
			PostQuitMessage(0);
			break;
    case WM_GETMINMAXINFO:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_GETMINMAXINFO\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_NCCREATE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_NCCREATE\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_NCCALCSIZE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_NCCALCSIZE\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_CREATE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_CREATE\n"); 
      csbMessage.type=UIM_INITIALIZE;
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_SHOWWINDOW:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_SHOWWINDOW\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_NCDESTROY:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_NCDESTROY\n"); 
      if (trace >= 0) CLOSE(trace);
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_WINDOWPOSCHANGING:
      //if (trace >= 0) fprintf(trace,"WM_WINDOWPOSCHANGING\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_ACTIVATEAPP:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_ACTIVATEAPP(%s)\n",wParam?"true":"false"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_NCACTIVATE:
      //if (trace >= 0) fprintf(trace,"WM_NCACTIVATE\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_GETTEXT:
      //if (trace >= 0) fprintf(trace,"WM_GETTEXT\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_ACTIVATE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_ACTIVATE\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_SETFOCUS:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_SETFOCUS\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_NCPAINT:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_NCPAINT\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_ERASEBKGND:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_ERASEBKGND\n"); 

      csbMessage.type=UIM_REDRAW_ENTIRE_SCREEN;
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_WINDOWPOSCHANGED:
      //if (trace >= 0) fprintf(trace,"WM_WINDOWPOSCHANGED\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_SIZE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_SIZE\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_MOVE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_MOVE\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_NCHITTEST:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_NCHITTEST\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_SETCURSOR:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_SETCURSOR\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_MOUSEMOVE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_MOUSEMOVE\n");
      x=LOWORD(lParam);
      y=HIWORD(lParam);
      if (fullscreenActive)
      {
        int x1=x, y1=y;
        TranslateFullscreen(x1,y1,x,y);
      }
      else
      {
        x = (x+screenSize/2)/screenSize;
        y = (y+screenSize/2)/screenSize;
      };
      inWindow = true;
      size = screenSize;
      if (y > 200) inWindow = false;
      if (y < 1)   inWindow = false;
      if (x > 320) inWindow = false;
      if (x < 1)   inWindow = false;
      if (GameMode == 1)
      {
        if (inWindow)
        {
          if (cursorIsShowing)
          {
            ShowCursor(false);
            cursorIsShowing = false;
          }
          else
          {
          };
        }
        else
        {
          if (cursorIsShowing)
          {
          }
          else
          {
            ShowCursor(true);
            cursorIsShowing = true;
          };
        };
      };
      if (GameMode != 1)
      {
        if (cursorIsShowing)
        {
        }
        else
        {
          ShowCursor(true);
          cursorIsShowing = true;
        };
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_KEYDOWN:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_KEYDOWN\n"); 
      csbMessage.type=UIM_KEYDOWN;
      csbMessage.p1 = wParam; //virtual key
      csbMessage.p2 = (lParam>>16)&0xff; //scancode
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_KEYUP:
      //if (trace >= 0) fprintf(trace,"WM_KEYUP\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_CHAR:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_CHAR\n"); 
      csbMessage.type=UIM_CHAR;
      csbMessage.p1 = wParam;
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			return 0;// DefWindowProc(hWnd, message, wParam, lParam);
    case WM_KILLFOCUS:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_KILLFOCUS\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_NCMOUSEMOVE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_NCMOUSEMOVE\n"); 
      if (cursorIsShowing)
      {
      }
      else
      {
        ShowCursor(true);
        cursorIsShowing = true;
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_SYSKEYDOWN:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_SYSKEYDOWN\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_SYSCHAR:
      if (trace >=0) fprintf(GETFILE(trace),"WM_SYSCHAR\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_SYSCOMMAND:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_SYSCOMMAND\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_ENTERMENULOOP:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_ENTERMENULOOP\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_INITMENU:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_INITMENU\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_MENUSELECT:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_MENUSELECT\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_INITMENUPOPUP:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_INITMMENUPOPUP\n"); 
      switch (LOWORD(lParam))
      {
      case 0: //File menu
        break;
      case 1: //Misc menu
        {
          i32 flag;
          if (screenSize==1)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDC_Normal,
                         MF_BYCOMMAND|flag);

          if (screenSize==2)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDC_Double,
                         MF_BYCOMMAND|flag);

          if (screenSize==3)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDC_Triple,
                         MF_BYCOMMAND|flag);

          if (screenSize==4)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDC_Quadruple,
                         MF_BYCOMMAND|flag);

          if (TimerTraceActive)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDC_TimerTrace,
                         MF_BYCOMMAND|flag);

          if (encipheredDataFile == NULL) flag = MF_ENABLED;
          else flag = MF_GRAYED;
          EnableMenuItem((HMENU)wParam,
                         IDC_TimerTrace,
                         MF_BYCOMMAND|flag);

          if (DM_rules)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_DMRULES,
                         MF_BYCOMMAND|flag);

          if (AttackTraceActive)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDC_AttackTrace,
                         MF_BYCOMMAND|flag);

          flag = MF_GRAYED;
          if (BeginRecordOK) flag = MF_ENABLED;
          EnableMenuItem((HMENU)wParam,
                         IDC_Playback,
                         MF_BYCOMMAND | flag);
          flag = MF_GRAYED;
          if (ItemsRemainingOK
              && (encipheredDataFile==NULL)) flag = MF_ENABLED;
          EnableMenuItem((HMENU)wParam,
                         IDC_ItemsRemaining,
                         MF_BYCOMMAND | flag);
          flag = MF_GRAYED;
          if (ItemsRemainingOK
              && (encipheredDataFile==NULL)) flag = MF_ENABLED;
          EnableMenuItem((HMENU)wParam,
                         IDC_NonCSBItemsRemaining,
                         MF_BYCOMMAND | flag);
          flag = MF_UNCHECKED;
          if (PlayfileIsOpen()) flag = MF_CHECKED;
          CheckMenuItem((HMENU)wParam,
                        IDC_Playback,
                        MF_BYCOMMAND | flag);

          flag = MF_GRAYED;
          if (BeginRecordOK) flag = MF_ENABLED;
          EnableMenuItem((HMENU)wParam,
                         IDC_Record,
                         MF_BYCOMMAND | flag);
          flag = MF_UNCHECKED;
          if (RecordfileIsOpen()) flag = MF_CHECKED;
          CheckMenuItem((HMENU)wParam,
                        IDC_Record,
                        MF_BYCOMMAND | flag);
          flag = MF_GRAYED;
          if (PlayfileIsOpen()) flag = MF_ENABLED;
          EnableMenuItem((HMENU)wParam,
                         IDC_QuickPlay,
                         MF_BYCOMMAND | flag);
          flag = MF_UNCHECKED;
          if (NoSpeedLimit!=0) flag = MF_CHECKED;
          CheckMenuItem((HMENU)wParam,
                        IDC_QuickPlay,
                        MF_BYCOMMAND | flag);

        };
        return 0;
      case 2: //Speed Menu
        {
          i32 flag;
          if (gameSpeed==SPEED_GLACIAL)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_Glacial,
                         MF_BYCOMMAND|flag);

          if (gameSpeed==SPEED_MOLASSES)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_Molasses,
                         MF_BYCOMMAND|flag);

          if (gameSpeed==SPEED_VERYSLOW)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_VerySlow,
                         MF_BYCOMMAND|flag);

          if (gameSpeed==SPEED_SLOW)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_Slow,
                         MF_BYCOMMAND|flag);

          if (gameSpeed==SPEED_NORMAL)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_Normal,
                         MF_BYCOMMAND|flag);

          if (gameSpeed==SPEED_QUICK)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_Quick,
                         MF_BYCOMMAND|flag);

          if (gameSpeed==SPEED_FAST)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_Fast,
                         MF_BYCOMMAND|flag);

          if (playerClock)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_PlayerClock,
                         MF_BYCOMMAND|flag);

          if (extraTicks)flag = MF_CHECKED;
          else flag = MF_UNCHECKED;
          CheckMenuItem ((HMENU)wParam,
                         IDM_ExtraTicks,
                         MF_BYCOMMAND|flag);
        };
      case 3: 
        break;//Help menu
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_ENTERIDLE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_ENTERIDLE\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_CAPTURECHANGED:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_CAPTURECHANGED\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_EXITMENULOOP:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_EXITMENULOOP\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_NCLBUTTONDOWN:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_NCLBUTTONDOWN\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_CLOSE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_CLOSE\n"); 
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_SIZING:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_SIZING\n");
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_ENTERSIZEMOVE:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_ENTERSIZEMOVE\n");
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_LBUTTONDOWN:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_LBUTTONDOWN\n");
      csbMessage.type=UIM_LEFT_BUTTON_DOWN;
      csbMessage.p1 = LOWORD(lParam);  // horizontal position of cursor 
      csbMessage.p2 = HIWORD(lParam);  // vertical position of cursor 
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_LBUTTONUP:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_LBUTTONUP\n");
      csbMessage.type=UIM_LEFT_BUTTON_UP;
      csbMessage.p1 = LOWORD(lParam);  // horizontal position of cursor 
      csbMessage.p2 = HIWORD(lParam);  // vertical position of cursor 
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_RBUTTONDOWN:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_RBUTTONDOWN\n");
      csbMessage.type=UIM_RIGHT_BUTTON_DOWN;
      csbMessage.p1 = LOWORD(lParam);  // horizontal position of cursor 
      csbMessage.p2 = HIWORD(lParam);  // vertical position of cursor 
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_RBUTTONUP:
      if (trace >= 0) fprintf(GETFILE(trace),"WM_RBUTTONUP\n");
      csbMessage.type=UIM_RIGHT_BUTTON_UP;
      csbMessage.p1 = LOWORD(lParam);  // horizontal position of cursor 
      csbMessage.p2 = HIWORD(lParam);  // vertical position of cursor 
      if (CSBUI(&csbMessage) != UI_STATUS_NORMAL)
      {
        PostQuitMessage(0);
        break;
      };
			return DefWindowProc(hWnd, message, wParam, lParam);
		default:
      if (trace >= 0) fprintf(GETFILE(trace),"0x%02x\n",message);
			return DefWindowProc(hWnd, message, wParam, lParam);
   };
   if (trace >= 0) fflush(GETFILE(trace));
   return 0;
}

// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, 
                       UINT message, 
                       WPARAM wParam, 
                       LPARAM /*lParam*/)
{
	switch (message)
	{
		case WM_INITDIALOG:
      {
        SetDlgItemText(hDlg, IDC_Version, szCSBVersion);
      };
				return TRUE;

		case WM_COMMAND:
			if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
			{
				EndDialog(hDlg, LOWORD(wParam));
				return TRUE;
			}
			break;
	}
    return FALSE;
}
