home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Games / MCommand / Source / BattleView.m < prev    next >
Encoding:
Text File  |  1994-04-01  |  25.2 KB  |  1,092 lines

  1. /*
  2.  
  3.     Copyright 1992, Stefanos Kiakas. All rights reserved.
  4.  
  5.     You may not delete this notice.
  6.  
  7. */
  8. #define ABS(x) ( x < 0 ? -x : x)     /* macro to calculate absolute value */
  9. #define RANDTARGET ( random() % TARGETS)/* select a random target to attack */
  10. #define RANDLAUNCH ( ( random() % 440 ) + 20 ) /* x pos. of attack missles */
  11. #define PLACECITY(x) ( random() % x )  /* selct position to place city */
  12.  
  13.  
  14. #define NULL             0 /* define end of list marker */
  15.  
  16.  
  17. #define MAXRADIUS      15.0  /* maximum radius of explosions */
  18. #define TERRAINCOLOUR   0.20
  19.  
  20. #define TIMEINTERVAL    0.1
  21. #define DELTA_TIME      100
  22. #define RADINC          1.0 /* radius increment of explosion circles */
  23. #define MAXDEFEXP       15  
  24. #define MAXDEFLAUNCH    10  /* maximum number of defensive missiles */
  25. #define MAXATCKMSSLS    10  /* maximum number of attack missiles */
  26.  
  27. /* define launch coordinates for defensive missiles */
  28. #define LAUNCH_X        250.0  
  29. #define LAUNCH_Y        25.0
  30.  
  31. #define DISP             3.0
  32.  
  33. #define CDX             18.0   // center of target from display coordinates
  34.  
  35. #define CITYBONUS      500    // city saved bonus
  36. #define MSLBONUS        50    // missiles saved bonus
  37. #define MSLDSTRCT      100    // attack missle intercepted ( destroyed ) bonus
  38. #define BONUSMARK     7000    // give bonus city every so many points
  39.  
  40. #define OLAUNCH_Y     390.0;  /* Y launch position of attack missles */
  41.  
  42. #define  DX  5.0
  43. #define  DY  5.0
  44.  
  45. #define H_CURSOR    330
  46. #define W_CURSOR    460
  47. #define Y_CURSOR     50
  48. #define X_CURSOR     20
  49.  
  50. #define H_TRG  Y_CURSOR + H_CURSOR
  51. #define W_TRG  X_CURSOR + W_CURSOR
  52. #define Y_TRG   Y_CURSOR
  53. #define X_TRG   X_CURSOR
  54.  
  55.  
  56. #define MAXNDIFF    2.0      /* maximum difficulty for novice level */
  57. #define MAXEDIFF    2.5      /* maximum difficulty for experienced level */
  58. #define MAXPDIFF    3.0      /* maximum difficulty for pro level */
  59.  
  60.  
  61. #define STARTNDIFF  0.8      /* starting difficulty for novice level */
  62. #define STARTEDIFF  0.75     /* starting difficulty for experienced level */
  63. #define STARTPDIFF  0.9      /* starting difficulty for por level */
  64.  
  65. #define DIFFINCN    0.1      /* increase in difficulty after each attack for novice level */
  66. #define DIFFINCE    0.25     /* increase in difficulty after each attack for experienced level */ 
  67. #define DIFFINCP    0.3      /* increase in difficulty after each attack for pro level */
  68.  
  69.  
  70. #define DISPLAYDELAY 50000
  71.  
  72.  
  73. #define SCOREXPOS  150
  74. #define SCOREYPOS  250
  75.  
  76. #import "markLoc.h"
  77. #import "plotTrajectory.h"
  78. #import "scorePhaseCities.h"   
  79. #import "scorePhaseMissiles.h"  
  80.  
  81. #include <sys/param.h>
  82. #import <libc.h>
  83. #import "BattleView.h"
  84. #import <appkit/appkit.h>
  85. #import <soundkit/Sound.h>
  86.  
  87.  
  88.  
  89. @implementation BattleView
  90.  
  91. - initFrame:(const NXRect *) frm
  92. {
  93.    char appD[MAXPATHLEN];
  94.    NXPoint  mySpot;   
  95.  
  96.    [super initFrame:frm ];
  97.    
  98.    [self allocateGState];
  99.    
  100.    gameRunning = FALSE;
  101.    gamePaused = FALSE;
  102.    
  103.    sprintf(appD,"%s/%s",[self appDirectory],"RedAlert.snd");
  104.    
  105.    redAlertSound = [ [Sound alloc] initFromSoundfile:appD ];
  106.    
  107.    cityBitmap = [NXImage findImageNamed:"city3.tiff"];
  108.  
  109.    launcherBitmap = [NXImage findImageNamed:"mBase.tiff"];
  110.    
  111.           
  112.    cursorImage=[NXCursor newFromImage:[NXImage newFromSection:"targetD3.tiff"]];
  113.    cBounds.origin.x = X_CURSOR;
  114.    cBounds.origin.y = Y_CURSOR;
  115.    cBounds.size.width= W_CURSOR;
  116.    cBounds.size.height = H_CURSOR;
  117.      
  118.    mySpot.x = 8;
  119.    mySpot.y = 7;
  120.    [cursorImage setHotSpot:&mySpot];
  121.  
  122.  
  123.    ndiffstart = STARTNDIFF;
  124.    ndiffinc   = DIFFINCN;
  125.    ndiffmax   = MAXNDIFF;
  126.  
  127.    return self;
  128. }
  129.  
  130.  
  131. /* 
  132.    This function was shamelessly copied from the examples provided.
  133.    
  134. */
  135. - (const char *)appDirectory
  136. {
  137.     char *suffix;
  138.     
  139.     strcpy(appDirectory, NXArgv[0]);
  140.     if (suffix = rindex(appDirectory,'/'))
  141.         *suffix = '\0';
  142.     if (appDirectory) chdir(appDirectory);
  143.     getwd(appDirectory);
  144.     return  appDirectory;
  145. }
  146.  
  147. - selectExperienced:sender
  148. {
  149.     ndiffinc = DIFFINCE;
  150.     ndiffstart = STARTEDIFF;
  151.     ndiffmax   = MAXEDIFF;
  152.     return self;
  153. }
  154.  
  155. - selectNovice:sender
  156. {
  157.     ndiffinc = DIFFINCN;
  158.     ndiffstart = STARTNDIFF;
  159.     ndiffmax   = MAXNDIFF;
  160.  
  161.     return self;
  162. }
  163.  
  164. - selectPro:sender
  165. {
  166.     ndiffinc = DIFFINCP;
  167.     ndiffstart = STARTPDIFF;
  168.     ndiffmax   = MAXPDIFF;
  169.  
  170.     return self;
  171. }
  172.  
  173.  
  174. - pauseGame:sender
  175. {
  176.     void stepFun();
  177.  
  178.     if( gameRunning )
  179.     {
  180.        gameRunning = FALSE;
  181.        gamePaused = TRUE;
  182.        DPSRemoveTimedEntry(gameTimer);
  183.     }   
  184.     else if( !gameRunning && gamePaused )
  185.     {
  186.        gameRunning = TRUE;
  187.        gamePaused = FALSE;
  188.        gameTimer =DPSAddTimedEntry(TIMEINTERVAL,&stepFun,self,NX_BASETHRESHOLD);  
  189.     }
  190.     return self;
  191. }
  192.  
  193. - resetCursorRects
  194. {
  195.     [self addCursorRect:&cBounds cursor:cursorImage];
  196.     return self;
  197. }
  198.  
  199. - newGame:sender
  200. {
  201.    int i;
  202.    void stepFun();
  203.    unsigned int currentTimeInMs();
  204.    MSLE_NODE_PNTR   cpdm,fpdm;
  205.    MA_NODE_PNTR     cpam,fpam;
  206.    EXP_PNTR         cpe,fpe;
  207.     
  208.    if( !gameRunning && !gamePaused )
  209.    { 
  210.       /* set up current game difficulty levels */
  211.       cdiffstart = ndiffstart;
  212.       cdiffinc = ndiffinc;
  213.       cdiffmax = ndiffmax;
  214.       
  215.       dFactor = cdiffstart;
  216.       phaseOne = TRUE;
  217.       defensiveMissiles.launched = 0;
  218.       defensiveMissiles.next = NULL;
  219.    
  220.       offensiveMissiles.launched = 0;
  221.       offensiveMissiles.next = NULL;
  222.  
  223.       defensiveExplosions.exploding = 0;
  224.       defensiveExplosions.next = NULL;   
  225.  
  226.       for( i = 0; i < CITIES; i++)
  227.          if( ( i % 3 )  && ( i %4 ) )
  228.             cityStatus[i] = TRUE;
  229.          else
  230.             cityStatus[i] = FALSE;
  231.       
  232.       // reset number of missiles  
  233.       aTimeBefore = currentTimeInMs();
  234.   
  235.       // select attack positions
  236.       [self selectTargets];
  237.   
  238.       missiles = 40;              
  239.       score = 0;
  240.       lastBonusAt = 0;
  241.       displayBase = TRUE;
  242.       
  243.       [outMissiles setIntValue:missiles];
  244.       [outScore setIntValue:score];
  245.       [window makeKeyAndOrderFront:self];
  246.    
  247.       gameRunning = TRUE;
  248.       gameTimer =DPSAddTimedEntry(TIMEINTERVAL,&stepFun,self,NX_BASETHRESHOLD);
  249.     
  250.       [self display]; 
  251.    }
  252.    else if( gameRunning && !gamePaused )
  253.    {
  254.        gameRunning = FALSE;
  255.        DPSRemoveTimedEntry(gameTimer);
  256.        // remove entries in linked lists
  257.        cpdm = defensiveMissiles.next;
  258.        while( cpdm != NULL )
  259.        {
  260.           fpdm = cpdm;
  261.       cpdm = cpdm->next;
  262.       free(fpdm);
  263.        }
  264.        
  265.        /* remove attack missiles from list, and free memory */ 
  266.        cpam = offensiveMissiles.next;
  267.        while( cpdm != NULL )
  268.        {
  269.           fpam = cpam;
  270.       cpam = cpam->next;
  271.       free(fpam);
  272.        }
  273.  
  274.        /* remove air explosions from list and free memory */
  275.        cpe = defensiveExplosions.next;
  276.        while( cpe != NULL )
  277.        {
  278.           fpe = cpe;
  279.       cpe = cpe->next;
  280.       free(fpe);         
  281.        }
  282.        
  283.        /* remove surface explosions from list and free memory */
  284.        cpe = surfaceExplosions.next;
  285.        while( cpe != NULL )
  286.        {
  287.           fpe = cpe;
  288.       cpe = cpe->next;
  289.       free(fpe);
  290.        }
  291.       
  292.    }  
  293.    return self;
  294. }
  295.  
  296.  
  297. unsigned currentTimeInMs()
  298. {
  299.    struct timeval curTime;
  300.    gettimeofday(&curTime, NULL);
  301.    return ((unsigned)curTime.tv_sec)*1000+curTime.tv_usec / 1000;
  302. }
  303.  
  304. - step
  305. {
  306.     NXEvent dummyEvent;
  307.     unsigned int timeNow,dTime;
  308.      
  309.     do
  310.     {
  311.        timeNow = currentTimeInMs();
  312.        dTime = timeNow - aTimeBefore; 
  313.        if( dTime > DELTA_TIME )
  314.        {
  315.           aTimeBefore = timeNow;
  316.        
  317.           if( defensiveMissiles.launched != 0 )
  318.              [self missilePath];
  319.           if( defensiveExplosions.exploding > 0 )
  320.          [self expDraw];
  321.           if( offensiveMissiles.launched > 0)
  322.              [self attackMissilesPath];
  323.           if( surfaceExplosions.exploding > 0 )
  324.              [self surfaceExplosionsDraw];
  325.        }
  326.        if( 
  327.             defensiveMissiles.launched == 0  && 
  328.             defensiveExplosions.exploding == 0    &&
  329.        offensiveMissiles.launched == 0  &&
  330.        surfaceExplosions.exploding  == 0    
  331.          )
  332.     { 
  333.        if( !phaseOne )
  334.           [ self bonusPoints];
  335.            [self nextLevel];
  336.      }   
  337.       NXPing();
  338.     }
  339.     while ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent] == NULL );
  340.     return self;
  341. }
  342.  
  343. - drawSelf:(const NXRect *)r :(int)c
  344. {
  345.    int i;
  346.  
  347.    PSsetgray(1.0);
  348.    NXRectFill(r);
  349.    PSsetgray(NX_BLACK);
  350.    NXFrameRect(r);
  351.     
  352.    // draw terrain
  353.    PSsetgray(TERRAINCOLOUR);
  354.    PSnewpath();
  355.    
  356.    PSmoveto(0.0,0.0);
  357.    PSrlineto(0.0,5.0);
  358.    PSrlineto(50.0,0.0);
  359.    PSrlineto(5.0,5.0);
  360.  
  361.    PSrlineto(40.0,0.0);
  362.    PSrlineto(5.0,-5.0);
  363.  
  364.    PSrlineto(80.0,0.0);
  365.    PSrlineto(5.0,5.0);
  366.  
  367.    PSrlineto(40.0,0.0);
  368.    PSrlineto(5.0,5.0);
  369.    PSrlineto(40.0,0.0);
  370.    PSrlineto(5.0,-5.0);
  371.    PSrlineto(40.0,0.0);
  372.    PSrlineto(5.0,-5.0);
  373.    PSrlineto(80.0,0.0);
  374.    PSrlineto(5.0,5.0);
  375.    PSrlineto(40.0,0.0);
  376.    PSrlineto(5.0,-5.0);
  377.    PSrlineto(50.0,0.0);
  378.    PSrlineto(0.0,-5.0);    
  379.    PSclosepath();
  380.    PSfill();
  381.    PSflushgraphics();
  382.    
  383.    if( displayBase )   /* display missles base if it has not been destroyed */
  384.       [self drawLaunchPad];
  385.       
  386.    for(i=0;i<CITIES; i++)
  387.       if( cityStatus[i] )
  388.          [self drawCityBM:CBarray[i].coord];
  389.    return self;
  390. }
  391.  
  392. - drawCityBM:(NXPoint ) dcPt
  393. {
  394.    [cityBitmap composite:NX_SOVER toPoint:&dcPt];
  395.    return self;
  396. }
  397.  
  398. - drawLaunchPad
  399. {
  400.     NXPoint  Pt;
  401.     Pt.x = 230.0;
  402.     Pt.y = 15.0;
  403.    [launcherBitmap composite:NX_SOVER toPoint:&Pt];
  404.    return self;
  405.  
  406. }
  407. - drawMissile
  408. {
  409.    id missileBitmap = [NXImage findImageNamed:"missileIcon.tiff"];
  410.    NXPoint  Pt;
  411.    Pt.x = 160.0;
  412.    Pt.y = 190.0;
  413.    [missileBitmap composite:NX_COPY toPoint:&Pt];
  414.    return self;
  415. }
  416.  
  417. - mouseDown:(NXEvent *)theEvent
  418. {
  419.        NXPoint sPt;
  420.     int pntInRect();
  421.     MSLE_NODE_PNTR mLaunch,p;
  422.         
  423.     sPt = theEvent->location;
  424.     [self convertPoint:&sPt fromView:nil];
  425.         
  426.     if ( defensiveMissiles.launched < MAXDEFLAUNCH  && missiles > 0  && pntInRect(&sPt))
  427.     {
  428.             [outMissiles setIntValue:--missiles];    
  429.        defensiveMissiles.launched++;
  430.        [self lockFocus];
  431.             markLoc(sPt.x,sPt.y);
  432.        [self unlockFocus];
  433.        
  434.       
  435.        mLaunch = malloc(sizeof(MSLE_NODE));
  436.         
  437.        mLaunch->dPos = sPt;
  438.        mLaunch->cPos.x = LAUNCH_X;
  439.        mLaunch->cPos.y = LAUNCH_Y;
  440.        mLaunch->next   = NULL;
  441.     
  442.        // must check for zeros
  443.       if (ABS(sPt.x - LAUNCH_X) > ABS(sPt.y - LAUNCH_Y))
  444.       {
  445.          mLaunch->delta_x = DISP;
  446.          mLaunch->delta_y = DISP *(sPt.y - LAUNCH_Y) /(sPt.x - LAUNCH_X);
  447.       }
  448.       else
  449.       { 
  450.          mLaunch->delta_y = DISP;
  451.          mLaunch->delta_x = DISP *(sPt.x - LAUNCH_X)/ (sPt.y - LAUNCH_Y);
  452.       }
  453.     
  454.       if ( defensiveMissiles.next == NULL) 
  455.          defensiveMissiles.next = mLaunch;
  456.       else 
  457.       { 
  458.         p = defensiveMissiles.next;
  459.         while (p->next != NULL )
  460.               p = p->next;
  461.         p->next = mLaunch;
  462.        
  463.       }     
  464.      }
  465.  
  466.      return self;
  467. }
  468.  
  469. - expDraw
  470. {
  471.     EXP_PNTR  cp,pp;
  472.     pp = cp = defensiveExplosions.next;
  473.     [self lockFocus];
  474.     while (cp != NULL )
  475.     {
  476.        if (cp->rad > MAXRADIUS )
  477.        {
  478.           cp->maxReached = YES;
  479.       cp->rad += ( cp->maxReached ) ?  -RADINC: RADINC ;
  480.       pp = cp; 
  481.           cp = cp->next;
  482.        }   
  483.        else if ( ( cp->rad <= 0.0 ) && cp->maxReached )
  484.        {
  485.           if ( defensiveExplosions.next == cp )
  486.       {
  487.          pp = defensiveExplosions.next = cp->next;
  488.          free(cp);
  489.          cp = pp;
  490.       }   
  491.       else   
  492.       {
  493.          pp->next = cp->next;
  494.          free(cp);
  495.          cp = pp->next;
  496.       }
  497.       defensiveExplosions.exploding--;
  498.        }   
  499.        else
  500.        {
  501.           PSsetgray((cp->maxReached) ?  NX_WHITE : NX_BLACK );
  502.           PSarc(cp->cPt.x,cp->cPt.y,cp->rad,0.0,360.0);
  503.           PSstroke();
  504.           PSflushgraphics();
  505.        cp->rad += (( cp->maxReached ) ?  -RADINC: RADINC ) ;
  506.       pp = cp; 
  507.       cp = cp->next;
  508.         }  
  509.     }
  510.     [self unlockFocus];  
  511.     return self;
  512. }
  513.  
  514. - surfaceExplosionsDraw
  515. {
  516.       EXP_PNTR  cp,pp;
  517.  
  518.     pp = cp = surfaceExplosions.next;
  519.     [self lockFocus];
  520.     while (cp != NULL )
  521.     {
  522.        if (cp->rad > MAXRADIUS )
  523.        {
  524.           cp->maxReached = YES;
  525.       cp->rad += ( cp->maxReached ) ?  -RADINC: RADINC ;
  526.       pp = cp; 
  527.           cp = cp->next;
  528.        }   
  529.        else if ( ( cp->rad <= 0.0 ) && cp->maxReached )
  530.        {
  531.           if ( surfaceExplosions.next == cp )
  532.       {
  533.          pp = surfaceExplosions.next = cp->next;
  534.          PSnewpath();
  535.          PSsetgray( NX_WHITE);
  536.          PSmoveto(cp->cPt.x,cp->cPt.y);
  537.          PSrlineto(-10,0);
  538.          PSrlineto(0,20);
  539.          PSrlineto(30,0);
  540.          PSrlineto(0,-20);
  541.          PSrlineto(-10,0);
  542.          PSfill();
  543.          PSflushgraphics();
  544.          free(cp);
  545.          cp = pp;
  546.       }   
  547.       else   
  548.       {
  549.          pp->next = cp->next;
  550.          
  551.          PSnewpath();
  552.          PSsetgray( NX_WHITE);
  553.          PSmoveto(cp->cPt.x,cp->cPt.y);
  554.          PSrlineto(-10,0);
  555.          PSrlineto(0,20);
  556.          PSrlineto(30,0);
  557.          PSrlineto(0,-20);
  558.          PSrlineto(-10,0);
  559.          PSfill();
  560.          PSflushgraphics();
  561.  
  562.          free(cp);
  563.          cp = pp->next;
  564.       }
  565.       surfaceExplosions.exploding--;
  566.      
  567.        }   
  568.        else
  569.        {
  570.           [self lockFocus];
  571.           PSsetgray((cp->maxReached) ?  NX_WHITE : NX_BLACK );
  572.           PSarc(cp->cPt.x,cp->cPt.y,cp->rad,1.0,180.0);
  573.           PSstroke();
  574.           PSflushgraphics();
  575.           [self unlockFocus];
  576.       cp->rad += (( cp->maxReached ) ?  -RADINC: RADINC ) ;
  577.       pp = cp; 
  578.       cp = cp->next;
  579.  
  580.         }  
  581.     }
  582.    [self unlockFocus];
  583.    return self;
  584.    
  585.   
  586. }
  587.  
  588.  
  589. - missilePath
  590. {
  591.     NXPoint nPos;  // new missile position
  592.     MSLE_NODE_PNTR  cp,pp,dp;
  593.     EXP_PNTR        nExp;
  594.      
  595.     pp = cp = defensiveMissiles.next;
  596.     [self lockFocus];
  597.     while ( cp != NULL )
  598.     {   
  599.        if ( cp->dPos.y <= cp->cPos.y)                     /* missile has reached it destination  */
  600.        {     
  601.       PSmoveto(LAUNCH_X,LAUNCH_Y);
  602.       PSlineto(cp->dPos.x,cp->dPos.y);
  603.       PSsetgray(NX_WHITE);
  604.       PSsetlinewidth(2.0);
  605.       PSstroke();
  606.       PSsetgray(NX_BLACK);
  607.       PSflushgraphics();
  608.                 
  609.       if ( cp == defensiveMissiles.next )
  610.       {
  611.          defensiveMissiles.next = cp->next;
  612.          dp = cp; 
  613.          cp = defensiveMissiles.next;
  614.       }      
  615.       else
  616.       {                                                           
  617.          pp->next = cp->next;
  618.          dp = cp;
  619.          cp = pp->next; 
  620.       }     
  621.        nExp = malloc(sizeof(EXP_NODE));
  622.       nExp->cPt = dp->dPos;
  623.       nExp->rad = 0.0;
  624.       nExp->maxReached = NO;
  625.       nExp->next = NULL;
  626.          
  627.       free(dp);
  628.       [self addToAirExplosions:nExp];
  629.       defensiveMissiles.launched--;
  630.         }          
  631.     else    /* calculate and plot next position */
  632.     {
  633.      
  634.      
  635.            nPos.x = cp->cPos.x + cp->delta_x;
  636.       if( cp->delta_x  < 0 )      /* make sure that point is not past  detonation point */
  637.        {
  638.            if( nPos.x < cp->dPos.x)
  639.               nPos.x = cp->dPos.x;
  640.        }
  641.        else
  642.        {
  643.            if( nPos.x > cp->dPos.x )
  644.               nPos.x = cp->dPos.x;           
  645.        }  
  646.            nPos.y = cp->cPos.y + cp->delta_y;
  647.        
  648.            if ( cp->dPos.y > cp->cPos.y )
  649.        {
  650.           plotTrajectory(cp->cPos.x,cp->cPos.y,nPos.x,nPos.y);
  651.                cp->cPos = nPos;
  652.            }
  653.        pp = cp;
  654.        cp = cp->next;
  655.      }    
  656.      }
  657.      [self unlockFocus];
  658.      return self;
  659. }
  660.  
  661. - nextLevel
  662. {
  663.    int cities,i;
  664.    
  665.    cities = 0;
  666.    for(i=0;i<CITIES; i++)
  667.       if( cityStatus[ i ] )     
  668.      cities++;       
  669.    
  670.    if( cities == 0 )
  671.       gameRunning = FALSE;
  672.    else
  673.    {  
  674.       if( phaseOne)
  675.          phaseOne = FALSE;
  676.       else
  677.       {
  678.          phaseOne = TRUE;
  679.          if( dFactor < cdiffmax )
  680.             dFactor += cdiffinc;
  681.          missiles = 40;
  682.      displayBase = TRUE;     
  683.       }   
  684.       // reset time  
  685.       aTimeBefore = currentTimeInMs();
  686.   
  687.   
  688.       [outMissiles setIntValue:missiles];
  689.       [outScore setIntValue:score];
  690.    
  691.       [self display];
  692.       
  693.       // calculate attack positions
  694.       [self selectTargets];
  695.       
  696.    } 
  697.    return self;
  698. }
  699.  
  700. - bonusPoints
  701. {
  702.   NXPoint cityPt;
  703.   int  cities,i,re;
  704.   int  vacantPos[ CITIES ],j;
  705.   unsigned int stime,etime;
  706.   
  707.   cityPt.x = SCOREXPOS;
  708.   cityPt.y = SCOREYPOS;
  709.   cities = 0;
  710.   for(i=0;i<CITIES; i++)
  711.       if( cityStatus[ i ] )     
  712.     cities++;    
  713.  
  714.   [self lockFocus];       
  715.   [self drawCityBM:cityPt];
  716.   [self unlockFocus];   
  717.   for(i=0; i <= cities; i++ )
  718.   {  
  719.      [self lockFocus];
  720.      scorePhaseCities(i,i*CITYBONUS,&re);
  721.      [self unlockFocus];
  722.   } 
  723.  
  724.      etime = stime = currentTimeInMs();
  725.      while( etime - stime < 100 )
  726.         etime = currentTimeInMs();  
  727.  
  728.  
  729.   score +=  cities * CITYBONUS;
  730.   [outScore setIntValue:score];
  731.   
  732.   [self lockFocus];
  733.   [self drawMissile];
  734.   [self unlockFocus];
  735.  
  736.   for(i=0; i <= missiles; i++ )
  737.   {
  738.      [self lockFocus];
  739.      scorePhaseMissiles(i,i*MSLBONUS,&re);
  740.      [self unlockFocus];
  741.  
  742.      etime = stime = currentTimeInMs();
  743.      while( etime - stime < 100 )
  744.         etime = currentTimeInMs();
  745.   }   
  746.   
  747.   score += missiles * MSLBONUS;
  748.   [outScore setIntValue:score];
  749.   etime = stime = currentTimeInMs();
  750.   while( etime - stime < 1000 )
  751.      etime = currentTimeInMs();
  752.  
  753.   if( score - lastBonusAt > BONUSMARK )
  754.   {
  755.      lastBonusAt += BONUSMARK;
  756.      j = 0;
  757.      for(i=0;i<CITIES ; i++)
  758.         if( cityStatus[ i ] == FALSE )
  759.        vacantPos[j++] = i; ; 
  760.      
  761.      if( j )
  762.         cityStatus[ vacantPos[PLACECITY(j)]] = TRUE;
  763.      else
  764.         score += CITYBONUS;
  765.      
  766.   }  
  767.   return self;
  768. }
  769.  
  770.  
  771. - selectTargets
  772. {
  773.   float dx,dy;
  774.   MA_NODE_PNTR head,cp,pp;
  775.   pp = head = cp = malloc(sizeof(MA_NODE));
  776.  
  777.   while (++offensiveMissiles.launched <= MAXATCKMSSLS ) /* attack missles init */
  778.   {
  779.      cp->sPos.x = RANDLAUNCH;
  780.      cp->sPos.y = OLAUNCH_Y;
  781.      cp->targetLoc = RANDTARGET;
  782.      cp->dPos.x = CBarray[cp->targetLoc].coord.x + CDX;
  783.      cp->dPos.y = CBarray[cp->targetLoc].coord.y;
  784.      
  785.      cp->cPos = cp->sPos;
  786.      
  787.      dx = cp->dPos.x - cp->sPos.x ;
  788.      dy = cp->dPos.y - OLAUNCH_Y;
  789.      if ( ABS(dy ) > ABS(dx))
  790.      {
  791.         cp->delta_y = -1.0;
  792.     cp->delta_x = ( dx ) / ABS(dy );
  793.      }
  794.      else
  795.      {
  796.         cp->delta_y = ( dy )/ABS( dx ) ;
  797.         cp->delta_x = ABS(dx ) / dx ;
  798.      }
  799.      
  800.      cp->next = malloc(sizeof(MA_NODE));
  801.      pp = cp;
  802.      cp = cp->next; 
  803.       
  804.   }
  805.   offensiveMissiles.launched--;
  806.   offensiveMissiles.next = head;
  807.   pp->next = NULL;
  808.   free(cp);
  809.   [redAlertSound play];  
  810.  
  811.   return self;
  812. }
  813.  
  814. - addToAirExplosions: (EXP_PNTR )aExp
  815. {
  816.      EXP_PNTR ep;
  817.       
  818.      if ( defensiveExplosions.next == NULL )
  819.     defensiveExplosions.next = aExp;
  820.      else
  821.      {           
  822.     ep = defensiveExplosions.next;
  823.     while (ep->next != NULL )
  824.        ep = ep->next;
  825.     ep->next = aExp;
  826.      } 
  827.      defensiveExplosions.exploding++;              
  828.      return self;
  829. }
  830.  
  831. - addToSurfaceExplosions:(EXP_PNTR) aExp
  832. {
  833.     EXP_PNTR ep;
  834.       
  835.     if ( surfaceExplosions.next == NULL )
  836.        surfaceExplosions.next = aExp;
  837.     else
  838.     {           
  839.        ep = surfaceExplosions.next;
  840.        while (ep->next != NULL )
  841.       ep = ep->next;
  842.        ep->next = aExp;
  843.     } 
  844.     surfaceExplosions.exploding++; 
  845.     return self;
  846. }
  847.  
  848.  
  849. - attackMissilesPath
  850. {
  851.     MA_NODE_PNTR head,cp,pp;
  852.     EXP_PNTR     nExp;
  853.     NXPoint nPt;
  854.     NXRect rect = {{0.0, 0.0}, {1.0, 1.0}};
  855.     id image;
  856.     NXColor colorAtSomeLoc, colorAt();
  857.     float alpha,color;
  858.     
  859.     [self lockFocus];
  860.     head = cp = pp = offensiveMissiles.next;   /* set up pointers to point at head of attack missile list */
  861.        while ( cp != NULL )
  862.        {
  863.           // calculate next point in trajectory
  864.           nPt.x = cp->cPos.x + dFactor * cp->delta_x;    
  865.           nPt.y = cp->cPos.y + dFactor * cp->delta_y;
  866.       
  867.       // set rect to check  if missile has been hit
  868.           rect.origin = nPt;
  869.           image = [[NXBitmapImageRep alloc] initData:NULL fromRect:&rect];
  870.           colorAtSomeLoc = colorAt(image, 0, 0);
  871.           [image free];
  872.       
  873.           NXConvertColorToGrayAlpha (colorAtSomeLoc, &color, &alpha);
  874.           if ( nPt.y < cp->dPos.y)   /* attack missile has arrived at target */
  875.           {        
  876.              offensiveMissiles.launched--;
  877.          if  ( cp->targetLoc  ==  ( TARGETS - 1 ) )
  878.          {
  879.              missiles = 0;
  880.                  [outMissiles setIntValue:missiles];
  881.          displayBase = FALSE; 
  882.               }
  883.          else
  884.            cityStatus[ cp->targetLoc ] = FALSE;
  885.          /* erase missile trajectory */
  886.              PSmoveto(cp->cPos.x,cp->cPos.y);
  887.          PSlineto(cp->sPos.x,cp->sPos.y);
  888.          PSsetgray(NX_WHITE);
  889.          PSsetlinewidth(2.0);
  890.          PSstroke();
  891.          PSsetlinewidth(1.0);
  892.              PSflushgraphics();
  893.          
  894.           /* creat an explosion node for surface explosions */
  895.          nExp = malloc(sizeof(EXP_NODE));
  896.          nExp->cPt = cp->cPos;
  897.          nExp->rad = 0.0;
  898.          nExp->maxReached = NO;
  899.          nExp->next = NULL;
  900.          
  901.              [self addToSurfaceExplosions:nExp];   /* add explosion to surface exp. list */
  902.  
  903.              if ( cp == head )
  904.          {
  905.             offensiveMissiles.next = head = cp->next;
  906.             free(cp);
  907.             cp = head;        
  908.          }   
  909.          else
  910.          {
  911.             pp-> next = cp->next;
  912.             free(cp);
  913.             cp = pp->next;
  914.          }      
  915.  
  916.           }
  917.           else if ( ( ABS(color - NX_BLACK) < 0.005 ) && ( cp->cPos.y > 35 ))
  918.           {
  919.              offensiveMissiles.launched--;      // missile has been destroyed
  920.          score += MSLDSTRCT;
  921.          [outScore setIntValue:score];
  922.          // remove missile trajectory
  923.              PSmoveto(cp->cPos.x,cp->cPos.y);
  924.          PSlineto(cp->sPos.x,cp->sPos.y);
  925.          PSsetgray(NX_WHITE);
  926.          PSsetlinewidth(2.0);
  927.          PSstroke();
  928.          PSsetlinewidth(1.0);
  929.              PSflushgraphics();
  930.          
  931.          nExp = malloc(sizeof(EXP_NODE));
  932.          nExp->cPt = cp->cPos;
  933.          nExp->rad = 0.0;
  934.          nExp->maxReached = NO;
  935.          nExp->next = NULL;
  936.              [self addToAirExplosions:nExp];
  937.          
  938.          // remove missile from list
  939.              if ( cp == head )
  940.          {
  941.             offensiveMissiles.next = head = cp->next;
  942.             free(cp);
  943.             cp = pp = head;
  944.          }   
  945.          else
  946.          {
  947.             pp-> next = cp->next;
  948.             free(cp);
  949.             cp = pp->next;
  950.          }      
  951.           }
  952.           else
  953.           {
  954.         plotTrajectory(cp->cPos.x,cp->cPos.y,nPt.x,nPt.y);
  955.         cp->cPos = nPt;
  956.         pp = cp;
  957.             cp = cp->next;         
  958.           }    
  959.        }
  960.        [self unlockFocus];
  961.  
  962.        return self;
  963. }
  964.  
  965. int pntInRect(pnt)
  966. NXPoint *pnt;
  967. {
  968.       if( pnt->x  >= X_TRG && pnt->y >= Y_TRG && pnt->x <= W_TRG && pnt->y <= H_TRG )
  969.          return(TRUE);
  970.       else
  971.           return(FALSE);     
  972. }
  973.  
  974. void stepFun (DPSTimedEntry timedE, double timeN, void *data)
  975. {
  976.   [(id)data step ];
  977. }
  978.  
  979.  
  980.  
  981. /**************************************************************************************************/
  982. /* all the following code has been copied from the NeXT answers code provided by NeXT */
  983. /***************************************************************************************************/
  984.  
  985. /* Returns the color at a certain pixel location in a bitmap. */
  986. /* This version assumes the bitmap is 1, 2, 4, or 8 bps deep  */
  987. /* and its either grayscale or RGB. */
  988.  
  989. NXColor colorAt(NXBitmapImageRep *image, int x, int y)
  990. {
  991.     int sampleCnt, bps, spp, amask;
  992.     unsigned char *planes[5], data[5];
  993.     NXColorSpace colorSpace;
  994.  
  995.     spp = [image samplesPerPixel];
  996.     bps = [image bitsPerSample];
  997.     colorSpace = [image colorSpace];
  998.  
  999. #ifdef CHECK_VALIDITY
  1000.     if ((bps != 1 && bps != 2 && bps != 4 && bps != 8) ||
  1001.        (colorSpace != NX_RGBColorSpace || 
  1002.         colorSpace != NX_OneIsBlackColorSpace || 
  1003.         colorSpace != NX_OneIsWhiteColorSpace)) 
  1004.     {
  1005.         NXLogError ("colorAt() can't deal with provided image.\n");
  1006.         return NX_COLORCLEAR;
  1007.     }
  1008. #endif
  1009. #ifdef CHECK_RANGE
  1010.     if ((x < 0) || (y < 0) || (x >= [image pixelsWide]) || 
  1011.         (y >= [image pixelsHigh])) 
  1012.     {
  1013.         NXLogError ("Pixel out of bounds in colorAt().\n");
  1014.         return NX_COLORCLEAR;
  1015.     }
  1016. #endif
  1017.  
  1018.     [image getDataPlanes:planes];
  1019.    
  1020.     amask = (1 << bps) - 1;    /* 1, 3, 15, 255 for bps = 1, 2, 4, 8 */
  1021.  
  1022.     /* Get the samples into the data[] array. */
  1023.     if ([image isPlanar]) 
  1024.     {
  1025.         int pixel = x * bps;
  1026.         int byteLoc = [image bytesPerRow] * y + (pixel >> 3);
  1027.         int bitLoc = pixel & 7;
  1028.         for (sampleCnt = 0; sampleCnt < spp; sampleCnt++) 
  1029.         {
  1030.             data[sampleCnt] = 
  1031.                 ((*(planes[sampleCnt]+byteLoc)) >> (8 - bitLoc - bps)) & amask;
  1032.         }
  1033.     } 
  1034.     else 
  1035.     {
  1036.         unsigned char *byteLoc = planes[0] + [image bytesPerRow] * y;
  1037.         int bitLoc = x * bps * spp;
  1038.         for (sampleCnt = 0; sampleCnt < spp; sampleCnt++) 
  1039.         {
  1040.             data[sampleCnt] = 
  1041.                ((byteLoc[bitLoc >> 3]) >> (8 - (bitLoc & 7) - bps)) & amask;
  1042.             bitLoc += bps;
  1043.         }
  1044.     }
  1045.  
  1046.     /* If no alpha, set it to opaque and increment spp. */
  1047.     /* Otherwise, compute the true color values (by un-premultipling). */
  1048.  
  1049.     if (![image hasAlpha]) 
  1050.     {
  1051.         data[spp] = amask;
  1052.         spp++;
  1053.     } 
  1054.     else if (data[spp - 1] && data[spp - 1] != amask) 
  1055.     {
  1056.         for (sampleCnt = 0; sampleCnt < spp - 1; sampleCnt++) 
  1057.         {
  1058.             data[sampleCnt] = 
  1059.                (unsigned char)(0.5 + amask * 
  1060.                ( ((float)(data[sampleCnt])) / (data[spp - 1]) ));
  1061.         }
  1062.     }
  1063.  
  1064.     /* At this point data[] contains spp samples, right justified  */
  1065.     /* within the range 0..amask.  We can either return those, or  */
  1066.     /* return them in a normalized fashion (in the range 0..255,   */
  1067.     /* after shifting them over to the left by multiplying them by */
  1068.     /* 255/amask), or we can return an NXColor. The latter is less */
  1069.     /* efficient, probably, but most abstract.   */
  1070.  
  1071.     switch (colorSpace) 
  1072.     {
  1073.     case NX_RGBColorSpace:
  1074.         return NXConvertRGBAToColor(((float)data[0]) / amask, 
  1075.                                      ((float)data[1]) / amask, 
  1076.                                  ((float)data[2]) / amask, 
  1077.                 [image hasAlpha] ? ((float)data[3]) / amask : NX_NOALPHA);
  1078.                 
  1079.     case NX_OneIsWhiteColorSpace:
  1080.         return NXConvertGrayAlphaToColor(((float)data[0]) / amask, 
  1081.                         [image hasAlpha] ? ((float)data[1]) / amask : NX_NOALPHA);
  1082.                     
  1083.     case NX_OneIsBlackColorSpace:
  1084.         return NXConvertGrayAlphaToColor(((float)(amask - data[0])) / amask, 
  1085.                         [image hasAlpha] ? ((float)(amask - data[1])) / amask :
  1086.                     NX_NOALPHA);
  1087.     }
  1088. }
  1089.  
  1090.  
  1091. @end
  1092.