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 / server.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-15  |  13.7 KB  |  552 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1997 Microsoft Corporation.  All Rights Reserved.
  4.  *
  5.  *  File:       server.cpp
  6.  *  Content:    Slot machine server 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 UINT    MAX_RECORD_LENGTH    = 256;            // max database record size
  19. const DWORD    INDEX_JACKPOT        = 3;            // index of jackpot image
  20. const DWORD    INDEX_SPOILER        = 5;            // index of spoiler image
  21.  
  22. // window messages
  23. const UINT    WM_USER_ADDSTRING = WM_USER + 257;    // add string to log window
  24.  
  25. // structures
  26. typedef struct {
  27.     DWORD    dwBalance;                            // account record from database
  28. } ACCOUNTINFO, *LPACCOUNTINFO;
  29.  
  30. // globals
  31. HWND            ghServerWnd = NULL;                // main window
  32. FILE            *glpFile = NULL;                // database file
  33.  
  34. // prototypes
  35. HRESULT            HandleBalanceRequest(LPDPLAYINFO lpDPInfo, LPMSG_BALANCEREQUEST lpBalance, DPID idTo);
  36. HRESULT            HandleSpinRequest(LPDPLAYINFO lpDPInfo, LPMSG_SPINREQUEST lpBalance, DPID idTo);
  37. void            LogRequest(LPSTR lpszFormat, LPDPACCOUNTDESC lpAccountDesc, DWORD dwValue);
  38. LONG            GetAmountWonOrLost(DWORD dwAmountBet, DWORD dwIndex[]);
  39. FILE*            OpenAccountDB(LPSTR lpszDBName);
  40. void            CloseAccountDB(FILE *lpFile);
  41. BOOL            QueryAccount(FILE *lpFile, LPSTR lpszAccountID, LPACCOUNTINFO lpAccountInfo);
  42. BOOL            UpdateAccount(FILE *lpFile, LPSTR lpszAccountID, LPACCOUNTINFO lpAccountInfo);
  43. HRESULT            GetAccountDesc(LPDPLAYINFO lpDPInfo, DPID idPlayer, LPDPACCOUNTDESC *lplpAccountDesc);
  44.  
  45. BOOL CALLBACK ServerWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  46. {
  47.     static LPDPLAYINFO    lpDPInfo = NULL;
  48.     static UINT            idTimer = 0;
  49.     static FILE            *lpFile = NULL;
  50.     DWORD                dwTextLen;
  51.  
  52.     switch(uMsg)
  53.     {
  54.     case WM_INITDIALOG:
  55.         // save the connection info pointer
  56.         lpDPInfo = (LPDPLAYINFO) lParam;
  57.  
  58.         // store global window
  59.         ghServerWnd = hWnd;
  60.  
  61.         // open account database
  62.         glpFile = OpenAccountDB(gszDatabaseName);
  63.         break;
  64.  
  65.     case WM_DESTROY:
  66.         // stop the timer
  67.         if (idTimer)
  68.         {
  69.             KillTimer(hWnd, idTimer); 
  70.             idTimer = 0;
  71.         }
  72.  
  73.         // close account database
  74.         if (glpFile)
  75.             CloseAccountDB(glpFile);
  76.  
  77.         ghServerWnd = NULL;
  78.         break;
  79.  
  80.     // this is a user-defined message used to add strings to the log window
  81.     case WM_USER_ADDSTRING:
  82.         // get length of text in log window
  83.         dwTextLen = SendDlgItemMessage(hWnd, IDC_LOGEDIT, WM_GETTEXTLENGTH,
  84.                                        (WPARAM) 0, (LPARAM) 0);
  85.  
  86.         // put selection at end
  87.         dwTextLen = SendDlgItemMessage(hWnd, IDC_LOGEDIT, EM_SETSEL,
  88.                                        (WPARAM) dwTextLen, (LPARAM) dwTextLen);
  89.  
  90.         // add string in lParam to log window
  91.         SendDlgItemMessage(hWnd, IDC_LOGEDIT, EM_REPLACESEL,
  92.                             (WPARAM) FALSE, (LPARAM) lParam);
  93.         GlobalFreePtr((LPVOID) lParam);
  94.         break;
  95.  
  96.     case WM_COMMAND:
  97.         switch(LOWORD(wParam))
  98.         {
  99.         case IDCANCEL:
  100.             EndDialog(hWnd, FALSE);
  101.             break;
  102.         }
  103.         break;
  104.     }
  105.  
  106.     // Allow for default processing
  107.     return FALSE;
  108. }
  109.  
  110. void ServerApplicationMessage(LPDPLAYINFO lpDPInfo, LPDPMSG_GENERIC lpMsg, DWORD dwMsgSize,
  111.                               DPID idFrom, DPID idTo)
  112. {
  113.     switch (lpMsg->dwType)
  114.     {
  115.     case BALANCEREQUEST:
  116.  
  117.         HandleBalanceRequest(lpDPInfo, (LPMSG_BALANCEREQUEST)lpMsg, idFrom);
  118.         break;
  119.  
  120.     case SPINREQUEST:
  121.  
  122.         HandleSpinRequest(lpDPInfo, (LPMSG_SPINREQUEST)lpMsg, idFrom);
  123.         break;
  124.  
  125.     default:
  126.         break; 
  127.     }
  128. }
  129.  
  130. void ServerSystemMessage(LPDPLAYINFO lpDPInfo, LPDPMSG_GENERIC lpMsg, DWORD dwMsgSize,
  131.                          DPID idFrom, DPID idTo)
  132. {
  133.     // The body of each case is there so you can set a breakpoint and examine
  134.     // the contents of the message received.
  135.     switch (lpMsg->dwType)
  136.     {
  137.     case DPSYS_CREATEPLAYERORGROUP:
  138.         {
  139.             LPDPMSG_CREATEPLAYERORGROUP lp = (LPDPMSG_CREATEPLAYERORGROUP) lpMsg;
  140.         }
  141.         break;
  142.  
  143.     case DPSYS_DESTROYPLAYERORGROUP:
  144.         {
  145.             LPDPMSG_DESTROYPLAYERORGROUP lp = (LPDPMSG_DESTROYPLAYERORGROUP)lpMsg;
  146.         }
  147.         break;
  148.  
  149.     case DPSYS_ADDPLAYERTOGROUP:
  150.         {
  151.             LPDPMSG_ADDPLAYERTOGROUP lp = (LPDPMSG_ADDPLAYERTOGROUP)lpMsg;
  152.         }
  153.         break;
  154.  
  155.     case DPSYS_DELETEPLAYERFROMGROUP:
  156.         {
  157.             LPDPMSG_DELETEPLAYERFROMGROUP lp = (LPDPMSG_DELETEPLAYERFROMGROUP)lpMsg;
  158.         }
  159.         break;
  160.  
  161.     case DPSYS_SESSIONLOST:
  162.         {
  163.             LPDPMSG_SESSIONLOST lp = (LPDPMSG_SESSIONLOST)lpMsg;
  164.         }
  165.         break;
  166.  
  167.     case DPSYS_HOST:
  168.         {
  169.             LPDPMSG_HOST    lp = (LPDPMSG_HOST)lpMsg;
  170.         }
  171.         break;
  172.  
  173.     case DPSYS_SETPLAYERORGROUPDATA:
  174.         {
  175.             LPDPMSG_SETPLAYERORGROUPDATA lp = (LPDPMSG_SETPLAYERORGROUPDATA)lpMsg;
  176.         }
  177.         break;
  178.  
  179.     case DPSYS_SETPLAYERORGROUPNAME:
  180.         {
  181.             LPDPMSG_SETPLAYERORGROUPNAME lp = (LPDPMSG_SETPLAYERORGROUPNAME)lpMsg;
  182.         }
  183.         break;
  184.  
  185.     case DPSYS_SECUREMESSAGE:
  186.         {
  187.             LPDPMSG_SECUREMESSAGE lp = (LPDPMSG_SECUREMESSAGE)lpMsg;
  188.  
  189.             ServerApplicationMessage(lpDPInfo, (LPDPMSG_GENERIC) lp->lpData, lp->dwDataSize,
  190.                               lp->dpIdFrom, idTo);
  191.  
  192.         }
  193.         break;
  194.     }
  195. }
  196.  
  197. HRESULT HandleBalanceRequest(LPDPLAYINFO lpDPInfo, LPMSG_BALANCEREQUEST lpBalance, DPID idTo)
  198. {
  199.     MSG_BALANCERESPONSE    Msg;
  200.     LPDPACCOUNTDESC        lpAccountDesc = NULL;
  201.     ACCOUNTINFO            AccountInfo;
  202.     HRESULT                hr;
  203.  
  204.     // create balance response message
  205.     ZeroMemory(&Msg, sizeof(MSG_BALANCERESPONSE));
  206.     Msg.dwType = BALANCERESPONSE;
  207.  
  208.     // get account description for this player
  209.     hr = GetAccountDesc(lpDPInfo, idTo, &lpAccountDesc);
  210.     if FAILED(hr)
  211.         goto FAILURE;
  212.  
  213.     // get account information from database using account ID
  214.     if ((glpFile == NULL) ||
  215.         (!QueryAccount(glpFile, lpAccountDesc->lpszAccountIDA, &AccountInfo)))
  216.     {
  217.         hr = DPERR_ACCESSDENIED;
  218.         goto FAILURE;
  219.     }
  220.  
  221.     // return balance from database
  222.     Msg.dwBalance = AccountInfo.dwBalance;
  223.  
  224. FAILURE:
  225.     Msg.hr = hr;
  226.  
  227.     if FAILED(Msg.hr)
  228.         LogRequest("Balance request for \"%s\" failed: 0x%08X\r\n", lpAccountDesc, Msg.hr);
  229.     else
  230.         LogRequest("Balance request for \"%s\" returned $%d\r\n", lpAccountDesc, Msg.dwBalance);
  231.  
  232.     if (lpAccountDesc)
  233.         GlobalFreePtr(lpAccountDesc);
  234.  
  235.     // send the message
  236.     return (lpDPInfo->lpDirectPlay3A->Send(lpDPInfo->dpidPlayer,
  237.                         idTo, SENDFLAGS(lpDPInfo->bIsSecure),
  238.                         &Msg, sizeof(MSG_BALANCERESPONSE)));
  239. }
  240.  
  241. HRESULT HandleSpinRequest(LPDPLAYINFO lpDPInfo, LPMSG_SPINREQUEST lpSpin, DPID idTo)
  242. {
  243.     MSG_SPINRESPONSE    Msg;
  244.     LPDPACCOUNTDESC        lpAccountDesc = NULL;
  245.     ACCOUNTINFO            AccountInfo;
  246.     DWORD                i;
  247.     HRESULT                hr;
  248.  
  249.     // create spin response message
  250.     ZeroMemory(&Msg, sizeof(MSG_SPINRESPONSE));
  251.     Msg.dwType = SPINRESPONSE;
  252.  
  253.     // get account description for this player
  254.     hr = GetAccountDesc(lpDPInfo, idTo, &lpAccountDesc);
  255.     if FAILED(hr)
  256.         goto FAILURE;
  257.  
  258.     // get account information from database using account ID
  259.     if ((glpFile == NULL) ||
  260.         (!QueryAccount(glpFile, lpAccountDesc->lpszAccountIDA, &AccountInfo)))
  261.     {
  262.         hr = DPERR_ACCESSDENIED;
  263.         goto FAILURE;
  264.     }
  265.  
  266.     // bet exceeds balance in database
  267.     if (lpSpin->dwAmountBet > AccountInfo.dwBalance)
  268.     {
  269.         hr = DPERR_UNAVAILABLE;
  270.         goto FAILURE;
  271.     }
  272.  
  273.     // generate new slot settings
  274.     for (i = 0; i < NUMWHEELS; i++)
  275.         Msg.dwIndex[i] = ((DWORD)rand()) % SLOTSPERWHEEL;
  276.  
  277.     // determine amount won or lost
  278.     Msg.dwAmountWonOrLost = GetAmountWonOrLost(lpSpin->dwAmountBet, Msg.dwIndex);
  279.  
  280.     // update account info in database for this player
  281.     AccountInfo.dwBalance += Msg.dwAmountWonOrLost;
  282.  
  283.     if (!UpdateAccount(glpFile, lpAccountDesc->lpszAccountIDA, &AccountInfo))
  284.     {
  285.         hr = DPERR_ACCESSDENIED;
  286.         goto FAILURE;
  287.     }
  288.  
  289.     // send new balance back
  290.     Msg.dwBalance = AccountInfo.dwBalance;
  291.  
  292. FAILURE:
  293.     Msg.hr = hr;
  294.  
  295.     if FAILED(Msg.hr)
  296.         LogRequest("Spin request for \"%s\" failed: 0x%08X\r\n", lpAccountDesc, Msg.hr);
  297.     else
  298.         LogRequest("Spin request for \"%s\" returned $%d\r\n", lpAccountDesc, Msg.dwAmountWonOrLost);
  299.  
  300.     if (lpAccountDesc)
  301.         GlobalFreePtr(lpAccountDesc);
  302.  
  303.     // send the message
  304.     return (lpDPInfo->lpDirectPlay3A->Send(lpDPInfo->dpidPlayer,
  305.                         idTo, SENDFLAGS(lpDPInfo->bIsSecure),
  306.                         &Msg, sizeof(MSG_SPINRESPONSE)));
  307. }
  308.  
  309. void LogRequest(LPSTR lpszFormat, LPDPACCOUNTDESC lpAccountDesc, DWORD dwValue)
  310. {
  311.     LPSTR    lpszStr;
  312.     LPSTR    lpszAccountID;
  313.  
  314.     // make sure we have an account ID
  315.     if (lpAccountDesc == NULL)
  316.         lpszAccountID = "unknown";
  317.     else
  318.         lpszAccountID = lpAccountDesc->lpszAccountIDA;
  319.  
  320.     // create a buffer for the output string, account string and a numeric value
  321.     lpszStr = (LPSTR) GlobalAllocPtr(GHND, strlen(lpszFormat) + strlen(lpszAccountID) + 10);
  322.     if (lpszStr == NULL)
  323.         return;
  324.  
  325.     // format the string to log
  326.     wsprintf(lpszStr, lpszFormat, lpszAccountID, dwValue);
  327.  
  328.     // log it - main wnd proc will dispose of the string
  329.     PostMessage(ghServerWnd, WM_USER_ADDSTRING, (WPARAM) 0, (LPARAM) lpszStr);
  330. }
  331.  
  332. LONG GetAmountWonOrLost(DWORD dwAmountBet, DWORD dwIndex[])
  333. {
  334.     LONG    nMultiplier;
  335.  
  336.     // check for jackpot
  337.     if ((dwIndex[0] == INDEX_JACKPOT) &&
  338.         (dwIndex[1] == INDEX_JACKPOT) &&
  339.         (dwIndex[2] == INDEX_JACKPOT))
  340.     {
  341.         nMultiplier = 100;
  342.     }
  343.  
  344.     // three in a row
  345.     else if ((dwIndex[0] == dwIndex[1]) &&
  346.              (dwIndex[1] == dwIndex[2]))
  347.     {
  348.         nMultiplier = 25;
  349.     }
  350.  
  351.     // first two match
  352.     else if (dwIndex[0] == dwIndex[1])
  353.     {
  354.         nMultiplier = 5;
  355.     }
  356.  
  357.     // you lose!
  358.     else
  359.         nMultiplier = -1;
  360.  
  361.     // any spoiler and you lose
  362.     if ((dwIndex[0] == INDEX_SPOILER) ||
  363.         (dwIndex[1] == INDEX_SPOILER) ||
  364.         (dwIndex[2] == INDEX_SPOILER))
  365.     {
  366.         nMultiplier = -1;
  367.     }
  368.  
  369.     // return amount won or lost
  370.     return (dwAmountBet * nMultiplier);
  371. }
  372.  
  373. FILE* OpenAccountDB(LPSTR lpszDBName)
  374. {
  375.     FILE    *lpFile;
  376.  
  377.     lpFile = fopen(lpszDBName, "r+b");
  378.  
  379.     return (lpFile);
  380. }
  381.  
  382. void CloseAccountDB(FILE *lpFile)
  383. {
  384.     fclose(lpFile);
  385. }
  386.  
  387. BOOL GetRecord(FILE *lpFile, LPSTR lpszKey, LPSTR lpszRecord)
  388. {
  389.     rewind(lpFile);
  390.     while (fgets(lpszRecord, MAX_RECORD_LENGTH, lpFile))
  391.     {
  392.         _strupr(lpszRecord);
  393.         if (!strncmp(lpszRecord, lpszKey, strlen(lpszKey)))
  394.             return (TRUE);
  395.     }
  396.  
  397.     return (FALSE);
  398. }
  399.  
  400. BOOL PutRecord(FILE *lpFile, LPSTR lpszKey, LPSTR lpszRecord)
  401. {
  402.     CHAR    szLine[MAX_RECORD_LENGTH];
  403.     DWORD    dwRecordIndex;
  404.  
  405.     rewind(lpFile);
  406.     dwRecordIndex = 0;
  407.     while (fgets(szLine, MAX_RECORD_LENGTH, lpFile))
  408.     {
  409.         _strupr(szLine);
  410.         if (!strncmp(szLine, lpszKey, strlen(lpszKey)))
  411.         {
  412.             fseek(lpFile, dwRecordIndex, SEEK_SET);
  413.             fputs(lpszRecord, lpFile);
  414.             return (TRUE);
  415.         }
  416.         dwRecordIndex += strlen(szLine);
  417.     }
  418.  
  419.     return (FALSE);
  420. }
  421.  
  422. BOOL QueryAccount(FILE *lpFile, LPSTR lpszAccountID, LPACCOUNTINFO lpAccountInfo)
  423. {
  424.     CHAR    szBuffer[MAX_RECORD_LENGTH];
  425.     CHAR    *lpToken;
  426.  
  427.     if (!GetRecord(lpFile, lpszAccountID, szBuffer))
  428.     {
  429.         return FALSE;
  430.     }
  431.  
  432.     lpToken = strtok(szBuffer, ",");
  433.     if (lpToken)
  434.     {
  435.         lpToken = strtok(NULL, "\n");
  436.         if (lpToken)
  437.         {
  438.             lpAccountInfo->dwBalance = atoi(lpToken);
  439.         }
  440.     }
  441.  
  442.     return TRUE;
  443. }
  444.  
  445. BOOL UpdateAccount(FILE *lpFile, LPSTR lpszAccountID, LPACCOUNTINFO lpAccountInfo)
  446. {
  447.     CHAR    szBuffer[MAX_RECORD_LENGTH];
  448.  
  449.     if (!GetRecord(lpFile, lpszAccountID, szBuffer))
  450.     {
  451.         return FALSE;
  452.     }
  453.  
  454.     sprintf(szBuffer, "%s,%8d", lpszAccountID, lpAccountInfo->dwBalance);
  455.     return (PutRecord(lpFile, lpszAccountID, szBuffer));
  456. }
  457.  
  458. HRESULT GetSecureAccountDesc(LPDPLAYINFO lpDPInfo, DPID idPlayer, LPDPACCOUNTDESC *lplpAccountDesc)
  459. {
  460.     LPDPACCOUNTDESC        lpAccountDesc = NULL;
  461.     DWORD                dwAccountDescSize;
  462.     HRESULT                hr;
  463.  
  464.     // get size of account description
  465.     hr = lpDPInfo->lpDirectPlay3A->GetPlayerAccount(idPlayer, 0,
  466.                                     NULL, &dwAccountDescSize);
  467.     if (hr != DPERR_BUFFERTOOSMALL)
  468.         goto FAILURE;
  469.  
  470.     // make room for it
  471.     lpAccountDesc = (LPDPACCOUNTDESC) GlobalAllocPtr(GHND, dwAccountDescSize);
  472.     if (lpAccountDesc == NULL)
  473.     {
  474.         hr = DPERR_OUTOFMEMORY;
  475.         goto FAILURE;
  476.     }
  477.  
  478.     // get the account description for this player
  479.     hr = lpDPInfo->lpDirectPlay3A->GetPlayerAccount(idPlayer, 0,
  480.                                     lpAccountDesc, &dwAccountDescSize);
  481.     if FAILED(hr)
  482.         goto FAILURE;
  483.  
  484.     // return account description
  485.     _strupr(lpAccountDesc->lpszAccountIDA);
  486.     *lplpAccountDesc = lpAccountDesc;
  487.     lpAccountDesc = NULL;
  488.  
  489. FAILURE:
  490.     if (lpAccountDesc)
  491.         GlobalFreePtr(lpAccountDesc);
  492.  
  493.     return (hr);
  494. }
  495.  
  496. HRESULT GetUnsecureAccountDesc(LPDPLAYINFO lpDPInfo, DPID idPlayer, LPDPACCOUNTDESC *lplpAccountDesc)
  497. {
  498.     LPDPACCOUNTDESC        lpAccountDesc = NULL;
  499.     DWORD                dwAccountDescSize;
  500.     LPDPNAME            lpName;
  501.     HRESULT                hr;
  502.  
  503.     // get size of player name
  504.     hr = lpDPInfo->lpDirectPlay3A->GetPlayerName(idPlayer,
  505.                                     NULL, &dwAccountDescSize);
  506.     if (hr != DPERR_BUFFERTOOSMALL)
  507.         goto FAILURE;
  508.  
  509.     // make room for it
  510.     lpAccountDesc = (LPDPACCOUNTDESC) GlobalAllocPtr(GHND, sizeof(DPACCOUNTDESC) + dwAccountDescSize);
  511.     if (lpAccountDesc == NULL)
  512.     {
  513.         hr = DPERR_OUTOFMEMORY;
  514.         goto FAILURE;
  515.     }
  516.  
  517.     // get the player name
  518.     lpName = (LPDPNAME) (((LPSTR)lpAccountDesc) + sizeof(DPACCOUNTDESC));
  519.     hr = lpDPInfo->lpDirectPlay3A->GetPlayerName(idPlayer,
  520.                                     lpName, &dwAccountDescSize);
  521.     if FAILED(hr)
  522.         goto FAILURE;
  523.  
  524.     // return account description
  525.     lpAccountDesc->lpszAccountIDA = lpName->lpszShortNameA;
  526.     _strupr(lpAccountDesc->lpszAccountIDA);
  527.     *lplpAccountDesc = lpAccountDesc;
  528.     lpAccountDesc = NULL;
  529.  
  530. FAILURE:
  531.     if (lpAccountDesc)
  532.         GlobalFreePtr(lpAccountDesc);
  533.  
  534.     return (hr);
  535. }
  536.  
  537. HRESULT GetAccountDesc(LPDPLAYINFO lpDPInfo, DPID idPlayer, LPDPACCOUNTDESC *lplpAccountDesc)
  538. {
  539.     HRESULT        hr;
  540.  
  541.     if (lpDPInfo->bIsSecure)
  542.     {
  543.         hr = GetSecureAccountDesc(lpDPInfo, idPlayer, lplpAccountDesc);
  544.     }
  545.     else
  546.     {
  547.         hr = GetUnsecureAccountDesc(lpDPInfo, idPlayer, lplpAccountDesc);
  548.     }
  549.  
  550.     return (hr);
  551. }
  552.