import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;

//--------------------------------------------------
// ゲームクラス
//--------------------------------------------------
class Game{
	//--------------------------------------------------
	// 定数
	//--------------------------------------------------
	// フォントサイズ
	final int FONT_SIZE = 14;

	final int LENGTH = 4;	//最大4マス

	// メインフェイズフラグ
	static final int NORMAL_PHASE = 0;			//何もない(選択カーソル動く)
	static final int CHARA_SELECT_PHASE = 1;	//キャラ選択(メニュー描画)
	static final int MOVE_SELECT_PHASE = 2;	//移動範囲選択(移動範囲描画)
	static final int MOVE_PHASE = 3;	//移動状態
	static final int TALK_SELECT_PHASE = 4;	// 話し相手選択フェイズ
	static final int TALK_PHASE = 5;	// 会話フェイズ
	static final int CHANGE_MAP_PHASE = 6;	// マップ切り替え
	static final int ENCOUNT_PHASE = 7;	// エンカウント
	static final int TO_SKY_PHASE = 8;	// 空へ羽ばたく
	static final int BATTLE_PHASE = 9;	// バトル

	//--------------------------------------------------
	// 管理クラス
	//--------------------------------------------------
	// 以下、受け継いだもの

	// グラフィックス
	Graphics g;

	// 親アプレット
	MapEdit applet;

	// 現在のフェイズ
	int now_phase;
	int GetNowPhase(){ return this.now_phase; }

	// 選択したキャラ(メイン)
	Chara m_selected_chara;

	// 選択したキャラの移動先
	int moved_x;
	int moved_y;

	// 選択座標
	int select_x, select_y;

	// 選択メニュー
	int selected_menu_no;

	// メニュー選択用マウス移動距離(Y座標の上下)
	int menu_move_length;

	// サブフェイズ
	int SubPhase = 0;

	// 次のマップID
	String m_next_map_id;

	// 主人公移動先
	int m_next_x, m_next_y;

	// 移動可能マップ（可能なら０）
	byte LightMapData[][];

	// 最短経路記憶
	String mvrec[][];

	// 移動処理フェイズ
	int MovePhase = 0;
	int goflag = 0;
	int golast = 0;

	// フェードアルファ
	int FadeAlpha;

	// 空を飛ぶ時用
	int SkyPhase = 0;

	// マップ縮小状態
	private int m_map_scale_sate;
	static final int NORMAL_SCALE_MAP = 0;	// 通常
	static final int SKY_SCALE_MAP = 1;		// 空
	static final int ENCOUNT_MAP = 2;			// エンカウント
	int GetMapScaleState(){ return m_map_scale_sate; }

	// キー列挙
	final int KEY_UP = 1;
	final int KEY_RIGHT = 2;
	final int KEY_DOWN = 4;
	final int KEY_LEFT = 8;
	final int KEY_ENTER = 0x10;
	final int KEY_TEST = 0x100;	// テスト用

	// キー状態
	int KeyState;

	// 前回のキー状態
	int PrevKeyState;

	// ゲーム内での時間
	private int m_game_hour;
	private int m_game_minute;
	private int m_night_level;	// 夜の明暗の度合い
	int GetGameHour(){return m_game_hour;}
	int GetNightLevel(){ return m_night_level; }

	// インスタンス
	static Game m_instance;
	static Game GetInstance(){return m_instance;}
	static void NewInstance( MapEdit applet ){ m_instance = new Game( applet ); }

	Game( MapEdit applet ){
		this.applet = applet;
	}

	//--------------------------------------------------
	// デバッグプリント
	//--------------------------------------------------
	void DebugPrint( String str ){
		System.out.println( str );
	}

	//--------------------------------------------------
	// グラフィックスセット
	//--------------------------------------------------
	void SetGraphics( Graphics g ){
		this.g = g;

		TalkManage.GetInstance().SetGraphics( g );
	}

	// 初期化
	void Initialize(){
		now_phase = NORMAL_PHASE;
		KeyState = 0;
		PrevKeyState = 0;
		FadeAlpha = 0x00;

		// ９時開始
		m_game_hour = 9;
		m_game_minute = 0;
		m_night_level = 0;
	}

	// 基本処理
	void BasicAction(){
		switch( now_phase ){
		case NORMAL_PHASE:break;
		case CHARA_SELECT_PHASE:
			break;
		case MOVE_SELECT_PHASE:
			break;
		case MOVE_PHASE:
			// 指定のキャラを動かしてみる
			MoveChara();
			break;
		case TALK_PHASE:
			// 会話処理
			TalkManage.GetInstance().TalkAction();
			break;
		// マップ切り替え
		case CHANGE_MAP_PHASE:
			ChangeMapAction();
			break;
		// エンカウント
		case ENCOUNT_PHASE:
			EnCountAction();
			break;
		// 空へ
		case TO_SKY_PHASE:
			ToSky();
			break;
		// バトルフェイズ
		case BATTLE_PHASE:
			BattleManage.GetInstance().BattleAction();
			break;
		}

		// ゲーム時間を進める
		ProcessGameTime();
	}

	void ProcessGameTime(){
		m_game_minute += 1;
		if( m_game_minute >= 60 ){
			m_game_hour++;
			m_game_minute = 0;
			if( m_game_hour >= 24 ){
				m_game_hour = 0;
			}
		}

		// 夜加算 3分に１回 つまり４時間かけて最大値に
		if( m_game_hour >= 17 && m_game_minute % 3 == 2 ){
			m_night_level++;
			if( m_night_level > 80 ) m_night_level = 80;
		}
		// 夜減算
		else if( m_game_hour >= 5 && m_game_minute % 3 == 2 ){
			m_night_level--;
			if( m_night_level < 0 ) m_night_level = 0;
		}
	}

	// クリック処理
	void ClickAction( int x, int y ){
		boolean ret;

		// 左クリックで移動、右クリックで決定
		// 画面中心からの距離
		int length_x = BasicManage.MyAbs( MapManage.WIDTH / 2 - x );
		int length_y = BasicManage.MyAbs( MapManage.HEIGHT / 2 - y );

		// 画面の中央より左で、Xのほうが長いなら、左キーと同等
		// ただしORはしない。マウスドラッグしながら方向を変えれるようにするため。
		if( x < MapManage.WIDTH/2 && length_x > length_y ){
			KeyState = KEY_LEFT;
		}
		else if( x > MapManage.WIDTH/2 && length_x > length_y ){
			KeyState = KEY_RIGHT;
		}
		else if( y < MapManage.HEIGHT/2 && length_y > length_x ){
			KeyState = KEY_UP;
		}
		else{
			KeyState = KEY_DOWN;
		}

		// ここからシミュレーションRPGタイプ　一旦没
/*
		switch( now_phase ){
		case NORMAL_PHASE:
			// その場所にいるキャラ検索
			SearchChara( x, y );
			break;
		// キャラ選択状態
		case CHARA_SELECT_PHASE:
			// 移動を選んだ場合
			if( selected_menu_no == 0 ){
				now_phase = MOVE_SELECT_PHASE;
			}
			// 話すを選んだ場合
			else if( selected_menu_no == 1 ){
				now_phase = TALK_SELECT_PHASE;
			}
			break;
		case MOVE_SELECT_PHASE:
			// 移動先を指定
			ret = SetMovePoint( x, y );
			if( ret ){
				now_phase = MOVE_PHASE;
			}
			break;
		case TALK_SELECT_PHASE:
			//DebugPrint("話キャラ選択");
			// 話し相手を指定
			Chara chara = SetTalkPoint( x, y );
			// キャラいた？
			if( chara != null ){
				//DebugPrint("話キャラ発見");

				// そのキャラをこっちに向かせる（主人公と逆向き）
				int dir = 0;
				if( m_selected_chara.GetDir() == 0 ) dir = 2;
				else if( m_selected_chara.GetDir() == 1 ) dir = 3;
				else if( m_selected_chara.GetDir() == 2 ) dir = 0;
				else if( m_selected_chara.GetDir() == 3 ) dir = 1;
				chara.SetDir( dir );

				// トークフェイズへ
				TalkManage.GetInstance().SetTargetChara( chara );
				TalkManage.GetInstance().Initialize();
				now_phase = TALK_PHASE;
			}else{
				now_phase = NORMAL_PHASE;
			}
			break;
		// 会話中
		case TALK_PHASE:
			// 会話が終了するまでは受け付けない
			if( TalkManage.GetInstance().IsExitTalk() ){
				// スクリプトの続きを読む
				if( TalkManage.GetInstance().NextCommand.equals("#nextpage") ){
					//DebugPrint("続き読む");
					TalkManage.GetInstance().AnalyzeScript();
				}else{
					//DebugPrint("最初へ");
					// 最初へ
					now_phase = NORMAL_PHASE;
				}
			}
			break;
		}
*/
	}

	// マウスリリース処理
	void MouseReleaseAction( int x, int y ){
		KeyState = 0;
	}

	// マップ切り替え処理
	void ChangeMapAction(){
		int ret;

		switch( SubPhase ){
		// 初期化
		case 0:
			// フェードアウト開始
			FadeAlpha = 0x00;
			SubPhase++;
			// そのまま次へ
		case 1:
			FadeOutAction();

			// アルファがFFになったらマップ切り替え
			if( FadeAlpha == 0xFF ){
				applet.ChangeMap( m_next_map_id );

				// 主人公ワープ
				PlayerManage.GetInstance().SetPlayerLocation( m_next_x, m_next_y );

				// カメラ調整
				SetCameraPosition();

				SubPhase++;
			}
			break;
		case 2:
			// フェードイン開始
			FadeInAction();
			// 終了
			if( FadeAlpha == 0 ){
				SubPhase++;
				now_phase = NORMAL_PHASE;
			}
			break;
		}
	}

	void MoveSelectPhase(){
		switch( SubPhase ){
		case 0:
			MoveSelectInit();
			SubPhase = 1;
			break;
		case 1:
			break;
		}
	}

	// キーを押した場合
	void KeyPressed( KeyEvent e ){
		int key;

		key = e.getKeyCode();

		switch( key ){
		// 上
		case KeyEvent.VK_UP:
			KeyState |= KEY_UP;
			break;
		// 右
		case KeyEvent.VK_RIGHT:
			KeyState |= KEY_RIGHT;
			break;
		// 下
		case KeyEvent.VK_DOWN:
			KeyState |= KEY_DOWN;
			break;
		// 左
		case KeyEvent.VK_LEFT:
			KeyState |= KEY_LEFT;
			break;
		// 決定
		case KeyEvent.VK_SPACE:case KeyEvent.VK_ENTER:case 0xe5:case KeyEvent.VK_Z:
			KeyState |= KEY_ENTER;
			break;
		// テスト
		case KeyEvent.VK_T:
			KeyState |= KEY_TEST;
			break;
		}
	}

	// キーを離した時
	void KeyReleased( KeyEvent e ){
		int key;

		key = e.getKeyCode();

		switch( key ){
		// 上
		case KeyEvent.VK_UP:
			KeyState &= ~KEY_UP;
			break;
		// 右
		case KeyEvent.VK_RIGHT:
			KeyState &= ~KEY_RIGHT;
			break;
		// 下
		case KeyEvent.VK_DOWN:
			KeyState &= ~KEY_DOWN;
			break;
		// 左
		case KeyEvent.VK_LEFT:
			KeyState &= ~KEY_LEFT;
			break;
		// 決定
		case KeyEvent.VK_SPACE:case KeyEvent.VK_ENTER:case 0xe5:case KeyEvent.VK_Z:
			KeyState &= ~KEY_ENTER;
			break;
		// テスト
		case KeyEvent.VK_T:
			KeyState &= ~KEY_TEST;
			break;
		}
	}

	// その方向に障害物があるかチェック(マップとキャラ)
	boolean IsCanWalkByDir( int px, int py, int dir ){
		boolean walk_flag;

		// 縮小マップ（飛行船モードならＯＫ）
		if( this.now_phase == TO_SKY_PHASE ){
			return true;
		}

		// 座標変換
		int x = px / MapManage.CHIP_SIZE;
		int y = py / MapManage.CHIP_SIZE;

		// 上
		if( dir == BasicManage.DIR_UP ){
			y--;
		}
		// 右
		else if( dir == BasicManage.DIR_RIGHT ){
			x++;
		}
		// 下
		else if( dir == BasicManage.DIR_DOWN ){
			y++;
		}
		// 左
		else if( dir == BasicManage.DIR_LEFT ){
			x--;
		}

		// ループマップじゃなくて領域外なら無理
		if( !applet.IsLoopMap() ){
			if( x < 0 || y < 0 || x >= MapManage.GetInstance().width || y >= MapManage.GetInstance().height ) return false;
		}
		// ループマップの場合
		else{
			// 領域外ならループさせる
			if( x < 0 ) x = MapManage.GetInstance().width + x;
			if( y < 0 ) y = MapManage.GetInstance().height + y;
			if( x >= MapManage.GetInstance().width ) x = x - MapManage.GetInstance().width;
			if( y >= MapManage.GetInstance().height ) y = y - MapManage.GetInstance().height;
		}

		// そこに通過フラグのないキャラがいたら無理
		Chara chara = CharaManage.GetInstance().SearchChara( x, y );
		if( chara != null && !chara.GetMoveFlag() ){
			walk_flag = false;
		}
		// 上層レイヤーが通行可能なら、下層レイヤーが通行不可能でも通れる（橋など対策）
		else if( MapManage.GetInstance().ToUnsignedByte( MapManage.GetInstance().MapUpData[ x ][ y ] ) > 0 &&
		MapManage.GetInstance().MapUpCell[ MapManage.GetInstance().ToUnsignedByte( MapManage.GetInstance().MapUpData[ x ][ y ] ) ].GetWalkFlag() >= 1 ){
			walk_flag = true;
		}
		// 上層レイヤーが通行不可能なら確実に通れない
		else if( MapManage.GetInstance().MapUpCell[ MapManage.GetInstance().ToUnsignedByte( MapManage.GetInstance().MapUpData[ x ][ y ] ) ].GetWalkFlag() == 0 ){
			walk_flag = false;
		}
		// 下層レイヤーが通行不可能
		else if( MapManage.GetInstance().MapDownCell[ MapManage.GetInstance().ToUnsignedByte( MapManage.GetInstance().MapData[ x ][ y ] ) ].GetWalkFlag() == 0 ){
			walk_flag = false;
		}
		else walk_flag = true;

		return walk_flag;
	}

	void BasicKeyAction(){
		switch( now_phase ){
		case NORMAL_PHASE:
		case TO_SKY_PHASE:
			NormalKeyAction();
			break;
		// 会話中
		case TALK_PHASE:
			// 決定を押した瞬間
			if( ( ~PrevKeyState & KeyState & KEY_ENTER ) != 0 ){
				// 会話が終了するまでは受け付けない
				if( TalkManage.GetInstance().IsExitTalk() ){
					// スクリプトの続きを読む
					if( TalkManage.GetInstance().NextCommand.equals("#nextpage") ){
						//DebugPrint("続き読む");
						TalkManage.GetInstance().AnalyzeScript();
					}else{
						//DebugPrint("最初へ");
						// 最初へ
						now_phase = NORMAL_PHASE;
					}
				}
			}
			break;
		}

		// 前回のキー格納
		PrevKeyState = KeyState;
	}

	// 待機中キーボード処理
	void NormalKeyAction(){
		int i;

		// 主人公取得
		Player player = PlayerManage.GetInstance().GetPlayerInstance( 0 );

		// 歩いていない時
		if( !player.WalkingFlag ){
			// プレイヤーの移動開始
			if( (KeyState & KEY_UP) != 0 ){
				player.SetDir( BasicManage.DIR_UP );
				// その方向に障害物があるかチェック(マップとキャラ)
				player.WalkingFlag = IsCanWalkByDir( player.px, player.py, BasicManage.DIR_UP );
			}
			if( (KeyState & KEY_RIGHT) != 0 ){
				player.SetDir( BasicManage.DIR_RIGHT );
				player.WalkingFlag = IsCanWalkByDir( player.px, player.py, BasicManage.DIR_RIGHT );
			}
			if( (KeyState & KEY_DOWN) != 0 ){
				player.SetDir( BasicManage.DIR_DOWN );
				player.WalkingFlag = IsCanWalkByDir( player.px, player.py, BasicManage.DIR_DOWN );
			}
			if( (KeyState & KEY_LEFT) != 0 ){
				player.SetDir( BasicManage.DIR_LEFT );
				player.WalkingFlag = IsCanWalkByDir( player.px, player.py, BasicManage.DIR_LEFT );
			}

			// 決定キー（話/調べる）
			if( ( ~PrevKeyState & KeyState & KEY_ENTER ) != 0 ){
				// 向いてる方向をチェック
				Chara chara = SetTalkPointForKey( player.px, player.py, player.dir );

				// キャラいた？
				if( chara != null ){
					//DebugPrint("話キャラ発見");

					// そのキャラをこっちに向かせる（主人公と逆向き）
					int dir = 0;
					if( player.GetDir() == 0 ) dir = 2;
					else if( player.GetDir() == 1 ) dir = 3;
					else if( player.GetDir() == 2 ) dir = 0;
					else if( player.GetDir() == 3 ) dir = 1;
					chara.SetDir( dir );

					// トークフェイズへ
					TalkManage.GetInstance().SetTargetChara( chara );
					TalkManage.GetInstance().Initialize();
					now_phase = TALK_PHASE;
				}
			}

			// テストキー
			if( ( KeyState & KEY_TEST ) != 0 ){

			}
		}

		// 歩いている時
		if( player.WalkingFlag ){
			boolean walk_stop;	// 移動完了フラグ

			walk_stop = player.WalkAction();
			// 領域外チェック
			player.AreaOutCheck( applet.IsLoopMap(), MapManage.GetInstance().width * MapManage.CHIP_SIZE, MapManage.GetInstance().height * MapManage.CHIP_SIZE );
			boolean my_walk_flag = player.WalkingFlag;

			// イベントチェック
			if( walk_stop ){
				// そこに主人公と接触イベントはあるのかい？
				Chara chara = CharaManage.GetInstance().SearchChara( player.px / MapManage.CHIP_SIZE, player.py / MapManage.CHIP_SIZE, 1 );
				if( chara != null ){
					// トークフェイズへ
					TalkManage.GetInstance().SetTargetChara( chara );
					TalkManage.GetInstance().Initialize();
					now_phase = TALK_PHASE;
					DebugPrint("イベント開始");
				}
			}

			// 軌跡を残す
			player.PutHistory();

			// 仲間は主人公の軌跡を辿る
			Player prev_player;
			int frame = MapManage.CHIP_SIZE / player.GetMoveSpeed();
			for( i = 1; i < PlayerManage.PLAYER_MAX; i++ ){
				prev_player = PlayerManage.GetInstance().GetPlayerInstance( i-1 );
				player = PlayerManage.GetInstance().GetPlayerInstance( i );

				// 前の人のchip/speed=4フレーム前の座標にセット
				player.px = prev_player.GetPxHistory( frame );
				player.py = prev_player.GetPyHistory( frame );
				player.dir = prev_player.GetDirHistory( frame );

				player.WalkingFlag = my_walk_flag;
				player.PutHistory();
			}
		}

		// カメラ調整
		SetCameraPosition();
	}

	// カメラ座標を主人公プレイヤーと同じにする。
	void SetCameraPosition(){
		Player player = PlayerManage.GetInstance().GetPlayerInstance( 0 );
		int px = player.px + MapManage.GetInstance().CHIP_SIZE / 2;
		int py = player.py + MapManage.GetInstance().CHIP_SIZE / 2;

		// 端対策をきっちり(ループマップではない時)
		if( !applet.IsLoopMap() ){
			if( px < MapManage.WIDTH / 2 ){ px = MapManage.WIDTH / 2; }
			else if( px > MapManage.GetInstance().width * MapManage.GetInstance().CHIP_SIZE - MapManage.WIDTH / 2 ){
				px = MapManage.GetInstance().width * MapManage.GetInstance().CHIP_SIZE - MapManage.WIDTH / 2;
			}

			if( py < MapManage.HEIGHT / 2 ){ py = MapManage.HEIGHT / 2; }
			else if( py > MapManage.GetInstance().height * MapManage.GetInstance().CHIP_SIZE - MapManage.HEIGHT / 2 ){
				py = MapManage.GetInstance().height * MapManage.GetInstance().CHIP_SIZE - MapManage.HEIGHT / 2;
			}
		}

		applet.SetCamera( px, py );
	}


	// 移動範囲初期化
	void MoveSelectInit(){
		int i, j;

		//DebugPrint("移動範囲初期化");

		// マップ情報の初期化
		LightMapData = new byte[ MapManage.GetInstance().width ][ MapManage.GetInstance().height ];
		mvrec = new String[ MapManage.GetInstance().width ][ MapManage.GetInstance().height ];

		for( i = 0; i < MapManage.GetInstance().width; i++ ){
			for( j = 0; j < MapManage.GetInstance().height; j++ ){
				LightMapData[i][j] = 1;
				mvrec[i][j] = new String("");
			}
		}

		// 座標系に
		int chara_x = m_selected_chara.px / MapManage.CHIP_SIZE;
		int chara_y = m_selected_chara.py / MapManage.CHIP_SIZE;

		// 四方向にアンカーを伸ばす
		Search( chara_x, chara_y - 1, LENGTH, 1, "1" );
		Search( chara_x + 1, chara_y, LENGTH, 2, "2" );
		Search( chara_x, chara_y + 1, LENGTH, 3, "3" );
		Search( chara_x - 1, chara_y, LENGTH, 4, "4" );

		// 今の場所は行けない
		LightMapData[ chara_x ][ chara_y ] = 1;

	}


	// 移動処理
	void MoveChara(){
		if( m_selected_chara != null ){
			// 目的値に向かって進め

			// 座標系に
			int point_x = moved_x / 16;
			int point_y = moved_y / 16;

			// 初期化
			switch( MovePhase ){
			case 0:
				if( LightMapData[ point_x ][ point_y ] == 0 ){
					// 到着してない
					if( !(m_selected_chara.px == moved_x && m_selected_chara.py == moved_y) ){
						// いけ
						golast = mvrec[ point_x ][ point_y ].length();
						//DebugPrint("str="+mvrec[ point_x ][ point_y ]+"golast="+golast);
						MovePhase++;

						// 移動開始
						m_selected_chara.WalkingFlag = true;

					}
				}else{
					now_phase = NORMAL_PHASE;
				}
				break;
			case 1:
				String sr = mvrec[ point_x ][ point_y ];
				final int CHARA_SPEED = 4;

				// 指定の距離の文字（方角が格納）を取り出す
				if( sr.charAt( goflag ) == '1' ){
					m_selected_chara.py -= CHARA_SPEED;
					m_selected_chara.SetDir( CharaManage.DIR_UP );
				}
				if( sr.charAt( goflag ) == '2' ){
					m_selected_chara.px += CHARA_SPEED;
					m_selected_chara.SetDir( CharaManage.DIR_RIGHT );
				}
				if( sr.charAt( goflag ) == '3' ){
					m_selected_chara.py += CHARA_SPEED;
					m_selected_chara.SetDir( CharaManage.DIR_DOWN );
				}
				if( sr.charAt( goflag ) == '4' ){
					m_selected_chara.px -= CHARA_SPEED;
					m_selected_chara.SetDir( CharaManage.DIR_LEFT );
				}
				m_selected_chara.WaitTimer += CHARA_SPEED;
				if( m_selected_chara.WaitTimer >= 16 ){
					m_selected_chara.WaitTimer = 0;
					goflag++;
				}
				// ゴール
				if( goflag >= golast ){
					//DebugPrint( "ゴール" );
					goflag = 0;
					now_phase = NORMAL_PHASE;
					MovePhase = 0;
					m_selected_chara.WalkingFlag = false;

					// そこに主人公と接触イベントはあるのかい？
					Chara chara = CharaManage.GetInstance().SearchChara( point_x, point_y, 1 );
					if( chara != null ){
						// トークフェイズへ
						TalkManage.GetInstance().SetTargetChara( chara );
						TalkManage.GetInstance().Initialize();
						now_phase = TALK_PHASE;

						DebugPrint("おい");
					}
				}
				break;
			}
		}
	}

	// 基本描画
	void BasicDraw(){
		switch( now_phase ){
		case NORMAL_PHASE:
			// 枠
			//DrawSelectRect();
			break;
		case CHARA_SELECT_PHASE:
			// メニュー表示
			DrawMenu();

			break;
		case MOVE_SELECT_PHASE:
			// 移動できる範囲表示
			DrawCanMoveArea();
			break;
		case MOVE_PHASE:
			break;
		// 話し相手選択フェイズ
		case TALK_SELECT_PHASE:
			TalkManage.GetInstance().DrawCanTalkArea( m_selected_chara.px, m_selected_chara.py );
			break;
		// 会話中フェイズ
		case TALK_PHASE:
			TalkManage.GetInstance().DrawTalkWindow();
			break;
		}

		// デバッグ情報
		DrawDebugInfo();
	}

	// デバッグ情報ウィンドウ
	void DrawDebugInfoWindow(){
		// バージョン情報
		fillRectToMemory( MapCanvas.GetInstance().GetOffPix(), 0 , MapManage.HEIGHT - FONT_SIZE, FONT_SIZE*9, FONT_SIZE, 0xFF000080 );
	}
	// デバッグ情報
	void DrawDebugInfo(){
		Player player = PlayerManage.GetInstance().GetPlayerInstance( 0 );

		// バージョン情報
		g.setColor( Color.white );
		//g.drawString( "("+player.px+","+player.py+")", 0, 240 - 2 );
		g.drawString( "ver:13.1 F:"+(MapCanvas.FrameTime/10)+(MapCanvas.FrameTime%10)+ " "+(m_game_hour/10)+(m_game_hour%10) + "時"+(m_game_minute/10)+(m_game_minute%10)+"分", 0, MapManage.HEIGHT - 2 );
		// ゲーム内時刻

	}

	// ピクセル操作用
	void BasicDrawForPixel( int OffPix[] ){
		switch( now_phase ){
		case CHARA_SELECT_PHASE:
			// メニューウィンドウ
			DrawMenuWindow( OffPix );
			break;
		case TALK_PHASE:
			// 会話ウィンドウ
			TalkManage.GetInstance().DspDrawTalkWindow( OffPix );
			break;
		}
	}

	// メニューウィンドウ
	void DrawMenuWindow( int OffPix[] ){
		// 表示開始位置は、キャラの隣
		int chara_x = m_selected_chara.px;
		int chara_y = m_selected_chara.py;

		// スクリーン座標へ
		int start_x = CharaManage.GetInstance().ToScreenX( chara_x );
		int start_y = CharaManage.GetInstance().ToScreenY( chara_y );

		fillRectToMemory( OffPix, start_x, start_y, 70, 50, 0x80000000 );
	}

	// 移動先指定
	boolean SetMovePoint( int x, int y ){
		int world_x, world_y, len;
		// ワールド座標に変換
		world_x = x / MapManage.CHIP_SIZE;
		world_x += MapManage.GetInstance().GetNowIndex().x;
		world_y = y / MapManage.CHIP_SIZE;
		world_y += MapManage.GetInstance().GetNowIndex().y;

		// 移動先
		moved_x = world_x * MapManage.CHIP_SIZE;
		moved_y = world_y * MapManage.CHIP_SIZE;
		return true;
	}

	// 話し相手指定
	Chara SetTalkPoint( int x, int y ){
		int world_x, world_y, len;
		// ワールド座標に変換
		world_x = x / MapManage.CHIP_SIZE;
		world_x += MapManage.GetInstance().GetNowIndex().x;
		world_y = y / MapManage.CHIP_SIZE;
		world_y += MapManage.GetInstance().GetNowIndex().y;

		// 方角確認
		int dir = 0;
		// 上
		if( m_selected_chara.py / MapManage.CHIP_SIZE > world_y ){
			dir = 0;
		}
		// 右
		else if( m_selected_chara.px / MapManage.CHIP_SIZE < world_x ){
			dir = 1;
		}
		// 下
		else if( m_selected_chara.py / MapManage.CHIP_SIZE < world_y ){
			dir = 2;
		}
		// 左
		else if( m_selected_chara.px / MapManage.CHIP_SIZE > world_x ){
			dir = 3;
		}
		// その方向セット（自分）
		m_selected_chara.SetDir( dir );

		// その場所は会話範囲？
		if( LightMapData[ world_x ][ world_y ] == 0 ){
			// イベント開始方法が「話す・調べる」のキャラがいるか検索
			Chara chara = CharaManage.GetInstance().SearchChara( world_x, world_y, 0 );

			// もしいなくて、そこがカウンター属性のチップなら、さらにその先を調べる。
			if( chara == null && MapManage.GetInstance().GetMapCell( world_x, world_y ).GetElement() == 1 ){

				// 主人公の方向より先
				if( m_selected_chara.GetDir() == 0 ){ world_y--; }
				else if( m_selected_chara.GetDir() == 1 ){ world_x++; }
				else if( m_selected_chara.GetDir() == 2 ){ world_y++; }
				else if( m_selected_chara.GetDir() == 3 ){ world_x--; }

				chara = CharaManage.GetInstance().SearchChara( world_x, world_y );
			}

			// イベントスクリプト取得
			return chara;
		}else{
			return null;
		}
	}


	// 話し相手指定(キーボード操作)
	Chara SetTalkPointForKey( int px, int py, int dir ){
		int x = px / MapManage.CHIP_SIZE;
		int y = py / MapManage.CHIP_SIZE;

		if( dir == CharaManage.DIR_UP ) y--;
		if( dir == CharaManage.DIR_RIGHT ) x++;
		if( dir == CharaManage.DIR_DOWN ) y++;
		if( dir == CharaManage.DIR_LEFT ) x--;

		// 領域外なら無理
		if( x < 0 || y < 0 || x >= MapManage.GetInstance().width || y >= MapManage.GetInstance().height ) return null;

		// イベント開始方法が「話す・調べる」のキャラがいるか検索
		Chara chara = CharaManage.GetInstance().SearchChara( x, y, 0 );

		// もしいなくて、そこがカウンター属性のチップなら、さらにその先を調べる。
		if( chara == null && MapManage.GetInstance().GetMapCell( x, y ).GetElement() == 1 ){
			// 主人公の方向より先
			if( dir == 0 ){ y--; }
			else if( dir == 1 ){ x++; }
			else if( dir == 2 ){ y++; }
			else if( dir == 3 ){ x--; }

			chara = CharaManage.GetInstance().SearchChara( x, y );
		}
		// イベントスクリプト取得
		return chara;
	}

	// キャラ検索
	void SearchChara( int x, int y ){
		int world_x, world_y;
		// ワールド座標に変換
		world_x = x / MapManage.CHIP_SIZE;
		world_x += MapManage.GetInstance().GetNowIndex().x;
		world_y = y / MapManage.CHIP_SIZE;
		world_y += MapManage.GetInstance().GetNowIndex().y;

		// キャラマネージャーに任せる
		Chara chara = CharaManage.GetInstance().SearchChara( world_x, world_y );

		if( chara != null ){

			// イベント開始方法が「話す・調べる」以外の時は抜ける
			if( chara.GetEventWay() != 0 ){return;}

			// キャラがいたらキャラセレクトフェイズへ
			now_phase = CHARA_SELECT_PHASE;
			m_selected_chara = chara;

			selected_menu_no = 0;
			menu_move_length = 0;

			// 移動可能範囲初期化
			MoveSelectInit();
		}else{
		}
	}

	void Search( int ax, int ay, int mv, int di, String mway ){
		int down, num;

		// 領域外
		if( ax < 0 || ay < 0 || ax >= MapManage.GetInstance().width || ay >= MapManage.GetInstance().height ) return;

		// 最短経路更新？
		if( !mvrec[ ax ][ ay ].equals("") && mway.length() > mvrec[ ax ][ ay ].length() ) return;

		down = 0;

		// 通行不可能エリア？

		// そこに通過フラグのないキャラがいたら無理
		Chara chara = CharaManage.GetInstance().SearchChara( ax, ay );
		if( chara != null && !chara.GetMoveFlag() ){
			down = 1000;
		}
		// 上層レイヤーが通行可能なら、下層レイヤーが通行不可能でも通れる（橋など対策）
		else if( MapManage.GetInstance().ToUnsignedByte( MapManage.GetInstance().MapUpData[ ax ][ ay ] ) > 0 &&
		MapManage.GetInstance().MapUpCell[ MapManage.GetInstance().ToUnsignedByte( MapManage.GetInstance().MapUpData[ ax ][ ay ] ) ].GetWalkFlag() >= 1 ){
			down = 1;
		}
		// 上層レイヤーが通行不可能なら確実に通れない
		else if( MapManage.GetInstance().MapUpCell[ MapManage.GetInstance().ToUnsignedByte( MapManage.GetInstance().MapUpData[ ax ][ ay ] ) ].GetWalkFlag() == 0 ){
			down = 1000;
		}
		// 下層レイヤーが通行不可能
		else if( MapManage.GetInstance().MapDownCell[ MapManage.GetInstance().ToUnsignedByte( MapManage.GetInstance().MapData[ ax ][ ay ] ) ].GetWalkFlag() == 0 ){
			down = 1000;
		}
		else down = 1;

		// 移動できない場合
		if( mv - down < 0 ) return;

		LightMapData[ ax ][ ay ] = 0;
		mvrec[ ax ][ ay ] = mway;

		if( di != 3 ) Search( ax, ay - 1, mv - down, 1, mway + "1" );
		if( di != 4 ) Search( ax + 1, ay, mv - down, 2, mway + "2" );
		if( di != 1 ) Search( ax, ay + 1, mv - down, 3, mway + "3" );
		if( di != 2 ) Search( ax - 1, ay, mv - down, 4, mway + "4" );
	}

	// 移動できる範囲描画
	void DrawCanMoveArea(){
		int i, j;
		int x, y;
		int len;

		// 座標系に
		int chara_x = m_selected_chara.px / MapManage.CHIP_SIZE;
		int chara_y = m_selected_chara.py / MapManage.CHIP_SIZE;

		// 描画
		g.setColor( Color.cyan );
		for( y = chara_y - LENGTH; y <= chara_y + LENGTH; y++ ){
			for( x = chara_x - LENGTH; x <= chara_x + LENGTH; x++ ){
				// 主人公との距離がLENGTH以内だけ描画
				len = abs( chara_x - x ) + abs( chara_y - y );
				if( len <= LENGTH && len >= 1 && 
					x >= 0 && y >= 0 && x < MapManage.GetInstance().width && y < MapManage.GetInstance().height ){
					// その場所が通行不可なら何も描かない
					if( LightMapData[ x ][ y ] == 0 ){
						// 四角形描画
						// スクリーン座標に変換
						g.drawRect( CharaManage.GetInstance().ToScreenX(x*MapManage.CHIP_SIZE) +1,
						CharaManage.GetInstance().ToScreenY( y*MapManage.CHIP_SIZE + 1 ),
						 MapManage.CHIP_SIZE - 2, MapManage.CHIP_SIZE - 2 );
					}
				}
			}
		}
	}

	int abs( int a ){
		return a > 0 ? a : -a;
	}

	// 選択座標を枠で囲む
	void DrawSelectRect(){
		g.setColor( Color.white );
		g.drawRect( (select_x - MapManage.GetInstance().GetNowIndex().x) * MapManage.CHIP_SIZE,
			(select_y - MapManage.GetInstance().GetNowIndex().y) * MapManage.CHIP_SIZE, MapManage.CHIP_SIZE - 1, MapManage.CHIP_SIZE - 1 );
	}

	// 移動の上だけ明るく
	void MouseMoved( int x, int y ){
		// 表示開始位置は、キャラの隣
		int chara_x = m_selected_chara.px;
		int chara_y = m_selected_chara.py;

		// スクリーン座標へ
		int start_x = CharaManage.GetInstance().ToScreenX( chara_x ) + MapManage.CHIP_SIZE;
		int start_y = CharaManage.GetInstance().ToScreenY( chara_y );
		int no = ( y - start_y ) / FONT_SIZE;

		if( no < 0 ){
			selected_menu_no = 0;
		}else if( no > 2 ){
			selected_menu_no = 2;
		}else{
			selected_menu_no = no;
		}
	}

	// メニュー表示
	void DrawMenu(){

		// 表示開始位置は、キャラの隣
		int chara_x = m_selected_chara.px;
		int chara_y = m_selected_chara.py;

		// スクリーン座標へ
		int start_x = CharaManage.GetInstance().ToScreenX( chara_x );
		int start_y = CharaManage.GetInstance().ToScreenY( chara_y );

		// 背景は黒
		// 半透明にするためにピクセル操作で
		//g.setColor( new Color(0,0,0) );
		//g.fillRect( start_x, start_y, 70, 50 );

		// 選択しているところは青色
		// １文字14pixで計算
		g.setColor( Color.blue );
		g.fillRect( start_x + 1, start_y + 1 + selected_menu_no * 14, 68, 15 );

		// 文字は白 230 170
		g.setColor( Color.white );
		g.drawString("移動", start_x + 4, start_y + 14 );
		g.drawString("話す/調べる", start_x + 4, start_y + 28 );
		g.drawString("たたかう", start_x + 4, start_y + 42 );
	}

	//--------------------------------------------------
	//  メモリイメージに塗りつぶし円描画
	//  中心XY 距離 色
	//--------------------------------------------------
	void fillOvalToMemory( int []off, int x, int y, int width, int height, int color ){
		int xx, yy;
		int point;

		// これから描画しようとする方がsrc 元々書いてあったのがdest

		// 加算する色
		int in_alpha = (color >> 24) & 0xff;
		int in_r = ( color >> 16 ) & 0xff;
		int in_g = ( color >> 8 ) & 0xff;
		int in_b = color & 0xff;

		// 元の色
		int dis_r;
		int dis_g;
		int dis_b;

		for( yy = -height; yy < height; yy++ ){
			for( xx = -width; xx < width; xx++ ){
				// 領域外なら書き込まない
				if( x + xx < 0 || x + xx > MapManage.WIDTH ){ continue; }
				if( y + yy < 0 || y + yy > MapManage.HEIGHT ){ continue; }

				// 円の中心までの距離
				if( width * width < xx * xx + yy * yy ){ continue; }

				// 書き込む場所
				point = x + xx + (yy+y)*MapManage.WIDTH;
				if( point >= 0 && point < MapManage.WIDTH * MapManage.HEIGHT ){
					// アルファブレンド
					dis_r = ( ( in_r - ( ( off[ point ] >> 16 ) & 0xff ) ) * in_alpha >> 8 ) + ( ( off[ point ] >> 16 ) & 0xff );
					dis_g = ( ( in_g - ( ( off[ point ] >> 8  ) & 0xff ) ) * in_alpha >> 8 ) + ( ( off[ point ] >> 8  ) & 0xff );
					dis_b = ( ( in_b - ( ( off[ point ] ) & 0xff ) )       * in_alpha >> 8 ) + ( ( off[ point ] ) & 0xff );

					off[ point ] = (0xff<<24)|(dis_r<<16)|(dis_g<<8)|(dis_b);
				}
			}
		}
	}

	//--------------------------------------------------
	//  メモリイメージに塗りつぶし四角形描画(アルファブレンド)
	//--------------------------------------------------
	void fillRectToMemory( int []off, int x, int y, int width, int height, int color ){
		int xx, yy, yyy;
		int point, max_point;

		// これから描画しようとする方がsrc 元々書いてあったのがdest

		// 加算する色
		int in_alpha = (color >> 24) & 0xff;
		int in_r = ( color >> 16 ) & 0xff;
		int in_g = ( color >> 8 ) & 0xff;
		int in_b = color & 0xff;

		// 出力する色
		int dis_r;
		int dis_g;
		int dis_b;

		max_point = MapManage.WIDTH * MapManage.HEIGHT;

		for( yy = 0; yy < height; yy++ ){
			yyy = (yy+y)*MapManage.WIDTH;
			for( xx = 0; xx < width; xx++ ){
				// 領域外なら書き込まない
				if( x + xx < 0 || x + xx > MapManage.WIDTH ){ continue; }
				if( y + yy < 0 || y + yy > MapManage.HEIGHT ){ continue; }

				// 書き込む場所
				point = x + xx + yyy;
				if( point >= 0 && point < max_point ){
					// アルファブレンド
					//     元の色 * ( 256 - α ) / 256 + 加算の色 * α / 256
					// = ( 元の色 * ( 256 - α ) + 加算の色 * α ) / 256
					// = ( 元の色 * 256 - 元の色 * α + 加算の色 * α ) / 256
					// = ( ( 加算の色 - 元の色 ) * α + 元の色 * 256 ) / 256
					// = ( ( 加算の色 - 元の色 ) * α ) / 256 + 元の色
					// = ( ( ( 加算の色 - 元の色 ) * α ) >> 8 ) + 元の色
					if( in_alpha != 0xff ){
						dis_r = ( ( in_r - ( ( off[ point ] >> 16 ) & 0xff ) ) * in_alpha >> 8 ) + ( ( off[ point ] >> 16 ) & 0xff );
						dis_g = ( ( in_g - ( ( off[ point ] >> 8  ) & 0xff ) ) * in_alpha >> 8 ) + ( ( off[ point ] >> 8  ) & 0xff );
						dis_b = ( ( in_b - ( ( off[ point ] ) & 0xff ) )       * in_alpha >> 8 ) + ( ( off[ point ] ) & 0xff );

						off[ point ] = (0xff<<24)|(dis_r<<16)|(dis_g<<8)|(dis_b);
					}else{
						off[ point ] = color;
					}
				}
			}
		}
	}

	//--------------------------------------------------
	//  フェードアウト
	//--------------------------------------------------
	void FadeOutAction(){
		FadeAlpha += 20;
		if( FadeAlpha > 0xFF ){ FadeAlpha = 0xFF; }
	}
	//--------------------------------------------------
	//  フェードイン
	//--------------------------------------------------
	void FadeInAction(){
		FadeAlpha -= 20;
		if( FadeAlpha < 0 ){ FadeAlpha = 0; }
	}
	//--------------------------------------------------
	//  フェード描画
	//--------------------------------------------------
	void DrawFade(){
		if( FadeAlpha == 0 ) return;

		// 黒い四角形のアルファを変えてブレンドしていく手法
		int color = 0x00000000;
		color |= FadeAlpha << 24;
		fillRectToMemory( MapCanvas.GetInstance().GetOffPix(), 0, 0, MapManage.WIDTH, MapManage.HEIGHT, color );
	}

	//--------------------------------------------------
	//  空を飛ぶ
	//--------------------------------------------------
	void ToSky(){
		// 世界を小さく

		switch( SkyPhase ){
		// 待機状態
		case 0:
			break;
		case 1:
			// 空へ初期化
			MapManage.GetInstance().m_scale_per = 1.0f;
			m_map_scale_sate = SKY_SCALE_MAP;
			SkyPhase++;
			break;
		case 2:

			// 縮小率を操作
			MapManage.GetInstance().m_scale_per += 0.02f;
			// 最大値
			if( MapManage.GetInstance().m_scale_per > 2.0f ){
				MapManage.GetInstance().m_scale_per = 2;
				SkyPhase++;
			}
			break;
		case 3:
			break;
		case 4:
			// 縮小率を操作
			MapManage.GetInstance().m_scale_per -= 0.02f;
			// 着陸
			if( MapManage.GetInstance().m_scale_per < 1.0f ){
				this.SkyPhase++;
				this.m_map_scale_sate = NORMAL_SCALE_MAP;
				this.now_phase = NORMAL_PHASE;
			}
			break;
		case 5:
			break;
		}
	}

	//--------------------------------------------------
	//  エンカウント初期化
	//--------------------------------------------------
	void EnCountInit(){
		this.now_phase = ENCOUNT_PHASE;
		SkyPhase = 1;
	}

	//--------------------------------------------------
	//  エンカウント
	//--------------------------------------------------
	void EnCountAction(){
		// 世界を拡大
		switch( SkyPhase ){
		// 待機状態
		case 0:
			break;
		case 1:
			// 初期化
			MapManage.GetInstance().m_scale_per = 1.0f;
			m_map_scale_sate = ENCOUNT_MAP;
			SkyPhase++;
			break;
		case 2:
			MapManage.GetInstance().m_scale_per -= 0.04f;
			// ある程度大きくなれば、一旦逆の流れ
			if( MapManage.GetInstance().m_scale_per < 0.5f ){
				SkyPhase++;
			}
			break;
		case 3:
			MapManage.GetInstance().m_scale_per += 0.04f;
			// ある程度小さくなれば、逆の流れ
			if( MapManage.GetInstance().m_scale_per > 0.7f ){
				SkyPhase++;

				// フェードアウト開始
				FadeAlpha = 0x00;
			}
			break;
		case 4:
			// 縮小率を操作
			MapManage.GetInstance().m_scale_per -= 0.04f;

			// フェード
			FadeOutAction();

			// 最大
			if( MapManage.GetInstance().m_scale_per < 0.2f ){
				// シーン暗転
				applet.ChangeMap( "1203065187" );

				// プレイヤー配置
				BattleManage.GetInstance().SetPlayers();

				// カメラ調整
				SetCameraPosition();

				SkyPhase++;

				// 通常スケールのマップへ
				m_map_scale_sate = NORMAL_SCALE_MAP;
			}
			break;
		case 5:
			// 戦闘用のマップをロード
			// フェードイン開始
			FadeInAction();
			// 終了
			if( FadeAlpha == 0 ){
				SubPhase++;
				// バトルフェイズへ
				now_phase = BATTLE_PHASE;

				BattleManage.GetInstance().Initialize();
			}
			break;
		}
	}

}
