// Warp // By Karl Hornell, June 10, 1996 // Last modified June 27 import java.awt.*; import java.awt.image.*; import java.applet.AudioClip; import java.net.*; import java.awt.Font; public final class warp extends java.applet.Applet implements Runnable { int i,j,k,p,q,r,counter=0,mileage,windowHeight,windowStep,loadedLev=-1; int runMode,objCount,level,lives,currentKey=0,bulletIx,currentSnd=-1; int objX[],objY[],objType[],objMode[],objLook[],objPar[]; int brickPos[],brickType[],brickArea[]; int brickMap[]; int sortBuf1[],sortBuf2[],touching[]={0,0,0,0}; int fixQueueX[],fixQueueY[],fixQueueBrick[]; Font fo; boolean objDraw[],bulletOn,showLights,drawScore; final int maxObj=10,maxLev=9,maxFix=10,objectImages=26,maxOtherBricks=6; final int cyclic[]={0,1,2,1},shark[]={31,32,33,34,35,35,35,35,35,35,35,34,33,32,31}; final int groundMouth[]={46,47,48,49,50,51,52,52,52,51,50,49,48,47,46}; final int cyclic2[]={0,1,2,3,2,1}; final int maxEnemies=4,levObjStart[]={13,19,29,36,43,53,61,74,82,90}; final int blastable=14,totalBricks=10; final int objImX[]={240,280,240,280,296,280,96,128,160,192,224,256,288, 248,288,328,368,408,448, 288,328,368,408,448,488,528,568,608,648, 312,352,392,424,456,488,528, 288,328,368,408,448,488,528, 280,320,360,400,432,464,504,544,584,624, 288,328,368,408,448,488,528,568, 328,368,408,448,488,528,568,600,632,664,704,744,784, 320,360,400,440,480,520,560,600, 320,360,400,440,480,520,560,576}; final int objImY[]={128,128,160,160,160,176,96,96,96,96,96,96,96}; final int objImW[]={40,40,40,16,16,16,32,32,32,32,32,32,32, 40,40,40,40,40,40, 40,40,40,40,40,40,40,40,40,40, 40,40,32,32,32,40,40, 40,40,40,40,40,40,40, 40,40,40,32,32,40,40,40,40,40, 40,40,40,40,40,40,40,40, 40,40,40,40,40,40,32,32,32,40,40,40,40, 40,40,40,40,40,40,40,40, 40,40,40,40,40,40,16,16}; final int objImPractW[]={32,32,32,16,16,16,32,32,32,32,32,32,32, 32,32,32,32,32,32, 32,32,32,32,32,32,32,32,32,32, 32,32,32,32,32,32,32, 32,32,32,32,32,32,32, 32,32,32,32,32,32,32,32,32,32, 32,32,32,32,32,32,32,32, 32,32,32,32,32,32,32,32,32,32,32,32,32, 32,32,32,32,32,32,32,32, 32,32,32,32,32,32,16,16}; final int objImH[]={32,32,32,16,16,16,32,32,32,32,32,32,32, 32,32,32,32,32,32, 32,32,32,32,32,32,32,32,32,32, 32,32,32,32,32,32,32, 32,32,32,32,32,32,32, 32,32,32,32,32,32,32,32,32,32, 32,32,32,32,32,32,32,32, 32,32,32,32,32,32,32,32,32,32,32,32,32, 32,32,32,32,32,32,32,32, 32,32,32,32,32,32,16,16}; final int objNum[]={0,1,2,3,4,5,6,7,8,9,10,11,12, 13,14,15,16,17,18, 13,14,15,16,17,18,19,20,21,22, 13,14,15,16,17,18,19, 13,14,15,16,17,18,19, 13,14,15,16,17,18,19,20,21,22, 13,14,15,16,17,18,19,20, 13,14,15,16,17,18,19,20,21,22,23,24,25, 13,14,15,16,17,18,19,20, 13,14,15,16,17,18,19,20}; final int brickX[]={64, 0,32,72,104,144,176,208, 0,32,72,104,144,184,216,256, 0,32,64,96,128,168,200,240,280, 0,32,64,96,136,176,216,248, 0,32,64,104,136,176,208,240, 0,32,64,104,136,176,216,248, 0,32,72,112,152,192,224,264,296, 0,32,72,112,144,184,216,256,288, 0,32,72,104,136,176,216,256,288}; final int brickW[]={32, 32,40,32,40,32,32,40, 32,40,32,40,32,32,40,32, 32,32,32,32,40,32,40,40,32, 32,32,32,40,40,40,32,40, 32,32,40,32,40,32,32,40, 32,32,40,32,40,40,32,40, 32,40,40,40,40,32,40,32,32, 32,40,40,32,40,32,40,32,32, 32,40,32,32,40,40,40,32,32}; final int levBrickStart[]={1,8,16,25,33,41,49,58,67,76}; final int brickQual[]={0, 0,3,0,1,0,0,1, 0,3,0,3,0,0,1,0, 0,4,4,4,3,4,1,3,4, 0,0,0,1,1,3,0,1, 0,4,3,4,1,4,4,1, 0,0,3,0,1,0,0,1, 0,3,0,3,0,4,1,0,0, 0,1,3,0,3,0,1,0,0, 0,3,0,0,1,1,3,4,0}; final int brickIm[]={0, 1,2,3,4,5,6,7, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8,9, 1,2,3,4,5,6,7,8,9}; final int levBackgr[]={1,8,16,25,33,41,49,58,67}; final int blastBrick[]={2,9,11,20,23,30,35,43,50,52,60,62,68,73}; final int brickPoints[]={15,15,15,20,10,20,25,15,25,20,20,20,25,25}; final double bricksPerLine[]={3,3.2,3,3.1,3,3.2,3.1,3.2,2.9}; final int levBrick[]={2,4,5,6,7,0, 9,11,13,14,15,0, 17,18,19,20,22,23, 26,27,28,29,30,32, 34,35,37,38,39,40, 42,43,45,46,47,48, 50,52,54,55,56,57, 59,60,62,64,65,66, 68,70,71,72,73,75}; final double randBrick[]={0.25,0.5,0.75,0.85,1,1, 0.2,0.4,0.55,0.70,1,1, 0.15,0.30,0.4,0.55,0.80,1, 0.1,0.35,0.5,0.65,0.85,1, 0.15,0.3,0.4,0.55,0.70,1, 0.14,0.46,0.54,0.70,0.85,1, 0.22,0.4,0.5,0.68,0.82,1, 0.18,0.4,0.6,0.75,0.83,1, 0.2,0.34,0.52,0.67,0.83,1}; final int levEnemy[]={7,8,0,0, 8,12,0,0, 13,14,0,0, 7,15,0,0, 8,14,0,0, 15,13,7,0, 15,8,7,0, 7,15,0,0, 8,16,0,0}; final int enemyPoints[]={25,30,0,0, 30,40,0,0, 40,50,0,0, 35,30,0,0, 30,50,0,0, 30,40,25,0, 20,30,25,0, 25,25,0,0, 30,25,0,0}; final double randEnemy[]={0.5,1,1,1, 0.5,1,1,1, 0.5,1,1,1, 0.5,1,1,1, 0.5,1,1,1, 0.4,0.6,1,1, 0.4,0.7,1,1, 0.5,1,1,1, 0.7,1,1,1}; final int levLength[]={700,700,700,700,700,700,700,700,700}; Image offImage,landscape,defaultStrip,modStrip,logo,bricks[]; Image panel,outline[],objects[],scoreDisp,clearDisp,clearScreen; AudioClip sound[]; Graphics offGraphics,landscapeG,defaultSG,modSG,scoreDG,clearDG,clearSG; Color bgcolor; ImageFilter filter; Thread updateThread; long startTime,score,newScore,tempScore,highScores[]={0,0,0,0,0}; Math m; public void init() { bgcolor=findBGColor(); setBackground(bgcolor); fo=new Font("Courier",Font.BOLD,14); setFont(fo); sound=new AudioClip[3]; sound[0] = getAudioClip(getCodeBase(),"warpsnd0.au"); sound[1] = getAudioClip(getCodeBase(),"warpsnd1.au"); sound[2] = getAudioClip(getCodeBase(),"warpsnd2.au"); bricks=new Image[totalBricks]; brickMap=new int[22*9]; outline=new Image[5]; objects=new Image[objectImages]; defaultStrip=createImage(288,32); defaultSG=defaultStrip.getGraphics(); modStrip=createImage(288,32); modSG=modStrip.getGraphics(); scoreDisp=createImage(74,13); scoreDG=scoreDisp.getGraphics(); scoreDG.setColor(Color.lightGray); scoreDG.fillRect(0,0,74,13); scoreDG.setColor(Color.black); scoreDG.setFont(fo); clearDisp=createImage(74,13); clearDG=clearDisp.getGraphics(); clearDG.setColor(Color.lightGray); clearDG.fillRect(0,0,74,13); clearScreen=createImage(288,8); clearSG=clearScreen.getGraphics(); clearSG.setColor(Color.black); clearSG.fillRect(0,0,288,8); getMainGraphics(); System.gc(); objX=new int[maxObj]; objY=new int[maxObj]; objType=new int[maxObj]; objMode=new int[maxObj]; objLook=new int[maxObj]; objPar=new int[maxObj]; objDraw=new boolean[maxObj]; brickPos=new int[5]; brickType=new int[5]; brickArea=new int[9]; fixQueueX=new int[maxFix]; fixQueueY=new int[maxFix]; fixQueueBrick=new int[maxFix]; sortBuf1=new int[maxObj]; sortBuf2=new int[maxObj]; offImage=createImage(288,288); offGraphics=offImage.getGraphics(); offGraphics.setFont(fo); landscape=createImage(288,608); landscapeG=landscape.getGraphics(); landscapeG.setFont(fo); preparePresentation(); handleSound(2,false); resize(320,400); } public Color findBGColor() // Convert hexadecimal RGB parameter to color { int hex[]; String s,h="0123456789abcdef"; Color c; hex=new int[6]; s=getParameter("bgcolor"); if ((s!=null)&&(s.length()==6)) { for (i=0;i<6;i++) for (j=0;j<16;j++) if (s.charAt(i)==h.charAt(j)) hex[i]=j; c=new Color(hex[0]*16+hex[1],hex[2]*16+hex[3],hex[4]*16+hex[5]); } else c=Color.lightGray; // Default return c; } public void getMainGraphics() // Load and process the most common graphics { Image collection; MediaTracker tracker; int i; tracker=new MediaTracker(this); collection = getImage(getCodeBase(),"warp0.gif"); tracker.addImage(collection,0); try { tracker.waitForID(0); } catch(InterruptedException e) {} logo=createImage(new FilteredImageSource( collection.getSource(),new CropImageFilter(0,128,240,70))); tracker.addImage(logo,1); bricks[0]=createImage(new FilteredImageSource( collection.getSource(),new CropImageFilter(brickX[0],96, 32,32))); tracker.addImage(bricks[0],1); outline[0]=createImage(new FilteredImageSource( collection.getSource(),new CropImageFilter(0,96,16,32))); tracker.addImage(outline[0],1); outline[1]=createImage(new FilteredImageSource( collection.getSource(),new CropImageFilter(16,96,16,32))); tracker.addImage(outline[1],1); outline[2]=createImage(new FilteredImageSource( collection.getSource(),new CropImageFilter(32,96,32,16))); tracker.addImage(outline[2],1); outline[3]=createImage(new FilteredImageSource( collection.getSource(),new CropImageFilter(32,112,16,16))); tracker.addImage(outline[3],1); outline[4]=createImage(new FilteredImageSource( collection.getSource(),new CropImageFilter(48,112,16,16))); tracker.addImage(outline[4],1); panel=createImage(new FilteredImageSource( collection.getSource(),new CropImageFilter(0,0,320,96))); tracker.addImage(panel,1); for (i=0;i=0) sound[currentSnd].stop(); if (sndNum>=0) if (loop) sound[sndNum].loop(); else sound[sndNum].play(); currentSnd=sndNum; } public void preparePresentation() { windowHeight=0; windowStep=2; paintBackground(0); runMode=1; for (i=0;isortBuf2[j+1]) { k=sortBuf1[j]; sortBuf1[j]=sortBuf1[j+1]; sortBuf1[j]=k; k=sortBuf2[j]; sortBuf2[j]=sortBuf2[j+1]; sortBuf2[j]=k; } for (i=0;i0) && objDraw[sortBuf1[i]]) offGraphics.drawImage(objects[objNum[objLook[sortBuf1[i]]]],objX[sortBuf1[i]], objY[sortBuf1[i]],this); } public void activateObject(int x,int y,int type,int mode,int look, int par, boolean drawIt) // Start up a new live object { objX[objCount]=x; objY[objCount]=y; objLook[objCount]=look; objMode[objCount]=mode; objDraw[objCount]=drawIt; objType[objCount]=type; objPar[objCount]=par; objCount++; } public void smallUpdates() // Make requested small modifications of landscape { int i; if (fixQueueBrick[0]>0) { landscapeG.drawImage(bricks[brickIm[fixQueueBrick[0]]],fixQueueX[0], fixQueueY[0],this); fixQueueBrick[0]=0; i=1; while (fixQueueBrick[i]>0) { fixQueueX[i-1]=fixQueueX[i]; fixQueueY[i-1]=fixQueueY[i]; fixQueueBrick[i-1]=fixQueueBrick[i]; fixQueueBrick[i]=0; i++; } } else if (newScore>score) { score=newScore; scoreDG.drawImage(clearDisp,0,0,this); scoreDG.drawString(String.valueOf(score),2,11); drawScore=true; } } public void blastBrick(int pos) // Draw destroyed brick (or rather place in queue) { int i,j; for (i=0;i0) j++; fixQueueBrick[j]=blastBrick[i]+1; brickMap[pos]=blastBrick[i]+1; fixQueueX[j]=32*(pos % 9); fixQueueY[j]=32*(pos/9-1); if (pos<90) // We need one update for bottom half too { brickMap[pos+90]=blastBrick[i]+1; fixQueueBrick[j+1]=blastBrick[i]+1; fixQueueX[j+1]=fixQueueX[j]; fixQueueY[j+1]=fixQueueY[j]+320; } i=blastable; } } public void placeBricks() // Choose bricks to distribute randomly onto modStrip, then enemies { int i,j,k,l; double d; i=(int)(m.random()*(1+bricksPerLine[level])); for (j=0;j<9;j++) brickArea[j]=0; for (j=0;j0) k=(int)(m.random()*9); d=m.random(); l=0; while (d>randBrick[maxOtherBricks*level+l]) l++; brickArea[k]=levBrick[level*maxOtherBricks+l]; } j=0; for (i=0;i<9;i++) if (brickArea[i]>0) { brickPos[j]=i; brickType[j]=brickArea[i]; j++; } i=(int)(m.random()*9); // And now for the enemies if ((brickQual[brickMap[9*((32+windowHeight-24)/32)+i]]==0)&&(objCount<5)&&(m.random()<0.3)) { d=m.random(); l=0; while (d>randEnemy[maxEnemies*level+l]) l++; activateObject(i*32,-24,levEnemy[level*maxEnemies+l],0,0,0,true); } } public void initiatePlaying() // Prepares for start of new game or level { windowHeight=0; windowStep=4; paintBackground(levBackgr[level]); for (i=0;i<9;i++) brickArea[i]=0; for (i=0;i<22*9;i++) brickMap[i]=0; for (i=0;i<5;i++) brickPos[i]=-1; for (i=0;i1)&&(cyclic<7)) if (brickPos[6-cyclic]>=0) modSG.drawImage(bricks[brickIm[brickType[6-cyclic]]], brickPos[6-cyclic]*32,0,this); else smallUpdates(); } public void sortObjects() // Called after deleting an object { int lastEmpty,lastExisting,j; lastEmpty=-1; lastExisting=-1; for (j=0;j64)&&(currentKey<70))) { if ((currentKey>64)&&(currentKey<70)) level=currentKey-65; else level=0; runMode=3; // Prepare for playing offGraphics.setColor(Color.black); counter=-1; } break; case 2: // Main game loop loadBalance((windowHeight & 28)/4); scrollScreen(); handleObjects(); drawObjects(); mileage++; if (mileage>levLength[level]+80) // Prepare to finish and exit level { handleSound(2,true); runMode=4; tempScore=newScore+500; objType[0]=6; windowStep=0; } break; case 3: // Prepare for playing, clear screen slowly offGraphics.drawImage(clearScreen,0,counter*8,this); offGraphics.drawImage(clearScreen,0,280-counter*8,this); if (counter>17) { lives=3; // Initial set-up score=0; newScore=0; counter=0; getLevelGraphics(level); System.gc(); initiatePlaying(); runMode=2; showLights=true; drawScore=true; } break; case 4: // Finish level scrollScreen(); handleObjects(); if (newScore17) { if (lives>=0) { getLevelGraphics(level); System.gc(); initiatePlaying(); runMode=2; showLights=true; drawScore=true; } else // Game over? { counter=0; p=getFontMetrics(fo).stringWidth("GAME OVER"); offGraphics.setColor(Color.white); offGraphics.drawString("GAME OVER",144-p/2,140); offGraphics.setColor(Color.black); runMode=6; } } break; case 6: // Game over message if (counter>50) if (score<=highScores[4]) { mileage=0; preparePresentation(); } else // New highscore { landscapeG.setColor(Color.black); landscapeG.fillRect(0,0,288,510); landscapeG.setColor(Color.white); p=getFontMetrics(fo).stringWidth("GAME OVER"); landscapeG.drawString("GAME OVER",144-p/2,140); highScores[4]=score; q=4; for (i=3;i>=0;i--) if (score>highScores[i]) { highScores[i+1]=highScores[i]; highScores[i]=score; q=i; } p=getFontMetrics(fo).stringWidth("Current Highscores"); landscapeG.drawString("Current Highscores",144-p/2,308); for (i=0;i<5;i++) { if (i==q) landscapeG.setColor(Color.yellow); else landscapeG.setColor(Color.white); landscapeG.drawString(""+(i+1)+".",100,340+i*27); p=getFontMetrics(fo).stringWidth(String.valueOf( highScores[i])); landscapeG.drawString(""+highScores[i],188-p,340+i*27); } windowHeight=0; windowStep=-4; counter=0; runMode=7; score=0; } break; case 7: // Scroll in highscore table scrollScreen(); if (counter>54) { counter=0; runMode=6; // Go back to waiting } break; default: break; } repaint(); } } public void start() { if (updateThread==null) { updateThread=new Thread(this,"Game"); updateThread.start(); startTime=System.currentTimeMillis(); } } public void stop() { if ((updateThread!=null)&&(updateThread.isAlive())) { updateThread.stop(); } updateThread=null; } public boolean keyDown(java.awt.Event e,int key) { currentKey=key; return false; } public boolean keyUp(java.awt.Event e,int key) { currentKey=0; return false; } public void handleObjects() // Control non-stationary stuff { int i,j,k,mapPos; boolean upFree,downFree,leftFree,rightFree; for (i=0;i0)) // Go left { objX[i]-=8; objLook[i]=1; } else if ((currentKey==108)&&(objX[i]<256)) // Go right { objX[i]+=8; objLook[i]=2; } if ((currentKey==107)&&(!bulletOn)) // Fire { activateObject(objX[i]+8,objY[i],2,0,3,0,true); bulletOn=true; handleSound(0,false); } if (touching[0]+touching[1]+touching[2]+touching[3]>0) blowUpShip(); break; case 2: // Friendly bullet mapPos=checkTouching(i); bulletIx=i; if (touching[0]+touching[1]>0) // Smashed into something? { if ((touching[0] & 2)>0) // Destructible? { objType[i]=5; objX[i]-=8; objY[i]-=16; objPar[i]=8; objLook[i]=6; blastBrick(mapPos); handleSound(1,false); } else if ((touching[1] & 2)>0) { objType[i]=5; objX[i]-=8; objY[i]-=16; objPar[i]=8; objLook[i]=6; blastBrick(mapPos+1); handleSound(1,false); } else // No? Just remove bullet { objType[i]=0; bulletOn=false; } } else // Keep going up { objY[i]-=16; if (objY[i]<0) { objType[i]=0; bulletOn=false; } } break; case 3: // Dummy ship (used in intro) if (objX[i]objPar[i]) { objX[i]-=8; objLook[i]=2; } else objLook[i]=0; if (m.random()<0.1) objPar[i]=8*(1+(int)(m.random()*30.49)); if ((objCount<3)&&(m.random()<0.1)) // Dummy fire activateObject(objX[i]+8,objY[i],4,0,3,0,true); break; case 4: // Dummy bullet objY[i]-=18; if (objY[i]<0) { objType[i]=0; } break; case 5: // Exploding friendly bullet objLook[i]++; objY[i]+=windowStep; if (objLook[i]>objPar[i]) { objType[i]=0; bulletOn=false; } break; case 6: // Exiting ship (also rather dummy) if (objX[i]<128) { objX[i]+=8; objLook[i]=1; } else if (objX[i]>128) { objX[i]-=8; objLook[i]=2; } else objLook[i]=0; objY[i]-=4; break; case 7: // Spiked ball type objY[i]+=windowStep; mapPos=9*((32+windowHeight+objY[i])/32)+objX[i]/32; if ((objX[i]&31)+((objY[i]+windowHeight)&31)==0) { downFree=(brickQual[brickMap[mapPos+9]]==0); leftFree=((brickQual[brickMap[mapPos-1]]==0)&&(objX[i]>0)); rightFree=((brickQual[brickMap[mapPos+1]]==0)&&(objX[i]<256)); if (objMode[i]==0) { if (downFree) objMode[i]=2; else { if (leftFree && rightFree) objMode[i]=(int)(3+2*m.random()); else if (leftFree) objMode[i]=3; else if (rightFree) objMode[i]=4; } } else { if (((objMode[i]==2)&&(!downFree))|| ((objMode[i]==3)&&(!leftFree))|| ((objMode[i]==4)&&(!rightFree))) objMode[i]=0; } } switch(objMode[i]) { case 2: objY[i]+=4; break; case 3: objX[i]-=4; break; case 4: objX[i]+=4; break; default: break; } animateObject(i,0); if (objY[i]>287) // Vanished off screen { objType[i]=0; } else checkForHit(i); break; case 8: // Tank type objY[i]+=windowStep; mapPos=9*((32+windowHeight+objY[i])/32)+objX[i]/32; if ((objX[i]&31)==0) { leftFree=((brickQual[brickMap[mapPos-1]]==0)&&(objX[i]>0)); rightFree=((brickQual[brickMap[mapPos+1]]==0)&&(objX[i]<256)); if (objMode[i]==0) { if (leftFree && rightFree) objMode[i]=(int)(3+2*m.random()); else if (leftFree) objMode[i]=3; else if (rightFree) objMode[i]=4; } else { if (((objMode[i]==3)&&(!leftFree))|| ((objMode[i]==4)&&(!rightFree))) objMode[i]=0; } } if ((objCount<5)&&(objX[i]-objX[0]<40)&&(objX[0]-objX[i]<40)&& (m.random()<0.12)) // Fire! { activateObject(objX[i]+8,objY[i]+12,9,0,4,0,true); animateObject(i,5); handleSound(0,false); objPar[i]=3; // Busy shooting for 3 cycles } if (objPar[i]==0) // Not busy { switch(objMode[i]) { case 3: objX[i]-=4; break; case 4: objX[i]+=4; break; default: break; } animateObject(i,objMode[i]); } else objPar[i]--; if (objY[i]>287) // Vanished off screen { objType[i]=0; } else checkForHit(i); break; case 9: // Enemy bullet objY[i]+=20; if (objPar[i]==0) // Start as nozzle explosion { objLook[i]=5; objPar[i]=1; } else objLook[i]=4; mapPos=checkTouching(i); if ((objType[0]==1)&&((objX[i]-objX[0])*(objX[i]-objX[0])+ (objY[i]-objY[0])*(objY[i]-objY[0])<500)) // Hit ship? { blowUpShip(); objType[i]=0; } if ((touching[0]+touching[1]+touching[2]+touching[3]>0)|| (objY[i]>287)) // Crashed or off screen? { objType[i]=0; // Remove bullet } break; case 10: // Exploding enemy objLook[i]++; objY[i]+=windowStep; // Done exploding? if (objLook[i]>objPar[i]) objType[i]=0; break; case 11: // Exploding self objX[i]+=(int)(10*m.cos(objMode[i])); objY[i]-=(int)(10*m.sin(objMode[i])); if (objPar[i]<6) objLook[i]=6+objPar[i]/2; else objDraw[i]=false; objPar[i]++; if ((objPar[i]>12)&&(runMode==2)) { objType[i]=0; counter=-1; lives--; mileage=m.max(mileage,0); runMode=5; showLights=true; } break; case 12: // Homing objY[i]+=(windowStep+2); if ((objX[i]objX[0])&&(objPar[i]>-10)) objPar[i]-=2; objX[i]+=objPar[i]; animateObject(i,0); if (objY[i]>287) // Vanished off screen objType[i]=0; else checkForHit(i); break; case 13: // Dragonfly type objY[i]+=(windowStep+8); animateObject(i,0); if (objY[i]>287) // Vanished off screen objType[i]=0; else checkForHit(i); break; case 14: // Shark type objY[i]+=windowStep; mapPos=9*((32+windowHeight+objY[i])/32); if (objPar[i]==0) { objDraw[i]=false; j=(int)(m.random()*8); if ((j!=(objX[i]/32))&&(brickQual[brickMap[mapPos+j]]==0)) { objPar[i]=16; // Emerge from the depth objX[i]=32*j; objDraw[i]=true; } } if (objPar[i]>0) { objPar[i]--; if (objPar[i]>0) { animateObject(i,objPar[i]-1); checkForHit(i); } else objDraw[i]=false; } if (objY[i]>287) // Vanished off screen objType[i]=0; break; case 15: // Moving right-left type objY[i]+=windowStep; mapPos=9*((32+windowHeight+objY[i])/32)+objX[i]/32; if ((objX[i]&31)==0) { leftFree=((brickQual[brickMap[mapPos-1]]==0)&&(objX[i]>0)); rightFree=((brickQual[brickMap[mapPos+1]]==0)&&(objX[i]<256)); if (objMode[i]==0) { if (leftFree && rightFree) objMode[i]=(int)(3+2*m.random()); else if (leftFree) objMode[i]=3; else if (rightFree) objMode[i]=4; } else { if (((objMode[i]==3)&&(!leftFree))|| ((objMode[i]==4)&&(!rightFree))) objMode[i]=0; } } switch(objMode[i]) { case 3: objX[i]-=4; break; case 4: objX[i]+=4; break; default: break; } animateObject(i,objMode[i]); if (objY[i]>287) // Vanished off screen { objType[i]=0; } else checkForHit(i); break; case 16: // Saucer type objY[i]+=(windowStep+6); animateObject(i,0); if ((objCount<5)&&(m.random()<0.08)) // Fire! { activateObject(objX[i]+8,objY[i]+8,17,0,88,8*(1-(counter&2)), true); handleSound(0,false); } if (objY[i]>287) // Vanished off screen objType[i]=0; else checkForHit(i); break; case 17: // Enemy fireball objY[i]+=(windowStep+5); animateObject(i,0); if ((objX[i]<(objX[0]+12))&&(objPar[i]<10)) objPar[i]+=2; else if ((objX[i]>objX[0])&&(objPar[i]>-10)) objPar[i]-=2; objX[i]+=objPar[i]; if (objY[i]>287) // Vanished off screen objType[i]=0; else if ((objType[0]==1)&&((objX[i]-objX[0])*(objX[i]-objX[0])+ (objY[i]-objY[0])*(objY[i]-objY[0])<500)) { blowUpShip(); // Fireball collided with spaceship objType[i]=0; } break; default: break; } } sortObjects(); } public void animateObject(int i, int action) // Give the enemy the right look { switch(objType[i]) { case 7: switch(level) { case 0: // Spiked ball objLook[i]=13+(counter%3); break; case 3: // Spinning cube objLook[i]=40+(counter%3); break; case 5: // Beach ball objLook[i]=57+(counter&3); break; case 6: // Snowman objLook[i]=70+(counter&3); break; case 7: // Killer tomato objLook[i]=74+cyclic2[counter%6]; break; default: break; } break; case 8: switch(level) { case 0: // Tank objLook[i]=16+((objX[i]/4)%3); break; case 1: // Bazooka bird if (action==3) // Left objLook[i]=22+cyclic[(objX[i]/4)%3]; else if (action==4) // Right objLook[i]=25+cyclic[(objX[i]/4)%3]; else // Fire objLook[i]=28; break; case 4: // Eyeball if (action==3) // Left objLook[i]=44; else if (action==4) // Right objLook[i]=45; else // Fire objLook[i]=43; break; case 6: // Fire objLook[i]=67+(counter%3); break; case 8: // Rolling cannon objLook[i]=82+((objX[i]/4)%3); break; default: break; } break; case 12: switch(level) { case 1: // Homing bird objLook[i]=19+(counter%3); break; default: break; } break; case 13: switch(level) { case 2: // Dragonfly objLook[i]=29+(counter&1); break; case 5: // Seagull objLook[i]=56; break; default: break; } break; case 14: switch(level) { case 2: // Shark objLook[i]=shark[action]; break; case 4: // Groundmouth objLook[i]=groundMouth[action]; break; default: break; } break; case 15: switch(level) { case 3: // Rolling cube objLook[i]=36+((objX[i]/4)&3); break; case 5: // Crab objLook[i]=53+cyclic[(objX[i]/4)&3]; break; case 6: // Penguin if (action==3) objLook[i]=61+cyclic[counter&3]; else objLook[i]=64+cyclic[counter&3]; break; case 7: // Vegetable objLook[i]=78+((objX[i]/4)&3); break; default: break; } break; case 16: // Saucer objLook[i]=85+(counter%3); break; case 17: // Fireball objLook[i]=88+(counter&1); break; default: break; } } public int checkTouching(int i) // Used by handleObjects() { int mapPos; touching[1]=0; touching[2]=0; touching[3]=0; mapPos=9*((32+windowHeight+objY[i])/32)+objX[i]/32; // Check what's under it touching[0]=brickQual[brickMap[mapPos]]&3; if (((objX[i]&31)+objImPractW[objLook[i]])>32) { touching[1]=brickQual[brickMap[mapPos+1]]&3; if ((((objY[i]+windowHeight)&31)+objImH[objLook[i]])>32) touching[3]=brickQual[brickMap[mapPos+10]]&3; } if ((((objY[i]+windowHeight)&31)+objImH[objLook[i]])>32) touching[2]=brickQual[brickMap[mapPos+9]]&3; return mapPos; } public void checkForHit(int i) // Used by handleObjects(). { int j; if ((objType[bulletIx]==2)&&((objX[i]-objX[bulletIx])* (objX[i]-objX[bulletIx])+(objY[i]-objY[bulletIx])* (objY[i]-objY[bulletIx])<570)) { for (j=0;j