text: /*
   * $Id: barragemanager.cc,v 1.4 2003/02/09 07:34:15 kenta Exp $
   *
   * Copyright 2002 Kenta Cho. All rights reserved.
   */
  
  /**
   * Handle stage data.
   *
   * @version $Revision: 1.4 $
   */
  extern "C" {
  #include "SDL.h"
  #include <sys/types.h>
  #include <dirent.h>
  #include "noiz2sa.h"
  #include "degutil.h"
  #include "vector.h"
  #include "screen.h"
  #include "rand.h"
  #include "brgmng_mtd.h"
  #include "soundmanager.h"
  #include "attractmanager.h"
  }
  
  #include "barragemanager.h"
  #include "foe.h"
  
  #include "log.h"
  #include "java.h"
  
  #define BARRAGE_PATTERN_MAX 32
  
  static Barrage barragePattern[BARRAGE_TYPE_NUM][BARRAGE_PATTERN_MAX];
  static Barrage *barrageQueue[BARRAGE_TYPE_NUM][BARRAGE_PATTERN_MAX];
  static int barragePatternNum[BARRAGE_TYPE_NUM];
  
  static Barrage *barrage[BARRAGE_MAX];
  
  static const char *BARRAGE_DIR_NAME[] = {
    "zako", "middle", "boss"
  };
  
  #ifndef ANDROID
  #define readBulletMLFiles(a,b) 0
  #else
  
  static int readBulletMLFiles(const char *dirPath, Barrage brg[]) {
  	int i = 0;
  	char fileName[256];
  	fprintf(stdout, "Opening...: %s\n", dirPath);
  	AAssetDir* const di = AAssetManager_openDir(getAAssetManager(), dirPath);
  	if ( di == NULL ) {
  		fprintf(stderr, "Can't open directory: %s\n", dirPath);
  		exit(1);
  	}else{
  		fprintf(stdout, "Opened directory: %s\n", dirPath);
  	}
  	const char* dir = 0;
  	while ((dir = AAssetDir_getNextFileName(di)) != NULL) {
  		if ( strcmp(strrchr(dir, '.'), ".amr") != 0 ) continue; // Read .xml files.
  		strcpy(fileName, dirPath);
  		strcat(fileName, "/");
  		strcat(fileName, dir);
  		//fprintf(stdout, "Opening...: %s\n", fileName);
  		brg[i].bulletml = new BulletMLParserTinyXML(fileName);
  		brg[i].bulletml->build(); i++;
  		//fprintf(stdout, "XML load: %s\n", fileName);
  	}
  	AAssetDir_close(di);
  	return i;
  }
  #endif
  
  static unsigned int rnd;
  
  void initBarragemanager() {
    fprintf(stdout, "initBarragemanager...");
    for ( int i=0 ; i<BARRAGE_TYPE_NUM ; i++ ) {
      barragePatternNum[i] = readBulletMLFiles(BARRAGE_DIR_NAME[i], barragePattern[i]);
      fprintf(stdout, "--------\n");
      for ( int j=0 ; j<barragePatternNum[i] ; j++ ) {
        barragePattern[i][j].type = i;
      }
    }
    fprintf(stdout, "Initialized.\n");
  }
  
  void closeBarragemanager() {
    for ( int i=0 ; i<BARRAGE_TYPE_NUM ; i++ ) {
      for ( int j=0 ; j<barragePatternNum[i] ; j++ ) {
        delete barragePattern[i][j].bulletml;
      }
    }
  }
  
  int scene;
  int endless, insane;
  static int sceneCnt;
  static float level, levelInc;
  
  void initBarrages(int seed, float startLevel, float li) {
    int n1, n2, rn;
  
    for ( int i=0 ; i<BARRAGE_TYPE_NUM ; i++ ) {
      for ( int j=0 ; j<barragePatternNum[i] ; j++ ) {
        barrageQueue[i][j] = &(barragePattern[i][j]);
      }
    }
  
    processSpeedDownBulletsNum = DEFAULT_SPEED_DOWN_BULLETS_NUM;
    if ( seed >= 0 ) {
      rnd = seed;
      endless = 0;
      insane = 0;
    } else {
      rnd = (unsigned int)SDL_GetTicks();
      endless = 1;
      if ( seed == -2 ) insane = 1;
      else insane = 0;
      if ( seed == -3 ) processSpeedDownBulletsNum = EASY_SPEED_DOWN_BULLETS_NUM;
      else if ( seed == -4 ) processSpeedDownBulletsNum = HARD_SPEED_DOWN_BULLETS_NUM;
    }
    // Shuffle.
    for ( int i=0 ; i<BARRAGE_TYPE_NUM ; i++ ) {
      int bn = barragePatternNum[i];
      rn = 60+nextRandInt(&rnd)%4;
      for ( int j=0 ; j<rn ; j++ ) {
        n1 = nextRandInt(&rnd)%bn; n2 = nextRandInt(&rnd)%bn;
        Barrage* tb = barrageQueue[i][n1];
        barrageQueue[i][n1] = barrageQueue[i][n2];
        barrageQueue[i][n2] = tb;
      }
      for ( int j=0 ; j<bn ; j++ ) {
        barrageQueue[i][j]->maxRank = (float)(nextRandInt(&rnd)%70)/100 + 0.3f;
        barrageQueue[i][j]->frq = 1;
      }
    }
  
    scene = -1;
    sceneCnt = 0;
    level = startLevel;
    levelInc = li;
  }
  
  /**
   * Roll the barrage queue after the new barrage pattern is set.
   */
  static void rollBarragePattern(Barrage *br[], int brNum) {
    Barrage *tbr;
    int n = (int)((float)brNum/((float)(nextRandInt(&rnd)%32)/32+1)+0.5f);
    if ( n == 0 ) return;
    if ( n > brNum ) n = brNum;
    tbr = br[0];
    for ( int i=0 ; i<n-1 ; i++ ) {
      br[i] = br[i+1];
    }
    br[n-1] = tbr;
    br[0]->maxRank *= 2;
    while ( br[0]->maxRank > 1 ) br[0]->maxRank -= 0.7f;
  }
  
  static int barrageNum;
  static int bossMode;
  
  static int pax;
  static int pay;
  static int quickAppType;
  
  /**
   * Make the barrage pattern of this scene.
   */
  void setBarrages(float level, int bm, int midMode) {
    int bpn = 0, bn, i;
    int barrageMax, addFrqLoop = 0;
  
    barrageNum = 0;
    barrageMax = nextRandInt(&rnd)%3+4;
    bossMode = bm;
    if ( !midMode ) {
      bpn = 0;
    } else {
      bpn = 1;
    }
    quickAppType = bpn;
    for ( bn = 0 ;  ; bn++ ) {
      if ( bn == 0 && level < 0 ) break;
      if ( bossMode ) {
        if ( bn == 0 ) bpn = 0;
        else bpn = 2;
        if ( bn >= BARRAGE_MAX ) break;
      } else {
        if ( bn >= barrageMax ) {
  	bn = 0;
  	addFrqLoop = 1;
        }
      }
      if ( addFrqLoop ) {
        barrage[bn]->frq++;
        level -= 1+barrage[bn]->rank;
        if ( level < 0 ) break;
      } else {
        barrageNum++;
        rollBarragePattern(barrageQueue[bpn], barragePatternNum[bpn]);
        barrage[bn] = barrageQueue[bpn][0];
        barrage[bn]->frq = 1;
        if ( level < barrageQueue[bpn][0]->maxRank ) {
  	if ( level < 0 ) level = 0;
  	barrage[bn]->rank = level;
  	if ( !bossMode || bn > 0 ) break;
        }
        barrage[bn]->rank = barrageQueue[bpn][0]->maxRank;
        if ( !bossMode ) {
  	level -= 1+barrageQueue[bpn][0]->maxRank;
        } else {
  	if ( bn > 0 ) level -= 4+(barrageQueue[bpn][0]->maxRank*6);
        }
  
        bpn++;
        if ( bpn >= BARRAGE_TYPE_NUM ) {
  	if ( !midMode ) {
  	  bpn = 0;
  	} else {
  	  bpn = 1;
  	}
        }
      }
    }
  
    pax = (nextRandInt(&rnd)%(SCAN_WIDTH_8*2/3) + (SCAN_WIDTH_8/6));
    pay = (nextRandInt(&rnd)%(SCAN_HEIGHT_8/6) + (SCAN_HEIGHT_8/10));
    
    scene++;
  }
  
  #define SCENE_TERM 1000
  #define SCENE_END_TERM 100
  #define ZAKO_APP_TERM 1500
  static int zakoAppCnt;
  
  static int appFreq[] = {90, 360, 800};
  static int shield[] = {3, 6, 9};
  
  static Foe *bossBullet;
  
  /**
   * Add enemies.
   */
  void addBullets() {
    int x, y, i;
    int type, frq;
  
    // Scene time control.
    sceneCnt--;
    if ( sceneCnt < 0 ) {
      if ( !insane ) clearFoes();
      if ( scene >= 0 && !endless ) setClearScore();
      if ( scene%10 == 8 ) {
        sceneCnt = 999999;
        zakoAppCnt = ZAKO_APP_TERM;
        setBarrages(level, true, false);
        addBossBullet();
      } else {
        sceneCnt = SCENE_TERM;
        if ( scene%10 == 3 ) {
  	setBarrages(level, false, true);
        } else {
  	setBarrages(level, false, false);
        }
      }
      level += levelInc;
      if ( status == IN_GAME ) {
        drawRPanel();
      } else {
        sceneCnt = 999999;
      }
    }
  
    if ( sceneCnt < SCENE_END_TERM ) return;
  
    for ( i=0 ; i<barrageNum ; i++ ) {
      if ( bossMode ) {
        if ( i > 0 ) break;
        if ( zakoAppCnt <= 0 ) break;
        zakoAppCnt--;
      }
      type = barrage[i]->type;
      // An additional enemy appears when there is no enemy of the same type.
      if ( type == quickAppType && enNum[type] == 0 ) {
        x = pax; y = pay;
        addFoe(x, y, barrage[i]->rank, 512, 0, type, shield[type], barrage[i]->bulletml);
      }
  
      frq = appFreq[type]/barrage[i]->frq;
      if ( frq < 2 ) frq = 2;
      if ( (nextRandInt(&rnd)%frq) == 0 ) {
        x = nextRandInt(&rnd)%(SCAN_WIDTH_8*2/3) + (SCAN_WIDTH_8/6);
        y = nextRandInt(&rnd)%(SCAN_HEIGHT_8/6) + (SCAN_HEIGHT_8/10);
        if ( type == quickAppType ) {
  	pax = x; pay = y;
        }
        addFoe(x, y, barrage[i]->rank, 512, 0, type, shield[type], barrage[i]->bulletml);
      }
    }
  }
  
  void bossDestroied() {
    if ( !endless ) {
      setClearScore();
      addLeftBonus();
      initStageClear();
    }
    clearFoes();
    sceneCnt = 180;
    zakoAppCnt = 0;
  }
  
  #define BOSS_SHIELD 128
  
  void addBossBullet() {
    Foe *bl;
    bossBullet = NULL;
  
    for ( int i=0 ; i<barrageNum ; i++ ) {
      if ( barrage[i]->type != 2 ) continue;
      if ( bossBullet == NULL ) {
        bl = addFoe(SCAN_WIDTH_8/2, SCAN_HEIGHT_8/5, barrage[i]->rank, 512, 0, 
  		  BOSS_TYPE, BOSS_SHIELD, barrage[i]->bulletml);
        bossBullet = bl;
      } else {
        bl = addFoeBossActiveBullet(SCAN_WIDTH_8/2, SCAN_HEIGHT_8/5, barrage[i]->rank, 512, 0, 
  				  barrage[i]->bulletml);
      }
    }
  }
  