home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / dpslots / client.cpp next >
C/C++ Source or Header  |  1997-07-14  |  15KB  |  531 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1997 Microsoft Corporation.  All Rights Reserved.
  4.  *
  5.  *  File:       client.cpp
  6.  *  Content:    Slot machine client using DirectPlay.
  7.  *
  8.  ***************************************************************************/
  9.  
  10. #include <windows.h>
  11. #include <windowsx.h>
  12. #include <stdio.h>
  13.  
  14. #include "dpslots.h"
  15. #include "resource.h"
  16.  
  17. // constants
  18. const DWORD SLOTWIDTH            = 110;            // width of slot
  19. const DWORD SLOTHEIGHT            = 119;            // height of slot
  20. const DWORD SLOTBORDER            = 9;            // space between slots
  21. const DWORD REVSPERSECOND        = 1;            // no. revolutions per second
  22. const DWORD PIXELSPERSLOT        = SLOTHEIGHT - SLOTBORDER;        // no. vertical pixels per slot
  23. const DWORD PIXELSPERREV        = PIXELSPERSLOT * SLOTSPERWHEEL;// no. vertical pixels drawn per revolution
  24. const DWORD PIXELSPERSECOND        = PIXELSPERREV * REVSPERSECOND;    // no. vertical pixels drawn per second
  25. const UINT    TIMERID                = 1;            // timer ID to use
  26. const UINT    TIMERINTERVAL        = 50;            // timer interval
  27. const UINT    MAXSTRING            = 200;            // max size of a string
  28.  
  29. // window messages
  30. const UINT    WM_USER_UPDATEBALANCE = WM_USER + BALANCERESPONSE;
  31. const UINT    WM_USER_STARTSPINNING = WM_USER + SPINRESPONSE;
  32.  
  33. // structures
  34. typedef struct {
  35.     DWORD    dwIndex;                            // index of wheel slot to show
  36.     DWORD    dwStartTicks;                        // time wheel started spinning
  37.     DWORD    dwDuration;                            // duration wheel should spin
  38. } WHEELINFO, *LPWHEELINFO;
  39.  
  40. // globals
  41. HWND            ghClientWnd = NULL;                // main window
  42.  
  43. // prototypes
  44. HRESULT            SendBalanceRequest(LPDPLAYINFO lpDPInfo);
  45. HRESULT            SendSpinRequest(LPDPLAYINFO lpDPInfo, DWORD dwAmountBet);
  46. void            DrawWheels(LPWHEELINFO lpWheels, HBITMAP hWheelBitmap,
  47.                            HDC hDC, LPRECT lpBoundsRect);
  48. void            StartSpinning(LPWHEELINFO lpWheels);
  49. BOOL            SpinWheels(HWND hWnd, LPWHEELINFO lpWheels, HBITMAP hWheelBitmap);
  50.  
  51. BOOL CALLBACK ClientWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  52. {
  53.     static LPDPLAYINFO            lpDPInfo = NULL;
  54.     static UINT                    idTimer = 0;
  55.     static HBITMAP                hWheelBitmap = NULL;
  56.     static WHEELINFO            WheelInfo[NUMWHEELS];
  57.     static MSG_SPINRESPONSE        SpinResponse;
  58.     CHAR                        szStr[MAXSTRING];
  59.     DWORD                        i;
  60.     DWORD                        dwAmountBet;
  61.  
  62.     switch(uMsg)
  63.     {
  64.     case WM_INITDIALOG:
  65.         // save the connection info pointer
  66.         lpDPInfo = (LPDPLAYINFO) lParam;
  67.  
  68.         // store global window
  69.         ghClientWnd = hWnd;
  70.  
  71.         // get slots bitmap
  72.         hWheelBitmap = LoadBitmap(ghInstance, MAKEINTRESOURCE(IDB_SLOTSBITMAP));
  73.  
  74.         // initialize slots
  75.         for (i = 0; i < NUMWHEELS; i++)
  76.             WheelInfo[i].dwIndex = ((DWORD)rand()) % SLOTSPERWHEEL;
  77.  
  78.         // get starting balance
  79.         SendBalanceRequest(lpDPInfo);
  80.         break;
  81.  
  82.     case WM_DESTROY:
  83.         // stop the timer
  84.         if (idTimer)
  85.         {
  86.             KillTimer(hWnd, idTimer); 
  87.             idTimer = 0;
  88.         }
  89.  
  90.         // free the bitmap handle
  91.         if (hWheelBitmap)
  92.         {
  93.             DeleteObject(hWheelBitmap);
  94.             hWheelBitmap = NULL;
  95.         }
  96.         ghClientWnd = NULL;
  97.         break;
  98.  
  99.     case WM_USER_UPDATEBALANCE:
  100.  
  101.         // balance is in lParam
  102.         sprintf(szStr, "$%4d", lParam);
  103.  
  104.         // display new balance
  105.         SetDlgItemText(hWnd, IDC_EDIT_BALANCE, szStr);
  106.         break;
  107.  
  108.     case WM_USER_STARTSPINNING:
  109.  
  110.         // copy spin response message from lParam
  111.         SpinResponse = *((LPMSG_SPINRESPONSE) lParam);
  112.         GlobalFreePtr((LPVOID) lParam);    // free memory
  113.  
  114.         // check for valid spin
  115.         if FAILED(SpinResponse.hr)
  116.         {
  117.             SetDlgItemText(hWnd, IDC_RESULTEDIT, "You don't have enough money!");
  118.         }
  119.         else
  120.         {
  121.             // copy slot settings specified by server
  122.             for (i = 0; i < NUMWHEELS; i++)
  123.                 WheelInfo[i].dwIndex = SpinResponse.dwIndex[i];
  124.  
  125.             // clear win or lose
  126.             SetDlgItemText(hWnd, IDC_RESULTEDIT, "");
  127.  
  128.             // start things spinning
  129.             StartSpinning(WheelInfo);
  130.             idTimer = SetTimer(hWnd, TIMERID, TIMERINTERVAL, NULL);
  131.  
  132.             // disable spin button while spinning
  133.             EnableDlgButton(hWnd, IDC_SPINBUTTON, FALSE);
  134.         }
  135.         break;
  136.  
  137.     case WM_TIMER:
  138.         // readraw any spinning wheels
  139.         if (!SpinWheels(hWnd, WheelInfo, hWheelBitmap))
  140.         {
  141.             KillTimer(hWnd, idTimer); 
  142.             idTimer = 0;
  143.  
  144.             // display amount won or lost
  145.             if (SpinResponse.dwAmountWonOrLost > 0)
  146.             {
  147.                 sprintf(szStr,"You win $%d!", SpinResponse.dwAmountWonOrLost);
  148.                 PlaySound(MAKEINTRESOURCE(IDR_WINWAVE), ghInstance, SND_ASYNC | SND_RESOURCE);
  149.             }
  150.             else if (SpinResponse.dwAmountWonOrLost < 0)
  151.             {
  152.                 sprintf(szStr,"You lose $%d!", -SpinResponse.dwAmountWonOrLost);
  153.                 PlaySound(MAKEINTRESOURCE(IDR_LOSEWAVE), ghInstance, SND_ASYNC | SND_RESOURCE);
  154.             }
  155.             else
  156.             {
  157.                 strcpy(szStr, "");
  158.             }
  159.  
  160.             // display win or loss
  161.             SetDlgItemText(hWnd, IDC_RESULTEDIT, szStr);
  162.  
  163.             PostMessage(hWnd, WM_USER_UPDATEBALANCE, (WPARAM) 0, (LPARAM) SpinResponse.dwBalance);
  164.  
  165.             // enable spin button again
  166.             EnableDlgButton(hWnd, IDC_SPINBUTTON, TRUE);
  167.         }
  168.         break;
  169.  
  170.     case WM_DRAWITEM:
  171.         {
  172.             DRAWITEMSTRUCT    *diInfo;
  173.  
  174.             diInfo = (DRAWITEMSTRUCT *) lParam;
  175.  
  176.             switch (diInfo->CtlID)
  177.             {
  178.             case IDC_SLOTS:
  179.                 if (diInfo->itemAction == ODA_DRAWENTIRE)
  180.                 {
  181.                     DrawWheels(WheelInfo, hWheelBitmap, diInfo->hDC, &diInfo->rcItem);
  182.                 }
  183.                 break;
  184.             }
  185.         }
  186.         break;
  187.  
  188.     case WM_COMMAND:
  189.         switch(LOWORD(wParam))
  190.         {
  191.         case IDC_SPINBUTTON:
  192.             // find out how much was bet
  193.             dwAmountBet = 0;
  194.  
  195.             // one dollar
  196.             if (DlgItemIsChecked(hWnd, IDC_BET1CHECK))
  197.                 dwAmountBet += 1;
  198.  
  199.             // five dollars
  200.             if (DlgItemIsChecked(hWnd, IDC_BET2CHECK))
  201.                 dwAmountBet += 5;
  202.  
  203.             // ten dollars
  204.             if (DlgItemIsChecked(hWnd, IDC_BET3CHECK))
  205.                 dwAmountBet += 10;
  206.  
  207.             // ask server for results of spin using this bet
  208.             SendSpinRequest(lpDPInfo, dwAmountBet);            
  209.             break;
  210.  
  211.         case IDCANCEL:
  212.             EndDialog(hWnd, FALSE);
  213.             break;
  214.         }
  215.         break;
  216.     }
  217.  
  218.     // Allow for default processing
  219.     return FALSE;
  220. }
  221.  
  222. void ClientApplicationMessage(LPDPLAYINFO lpDPInfo, LPDPMSG_GENERIC lpMsg, DWORD dwMsgSize,
  223.                               DPID idFrom, DPID idTo)
  224. {
  225.     switch (lpMsg->dwType)
  226.     {
  227.     case BALANCERESPONSE:
  228.         {
  229.             LPMSG_BALANCERESPONSE lpBalance = (LPMSG_BALANCERESPONSE)lpMsg;
  230.  
  231.              PostMessage(ghClientWnd, WM_USER_UPDATEBALANCE, (WPARAM) 0, (LPARAM) lpBalance->dwBalance);
  232.         }
  233.         break;
  234.  
  235.     case SPINRESPONSE:
  236.         {
  237.             LPMSG_SPINRESPONSE lpSpin = (LPMSG_SPINRESPONSE)lpMsg;
  238.             LPMSG_SPINRESPONSE lpSpinCopy;
  239.  
  240.             // make a copy of the message so we can pass it to the wndproc
  241.             lpSpinCopy = (LPMSG_SPINRESPONSE) GlobalAllocPtr(GHND, sizeof(MSG_SPINRESPONSE));
  242.             if (lpSpinCopy == NULL)
  243.                 break;
  244.  
  245.             *lpSpinCopy = *lpSpin;
  246.  
  247.             PostMessage(ghClientWnd, WM_USER_STARTSPINNING, (WPARAM) 0, (LPARAM) lpSpinCopy);
  248.         }
  249.         break;
  250.  
  251.     default:
  252.         break; 
  253.     }
  254. }
  255.  
  256. void ClientSystemMessage(LPDPLAYINFO lpDPInfo, LPDPMSG_GENERIC lpMsg, DWORD dwMsgSize,
  257.                          DPID idFrom, DPID idTo)
  258. {
  259.     // The body of each case is there so you can set a breakpoint and examine
  260.     // the contents of the message received.
  261.     switch (lpMsg->dwType)
  262.     {
  263.     case DPSYS_CREATEPLAYERORGROUP:
  264.         {
  265.             LPDPMSG_CREATEPLAYERORGROUP lp = (LPDPMSG_CREATEPLAYERORGROUP) lpMsg;
  266.         }
  267.         break;
  268.  
  269.     case DPSYS_DESTROYPLAYERORGROUP:
  270.         {
  271.             LPDPMSG_DESTROYPLAYERORGROUP lp = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg;
  272.         }
  273.         break;
  274.  
  275.     case DPSYS_ADDPLAYERTOGROUP:
  276.         {
  277.             LPDPMSG_ADDPLAYERTOGROUP lp = (LPDPMSG_ADDPLAYERTOGROUP)lpMsg;
  278.         }
  279.         break;
  280.  
  281.     case DPSYS_DELETEPLAYERFROMGROUP:
  282.         {
  283.             LPDPMSG_DELETEPLAYERFROMGROUP lp = (LPDPMSG_DELETEPLAYERFROMGROUP)lpMsg;
  284.         }
  285.         break;
  286.  
  287.     case DPSYS_SESSIONLOST:
  288.         {
  289.             LPDPMSG_SESSIONLOST lp = (LPDPMSG_SESSIONLOST)lpMsg;
  290.         }
  291.         break;
  292.  
  293.     case DPSYS_HOST:
  294.         {
  295.             LPDPMSG_HOST    lp = (LPDPMSG_HOST)lpMsg;
  296.         }
  297.         break;
  298.  
  299.     case DPSYS_SETPLAYERORGROUPDATA:
  300.         {
  301.             LPDPMSG_SETPLAYERORGROUPDATA lp = (LPDPMSG_SETPLAYERORGROUPDATA)lpMsg;
  302.         }
  303.         break;
  304.  
  305.     case DPSYS_SETPLAYERORGROUPNAME:
  306.         {
  307.             LPDPMSG_SETPLAYERORGROUPNAME lp = (LPDPMSG_SETPLAYERORGROUPNAME)lpMsg;
  308.         }
  309.         break;
  310.  
  311.     case DPSYS_SECUREMESSAGE:
  312.         {
  313.             LPDPMSG_SECUREMESSAGE lp = (LPDPMSG_SECUREMESSAGE)lpMsg;
  314.  
  315.             ClientApplicationMessage(lpDPInfo, (LPDPMSG_GENERIC) lp->lpData, lp->dwDataSize,
  316.                               lp->dpIdFrom, idTo);
  317.  
  318.         }
  319.         break;
  320.     }
  321. }
  322.  
  323. HRESULT SendBalanceRequest(LPDPLAYINFO lpDPInfo)
  324. {
  325.     MSG_BALANCEREQUEST    Msg;
  326.  
  327.     ZeroMemory(&Msg, sizeof(MSG_BALANCEREQUEST));
  328.     Msg.dwType = BALANCEREQUEST;
  329.  
  330.     return (lpDPInfo->lpDirectPlay3A->Send(lpDPInfo->dpidPlayer,
  331.                         DPID_SERVERPLAYER, SENDFLAGS(lpDPInfo->bIsSecure),
  332.                         &Msg, sizeof(MSG_BALANCEREQUEST)));
  333. }
  334.  
  335. HRESULT SendSpinRequest(LPDPLAYINFO lpDPInfo, DWORD dwAmountBet)
  336. {
  337.     MSG_SPINREQUEST        Msg;
  338.  
  339.     ZeroMemory(&Msg, sizeof(MSG_SPINREQUEST));
  340.     Msg.dwType = SPINREQUEST;
  341.     Msg.dwAmountBet = dwAmountBet;
  342.  
  343.     return (lpDPInfo->lpDirectPlay3A->Send(lpDPInfo->dpidPlayer,
  344.                         DPID_SERVERPLAYER, SENDFLAGS(lpDPInfo->bIsSecure),
  345.                         &Msg, sizeof(MSG_SPINREQUEST)));
  346. }
  347.  
  348. #define RECTWIDTH(lpRect)     ((lpRect)->right - (lpRect)->left)
  349. #define RECTHEIGHT(lpRect)    ((lpRect)->bottom - (lpRect)->top)
  350.  
  351. BOOL PaintBitmap(HDC hDC, LPRECT lpDCRect, HBITMAP hDDB,  LPRECT lpDDBRect)
  352. {
  353.     HDC         hMemDC;            // Handle to memory DC
  354.     HBITMAP     hOldBitmap;        // Handle to previous bitmap
  355.     BOOL        bSuccess = FALSE;  // Success/fail flag
  356.  
  357.     // Create a memory DC
  358.  
  359.     hMemDC = CreateCompatibleDC(hDC);
  360.  
  361.     // If this failed, return FALSE
  362.  
  363.     if (!hMemDC)
  364.         return FALSE;
  365.  
  366.     // Select bitmap into the memory DC
  367.  
  368.     hOldBitmap = (HBITMAP) SelectObject (hMemDC, hDDB);
  369.  
  370.     // Make sure to use the stretching mode best for color pictures
  371.  
  372.     SetStretchBltMode (hDC, COLORONCOLOR);
  373.  
  374.     // Determine whether to call StretchBlt() or BitBlt()
  375.     if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDDBRect)) &&
  376.             (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDDBRect)))
  377.         bSuccess = BitBlt(hDC, lpDCRect->left, lpDCRect->top,
  378.                 lpDCRect->right - lpDCRect->left,
  379.                 lpDCRect->bottom - lpDCRect->top, hMemDC, lpDDBRect->left,
  380.                 lpDDBRect->top, SRCCOPY);
  381.     else
  382.         bSuccess = StretchBlt(hDC, lpDCRect->left,  lpDCRect->top, 
  383.                 lpDCRect->right - lpDCRect->left,
  384.                 lpDCRect->bottom - lpDCRect->top, hMemDC, lpDDBRect->left, 
  385.                 lpDDBRect->top,  lpDDBRect->right - lpDDBRect->left,
  386.                 lpDDBRect->bottom - lpDDBRect->top, SRCCOPY);
  387.  
  388.     // Clean up
  389.  
  390.     SelectObject(hMemDC, hOldBitmap);
  391.  
  392.     DeleteDC(hMemDC);
  393.  
  394.     // Return with success/fail flag
  395.  
  396.     return bSuccess;
  397. }
  398.  
  399. void DrawWheels(LPWHEELINFO lpWheels, HBITMAP hWheelBitmap, HDC hDC, LPRECT lpBoundsRect)
  400. {
  401.     RECT            rectDC, rectSlot;
  402.     DWORD            dwWidth, dwHeight, dwXOffset, dwYOffset;
  403.     DWORD            i;
  404.  
  405.     if (hWheelBitmap == NULL)
  406.         return;
  407.  
  408.     dwWidth = lpBoundsRect->right - lpBoundsRect->left;
  409.     dwHeight = lpBoundsRect->bottom - lpBoundsRect->top;
  410.  
  411.     dwXOffset = (dwWidth - (SLOTWIDTH * NUMWHEELS)) / (NUMWHEELS + 1);
  412.     dwYOffset = (dwHeight - SLOTHEIGHT) / 2;
  413.  
  414.     SetRect(&rectDC, dwXOffset, dwYOffset,
  415.             dwXOffset + SLOTWIDTH, dwYOffset + SLOTHEIGHT);
  416.  
  417.     for (i = 0; i < NUMWHEELS; i++)
  418.     {
  419.         SetRect(&rectSlot, 0, 0, SLOTWIDTH, SLOTHEIGHT);
  420.         OffsetRect(&rectSlot, 0, lpWheels[i].dwIndex * PIXELSPERSLOT);
  421.  
  422.         PaintBitmap(hDC, &rectDC, hWheelBitmap, &rectSlot);
  423.  
  424.         OffsetRect(&rectDC, SLOTWIDTH + dwXOffset, 0);
  425.     }
  426. }
  427.  
  428. void StartSpinning(LPWHEELINFO lpWheels)
  429. {
  430.     DWORD    i;
  431.  
  432.     for (i = 0; i < NUMWHEELS; i++)
  433.     {
  434.         lpWheels[i].dwStartTicks = GetTickCount();
  435.         lpWheels[i].dwStartTicks -= lpWheels[i].dwIndex * PIXELSPERSLOT * 1000 / PIXELSPERREV;
  436.         lpWheels[i].dwDuration = 1000 * (i + 1) + 1000;
  437.     }
  438. }
  439.  
  440. BOOL SpinWheels(HWND hWnd, LPWHEELINFO lpWheels, HBITMAP hWheelBitmap)
  441. {
  442.     HDC                hDC;
  443.     RECT            rectBounds;
  444.     LPRECT            lpBoundsRect;
  445.     RECT            rectDC, rectSlot;
  446.     DWORD            dwWidth, dwHeight, dwXOffset, dwYOffset, dwYStart;
  447.     DWORD            i, dwTicks, dwStoppedCount;
  448.  
  449.     if (hWheelBitmap == NULL)
  450.         return (FALSE);
  451.  
  452.     hDC = GetWindowDC(GetDlgItem(hWnd, IDC_SLOTS));
  453.     if (hDC == NULL)
  454.         return (FALSE);
  455.  
  456.     if (!GetWindowRect(GetDlgItem(hWnd, IDC_SLOTS), &rectBounds))
  457.         return (FALSE);
  458.  
  459.     lpBoundsRect = &rectBounds;
  460.  
  461.     dwWidth = lpBoundsRect->right - lpBoundsRect->left;
  462.     dwHeight = lpBoundsRect->bottom - lpBoundsRect->top;
  463.  
  464.     dwXOffset = (dwWidth - (SLOTWIDTH * NUMWHEELS)) / (NUMWHEELS + 1);
  465.     dwYOffset = (dwHeight - SLOTHEIGHT) / 2;
  466.  
  467.     SetRect(&rectDC, dwXOffset, dwYOffset,
  468.             dwXOffset + SLOTWIDTH, dwYOffset + SLOTHEIGHT);
  469.  
  470.     dwStoppedCount = 0;
  471.     for (i = 0; i < NUMWHEELS; i++)
  472.     {
  473.         if (lpWheels[i].dwDuration == 0)
  474.         {
  475.             dwStoppedCount++;
  476.         }
  477.         else
  478.         {
  479.             dwTicks = GetTickCount() - lpWheels[i].dwStartTicks;
  480.             dwYStart = (dwTicks * PIXELSPERSECOND) / 1000;
  481.             dwYStart %= PIXELSPERREV;
  482.  
  483.             if (dwTicks >= lpWheels[i].dwDuration)
  484.             {
  485. //                lpWheels[i].value = ((dwYStart + (PIXELSPERSLOT - 1)) / PIXELSPERSLOT) % SLOTSPERWHEEL;
  486.  
  487.                 SetRect(&rectSlot, 0, 0, SLOTWIDTH, SLOTHEIGHT);
  488.                 OffsetRect(&rectSlot, 0, lpWheels[i].dwIndex * PIXELSPERSLOT);
  489.                 PaintBitmap(hDC, &rectDC, hWheelBitmap, &rectSlot);
  490.  
  491.                 lpWheels[i].dwDuration = 0;
  492.                 if (dwStoppedCount == (NUMWHEELS - 1))
  493.                     PlaySound(MAKEINTRESOURCE(IDR_STOPWAVE), ghInstance, SND_RESOURCE);
  494.                 else
  495.                     PlaySound(MAKEINTRESOURCE(IDR_STOPWAVE), ghInstance, SND_ASYNC | SND_RESOURCE);
  496.             }
  497.             else
  498.             {
  499.                 SetRect(&rectSlot, 0, 0, SLOTWIDTH, SLOTHEIGHT);
  500.                 OffsetRect(&rectSlot, 0, dwYStart);
  501.                 if (rectSlot.bottom > PIXELSPERREV)
  502.                 {
  503.                     RECT    rectSlotTmp, rectDCTmp;
  504.                     DWORD    height;
  505.  
  506.                     // copy from bottom end of bitmap
  507.                     height = PIXELSPERREV - rectSlot.top;
  508.                     rectSlotTmp = rectSlot;
  509.                     rectSlotTmp.bottom = rectSlotTmp.top + height;
  510.                     rectDCTmp = rectDC;
  511.                     rectDCTmp.bottom = rectDCTmp.top + height;
  512.                     PaintBitmap(hDC, &rectDCTmp, hWheelBitmap, &rectSlotTmp);
  513.  
  514.                     height = rectSlot.bottom - PIXELSPERREV;
  515.                     rectSlotTmp = rectSlot;
  516.                     rectSlotTmp.top = 0;
  517.                     rectSlotTmp.bottom = height;
  518.                     rectDCTmp = rectDC;
  519.                     rectDCTmp.top = rectDCTmp.bottom - height;
  520.                     PaintBitmap(hDC, &rectDCTmp, hWheelBitmap, &rectSlotTmp);
  521.                 }
  522.                 else
  523.                     PaintBitmap(hDC, &rectDC, hWheelBitmap, &rectSlot);
  524.             }
  525.         }
  526.         OffsetRect(&rectDC, SLOTWIDTH + dwXOffset, 0);
  527.     }
  528.  
  529.     return (dwStoppedCount != NUMWHEELS);
  530. }
  531.