C:\eclipse\workspace\Epsilon_03\src\GameCanvas.java
   1  /**
   2   *  GameCanvas contains the Canvas for the Epsilon game.
   3   *  Epsilon is a simple space-shooter-vertical-scroller game.
   4   *
   5   *  Epsilon is available for non-commercial use only!
   6   *  You can learn from this sources and you can modify them
   7   *  for learning purposes.
   8   * 
   9   *  @author      Ziga Hajdukovic
  10   *  @version     1.0
  11   *
  12   *  CHANGES (01 --> 02)
  13   *  + new player sprite, p.png
  14   *  + added boss sprite boss1.png
  15   *  + added tileset t04.png
  16   *  + added enemy sprites e1.png, e2.png, e3.png
  17   *  + added fire.png, removed pf.png
  18   *  + added explosion sprite, exp.png
  19   *  + moved Image objects for sprites to spriteImage array
  20   *  + added tileImage
  21   *  + moved image loading to loadImages()
  22   *  + setClip in paintSprite
  23   *  + player sprite frames for left and right movement
  24   *  + multiple fire sprites + fire_cooldown_wait_frames
  25   *  + 20 FPS fixed frame rate
  26   *  + Vector explosionSprites
  27   *  + updateExplosionSprites()
  28   *  + doCollision() -> add explosion on collision
  29   *  + paint explosionSprites
  30   *  + Level class
  31   *  + loadLevel(), tile map, and sprite positions
  32   *  + space and tiles y and vy
  33   *  + load sprites positions
  34   *  + level paint
  35   *  +   (scrolling background space layer)
  36   *  +   (scrolling tile layer)
  37   *  + new (but still random) enemies
  38   *  + player game over explosion
  39   * 
  40   *
  41   *  CHANGES (02 -> 03)
  42   *  + run() if(gameRunning)
  43   *  + run(), + midlet.display.callSerially(this);
  44   *  + midlet.startApp(), gameCanvas.run()
  45   *  
  46   *  + pause game screen
  47   *     + new menu scr paused game, with 2 softkey labels
  48   *             + resume on softkey1
  49   *             + main menu on softkey2
  50   *     + hidenotify()
  51   *  + player.vy += Level.tiles_scroll_vy
  52   *  + removed automatic enemy sprite generation
  53   *  + updated player screen edge collision detection
  54   *  + spriteData array  
  55   *  + damage and score added to GameSprite, see doCollision
  56   *  + EXPLOSION_FRAME_SMOKE_START
  57   *  + move player with level scroll
  58   *  + enemy activation zone 
  59   *  + remove out-of-screen enemies, updated!
  60   *  + doEnemyAI()
  61   *  + fire_cooldown_frames_counter moved to GameSprite
  62   *  + collision updated, vector loop inverted...
  63   *  + enemyFireSprites Vector, updateEnemyFireSprites() paint ...
  64   *  + doEnemyAI(), shooting enemies!
  65   *  + enemy fire sprites <-> player collision
  66   *  + boss big bada boom explosion, like players...
  67   *  + god_mode
  68   *  + boss, moving, shooting
  69   *  + view and enter hiscore screens
  70   *  + flow for score view and edit
  71   *  + import javax.microedition.rms.*;
  72   *  + import java.io.*;
  73   *  + loadHighscoreFromRMS(), add call to intro mode, when loading
  74   *  + isQualified(int score)
  75   *  + addHighscore(int score, String name)
  76   *  + getHighscoreData(), highscore helper function
  77   *  + saveHighscores(), highscore helper function
  78   *  
  79   *  
  80 */
  81 
  82 import java.util.*;
  83 
  84 import javax.microedition.lcdui.*;
  85 
  86 import javax.microedition.rms.*;
  87 import java.io.*;
  88 
  89 import com.nokia.mid.ui.FullCanvas;
  90 
  91 class GameCanvas extends FullCanvas implements Runnable
  92 //class GameCanvas extends Canvas implements Runnable
  93 {
  94         private final Game midlet;
  95         
  96         public static int canvasWidth;
  97         public static int canvasHeight;
  98 
  99         public static boolean gameRunning;
 100 
 101         public static final int SOFTKEY_1 = -6;
 102         public static final int SOFTKEY_2 = -7;
 103         
 104         public static boolean menu_command_1;
 105         public static boolean menu_command_2;
 106         
 107         public static boolean command_up;
 108         public static boolean command_down;
 109         public static boolean command_left;
 110         public static boolean command_right;
 111         public static boolean command_fire;
 112         
 113         public static byte mode;
 114         public static final byte MODE_INTRO = 0;
 115         public static final byte MODE_GAME = 1;
 116         public static final byte MODE_MENU = 2;
 117         
 118         public static int loadingCounter;
 119 
 120         public static Image imgIntro;
 121         public static Image imgBackground;
 122 
 123         public static Image[] spriteImages;
 124         public static final byte SPRITE_IMAGE_PLAYER = 0;
 125         public static final byte SPRITE_IMAGE_FIRE = 1;
 126         public static final byte SPRITE_IMAGE_BOSS1 = 2;
 127         public static final byte SPRITE_IMAGE_ENEMY1 = 3;
 128         public static final byte SPRITE_IMAGE_ENEMY2 = 4;
 129         public static final byte SPRITE_IMAGE_ENEMY3 = 5;
 130         public static final byte SPRITE_IMAGE_EXPLOSION = 6;
 131         public static final byte SPRITE_IMAGE_MAX = 7;
 132         
 133         public static final byte SPRITE_FRAME_PLAYER_LEFT = 0;
 134         public static final byte SPRITE_FRAME_PLAYER_CENTER = 1;
 135         public static final byte SPRITE_FRAME_PLAYER_RIGHT = 2;
 136         
 137         public static final byte PLAYER_FIRE_COOLDOWN_WAIT_FRAMES = 5;
 138         public static final byte ENEMY_FIRE_COOLDOWN_WAIT_FRAMES = 40;
 139         
 140         public static Image tileImage;
 141 
 142         public static int menuScreen;
 143         public static final byte MENU_SCR_MAIN = 0; 
 144         public static final byte MENU_SCR_TEXT_ABOUT = 1;
 145         public static final byte MENU_SCR_TEXT_HELP = 2;
 146         public static final byte MENU_SCR_TEXT_GAME_OVER = 3;
 147         public static final byte MENU_SCR_PAUSE_GAME = 4; 
 148         public static final byte MENU_SCR_HISCORE_ENTER = 5; 
 149         public static final byte MENU_SCR_HISCORE_VIEW = 6; 
 150 
 151         public static int menuSelectedOption;
 152         public static final byte MENU_OPTION_MAIN_NEW_GAME = 0;
 153         public static final byte MENU_OPTION_MAIN_HISCORES = 1;
 154         public static final byte MENU_OPTION_MAIN_ABOUT = 2;
 155         public static final byte MENU_OPTION_MAIN_HELP = 3;
 156         public static final byte MENU_OPTION_MAIN_MAX = 3;
 157         
 158         public static final String[] menuScreenMainOptions = { "New game", "Highscore", "About", "Help"};
 159         
 160         public static final String[][] menuScreensTextLines = {
 161                 { "" },
 162                 { "About", "", "Epsilon v0.1", "(c) 2005 zigah." },
 163                 { "Help", "", "Press LEFT, RIGHT, ", "UP or DOWN", "to move and", "FIRE to shoot." },
 164                 { "Game Over", "", "Well done!"},
 165                 { "","Paused!"},
 166         };
 167 
 168 
 169         // Highscore
 170         public static final byte MAX_SCORES = 5;
 171         public static final String SCORE_DB_NAME = "EPS";
 172         public static String hiNames[] = { "JOE", "DOE", "LAA", "BIG", "MAC" };
 173         public static int hiScores[] = { 300, 200, 150, 100, 50 };
 174         private static RecordStore db;
 175 
 176         public static final char[] HI_NAME_ENTER_DEFAULT = {"A","A","A"};
 177         public static final byte MAX_HI_NAME_LENGTH = 3;
 178     public static char[] hi_name_enter = new char[MAX_HI_NAME_LENGTH];
 179         public static byte hi_name_enter_char_pos;
 180         
 181 
 182         // for debug purposes
 183         public boolean god_mode; 
 184         
 185         public static GameSprite player;
 186         public static Vector playerFireSprites;
 187         public static int player_score;
 188         public static int player_gameover_explosion_counter;
 189         public static final byte PLAYER_GAMEOVER_EXPLOSION_COUNTER_MAX = 40;
 190         
 191         public static boolean activate_boss_energy_bar;
 192         
 193         public static int boss_dead_explosion_counter;
 194         public static final byte BOSS_DEAD_EXPLOSION_COUNTER_MAX = 80;
 195 
 196         public static final byte FIRE_VELOCITY = 8;
 197         public static final byte MAX_ENEMY_FIRE = 6;
 198                 
 199         public static Vector enemyFireSprites;
 200 
 201         public static final byte MAX_ENERGY_PLAYER = 100;
 202         public static final byte MAX_ENERGY_PLAYER_FIRE = 10;
 203         public static final byte MAX_ENERGY_ENEMY = 10;
 204         
 205         public static Vector explosionSprites;
 206 
 207         public static byte max_enemy_sprites = 3;
 208         
 209         public static final short FIXED_FRAME_TIME = 40;
 210 
 211         public static int global_frame_counter;
 212         
 213         public static Random random = new Random();
 214         
 215         GameCanvas(Game midlet)
 216         {
 217                 this.midlet = midlet;
 218 
 219                 canvasWidth = this.getWidth();
 220                 canvasHeight = this.getHeight();
 221 
 222                 loadingCounter = 0;
 223                 menuScreen = MENU_SCR_MAIN;
 224                 menuSelectedOption = MENU_OPTION_MAIN_NEW_GAME;
 225                 mode = MODE_INTRO;
 226                 gameRunning = true;
 227         }
 228 
 229         public synchronized void run()
 230         {
 231                 if(gameRunning)
 232                 {
 233                         long frameStartTime = System.currentTimeMillis();
 234                         global_frame_counter++;
 235                         
 236                         repaint();
 237                         //serviceRepaints();
 238                         midlet.display.callSerially(this);
 239 
 240                         switch (mode) {
 241                         case MODE_INTRO:
 242 
 243                                 try
 244                                 {
 245                                         if (loadingCounter == 0)
 246                                         {
 247                                                 imgIntro = Image.createImage("/intro.png");
 248                                         }
 249                                         else if (loadingCounter == 1)
 250                                         {
 251                                                 loadImages();
 252                                                 loadHighscoreFromRMS();
 253                                         }
 254                                         else
 255                                         {
 256                                                 // view the intro splash image for a while
 257                                                 // it would be better to let user skip intro by pressing a key
 258                                                 // but, in a full game project, loading would take forever, anyway, so...
 259                                                 try     {
 260                                                         Thread.sleep(1000);
 261                                                 } catch (Exception e) {};
 262                                                 // switch mode
 263                                                 mode = MODE_MENU;
 264                                         }
 265                                         loadingCounter++;
 266                                 }
 267                                 catch (Exception e)     {
 268                                         // ignore loading exception     
 269                                 };
 270                                 break;
 271                                 
 272                         case MODE_MENU:
 273 
 274                                 if (command_up) {
 275                                         command_up = false;
 276                                         menuSelectedOption--;
 277                                         if (menuSelectedOption < 0)
 278                                                 menuSelectedOption = 0;
 279                                         
 280                                         if (menuScreen == MENU_SCR_HISCORE_ENTER)
 281                                         {
 282                                                 if ( hi_name_enter[hi_name_enter_char_pos] > "A")
 283                                                         hi_name_enter[hi_name_enter_char_pos]--;
 284                                         }
 285                                 }
 286                                 if (command_down) {
 287                                         command_down = false;
 288                                         menuSelectedOption++;
 289                                         if ((menuScreen == MENU_SCR_MAIN) &&
 290                                                         (menuSelectedOption > MENU_OPTION_MAIN_MAX))
 291                                                 menuSelectedOption = MENU_OPTION_MAIN_MAX;
 292                                         
 293                                         if (menuScreen == MENU_SCR_HISCORE_ENTER)
 294                                         {
 295                                                 if ( hi_name_enter[hi_name_enter_char_pos] < "Z")
 296                                                         hi_name_enter[hi_name_enter_char_pos]++;
 297                                         }
 298                                 }
 299                                 if (command_left) {
 300                                         command_left = false;
 301                                         
 302                                         if (menuScreen == MENU_SCR_HISCORE_ENTER)
 303                                         {
 304                                                 if (hi_name_enter_char_pos > 0)
 305                                                         hi_name_enter_char_pos--;
 306                                         }
 307                                 }
 308                                 if (command_right) {
 309                                         command_left = false;
 310                                         
 311                                         if (menuScreen == MENU_SCR_HISCORE_ENTER)
 312                                         {
 313                                                 if (hi_name_enter_char_pos < MAX_HI_NAME_LENGTH-1)
 314                                                         hi_name_enter_char_pos++;
 315                                         }
 316                                 }
 317                                 
 318                                 if (menu_command_1)
 319                                 {
 320                                         menu_command_1 = false;
 321                                         if (menuScreen == MENU_SCR_MAIN)
 322                                         {
 323                                                 switch(menuSelectedOption)
 324                                                 {
 325                                                 case MENU_OPTION_MAIN_NEW_GAME:
 326                                                         startGame();
 327                                                         break;
 328                                                         
 329                                                 case MENU_OPTION_MAIN_HISCORES:
 330                                                         menuScreen = MENU_SCR_HISCORE_VIEW;
 331                                                         break;
 332                                                 
 333                                                 case MENU_OPTION_MAIN_ABOUT:
 334                                                         menuScreen = MENU_SCR_TEXT_ABOUT;
 335                                                         break;
 336                                                         
 337                                                 case MENU_OPTION_MAIN_HELP:
 338                                                         menuScreen = MENU_SCR_TEXT_HELP;
 339                                                         break;
 340                                                 }
 341                                         } else if ( menuScreen == MENU_SCR_PAUSE_GAME) {
 342                                                 // resume pressed
 343                                                 mode = MODE_GAME;
 344                                         } else if ( menuScreen == MENU_SCR_TEXT_GAME_OVER) {
 345                                                 // ok pressed
 346                                                 if ( isQualified( player_score ) != -1 )
 347                                                 {
 348                                                         menuScreen = MENU_SCR_HISCORE_ENTER;
 349                                                         // init enter name character position
 350                                                         hi_name_enter_char_pos = 0;
 351                                                         hi_name_enter = HI_NAME_ENTER_DEFAULT;
 352                                                 } else {
 353                                                         menuScreen = MENU_SCR_HISCORE_VIEW;
 354                                                 }
 355                                         } else if ( menuScreen == MENU_SCR_HISCORE_ENTER) {
 356                                                 // save highscore
 357 
 358                                                 String name = new String(hi_name_enter);
 359                                                 addHighscore(player_score, name);
 360                                                 
 361                                                 menuScreen = MENU_SCR_HISCORE_VIEW;
 362                                         } else {
 363                                                 // all other menu screens go to main menu when OK is selected
 364                                                 menuScreen = MENU_SCR_MAIN;
 365                                         }
 366                                 }
 367                                 if (menu_command_2)
 368                                 {
 369                                         menu_command_2 = false;
 370                                         
 371                                         // back to main menu, when end game selected
 372                                     if ( menuScreen == MENU_SCR_PAUSE_GAME) {
 373                                                 menuScreen = MENU_SCR_MAIN;
 374                                     } else if (menuScreen == MENU_SCR_MAIN)
 375                                     {
 376                                                 midlet.exitRequested();
 377                                     }
 378                                 }
 379 
 380                                 // delay, so the keypress events get their turn...
 381                                 try     {
 382                                         Thread.sleep(40);
 383                                 } catch (Exception e) {};
 384                                 break;
 385                                 
 386                         case MODE_GAME:
 387 
 388                                 // scroll space and tile background
 389                                 Level.space_scroll_y += Level.space_scroll_vy;
 390                                 Level.tiles_scroll_y += Level.tiles_scroll_vy;
 391 
 392                                 // top of the level (boss) reached, stop scrolling
 393                                 if (Level.tiles_scroll_y < 0) {
 394                                         Level.tiles_scroll_y = 0;
 395                                         Level.tiles_scroll_vy = 0;
 396                                 }
 397                                 
 398 //                              int tiles_scroll_x_range = (Level.LEVEL_WIDTH * Level.TILE_SIZE - canvasWidth);
 399 //                              int player_x_range = canvasWidth - player.w;
 400 //                              Level.tiles_scroll_x = player.x * tiles_scroll_x_range / player_x_range;
 401 
 402 
 403                                 // update scroll_x
 404                                 Level.tiles_scroll_x = player.x + player.w/2 - canvasWidth/2;
 405                                 if (Level.tiles_scroll_x > (Level.LEVEL_WIDTH * Level.TILE_SIZE - canvasWidth)) {
 406                                         Level.tiles_scroll_x = (Level.LEVEL_WIDTH * Level.TILE_SIZE - canvasWidth);
 407                                 }
 408                                 
 409                                 if (Level.tiles_scroll_x < 0) {
 410                                         Level.tiles_scroll_x = 0;
 411                                 }
 412                                 
 413                                 updatePlayerSprite();
 414                                 updatePlayerFireSprites();
 415 
 416                                 updateEnemySprites();
 417                                 updateEnemyFireSprites();
 418                                 
 419                                 updateExplosionSprites();
 420                                 
 421                                 // check player <-> enemy <-> player fire collision
 422                                 doCollision();
 423                                 
 424                                 // check for game end
 425                                 if ( (player.energy <= 0) && (player_gameover_explosion_counter == 0) )
 426                                 {
 427                                         // TODO: lose screen
 428                                         endGame();
 429                                 }
 430                                 // check for game end
 431                                 if ( (Level.boss.energy <= 0) && (boss_dead_explosion_counter == 0) )
 432                                 {
 433                                         // TODO: win screen
 434                                         endGame();
 435                                 }
 436                                 if (menu_command_2)
 437                                 {
 438                                         menu_command_2 = false;
 439                                         // on softkey_2 activate pause game menu
 440                                         mode = MODE_MENU;
 441                                         menuScreen = MENU_SCR_PAUSE_GAME;
 442                                 }
 443 
 444                                 // calc. delay
 445                                 long frameTime = System.currentTimeMillis() - frameStartTime;
 446                                 if (frameTime < FIXED_FRAME_TIME)
 447                                 {
 448                                         try     {
 449                                                 Thread.sleep( FIXED_FRAME_TIME - frameTime );
 450                                         } catch (Exception e) {};
 451                                 }
 452                                 break;
 453                         }
 454                 }
 455         }
 456         
 457         public synchronized void paint(Graphics g)
 458         {
 459                 switch(mode)
 460                 {
 461                 case MODE_INTRO:
 462 
 463                         g.setColor(0x000000);
 464                         g.fillRect(0, 0, canvasWidth, canvasHeight);
 465                         if (imgIntro != null) {
 466                                 g.drawImage(imgIntro, canvasWidth/2, canvasHeight/2, Graphics.VCENTER | Graphics.HCENTER);
 467                         }
 468 
 469 //                      g.setColor(0xFFFFFF);
 470 //                      g.drawString(""+loadingCounter,0,0,Graphics.LEFT | Graphics.TOP);
 471 
 472                         break;
 473                         
 474                 case MODE_MENU:
 475 
 476                         Level.paintSpaceBackground(g);
 477 
 478                         switch(menuScreen)
 479                         {
 480                         case MENU_SCR_MAIN:
 481                                 paintMainMenu(g);
 482                                 break;
 483                                 
 484                         case MENU_SCR_TEXT_ABOUT:
 485                         case MENU_SCR_TEXT_HELP:
 486                         case MENU_SCR_TEXT_GAME_OVER:
 487                         case MENU_SCR_PAUSE_GAME:
 488                                 paintTextMenu(g, menuScreen);
 489                                 break;
 490                         case MENU_SCR_HISCORE_VIEW:
 491                                 paintHiscoreView(g);
 492                                 break;
 493                         case MENU_SCR_HISCORE_ENTER:
 494                                 paintHiscoreEnter(g);
 495                                 break;
 496                         }
 497                         break;
 498                         
 499                 case MODE_GAME:
 500                         
 501                         Level.paintSpaceBackground(g);
 502                         Level.paintTiles(g);
 503                         
 504                         paintSprite( g, player );
 505                         
 506                         for (int i=0; i < Level.enemySprites.size(); i++)
 507                                 paintSprite( g, (GameSprite) Level.enemySprites.elementAt(i) );
 508                         
 509                         for (int i=0; i < explosionSprites.size(); i++)
 510                                 paintSprite( g, (GameSprite) explosionSprites.elementAt(i) );
 511 
 512                         for (int i=0; i < playerFireSprites.size(); i++)
 513                                 paintSprite( g, (GameSprite) playerFireSprites.elementAt(i));
 514                         
 515                         for (int i=0; i < enemyFireSprites.size(); i++)
 516                                 paintSprite( g, (GameSprite) enemyFireSprites.elementAt(i));
 517 
 518                         paintStatusBars(g);
 519                         
 520                         break;          
 521                 }
 522         }
 523         
 524         public void keyPressed(int key)
 525         {
 526                 switch(key) {
 527                 case SOFTKEY_1:
 528                         menu_command_1 = true;
 529                         break;
 530                         
 531                 case SOFTKEY_2:
 532                         menu_command_2 = true;
 533                         break;
 534 
 535                 // TODO: debug, temp, remove
 536                 case KEY_POUND:
 537                         god_mode = !god_mode;
 538                         break;
 539                 // TODO: debug, temp, remove
 540                 case KEY_STAR:
 541                         Level.tiles_scroll_vy *= 2;
 542                         break;
 543                 }
 544                 
 545                 int game_action = getGameAction(key);
 546                 
 547                 switch(game_action)
 548                 {
 549                 case UP:
 550                         command_up = true;
 551                         break;
 552 
 553                 case DOWN:
 554                         command_down = true;
 555                         break;
 556 
 557                 case LEFT:
 558                         command_left = true;
 559                         break;
 560 
 561                 case RIGHT:
 562                         command_right = true;
 563                         break;
 564 
 565                 case FIRE:
 566                         command_fire = true;
 567                         menu_command_1 = true;
 568                         break;
 569                 }
 570         }
 571         
 572         public void keyReleased(int key)
 573         {
 574                 int game_action = getGameAction(key);
 575 
 576                 switch(game_action)
 577                 {
 578                 case UP:
 579                         command_up = false;
 580                         break;
 581 
 582                 case DOWN:
 583                         command_down = false;
 584                         break;
 585 
 586                 case LEFT:
 587                         command_left = false;
 588                         break;
 589 
 590                 case RIGHT:
 591                         command_right = false;
 592                         break;
 593 
 594                 case FIRE:
 595                         command_fire = false;
 596                         menu_command_1 = false;
 597                         break;
 598                 }
 599         }
 600 
 601         public void paintMainMenu(Graphics g)
 602         {
 603                 // init font
 604                 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_LARGE));
 605                 int menu_y = canvasHeight/2 - 45;
 606                 for(int i=0; i <= MENU_OPTION_MAIN_MAX; i++)
 607                 {
 608                         // paint the main menu options
 609                         if (i == menuSelectedOption) {
 610                                 g.setColor(0xFFCC00);
 611                         } else {
 612                                 g.setColor(0xFFFFFF);
 613                         }
 614                         
 615                         g.drawString(menuScreenMainOptions[i], canvasWidth/2, menu_y, Graphics.HCENTER | Graphics.TOP);
 616 
 617                         menu_y += 20;
 618                 }
 619                 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
 620                 g.setColor(0xFFFFFF);
 621                 // paint softkey_1 label
 622                 g.drawString("Select", 2, canvasHeight-2, Graphics.LEFT | Graphics.BOTTOM);
 623                 // paint softkey_2 label
 624                 g.drawString("Exit", canvasWidth-2, canvasHeight-2, Graphics.RIGHT | Graphics.BOTTOM);
 625         }
 626 
 627         public void paintTextMenu(Graphics g, int screen)
 628         {
 629                 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
 630                 g.setColor(0xFFFFFF);
 631                 int text_line_y = 10;
 632                 for(int line=0; line < menuScreensTextLines[screen].length; line++)
 633                 {
 634                         // paint all the lines of text in this menu screen
 635                         g.drawString(menuScreensTextLines[screen][line], canvasWidth/2, text_line_y, Graphics.HCENTER | Graphics.TOP);
 636                         
 637                         text_line_y += 15;
 638                 }
 639                 if (screen == MENU_SCR_TEXT_GAME_OVER)
 640                 {
 641                         // print score in the game over screen
 642                         text_line_y += 15;
 643                         g.drawString("Score: "+ player_score, canvasWidth/2, text_line_y, Graphics.HCENTER | Graphics.TOP);
 644                 }
 645 
 646                 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_MEDIUM));
 647                 
 648                 if (menuScreen == MENU_SCR_PAUSE_GAME )
 649                 {
 650                         // paint softkey_1 label
 651                         g.drawString("Resume", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
 652                         // paint softkey_2 label
 653                         g.drawString("End game", canvasWidth-1, canvasHeight-1, Graphics.RIGHT | Graphics.BOTTOM);
 654                 }
 655                 else
 656                 {
 657                         // paint softkey_1 label
 658                         g.drawString("Ok", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
 659                 }
 660         }
 661 
 662         public static void paintHiscoreView(Graphics g)
 663         {
 664                 g.setColor(0xFFFFFF);
 665 
 666                 g.drawString("Highscore!", canvasWidth/2, 2, Graphics.HCENTER | Graphics.TOP);
 667 
 668                 for (int i=0; i < MAX_SCORES; i++)
 669                 {
 670                         g.drawString(hiNames[i], canvasWidth*1/4, 20 + 20*i, Graphics.LEFT | Graphics.TOP);
 671                         g.drawString(""+hiScores[i], canvasWidth*3/4, 20 + 20*i, Graphics.RIGHT | Graphics.TOP);
 672                 }
 673                 
 674                 // paint softkey_1 label
 675                 g.drawString("Ok", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
 676         }
 677         public static void paintHiscoreEnter(Graphics g)
 678         {
 679                 g.setColor(0xFFFFFF);
 680 
 681                 g.drawString("Enter name:", canvasWidth/2, canvasHeight*1/4, Graphics.HCENTER | Graphics.BOTTOM);
 682 
 683                 for (int i=0; i < MAX_HI_NAME_LENGTH; i++)
 684                 {
 685                         if (i == hi_name_enter_char_pos)
 686                                 g.setColor(0xFFFF00);
 687                         else
 688                                 g.setColor(0xFFFFFF);
 689                         g.drawChar(hi_name_enter[i], canvasWidth/2 - 12 + 12*i, canvasHeight*2/4, Graphics.HCENTER | Graphics.BOTTOM);
 690                 }
 691 
 692                 g.setColor(0xFFFFFF);
 693                 g.drawString("Score: "+ player_score, canvasWidth/2, canvasHeight*3/4, Graphics.HCENTER | Graphics.BOTTOM);
 694 
 695                 // paint softkey_1 label
 696                 g.drawString("Save", 1, canvasHeight-1, Graphics.LEFT | Graphics.BOTTOM);
 697         }
 698 
 699         public static void paintSprite(Graphics g, GameSprite spr)
 700         {
 701                 // set the clip window
 702                 int dx = spr.x - Level.tiles_scroll_x;
 703                 int dy = spr.y - Level.tiles_scroll_y;
 704                 int cx = dx;
 705                 int cy = dy;
 706                 int cw = GameSprite.spriteImageFrameWidths[spr.imageId];
 707                 int ch = spr.h;
 708                 g.setClip(cx, cy, cw, ch);
 709 
 710                 //  check clip window coordinates, if out of screen
 711                 if (cx < 0)
 712                 {
 713                         cw += cx;
 714                         cx = 0;
 715                 }
 716                 if (cy < 0)
 717                 {
 718                         ch += cy;
 719                         cy = 0;
 720                 }
 721                 
 722                 // calculate the x coordinate of where to start the image paint, so our frame will be seen through the clip window
 723                 dx = dx - spr.frameId * GameSprite.spriteImageFrameWidths[spr.imageId];
 724                 
 725                 // paint the sprites image at the calculated coordinates
 726                 g.drawImage(spriteImages[spr.imageId], dx, dy, Graphics.TOP | Graphics.LEFT);
 727 
 728                 // restore the clip window
 729                 g.setClip(0, 0, canvasWidth, canvasHeight);
 730         }
 731 
 732         public static void paintStatusBars(Graphics g)
 733         {
 734                 int max_energy_bar_width = canvasWidth/2;
 735 
 736                 // paint the energy bar
 737                 g.setColor(0xFFFFFF);
 738                 g.drawRect(5, 5, max_energy_bar_width + 1, 4);
 739                 g.setColor(0xFFCC00);
 740                 g.fillRect(6, 6, player.energy * max_energy_bar_width / player.energyMax, 3);
 741                 
 742                 if ( activate_boss_energy_bar)
 743                 {
 744                         // paint the energy bar
 745                         g.setColor(0xFFFFFF);
 746                         g.drawRect(5, 12, max_energy_bar_width + 1, 4);
 747                         g.setColor(0xFF9900);
 748                         g.fillRect(6, 13, Level.boss.energy * max_energy_bar_width / Level.boss.energyMax, 3);
 749                 }
 750 
 751                 
 752                 // paint the score count
 753                 g.setColor(0xFFFFFF);
 754                 g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL));
 755                 g.drawString(""+player_score, canvasWidth-4, 8, Graphics.TOP | Graphics.RIGHT);
 756         }
 757 
 758         public void startGame()
 759         {
 760                 // switch to game mode
 761                 mode = MODE_GAME;
 762 
 763                 player_score = 0;
 764                 player_gameover_explosion_counter = -1;
 765                                 
 766                 activate_boss_energy_bar = false;
 767                 boss_dead_explosion_counter = -1;
 768 
 769                 // initialize the explosion sprite list
 770                 explosionSprites = new Vector();
 771                 
 772                 // initialize the player fire list
 773                 playerFireSprites = new Vector();
 774 
 775                 // initialize the enemy fire list
 776                 enemyFireSprites = new Vector();
 777 
 778                 // init level tiles position to horizontal center and vertical bottom
 779                 Level.tiles_scroll_x = Level.LEVEL_WIDTH * Level.TILE_SIZE / 2 - canvasWidth /2;
 780                 Level.tiles_scroll_y = Level.LEVEL_HEIGHT * Level.TILE_SIZE - canvasHeight - 1;
 781                 
 782                 Level.loadLevel((byte) 1);
 783         }
 784         
 785         public void endGame()
 786         {
 787                 // back to menu mode, set the game over text screen
 788                 mode = MODE_MENU;
 789                 menuScreen = MENU_SCR_TEXT_GAME_OVER;
 790 
 791                 // clean up
 792                 player = null;
 793                 Level.enemySprites = null;
 794         }
 795 
 796         public void updateEnemySprites()
 797         {
 798                 // move enemy sprites
 799                 int i = Level.enemySprites.size()-1;
 800                 while (i >= 0)
 801                 {
 802                         GameSprite enemy = (GameSprite) Level.enemySprites.elementAt(i);
 803                         
 804                         if ( (enemy.y - Level.tiles_scroll_y > canvasHeight) )
 805                         {
 806                                 // remove out-of-screen enemies
 807                                 Level.enemySprites.removeElementAt(i);
 808                                 i--;
 809                         }
 810                         else
 811                         {
 812                                 //System.out.println(enemy.y +"-"+ Level.tiles_scroll_y +">"+ Level.ENEMY_AI_ACTIVATION_ZONE_Y);
 813                                 // do the AI move, shoot and other tricks
 814                                 if ( enemy.y - Level.tiles_scroll_y > Level.ENEMY_AI_ACTIVATION_ZONE_Y )
 815                                 {
 816                                         doEnemyAI( enemy );
 817                                         i--;
 818                                 } else {
 819                                         // optimization
 820                                         // but enemySprites must be ordered by the sprites" y coordinate !
 821                                         // they are in this case, because of loadLevel
 822                                         break;
 823                                 }
 824                         }
 825                 }
 826                 if (boss_dead_explosion_counter > 0)
 827                 {
 828                         boss_dead_explosion_counter--;
 829                 }
 830         }
 831         
 832         public void doEnemyAI( GameSprite sprite )
 833         {
 834                 //System.out.println("doing enemy ai for "+sprite.spriteId);
 835                 
 836                 switch (sprite.spriteId)
 837                 {
 838                 case Level.SPRITE_ID_ENEMY1:
 839                         break;
 840                 case Level.SPRITE_ID_ENEMY1_SHOOTING:
 841 
 842                         shootEnemyFire(sprite, Level.SPRITE_ID_FIRE2, (byte) 1);
 843                         
 844                         break;
 845                 case Level.SPRITE_ID_ENEMY2:
 846                         break;
 847                 case Level.SPRITE_ID_ENEMY2_SHOOTING:
 848                         
 849                         shootEnemyFire(sprite, Level.SPRITE_ID_FIRE2, (byte) 1);
 850 
 851                         break;
 852                 case Level.SPRITE_ID_ENEMY3:
 853 
 854                         // animate sprite to next sprite frame every 3 frames
 855                         if (global_frame_counter % 3 == 0)
 856                                 sprite.frameId = (byte) ( (sprite.frameId + 1) % (sprite.frameIdMax+1));
 857                         
 858                         break;
 859                 case Level.SPRITE_ID_BOSS1:
 860 
 861                         activate_boss_energy_bar = true;
 862 
 863                         // boss fire
 864                         if (sprite.fire_cooldown_frames_counter <= 0)
 865                         {
 866                                 GameSprite new_fire;
 867 
 868                                 new_fire = new GameSprite(Level.SPRITE_ID_FIRE2);
 869                                 new_fire.frameId = 1;
 870                                 new_fire.x = sprite.x + sprite.w - 5 - new_fire.w;
 871                                 new_fire.y = sprite.y + sprite.h;
 872                                 new_fire.vy = sprite.vy + FIRE_VELOCITY/2;
 873                                 enemyFireSprites.addElement(new_fire);
 874 
 875                                 new_fire = new GameSprite(Level.SPRITE_ID_FIRE2);
 876                                 new_fire.frameId = 1;
 877                                 new_fire.x = sprite.x + 5;
 878                                 new_fire.y = sprite.y + sprite.h;
 879                                 new_fire.vy = sprite.vy + FIRE_VELOCITY/2;
 880                                 enemyFireSprites.addElement(new_fire);
 881 
 882                                 new_fire = new GameSprite(Level.SPRITE_ID_FIRE3);
 883                                 new_fire.frameId = 2;
 884                                 new_fire.x = sprite.x + sprite.w / 2 - new_fire.w / 2;
 885                                 new_fire.y = sprite.y + sprite.h;
 886                                 new_fire.vy = sprite.vy + FIRE_VELOCITY;
 887                                 enemyFireSprites.addElement(new_fire);
 888 
 889                                 sprite.fire_cooldown_frames_counter = ENEMY_FIRE_COOLDOWN_WAIT_FRAMES;
 890                         } else {
 891                                 // extra cooldown, boss only
 892                                 sprite.fire_cooldown_frames_counter--;
 893                         }
 894                         
 895                         // boss move
 896                         if (sprite.x + sprite.w > (Level.LEVEL_WIDTH * Level.TILE_SIZE) - (Level.TILE_SIZE/2) )
 897                                 sprite.vx = -1;
 898                         if (sprite.x < Level.TILE_SIZE/2 )
 899                                 sprite.vx = 1;
 900                         
 901                         break;
 902                 }
 903                 
 904                 // move the sprite
 905                 sprite.x += sprite.vx;
 906                 sprite.y += sprite.vy;
 907 
 908                 if (sprite.fire_cooldown_frames_counter > 0)
 909                         sprite.fire_cooldown_frames_counter--;
 910         }
 911 
 912         public GameSprite shootEnemyFire(GameSprite sprite, byte fire_sprite_id, byte fire_sprite_frame_id)
 913         {
 914                 GameSprite new_fire = null;
 915                 if (enemyFireSprites.size() < MAX_ENEMY_FIRE && sprite.fire_cooldown_frames_counter <= 0)
 916                 {
 917 //                      System.out.println("adding fire sprite ... ");
 918                         new_fire = new GameSprite(fire_sprite_id);
 919                         new_fire.frameId = fire_sprite_frame_id;
 920                         new_fire.x = sprite.x + sprite.w / 2;
 921                         new_fire.y = sprite.y + sprite.h;
 922                         new_fire.vy = sprite.vy + FIRE_VELOCITY/2;
 923                         enemyFireSprites.addElement(new_fire);
 924 
 925                         sprite.fire_cooldown_frames_counter = ENEMY_FIRE_COOLDOWN_WAIT_FRAMES;
 926                         
 927                 }
 928                 return new_fire;
 929         }
 930         
 931         public void updatePlayerSprite()
 932         {
 933                 // move player with level scroll
 934                 player.y += Level.tiles_scroll_vy;
 935 
 936                 if (player_gameover_explosion_counter > 0)
 937                 {
 938                         player_gameover_explosion_counter--;
 939                 }
 940                 else
 941                 {
 942                         // move player sprite on command, and check player <-> screen edge collision
 943                         if (command_up)
 944                         {
 945                                 player.y -= player.vy;
 946                                 if (player.y < Level.tiles_scroll_y)
 947                                         player.y = Level.tiles_scroll_y;
 948                         }
 949                         if (command_down)
 950                         {       
 951                                 player.y += player.vy;
 952                                 // level edge collision
 953                                 if (player.y - Level.tiles_scroll_y > canvasHeight - player.h)
 954                                         player.y = Level.tiles_scroll_y + canvasHeight - player.h;
 955                         }
 956                         player.frameId = SPRITE_FRAME_PLAYER_CENTER;
 957                         if (command_left)
 958                         {       
 959                                 player.x -= player.vx;
 960                                 if (player.x < Level.tiles_scroll_x)
 961                                         player.x = Level.tiles_scroll_x;
 962                                 player.frameId = SPRITE_FRAME_PLAYER_LEFT;
 963                         }
 964                         if (command_right)
 965                         {       
 966                                 player.x += player.vx;
 967                                 if (player.x - Level.tiles_scroll_x > canvasWidth - player.w)
 968                                         player.x = Level.tiles_scroll_x + canvasWidth - player.w;
 969                                 player.frameId = SPRITE_FRAME_PLAYER_RIGHT;
 970                         }
 971                         if (command_fire)
 972                         {
 973                                 if (player.fire_cooldown_frames_counter <= 0)
 974                                 {
 975                                         GameSprite fire = new GameSprite(Level.SPRITE_ID_FIRE1);
 976                                         fire.x = player.x + player.w/2 - fire.w/2;
 977                                         fire.y = player.y;
 978                                         fire.vy = -FIRE_VELOCITY + Level.tiles_scroll_vy;
 979                                         playerFireSprites.addElement(fire);
 980         
 981                                         player.fire_cooldown_frames_counter = PLAYER_FIRE_COOLDOWN_WAIT_FRAMES;
 982                                 }
 983                         }
 984                         if (player.fire_cooldown_frames_counter > 0)
 985                                 player.fire_cooldown_frames_counter--;
 986                         if ( god_mode )
 987                                 player.fire_cooldown_frames_counter -= 2;
 988                 }
 989         }
 990 
 991         public void doCollision()
 992         {
 993                 
 994                 int i = Level.enemySprites.size() - 1;
 995                 while (i >= 0 )
 996                 {
 997                         GameSprite enemy = (GameSprite) Level.enemySprites.elementAt(i);
 998                         
 999                         // check player <-> enemy collision
1000                         if (player.collidesWith(enemy))
1001                         {
1002                                 // add explosion
1003                                 addExplosion(enemy);
1004                                 addExplosion(player);
1005 
1006                                 // player loses energy
1007                                 if ( !god_mode )
1008                                         player.energy -= enemy.damage;
1009                                 
1010                                 if (player.energy <= 0 && player_gameover_explosion_counter < 0)
1011                                 {
1012                                         player_gameover_explosion_counter = PLAYER_GAMEOVER_EXPLOSION_COUNTER_MAX;
1013                                 }
1014 
1015                                 // level boss does not take damage from colliding with player
1016                                 if (enemy != Level.boss)
1017                                         enemy.energy -= player.damage;
1018 
1019                         }
1020                         
1021                         // check the player fire sprites <-> enemy collision
1022                         int j = playerFireSprites.size() - 1;
1023                         while (j >= 0)
1024                         {
1025                                 GameSprite fire = (GameSprite) playerFireSprites.elementAt(j);
1026                                 if (fire.collidesWith(enemy))
1027                                 {
1028                                         enemy.energy -= fire.damage;
1029                                         
1030                                         // add explosions
1031                                         addExplosion(enemy);
1032 
1033                                         // destroy player fire
1034                                         playerFireSprites.removeElementAt(j);
1035                                         j--;
1036                                 }
1037                                 j--;
1038                         }
1039                         // remove dead enemies
1040                         if (enemy.energy <= 0)
1041                         {
1042                                 Level.enemySprites.removeElementAt(i);
1043                                 i--;
1044                                 // increase player score
1045                                 player_score += enemy.score;
1046 
1047                                 // if boss sprite
1048                                 if (enemy.spriteId == Level.SPRITE_ID_BOSS1)
1049                                 {
1050                                         boss_dead_explosion_counter = BOSS_DEAD_EXPLOSION_COUNTER_MAX;
1051                                 }
1052                         }
1053                         
1054                         i--;
1055                 }
1056                 // check the enemy fire sprites <-> player collision
1057                 int j = enemyFireSprites.size() - 1;
1058                 while (j >= 0)
1059                 {
1060                         GameSprite fire = (GameSprite) enemyFireSprites.elementAt(j);
1061                         if (fire.collidesWith(player))
1062                         {
1063                                 if ( !god_mode )
1064                                         player.energy -= fire.damage;
1065                                 
1066                                 // add explosions
1067                                 addExplosion(player);
1068 
1069                                 // destroy enemy fire
1070                                 enemyFireSprites.removeElementAt(j);
1071                                 j--;
1072                         }
1073                         j--;
1074                 }
1075         }
1076 
1077         public void updatePlayerFireSprites()
1078         {
1079                 for (int i=0; i < playerFireSprites.size(); i++)
1080                 {
1081                         GameSprite fire = (GameSprite) playerFireSprites.elementAt(i);
1082                         fire.y += fire.vy;
1083                         
1084                         // destroy player fire when out of screen
1085                         if ( (fire.y + fire.h) < Level.tiles_scroll_y)
1086                         {
1087                                 playerFireSprites.removeElementAt(i);
1088                                 // only increase counter, if not removed from list
1089                                 i--;
1090                         }
1091                 }
1092         }
1093 
1094         public void updateEnemyFireSprites()
1095         {
1096                 for (int i=0; i < enemyFireSprites.size(); i++)
1097                 {
1098 //                      System.out.println("updating enemy fire sprite...");
1099                         
1100                         GameSprite fire = (GameSprite) enemyFireSprites.elementAt(i);
1101                         fire.y += fire.vy;
1102                         
1103                         // destroy enemy fire when out of screen
1104                         if ( fire.y > Level.tiles_scroll_y + canvasHeight)
1105                         {
1106                                 enemyFireSprites.removeElementAt(i);
1107                                 // only increase counter, if not removed from list
1108                                 i--;
1109                         }
1110                 }
1111         }
1112 
1113         public void updateExplosionSprites()
1114         {
1115                 for (int i=0; i < explosionSprites.size(); i++)
1116                 {
1117                         GameSprite exp = (GameSprite) explosionSprites.elementAt(i);
1118                         
1119                         // animate explosion!
1120                         exp.frameId++;
1121                         
1122                         if (exp.frameId > exp.frameIdMax)
1123                         {
1124                                 explosionSprites.removeElementAt(i);
1125                                 // only increase counter, if not removed from list
1126                                 i--;
1127                         }
1128                 }
1129                 // create a big bada boom player gameover explosion
1130                 //  7 - max explosion frames
1131                 //  2 - add an explosion every 2nd frame
1132                 if (player_gameover_explosion_counter > 7 &&
1133                                 player_gameover_explosion_counter % 2 == 0
1134                                 )
1135                 {
1136                         GameSprite new_exp = addExplosion(player);
1137                         new_exp.x += random.nextInt() % player.w;
1138                         new_exp.y += random.nextInt() % player.h;
1139                 }
1140                 // create a big bada boom boss gameover explosion
1141                 //  7 - max explosion frames
1142                 //  2 - add an explosion every 2nd frame
1143                 if (boss_dead_explosion_counter > 7 &&
1144                                 boss_dead_explosion_counter % 2 == 0
1145                                 )
1146                 {
1147                         GameSprite new_exp = addExplosion(Level.boss);
1148                         new_exp.x += random.nextInt() % Level.boss.w;
1149                         new_exp.y += random.nextInt() % Level.boss.h;
1150                 }
1151         }
1152 
1153         public static void loadImages()
1154         {
1155                 try {
1156                         
1157                         spriteImages = new Image[SPRITE_IMAGE_MAX]; 
1158                         spriteImages[SPRITE_IMAGE_PLAYER] = Image.createImage("/p.png"); 
1159                         spriteImages[SPRITE_IMAGE_FIRE] = Image.createImage("/fire.png"); 
1160                         spriteImages[SPRITE_IMAGE_BOSS1] = Image.createImage("/boss1.png"); 
1161                         spriteImages[SPRITE_IMAGE_ENEMY1] = Image.createImage("/e1.png"); 
1162                         spriteImages[SPRITE_IMAGE_ENEMY2] = Image.createImage("/e2.png"); 
1163                         spriteImages[SPRITE_IMAGE_ENEMY3] = Image.createImage("/e3.png"); 
1164                         spriteImages[SPRITE_IMAGE_EXPLOSION] = Image.createImage("/exp.png"); 
1165         
1166                         tileImage = Image.createImage("/t04.png");
1167                         
1168                         imgBackground = Image.createImage("/bg.png");
1169                         
1170                 } catch (Exception e)   {};
1171         }
1172 
1173         public static GameSprite addExplosion(GameSprite exp_spr)
1174         {
1175                 // add explosion
1176                 GameSprite exp = new GameSprite(Level.SPRITE_ID_EXPLOSION);
1177                 // center the explosion position on the exploded sprite
1178                 exp.x = exp_spr.x + exp_spr.w/2 - exp.w/2;
1179                 exp.y = exp_spr.y + exp_spr.h/2 - exp.h/2;
1180                 exp.vx = exp_spr.vx;
1181                 exp.vy = exp_spr.vy;
1182                 explosionSprites.addElement(exp);
1183                 
1184                 if (exp_spr.energy > 0)
1185                         exp.frameId = GameSprite.EXPLOSION_FRAME_SMOKE_START;
1186                 
1187                 return exp;
1188         }
1189         
1190         public void hideNotify()
1191         {
1192                 // hideNotify method of Canvas is called on external events, which hide the Canvas
1193                 // this method can be used to handle such events (battery warnings, incoming phone calls...)
1194                 if (mode == MODE_GAME)
1195                 {
1196                         mode = MODE_MENU;
1197                         menuScreen = MENU_SCR_PAUSE_GAME;
1198                 }
1199         }
1200 
1201 //      public void showNotify()
1202 //      {
1203 //              
1204 //      }
1205 
1206 
1207     // loads the highscores from RMS - the internal phone database
1208         // also saves default scores, if no scores exist.
1209         public static void loadHighscoreFromRMS()
1210         {
1211                 try
1212                 {
1213                         db = RecordStore.openRecordStore(SCORE_DB_NAME, true);
1214 
1215                         byte[] score_data = null;
1216                         // initialize scores
1217                         if (db.getNumRecords() == 0)
1218                         {
1219                                 // add record with initial default scores
1220                                 score_data = getHighscoreData();
1221                                 db.addRecord(score_data, 0, score_data.length);
1222                         }
1223                         // load highscore
1224                         score_data = db.getRecord(1);
1225                         ByteArrayInputStream in = new ByteArrayInputStream(score_data);
1226                         DataInputStream dis = new DataInputStream(in);
1227                         for (byte i = 0; i < MAX_SCORES; i++)
1228                         {
1229                                 hiScores[i] = dis.readInt();
1230                                 hiNames[i] = dis.readUTF();
1231                         }
1232                         dis.close();
1233                         in.close();
1234                         db.closeRecordStore();
1235                         dis = null;
1236                         in = null;
1237                         db = null;
1238 //                      System.gc();
1239                 } catch (Exception ex) {
1240                         ex.printStackTrace();
1241                 }
1242         }
1243 
1244         // prepares data in a byte array, ready for saving to a RMS record
1245         public static byte[] getHighscoreData() throws IOException
1246         {
1247                 ByteArrayOutputStream out = new ByteArrayOutputStream();
1248                 DataOutputStream dos = new DataOutputStream(out);
1249                 for (byte i = 0; i < MAX_SCORES; i++)
1250                 {
1251                         dos.writeInt(hiScores[i]);
1252                         dos.writeUTF(hiNames[i]);
1253                 }
1254                 dos.close();
1255                 out.close();
1256 
1257                 return out.toByteArray();
1258         }
1259 
1260         // saves highscores to RMS
1261         public static void saveHighscores()
1262         {
1263                 try
1264                 {
1265                         db = RecordStore.openRecordStore(SCORE_DB_NAME, true);
1266 
1267                         byte[] data = getHighscoreData();
1268 
1269                         db.setRecord(1, data, 0, data.length);
1270                         db.closeRecordStore();
1271                 } catch (Exception ex) {
1272                         ex.printStackTrace();
1273                 }
1274         }
1275 
1276         // returns -1 if not qualified, highscore position otherwise
1277         public static int isQualified(int score)
1278         {
1279                 for (byte i = 0; i < MAX_SCORES; i++)
1280                         if (hiScores[i] < score)
1281                                 return i;
1282                 return -1;
1283         }
1284 
1285         // add a score to the scores array and to the rms
1286         public static void addHighscore(int score, String name)
1287         {
1288                 int i = isQualified(score);
1289                 
1290                 // move others down 1 place
1291                 for (byte k = (byte) (MAX_SCORES - 1); k > i; k--) {
1292                         hiScores[k] = hiScores[k - 1];
1293                         hiNames[k] = hiNames[k - 1];
1294                 }
1295                 // insert score
1296                 hiScores[i] = score;
1297                 hiNames[i] = name;
1298 
1299                 saveHighscores();
1300                 return;
1301         }
1302 
1303 }
1304