home *** CD-ROM | disk | FTP | other *** search
/ The Best of Select: Games 3 / cd.iso / os2 / rollball / thread.c < prev    next >
Text File  |  1992-07-16  |  20KB  |  414 lines

  1. /***********************************************************************\
  2.  *                                Tread.c                              *
  3. \***********************************************************************/
  4.  
  5. #define         INCL_DOSPROCESS
  6. #define         INCL_DOSMISC
  7. #define         INCL_PM
  8. #define         QSV_MS_COUNT 14
  9.  
  10. #include        <os2.h>                 /* PM header files */
  11. #include        <stdlib.h>
  12. #include        "Error.h"
  13. #include        "RollBall.h"
  14.  
  15. void    Put_Random_Field(void);
  16. void    Clear_Random_Field(void);
  17. void    Draw_Bitmap(ULONG Bitmap,ULONG mode,ULONG x,ULONG y);
  18.  
  19. HAB             habDT;                  /* Anchor block handle for drawing thread */
  20. HPS             hpsDT;                  /* Handle of presentation space for window */
  21. QMSG            qmsqDT;                 /* Message queue for drawing thread */
  22. HMQ             hmqDT;                  /* Message queue handle for drawing thread
  23.                                            message queue */
  24. BOOL            runRB;                  /* RollBall should roll indicator */
  25.                                         /* The position of RollBall RB_PosX and RB_PosY
  26.                                            point to the lower left corner of the RollBall
  27.                                            bitmap. To test for hits against the border, the
  28.                                            size of the bitmap is added. To test against
  29.                                            deflectors and points, the lower left edge of
  30.                                            both symbols must match, which is RB_PosX*RB_SIZE
  31.                                            and RB_PosY*RB_SIZE */
  32. LONG            RB_PosX;                /* Position of RollBall on X-axis */
  33. LONG            RB_PosY;                /* Position of RollBall on Y-axis */
  34.                                         /* Direction where RollBall is rolling to, the
  35.                                            direction changes, as RollBall hits the border,
  36.                                            or the deflectors / and \, hitting a point only
  37.                                            increases the score in the field RB_Point[0] */
  38. typedef enum {RIGHT,UP,LEFT,DOWN} _RB_Dir;
  39. _RB_Dir         RB_Dir;
  40. ULONG           RB_Array[RB_X][RB_Y];   /* The playing ground of RollBall is an array
  41.                                            of 40x25, whereby the surrounding fields
  42.                                            are the playing ground borders. The array
  43.                                            can be: */
  44. #define         RB_EMPTY    0           /*      An empty field */
  45. #define         RB_BP       1           /*      The blue 1 point */
  46. #define         RB_GP       2           /*      The green 5 points */
  47. #define         RB_MP       3           /*      The magenta 10 points */
  48. #define         RB_VP       4           /*      The violett 20 points */
  49. #define         RB_LX       5           /*      The left (\) deflector */
  50. #define         RB_RX       6           /*      The right (/) deflector */
  51. #define         RB_HOLE     7           /*      The hole, that kills a player */
  52. #define         RB_RB       8           /*      The RollBall */
  53. #define         RB_BORDER   9           /*      The surrounding border */
  54.  
  55.                                         /* The scoring array, where the first position 
  56.                                            contains all points earned up to now */
  57. ULONG           RB_Point[5]={0,1,5,10,20};
  58.                                         /* For the following handles, the first field
  59.                                            is unused (the field RB_Point[0]) ! */
  60. HDC             hdcRB[RB_BORDER];       /* For each symbol prepare a device context */
  61. HPS             hpsRB[RB_BORDER];       /* For each symbol prepare a presentation space */
  62. HBITMAP         hbmRB[RB_BORDER];       /* For each symbol prepare a bitmap handle */
  63.                                         /* For each symbol prepare device setup */
  64. DEVOPENSTRUC    dcRB[RB_BORDER]={NULL,"DISPLAY",NULL,NULL,NULL,NULL,NULL,NULL,NULL};
  65.                                         /* Size of each symbol presentation space */
  66. SIZEL           sizelRB={RB_SIZE,RB_SIZE};
  67.                                         /* IDs of each symbol in ressource compilition */
  68. ULONG           RB_RESSOURCE_ID[RB_BORDER]={0,BM_BP,BM_GP,BM_MP,BM_VP,BM_LX,BM_RX,BM_HOLE,BM_RB};
  69.  
  70.                                         /* Initialize data for our drawing thread */
  71. int             Draw_Initialize(void)
  72. {
  73. int             i;                      /* Temporary variables */
  74.  
  75.                                         /* For each symbol, open a memory devicecontext,
  76.                                            create a presentation space and load the bitmap
  77.                                            from the EXE file */
  78. for(i=1;i<RB_BORDER;i++)
  79.    {
  80.    if(!(hdcRB[i]=DevOpenDC(hab,         /* Open device context with anchor block handle of
  81.                                            our application */
  82.         OD_MEMORY,                      /* Type of device context (memory) */
  83.         (PSZ)"*",                       /* Device information token (no initialization) */
  84.         8L,                             /* Number of items (of deviceopendata) */
  85.         (PDEVOPENDATA)&dcRB[i],         /* Open device context data */
  86.         (HDC)NULL)))                    /* Compatible device context (compatibilty with screen) */
  87.         GEN_ERR(hab,hwndFrame,hwndClient);
  88.    if(!(hpsRB[i]=GpiCreatePS(hab,       /* Create a presentation space with our anchor block
  89.                                            handle */
  90.         hdcRB[i],                       /* Device context handle (of our symbols) */
  91.         &sizelRB,                       /* Presentation space size (or our symbols) */
  92.         GPIA_ASSOC|PU_PELS)))           /* Options (assoziate to screen, pels as unit) */
  93.         GEN_ERR(hab,hwndFrame,hwndClient);
  94.                                         /* Load bitmap from EXE file */
  95.    if(!(hbmRB[i]=GpiLoadBitmap(hpsRB[i],
  96.         (HMODULE)0,                     /* Ressource (EXE file) */
  97.         RB_RESSOURCE_ID[i],             /* ID of bitmap within ressource */
  98.         0L,                             /* Width of bitmap in pels (no streching) */
  99.         0L)))                           /* Height of bitmap in pels (no streching) */
  100.         GEN_ERR(hab,hwndFrame,hwndClient);
  101.    }
  102. return(0);
  103. }
  104.  
  105. void            Playground_Initialize(void)
  106. {
  107. int     i,j,x,y;
  108. ULONG   sys_timer;
  109. APIRET  rc;
  110.  
  111. if((rc=DosQuerySysInfo(QSV_MS_COUNT,QSV_MS_COUNT,&sys_timer,4UL))!=0)
  112.     DOS_ERR(rc,hwndFrame,hwndClient);
  113. srand(sys_timer);                       /* Start random generator with a really random
  114.                                            number, the milliseconds count since bootup */
  115. RB_Point[0]=0;                          /* Reset points */
  116. for(i=0;i<=RB_X;i++)                    /* Set border lines of playground */
  117.    RB_Array[i][0]=RB_Array[i][(RB_Y-1)]=RB_BORDER;
  118. for(i=0;i<=RB_Y;i++)
  119.    RB_Array[0][i]=RB_Array[(RB_X-1)][i]=RB_BORDER;
  120. for(i=1;i<RB_X;i++)                     /* Clear the playing ground */
  121.    for(j=1;j<RB_Y;j++)
  122.       RB_Array[i][j]=RB_EMPTY;
  123. for(i=1;i<50;i++)                       /* 50 random symbols */
  124.     Put_Random_Field();
  125. do                                      /* Position RollBall randomly on the playing
  126.                                            ground, rolling in a random direction */
  127. {
  128.     x=rand()%(RB_X-2);                  /* Random position on playing ground */
  129.     y=rand()%(RB_Y-2);
  130.     i=rand()%4;                         /* Random direction */
  131.     RB_PosX=x*RB_SIZE;
  132.     RB_PosY=y*RB_SIZE;
  133.     RB_Dir=i;
  134. }while(RB_Array[x][y]!=RB_EMPTY);
  135. }
  136.  
  137. void    Put_Random_Field(void)          /* Put a random symbol in a random field */
  138. {
  139. int     i,k,x,y;
  140.  
  141. do
  142.    {
  143.     x=(rand()%(RB_X-2))+1;              /* Random position on playing ground */
  144.     y=(rand()%(RB_Y-2))+1;
  145.     i=(rand()%136);                     /* Fill symbols with probability classes */
  146.     if((i>=0) && (i<17)) k=RB_VP;
  147.     if((i>=17) && (i<35)) k=RB_MP;
  148.     if((i>=35) && (i<60)) k=RB_GP;
  149.     if((i>=60) && (i<105)) k=RB_BP;
  150.     if((i>=105) && (i<115)) k=RB_LX;
  151.     if((i>=115) && (i<125)) k=RB_RX;
  152.     if((i>=125) && (i<136)) k=RB_HOLE;
  153.     if(RB_Array[x][y]==RB_EMPTY)        /* Add the symbol, but only if the field is empty */
  154.         {
  155.         RB_Array[x][y]=k;
  156.         Draw_Bitmap(k,ROP_SRCCOPY,(x-1)*RB_SIZE,(y-1)*RB_SIZE);
  157.         break;
  158.         }
  159.     }while(1);                          /* Loop until one symbol added in a random field */
  160. }
  161.  
  162. void    Clear_Random_Field()            /* Clear a random field to RB_EMPTY. There's a
  163.                                            great chance, that we get an empty field, so
  164.                                            we retry 50 times */
  165. {
  166. int     i,x,y;
  167.  
  168. for(i=0;i<50;i++)                       /* Retry 50 times */
  169.     {
  170.     x=(rand()%(RB_X-2))+1;              /* Random position on playing ground */
  171.     y=(rand()%(RB_Y-2))+1;
  172.     if(RB_Array[x][y]!=RB_EMPTY)        /* Clear the symbol, but only if the field isn't empty */
  173.         {
  174.         RB_Array[x][y]=RB_EMPTY;
  175.         Draw_Bitmap(RB_EMPTY,ROP_SRCCOPY,(x-1)*RB_SIZE,(y-1)*RB_SIZE);
  176.         break;
  177.         }
  178.     }
  179. }
  180.  
  181. void Draw_Thread(ULONG ulThreadArg)
  182. {
  183. if(!(habDT=WinInitialize(0UL)))         /* Initialize client window */
  184.     GEN_ERR(habDT,hwndFrame,hwndClient);
  185.                                         /* Create a message queue */
  186. if(!(hmqDT=WinCreateMsgQueue(habDT,0UL)))
  187.     GEN_ERR(habDT,hwndFrame,hwndClient);
  188. if(!(hpsDT=WinGetPS(hwndClient)))       /* Get a presentation space for client area */
  189.     GEN_ERR(habDT,hwndFrame,hwndClient);
  190.                                         /* Initialize message queue */
  191. WinPostQueueMsg(hmqDT,DT_PAINT,0UL,0UL);
  192. while(qmsqDT.msg!=DT_EXIT)
  193.     {
  194.     if(WinPeekMsg(habDT,                /* Get the message into message queue */
  195.     &qmsqDT,                            /* Message structure */
  196.     NULLHANDLE,                         /* Window filter (none) */
  197.     0UL,                                /* First message ID */
  198.     0UL,                                /* Last message ID */
  199.     PM_REMOVE)==FALSE)                  /* Options (remove message) */
  200.         qmsqDT.msg=DT_IDLE;             /* If no message available, assume idle */
  201.     switch(qmsqDT.msg)
  202.     {
  203.     case DT_PAINT:                      /* Repaint client window */
  204.         {
  205.         RECTL   rclDT;
  206.         int     x,y;
  207.                                         /* Repaint client window aread */
  208.         WinQueryWindowRect(hwndClient,&rclDT);
  209.         WinFillRect(hpsDT,&rclDT,CLR_WHITE);
  210.         for(x=1;x<RB_X;x++)             /* Draw the entries on playing ground */
  211.             for(y=1;y<RB_Y;y++)
  212.                 if(RB_Array[x][y]!=RB_EMPTY)
  213.                     Draw_Bitmap(RB_Array[x][y],ROP_SRCCOPY,(x-1)*RB_SIZE,(y-1)*RB_SIZE);
  214.         break;
  215.         }
  216.     case DT_LBUTTON:
  217.         {
  218.         int     x,y;
  219.                                         /* Left button was pressed, get the location,
  220.                                            add \ to RB_Array, and draw \ bitmap, if
  221.                                            field is emty */
  222.         x=(LONGFROMMP(qmsqDT.mp1)/RB_SIZE)+1;
  223.         y=(LONGFROMMP(qmsqDT.mp2)/RB_SIZE)+1;
  224.         if(RB_Array[x][y]==RB_EMPTY)
  225.             {
  226.             RB_Array[x][y]=RB_LX;
  227.             Draw_Bitmap(RB_LX,ROP_SRCCOPY,(x-1)*RB_SIZE,(y-1)*RB_SIZE);
  228.             }
  229.         break;
  230.         }
  231.     case DT_RBUTTON:
  232.         {
  233.         int     x,y;
  234.                                         /* Right button was pressed, get the location,
  235.                                            add / to RB_Array, and draw / bitmap, if
  236.                                            field is emty */
  237.         x=(LONGFROMMP(qmsqDT.mp1)/RB_SIZE)+1;
  238.         y=(LONGFROMMP(qmsqDT.mp2)/RB_SIZE)+1;
  239.         if(RB_Array[x][y]==RB_EMPTY)
  240.             {
  241.             RB_Array[x][y]=RB_RX;
  242.             Draw_Bitmap(RB_RX,ROP_SRCCOPY,(x-1)*RB_SIZE,(y-1)*RB_SIZE);
  243.             }
  244.         break;
  245.         }
  246.      case DT_IDLE:
  247.         {
  248.         if(runRB==TRUE)
  249.             {
  250.             ULONG       x,y,Symbol;
  251.                                         /* Under DOS we would query the time in milliseconds
  252.                                            from the system timer, to adjust graphics. This
  253.                                            is accurate, but in a multitasking in a multitasking
  254.                                            system, we must assume being pre-empted. Therefore
  255.                                            we can't have an exact time bases. Hope that
  256.                                            the system timer counts more often than all 31
  257.                                            milliseconds in future releases/machines */
  258.                                         /* Draw bitmap */
  259.             switch(RB_Dir)              /* Test that RollBall doesn't leave borders. A
  260.                                            border reverses the direction and produces a
  261.                                            beep */
  262.             {
  263.             case UP:
  264.                 RB_PosY++;
  265.                 if((RB_PosY+RB_SIZE)>=((RB_Y-2)*RB_SIZE))
  266.                     {
  267.                     RB_PosY=(RB_Y-3)*RB_SIZE;
  268.                     RB_Dir=DOWN;
  269.                     DosBeep(800,50);
  270.                     }
  271.                 break;
  272.             case DOWN:
  273.                 RB_PosY--;
  274.                 if(RB_PosY<0)
  275.                     {
  276.                     RB_PosY=0;
  277.                     RB_Dir=UP;
  278.                     DosBeep(800,50);
  279.                     }
  280.                 break;
  281.             case LEFT:
  282.                 RB_PosX--;
  283.                 if(RB_PosX<0)
  284.                     {
  285.                     RB_PosX=0;
  286.                     RB_Dir=RIGHT;
  287.                     DosBeep(800,50);
  288.                     }
  289.                 break;
  290.             case RIGHT:
  291.                 RB_PosX++;
  292.                 if((RB_PosX+RB_SIZE)>=((RB_X-2)*RB_SIZE))
  293.                     {
  294.                     RB_PosX=(RB_X-3)*RB_SIZE;
  295.                     RB_Dir=LEFT;
  296.                     DosBeep(800,50);
  297.                     }
  298.                 break;
  299.             }
  300.                                         /* Draw RollBall at new position */
  301.             Draw_Bitmap(RB_RB,ROP_SRCCOPY,RB_PosX,RB_PosY);
  302.                                         /* Now, test if the middle of RollBall is over any
  303.                                            symbol. If a symbol is found, add points, deflect
  304.                                            or end game */
  305.                                         /* RB_Array is 1 based, because 0 indices are the
  306.                                            playing ground borders */
  307.             x=((RB_PosX)/RB_SIZE)+1;
  308.             y=((RB_PosY)/RB_SIZE)+1;
  309.                                         /* A Symbol if RB_SIZE*RB_SIZE in size, that means
  310.                                            RollBall is exactly over a symbol, if the lower
  311.                                            left edges of both symbols match. Then, and only
  312.                                            then, we count points, deflect or loose */
  313.             if((RB_PosX==(x-1)*RB_SIZE) && (RB_PosY==(y-1)*RB_SIZE))
  314.                 Symbol=RB_Array[x][y];
  315.             else Symbol=RB_EMPTY;
  316.             switch(Symbol)
  317.             {
  318.             case RB_LX:                 /* We got a \ deflector */
  319.                 {
  320.                 switch(RB_Dir)          /* \ deflects direction of RollBall */
  321.                 {
  322.                 case RIGHT:
  323.                     RB_Dir=DOWN; break;
  324.                 case UP:
  325.                     RB_Dir=LEFT; break;
  326.                 case LEFT:
  327.                     RB_Dir=UP; break;
  328.                 case DOWN:
  329.                     RB_Dir=RIGHT; break;
  330.                 }                       /* Remove deflector */
  331.                 RB_Array[x][y]=RB_EMPTY;
  332.                 break;
  333.                 }
  334.             case RB_RX:                 /* We got a / deflector */
  335.                 {
  336.                 switch(RB_Dir)          /* / deflects direction of RollBall */
  337.                 {
  338.                 case RIGHT:
  339.                     RB_Dir=UP; break;
  340.                 case UP:
  341.                     RB_Dir=RIGHT; break;
  342.                 case LEFT:
  343.                     RB_Dir=DOWN; break;
  344.                 case DOWN:
  345.                     RB_Dir=LEFT; break;
  346.                 }                       /* Remove deflector */
  347.                 RB_Array[x][y]=RB_EMPTY;
  348.                 DosBeep(600,20);
  349.                 break;
  350.                 }
  351.             case RB_BP:                 /* We got a point */
  352.             case RB_GP:
  353.             case RB_MP:
  354.             case RB_VP:
  355.                 {                       /* Add the points for each symbol */
  356.                 RB_Point[0]+=RB_Point[Symbol];
  357.                                         /* Remove the point */
  358.                 RB_Array[x][y]=RB_EMPTY;
  359.                 DosBeep(700,20);
  360.                 break;
  361.                 }
  362.             case RB_HOLE:               /* We got a hole, sorry but RollBall will be killed.
  363.                                            We disable RollBall from rolling, and send a 
  364.                                            ID_STOPTHREAD message to our window, which
  365.                                            informs the user about the points with a message
  366.                                            box */
  367.                 {
  368.                 int     freq;
  369.                 for(freq=5000;freq>100;freq-=100) DosBeep(freq,5);
  370.                 runRB=FALSE;            /* Prevent RollBall from further rolling */
  371.                 WinPostMsg(hwndClient,WM_COMMAND,(MPARAM)ID_STOPTHREAD,(MPARAM)0);
  372.                 break;
  373.                 }
  374.             }
  375.                                         /* Randomly add and remove symbols on playing ground */
  376.             if((rand()%500)<2)
  377.                 {
  378.                 Put_Random_Field();
  379.                 Clear_Random_Field();
  380.                 }
  381.             }
  382.         }
  383.     }
  384.     DosSleep(0L);
  385.     }
  386. WinReleasePS(hpsDT);                    /* Clean up */
  387. WinDestroyMsgQueue(hmqDT);
  388. WinTerminate(habDT);
  389. DosExit(EXIT_THREAD,0UL);
  390. }
  391.  
  392.                                         /* Draw a bitmap on client window */
  393. void Draw_Bitmap(ULONG Bitmap,ULONG mode,ULONG x,ULONG y)
  394. {
  395. static POINTL   D_Array[5];             /* Structure to locate bitmap into window */
  396.                                         /* Destination edges */
  397. D_Array[0].x=x; D_Array[0].y=y; D_Array[1].x=x+RB_SIZE; D_Array[1].y=y+RB_SIZE;
  398.                                         /* Source edges */
  399. D_Array[2].x=D_Array[2].y=0; D_Array[3].x=D_Array[3].y=RB_SIZE;
  400.                                         /* Select bitmap */
  401. GpiSetBitmap(hpsRB[Bitmap],hbmRB[Bitmap]);
  402.                                         /* Select selected bitmap into client area */
  403. if(!(GpiSetBitmap(hpsDT,hbmRB[Bitmap])))
  404.     GEN_ERR(habDT,hwndFrame,hwndClient);
  405.                                         /* Copy bitmap from memory to client area */
  406. if(GpiBitBlt(hpsDT,                     /* Target presentation space handle */
  407.     hpsRB[Bitmap],                      /* Source presentation space handle */
  408.     4L,                                 /* Point count */
  409.     (PPOINTL)D_Array,                   /* Point array */
  410.     mode,                               /* Mixing function required (copy over target) */
  411.     BBO_IGNORE)==GPI_ERROR)             /* Options for compression (ignore it) */
  412.     GEN_ERR(habDT,hwndFrame,hwndClient);
  413. }
  414.