SCOREWND.C

/*********************************************************************** 
File: ScoreWnd.c

Abstract:

This module contains functions to maintain the Score window.


Contents:

DelScoreType() -- Delete a record of type ScoreType
NewScoreType() -- Create & initialize a record of type ScoreType
DrawScore() -- Draws a score entry with parametric update selection
ScoreWndProc() -- Main windows entrypoint for window with scores


************************************************************************/

#include "winmaze.h"
#include "mazproto.h"
#include "net.h"
#include <mmsystem.h>
#include <string.h>


TEXTMETRIC tmScoreInfo;
RECT rDirRect[4],rBitmapRect; // These will need ix and iy added to be right.

int iTextYPos;

#define SC_PIC 0x1
#define SC_NAME 0x2
#define SC_SCORE 0x4
#define SC_DIRECT 0x8
#define SC_REDRAW 0x10




/*=====================================================================
Function: DelScoreType()

Inputs: Pointer to record of ScoreType to delete

Outputs: returns ->next field of deleted record

Abstract:
Returns ->next field to facilitate linked list maintenance
======================================================================*/

ScoreType FAR *DelScoreType(
ScoreType FAR *stTrav
)
{
ScoreType FAR *stHold;
HGLOBAL hMem;

if (stTrav == (ScoreType FAR *) NULL) {
stHold = (ScoreType FAR *) NULL;
}
else {
stHold = stTrav->next;
hMem = (HGLOBAL) GlobalHandle(SELECTOROF(stTrav));
GlobalUnlock(hMem);
GlobalFree(hMem);
}

return(stHold);
}



/*=====================================================================
Function: NewScoreType()

Inputs: Values for ScoreType member elements

Outputs: Returns pointer to a newly allocated & Init'd record

Abstract:
Needs no explanation
======================================================================*/

ScoreType FAR *NewScoreType(
unsigned long ulID,
int ix,
int iy,
int iScore,
BYTE bDir,
ScoreType FAR *next
)
{
ScoreType FAR *stTrav;
HGLOBAL hMem;

hMem = GlobalAlloc(GHND,sizeof(ScoreType));
stTrav = (ScoreType FAR *) GlobalLock(hMem);
if (stTrav == (ScoreType FAR *)NULL) {
MessageBox((HWND)NULL,GetStringRes(IDS_MALLOCFAIL),"NewScoreType",
MB_ICONEXCLAMATION|MB_APPLMODAL);
}
else {
stTrav->ulID = ulID;
stTrav->ix = ix;
stTrav->iy = iy;
stTrav->iScore = iScore;
stTrav->bDir = bDir;
stTrav->next = next;
}

return(stTrav);
}






/*=====================================================================
Function: DrawScore()

Inputs: Pointer to score structure for to draw, flags for what to update

Outputs: none

Abstract:
DrawScore is the workhorse routine for drawing score entries.
======================================================================*/

void DrawScore(
ScoreType FAR *stTrav,
DWORD dwSCFlags
)
{
char Buff[132];
UINT uiAlign;
int x,y,px,py;
PlayerType FAR *ptTrav;
FullPicType FAR *fptTrav;
HBRUSH hWhiteBrush,hBlackBrush,hOld;
HPEN hWhitePen, hOldPen;
HDC hDC,hPicDC;
RECT rScratch;
BOOL bFound,bIsSelf,bFound2;
BYTE bDir,bNewDir,bB;
float fAspect;


bFound = FALSE;
ptTrav = &ptPlayers;

hWhiteBrush = GetStockObject(WHITE_BRUSH);
hWhitePen = GetStockObject(WHITE_PEN);

//
// Find the player structure associated with the score we're updating
//
while (ptTrav->next != NULL) {
ptTrav = ptTrav->next;
if (ptTrav->ulID == stTrav->ulID) {
bFound = TRUE;
break;
}
}

if (!bFound) {
bIsSelf = (stTrav->ulID == ptSelf.ulID);
}
else {
bIsSelf = FALSE;
}


hDC = GetDC(hWndScore);

//
// Play the dog-being-kicked sound if the player is doing bad.
//
if (stTrav->ulID == ptSelf.ulID) {
if (iKilledByDrones&&(!(iKilledByDrones%5))&&(stTrav->iScore > ptSelf.iScore)) {
sndPlaySound("dog.wav",SND_ASYNC);
}
}

//
// Draw a profile of the player if appropriate
//
if ((dwSCFlags&SC_PIC)&&(dwSCFlags&SC_REDRAW)) {
rScratch.left = rBitmapRect.left + stTrav->ix;
rScratch.right = rBitmapRect.right + stTrav->ix;
rScratch.top = rBitmapRect.top + stTrav->iy;
rScratch.bottom = rBitmapRect.bottom + stTrav->iy;

hPicDC = CreateCompatibleDC(hDC);
fptTrav = &fptPic;
bFound2 = FALSE;
while (fptTrav->next != (FullPicType FAR *)NULL) {
fptTrav = fptTrav->next;
if (fptTrav->iPicNum == ((bIsSelf) ? ptSelf.iPicNum : ptTrav->iPicNum)) {
bFound2 = TRUE;
break;
}
}

if (bFound2) {
SelectObject(hPicDC,fptTrav->P[1].hBitmap);
x = rScratch.right - rScratch.left;
y = rScratch.bottom - rScratch.top;
fAspect=((float) fptTrav->P[1].ySize)/
((float) fptTrav->P[1].xSize);

StretchBlt(hDC,rScratch.left,
rScratch.top+fptTrav->P[1].yOrg*y/PIC_Y,
(int) ((x < (y/fAspect))? x : y/fAspect),
(int) ((y < (x*fAspect))? y : (int) x*fAspect),
hPicDC,0,0,
fptTrav->P[1].xSize,
fptTrav->P[1].ySize,
SRCCOPY);
}

DeleteDC(hPicDC);
}

//
// Print the User & computer name of the player if appropriate
//
if ((dwSCFlags&SC_NAME)&&(dwSCFlags&SC_REDRAW)) {
if (bIsSelf) {
sprintf(Buff,"%s@%s",ptSelf.cUserName,ptSelf.cComputerName);
}
else {
if (bFound) {
sprintf(Buff,"%s@%s",ptTrav->cUserName,ptTrav->cComputerName);
}
}
TextOut(hDC,80,iTextYPos+stTrav->iy,Buff,lstrlen(Buff));
}

//
// Print the current score of the player if appropriate
//
if ((dwSCFlags&SC_SCORE)&&
((dwSCFlags&SC_REDRAW)||
(bFound&&(ptTrav->iScore != stTrav->iScore)) ||
(bIsSelf&&(ptSelf.iScore != stTrav->iScore)))
) {

hOldPen = SelectObject(hDC,hWhitePen);
hOld = SelectObject(hDC,hWhiteBrush);
sprintf(Buff,"%ld",stTrav->iScore);

Rectangle(hDC,rScore.right-5-((strlen(Buff)+1)* tmScoreInfo.tmAveCharWidth),
iTextYPos+stTrav->iy,rScore.right-5,
iTextYPos+stTrav->iy + tmScoreInfo.tmHeight);
SelectObject(hDC,hOldPen);
SelectObject(hDC,hOld);

if (bIsSelf) {
sprintf(Buff,"%ld",ptSelf.iScore);
stTrav->iScore = ptSelf.iScore;
}
else {
if (bFound) {
sprintf(Buff,"%ld",ptTrav->iScore);
stTrav->iScore = ptTrav->iScore;
}
else {
MessageBox((HWND)NULL,GetStringRes(IDS_MDFYSCO),"DrawScore",
MB_ICONEXCLAMATION|MB_APPLMODAL);
}
}

uiAlign = SetTextAlign(hDC,TA_TOP | TA_RIGHT);
TextOut(hDC,rScore.right-5,iTextYPos+stTrav->iy,Buff,lstrlen(Buff));
SetTextAlign(hDC,uiAlign);
}

//
// Modify the squares which say which direction to go to find this
// particular player, if appropriate.
//
if (bFound&&(dwSCFlags&SC_DIRECT)) {
x = ptSelf.Pos.ix;
y = ptSelf.Pos.iy;

hBlackBrush = GetStockObject(BLACK_BRUSH);

px = ptTrav->Pos.ix;
py = ptTrav->Pos.iy;
bDir = stTrav->bDir;

bNewDir = (py <= y) ? NORTH : (BYTE)0;
bNewDir |= (py >= y) ? SOUTH : (BYTE)0;
bNewDir |= (px >= x) ? EAST : (BYTE)0;
bNewDir |= (px <= x) ? WEST : (BYTE)0;

//
// Now that we have the ABSOLUTE directions, we need to rotate it for
// our offset from true north.
//

bB = ptSelf.Pos.Facing;

while (bB /=2 ) {
if (bNewDir & 1) {
bNewDir = bNewDir / 2 + 8;
}
else {
bNewDir /= 2;
}
/****
if (bNewDir & 16) {
bNewDir = (bNewDir & 15) + 1;
}
****/
}

//
// Draw square #0
//
if ((dwSCFlags&SC_REDRAW)||
((bNewDir&(NORTH|WEST)) != (bDir&(NORTH|WEST)))
) {
if ((bNewDir&NORTH)&&(bNewDir&WEST)) {
hOld = SelectObject(hDC,hBlackBrush);
}
else {
hOld = SelectObject(hDC,hWhiteBrush);
}

Rectangle(hDC,rDirRect[0].left+stTrav->ix,rDirRect[0].top+stTrav->iy,
rDirRect[0].right+stTrav->ix,rDirRect[0].bottom+stTrav->iy);
SelectObject(hDC,hOld);
}

//
// Draw square #1
//
if ((dwSCFlags&SC_REDRAW)||
((bNewDir&(NORTH|EAST)) != (bDir&(NORTH|EAST)))
) {
if ((bNewDir&NORTH)&&(bNewDir&EAST)) {
hOld = SelectObject(hDC,hBlackBrush);
}
else {
hOld = SelectObject(hDC,hWhiteBrush);
}

Rectangle(hDC,rDirRect[1].left+stTrav->ix,rDirRect[1].top+stTrav->iy,
rDirRect[1].right+stTrav->ix,rDirRect[1].bottom+stTrav->iy);
SelectObject(hDC,hOld);
}

//
// Draw square #2
//
if ((dwSCFlags&SC_REDRAW)||
((bNewDir&(SOUTH|WEST)) != (bDir&(SOUTH|WEST)))
) {
if ((bNewDir&SOUTH)&&(bNewDir&WEST)) {
hOld = SelectObject(hDC,hBlackBrush);
}
else {
hOld = SelectObject(hDC,hWhiteBrush);
}

Rectangle(hDC,rDirRect[2].left+stTrav->ix,rDirRect[2].top+stTrav->iy,
rDirRect[2].right+stTrav->ix,rDirRect[2].bottom+stTrav->iy);
SelectObject(hDC,hOld);
}

//
// Draw square #1
//
if ((dwSCFlags&SC_REDRAW)||
((bNewDir&(SOUTH|EAST)) != (bDir&(SOUTH|EAST)))
) {
if ((bNewDir&SOUTH)&&(bNewDir&EAST)) {
hOld = SelectObject(hDC,hBlackBrush);
}
else {
hOld = SelectObject(hDC,hWhiteBrush);
}

Rectangle(hDC,rDirRect[3].left+stTrav->ix,rDirRect[3].top+stTrav->iy,
rDirRect[3].right+stTrav->ix,rDirRect[3].bottom+stTrav->iy);
SelectObject(hDC,hOld);
}

stTrav->bDir = bNewDir;

DeleteObject(hBlackBrush);
}

DeleteObject(hWhiteBrush);
DeleteObject(hWhitePen);
ReleaseDC(hWndScore,hDC);

return;
}




/*=====================================================================
Function: ScoreWndProc()

Inputs: Standard Windows Proc parms

Outputs: returns success/failure

Abstract:
Handles updating/controlling the score child window
======================================================================*/

LONG FAR PASCAL ScoreWndProc(
HWND hWnd,
UINT Message,
WPARAM wParam,
LPARAM lParam
)
{
PAINTSTRUCT ps;
HDC hDC;
ScoreType FAR *stTrav,FAR *stTrav2;
BOOL bFound,bFoundpt,bIsSelf;
PlayerType FAR *ptTrav;
RECT rScratch;
HPEN hWhitePen,hOldPen;


bIsSelf = (lParam == (LPARAM) ptSelf.ulID);
bFoundpt = FALSE;
ptTrav=&ptPlayers;
while(ptTrav->next != NULL) {
ptTrav = ptTrav->next;
if (ptTrav->ulID == (UINT) lParam) {
bFoundpt = TRUE;
break;
}
}

switch (Message) {
case WM_CREATE:
GetClientRect(hWnd,&rScore);
hDC = GetDC(hWnd);

//
// Kludge: fill out scores with our own entry
//
Scores.ulID = ptSelf.ulID;
Scores.ix = 0;
Scores.iy = 0;
Scores.iScore = ptSelf.iScore;
Scores.bDir = 0xFF;
Scores.next=NULL;

if(!GetTextMetrics(hDC,&tmScoreInfo)) {
MessageBox((HWND)NULL,GetStringRes(IDS_GETTXTMTRCSFAIL),
"ScoreWndProc",MB_ICONEXCLAMATION|MB_APPLMODAL);
}

rBitmapRect.left = 40;
rBitmapRect.right = rBitmapRect.left + 19;
rBitmapRect.top = 5;
rBitmapRect.bottom = rBitmapRect.top+29;

//
// 01
// 23
//
rDirRect[0].left = rDirRect[2].left = 5;
rDirRect[1].left = rDirRect[3].left = rDirRect[0].right = rDirRect[2].right = 20;
rDirRect[1].right = rDirRect[3].right = 35;
rDirRect[0].top = rDirRect[1].top = 5;
rDirRect[2].top = rDirRect[3].top = rDirRect[0].bottom = rDirRect[1].bottom = 20;
rDirRect[2].bottom = rDirRect[3].bottom = 35;

iTextYPos = rBitmapRect.top + (rBitmapRect.bottom - tmScoreInfo.tmHeight - rBitmapRect.top)/2;

ReleaseDC(hWnd,hDC);
break;

case WM_COMMAND:
//
// Note -- we use lParam because we pass WM_COMMAND msg's ourselves.
//
bFound = FALSE;
stTrav = &Scores;
while (stTrav->next != NULL) {
if (stTrav->next->ulID == (unsigned long)lParam) {
bFound = TRUE;
break;
}
stTrav = stTrav->next;
}

switch (wParam) {

case WC_ADDSCORE:
if (!bFound) {
if ((lParam != 0)&&bFoundpt) {
stTrav->next = NewScoreType(ptTrav->ulID,stTrav->ix,
stTrav->iy+35,ptTrav->iScore,0,stTrav->next);
DrawScore(stTrav->next,SC_PIC|SC_NAME|SC_SCORE|SC_DIRECT|SC_REDRAW);
}
else {
MessageBox((HWND)NULL,GetStringRes(IDS_SCOADD0FAIL),"ScoreDlg",
MB_ICONEXCLAMATION|MB_APPLMODAL);
}
}
break;

case WC_UPDATESCORE:
if (bFound&&bFoundpt) {
DrawScore(stTrav->next,SC_SCORE);
}
else {
if (bIsSelf) {
DrawScore(&Scores,SC_SCORE);
}
else {
MessageBox((HWND)NULL,GetStringRes(IDS_CHGSCOFAIL),"ScoreDlg",
MB_ICONEXCLAMATION|MB_APPLMODAL);
}
}
break;

case WC_UPDATEDIRECTION:
//
// if it's a global update
//
if (lParam == 0) {
stTrav = &Scores;
while (stTrav->next != NULL) {
stTrav = stTrav->next;
DrawScore(stTrav,SC_DIRECT);
}
}
else {
if (bFound&&bFoundpt) {
//
// must be updated in routine
//
DrawScore(stTrav->next,SC_DIRECT);
}
else {
MessageBox((HWND)NULL,GetStringRes(IDS_CHGDIRFAIL),"ScoreDlg",
MB_ICONEXCLAMATION|MB_APPLMODAL);
}
}
break;

case WC_DELETESCORE:
if (bFound) {
stTrav2 = stTrav;
stTrav->next = DelScoreType(stTrav->next);
while (stTrav2->next != NULL) {
DrawScore(stTrav2->next,SC_PIC|SC_NAME|SC_SCORE|SC_DIRECT|SC_REDRAW);
stTrav2 = stTrav2->next;
}
rScratch.top = rDirRect[0].top + stTrav->iy + 35;
rScratch.bottom = rDirRect[2].bottom + stTrav->iy + 35;
rScratch.left = 5;
rScratch.right = rScore.right - 5;
hDC = GetDC(hWndScore);
hWhitePen = GetStockObject(WHITE_PEN);
hOldPen = SelectObject(hDC,hWhitePen);
Rectangle(hDC,rScratch.left,rScratch.top,
rScratch.right,rScratch.bottom);
SelectObject(hDC,hOldPen);
DeleteObject(hWhitePen);
ReleaseDC(hWndScore,hDC);
}
else {
MessageBox((HWND)NULL,GetStringRes(IDS_DELSCOFAIL),"ScoreDlg",
MB_ICONEXCLAMATION|MB_APPLMODAL);
}
break;

default:
MessageBox((HWND)NULL,GetStringRes(IDS_BADMSG),"ScoreDlg",
MB_ICONEXCLAMATION|MB_APPLMODAL);
break;
}
break;

case WM_KEYDOWN:
SendMessage(hWndMaze,WM_KEYDOWN,wParam,lParam);
break;

case WM_MOVE:
break;

case WM_SIZE:
//
// BUGBUG -- eventually we'll want to soft-code the now hard-coded rects.
//
break;

case WM_PAINT:
GetClientRect(hWnd,&rScore);
hDC = BeginPaint(hWnd, &ps);
//
// OPTIMIZE -- this can be set to loop through only visible portions
//
stTrav = &Scores;
SetBkMode(hDC, TRANSPARENT);
do {
DrawScore(stTrav,SC_PIC|SC_NAME|SC_SCORE|SC_DIRECT|SC_REDRAW);
stTrav = stTrav->next;
} while (stTrav != NULL);
EndPaint(hWnd, &ps);
break;

case WM_CLOSE:
stTrav = &Scores;
while (stTrav->next != NULL) {
stTrav->next = DelScoreType(stTrav->next);
}
DestroyWindow(hWnd);
break;

default:
return DefWindowProc(hWnd, Message, wParam, lParam);
}

return(0);
}