import java.awt.*;
import java.applet.*;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.awt.image.*;

// マップ管理クラス
class MapManage extends BasicManage{
	// 画面サイズ
	static final short WIDTH = 256;
	static final short HEIGHT = 224;

	// 半分サイズ
	static final short HALF_WIDTH = WIDTH >> 1;
	static final short HALF_HEIGHT = HEIGHT >> 1;

	// 画面横幅をシフトで表す
	static final short WIDTH_SHIFT = 8;

	// チップサイズ
	static final byte CHIP_SIZE = 16;
	// チップサイズシフト用
	final byte CHIP_SIZE_SHIFT = 4;

	// マップ最大のサイズ
	final int MAX_SIZE = 256;

	// チップ最大数
	final int MAX_CHIP_NUM = 256;

	// 海の海岸線種類
	static final int SEA_NUM = 16 + 2;

	// ゲームモード
	static final int LOOK_ONLY_MODE = 1;	// 閲覧モード
	static final int EDIT_MODE = 0;	// 編集モード
	static final int GAME_MODE = 2;	// ゲームモード
	int GameMode = EDIT_MODE;
	void SetGameMode( int mode ){
		GameMode = mode;
	}
	int GetGameMode(){
		return GameMode;
	}

	// マップモード
	static final int DOWN_LAYER_MODE = 0;
	static final int UP_LAYER_MODE = 1;
	int map_window_mode = DOWN_LAYER_MODE;

	//--------------------------------------------------
	// マップモードを返す
	//--------------------------------------------------
	int GetMapWindowMode(){return map_window_mode;}

	//--------------------------------------------------
	// マップモードをセット
	//--------------------------------------------------
	void SetChipMode( int mode ){ map_window_mode = mode; }

	// ピクセル処理モード
	int PixAction = 0;
	final byte NORMAL_PIX = 0;	//通常
	final byte NIGHT_PIX = 1;	//夜
	final byte GRAY_PIX = 2;	//グレー
	final byte SEPI_PIX = 3;	//セピア
	void SetPixAction( int mode ){
		PixAction = mode;
	}

	// チップの個数
	int ChipNum;	// 下層レイヤー用
	int ChipUpNum;	// 上層レイヤー用

	// マップデータ配列(下層レイヤー)
	byte MapData[][];

	// マップデータ配列（上層レイヤー）
	byte MapUpData[][];

	// 透過色
	int AlphaColor;

	// でかマップピクセル
	int BigPixels[];

	// 上層レイヤー用 マップセル
	MapCell MapUpCell[];

	// 下層レイヤー用 マップセル（画像と通過可能か）
	MapCell MapDownCell[];

	// でかいマップ画像
	Image BigMapImage;

	// 横幅(チップ数)
	int width;

	// 縦幅
	int height;

	// チップ数×チップサイズの横幅縦幅
	int m_total_width;
	int m_total_height;

	// 作業中の左上のインデックス
	private Point now_index = new Point();
	Point GetNowIndex(){ return now_index; }

	// 選択しているパーツ
	byte selected_part = 0;

	// セーブフラグ
	int save_flag = 0;

	// デバッグ用 初期化にかかった時間
	long initTime = 0;

	// スケール
	float m_scale_per = 1.0f;
	float GetScalePer(){ return m_scale_per; }

	// インスタンス
	static MapManage m_instance;
	static MapManage GetInstance(){ return m_instance; }
	static void NewInstance( MapEdit applet ){ m_instance = new MapManage( applet ); }

	//--------------------------------------------------
	// コンストラクタ
	//--------------------------------------------------
	MapManage( MapEdit applet ){
		this.applet = applet;
	}

	MapCell GetMapCell( int x, int y ){
		return MapDownCell[ ToUnsignedByte( MapData[ x ][ y ] ) ];
	}

	//--------------------------------------------------
	// チップ数を返す
	//--------------------------------------------------
	int GetChipNum(){
		if( map_window_mode == DOWN_LAYER_MODE ){
			return ChipNum;
		}else{
			return ChipUpNum;
		}
	}

	//--------------------------------------------------
	// 選択しているパーツを返す
	//--------------------------------------------------
	byte GetSelectedPart(){
		return selected_part;
	}

	//--------------------------------------------------
	// インデックスセット（スクロールバーから操作）
	//--------------------------------------------------
	void SetIndex( int x, int y ){
		if( x >= 0 && x < width ){
			this.now_index.x = x;
		}
		if( y >= 0 && y < height ){
			this.now_index.y = y;
		}
		applet.SetCamera( CHIP_SIZE * this.now_index.x + MapManage.WIDTH/2, CHIP_SIZE * this.now_index.y + MapManage.HEIGHT/2 );
	}

	//--------------------------------------------------
	// 初期化
	//--------------------------------------------------
	void Initialize(){
		this.width = 0;
		this.height = 0;
		now_index.x = 0;
		now_index.y = 0;

		// マップデータ配列初期化
		MapData = new byte[ MAX_SIZE ][ MAX_SIZE ];
		MapUpData = new byte[ MAX_SIZE ][ MAX_SIZE ];

		MapDownCell = new MapCell[ MAX_CHIP_NUM ];
		MapUpCell = new MapCell[ MAX_CHIP_NUM ];

		// マップセル初期化
		for( int i = 0; i < MAX_CHIP_NUM; i++ ){
			MapDownCell[i] = new MapCell();
			MapUpCell[i] = new MapCell();
		}
	}

	//--------------------------------------------------
	// マップリセット
	//--------------------------------------------------
	void Reset( int width, int height ){
		int i,j;

		this.width = width;
		this.height = height;
		now_index.x = 0;
		now_index.y = 0;
		this.m_total_width = width * CHIP_SIZE;
		this.m_total_height = height * CHIP_SIZE;

		for( i = 0; i < MAX_SIZE; i++ ){
			for( j = 0; j < MAX_SIZE; j++ ){
				MapData[ i ][ j ] = 0;
				MapUpData[ i ][ j ] = 0;
			}
		}
	}

	//--------------------------------------------------
	// マップ画像読み込み
	//--------------------------------------------------
	void LoadMapImage( String file, MediaTracker mediaT ){
		// でかい画像ロード
		BigMapImage = applet.getImage( applet.getDocumentBase(), file );
		mediaT.addImage( BigMapImage, 0 );
	}

	//--------------------------------------------------
	// マップデータ読み込み
	//--------------------------------------------------
	void LoadMapData( String file ){
		DebugPrint( file );

		try{
			InputStream is = new URL( applet.getDocumentBase(), file ).openStream();
			int i, x, y;
			x = y = 0;
			DebugPrint( "load_start" );

			// 一気にロード
			byte[] buf = new byte[ this.width * this.height ];
			is.read( buf, 0, this.width * this.height );
			is.close();

			for( i = 0; i < this.width * this.height; i++ ){
				//DebugPrint( "("+x+","+y+", "+i+")" );
				MapData[ x ][ y ] = buf[i];
				if( ++x == this.width ){
					++y;
					x = 0;
					if( y == this.height ){
						break;
					}
				}
			}
		}catch( IOException e ){
			DebugPrint( "load_fail" );
		}
	}

	//--------------------------------------------------
	// マップデータ読み込み(上層レイヤー)
	//--------------------------------------------------
	void LoadMapUpData( String file ){
		DebugPrint( file );

		try{
			InputStream is = new URL( applet.getDocumentBase(), file ).openStream();
			int i, x, y;
			x = y = 0;
			DebugPrint( "load_start" );
			// 一気にロード
			byte[] buf = new byte[ this.width * this.height ];
			is.read( buf, 0, this.width * this.height );
			is.close();

			for( i = 0; i < this.width * this.height; i++ ){
				//DebugPrint( "("+x+","+y+", "+i+")" );
				MapUpData[ x ][ y ] = buf[i];
				if( ++x == this.width ){
					++y;
					x = 0;
					if( y == this.height ){
						break;
					}
				}
			}
		}catch( IOException e ){
			DebugPrint( "load_fail" );
		}
	}


	//--------------------------------------------------
	// データセーブ
	//--------------------------------------------------
	void SaveData( String mapid ){
		// CGIアクセス
		try{
			System.out.println("SaveData()");
			URL url = new URL( applet.getDocumentBase(),"check.cgi");

			//POSTコマンドのデータ部分に突っ込むデータ
			StringBuffer poststr = new StringBuffer();

			URLConnection conn = url.openConnection();

			conn.setDoOutput(true);

			PrintStream pout = new PrintStream(conn.getOutputStream());

			// 最初の１バイトはマップＮＯ
			pout.print( mapid );

			//pout.print(poststr);
			for( int i = 0; i < height; i++ ){
				for( int j = 0; j < width; j++ ){
					pout.write( MapData[j][i] );
				}
			}
			pout.close();

			//POSTコマンドを発行したので、次にその結果を読み込む。
			BufferedReader reader = new BufferedReader(
								new InputStreamReader(conn.getInputStream() ) );
			String line;
			while( (line = reader.readLine() ) != null){
				System.out.println(line);
			}
			reader.close();

			// 上層レイヤーも
			{
				url = new URL( applet.getDocumentBase(),"saveup.cgi");

				//POSTコマンドのデータ部分に突っ込むデータ
				poststr = new StringBuffer();

				conn = url.openConnection();

				conn.setDoOutput(true);

				pout = new PrintStream(conn.getOutputStream());

				// 最初の１バイトはマップＮＯ
				pout.print( mapid );

				//pout.print(poststr);
				for( int i = 0; i < height; i++ ){
					for( int j = 0; j < width; j++ ){
						pout.write( MapUpData[j][i] );
					}
				}
				pout.close();

				//POSTコマンドを発行したので、次にその結果を読み込む。
				reader = new BufferedReader(
									new InputStreamReader(conn.getInputStream() ) );

				while( (line = reader.readLine() ) != null){
					System.out.println(line);
				}
				reader.close();
			}

			// セーブフラグ
			save_flag = 1;

		}catch(Exception e){
			System.out.println("POSTの実行に失敗しました");

			// セーブフラグ
			save_flag = 2;
		}
	}

	//--------------------------------------------------
	// グラフィックスセット
	//--------------------------------------------------
	void SetGraphics( Graphics g ){
		this.g = g;
	}

	//--------------------------------------------------
	// マップバラバラ画像構築
	//--------------------------------------------------
	void MakeBaraMap(){
		int i;
		int x, y;
		int count;

		// 処理にかかる時間を計測
		long waitTime = System.currentTimeMillis();

		// でかいマップ画像を解体
		// ツクール素材互換
		BigPixels = new int[ 480 * 256 ];
		PixelGrabber pg = new PixelGrabber( BigMapImage, 0, 0, 480, 256, BigPixels, 0, 480 );
		try{
			pg.grabPixels();
		}catch( InterruptedException e ){
			System.err.println("Error");
		}


		// まず上層レイヤーから作る
		count = 0;

		for( y = 8; y < 16; y++ ){
			for( x = 18; x < 24; x++ ){
				MapUpCell[ count++ ].SetChipImage( MakeImageByBigMap( x, y ) );
			}
		}

		for( y = 0; y < 16; y++ ){
			for( x = 24; x < 30; x++ ){
				MapUpCell[ count++ ].SetChipImage( MakeImageByBigMap( x, y ) );
			}
		}

		// 透過色の指定 上層レイヤの最初のチップの色
		AlphaColor = MapUpCell[0].GetChipImage().pix[0];

		ChipUpNum = count;

		// 下層レイヤー(海などの特殊チップ)
		// 海は左上、右上、右下、左下の組み合わせで行う
		MapDownCell[0].SetChipImage( MakeSeaPart( 3, 3, 3, 3 ) );
		MapDownCell[1].SetChipImage( MakeSeaPart( 0, 2, 3, 1 ) );
		MapDownCell[2].SetChipImage( MakeSeaPart( 2, 2, 3, 3 ) );
		MapDownCell[3].SetChipImage( MakeSeaPart( 2, 0, 1, 3 ) );
		MapDownCell[4].SetChipImage( MakeSeaPart( 3, 1, 1, 3 ) );
		MapDownCell[5].SetChipImage( MakeSeaPart( 3, 1, 0, 2 ) );
		MapDownCell[6].SetChipImage( MakeSeaPart( 3, 3, 2, 2 ) );
		MapDownCell[7].SetChipImage( MakeSeaPart( 1, 3, 2, 0 ) );
		MapDownCell[8].SetChipImage( MakeSeaPart( 1, 3, 3, 1 ) );
		MapDownCell[9].SetChipImage( MakeSeaPart( 1, 1, 1, 1 ) );
		MapDownCell[0xa].SetChipImage( MakeSeaPart( 2, 2, 2, 2 ) );
		MapDownCell[0xb].SetChipImage( MakeSeaPart( 0, 2, 2, 0 ) );
		MapDownCell[0xc].SetChipImage( MakeSeaPart( 0, 0, 1, 1 ) );
		MapDownCell[0xd].SetChipImage( MakeSeaPart( 2, 0, 0, 2 ) );
		MapDownCell[0xe].SetChipImage( MakeSeaPart( 1, 1, 0, 0 ) );
		MapDownCell[0xf].SetChipImage( MakeSeaPart( 0, 0, 0, 0 ) );
		MapDownCell[0x10].SetChipImage( MakeImageByBigMap( 23, 7 ) );
		MapDownCell[0x11].SetChipImage( MakeImageByBigMap( 23, 7 ) );

		// ここから飛び飛びの値でおｋ
		// 表示リスト
		int list_x[] = {0,3,0,3,4,5,0,3,0, 3 ,6+1,9+1,6+1,9+1,6,9,6, 9 };	//18個
		int list_y[] = {0,0,4,4,4,4,8,8,12,12,0+2,0+2,4+2,4+2,8,8,12,12};
		for( i = 0; i < list_x.length; i++){
			MapDownCell[ i + SEA_NUM ].SetChipImage( MakeImageByBigMap( list_x[i], list_y[i] ) );
		}

		// ここから連続
		count = 18 + SEA_NUM;
		for( y = 0; y < 16; y++ ){
			for( x = 12; x < 18; x++ ){
				MapDownCell[ count++ ].SetChipImage( MakeImageByBigMap( x, y ) );
			}
		}
		for( y = 0; y < 8; y++ ){
			for( x = 18; x < 24; x++ ){
				MapDownCell[ count++ ].SetChipImage( MakeImageByBigMap( x, y ) );
			}
		}

		ChipNum = count;

		// 処理にかかった時間を表示
		DebugPrint("bara="+( System.currentTimeMillis() - waitTime ) );
	}

	//--------------------------------------------------
	// 対応する場所のピクセルイメージ作成
	//--------------------------------------------------
	ChipImage MakeImageByBigMap( int x, int y ){
		int[] rPixels = new int[ CHIP_SIZE * CHIP_SIZE ];
		GetPixelByBigImage( rPixels, x*CHIP_SIZE, y*CHIP_SIZE, CHIP_SIZE, CHIP_SIZE, BigPixels );
		return new ChipImage( rPixels, CHIP_SIZE, CHIP_SIZE );
	}

	//--------------------------------------------------
	// でか画像から指定のチップ採取
	// 入力、開始x,y 幅、高さ、でか画像ピクセル
	//--------------------------------------------------
	void GetPixelByBigImage( int pix[], int x, int y, int width, int height, int big_pixels[] ){
		// でかマップから採取
		int xx, yy;
		for( yy = 0; yy < width; yy++ ){
			for( xx = 0; xx < height; xx++ ){
				pix[ xx + yy * width ] = big_pixels[ ( x + xx ) + ( y + yy ) * 480 ];
			}
		}
	}

	//--------------------------------------------------
	// 海岸線付き海チップ作成
	// 左上、右上、右下、左下の組み合わせで行う
	//--------------------------------------------------
	ChipImage MakeSeaPart( int a, int b, int c, int d ){
		final int list_x[] = {0,1,1,0};//左上、右上、右下、左下のオフセット
		final int list_y[] = {0,0,1,1};
		final int plase_list[] = {0,1,2,4};
		int order_list[] = {a,b,c,d};
		int i, count = 0;
		final int CUT_SIZE = 8;
		int[][] pixels = new int[4][CUT_SIZE*CUT_SIZE];

		// 作成
		int[] total = new int[CHIP_SIZE*CHIP_SIZE];

		for( count = 0; count < 4; count++ ){
			GetPixelByBigImage( pixels[count], list_x[count]*CUT_SIZE, CHIP_SIZE*plase_list[ order_list[count] ] + list_y[count]*CUT_SIZE,
				CUT_SIZE, CUT_SIZE, BigPixels );
		}

		int start = 0;
		int offset;
		for( i = 0; i < CUT_SIZE*CUT_SIZE; i++ ){
			start = CHIP_SIZE*(i/CUT_SIZE);
			offset = i%CUT_SIZE;
			total[ offset + start] = pixels[0][i];
			start = CUT_SIZE + CHIP_SIZE*(i/CUT_SIZE);
			total[ offset + start ] = pixels[1][i];
			start = CUT_SIZE + CHIP_SIZE*(i/CUT_SIZE) + 0x80;
			total[ offset + start ] = pixels[2][i];
			start = CHIP_SIZE*(i/CUT_SIZE) + 0x80;
			total[ offset + start ] = pixels[3][i];
		}

		// チップイメージにする
		return new ChipImage( total, CHIP_SIZE, CHIP_SIZE );
	}

	//--------------------------------------------------
	// 左画面マップ描画
	//--------------------------------------------------
	void DspMap( int OffPix[] ){
		int x, y;
		int map_x, map_y;
		byte index;


		// 描画にかかる時間を計測
		long waitTime = System.currentTimeMillis();

		// 描くチップ数
		int dsp_width_num = WIDTH / CHIP_SIZE + 2;
		int dsp_height_num = HEIGHT / CHIP_SIZE + 2;

		// 描画用座標
		int dsp_map_x, dsp_map_y;

		// 左上の座標（カメラ座標から求める）
		// 負の時があるので、小数切捨てはまずい。繰り下げにする。
		// そんな計算するくらいなら１パーツ増やすの術　最後の-1
		int left_up_x = ( (applet.GetCamera().x - HALF_WIDTH) / CHIP_SIZE ) - 1;
		int left_up_y = ( (applet.GetCamera().y - HALF_HEIGHT) / CHIP_SIZE ) - 1;

		// 縮小モード
		if( Game.GetInstance().GetMapScaleState() != Game.NORMAL_SCALE_MAP ){
			// 発想の逆転 縮小サイズイメージから逆参照
			int pixel;
			int s_point;

			// X方向のスケール
			//float x_scale = m_scale_per;
			//float y_scale = m_scale_per;
			//float gen = ( m_scale_per - 1.0f ) / 300.0f;

			// 固定小数
			int x_scale_i = (int)(m_scale_per * ONE);
			int y_scale_i = (int)(m_scale_per * ONE);
			int yy;	// 先計算用

			// 空中モードの場合、遠近感を出すために縮小率を徐々に下げていく
			int gen_i = (int)( ( m_scale_per - 1.0f ) * ONE / 300.0f);

			for( y = 0; y < HEIGHT; y++ ){
				yy = y << WIDTH_SHIFT;
				for( x = 0; x < WIDTH; x++ ){
					s_point = yy + x;
					// 下層と上層を合わせて行う
					// 浮動小数ver
					//OffPix[ s_point ] = GetPixelByMap( (int)( (x-HALF_WIDTH) * x_scale) + 160, (int)( (y-HALF_HEIGHT) * y_scale ) + HALF_HEIGHT );
					// 固定小数ver
					OffPix[ s_point ] = GetPixelByMap( ChangeOne( (x-HALF_WIDTH) * x_scale_i) + HALF_WIDTH, ChangeOne( (y-HALF_HEIGHT) * y_scale_i ) + HALF_HEIGHT );
					OffPix[ s_point ] = ToNight( OffPix[ s_point ], Game.GetInstance().GetNightLevel() );
				}
				//x_scale -= gen;
				//y_scale -= gen;

				// 空のとき
				if( Game.GetInstance().GetMapScaleState() == Game.SKY_SCALE_MAP ){
					x_scale_i -= gen_i;
					y_scale_i -= gen_i;
				}
			}
			return;
		}else{
			m_scale_per = 1.0f;
		}

		// 下層レイヤー
		for( y = 0; y < dsp_height_num; y++ ){
			for( x = 0; x < dsp_width_num; x++ ){
				// 左上(起点)を加算
				map_x = left_up_x + x;
				map_y = left_up_y + y;

				// 描画用に記憶
				dsp_map_x = map_x;
				dsp_map_y = map_y;

				// ループマップ構成
				if( map_x < 0 ) map_x = width + map_x;
				if( map_y < 0 ) map_y = height + map_y;
				if( map_x >= width ) map_x = map_x - width;
				if( map_y >= height ) map_y = map_y - height;

				index = MapData[ map_x ][ map_y ];
				// ↓初期バージョンとの互換で一応
				if( ToUnsignedByte(index) < ChipNum ){
					// オフスクリーンに直接描画
					drawChipImageToMap( OffPix, MapDownCell[ ToUnsignedByte(index) ].GetChipImage(),
						ToScreenX( dsp_map_x*CHIP_SIZE ), ToScreenY( dsp_map_y*CHIP_SIZE ), WIDTH, HEIGHT );
				}
			}
		}

		// 上層レイヤー
		for( y = 0; y < dsp_height_num; y++ ){
			for( x = 0; x < dsp_width_num; x++ ){
				// 左上(起点)を加算
				map_x = left_up_x + x;
				map_y = left_up_y + y;

				// 描画用に記憶
				dsp_map_x = map_x;
				dsp_map_y = map_y;

				// ループマップ構成
				if( map_x < 0 ) map_x = width + map_x;
				if( map_y < 0 ) map_y = height + map_y;
				if( map_x >= width ) map_x = map_x - width;
				if( map_y >= height ) map_y = map_y - height;

				index = MapUpData[ map_x ][ map_y ];
				if( index != 0 && ToUnsignedByte(index) < ChipUpNum ){
					// 通過フラグ２は後で描画
					if( MapUpCell[ ToUnsignedByte(index) ].GetWalkFlag() != 2 ){
						// オフスクリーンに描画
						drawChipImageToMap( OffPix, MapUpCell[ ToUnsignedByte(index) ].GetChipImage(),
							ToScreenX( dsp_map_x*CHIP_SIZE ), ToScreenY( dsp_map_y*CHIP_SIZE ), WIDTH, HEIGHT );
					}
				}
			}
		}
	}

	//--------------------------------------------------
	// 上層レイヤの通過フラグ２専用
	//--------------------------------------------------
	void DspMapUp2( int OffPix[] ){
		int x, y;
		int map_x, map_y;
		byte index;

		// 描く数
		int dsp_width_num = WIDTH / CHIP_SIZE + 2;
		int dsp_height_num = HEIGHT / CHIP_SIZE + 2;

		// 左上の座標（カメラ座標から求める）
		// 負の時があるので、小数切捨てはまずい。繰り下げにする。
		// そんな計算するくらいなら１パーツ増やすの術　最後の-1
		int left_up_x = ( (applet.GetCamera().x - HALF_WIDTH) / 16 ) - 1;
		int left_up_y = ( (applet.GetCamera().y - HALF_HEIGHT) / 16 ) - 1;

		// 描画用座標
		int dsp_map_x, dsp_map_y;

		// 空モード
		if( Game.GetInstance().GetNowPhase() == Game.TO_SKY_PHASE ){
			// 飛行船だけ表示

			// 影の半径
			int size = (int)(CHIP_SIZE / 2 / m_scale_per);
			// カメラの位置に影表示
			//Game.GetInstance().fillRectToMemory( OffPix, HALF_WIDTH - size/2, HALF_HEIGHT - size/2, size, size, 0x80000000 );
			Game.GetInstance().fillOvalToMemory( OffPix, HALF_WIDTH, HALF_HEIGHT, size, size, 0x80000000 );

			// 乗り物描画
			// 位置は影の上で。
			Player player = PlayerManage.GetInstance().GetPlayerInstance( 10 );
			player.SetDir( PlayerManage.GetInstance().GetPlayerInstance( 0 ).GetDir() );
			int dsp_x = HALF_WIDTH - 8;
			int dsp_y = HALF_HEIGHT - 8 - (int)( ( m_scale_per - 1.0f ) * 32 );

			dsp_x += CharaManage.CENTER_OFFSET_X;
			dsp_y += CharaManage.CENTER_OFFSET_Y;

			CharaManage.GetInstance().drawChipImageToMemory( OffPix, player.GetChipImage(),
				dsp_x, dsp_y, player.GetAlphaColor(), WIDTH, HEIGHT );

		}
		// エンカウント
		else if( Game.GetInstance().GetNowPhase() == Game.ENCOUNT_PHASE ){

		}
		// 通常
		else{
			// 上層レイヤー
			for( y = 0; y < dsp_height_num; y++ ){
				for( x = 0; x < dsp_width_num; x++ ){
					// 左上(起点)を加算
					map_x = left_up_x + x;
					map_y = left_up_y + y;

					// 描画用に記憶
					dsp_map_x = map_x;
					dsp_map_y = map_y;

					// ループマップ構成
					if( map_x < 0 ) map_x = width + map_x;
					if( map_y < 0 ) map_y = height + map_y;
					if( map_x >= width ) map_x = map_x - width;
					if( map_y >= height ) map_y = map_y - height;

					index = MapUpData[ map_x ][ map_y ];
					if( index != 0 && ToUnsignedByte(index) < ChipUpNum ){
						// 通過フラグ２
						if( MapUpCell[ ToUnsignedByte(index) ].GetWalkFlag() == 2 ){
							// オフスクリーンに描画
							drawChipImageToMap( OffPix, MapUpCell[ ToUnsignedByte(index) ].GetChipImage(),
								ToScreenX( dsp_map_x*CHIP_SIZE ), ToScreenY( dsp_map_y*CHIP_SIZE ), WIDTH, HEIGHT );
						}
					}
				}
			}
		}
	}


	//--------------------------------------------------
	//  文字列専用
	//--------------------------------------------------
	void DrawString(){
		// 文字
		g.setColor( Color.black );
		g.drawString( "左上("+now_index.x+","+now_index.y+") 右下("+(now_index.x+WIDTH/CHIP_SIZE -1 )+","+(now_index.y+HEIGHT/CHIP_SIZE - 1)+") 全体サイズ("+width+","+height+")", 0, 276 );
		g.drawString("初期化時間:"+initTime+"ミリ秒", 0, 296 );

		if( save_flag == 1 ){
			g.drawString( "データセーブに成功", 200, 312 );
		}
		else if( save_flag == 2 ){
			g.drawString( "データセーブに失敗", 200, 312 );
		}
		g.drawString("選択チップ:"+ToUnsignedByte(selected_part), 0, 330 );
	}

	//--------------------------------------------------
	//  キャラ描画
	//--------------------------------------------------
	void DrawChara(){
		g.setColor( Color.black );
		// 選択チップ画像の描画（拡大）
		if( GetMapWindowMode() == DOWN_LAYER_MODE ){
			g.drawString("下層レイヤー", 40, 350 );
			g.drawImage( MapDownCell[ ToUnsignedByte( selected_part ) ].GetChipImage().GetImage(), 4, 332, 4 + CHIP_SIZE*2, 330 + CHIP_SIZE*2, 0, 0, CHIP_SIZE, CHIP_SIZE, applet );
		}else{
			g.drawString("上層レイヤー", 40, 350 );
			g.drawImage( MapUpCell[ ToUnsignedByte( selected_part ) ].GetChipImage().GetImage(), 4, 332, 4 + CHIP_SIZE*2, 330 + CHIP_SIZE*2, 0, 0, CHIP_SIZE, CHIP_SIZE, applet );
		}
	}

	//--------------------------------------------------
	//  正しいチップＩＤか
	//--------------------------------------------------
	boolean IsCorrectID( byte id, int mode ){
		if( mode == DOWN_LAYER_MODE ){
			if( ToUnsignedByte( id ) < ChipNum ) return true;
			else return false;
		}else{
			if( ToUnsignedByte( id ) < ChipUpNum ) return true;
			else return false;
		}
	}

	//--------------------------------------------------
	//  右画面チップセレクトウィンドウ描画
	//--------------------------------------------------
	void DspMapWindow( int OffPix[], int mode ){
		int x, y;
		int map_x, map_y;
		byte index;

		int i, j;
		// この個数配置して改行
		final int BR_NUM = 6;

		// 海分オフセット
		final int SEA_OFFSET = (SEA_NUM / BR_NUM) * CHIP_SIZE;

		// 下層レイヤーモード
		if( mode == DOWN_LAYER_MODE ){
			for( i = 0; i < ChipNum; i++){
				// 海の海岸線複数は出したくないので隠す
				if( i < SEA_NUM ){continue;}

				x = (i%BR_NUM) * CHIP_SIZE;
				y = (int)(i/BR_NUM) * CHIP_SIZE;

				// オフスクリーンに描画
				drawChipImage( OffPix, MapDownCell[ i ].GetChipImage(), x, y - SEA_OFFSET );
			}
		}
		// 上層レイヤー
		else{
			// 一覧
			for( i = 0; i < ChipUpNum; i++ ){
				x = (i%BR_NUM) * CHIP_SIZE;
				y = (int)(i/BR_NUM) * CHIP_SIZE;

				// オフスクリーンに描画
				drawChipImage( OffPix, MapUpCell[ i ].GetChipImage(), x, y );
			}
		}
	}

	//--------------------------------------------------
	//  選択している枠描画
	//--------------------------------------------------
	void DrawRect( int mode ){
		// この個数配置して改行
		final int BR_NUM = 6;

		// 海分オフセット
		final int SEA_OFFSET = (SEA_NUM / BR_NUM) * CHIP_SIZE;

		int x = (ToUnsignedByte(selected_part)%BR_NUM) * CHIP_SIZE;
		int y = (int)(ToUnsignedByte(selected_part)/BR_NUM) * CHIP_SIZE;

		// 下層レイヤの場合
		if( mode == DOWN_LAYER_MODE ){
			g.setColor( Color.white );
			// 海以上なら
			if( ToUnsignedByte(selected_part) >= SEA_NUM ){
				g.drawRect( x, y - SEA_OFFSET, CHIP_SIZE - 1, CHIP_SIZE - 1 );
			}
			// 海の場合なら左上を囲んでおく
			else if( ToUnsignedByte(selected_part) < SEA_NUM ){
				g.drawRect( 0, 0, CHIP_SIZE - 1, CHIP_SIZE - 1 );
			}
		}
		// 上層レイヤー
		else{
			g.setColor( Color.cyan );
			g.drawRect( x, y, CHIP_SIZE - 1, CHIP_SIZE - 1 );
		}
	}

	//--------------------------------------------------
	//  チップをオフスクリーン(メモリイメージ)に描画(マップキャンバス用)
	//  メモリイメージ配列 チップイメージ スクリーン座標 オフスクリーンの横幅 オフスクリーンの縦幅
	//--------------------------------------------------
	void drawChipImageToMap( int []off, ChipImage chip_image, int x, int y, int off_width, int off_height ){
		int xx, yy;
		int draw_p;
		int new_x, new_y;
		int s_point;	//ソースポイント

		for( yy = 0; yy < CHIP_SIZE; yy++ ){
			for( xx = 0; xx < CHIP_SIZE; xx++ ){
				// オフスクリーンに書き込む新座標
				new_x = x + xx;
				new_y = y + yy;

				// 領域外なら抜ける
				if( new_x < 0 || new_x >= off_width ) continue;
				if( new_y < 0 || new_y >= off_height ) continue;

				// オフスクリーン配列上の描き込む位置
				draw_p = new_x + new_y * off_width;

				if( draw_p < off_width * off_height ){
					// 元チップ側のピクセル座標
					s_point = xx + yy*CHIP_SIZE;

					// 透過色ならスキップ
					if( chip_image.pix[ s_point ] == AlphaColor ) continue;

					// (ゲームモード)ゲーム時間に応じて色変化
					if( applet.GetGameMode() == MapEdit.GAME_MODE ){
						// 夜
						off[ draw_p ] = ToNight( chip_image.pix[ s_point ], Game.GetInstance().GetNightLevel() );
					}
					// エディタモード
					else{
						// 通常描画
						if( PixAction == NORMAL_PIX ){
							off[ draw_p ] = chip_image.pix[ s_point ];
						}
						// 夜にしてみる
						else if( PixAction == NIGHT_PIX ){
							off[ draw_p ] = ToNight( chip_image.pix[ s_point ], 50 );
						}
						// グレー
						else if( PixAction == GRAY_PIX ){
							off[ draw_p ] = ToGray( chip_image.pix[ s_point ] );
						}
					}
				}
			}
		}
	}

	// 引数はスクリーン座標
	int GetPixelByMap( int x, int y ){
		int world_x, world_y;
		int map_x;
		int map_y;

		int pix_x, pix_y;

		// スクリーン座標からワールド座標へ
		world_x = ToWorldX( x );
		world_y = ToWorldY( y );

		// ループマップ構成
		while( world_x < 0 ) world_x += m_total_width;
		while( world_y < 0 ) world_y += m_total_height;
		while( world_x >= m_total_width ) world_x -= m_total_width;
		while( world_y >= m_total_height ) world_y -= m_total_height;

		// マップ座標へ変換
		map_x = world_x >> CHIP_SIZE_SHIFT;
		map_y = world_y >> CHIP_SIZE_SHIFT;

		// 位置
		pix_x = world_x - ( map_x << CHIP_SIZE_SHIFT );
		pix_y = world_y - ( map_y << CHIP_SIZE_SHIFT );

		// そのマップのピクセルゲット

		// ピクセル配列上の位置
		int pix_point = (pix_y<<CHIP_SIZE_SHIFT) + pix_x;

		// 上層
		int pixel_up = MapUpCell[ ToUnsignedByte( MapUpData[ map_x ][ map_y ] ) ].GetChipImage().pix[ pix_point ];

		// 上層が透明色なら下層を返す
		if( pixel_up == AlphaColor ){
			//下層
			return MapDownCell[ ToUnsignedByte( MapData[ map_x ][ map_y ] ) ].GetChipImage().pix[ pix_point ];
		}else{
			return pixel_up;
		}
	}

	// 夜
	int ToNight( int pix, int value ){
		// RとGを減算
		int r = ( pix >> 16 ) & 0xff;
		int g = ( pix >> 8 ) & 0xff;
		int b = pix & 0xff;
		r -= value;
		if( r <= 0 ){ r = 0; }
		g -= value;
		if( g <= 0 ){ g = 0; }
		return b | (g<<8) | (r<<16) | (0xff000000);
	}

	// グレー
	int ToGray( int pix ){
		int r = ( pix >> 16 ) & 0xff;
		int g = ( pix >> 8 ) & 0xff;
		int b = pix & 0xff;
		// ３色の重み付き平均をとってみる
		int av = (int)(0.298912 * r + 0.586611 * g + 0.114478 * b);
		return av | (av<<8) | (av<<16) | (0xff000000);
	}

	//--------------------------------------------------
	//  チップをオフスクリーンに描画(セレクトキャンバス用)
	//--------------------------------------------------
	void drawChipImage( int []off, ChipImage chip_image, int x, int y ){
		int xx, yy;
		for( yy = 0; yy < CHIP_SIZE; yy++ ){
			for( xx = 0; xx < CHIP_SIZE; xx++ ){
				if( x + xx + (yy+y)*SelectChipCanvas.WIDTH < SelectChipCanvas.WIDTH * SelectChipCanvas.HEIGHT ){
					off[ x + xx + y * SelectChipCanvas.WIDTH + yy*SelectChipCanvas.WIDTH ] = chip_image.pix[ xx + yy*CHIP_SIZE ];
				}
			}
		}
	}

	//--------------------------------------------------
	//  符号付バイトを符号無バイトへ
	//--------------------------------------------------
	int ToUnsignedByte( byte b ){
		if( b < 0 ){
			return 256 + b;
		}else{
			return b;
		}
	}

	//--------------------------------------------------
	//  選択チップIDセット
	//--------------------------------------------------
	void SetSelectedID( byte id ){
		this.selected_part = id;
	}

	//--------------------------------------------------
	//  マップにチップセット
	//--------------------------------------------------
	void SetChip( int x, int y ){
		// 左上(起点)を加算
		int map_x = now_index.x + x;
		int map_y = now_index.y + y;

		if( map_x >= 0 && map_x < width && map_y >= 0 && map_y < height ){}
		else return;

		// 下層レイヤーの場合
		if( this.map_window_mode == DOWN_LAYER_MODE ){
			this.MapData[ map_x ][ map_y ] = selected_part;
			// 海岸線処理
			PutCoastline( map_x, map_y );

			// 上下左右チェック
			PutCoastline( map_x, map_y - 1 );
			PutCoastline( map_x, map_y + 1 );
			PutCoastline( map_x - 1, map_y );
			PutCoastline( map_x + 1, map_y );
		}else{
			this.MapUpData[ map_x ][ map_y ] = selected_part;
		}
	}

	//--------------------------------------------------
	//  自動海岸線補完
	//--------------------------------------------------
	void PutCoastline( int x, int y ){
		// 領域外
		if( x < 0 || y < 0 || x >= width || y >= height ){ return; }

		// 海岸線を付けないID(これ未満)
		final int NOT_COAST = 24;

		// 海のID（これ未満）

		// 海じゃない場合
		if( ToUnsignedByte( MapData[ x ][ y ] ) >= SEA_NUM ){
			return;
		}


		final int UP = 0x1;
		final int DOWN = 0x2;
		final int LEFT = 0x4;
		final int RIGHT = 0x8;

		int flag = 0;

		// 上は海じゃない？
		if( y >= 1 ){
			if( ToUnsignedByte( MapData[ x ][ y-1 ] ) >= NOT_COAST ){
				flag |= UP;
			}
		}
		// 下は海じゃない？
		if( y < height-1 ){
			if( ToUnsignedByte( MapData[ x ][ y+1 ] ) >= NOT_COAST ){
				flag |= DOWN;
			}
		}
		// 左は海じゃない？
		if( x >= 1 ){
			if( ToUnsignedByte( MapData[ x-1 ][ y ] ) >= NOT_COAST ){
				flag |= LEFT;
			}
		}
		// 右は海じゃない？
		if( x < width-1 ){
			if( ToUnsignedByte( MapData[ x+1 ][ y ] ) >= NOT_COAST ){
				flag |= RIGHT;
			}
		}

		byte chip = 0;

		switch( flag ){
		// 何もない
		case 0x00: chip = 0; break;
		// 左上
		case LEFT|UP: chip = 0x01; break;
		// 上
		case UP: chip = 0x02; break;
		// 右上
		case RIGHT|UP: chip = 0x03; break;
		// 右
		case RIGHT: chip = 0x04; break;
		// 右下
		case RIGHT|DOWN: chip = 0x05; break;
		// 下
		case DOWN: chip = 0x06; break;
		// 左下
		case LEFT|DOWN: chip = 0x07; break;
		// 左
		case LEFT: chip = 0x08; break;
		// 左右
		case LEFT|RIGHT: chip = 0x09; break;
		// 上下
		case UP|DOWN: chip = 0x0a; break;
		// 左上下
		case LEFT|UP|DOWN: chip = 0x0b; break;
		// 上左右
		case UP|LEFT|RIGHT: chip = 0x0c; break;
		// 上下右
		case UP|DOWN|RIGHT: chip = 0x0d; break;
		// 下左右
		case DOWN|LEFT|RIGHT: chip = 0x0e; break;
		// 上下左右
		case UP|DOWN|LEFT|RIGHT: chip = 0x0f; break;
		}

		MapData[ x ][ y ] = chip;

	}

	//--------------------------------------------------
	// 通過リスト読み込み 引数：ファイル名、下層=0 or 上層=1
	//--------------------------------------------------
	void LoadCanWalkList( String file, int mode ){
		DebugPrint( file );

		try{
			InputStream is = new URL( applet.getDocumentBase(), file ).openStream();

			// テキストだからリーダーを使う
			BufferedReader br = new BufferedReader( new InputStreamReader( is ) );

			// ライン格納
			String line;

			int i, j;
			DebugPrint( "walk_load_start" );

			// 一行ずつ読み込む
			int line_num = 0;

			if( mode == DOWN_LAYER_MODE ){
				// 海は通行不可
				for( i = 0; i < 0x12; i++ ){
					MapDownCell[ i ].SetWalkFlag( 0 );
				}
				i = 0x12;
			}else{
				i = 0;
			}
			while( ( line = br.readLine() ) != null ){
				for( j = 0; j < line.length(); j++ ){
					int value = 0;
					int element = 0;
					if( line.charAt( j ) == '1' ){
						value = 1;
					}else if( line.charAt( j ) == '2' ){
						value = 2;
					}
					// 3はとりあえず通れない設定
					else if( line.charAt( j ) == '3' ){
						value = 0;
					}
					// カウンター属性
					else if( line.charAt( j ) == 'c' ){
						element = 1;
					}
					if( mode == DOWN_LAYER_MODE ){
						MapDownCell[ i ].SetWalkFlag( value );
						MapDownCell[ i ].SetElement( element );
					}else{
						MapUpCell[ i ].SetWalkFlag( value );
						MapUpCell[ i ].SetElement( element );
					}
					i++;
				}
			}

			MapDownCell[ 33 ].SetElement( 1 );

			is.close();
		}catch( IOException e ){
			DebugPrint( "load_fail" );
		}
	}

}
