Annotation of os2sdk/demos/apps/chaser/chaser.c, revision 1.1.1.2

1.1.1.2 ! root        1: /*  SWARM
        !             2:  *  Created by Microsoft Corp. 1986
        !             3:  *
        !             4:  *  the idea behind this game is as follows:
1.1       root        5:  *
                      6:  *   You have a collection of objects in the center of the playing field
                      7:  *   that you are trying to protect (just one object in current version). You
                      8:  *   control your own movements with the mouse. A number of "chasers" start
                      9:  *   around the edges of the field and begin moving towards the objects
                     10:  *   you want to protect. If you move the mouse on top of a chaser and click
                     11:  *   the left button, the chaser will be killed and disappear from the screen.
                     12:  *   But as you close in on the chaser, it will detect your presence and try
                     13:  *   to dodge you. Meanwhile the other chasers will continue to go after
                     14:  *   your objects. If one of the chasers reaches an object, it will begin
                     15:  *   dragging it away to the edge of the screen (currently the game just
                     16:  *   ends when the single object is reached). When all objects are dragged
                     17:  *   away, the game ends. If a chaser is killed while dragging an object, the
                     18:  *   object is left where it is and must be protected in place - player cannot
                     19:  *   move objects. If you kill all the chasers, a new group of faster ones
                     20:  *   will be spawned (currently the speed is constant). Your score is how
                     21:  *   many chasers you can kill (no score currently kept), so there is no
                     22:  *   advantage in sitting on the object for long periods.
                     23:  *
                     24:  * Swarm demonstrates several capabilities of OS/2 and the philosphy behind
                     25:  * them.  This program is made of three components: Initialization, the
                     26:  * mouse driven thread and the attacker thread.  The attacker thread is
                     27:  * launched as many times as there are attackers in a game.  Launching
                     28:  * the attacker several times takes full advantage of the OS to schedule
                     29:  * resources.  The programmer can think of the problem as only one attacker.
                     30:  * The system handles multiple instances of the thread.
                     31:  *
1.1.1.2 ! root       32:  * As the main loop launches threads it puts an ID code into the thread's
1.1       root       33:  * stack.  The code is used to index into the universe data.
                     34:  *
                     35:  * A ram semaphore is used to control access to global data.
                     36:  *
                     37:  * This demonstration shows the use of the following OS/2 system calls:
                     38:  *
                     39:  * Tasking:           VIO API:              Mouse API:
                     40:  *
1.1.1.2 ! root       41:  *   DosSemRequest()    VioScrollUp()         MouOpen()
        !            42:  *   DosSemClear()      VioWrtCellStr()       MouSetPtrPos()
        !            43:  *   DosCreateThread()  VioSetCurType()       MouReadEventQue()
        !            44:  *   DosExit()          VioSetMode()
        !            45:  *   DosSleep()
1.1       root       46:  */
1.1.1.2 ! root       47: #include <os2def.h>
        !            48: #define INCL_DOSPROCESS
        !            49: #define INCL_DOSSEMAPHORES
        !            50: #include <bsedos.h>
        !            51: #define INCL_SUB
        !            52: #include <bsesub.h>
1.1       root       53: #include <malloc.h>
1.1.1.2 ! root       54: #undef NULL
1.1       root       55: #include <stdio.h>
                     56: 
                     57: #define  STACKSIZE  200
                     58: 
                     59: #define  DANGERZONE  3
                     60: 
                     61: #define  LONGNAP     500L
                     62: #define  SHORTNAP    150L
                     63: 
                     64: #define  WAIT (-1L)                    /* Wait for ram Semaphore */
                     65: 
                     66: #define  CHASER    8                   /* Number of chasers */
                     67: 
                     68: #define  SCREEN_HEIGHT    24           /* Default screen size */
                     69: #define  SCREEN_WIDTH     79
                     70: 
                     71: #define  GOAL univ[CHASER]             /* Macros for constant stuff */
                     72: #define  ME univ[ID]
                     73: #define  MOUSE univ[CHASER+1]
                     74: 
                     75: #define  ALIVE 1                       /* Flags for attackers/goal */
                     76: #define  DEAD 0
                     77: 
                     78: char   Chaser[2] = { 0xE8, 0x20 };   /* character and attribute */
                     79: char   Prize[2] = { 0x03, 0x2C };   /* for our various objects */
                     80: char   Blank[2] = { 0x20, 0x22 };
                     81: char   Blood[2] = { 0x20, 0x44 };
                     82: 
                     83: struct {                             /* Universe structure and array */
                     84:     int     row;                       /* univ[0] = chaser     */
                     85:     int     col;                       /* univ[n-1] = chaser     */
                     86:     int     state;                     /* univ[n] = GOAL */
                     87: } univ[CHASER+1];                      /* univ[n+1]= MOUSE */
                     88: 
                     89: short          ScreenHeight,           /* Screen attributes */
                     90:                ScreenWidth;
                     91: 
1.1.1.2 ! root       92: HMOU           Mouse;                  /* place for mouse handle */
        !            93: ULONG          Shortnap;               /* Sleep times for chasers */
        !            94: ULONG          Longnap;
        !            95: ULONG          Semaphore = 0;          /* Ram semaphore */
1.1       root       96: 
1.1.1.2 ! root       97: struct _VIOCURSORINFO  NewCur;         /* struct for setting cursor type */
        !            98: struct _VIOCURSORINFO  OldCur;
1.1       root       99: 
1.1.1.2 ! root      100: struct _VIOMODEINFO    modedata;       /* Data saves for VIO mode */
        !           101: struct _VIOMODEINFO    OldVioMode;
1.1       root      102: 
                    103: /*
                    104:  * Define all procedures before main.
                    105:  */
                    106: void Defender();
                    107: void CleanUp();
                    108: int InitGame();
                    109: void chaserthread();
                    110: int ParseCmdLine(int,char **);
                    111: 
                    112: /*
                    113:  * main(ac,av)
                    114:  *
                    115:  * Top level procedure and MOUSE thread for the GAME demo.
                    116:  */
                    117: int main(ac, av)
                    118: int ac;
                    119: char *av[];
                    120: {
                    121:     /*
                    122:      * Parse the command line and perform some initialization.
                    123:      */
                    124:     if (ParseCmdLine(ac,av)) {
                    125:        printf("usage: %s [24|43] [F|M|S]\n",av[0]);
1.1.1.2 ! root      126:        DosExit(EXIT_THREAD,1);
1.1       root      127:     }
                    128:     if (InitGame())            /* Init game, exit if some problem */
1.1.1.2 ! root      129:        DosExit(EXIT_PROCESS,1);
1.1       root      130: 
1.1.1.2 ! root      131:     Defender();                /* Run mouse loop (defend against the swarm) */
1.1       root      132: 
                    133:     CleanUp();
                    134: }
                    135: 
                    136: /*
                    137:  * Defender()
                    138:  *
                    139:  * This is the main loop of the mouse control thread.
                    140:  *
                    141:  * The semaphore is used to prevent the other threads from time slicing 
                    142:  * while this routine is examining and/or modifying the universe.  The 
                    143:  * Semaphore is grabbed after the read of the Mouse queue so we don't tie
                    144:  * up the attackers while waiting for a mouse event.
                    145:  */
                    146: void Defender()
                    147: {
1.1.1.2 ! root      148:     USHORT ReadType = 1,       /* Wait for mouse events */
        !           149:           alive,
        !           150:           i;
        !           151:     struct _MOUEVENTINFO  MouInfo;    /* mouse event packet structure */
1.1       root      152: 
                    153:     alive = CHASER;
                    154: 
                    155:     do {
1.1.1.2 ! root      156:        MouReadEventQue( &MouInfo, &ReadType, Mouse); /* read where mouse is */
        !           157: 
        !           158:        DosSemRequest( &Semaphore, WAIT);
        !           159: 
        !           160:        if( MouInfo.fs & 1) {                 /* If the mouse has moved */
        !           161:            MOUSE.row = MouInfo.row;
        !           162:            MOUSE.col = MouInfo.col;
1.1       root      163:        }
1.1.1.2 ! root      164:        if( MouInfo.fs & 4 ) {                 /* if left button pressed, */
1.1       root      165:            for (i = 0; i < CHASER; i++ ) {
                    166:                if( ( MOUSE.row == univ[i].row ) &&
                    167:                    ( MOUSE.col == univ[i].col ) &&  /* see if we hit one */
                    168:                    ( univ[i].state == ALIVE) ) {
                    169:                     univ[i].state = DEAD;      
                    170: 
1.1.1.2 ! root      171:                     DosBeep(300,75);                /* make a dying sound */
        !           172:                     DosBeep(600,75);
        !           173:                     DosBeep(300,85);
1.1       root      174: 
1.1.1.2 ! root      175:                     alive--;               /* Decrease number alive */
1.1       root      176:                     break;                 /* Can only kill one at a time */
                    177:                }
                    178:            }
                    179:        }
1.1.1.2 ! root      180:        if( MouInfo.fs & 16 )         /* If right button pressed... */
1.1       root      181:            break;                      /* End game, clean up */
                    182: 
1.1.1.2 ! root      183:        DosSemClear(&Semaphore);
1.1       root      184:     }
                    185:     while (GOAL.state == ALIVE && alive);    /* loop till all are dead */
                    186: }
                    187: 
                    188: /*
1.1.1.2 ! root      189:  * This thread manages the individual attackers.  It is spun off as
1.1       root      190:  * many times as needed for a game.
                    191:  *
                    192:  * The interaction of the mouse cursor and the chaser character is sort
                    193:  * of funny, hence the funny code, below.  The mouse cursor seems to
                    194:  * remember what was under it when it was written.  Hence we cannot erase
                    195:  * the chaser if the mouse is "sitting" on it. If we do, then when the
                    196:  * mouse moves it will re-write the original object.  This shows up as
                    197:  * phantom chasers.
                    198:  */
                    199: void far chasethread(ID)              /* code that controls each "chaser" */
                    200: int ID;
                    201: {
                    202:     short  row, col;          /* Our current position */
                    203:     short  deltaX, deltaY;     /* how far from the mouse are we? */
                    204:     short  danger;            /* flag to indicate not far enough! */
                    205:     short  m;                 /* general purpose indexes */
                    206: 
                    207: 
                    208:     /* Print out the initial chaser character */
                    209: 
1.1.1.2 ! root      210:     VioWrtCellStr( Chaser, 2, ME.row, ME.col, 0 );
1.1       root      211: 
                    212:     /*
                    213:      * Keep running as long as the goal and myself haven't been killed.
                    214:      */
                    215:     for (;;) {
                    216: 
                    217:        row = ME.row;             /* Grab the current position */
                    218:        col = ME.col;
                    219:        /*
                    220:         * If mouse is sitting upon the chaser, do nothing.  Allow
                    221:         * the player some time to kill the chaser
                    222:         */
                    223:        if ((MOUSE.row == row) && (MOUSE.col == col)) {
1.1.1.2 ! root      224:            DosSleep( 1L );
1.1       root      225:            continue;
                    226:        }
1.1.1.2 ! root      227:        DosSemRequest(&Semaphore, WAIT);
1.1       root      228:        /*
                    229:         * If either the GOAL or Myself is dead, exit loop and clean up.
                    230:         * This wasn't tested in the for loop since we don't want to exit
                    231:         * if the MOUSE is sitting on the chaser.
                    232:         */
                    233:        if (ME.state != ALIVE || GOAL.state != ALIVE)
                    234:            break;
                    235: 
                    236:        deltaX = MOUSE.col - col;       /* calculate how far we are */
                    237:        deltaY = MOUSE.row - row;
                    238: 
                    239:        if (((deltaX < -DANGERZONE) || (DANGERZONE < deltaX)) ||
                    240:            ((deltaY < -DANGERZONE) || (DANGERZONE < deltaY))) {
                    241: 
                    242:            danger = 0;
                    243: 
                    244:            if(GOAL.row < row)              /* Creep towards the GOAL */
                    245:                row--;
                    246:            else if (GOAL.row > row)
                    247:                row++;
                    248:            if(GOAL.col < col)
                    249:                col--;
                    250:            else if(GOAL.col > col)
                    251:                col++;
                    252:        }
                    253:        else {
                    254:            danger = 1;                     /* Run away from the mouse */
                    255: 
                    256:            if ((MOUSE.row > row) && (row > 0))
                    257:                row--;
                    258:            else if ((MOUSE.row < row) && (row < ScreenHeight))
                    259:                row++;
                    260:            if ((MOUSE.col > col) && (col < ScreenWidth))
                    261:                col--;
                    262:            else if ((MOUSE.col < col) && (col > 0))
                    263:                col++;
                    264:        }
                    265:        /*
                    266:         * A quick and Dirty hack to prevent chasers from merging
                    267:         */
                    268:        for (m = 0; m < CHASER; m++ ) {
                    269:            if (univ[m].state == ALIVE &&
                    270:                univ[m].row == row &&
                    271:                univ[m].col == col &&
                    272:                m != ID) {
                    273:               row += 1;
                    274:               col += 3;
                    275:            }
                    276:        }
                    277:        /*
                    278:         * Zap the old chaser and print the new.  Release the semaphore
                    279:         * after this, there can be no undesirable interactions now.
                    280:         */
1.1.1.2 ! root      281:        VioWrtCellStr( Blank, 2, ME.row, ME.col, 0 );
        !           282:        VioWrtCellStr( Chaser, 2, row, col, 0 );
1.1       root      283: 
1.1.1.2 ! root      284:        DosSemClear(&Semaphore);
1.1       root      285:        /*
                    286:         * Update the current location
                    287:         */
                    288:        ME.row = row;
                    289:        ME.col = col;
                    290:        /*
                    291:         * See if we have reached the GOAL, if so eat it and exit
                    292:         */
                    293:        if ((row == GOAL.row) && (col == GOAL.col)) {
1.1.1.2 ! root      294:            VioWrtCellStr( Blank, 2, row, col, 0 );
        !           295:            DosBeep(600,175);
        !           296:            DosBeep(1200,175);      /* if we reach the prize, let out a yell */
        !           297:            DosBeep(600,185);       /* paint the screen red and end the game */
        !           298:            DosBeep(1200,175);
        !           299:            VioScrollUp( 0, 0, -1, -1, -1, Blood, 0 );
1.1       root      300:            GOAL.state = DEAD;
                    301:        }
                    302:        /*
                    303:         * Sleep an amount of time that varies depending
                    304:         * upon the danger level
                    305:         */
                    306:        if( danger )
1.1.1.2 ! root      307:            DosSleep(Shortnap);
1.1       root      308:        else
1.1.1.2 ! root      309:            DosSleep(Longnap);
1.1       root      310: 
                    311:     }
                    312:     /*
                    313:      * chaser is now dead or the game is over.
                    314:      * Erase its body and terminate the thread.  Release the semaphore.
                    315:      */
1.1.1.2 ! root      316:     DosSemClear(&Semaphore);
1.1       root      317: 
                    318:     if (GOAL.state == ALIVE) {
1.1.1.2 ! root      319:        VioWrtCellStr(Blank, 2, ME.row, ME.col, 0 );
1.1       root      320:     }
1.1.1.2 ! root      321:     DosExit( EXIT_THREAD ,0);
1.1       root      322: }
                    323: 
                    324: /*
                    325:  * InitGame()
                    326:  *
                    327:  * Initialize the GOAL, MOUSE and the CHASERS, launch each chase thread.
                    328:  *
                    329:  * Returns an error if any internal processing errors
                    330:  */
                    331: int InitGame()
                    332: {
1.1.1.2 ! root      333:     struct _PTRLOC InitMouPos;
1.1       root      334:     void far chasethread();            /* code to control chasers */
1.1.1.2 ! root      335:     PBYTE Tstack;                      /* stack for new threads */
1.1       root      336:     unsigned chaseID;
                    337:     int i, rc;
                    338:     /*
                    339:      * Clear the screen.
                    340:      */
1.1.1.2 ! root      341:     VioScrollUp( 0, 0, -1, -1, -1, Blank, 0 );
1.1       root      342:     /*
                    343:      * Draw the prize
                    344:      */
                    345:     GOAL.row = ScreenHeight/2;
                    346:     GOAL.col = ScreenWidth /2;
                    347:     GOAL.state = ALIVE;
1.1.1.2 ! root      348:     VioWrtCellStr(Prize, 2, GOAL.row, GOAL.col, 0 );
1.1       root      349:     /*
                    350:      * Open the mouse pointer device and set it's location.
                    351:      */
1.1.1.2 ! root      352:     MouOpen( 0L, &Mouse );
        !           353:     InitMouPos.row = GOAL.row;
        !           354:     InitMouPos.col = GOAL.col;
        !           355:     MouSetPtrPos( &InitMouPos, Mouse);
        !           356:     MouDrawPtr(Mouse);
1.1       root      357:     /*
                    358:      * A simple minded initialization for the start of each chaser.
                    359:      * Some sort of random placement (based upon system time?) would
                    360:      * be nice.
                    361:      */
                    362:     univ[0].row = 0;  univ[0].col = 0;
                    363:     univ[1].row = 0;  univ[1].col = 25;
                    364:     univ[2].row = 0;  univ[2].col = 55;
                    365:     univ[3].row = 0;  univ[3].col = 79;
                    366:     univ[4].row = ScreenHeight;  univ[4].col = 0;
                    367:     univ[5].row = ScreenHeight;  univ[5].col = 25;
                    368:     univ[6].row = ScreenHeight;  univ[6].col = 55;
                    369:     univ[7].row = ScreenHeight;  univ[7].col = 79;
                    370:     /* 
                    371:      * Grab the semaphore to prevent chaser from running until we are done.
                    372:      */
1.1.1.2 ! root      373:     DosSemRequest(&Semaphore, WAIT);
1.1       root      374: 
                    375:     for( i = 0; i < CHASER; i++ ) {            /* for each of our threads... */
                    376:        univ[i].state = ALIVE;                  /* Set each one alive */
1.1.1.2 ! root      377:        Tstack = (PBYTE)malloc(sizeof(int) * STACKSIZE);
1.1       root      378:        if (Tstack == NULL ) {                  /* Create a stack */
                    379:            printf( "thread %d stack malloc failed\n", i );
                    380:            return(1);
                    381:        }
1.1.1.2 ! root      382:        Tstack += sizeof(int)*STACKSIZE; /* set stack pointer to correct end */
        !           383:        *--Tstack = HIBYTE(i);
        !           384:        *--Tstack = LOBYTE(i);           /* Push the ID on as a parameter */
1.1       root      385: 
1.1.1.2 ! root      386:        rc = DosCreateThread(chasethread, &chaseID, Tstack);
1.1       root      387:        if(rc) {
                    388:            printf( "create of thread %d failed, error: %d\n", i, rc );
                    389:            return (1);
                    390:        }
                    391:     }
1.1.1.2 ! root      392:     DosSemClear(&Semaphore);
1.1       root      393: 
                    394:     return (0);
                    395: }
                    396: 
                    397: /*
                    398:  * CleanUp()
                    399:  *
                    400:  * Routine to reset the Video modes back to where they were.
                    401:  * (As best as possible).
                    402:  */
                    403: void CleanUp()
                    404: {
                    405:     char blank[2];
                    406: 
1.1.1.2 ! root      407:     DosSleep(1L);           /* Yield the machine so attacker can clean up */
        !           408:     VioSetMode( &OldVioMode, 0);
1.1       root      409: /*
                    410:     blank[0] = ' ';
                    411:     blank[1] = OldVioMode.color;
1.1.1.2 ! root      412:     VioScrollUp( 0, 0, -1, -1, -1, blank, 0 );
1.1       root      413: */
1.1.1.2 ! root      414:     VioSetCurType( &OldCur, 0);
        !           415:     DosExit(EXIT_PROCESS,0);         /* Exit and terminate all threads. */
1.1       root      416: }
                    417: 
                    418: /*
                    419:  * ParseCmdLine(ac, av)
                    420:  *
                    421:  * Parses the command line arguments and sets up the game accordingly
                    422:  *
                    423:  */
                    424: int ParseCmdLine(ac,av)
                    425: int ac;
                    426: char **av;
                    427: {
1.1.1.2 ! root      428:     struct _VIOMODEINFO modedata;
1.1       root      429:     int    VioMode;
                    430: 
                    431:     Longnap = LONGNAP;
                    432:     Shortnap = SHORTNAP;
                    433:     ScreenWidth = SCREEN_WIDTH;
                    434:     ScreenHeight = SCREEN_HEIGHT;
                    435:     VioMode = 25;
                    436: 
                    437:     while(--ac) {
                    438:        av++;
                    439:        switch(**av) {
                    440:            case 'f':
                    441:            case 'F':
                    442:                Longnap = LONGNAP / 2;
                    443:                Shortnap= SHORTNAP/ 2;
                    444:                break;
                    445:            case 'm':
                    446:            case 'M':
                    447:                Longnap = LONGNAP;
                    448:                Shortnap= SHORTNAP;
                    449:                break;
                    450:            case 's':
                    451:            case 'S':
                    452:                Longnap = LONGNAP * 2;
                    453:                Shortnap= SHORTNAP* 2;
                    454:                break;
                    455:            case '4':       /* Assume 43 line mode was wanted */
                    456:                ScreenHeight = 42;
                    457:                ScreenWidth  = 79;
                    458:                VioMode = 43;
                    459:                break;
                    460:            case '2':
                    461:                ScreenHeight = 24;
                    462:                ScreenWidth  = 79;
                    463:                VioMode = 25;
                    464:                break;
                    465:            default:
                    466:                return(1);
                    467:        }
                    468:     }
                    469: 
1.1.1.2 ! root      470:     VioGetCurType(&OldCur, 0);         /* Save old cursor */
1.1       root      471: 
1.1.1.2 ! root      472:     modedata.cb = sizeof(modedata); /* change mode as needed */
        !           473:     VioGetMode( &modedata, 0);
1.1       root      474:     OldVioMode = modedata;
                    475:     modedata.row = VioMode;
1.1.1.2 ! root      476:     VioSetMode( &modedata, 0);
1.1       root      477: 
1.1.1.2 ! root      478:     NewCur.yStart = 0;
        !           479:     NewCur.cEnd = 0;
        !           480:     NewCur.cx = 1;
        !           481:     NewCur.attr = -1;
1.1       root      482: 
1.1.1.2 ! root      483:     VioSetCurType( &NewCur, 0 );        /* make cursor go away */
1.1       root      484: 
                    485:     return (0);
                    486: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.