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

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

unix.superglobalmegacorp.com

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