// Iceblox MIDlet using the com.nokia.mid libraries import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import com.nokia.mid.ui.*; import com.nokia.mid.sound.*; import javax.microedition.rms.*; import java.io.*; public class ice extends MIDlet { private final iceCanvas canvas; public ice() { canvas=new iceCanvas(this); } public void startApp() { Display.getDisplay(this).setCurrent(canvas); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } void exitRequested() { destroyApp(false); notifyDestroyed(); } } class iceCanvas extends FullCanvas implements Runnable { private int w,h,gameMode=1,counter,helpCount; private final ice owner; private Image background,maze; private DirectGraphics bg,mdg; private Graphics gg,mg; Thread runner; private java.util.Random rnd=new java.util.Random(); private byte imdata[],immask[],chardata[]; private byte textbuf[]=new byte[196]; private final int charbase[]={213, 0,0,0,0,0,0,0,0,0,0,0, 217,210,207,0, 0,8,16,24,32,40,48,56,64,72, 0,0,225,0,220,0, 80, 85,90,95,99,104,108,112,117,122,125,130,135,139,145,150,155,160,165,170,175,179,184,188,194,198,202}; private final int charwidth[]={4, 0,0,0,0,0,0,0,0,0,0,0, 3,4,3,0, 8,8,8,8,8,8,8,8,8,8, 0,0,5,0,5,0, 5, 5,5,4,5,4,4,5,5,3,5,5,4,6,5,5,5,5,5,5,4,5,4,6,4,4,5}; private final int blockpointer[]={0,2880,3888,2736}; private char levelChars[]={'L','E','V','E','L',' ','0','1'}; private final String infoStrings[]={"BY KARL H@RNELL","","GAME OVER","HIGHSCORES","DONE>"}; private final String helpStrings[]={"YOU CONTROL","PIXEL PETE,","THE PENGUIN.", "MOVE BLOCKS","BY WALKING","AGAINST THEM.", "OR CRUSH","THEM AGAINST","OTHER BLOCKS.", "WATCH OUT","FOR THE","EVIL FLAMES.", "SNUFF THEM","WITH ICE.", "COLLECT ALL","FIVE GOLD", "COINS ...", "TO GET TO","THE NEXT","LEVEL."}; private byte scorehold[]=new byte[40],scoremask[]=new byte[40],lifehold[]=new byte[17], lifemask[]=new byte[17]; private int lifeW; private int maxFlames,flames; private int highscores[]=new int[9],highpos,highx; private boolean acceptKey; private char highchars[]=new char[77]; private int i,j,k,sprCount; private int scX=16,scY=16,coins=0,lives=0,l,showW=0,showH=0,mapX,mapY; private int map[]=new int[12*12]; private int cyclic[]={0,1,2,1}; private int blockNum[]={0,27,5,6}; private iceObject objs[]=new iceObject[10]; private int score=0,level=0; private int offsets[]={0,-12,12,-1,1}; private int dx[]={0,0,0,-1,1},dy[]={0,-1,1,0,0}; private int lastKey=0,motionKeys[]={0,UP,DOWN,LEFT,RIGHT}; private RecordStore rs; private Sound beep1,beep2,beep3; public iceCanvas(ice o) { int i,j,len=0; owner=o; w=getWidth(); h=getHeight(); background=Image.createImage(w,h); gg=background.getGraphics(); bg=DirectUtils.getDirectGraphics(gg); maze=Image.createImage(144,144); mg=maze.getGraphics(); mdg=DirectUtils.getDirectGraphics(mg); // Get bitmap data try{ InputStream is=getClass().getResourceAsStream("imdata.bit"); len=is.read()*256+is.read(); imdata=new byte[len]; for (i=0;i0) i++; objs[i].x=ox; objs[i].y=oy; objs[i].pos=op; objs[i].dir=od; objs[i].type=ot; objs[i].look=ol; } void drawString(String s, int x, int y, DirectGraphics dg) { int i,j=0,k,l=s.length(),m,n; for (i=0;i6 && showH>6) { showW-=6; showH-=6; } gameMode=4; break; case 4: // Entering new level, zooming in gg.setClip((w-showW)/2,(h-showH)/2,showW,showH); gg.drawImage(maze,mapX,mapY,Graphics.LEFT | Graphics.TOP); showW+=6; showH+=6; if (showW>w) gameMode=5; break; case 5: if ((counter&15)==0 && flames0) j+=12; if (j<122) // Found an entrance { initiateObject(12*(j%12),12*(j/12),j,k,6,9); flames++; } } for (i=0;i<10;i++) // Process all mobile objects { switch(objs[i].type) { case 1: // Penguin if ((objs[i].x%12)+(objs[i].y%12)==0) { objs[i].dir=0; for (j=1;j<5;j++) if (lastKey==motionKeys[j]) { k=objs[i].pos+offsets[j]; if (map[k]==0) { objs[i].dir=j; objs[i].pos+=offsets[j]; } else if (map[k]<3) // Bumped into block { if (map[k+offsets[j]]==0) // Push? { initiateObject(objs[i].x+12*dx[j], objs[i].y+12*dy[j], objs[i].pos+offsets[j], j, map[k]==1?2:3, map[k]==1?20:27); map[k]=0; mg.setColor(0); mg.fillRect(objs[i].x+12*dx[j],objs[i].y+12*dy[j],12,12); } else // Crush? { initiateObject(objs[i].x+12*dx[j], objs[i].y+12*dy[j], objs[i].pos+offsets[j], 0, map[k]==1?4:5, map[k]==1?20:27); map[k]=0; mg.setColor(0); mg.fillRect(objs[i].x+12*dx[j],objs[i].y+12*dy[j],12,12); map[k]=3; } } } } if (objs[i].dir>0) { objs[i].x+=2*dx[objs[i].dir]; // Previously 3 pixels objs[i].y+=2*dy[objs[i].dir]; // Previously 3 pixels objs[i].look=objs[i].dir*2-2+(counter&1); } // Scroll screen to follow the penguin mapX=42-objs[i].x; mapY=24-objs[i].y; if (mapX>-8) mapX=-8; else if (mapX<-39) mapX=-39; if (mapY>-8) mapY=-8; else if (mapY<-70) mapY=-70; if (coins==5) // All coins taken? { flames=50; for (j=0;j<10;j++) if (objs[j].type==6) objs[j].type=0; objs[i].type=10; counter=0; } break; case 2: // Moving block case 3: // Moving frozen coin objs[i].x+=4*dx[objs[i].dir]; // Previously 6 pixels objs[i].y+=4*dy[objs[i].dir]; // Previously 6 pixels for (j=1;j<10;j++) // Check flame collision if (objs[j].type==6 && objs[j].x0) // Stop? { map[k]=objs[i].type-1; mdg.drawPixels(imdata,null,objs[i].look*144,12, objs[i].x,objs[i].y,12,12,0, DirectGraphics.TYPE_BYTE_1_GRAY); objs[i].type=0; } } break; case 4: // Crushed plain ice case 5: // Crushed frozen coin objs[i].look++; if (objs[i].look==27 || objs[i].look==34) { map[objs[i].pos]=0; if (objs[i].type==5) // Coin? { beep1.play(1); coins++; score+=100; buildScore(); } else // Plain ice { score+=5; buildScore(); } objs[i].type=0; } break; case 6: // Flame objs[i].look=9+cyclic[counter&3]; objs[i].x+=dx[objs[i].dir]; // Previously 2 pixels objs[i].y+=dy[objs[i].dir]; // Previously 2 pixels if ((objs[i].x%12)+(objs[i].y%12)==0) { objs[i].pos+=offsets[objs[i].dir]; if (objs[i].dir==0 || (counter&14)==0) objs[i].dir=1+(rnd.nextInt()&3); // Possibly home in on the penguin if (objs[i].xobjs[0].x-10) { if (objs[i].yobjs[0].y-10) { if (objs[0].x>objs[i].x) objs[i].dir=4; else objs[i].dir=3; } // Stop if there is something in the way if (map[objs[i].pos+offsets[objs[i].dir]]>0) objs[i].dir=0; } // Caught penguin? if (objs[i].xobjs[0].x-8 && objs[i].yobjs[0].y-8) { objs[0].type=9; objs[0].look=14; counter=0; flames=50; for (j=1;j<10;j++) if (objs[j].type==6) objs[j].type=0; beep3.play(1); } break; case 8: // Flashing score symbol objs[i].look=12+(counter&1); objs[i].temp++; if (objs[i].temp>10) { objs[i].type=0; flames--; } break; case 9: // Dying penguin if (objs[i].look<18) objs[i].look++; if (counter>30) { lives--; if (lives>=0) { lifeW-=8; flames=0; objs[i].type=1; objs[i].look=2; } else gameMode=6; // Game over } break; case 10: // Happy penguin objs[i].look=2+3*(counter&2); if (counter>33) { showW=w; showH=h; while (showW>6 && showH>6) { showW-=6; showH-=6; } gameMode=8; } break; default: break; } } gg.drawImage(maze,mapX,mapY,Graphics.LEFT | Graphics.TOP); // Draw mobile objects for (i=0;i<10;i++) if (objs[i].type>0) { if (objs[i].look>13) bg.drawPixels(imdata,null,objs[i].look*144,12, objs[i].x+mapX,objs[i].y+mapY,12,12,0,DirectGraphics.TYPE_BYTE_1_GRAY); else bg.drawPixels(imdata,immask,objs[i].look*144,12, objs[i].x+mapX,objs[i].y+mapY,12,12,0,DirectGraphics.TYPE_BYTE_1_GRAY); } bg.drawPixels(scorehold,scoremask,0,40,0,0,40,8,0, DirectGraphics.TYPE_BYTE_1_GRAY_VERTICAL); bg.drawPixels(lifehold,lifemask,0,lifeW,78,0,lifeW,8,0, DirectGraphics.TYPE_BYTE_1_GRAY_VERTICAL); break; case 6: // Prepare GAME OVER gg.setColor(0); gg.fillRect(23,26,48,13); drawString(infoStrings[3],27,29,bg); counter=0; gameMode=7; break; case 7: // GAME OVER pause if (counter>50) { if (score>highscores[5]) { highscores[6]=score; i=6; while (i>0 && score>highscores[i-1]) { highscores[i]=highscores[i-1]; for (j=0;j<11;j++) highchars[i*11+j]=highchars[i*11+j-11]; i--; highscores[i]=score; } highchars[i*11+8]='.'; highchars[i*11+9]='.'; highchars[i*11+10]='.'; for (j=4;j>=0;j--) { highchars[i*11+j]=(char)(48+(score%10)); score=score/10; } gg.setColor(0); gg.fillRect(0,h-8,w,8); drawHighscores(); drawString(infoStrings[5],72,58,bg); bg.drawPixels(imdata,null,864,12,83,7+i*7,12,12,0,DirectGraphics.TYPE_BYTE_1_GRAY); highpos=i; highx=8; gameMode=9; } else gameMode=1; } break; case 8: // Fade out, prepare for new level gg.setColor(0); gg.fillRect((w-showW)/2,(h-showH)/2,showW,showH); showW+=6; showH+=6; if (showW>w) { level++; getLevelParameters(); levelChars[6]=(char)(48+((level/10)%10)); levelChars[7]=(char)(48+(level%10)); drawString(new String(levelChars),28,22,bg); for (i=0;i'Z') highchars[highpos*11+highx]='.'; else if (highchars[highpos*11+highx]<'A') highchars[highpos*11+highx]='A'; break; case DOWN: // Down highchars[highpos*11+highx]--; if (highchars[highpos*11+highx]<'.') highchars[highpos*11+highx]='Z'; else if (highchars[highpos*11+highx]<'A') highchars[highpos*11+highx]='.'; break; /* case KEY_NUM4: // Left if (highx>8 && acceptKey) { highx--; acceptKey=false; } break;*/ // case KEY_NUM6: // Right case FIRE: // One pos forward if (highx<10 && acceptKey) { highx++; acceptKey=false; } break; default: break; } // if (lastKey==KEY_SOFTKEY2) // Enter if (lastKey==RIGHT) // Enter { storeHighscores(); counter=0; prepareIntro(); } else { gg.fillRect(50,9+highpos*7,32,7); drawString(new String(highchars,highpos*11,11),11,9+highpos*7,bg); } } break; case 11: // Wait before going to next level if (counter>25) gameMode=3; break; default: break; } repaint(0,0,w,h); serviceRepaints(); timeTaken=System.currentTimeMillis()-startTime; if (timeTaken<75) runner.sleep(75-timeTaken); } } catch(InterruptedException ie){} } void drawHighscores() { gg.setColor(0); gg.fillRect(0,0,w,h-8); drawString(infoStrings[4],28,1,bg); for (int j=0;j<6;j++) drawString(new String(highchars,j*11,11),11,9+j*7,bg); } void loadHighscores() { int i,j; // Obtain highscores // Attempt to fetch by way of record stores try{ rs=RecordStore.openRecordStore("iceHigh",true); RecordEnumeration re=rs.enumerateRecords(null,null,false); if (re.hasNextElement()) { byte tempBytes[]=re.nextRecord(); for (i=0;i<66;i++) highchars[i]=(char)tempBytes[i]; for (i=0;i<6;i++) { highscores[i]=0; for (j=0;j<5;j++) highscores[i]=highscores[i]*10+(highchars[i*11+j]-'0'); } } rs.closeRecordStore(); }catch(Exception e){} if (highchars[0]==0) { for (i=0;i<6;i++) { for (j=0;j<5;j++) highchars[i*11+j]='0'; for (j=5;j<8;j++) highchars[i*11+j]=' '; for (j=8;j<11;j++) highchars[i*11+j]='.'; } } } void storeHighscores() { try{ byte tempBytes[]=new byte[88]; for (int i=0;i<66;i++) tempBytes[i]=(byte)highchars[i]; rs=RecordStore.openRecordStore("iceHigh",true); if (rs.getNumRecords()>0) rs.deleteRecord(rs.getNextRecordID()-1); rs.addRecord(tempBytes,0,66); rs.closeRecordStore(); }catch(Exception e){} } public void paint(Graphics g) { g.drawImage(background,0,0,Graphics.LEFT | Graphics.TOP); } public void keyPressed(int k) { lastKey=getGameAction(k); if (lastKey==GAME_B) owner.exitRequested(); // else if (k==-6) // lastKey=LEFT; // else if (k==-7) // lastKey=RIGHT; } public void keyReleased(int k) { lastKey=0; } void prepareLevel() { int i,j,k,l,m,pile[]=new int[100]; m=0; while (m<5) { // Randomly place blocks for (i=0;i<12;i++) for (j=0;j<12;j++) { k=i*12+j; if (i>0 && i<11 && j>0 && j<11) map[k]=0; else map[k]=3; } map[13]=3; map[143]=0; for (j=1;j<4;j++) for (i=0;i0) mdg.drawPixels(imdata,null,blockpointer[map[i]],12,(i%12)*12,(i/12)*12,12,12,0,DirectGraphics.TYPE_BYTE_1_GRAY); } } } class iceObject { int x,y,pos,dir,look,temp; int type; }