/*=========================================================================\
 *                                                                         *
 *       FILE: wrmthrd.c                                                   *
 *                                                                         *
 *       DESCRIPTION:                                                      *
 *                                                                         *
 *                                                                         *
 *      Created 1991  IBM Corp.                                            *
 *      Updated 1994  IBM Corp.                                            *
 *                                                                         *
 *      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is        *
 *      sample code created by IBM Corporation.  This sample code is not   *
 *      part of any standard or IBM product and is provided to you solely  *
 *      for the purpose of assisting you in the development of your        *
 *      applications.  The code is provided "AS IS", without               *
 *      warranty of any kind.  IBM shall not be liable for any damages     *
 *      arising out of your use of the sample code, even if they have been *
 *      advised of the possibility of such damages.                        *
 *                                                                         *
 *-------------------------------------------------------------------------*
 *--------------------------------------------------------------
 *
 *  This source file contains the following functions:
 *
 *  WormThread
 *  move_worm_up
 *  move_worm_down
 *  move_worm_right
 *  move_worm_left
 *  move_worm_zigup
\*==============================================================*/

/*--------------------------------------------------------------*\
 *  Include files, macros, defined constants, and externs
\*--------------------------------------------------------------*/

#define  INCL_DOS
#define  INCL_VIO
#define  INCL_KBD
#define  INCL_MOU
#define  INCL_DOSPROCESS
#define  INCL_DOSSEMAPHORES

#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include "worms.h"
#include "wrmthrd.h"
/*--------------------------------------------------------------*\
 *  Global variables  and definitions for this file
\*--------------------------------------------------------------*/
CHAR *pszLeftWorm   =      "<<<------->";
CHAR *pszRightWorm  =      "<------->>>";
CHAR *pszBlank      =      "               ";
CHAR achUpWorm[10]  =      {'^','^','|','|','|','v'};
CHAR achDownWorm[10]=      {'^','^','|','|','|','v'};
SHORT asWidths   [] =      {2,4,8,16};
SHORT asHorizWidths  [] =  {HOR_WIDTH / 2, HOR_WIDTH /8,HOR_WIDTH,HOR_WIDTH / 3};
SHORT asVertHeights  [] =  {HEIGHT / 4,HEIGHT / 8, HEIGHT / 2, HEIGHT  };
SHORT sDirection = 0;
SHORT sVertHeight = 0;
SHORT sRefresh = 1;
#define MAX_LEN_WORM       48

/*--------------------------------------------------------------*\
 *  Entry point declarations
\*--------------------------------------------------------------*/
VOID move_worm_up( ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                   PBYTE  pbAttribute,
                   SHORT *psCurrentDirection,
                   LONG  tidWorm);

VOID move_worm_down( ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                     PBYTE  pbAttribute,
                     SHORT *psCurrentDirection,
                     LONG  tidWorm);

VOID move_worm_right( ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                      PBYTE  pbAttribute,
                      SHORT *psCurrentDirection,
                      LONG  tidWorm);

VOID move_worm_left( ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                     PBYTE  pbAttribute,
                     SHORT *psCurrentDirection,
                     LONG  tidWorm);

VOID move_worm_zigup(ULONG *pulCurrentRow,ULONG *pulCurrentCol,
                     PBYTE pbAttribute,
                     SHORT *psCurrentDirection,
                     LONG tidWorm);

/****************************************************************\
 *  Routine Name:wrmthrd()
 *--------------------------------------------------------------
 *
 *  Name:
 *
 *  Purpose: This routine allows each thread to draw to the screen.
 *           Each thread will stay in this loop, until the thread
 *           dies, or is terminated. Each thread may draw to the
 *           unless the semaphore is set by thread one or indicating
 *           that one of the parent threads wants control of the
 *           screeen.
 *
 *  Returns: There is no return value. The thread terminates.
 *
\****************************************************************/
VOID
WormThread( VOID *lpvMessage )
{
     PVOID pvMessage;
     PTHREAD_DATA pThreadData;
     SHORT  sDummy = 1;
     SHORT  asDirection [] = { UP,RIGHT,LEFT,DOWN};

     pvMessage = ( PVOID ) lpvMessage;
     srand(sDummy);
     pThreadData =  (PTHREAD_DATA) pvMessage;
     /*
      * start the worm  off
      */
     if(sDirection == ( sizeof(asDirection) / sizeof(SHORT) ) )
     {
          sDirection = 0;
     }
     pThreadData->sCurrentDirection = asDirection[sDirection++];
     do
     {
          switch(pThreadData->sCurrentDirection)
          {
          case UP:
               move_worm_up( &pThreadData->ulCurrentRow,
                             &pThreadData->ulCurrentCol,
                             &pThreadData->bAttribute,
                             &pThreadData->sCurrentDirection,
                              pThreadData->tidWorm);
               break;
          case DOWN:
               move_worm_down( &pThreadData->ulCurrentRow,
                               &pThreadData->ulCurrentCol,
                               &pThreadData->bAttribute,
                               &pThreadData->sCurrentDirection,
                                pThreadData->tidWorm);
               break;

          case LEFT:
               move_worm_left( &pThreadData->ulCurrentRow,
                               &pThreadData->ulCurrentCol,
                               &pThreadData->bAttribute,
                               &pThreadData->sCurrentDirection,
                                pThreadData->tidWorm );
               break;
          case RIGHT:
               move_worm_right( &pThreadData->ulCurrentRow,
                                &pThreadData->ulCurrentCol,
                                &pThreadData->bAttribute,
                                &pThreadData->sCurrentDirection,
                                 pThreadData->tidWorm );
               break;
          case ZIG_UP:
               move_worm_zigup( &pThreadData->ulCurrentRow,
                                &pThreadData->ulCurrentCol,
                                &pThreadData->bAttribute,
                                &pThreadData->sCurrentDirection,
                                 pThreadData->tidWorm );
               break;
          default:
               pThreadData->ulCurrentRow = ( LAST_ROW - FIRST_ROW ) /2;
               pThreadData->ulCurrentCol = ( LAST_COL - FIRST_COL ) /2;
               if(sDirection == ( sizeof(asDirection) / sizeof(SHORT) ) )
               {
                    sDirection = 0;
               }
               pThreadData->sCurrentDirection = asDirection[sDirection++];
               break;
          }
          DosSleep(PAUSE_TIME);
          /*
           * if set,then the thread that services the console,or the
           * thread that services the mouse queue wants control of
           * the screen
           */
          DosPostEventSem(hevDrawOk);
          DosWaitEventSem(hevDrawSem,SEM_INDEFINITE_WAIT);

        }while(pThreadData->fActive);

     pThreadData->tidWorm = 0;
     /*
      * if the process is to exit post the semaphore on the way out
      */
      if(fQuit)
      {
          DosPostEventSem(hevDrawOk);
      }

    /*
     * should alway be called to free any runtime resources this thread
     * might be using
     */
    /* _endthread(); */
    DosExit( EXIT_THREAD, 0 );

}/*WormThread*/
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:move_worm_down()
 *
 *  Purpose: Draw the worm down the screen vertically and set up to go to
 *           another direction.
 *  Returns: VOID
 *
\****************************************************************/
VOID move_worm_down(ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                    PBYTE pbAttribute, SHORT *psCurrentDirection,
                    LONG  tidWorm )

{

     USHORT sRow;
     SHORT  sPos = 0;
     ULONG  ulStartRow;
     CHAR  achCell[2];
     BYTE  bAttribute;
     ULONG  ulCount;
     BOOL  fOnce = TRUE;
     BYTE  bBackGround = WM_BACKGROUND;


     if(sVertHeight  == (sizeof(asVertHeights) / sizeof(SHORT ) ) )
     {
          sVertHeight = 0;
     }
     if(*pulCurrentRow <= FIRST_ROW || *pulCurrentRow >= LAST_ROW )
     {
          *pulCurrentRow = ( LAST_ROW - asVertHeights[sVertHeight++]) ;
     }

     if(*pulCurrentRow < FIRST_ROW || *pulCurrentRow > LAST_ROW )
     {
          *pulCurrentRow = (FIRST_ROW + 1);
     }
     ulStartRow = *pulCurrentRow;
     ulCount = sizeof(achCell);
     bAttribute = *pbAttribute;

     for(sRow = (*pulCurrentRow + WIDTH); *pulCurrentRow < LAST_ROW && fDraw;
                 (*pulCurrentRow)++ )
     {
          /*
           * read the current attribute on the screen if another worm
           */
          VioReadCellStr(achCell,&ulCount,*pulCurrentRow,
                         *pulCurrentCol,hvio);
          if(!fSilent)
          {
               if(achCell[0] != ' ' && fOnce )
               {
                    DosBeep(600,175);
                    DosBeep(1200,175);
                    bAttribute = 0x4F;
                    fOnce = FALSE;
               }
          }
          VioWrtCharStrAtt( &achDownWorm[sPos],
                            1L,
                            *pulCurrentRow,
                            *pulCurrentCol,
                            &bAttribute,
                            hvio );
          DosSleep(PAUSE_TIME);
          if(!achUpWorm[sPos++] )
          {
                for(; ulStartRow <= (*pulCurrentRow ) && fDraw; ulStartRow++)
                {
                    VioWrtCharStrAtt( &pszBlank[0],1L,
                                      ulStartRow,
                                      *pulCurrentCol,
                                      &bBackGround,
                                      hvio );
                }
                sPos = 0;
          }

     }  /* end for */
     /*
      * clean off any tail we left behind
      */
     if(sPos)
     {
          for(; ulStartRow <= (*pulCurrentRow ) ;ulStartRow++)
          {
              VioWrtCharStrAtt( &pszBlank[sPos],1L,
                                ulStartRow,
                                *pulCurrentCol,
                                &bBackGround,
                                hvio );
          }
     }

    /*
     * if we stopped drawing come back to the same spot
     */
    if(fDraw)
    {
         *psCurrentDirection = (rand() % MAX_DIRECTIONS);
         *pulCurrentRow = (rand() % HEIGHT);
         *pulCurrentCol = ( (rand() % HOR_WIDTH) /  asWidths[rand() %  4] + 1);
    }

}
/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:move_worm_up()
 *
 *  Purpose:Redraw the worm moving vertically up the screen.
 *          Draw until the bottom of the screen or fDraw flag has
 *          been reset.
 *
 *  Returns: VOID
 *
\****************************************************************/
VOID move_worm_up(ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                  PBYTE pbAttribute, SHORT *psCurrentDirection,
                  LONG tidWorm )

{

     USHORT sRow = 0;
     SHORT  sPos = 0;
     ULONG  ulStartRow;
     BYTE  bBackGround = WM_BACKGROUND;
     static SHORT sVertHeight = 0;

     if(sVertHeight  == (sizeof(asVertHeights) / sizeof(SHORT ) ) )
     {
          sVertHeight = 0;
     }
     if(*pulCurrentRow <= FIRST_ROW || *pulCurrentRow >= LAST_ROW )
     {
          *pulCurrentRow = ( LAST_ROW - asVertHeights[sVertHeight]) ;
     }
     ulStartRow = *pulCurrentRow;
     for(sRow = (*pulCurrentRow - WIDTH), sPos = 0;
                            (*pulCurrentRow > FIRST_ROW )&& fDraw;
                            (*pulCurrentRow)--)
     {
          /*
           * read the current attribute on the screen if another worm beep
           */
          VioWrtCharStrAtt( &achUpWorm[sPos],1L,
                            *pulCurrentRow,
                            *pulCurrentCol,
                            pbAttribute,
                            hvio );
          DosSleep(PAUSE_TIME);
          if(!achUpWorm[sPos++] )
          {
                for(; ulStartRow >= (*pulCurrentRow ) && fDraw; ulStartRow--)
                {
                    VioWrtCharStrAtt( &pszBlank[0],1L,
                                      ulStartRow,
                                      *pulCurrentCol,
                                      &bBackGround,
                                      hvio );
                }
                sPos = 0;
          }


     }
     /*
      * clean up any head on the screen
      */
    if(sPos)
    {
          for(; ulStartRow >= (*pulCurrentRow ) ; ulStartRow--)
          {
              VioWrtCharStrAtt( &pszBlank[0],1L,
                                ulStartRow,
                                *pulCurrentCol,
                                &bBackGround,
                                hvio );
          }
    }

    /*
     * if we stopped drawing come back to the same spot
     */
    if(fDraw)
    {
         *psCurrentDirection = ( rand() % MAX_DIRECTIONS);
         *pulCurrentRow = ( (rand() % HEIGHT)  );
         *pulCurrentCol = ( (rand() % HOR_WIDTH)/  asWidths[rand() %  4] + 1) ;
    }
} /* move_worm_up */


/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:move_worm_right()
 *
 *  Purpose:Move the worm to the right side of the screen and wrap
 *          around.
 *
 *  Returns: VOID
 *
\****************************************************************/
VOID move_worm_right(ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                      PBYTE pbAttribute, SHORT *psCurrentDirection,
                      LONG  tidWorm )

{
     LONG lCol;
     ULONG ulSize;
     BYTE  bAttribute;
     BOOL  fOnce = TRUE;
     static SHORT sHorizWidth = 0;
     BYTE  bBackGround = WM_BACKGROUND;
     ULONG ulOldRow,ulOldCol;
     CHAR  achCell[ MAX_LEN_WORM ];
     ULONG ulCount;


     if(*pulCurrentRow < FIRST_ROW || *pulCurrentRow > LAST_ROW )
     {
          *pulCurrentRow = (FIRST_ROW + 1);
     }
     if(sHorizWidth == (sizeof(asHorizWidths) / sizeof(SHORT ) ) )
     {
          sHorizWidth = 0;
     }

     ulSize = sizeof(achCell);
     bAttribute = *pbAttribute;

     ulOldRow = *pulCurrentRow;
     ulOldCol = *pulCurrentCol;
     ulCount = strlen(pszRightWorm);

     VioReadCellStr(achCell,&ulCount,ulOldRow,ulOldCol,hvio);
     for(lCol = (*pulCurrentCol + asHorizWidths[sHorizWidth++]);
                      *pulCurrentCol <= lCol && fDraw;
                           (*pulCurrentCol)++ )
     {
          /*
           * read the current attribute on the screen if another worm
           */
          VioReadCellStr(achCell,&ulSize,*pulCurrentRow,
                         *pulCurrentCol,hvio);
          if(!fSilent)
          {
               if(achCell[0] != ' ' && fOnce )
               {
                    DosBeep(600,175);
                    DosBeep(1200,175);
                    bAttribute = 0x4F;
                    fOnce = FALSE;
               }
          }
          VioWrtCharStrAtt( pszRightWorm, strlen(pszRightWorm),
                            *pulCurrentRow,
                            *pulCurrentCol,
                            &bAttribute,
                            hvio );
          /*
           * erase the last one by setting the background color
           */
          DosSleep(PAUSE_TIME);
          VioWrtCharStrAtt( pszBlank, strlen(pszRightWorm),
                            *pulCurrentRow,
                            *pulCurrentCol,
                            &bBackGround,
                            hvio );


    }

    /*
     * if we stopped drawing come back to the same spot
     */
    if(fDraw)
    {
         VioWrtCellStr(achCell,ulCount,ulOldRow,
                       ulOldCol,hvio);
         *psCurrentDirection = (rand() %  MAX_DIRECTIONS);
         *pulCurrentCol = ( (rand() % HOR_WIDTH) + 1/  asWidths[rand() %  4] + 1);
         *pulCurrentRow = ( (rand() % HEIGHT) );
    }

} /* move_worm_right */


/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:move_worm_zigup
 *
 *  Purpose:Draw the worm in a diagonal direction moving upwards.
 *
 *  Returns:
 *          VOID
\****************************************************************/
VOID move_worm_zigup(ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                      PBYTE pbAttribute, SHORT *psCurrentDirection,
                      LONG tidWorm )
{

     USHORT sRow = 0;
     SHORT  sPos = 0;
     ULONG  ulStartRow, ulStartCol;
     BYTE  bBackGround = WM_BACKGROUND;

     ulStartRow = *pulCurrentRow;
     ulStartCol = *pulCurrentCol;
     for(sRow = (*pulCurrentRow - WIDTH), sPos = 0;
                            (*pulCurrentRow > FIRST_ROW + 1) && fDraw;
                            (*pulCurrentRow) -=2,(*pulCurrentCol)++ )
     {
          VioWrtCharStrAtt( &achUpWorm[sPos],1L,
                            *pulCurrentRow,
                            *pulCurrentCol,
                            pbAttribute,
                            hvio );
          DosSleep(PAUSE_TIME);
          if(!achUpWorm[sPos++] )
          {
                for(; ulStartRow >= (*pulCurrentRow )&& fDraw;
                    ulStartRow -=2 ,ulStartCol++ )
                {
                    VioWrtCharStrAtt( &pszBlank[0],1L,
                                      ulStartRow,
                                      ulStartCol,
                                      &bBackGround,
                                      hvio );
                }
                sPos = 0;
          }


     }
     /*
      * clean up any head on the screen
      */
    if(sPos)
    {
          for(; ulStartRow >= (*pulCurrentRow );ulStartRow -=2 )
          {
              VioWrtCharStrAtt( &pszBlank[0],1L,
                                ulStartRow,
                                ulStartCol++,
                                &bBackGround,
                                hvio );
          }
    }

    /*
     * if we stopped drawing come back to the same spot
     */
    if(fDraw)
    {
         *psCurrentDirection = ( rand() % MAX_DIRECTIONS);
         *pulCurrentCol = ( (rand() % HOR_WIDTH)/  asWidths[rand() %  4] + 1);
         *pulCurrentRow = ( (rand() % HEIGHT) );
    }

} /* move_worm_zigup */


/****************************************************************\
 *
 *--------------------------------------------------------------
 *
 *  Name:move_worm_left()
 *
 *  Purpose:Move the worm to the left side of the screen.
 *
 *  Returns: VOID
 *
\****************************************************************/
VOID move_worm_left(ULONG *pulCurrentRow, ULONG *pulCurrentCol,
                    PBYTE pbAttribute, SHORT *psCurrentDirection,
                    LONG  tidWorm )

{

     ULONG  ulCol;
     static SHORT sHorizWidth = 0;
     BYTE  bBackGround = WM_BACKGROUND;


     if(sHorizWidth == (sizeof(asHorizWidths) / sizeof(SHORT ) ) )
     {
          sHorizWidth = 0;
     }

     if(*pulCurrentRow < FIRST_ROW || *pulCurrentRow > LAST_ROW )
     {
          *pulCurrentRow = (LAST_ROW - 1);
     }

    ulCol = rand()  % WIDTH;
    if( ulCol > *pulCurrentCol)
    {
          ulCol = ulCol - *pulCurrentCol;
    }

    for( ;((*pulCurrentCol) >  ulCol) && fDraw; (*pulCurrentCol)--)
    {
         /*
          * read the current attribute on the screen if another worm
          */
         VioWrtCharStrAtt( pszLeftWorm,strlen(pszLeftWorm),
                           *pulCurrentRow,
                           *pulCurrentCol,
                           pbAttribute,
                           hvio );

         DosSleep(PAUSE_TIME);
         if(!fDraw)
         {
               break;
         }
         VioWrtCharStrAtt( pszBlank,strlen(pszLeftWorm),
                           *pulCurrentRow,
                           *pulCurrentCol,
                           &bBackGround,
                           hvio );

    }
    /*
     * if we stopped drawing come back to the same spot
     */
    if(fDraw)
    {
          *psCurrentDirection = (rand() %  MAX_DIRECTIONS);
          *pulCurrentRow = ( (rand() % HEIGHT) );
          *pulCurrentCol = ( (rand() % HOR_WIDTH)/  asWidths[rand() %  4]  + 1);
    }
} /* move_worm_left */

/*--------------------------------------------------------------*\
 *  End of file : wrmthrd.c
\*--------------------------------------------------------------*/
