This is BattleView.m in view mode; [Download] [Up]
// BattleView V2.0 8/28/93 modified by cat >>>>>>>> tabsize 4 - windowwidth 95 char <<<<<<<<<< #import "BattleView.h" /* Resize so that the first line of this file does not break. Copyright 1992, Stefanos Kiakas. All rights reserved. You may not delete this notice. */ // 8/26/93 sounds added by cat // 8/27/93 bonusPoints rewritten, performance improved with register, sizeTo:: added by cat // 8/28/93 Scoring and BonusCity improved, 2 based play // 8/28/93 PSWs rewritten, hundereds of PSflushgraphics,and focusLocks removed #define CITYBONUS 100 /* city saved bonus */ #define MSLBONUS 10 /* missiles saved bonus */ #define MSLDSTRCT 100 /* attack missle intercepted ( destroyed ) bonus */ #define BOMBERSCORE 300 /* smartbomb */ #define SMARTSCORE 1000 /* smartbomb */ #define BONUSMARK 10000 /* give bonus city every so many points */ #define RANDTARGET ( random() % TARGETS) /* select a random target to attack */ #define RANDLAUNCH ( ( random() % 440 ) + 20 ) /* x pos. of attack missles */ #define PLACECITY(x) ( random() % x ) /* selct position to place city */ #define RAND(x) ( ( random() % (1+x) ) + x/2 ) /* random from x/2 to 3/2 x */ #define ZERO 0 #define MAXRADIUS 15.0 /* maximum radius of explosions */ #define TERRAINCOLOUR 0.20 #define DELTA_TIME 100 #define TIMEINTERVAL DELTA_TIME/1000.0 #define RADINC 1.0 /* radius increment of explosion circles */ #define MAXDEFLAUNCH 15 /* maximum number of defensive missiles */ #define MAXATCKMSSLS 15 /* maximum number of attack missiles */ #define BOMBERSTART 5 /* Level Bombers start on */ #define BOMBEREVERY 3 /* Add another bomb for bombers every */ #define LAUNCH_X 75.0 /* Coords for the defensive launch */ #define LAUNCH_Y 22.0 #define LAUNCH_X2 425.0 /* Coords for the defensive launch */ #define LAUNCH_Y2 22.0 #define DISP 5.0 /* Defensive missile speed */ #define DISPDELTA 0.2 /* Defensive missile speed increment per level */ #define CDX 18.0 /* center of target from display coordinates */ #define OLAUNCH_Y 390.0; /* Y launch position of attack missles */ #define H_CURSOR 330 #define W_CURSOR 460 #define Y_CURSOR 50 #define X_CURSOR 20 #define H_TRG Y_CURSOR + H_CURSOR #define W_TRG X_CURSOR + W_CURSOR #define Y_TRG Y_CURSOR #define X_TRG X_CURSOR #define MAX_dFactor 3.0 /* Max speed for incoming missiles */ #define STARTDIFF 0.5 /* start difficulty level */ #define FACTORINC 0.12 /* increment in difficulty level */ #define SCOREXPOS 150 #define SCOREYPOS 250 #import "MissileCommand.h" // The new PSWraps ! by cat #import <mach/mach.h> #include <sys/param.h> #import <libc.h> #import <math.h> #import <appkit/appkit.h> #import <soundkit/Sound.h> #import <soundkit/soundkit.h> #import "SoundEffect.h" unsigned currentTimeInMs() /* return time in 1/1000th of a second */ { struct timeval curTime; gettimeofday(&curTime, NULL); return ((unsigned)curTime.tv_sec) * 1000 + curTime.tv_usec / 1000; } BOOL testDefensiveBombs(EXP_PNTR DefExplosions, NXPoint testpoint) { /* Test to see if incoming missiles are hit */ while (DefExplosions != NULL) { /* If the distance to the explosion <= * Radius... */ /* Do 2 quick tests before we start doing sqrt and ^2 */ if ((fabs(testpoint.x - DefExplosions->currentPoint.x) <= DefExplosions->rad) && (fabs(testpoint.y - DefExplosions->currentPoint.y) <= DefExplosions->rad) && (sqrt(pow(testpoint.x - DefExplosions->currentPoint.x, 2) + pow(testpoint.y - DefExplosions->currentPoint.y, 2)) <= DefExplosions->rad)) { return TRUE; } DefExplosions = DefExplosions->next; } return FALSE; } BOOL testDefensiveBombsvSmart(EXP_PNTR DefExplosions, NXPoint testpoint, NXPoint *heatpoint, float *heatdist) { /* Is it dead, or near an explosion */ float thisdist; *heatdist = 0; while (DefExplosions != NULL) { if ((thisdist = sqrt(pow(testpoint.x - DefExplosions->currentPoint.x, 2) + pow(testpoint.y - DefExplosions->currentPoint.y, 2))) <= DefExplosions->rad) { return TRUE; } if ((thisdist <= (MAXRADIUS + 2)) && ((*heatdist == 0.0) || (thisdist < *heatdist))) { /* If it's close, and there are no previos or * closer */ *heatdist = thisdist; *heatpoint = DefExplosions->currentPoint; } DefExplosions = DefExplosions->next; } return FALSE; } @implementation BattleView - initFrame:(const NXRect *)frm { NXPoint mySpot; [super initFrame:frm]; [self allocateGState]; gameRunning = FALSE; gamePaused = FALSE; PSWinit(); redAlertSound = [[SoundEffect alloc] initFromSection:"RedAlert.snd"]; emptyBaseSound = [[SoundEffect alloc] initFromSection:"EmptyBase.snd"]; missileAlertSound = [[SoundEffect alloc] initFromSection:"MissileAlert.snd"]; countCitySound = [[SoundEffect alloc] initFromSection:"City.snd"]; countRocketSound = [[SoundEffect alloc] initFromSection:"Rocket.snd"]; bonusCitySound = [[SoundEffect alloc] initFromSection:"BonusCity.snd"]; exploSound = [[SoundEffect alloc] initFromSection:"Explo.snd" withLimit:8]; surfExploSound = [[SoundEffect alloc] initFromSection:"SurfExplo.snd" withLimit:4]; launchSound = [[SoundEffect alloc] initFromSection:"Launch.snd" withLimit:4]; smartBombSound = [[SoundEffect alloc] initFromSection:"SmartBomb.snd" withLimit:2]; cityBitmap = [NXImage findImageNamed:"city3.tiff"]; launcherBitmap = [NXImage findImageNamed:"mBase.tiff"]; bomberBitmap = [NXImage findImageNamed:"Bomber.tiff"]; smartbombBitmap = [NXImage findImageNamed:"SmartBomb.tiff"]; playSound = TRUE; /* Listen to the neato sound */ gameLevel = 1; bomber.hotspots[0].x = 44.0; /* Set the Bomber HotSpots (are tested for hits) */ bomber.hotspots[0].y = 2.0; bomber.hotspots[1].x = 26.0; bomber.hotspots[1].y = 0.0; bomber.hotspots[2].x = 12.0; bomber.hotspots[2].y = 0.0; bomber.hotspots[3].x = 12.0; bomber.hotspots[3].y = 10.0; cursorImage = [NXCursor newFromImage:[NXImage newFromSection:"targetD3.tiff"]]; cBounds.origin.x = X_CURSOR; cBounds.origin.y = Y_CURSOR; cBounds.size.width = W_CURSOR; cBounds.size.height = H_CURSOR; mySpot.x = 8; /* Set the cursor hot spot */ mySpot.y = 7; srandom(currentTimeInMs()); [cursorImage setHotSpot:&mySpot]; return self; } - sizeTo:(NXCoord)width :(NXCoord)height // this is too easy not to implement (cat) { static NXCoord sx=1,sy=1; [super sizeTo:width :height]; [self scale:sx :sy]; // scale back to 1:1 (scale works relatively) [self scale:width/500 :height/400]; sx=500/width; // this is for next time to scale back to the original value sy=400/height; return self; } - switchSound:sender { playSound = !playSound; [SoundEffect setSoundEnabled:playSound]; return self; } - pauseGame:sender { /* Pause or start the game */ void stepFun(); if(gameRunning && !gamePaused) { gameRunning = FALSE; gamePaused = TRUE; DPSRemoveTimedEntry(gameTimer); [[toButtonMatrix cellAt:1 :0] setEnabled:NO]; // start button [toButtonMatrix display]; return self; } if(!gameRunning && gamePaused) { gameRunning = TRUE; gamePaused = FALSE; gameTimer = DPSAddTimedEntry(TIMEINTERVAL, &stepFun, self, NX_BASETHRESHOLD); [[toButtonMatrix cellAt:1 :0] setEnabled:YES]; // start button [toButtonMatrix display]; return self; } return self; } - resetCursorRects { [self addCursorRect:&cBounds cursor:cursorImage]; return self; } - newGame:sender { /* Initialize a new game, or end existing one */ char levelString[15]; int i; /* Counter */ void stepFun(); /* for the DPStimedentry */ MSLE_NODE_PNTR currentPointdm, fpdm; /* *KJW* didn't name these * variables */ MA_NODE_PNTR currentPointam, fpam; EXP_PNTR currentPointe, fpe; SMART_NODE_PNTR smarthead, smart2free; if(gamePaused) return self; if(!gameRunning) { gameLevel = 1; [[toButtonMatrix cellAt:0 :0] setEnabled:YES]; // pause button [toButtonMatrix display]; sprintf(levelString, "Level %02d", gameLevel); [levelText setStringValue:levelString]; dFactor = STARTDIFF; /* Set the difficulty factor */ phaseOne = TRUE; defensiveMissiles.launched = 0; /* Initialize the various lists */ defensiveMissiles.next = NULL; offensiveMissiles.launched = 0; offensiveMissiles.next = NULL; defensiveExplosions.exploding = 0; defensiveExplosions.next = NULL; smartBombs.launched = 0; smartBombs.next = NULL; bomber.launched = 0; for (i = 0; i < CITIES; i++) /* Initialize the cities */ cityStatus[i] = TRUE; /* reset number of missiles */ aTimeBefore = currentTimeInMs(); /* select attack positions */ [self selectTargets]; missiles1 = 20; missiles2 = 20; score = 0; lastBonusAt = 0; displayBase1 = TRUE; displayBase2 = TRUE; [outMissiles setIntValue:missiles1]; [toRightMissiles setIntValue:missiles2]; [window makeKeyAndOrderFront:self]; gameRunning = TRUE; gameTimer = DPSAddTimedEntry(TIMEINTERVAL, &stepFun, self, NX_BASETHRESHOLD); [self display]; return self; } if (gameRunning) { [[toButtonMatrix cellAt:0 :0] setEnabled:NO]; // pause button [toButtonMatrix setState:NO at:1 :0]; // start button [toButtonMatrix display]; [highScoreTable putInHighScores: score]; gameRunning = FALSE; DPSRemoveTimedEntry(gameTimer); /* remove entries in linked lists */ currentPointdm = defensiveMissiles.next; while (currentPointdm != NULL) { fpdm = currentPointdm; currentPointdm = currentPointdm->next; free(fpdm); } /* remove attack missiles from list, and free memory */ currentPointam = offensiveMissiles.next; while (currentPointdm != NULL) { fpam = currentPointam; currentPointam = currentPointam->next; free(fpam); } /* remove air explosions from list and free memory */ currentPointe = defensiveExplosions.next; while (currentPointe != NULL) { fpe = currentPointe; currentPointe = currentPointe->next; free(fpe); } /* remove surface explosions from list and free memory */ currentPointe = surfaceExplosions.next; while (currentPointe != NULL) { fpe = currentPointe; currentPointe = currentPointe->next; free(fpe); } /* remove smartbombs and free memory -KJW */ smarthead = smartBombs.next; smartBombs.launched = 0; while (smarthead != NULL) { smart2free = smarthead; smarthead = smarthead->next; free(smart2free); } } return self; } - (void)step { /* Each frame of movement is done here... */ NXEvent dummyEvent; unsigned int timeNow, dTime;/* Make sure we've waited the right time */ if(!gameRunning) return; do { [self lockFocus]; timeNow = currentTimeInMs(); /* What time is it now? */ dTime = timeNow - aTimeBefore; /* How long's it been? */ if (dTime < (unsigned)DELTA_TIME) /* If it's too soon, wait */ { /* This is pathetic. All I want to do is a damn usleep -KJW */ thread_switch(THREAD_NULL, SWITCH_OPTION_WAIT, (int)(DELTA_TIME - dTime)); } aTimeBefore = timeNow; /* Do what needs doing */ if (defensiveMissiles.launched != 0) [self missilePath]; if (defensiveExplosions.exploding > 0) [self expDraw]; if (offensiveMissiles.launched > 0) [self attackMissilesPath]; if (surfaceExplosions.exploding > 0) [self surfaceExplosionsDraw]; if (bomber.launched > 0) [self doBomber]; if (smartBombs.launched > 0) [self doSmartBomb]; if(defensiveMissiles.launched == 0 && defensiveExplosions.exploding == 0) if(offensiveMissiles.launched == 0 && surfaceExplosions.exploding == 0) if(smartBombs.launched == 0 && bomber.launched == 0) { if(!phaseOne) [self bonusPoints]; [self nextLevel]; } PSflushgraphics(); NXPing(); [self unlockFocus]; } while([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent] == NULL); } - drawSelf:(const NXRect *)r :(int)c { NXPoint Pt; register int i; PSsetgray(1.0); NXRectFill(r); PSsetgray(NX_BLACK); NXFrameRect(r); PSsetgray(TERRAINCOLOUR); PSmoveto(0.0, 0.0); PSrlineto(0.0, 5.0); PSrlineto(50.0, 0.0); PSrlineto(5.0,10.0); // B1 PSrlineto(40.0, 0.0); PSrlineto(5.0,-10.0); PSrlineto(80.0, 0.0); PSrlineto(5.0, 5.0); PSrlineto(40.0, 0.0); PSrlineto(5.0, 3.0); // centerhill PSrlineto(40.0, 0.0); PSrlineto(5.0, -3.0); PSrlineto(40.0, 0.0); PSrlineto(5.0, -5.0); PSrlineto(80.0, 0.0); PSrlineto(5.0,10.0); // B2 PSrlineto(40.0, 0.0); PSrlineto(5.0,-10.0); PSrlineto(50.0, 0.0); PSrlineto(0.0, -5.0); PSclosepath(); PSfill(); [self drawLaunchPad]; for (i = 0; i < CITIES; i++) if(cityStatus[i]) [self drawCityBM:cityBasearray[i].coord]; Pt.x = 200.0; Pt.y = 200.0; return self; } - (void)drawCityBM:(NXPoint)dcurrentPoint { /* Draw a city at dcurrentPoint */ [[cityBitmap lastRepresentation] drawAt:&dcurrentPoint]; } - (void)drawLaunchPad { /* Draw the Launch pad */ if(displayBase1) [[launcherBitmap lastRepresentation] drawAt:&cityBasearray[10].coord]; if(displayBase2) [[launcherBitmap lastRepresentation] drawAt:&cityBasearray[9].coord]; } - (void)drawMissile { /* Draw the missle figure for the score part */ id missileBitmap = [NXImage findImageNamed:"missileIcon.tiff"]; NXPoint Pt; Pt.x = 160.0; Pt.y = 190.0; [[missileBitmap lastRepresentation] drawAt:&Pt]; } - rightMouseDown:(NXEvent *)theEvent { rflag = YES; [self mouseDown:theEvent]; rflag = NO; if(missiles2) [launchSound play]; else [emptyBaseSound play]; if(missiles2 < 3 && missiles2 != 0) [missileAlertSound play]; return self; } - mouseDown:(NXEvent *)theEvent { /* Deal with the IO... */ NXPoint sPt; int pntInRect(); register MSLE_NODE_PNTR mLaunch, p; float h1,h2; if(!gameRunning) return self; sPt = theEvent->location; [self convertPoint:&sPt fromView:nil]; if(defensiveMissiles.launched < MAXDEFLAUNCH && pntInRect(&sPt)) // like && if((rflag && missiles2 > 0) || (!rflag && missiles1 > 0)) { if(rflag) [toRightMissiles setIntValue:--missiles2]; else [outMissiles setIntValue:--missiles1]; defensiveMissiles.launched++; [self lockFocus]; // we really need this one grrrr! PSWmarkloc(sPt.x,sPt.y); [self unlockFocus]; // cat was here ... mLaunch = malloc(sizeof(MSLE_NODE)); mLaunch->destPos = sPt; if(rflag) { mLaunch->currentPos.x = LAUNCH_X2; mLaunch->currentPos.y = LAUNCH_Y2; } else { mLaunch->currentPos.x = LAUNCH_X; mLaunch->currentPos.y = LAUNCH_Y; } mLaunch->startPos = mLaunch->currentPos; mLaunch->next = NULL; h1=sqrt((sPt.y-LAUNCH_Y)*(sPt.y-mLaunch->currentPos.y) + (sPt.x-mLaunch->currentPos.x)*(sPt.x-mLaunch->currentPos.x)); h2=DISP+DISPDELTA*gameLevel; mLaunch->delta_x = h2 * (sPt.x - mLaunch->currentPos.x) / h1; mLaunch->delta_y = h2 * (sPt.y - mLaunch->currentPos.y) / h1; if (defensiveMissiles.next == NULL) defensiveMissiles.next = mLaunch; else { p = defensiveMissiles.next; while (p->next != NULL) p = p->next; p->next = mLaunch; } } if(!rflag) { if(missiles1) [launchSound play]; else [emptyBaseSound play]; if(missiles1 < 3 && missiles1 != 0) [missileAlertSound play]; } return self; } - (void)expDraw { /* Draw the explosions (and handle the logic) */ register EXP_PNTR currentPoint, pp; pp = currentPoint = defensiveExplosions.next; while (currentPoint != NULL) { if (currentPoint->rad > currentPoint->maxrad) /* If we've hit radius start to erase */ { currentPoint->maxReached = YES; currentPoint->rad += (currentPoint->maxReached) ? -RADINC : RADINC; pp = currentPoint; currentPoint = currentPoint->next; } else if ((currentPoint->rad <= 0.0) && currentPoint->maxReached) { /* If we've erased the whole thing */ if (defensiveExplosions.next == currentPoint) { pp = defensiveExplosions.next = currentPoint->next; free(currentPoint); currentPoint = pp; } else { pp->next = currentPoint->next; free(currentPoint); currentPoint = pp->next; } defensiveExplosions.exploding--; } else { /* Just draw the damn thing and increase the radius */ PSWexplode((currentPoint->maxReached) ? NX_WHITE : NX_BLACK, currentPoint->currentPoint.x,currentPoint->currentPoint.y, currentPoint->rad); currentPoint->rad += ((currentPoint->maxReached) ? -RADINC : RADINC); pp = currentPoint; currentPoint = currentPoint->next; } } } - (void)doBomber { /* Handle the bomber */ /* I wrote this (so proud ;-) -KJW */ NXPoint Pt; /* Coundn't tell by the var names, eh? */ register int i; if(bomber.currentPos.x > 0) /* If we've already plotted, erase */ { PSsetgray(NX_WHITE); PSrectfill(bomber.currentPos.x,bomber.currentPos.y,44,9); // cat was here tooo ... but this is nothing to be proud of :=) } for (i = 0; i < 4; i++) { /* Test all the hotspots */ Pt = bomber.hotspots[i]; Pt.x += bomber.currentPos.x; Pt.y += bomber.currentPos.y; if (testDefensiveBombs(defensiveExplosions.next, Pt)) { /* If hit... */ score += BOMBERSCORE; [outScore setIntValue:score]; [self airExplosionAt:&Pt withRadius:35.0]; bomber.launched--; bomber.currentPos.x = 0.0; return; } } bomber.currentPos.x += bomber.delta_x; /* Move the bomber */ [[bomberBitmap lastRepresentation] drawAt:&bomber.currentPos]; if (bomber.currentPos.x > 480) { /* Did we make it to the right side? */ [[bomberBitmap lastRepresentation] drawAt:&bomber.currentPos]; bomber.launched--; bomber.currentPos.x = 0; bomber.bombPos.y = 100.0 + RAND(100); bomber.currentPos.y = bomber.bombPos.y; if (bomber.launched) { /* Want to launch another? */ bomber.bombs = (int)((gameLevel - BOMBERSTART) / BOMBEREVERY + 1) / (int)((gameLevel + BOMBERSTART) / 10) + 1; bomber.bombPos.x = 480 / (bomber.bombs + 1); } return; } if (bomber.currentPos.x > bomber.bombPos.x && (bomber.bombs > 0)) { /* Ready to toss another bomb? */ NXPoint bombPoint = bomber.currentPos; bombPoint.x += 5; /* Put the bomb under the bomber (not at the * back) */ bomber.bombs--; bomber.bombPos.x += (480 - bomber.currentPos.x) / (bomber.bombs + 1); offensiveMissiles.next=[self addToIncoming:bomber.currentPos:1 :offensiveMissiles.next]; } } - (void)doSmartBomb { register SMART_NODE_PNTR CurrentSmartBomb = smartBombs.next; register SMART_NODE_PNTR PreviousSmartBomb = CurrentSmartBomb; NXPoint hotPoint, plotPoint; /* hotPoint will be a close defensive * bomb, plotPoint is where the * smartbomb appears */ float hotDist, /* distance to a close defensive bomb */ delta_x, delta_y, dx, dy; /* for calcing distance and new * movement (smarts) */ /* * set up pointers to point at head of attack missile list */ while (CurrentSmartBomb != NULL) { if(testDefensiveBombsvSmart(defensiveExplosions.next, CurrentSmartBomb->currentPos, &hotPoint, &hotDist)) { /* Did we get hit? (and what was close if not (hot)) */ smartBombs.launched--; /* missile has been destroyed */ score += SMARTSCORE; [outScore setIntValue:score]; [self airExplosionAt:&(CurrentSmartBomb->currentPos)]; /* remove missile from list */ if (CurrentSmartBomb == smartBombs.next) { /* Is this the head of the list */ smartBombs.next = CurrentSmartBomb->next; free(CurrentSmartBomb); CurrentSmartBomb = PreviousSmartBomb = smartBombs.next; } else { PreviousSmartBomb->next = CurrentSmartBomb->next; free(CurrentSmartBomb); CurrentSmartBomb = PreviousSmartBomb; } } else { /* Plot (erase) the bomb where the numbers say it is (not lower left of tiff */ plotPoint = CurrentSmartBomb->currentPos; plotPoint.x -= 3; plotPoint.y -= 2; //[smartbombBitmap composite:NX_XOR toPoint:&plotPoint]; PSsetgray(NX_WHITE); PSrectfill(plotPoint.x,plotPoint.y,5,5); /* calculate next point in trajectory */ /* Find out how far it is to the target */ dx = CurrentSmartBomb->destPos.x - CurrentSmartBomb->currentPos.x; dy = CurrentSmartBomb->destPos.y - CurrentSmartBomb->currentPos.y; /* And move toward it */ delta_y =.9 * dy * INCOMINGBASEV / sqrt(dy * dy + dx * dx); delta_x =.9 * dx * INCOMINGBASEV / sqrt(dy * dy + dx * dx); if (hotDist > 0) { /* Any Close calls */ /* Find out how far it is to the target (defensive bomb) */ dx = hotPoint.x - CurrentSmartBomb->currentPos.x; dy = hotPoint.y - CurrentSmartBomb->currentPos.y; /* And move *AWAY FROM* it */ delta_y -=.9 *.9 * dy * INCOMINGBASEV / sqrt(dy * dy + dx * dx); delta_x -=.9 *.9 * dx * INCOMINGBASEV / sqrt(dy * dy + dx * dx); } /* OK, move the bomb */ CurrentSmartBomb->currentPos.x += dFactor * delta_x; CurrentSmartBomb->currentPos.y += dFactor * delta_y; /* Plot the bomb where the numbers say it is (not lower left of tiff */ plotPoint = CurrentSmartBomb->currentPos; plotPoint.x -= 3; plotPoint.y -= 2; //[smartbombBitmap composite:NX_SOVER toPoint:&plotPoint]; [[smartbombBitmap lastRepresentation] drawAt:&plotPoint]; if (CurrentSmartBomb->currentPos.y < CurrentSmartBomb->destPos.y) { /* Did we reach target */ smartBombs.launched--; if (CurrentSmartBomb->targetLoc == (TARGETS - 1)) { missiles1 = 0; [outMissiles setIntValue:missiles1]; displayBase1 = FALSE; } else if (CurrentSmartBomb->targetLoc == (TARGETS - 2)) { missiles2 = 0; [toRightMissiles setIntValue:missiles2]; displayBase2 = FALSE; } else cityStatus[CurrentSmartBomb->targetLoc] = FALSE; [self surfaceExplosionAt:&(CurrentSmartBomb->currentPos)]; if (CurrentSmartBomb == smartBombs.next) { /* are we the head bomb */ smartBombs.next = CurrentSmartBomb->next; free(CurrentSmartBomb); CurrentSmartBomb = smartBombs.next; } else { PreviousSmartBomb->next = CurrentSmartBomb->next; free(CurrentSmartBomb); CurrentSmartBomb = PreviousSmartBomb; } } } if (CurrentSmartBomb != NULL) { PreviousSmartBomb = CurrentSmartBomb; CurrentSmartBomb = CurrentSmartBomb->next; } } if(smartBombs.launched > [smartBombSound soundsPlaying]) [smartBombSound play]; } - (void)surfaceExplosionsDraw { /* Not my work -KJW -- Plot and deal with surface explosions */ register EXP_PNTR currentPoint, pp; pp = currentPoint = surfaceExplosions.next; while (currentPoint != NULL) { if (currentPoint->rad > MAXRADIUS) { currentPoint->maxReached = YES; currentPoint->rad += (currentPoint->maxReached) ? -RADINC : RADINC; pp = currentPoint; currentPoint = currentPoint->next; } else if ((currentPoint->rad <= 0.0) && currentPoint->maxReached) { if (surfaceExplosions.next == currentPoint) { pp = surfaceExplosions.next = currentPoint->next; PSnewpath(); PSsetgray(NX_WHITE); PSmoveto(currentPoint->currentPoint.x, currentPoint->currentPoint.y); PSrlineto(-10, 0); PSrlineto(0, 20); PSrlineto(30, 0); PSrlineto(0, -20); PSrlineto(-10, 0); PSfill(); free(currentPoint); currentPoint = pp; } else { pp->next = currentPoint->next; PSnewpath(); PSsetgray(NX_WHITE); PSmoveto(currentPoint->currentPoint.x, currentPoint->currentPoint.y); PSrlineto(-10, 0); PSrlineto(0, 20); PSrlineto(30, 0); PSrlineto(0, -20); PSrlineto(-10, 0); PSfill(); free(currentPoint); currentPoint = pp->next; } surfaceExplosions.exploding--; } else { PSWsurfexpl((currentPoint->maxReached) ? NX_WHITE : NX_BLACK, currentPoint->currentPoint.x, currentPoint->currentPoint.y, currentPoint->rad); currentPoint->rad += ((currentPoint->maxReached) ? -RADINC : RADINC); pp = currentPoint; currentPoint = currentPoint->next; } } } - (void)missilePath { /* Not my work -KJW -- Plot and deal with defensive missiles */ NXPoint nPos; /* new missile position */ register MSLE_NODE_PNTR currentPoint,dp; MSLE_NODE_PNTR pp; pp = currentPoint = defensiveMissiles.next; while (currentPoint != NULL) { if (currentPoint->destPos.y <= currentPoint->currentPos.y) { /* missile has reached it destination */ PSWerasetrajectory(currentPoint->startPos.x,currentPoint->startPos.y, currentPoint->destPos.x ,currentPoint->destPos.y); if (currentPoint == defensiveMissiles.next) { defensiveMissiles.next = currentPoint->next; dp = currentPoint; currentPoint = defensiveMissiles.next; } else { pp->next = currentPoint->next; dp = currentPoint; currentPoint = pp->next; } [self airExplosionAt:&(dp->destPos)]; free(dp); defensiveMissiles.launched--; } else { /* calculate and plot next position */ nPos.x = currentPoint->currentPos.x + currentPoint->delta_x; if (currentPoint->delta_x < 0) { /* make sure that point is not past detonation point */ if (nPos.x < currentPoint->destPos.x) nPos.x = currentPoint->destPos.x; } else { if (nPos.x > currentPoint->destPos.x) nPos.x = currentPoint->destPos.x; } nPos.y = currentPoint->currentPos.y + currentPoint->delta_y; if (currentPoint->destPos.y > currentPoint->currentPos.y) { PSWplottrajectory(currentPoint->currentPos.x, currentPoint->currentPos.y,nPos.x,nPos.y); currentPoint->currentPos = nPos; } pp = currentPoint; currentPoint = currentPoint->next; } } } - nextLevel { /* initialize the next level */ int cities, i; cities=0; for(i=0;i<CITIES;i++) if(cityStatus[i]) cities++; if(cities == 0) { missiles1 = 0; missiles2 = 0; [self newGame:self]; // Abort return self; } else { if (phaseOne) phaseOne = FALSE; else { phaseOne = TRUE; if (dFactor < MAX_dFactor) dFactor += FACTORINC; if(cities) { if(gameLevel % 10 == 0) { missiles1 = 99; missiles2 = 99; } else { missiles1 = 20 + gameLevel / 5; missiles2 = 20 + gameLevel / 5; } } displayBase1 = TRUE; displayBase2 = TRUE; } /* reset time */ aTimeBefore = currentTimeInMs(); [outMissiles setIntValue:missiles1]; [toRightMissiles setIntValue:missiles2]; [outScore setIntValue:score]; [self display]; /* calculate attack positions */ [self selectTargets]; { /* Print level number */ char levelString[15]; sprintf(levelString, "Level %02d", gameLevel); [levelText setStringValue:levelString]; } /* initialize bomber values for level */ bomber.currentPos.x = 0.0; bomber.bombPos.y = 100.0 + RAND(100); bomber.currentPos.y = bomber.bombPos.y; bomber.delta_x = 3.0; bomber.launched = (int)((gameLevel + BOMBERSTART) / 10); if (bomber.launched) { bomber.bombs = (int)((gameLevel - BOMBERSTART) / BOMBEREVERY + 1) / (int)((gameLevel + BOMBERSTART) / 10) + 1; bomber.bombPos.x = 480 / (bomber.bombs + 1); } } return self; } /* End 'nextLevel' */ - bonusPoints // cat was here ... and anywhere else { NXPoint cityPt; int cities,i,bmulti = gameLevel/2+1; int vacantPos[CITIES], j; char str[100]; static NXRect fr={200,240,200,30}; static id cbon=0,rbon,bonc,font; if(cbon==0) { cbon = [[TextField alloc] initFrame:&fr]; fr.origin.y = 190; rbon = [[TextField alloc] initFrame:&fr]; fr.origin.x = 190; fr.origin.y = 140; bonc = [[TextField alloc] initFrame:&fr]; [cbon setEditable:NO]; [rbon setEditable:NO]; [bonc setEditable:NO]; font = [Font newFont:"Ohlfs" size:16.0]; [cbon setFont:font]; [rbon setFont:font]; [bonc setFont:font]; } [self addSubview:cbon]; [self addSubview:rbon]; cityPt.x = SCOREXPOS; cityPt.y = SCOREYPOS; cities = 0; for (i = 0; i < CITIES; i++) if (cityStatus[i]) cities++; [self drawCityBM:cityPt]; for (i = 0; i <= cities; i++) { sprintf(str,"%i x %i = %i",i,CITYBONUS*bmulti,i*CITYBONUS*bmulti); [outScore setIntValue:score+i*CITYBONUS*bmulti]; [cbon setStringValue:str]; [countCitySound playEvent]; usleep(300000); } score += cities * CITYBONUS * bmulti; [self drawMissile]; for (i = 0; i <= missiles1; i++) { sprintf(str,"%i x %i = %i",i,MSLBONUS*bmulti,i*MSLBONUS*bmulti); [outScore setIntValue:score+i*MSLBONUS*bmulti]; [outMissiles setIntValue:missiles1-i]; [rbon setStringValue:str]; [countRocketSound playEvent]; usleep(170000); } for (i = 0; i <= missiles2; i++) { sprintf(str,"%i x %i = %i",i+missiles1,MSLBONUS*bmulti,(i+missiles1)*MSLBONUS*bmulti); [outScore setIntValue:score+missiles1*MSLBONUS*bmulti+i*MSLBONUS*bmulti]; [toRightMissiles setIntValue:missiles2-i]; [rbon setStringValue:str]; [countRocketSound playEvent]; usleep(170000); } score += (missiles1 + missiles2) * MSLBONUS * bmulti; while(score-lastBonusAt > BONUSMARK) { j=0; for(i=0;i<CITIES;i++) { if(cityStatus[i]==FALSE) vacantPos[j++] = i; } if(j) { cityStatus[vacantPos[PLACECITY(j)]]=TRUE; lastBonusAt += BONUSMARK; [self addSubview:bonc]; [bonc setStringValue:"BONUS CITY !"]; PSflushgraphics(); NXPing(); [bonusCitySound play]; } else break; // no empty spot ! } gameLevel++; sleep(4); [cbon removeFromSuperview]; [rbon removeFromSuperview]; [bonc removeFromSuperview]; return self; } - selectTargets { /* Get targets for various things */ float dx, dy; int i; MA_NODE_PNTR head, currentPoint, pp; SMART_NODE_PNTR thisSmart, lastSmart; pp = head = currentPoint = malloc(sizeof(MA_NODE)); offensiveMissiles.splitters = MIN(MAXATCKMSSLS, (int)gameLevel / 2); while (++offensiveMissiles.launched <= MAXATCKMSSLS + random()%7-6) { /* attack missles init */ currentPoint->startPos.x = RANDLAUNCH; currentPoint->startPos.y = OLAUNCH_Y; currentPoint->targetLoc = RANDTARGET; currentPoint->destPos.x = cityBasearray[currentPoint->targetLoc].coord.x + CDX; currentPoint->destPos.y = cityBasearray[currentPoint->targetLoc].coord.y; currentPoint->currentPos = currentPoint->startPos; dx = currentPoint->destPos.x - currentPoint->startPos.x; dy = currentPoint->destPos.y - OLAUNCH_Y; currentPoint->delta_y = 1.0 * dy * INCOMINGBASEV / sqrt(dy * dy + dx * dx); currentPoint->delta_x = dx * INCOMINGBASEV / sqrt(dy * dy + dx * dx); if (offensiveMissiles.splitters > 0) { currentPoint->destPos.y = OLAUNCH_Y; currentPoint->destPos.y -= 1.0 / 4.0 * RAND((int)currentPoint->destPos.y); currentPoint->destPos.y -= gameLevel; currentPoint->missileType = SPLITTER; offensiveMissiles.splitters--; } else { currentPoint->missileType = BOMB; } currentPoint->next = malloc(sizeof(MA_NODE)); pp = currentPoint; currentPoint = currentPoint->next; } offensiveMissiles.launched--; offensiveMissiles.next = head; pp->next = NULL; free(currentPoint); smartBombs.next = thisSmart = lastSmart = malloc(sizeof(SMART_NODE)); while (++smartBombs.launched <= (int)(gameLevel - 4) / 3) { /* attack missles init */ thisSmart->currentPos.x = RANDLAUNCH; thisSmart->currentPos.y = OLAUNCH_Y; for (i = 0; i < 10; i++) /* Try to get a good city (bwa-ha-ha) */ { if (cityStatus[thisSmart->targetLoc = RANDTARGET] == TRUE) break; } thisSmart->targetLoc = RANDTARGET; thisSmart->destPos.x = cityBasearray[thisSmart->targetLoc].coord.x + CDX; thisSmart->destPos.y = cityBasearray[thisSmart->targetLoc].coord.y; thisSmart->next = malloc(sizeof(MA_NODE)); lastSmart = thisSmart; thisSmart = thisSmart->next; } smartBombs.launched--; if (smartBombs.launched == 0) { smartBombs.next = NULL; } lastSmart->next = NULL; free(thisSmart); [redAlertSound play:0.1 pan: 0.0]; return self; } - (MA_NODE_PNTR) addToIncoming:(NXPoint)startPoint :(int)number :(MA_NODE_PNTR) next { /* attack missles init */ MA_NODE_PNTR newbomb = malloc(sizeof(MA_NODE)); float dx, dy; offensiveMissiles.launched++; /* missile has been added */ newbomb->startPos = startPoint; newbomb->targetLoc = RANDTARGET; newbomb->destPos.x = cityBasearray[newbomb->targetLoc].coord.x + CDX; newbomb->destPos.y = cityBasearray[newbomb->targetLoc].coord.y; newbomb->currentPos = newbomb->startPos; dx = newbomb->destPos.x - newbomb->startPos.x; dy = newbomb->destPos.y - newbomb->startPos.y; newbomb->delta_y = dy * INCOMINGBASEV / sqrt(dy * dy + dx * dx); newbomb->delta_x = dx * INCOMINGBASEV / sqrt(dy * dy + dx * dx); newbomb->missileType = BOMB; newbomb->next = next; return newbomb; } - (void) airExplosionAt:(NXPoint*)p { register EXP_PNTR newExplosion; register EXP_PNTR ep; newExplosion = malloc(sizeof(EXP_NODE)); newExplosion->currentPoint = *p; newExplosion->rad = 0.0; newExplosion->maxrad = MAXRADIUS + (random() % 10 - 4); // variety is the spice of life // this makes small explosions where you need big ones and the other way round ! newExplosion->maxReached = NO; newExplosion->next = NULL; if (defensiveExplosions.next == NULL) defensiveExplosions.next = newExplosion; else { ep = defensiveExplosions.next; while (ep->next != NULL) ep = ep->next; ep->next = newExplosion; } defensiveExplosions.exploding++; [exploSound play]; } - (void) airExplosionAt:(NXPoint*)p withRadius:(float)r // this is for the bomber { register EXP_PNTR newExplosion; register EXP_PNTR ep; newExplosion = malloc(sizeof(EXP_NODE)); newExplosion->currentPoint = *p; newExplosion->rad = 0.0; newExplosion->maxrad = r; newExplosion->maxReached = NO; newExplosion->next = NULL; if (defensiveExplosions.next == NULL) defensiveExplosions.next = newExplosion; else { ep = defensiveExplosions.next; while (ep->next != NULL) ep = ep->next; ep->next = newExplosion; } defensiveExplosions.exploding++; [exploSound play]; } - (void) surfaceExplosionAt:(NXPoint*)p { register EXP_PNTR ep, newExplosion; newExplosion = malloc(sizeof(EXP_NODE)); newExplosion->currentPoint = *p; newExplosion->rad = 0.0; newExplosion->maxrad = MAXRADIUS + 10; newExplosion->maxReached = NO; newExplosion->next = NULL; if (surfaceExplosions.next == NULL) surfaceExplosions.next = newExplosion; else { ep = surfaceExplosions.next; while (ep->next != NULL) ep = ep->next; ep->next = newExplosion; } surfaceExplosions.exploding++; [surfExploSound play]; } - (void) attackMissilesPath { MA_NODE_PNTR head, currentPoint, pp; NXPoint nextPoint; head = currentPoint = pp = offensiveMissiles.next; /* * set up pointers to point at head of attack missile list */ while (currentPoint != NULL) { /* calculate next point in trajectory */ nextPoint.x = currentPoint->currentPos.x + dFactor * currentPoint->delta_x; nextPoint.y = currentPoint->currentPos.y + dFactor * currentPoint->delta_y; if (nextPoint.y < currentPoint->destPos.y) { /* attack missile has arrived at target */ switch (currentPoint->missileType) { case SPLITTER: { currentPoint->next = [self addToIncoming:currentPoint->currentPos:1 :currentPoint->next]; currentPoint->destPos.y = cityBasearray[currentPoint->targetLoc].coord.y; currentPoint->missileType = BOMB; break; } case BOMB: { offensiveMissiles.launched--; if (currentPoint->targetLoc == (TARGETS - 1)) { missiles1 = 0; [outMissiles setIntValue:missiles1]; displayBase1 = FALSE; } else if (currentPoint->targetLoc == (TARGETS - 2)) { missiles2 = 0; [toRightMissiles setIntValue:missiles2]; displayBase2 = FALSE; } else cityStatus[currentPoint->targetLoc] = FALSE; /* erase missile trajectory */ PSWerasetrajectory(currentPoint->currentPos.x,currentPoint->currentPos.y, currentPoint->startPos.x,currentPoint->startPos.y); /* creat an explosion node for surface explosions */ [self surfaceExplosionAt:&(currentPoint->currentPos)]; if (currentPoint == head) { offensiveMissiles.next = head = currentPoint->next; free(currentPoint); currentPoint = head; } else { pp->next = currentPoint->next; free(currentPoint); currentPoint = pp->next; } break; } } } else /* Test to see if missile is hit */ if (testDefensiveBombs(defensiveExplosions.next, currentPoint->currentPos)) { offensiveMissiles.launched--; /* missile has been destroyed */ score += MSLDSTRCT; [outScore setIntValue:score]; /* erase missile trajectory */ PSWerasetrajectory(currentPoint->currentPos.x,currentPoint->currentPos.y, currentPoint->startPos.x,currentPoint->startPos.y); [self airExplosionAt:&(currentPoint->currentPos)]; /* remove missile from list */ if (currentPoint == head) { offensiveMissiles.next = head = currentPoint->next; free(currentPoint); currentPoint = pp = head; } else { pp->next = currentPoint->next; free(currentPoint); currentPoint = pp->next; } } else { PSWplottrajectory(currentPoint->currentPos.x, currentPoint->currentPos.y, nextPoint.x, nextPoint.y); currentPoint->currentPos = nextPoint; pp = currentPoint; currentPoint = currentPoint->next; } } } - showHighs:sender { [highScoreTable displayHighScores: self]; return self; } int pntInRect(pnt) NXPoint * pnt; { if (pnt->x >= X_TRG && pnt->y >= Y_TRG && pnt->x <= W_TRG && pnt->y <= H_TRG) return (TRUE); else return (FALSE); } void stepFun(DPSTimedEntry timedE, double timeN, void *data) { [(id)data step]; } /**************************************************************************************************/ /* all the following code has been copied from the NeXT answers code provided by NeXT */ /* and is not currently used */ /***************************************************************************************************/ /* Returns the color at a certain pixel location in a bitmap. */ /* This version assumes the bitmap is 1, 2, 4, or 8 bps deep */ /* and its either grayscale or RGB. */ NXColor colorAt(NXBitmapImageRep * image, int x, int y) { int sampleCnt, bps, spp, amask; unsigned char *planes[5], data[5]; NXColorSpace colorSpace; spp = [image samplesPerPixel]; bps = [image bitsPerSample]; colorSpace = [image colorSpace]; #ifdef CHECK_VALIDITY if ((bps != 1 && bps != 2 && bps != 4 && bps != 8) || (colorSpace != NX_RGBColorSpace || colorSpace != NX_OneIsBlackColorSpace || colorSpace != NX_OneIsWhiteColorSpace)) { NXLogError("colorAt() can't deal with provided image.\n"); return NX_COLORCLEAR; } #endif #ifdef CHECK_RANGE if ((x < 0) || (y < 0) || (x >= [image pixelsWide]) || (y >= [image pixelsHigh])) { NXLogError("Pixel out of bounds in colorAt().\n"); return NX_COLORCLEAR; } #endif [image getDataPlanes:planes]; amask = (1 << bps) - 1; /* 1, 3, 15, 255 for bps = 1, 2, 4, 8 */ /* Get the samples into the data[] array. */ if ([image isPlanar]) { int pixel = x * bps; int byteLoc = [image bytesPerRow] * y + (pixel >> 3); int bitLoc = pixel & 7; for (sampleCnt = 0; sampleCnt < spp; sampleCnt++) { data[sampleCnt] = ((*(planes[sampleCnt] + byteLoc)) >> (8 - bitLoc - bps)) & amask; } } else { unsigned char *byteLoc = planes[0] + [image bytesPerRow] * y; int bitLoc = x * bps * spp; for (sampleCnt = 0; sampleCnt < spp; sampleCnt++) { data[sampleCnt] = ((byteLoc[bitLoc >> 3]) >> (8 - (bitLoc & 7) - bps)) & amask; bitLoc += bps; } } /* If no alpha, set it to opaque and increment spp. */ /* Otherwise, compute the true color values (by un-premultipling). */ if (![image hasAlpha]) { data[spp] = amask; spp++; } else if (data[spp - 1] && data[spp - 1] != amask) { for (sampleCnt = 0; sampleCnt < spp - 1; sampleCnt++) { data[sampleCnt] = (unsigned char)(0.5 + amask * (((float)(data[sampleCnt])) / (data[spp - 1]))); } } /* At this point data[] contains spp samples, right justified */ /* within the range 0..amask. We can either return those, or */ /* return them in a normalized fashion (in the range 0..255, */ /* after shifting them over to the left by multiplying them by */ /* 255/amask), or we can return an NXColor. The latter is less */ /* efficient, probably, but most abstract. */ switch (colorSpace) { case NX_RGBColorSpace: return NXConvertRGBAToColor(((float)data[0]) / amask, ((float)data[1]) / amask, ((float)data[2]) / amask, [image hasAlpha] ? ((float)data[3]) / amask : NX_NOALPHA); case NX_OneIsWhiteColorSpace: return NXConvertGrayAlphaToColor(((float)data[0]) / amask, [image hasAlpha] ? ((float)data[1]) / amask : NX_NOALPHA); case NX_OneIsBlackColorSpace: return NXConvertGrayAlphaToColor(((float)(amask - data[0])) / amask, [image hasAlpha] ? ((float)(amask - data[1])) / amask : NX_NOALPHA); case NX_CustomColorSpace:; case NX_CMYKColorSpace:; } return NXConvertGrayAlphaToColor(((float)(amask - data[0])) / amask, [image hasAlpha] ? ((float)(amask - data[1])) / amask : NX_NOALPHA); // just get rid of warning } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.