Annotation of os2sdk/demos/apps/chaser/chaser.c, revision 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.