module kyojintati4d.taskending1;

private import SDL;

private import std.stream;

private import std.utf;

private import y4d;
private import y4d_aux.filesys;
private import y4d_aux.widestring;
private import y4d_sound.sound;
private import y4d_timer.fixtimer;

private import kyojintati4d.val.y4dconst;
private import kyojintati4d.val.kyojinconst;
private import kyojintati4d.myapp;
private import kyojintati4d.gameinfo;

private import yamalib.headlinear;
private import yamalib.counterfsp;
private import yamalib.log.log;
private import yamalib.draw.texturelinenoise;
private import yamalib.draw.scatteredtexture;
private import yamalib.draw.moveview;
private import yamalib.draw.dropobject;

private import yamalib.draw.ripplingtexture;	// 波紋描画Texture
private import yamalib.draw.swallowdraw;		// 吸い込まれ描画
private import yamalib.draw.shellemulatordraw;


/**
	エンディングタスク
*/
class TaskEnding1 : GameTaskBase {
	
	/// エンディングタスククラスの文字列表現を返却する
	char[] toString() {
		return "TaskEndig:エンディングタスク";
	}
	
	/// タスク名を返却する
	/**
		このタスク名称を使って、コントローラ部でタスク判別を行う可能性があるので
		ユニークな名前で、実装しておくべきである
	*/	
	override char[] getTaskName() {
		with (kyojintati4d.val.kyojinconst) {
			return KyojinConst.TASK_NAME[KyojinConst.Task.Task_Ending1];
		}
	}

	/// 移動の処理を行います
	override int onMove(Object o) {
		try {
			info = cast(GameInfo)o;
	
			if (!init) {
				init = true;
				onInit();
				info.screen.setClearColor(0, 0, 0);
				this.mouse = info.mouse;
				this.mouse.getPos(mx, my);
				this.mshow = true;
				// onInitでロードスレッドが起動する
				return 0;
			}
			
			if (!initAfter) {
				// BGM再生開始
				bgm.play();
				// タイマ生成
				timer = new FixTimer();
				timer.reset();
				initAfter = true;
			}
			
			int x,y;
			this.mouse.getPos(x,y);
			
			// 必要なければマウスカーソルを非表示する
			if (mx != x || my != y) {
				if (!mshow) {
					mouse.show();
					mshow = true;
				}
				mstop = 0;
			} else {
				if (mshow) {
					++mstop;
					if (mstop >= 30) {
						mouse.hide();
						mstop = 0;
						mshow = false;
					}
				}
			}
			
			this.mx = x;
			this.my = y;
	
			if (staff && step < STAFF_STEP_MAX) {
				
				rt.onMove(info.screen);
		
				headline = headlinear1.isFinish();
				if (twoObject) {
					headline = headlinear2.isFinish();
				}
				drop = breakDrop1.isFinish();
				if (twoObject) {
					drop = cast(bool) (drop && breakDrop2.isFinish());
				}
		
				if (!headline || countAlpha) {
					roleAlpha++;
				}
				
				rtAlpha++;
				if (rtAlpha.isEnd() && rtAlpha.get() == 0) {
					rt.setSurface( surfaces[step] );
					rtAlpha.set(0, Y4dConst.C_ALPHA_MAX, 2);
				}
		
				if (headline && !drop) {
					if (!initDrop) {
						int x1,y1;
						headlinear1.getXY(x1,y1);
						breakDrop1.setXY(x1,y1);
						tln1.setXY(x1,y1);
						breakDrop1.divisionTexture(30,10);	// 分割数
						if (twoObject) {
							headlinear2.getXY(x1,y1);
							breakDrop2.setXY(x1,y1);
							tln2.setXY(x1,y1);
							breakDrop2.divisionTexture(30,10);	// 分割数
						}
						initDrop = true;
					}
					
					breakDrop1.onMove(info.screen);
					checkBreakObj( breakDrop1 );
					if (twoObject) {
						breakDrop2.onMove(info.screen);
						checkBreakObj( breakDrop2 );
					}
					
					if (breakDrop1.isBreaking() && !countAlpha) {
						countAlpha = true;
						roleAlpha.set(Y4dConst.C_ALPHA_MAX, 0, ROLE_ALPHA_STEP);
						rtAlpha.set(Y4dConst.C_ALPHA_MAX, 0, -1);
					}
				} else {
					countAlpha = false;
				}
				
				breakBg.onMove(info.screen);
		
				if (headline && drop) {
					// 次のロールへ
					step++;
									
					Log.print("Now Step:%s\n", step);
				}
				
				//  次のステップへ
				if (headline && drop && step<=13) {
		
					drawRole = null;
					drawName = null;
					rolex = null;
					roley = null;
		
					switch(step) {
					case 1:		// シナリオ/シナリオ演出・構成
						role1.load("img/ending/scenario.png");		// シナリオ
						role2.load("img/ending/scenario_sub.png");	// シナリオ演出・構成
						drawRole ~= role1;
						drawRole ~= role2;
		
						// 表示位置の指定
						rolex ~= rolePos[ROLE_POS.SCENARIO][0];
						roley ~= rolePos[ROLE_POS.SCENARIO][1];
						rolex ~= rolePos[ROLE_POS.SCENARIO_EDIT][0];
						roley ~= rolePos[ROLE_POS.SCENARIO_EDIT][1];
		
						name1.load("img/ending/alice.png");
						name2.load("img/ending/g9fried.png");
						drawName ~= name1;
						drawName ~= name2;
						tln1.setTexture(name1);
						tln2.setTexture(name2);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setXY(namePos[NAME_POS.SCENARIO][0],namePos[NAME_POS.SCENARIO][1]);
						headlinear1.setSprite(sl.getSprite(),Name.ALICE);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setEffectingFrame(HEADLINE_EFFECT_TIME);
						headlinear1.setStartRate(HEADLINE_RATE);
						headlinear1.setReverse(false);
		
						headlinear2.clear();	// 初期化
						headlinear2.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear2.setXY(namePos[NAME_POS.SCENARIO_EDIT][0],namePos[NAME_POS.SCENARIO_EDIT][1]);
						headlinear2.setSprite(sl.getSprite(),Name.G9);
						headlinear2.setMargin(0,15,0,20);
						headlinear2.setInterval(HEADLINE_INTERVAL);
						headlinear2.setEffectingFrame(HEADLINE_EFFECT_TIME);
						headlinear2.setStartRate(HEADLINE_RATE);
						headlinear2.setReverse(true);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						breakDrop2.clear();
						breakDrop2.setTexture(name2);
						breakDrop2.setFade(true);
						breakDrop2.setWaitCount(BREAK_WAIT);
		
						twoObject = true;
						roleAlpha.set(0, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						
						break;
		
					case 2:	// プログラム
						// ロールの読み込み
						role1.load("img/ending/program.png");		// プログラム
						drawRole ~= role1;
		
						name1.load("img/ending/kowasuhito.png");
						drawName ~= name1;
						tln1.setTexture(name1);
						setRoleCentering(role1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.KOW);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setEffectingFrame(HEADLINE_EFFECT_TIME);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						roleAlpha.set(0, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
		
						twoObject = false;
						break;
		
					case 3:	// ２Ｄグラフィック
						// ロールの読み込み
						role1.load("img/ending/gra.png");		// グラフィック
						drawRole ~= role1;
						name1.load("img/ending/nichino.png");
						drawName ~= name1;
						tln1.setTexture(name1);
						setRoleCentering(role1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.NICHI);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setEffectingFrame(HEADLINE_EFFECT_TIME);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						twoObject = false;
						roleAlpha.set(0, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						break;
		
					case 4:	// 音楽・効果音・音声編集
						// ロールの読み込み
						role1.load("img/ending/sound.png");
						drawRole ~= role1;
						name1.load("img/ending/g9fried.png");
						drawName ~= name1;
						tln1.setTexture(name1);
						setRoleCentering(role1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.G9);
						headlinear1.setMargin(0, 15, 0, 20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setEffectingFrame(HEADLINE_EFFECT_TIME);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						twoObject = false;
						roleAlpha.set(0, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						break;
		
					case 5:	// インターフェースデザイン
						// ロールの読み込み
						role1.load("img/ending/interface.png");		// インターフェースデザイン
						drawRole ~= role1;
		
						// 表示位置の指定
						rolex ~= rolePos[ROLE_POS.INTERFACE][0];
						roley ~= rolePos[ROLE_POS.INTERFACE][1];
		
						name1.load("img/ending/hara.png");
						drawName ~= name1;
						tln1.setTexture(name1);
						setRoleCentering(role1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.HARA);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setEffectingFrame(HEADLINE_EFFECT_TIME);
						headlinear1.setStartRate(HEADLINE_RATE);

						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);

						twoObject = false;
						roleAlpha.set(0, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						break;
		
					case 6:
						// ロールの読み込み
						role1.load("img/ending/sub_scenario.png");	// サブシナリオ
						drawRole ~= role1;
						setRoleCentering(role1);
						name1.load("img/ending/g9fried.png");
						drawName ~= name1;
						tln1.setTexture(name1);
						
						// 表示位置の指定
						rolex ~= rolePos[ROLE_POS.INTERFACE][0];
						roley ~= rolePos[ROLE_POS.INTERFACE][1];
						rolex ~= rolePos[ROLE_POS.PLAN][0];
						roley ~= rolePos[ROLE_POS.PLAN][1];
						rolex ~= rolePos[ROLE_POS.CREATE][0];
						roley ~= rolePos[ROLE_POS.CREATE][1];
						
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.G9);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setEffectingFrame(HEADLINE_EFFECT_TIME);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						twoObject = false;
						roleAlpha.set(0, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						break;
		
					case 7:
						// ロールの読み込み
						role1.load("img/ending/voice.png");	// 声優
						drawRole ~= role1;
						name1.load("img/ending/amua.png");
						drawName ~= name1;
						tln1.setTexture(name1);
						setRoleCentering(role1);
		
						// ありす
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.AMUA);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						twoObject = false;
						roleAlpha.set(0, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						break;
						
					case 8:
						// 翠子
						drawRole ~= role1;
						setRoleCentering(role1);
						name1.load("img/ending/suou.png");
						drawName ~= name1;
						tln1.setTexture(name1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.SUOU);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						roleAlpha.set(Y4dConst.C_ALPHA_MAX, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						twoObject = false;
						break;
		
					case 9:
						// タツヲ
						drawRole ~= role1;
						setRoleCentering(role1);
						name1.load("img/ending/tatuwo.png");
						drawName ~= name1;
						tln1.setTexture(name1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.TATUWO);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						roleAlpha.set(Y4dConst.C_ALPHA_MAX, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						twoObject = false;
						break;
		
					case 10:
						// 富絵
						drawRole ~= role1;
						setRoleCentering(role1);
						name1.load("img/ending/hazuki.png");
						drawName ~= name1;
						tln1.setTexture(name1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.HAZUKI);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						roleAlpha.set(Y4dConst.C_ALPHA_MAX, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						twoObject = false;
						break;
		
					case 11:
						// 安西
						drawRole ~= role1;
						setRoleCentering(role1);
						name1.load("img/ending/anzai.png");
						drawName ~= name1;
						tln1.setTexture(name1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.ANZAI);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						roleAlpha.set(Y4dConst.C_ALPHA_MAX, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						twoObject = false;
	
						// そろそろ雪を止ませる
						Log.printLook("STOP snow");
						sm.stop(10000);
	
						break;
		
					case 12:
						// ルビ
						drawRole ~= role1;
						setRoleCentering(role1);
						name1.load("img/ending/haruhi.png");
						drawName ~= name1;
						tln1.setTexture(name1);
		
						headlinear1.clear();	// 初期化
						headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
						headlinear1.setSprite(sl.getSprite(),Name.HARUHI);
						headlinear1.setMargin(0,15,0,20);
						headlinear1.setInterval(HEADLINE_INTERVAL);
						headlinear1.setStartRate(HEADLINE_RATE);
		
						// BreadDrop の設定
						breakDrop1.clear();
						breakDrop1.setTexture(name1);
						breakDrop1.setFade(true);
						breakDrop1.setWaitCount(BREAK_WAIT);
		
						roleAlpha.set(Y4dConst.C_ALPHA_MAX, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
						twoObject = false;
						
						
						break;
		
					default:
						Log.printError("invalied step:%s\n",step);
						break;
					}
		
					headline = drop = initDrop = false;
				}
			} else if (staff) {
				rtAlpha++;
				// スタッフフェーズの終了判定	
				if (step==STAFF_STEP_MAX && rtAlpha.isEnd()) {
					staff = false;
				}
				
			}
			
			
			timer.update();
			
			if ( !staff && !text && timer.get() < START_END_MS) {
			
				if (timer.get() >= START_TXT_MS) {
					text = true;
					textDrawEnd = false;
					intro = false;
				}
			
			} else if (text) {
				if (timer.get() >= START_END_MS) {
					text = false;
	//				endStep = true;
				}
			}
			
			if (!endStep && timer.get() >= START_COMMAND_MS) {
					Log.printLook("END STEP START!!");
					endStep = true;
			}
			
			if ( !bEndTelop && timer.get() >= START_END_TELOP_MS) {
				bEndTelop = true;
				rtAlpha.set(0, 255, 1);
			}
			
			if (endStep) {
				sed.onMove(info.screen);
			}
			
			if (bEndTelop) {
				rtAlpha++;
				
				if ( timer.get() >= START_END_TASK_MS && rtAlpha.get() == 255) {
					// 画面をフェードアウトしてから遷移しようっと
					rtAlpha.set(255, 0, 1);
				}
				
				if ( rtAlpha.get() == 0 ) {
					// タイトルへ遷移
					info.gameSceneTransiter.jumpScene(KyojinConst.Task.Task_Title);
					if (!mshow) {
						this.mouse.show();
					}
					return 1;
				}
				
			}
			
			if (text || !textDrawEnd) {
				textMove();
			}
			
			if ( !initTimer ) {
				initTimer = true;
				Log.printLook("ENDING TIMER REST!");
				timer.reset();
			}

			return 0;

		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onMove : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}

	/// 描画の処理を行います
	override int onDraw(Object o) {
		try {
			info = cast(GameInfo)o;
	
			info.screen.clear();
			
			// エンドステップフェーズ
			if ( endStep) {
				sed.onDraw(info.screen);
			}
			
			// イントロフェーズ
			if ( intro ) {
				introDraw();
			} 
			
			// スタッフフェーズ
			if (staff) {
			
	//			info.screen.setColor(255, 255, 255, Y4dConst.C_ALPHA_MAX);
	//			info.screen.blt(frame, 0, 0);
		
				info.screen.setColor(255,255,255,rtAlpha.get());
				onDrawRt();
				
				if (step != STAFF_STEP_MAX) {
					info.screen.setColor(255,255,255,roleAlpha.get());
					// ロールの描画
					foreach (int i, inout Texture t; drawRole) {
						info.screen.blt(t,rolex[i],roley[i]);
					}
					
					info.screen.resetColor();
		
					if (!headline) {
						// 名前のエフェクト描画
						headlinear1.onDraw(info.screen);
						if (twoObject)
							headlinear2.onDraw(info.screen);
					} else if (headline && !drop) {
						if (breakDrop1.isWait()) {
							tln1.onDraw(info.screen);
							if (twoObject)
								tln2.onDraw(info.screen);
						} else {
							breakDrop1.onDraw(info.screen);
							if (twoObject)
								breakDrop2.onDraw(info.screen);
						}
					}
				}
				
				// 雪でも降らせてみる？
				sm.onDraw(info.screen);
	
				info.screen.setColor(255, 255, 255, 96);
				// キャプション 
				info.screen.blt( caption, 350, 10 );
	
			} 
	
			// テキストフェーズ
			if (text || !textDrawEnd) {
				textDraw();
			}
			
			if (bEndTelop) {
				info.screen.setColor( 255, 255 ,255, rtAlpha.get() );
				info.screen.blt( endTelop, 0, 0 );
			}
	
			return 0;
		} catch (Exception e) {
			Log.printFatal("RuntimeException %s#onDraw : [%s] [%s]", 
				super.toString(), e.toString(), e.msg);
			throw e;
		}
	}

	/// レガシーなやつのため
	override int task(Object o) {
		info = cast(GameInfo)o;
		return 0;
	}

	/// 占有しているメモリを解放する
	override void destroy() {
		if ( bgm.isPlay() ) {
			bgm.stop();
			bgm.release();
			bgm = null;
		}
		
		Texture.safeRelease(bg);
		Texture.safeRelease(role1);
		Texture.safeRelease(role2);
		Texture.safeRelease(role3);
		Texture.safeRelease(name1);
		Texture.safeRelease(name2);
		Texture.safeRelease(caption);
		Texture.safeRelease(heading);
		Texture.safeRelease(endTelop);
		foreach(Texture t; drawRole) {
			Texture.safeRelease(t);
		}
		foreach(Texture t; drawName) {
			Texture.safeRelease(t);
		}
		
		sm = null;
		roleAlpha = cast(RootCounterS) null;
		breakDrop1 = null;
		breakDrop2 = null;
		breakBg = null;
		headlinear1 = null;
		headlinear2 = null;
		tln1 = null;
		tln2 = null;
		sed = null;
		timer = null;
		sds = null;
		moveView = null;
		sl = null;

		Log.print("%s#destroy : destroyed.", super.toString());
	}

	/// コンストラクタ
	this() {
		// bgm
		bgm = new Sound();
		bgm.load( "snd/song/(I'll_Take_Myself)To_The_End.ogg", -1 );
		
		rt = new RipplingTexture();
		
		bg = new Texture;
		role1 = new Texture;
		role2 = new Texture;
		role3 = new Texture;
		roleAlpha = new RootCounterS;
		
		name1 = new Texture;
		name2 = new Texture;

		breakDrop1 = new ScatteredTexture;
		breakDrop2 = new ScatteredTexture;
		breakBg = new ScatteredTexture();

		headlinear1 = new ReduceHeadlinear;
		headlinear2 = new ReduceHeadlinear;
		sl = new SpriteLoader;

		tln1 = new TextureLineNoise;
		tln2 = new TextureLineNoise;

		sm = new DropObjectManager;
		
		rand = new Rand();
		rand.randomize();
	}

private:

	/// 背景波紋テクスチャの描画
	void onDrawRt() {
		static Point[4] points = [
			{x:150, y:230},
			{x:490, y:230},
			{x:640, y:480},
			{x:0, y:480},
		];
		info.screen.blt(rt.getTexture(), null, points);
	}

	/// 初期化処理を行う
	void onInit() {
		// メモリー状況をプリント
		GameInfo.printMemoryState();

		// アルファ可能にしとく
		info.screen.blendSrcAlpha();
		// 速度調整		
		FSP_RATE = KyojinConst.C_FSP_DEFAULT / KyojinConst.C_FSP_NOW;
		
		// BGMのボリュームはオプション画面のボリュームにしとっかー
		bgm.setVolume( info.optionInfo.getBgmVol() );

//		onLoad();
		auto dg = &onLoad;
		info.gameSceneController.callScene(KyojinConst.Task.Task_Loader, dg);
		Log.printLook("Loader Thread setting..");

	}
	
	int onLoad() {
		try {
			with (kyojintati4d.val.kyojinconst.PicNameConst.getInstance()) {
			
				screenX = info.screen.getWidth();
				screenY = info.screen.getHeight();
				
				// moveview
				moveView = new MoveViewSmooth();
				moveView.setTextureLoader( info.tl_bg );
				moveView.setMoveXY(0.5f, 0.2f);
		
				sl.load( getFullName(IMG__ENDING__SPRITE_SDF) );
				name1.load( getFullName(IMG__ENDING__KOWASUHITO_PNG) );
		
				role1.load( getFullName(IMG__ENDING__COMMAND_PNG) );	// 製作総指揮
				setRoleCentering(role1);
				
				tln1.setTexture(name1);
				tln1.setInterval(50);
		
				bg.load( getFullName(IMG__ENDING__BG_JPG));
				headlinear1.setStyle(ReduceHeadlinear.Style.CENTER);
				headlinear1.setSprite(sl.getSprite(),Name.KOW);
				headlinear1.setMargin(0,15,0,20);
				headlinear1.setInterval(HEADLINE_INTERVAL);
				headlinear1.setEffectingFrame(HEADLINE_EFFECT_TIME);
				headlinear1.setMoveXY(-300,-200);
				headlinear1.setReverse(true);
		//		headlinear1.setRandomMove(true);
		
				// BreadDrop の設定
				breakDrop1.setTexture(name1);
				breakDrop1.setWaitCount(BREAK_WAIT);
				breakDrop1.setFade(true);
				roleAlpha.set(0, Y4dConst.C_ALPHA_MAX, ROLE_ALPHA_STEP);
				
				Surface surface = new Surface();
				surface.load( getFullName(IMG__ENDING__MASK1_PNG) );
				t = new Texture();
				t.load(IMG__BACK__PLACE010_JPG);
				breakBg.setTexture(t);
				breakBg.setWaitCount(BREAK_WAIT);
				breakBg.setFade(true);
				breakBg.divisionTextureWithSurface(surface, 2, 2);
		
				drawRole ~= role1;
				drawName ~= name1;
		
				// 雪
				sm = new DropObjectManager();
				sm.presetSnow();
				sm.init(250);
				
				// -------------------------追加分
				caption = new Texture();
				heading = new Texture();
				
				heading.load("img/ending/heading.jpg");
				caption.load("img/ending/caption.png");
				
				surfaces = new Surface[13];
				foreach(int i, inout Surface s; surfaces) {
					s = new Surface();
					s.load( SURFACE_NAME[i] );
				}
				
				rt.setSurface(surfaces[0]);
				rtAlpha = new RootCounterS();
				rtAlpha.set(0, Y4dConst.C_ALPHA_MAX, -1);
				
				// テキスト読み込み
				std.stream.MemoryStream m = 
					new std.stream.MemoryStream( cast(char[]) FileSys.read("data/ending.txt") );
				while (!m.eof) {
					char[] linebuf = m.readLine();
					message ~= linebuf;
				}
	
				// 吸い込みテクスト生成
				sds = new SwallowDraw[9];
				int drawWait;
				foreach( inout SwallowDraw sd; sds ) {
					sd = new SwallowDraw();
					drawWait += 18;
					Texture tmp = new Texture();
					wchar[] str = toWCS( message[rand.get(message.length)] );
					if (str.length >= 10) {
						str.length = 9;
					}
					tmp.setSurface( info.fontloader.get(0).drawBlendedUnicode( str )  );
					sd.setTexture( tmp );
					sd.setDrawWait( drawWait );
					sd.setEndStep(90);
				}
				
				// シェルエミュレートドロー生成
				static char[][] COMMAND_FILE = [
					"img/ending/sh/sh1.txt",
					"img/ending/sh/sh2.txt",
					"img/ending/sh/sh3.txt",
					"img/ending/sh/sh4.txt",
				];
				
				sed = new ShellEmulatorDraw();
				sed.setCommands( COMMAND_FILE, info.fontloader );
				
				// エンドテクスチャ生成
				endTelop = new Texture();
				endTelop.load( "img/ending/endtelop.jpg" );
			}

		} catch(Exception e) {
			Log.print("%s#onLoad : %s", super.toString(), e.toString());
		}
		
		return 0;
	}

	/// 役割画像をセンタリングする
	void setRoleCentering(Texture t,int y=int.min) {
		rolex ~= (screenX-cast(int)t.getWidth())/2;
		if (y==int.min) {
			roley ~= ROLE_Y;
		} else {
			roley ~= y;
		}
	}


private:


	/// 分解した文字が水面に接地したときに波紋を起こす
	void checkBreakObj(ScatteredTexture st) {
		if (!st.isBreaking()) return;
		
		foreach(inout ScatteredTexture.BreakObject bo; st.getObjectInfo()) {
			if (bo.posy > 430) {
				rt.createWave( cast(int)(cast(float)bo.posx*(cast(float)240/640)) , 200+(rand.get(20)-10), -250 * 256 );
				bo.kill();
			}
		}
	}

	/// テキスト描画移動
	void textMove() {
		bool textEnd = true;
		
		if (!text) {

			foreach( inout SwallowDraw sd; sds ) {
				sd.onMove(info.screen);
				if ( !sd.isEnd() ) {
					textEnd = false;
				}
			}

			if (textEnd) {
				textDrawEnd = true;
			}
			
		} else {
			
			foreach( inout SwallowDraw sd; sds ) {
				sd.onMove(info.screen);
				if ( sd.isEnd() ) {
					Texture tmp = new Texture();
					
					wchar[] str = toWCS( message[rand.get(message.length)] );
					tmp.setSurface( 
						info.fontloader.get(0).drawBlendedUnicode(str,false) );
							
					sd.setTexture( tmp );
					sd.reset();
				}
			}
			
		}

	}
	
	/// テキスト描画
	void textDraw() {	
		foreach( inout SwallowDraw sd; sds ) {
			sd.onDraw(info.screen);
		}
	}

	/// イントロ部分
	void introMove() {
	}
	
	/// イントロ部分描画
	void introDraw() {
		
		if ( add == int.min ) {
			add = FSP_RATE * 1;
		}
		
		info.screen.setColor( 255, 255, 255, (counter+=add));
		
		if (counter >= 255) {
			if (wait++ > (100/FSP_RATE) ) {
				add = (-1*FSP_RATE);
			} else {
				add = 0;
			}
		} else if (counter<=0) {
			add = 0;
		}
		
		// 表題描画
		info.screen.blt( heading, 0, 0 );
		
		if (add < 0 && counter <= 96 ) {
			info.screen.setColor(255, 255, 255, 96);
		}
		
		if (counter <= 0) {
			intro = false;
			staff = true;
		}

		// キャプション
		info.screen.blt( caption, 350, 10 );
	}


private:

	int counter = 0;
	int add = int.min;
	int wait = 0;


	static final const int ROLE_Y = 80;
	static final const int NAME_Y = 250;
	static final const int ROLE_ALPHA_STEP = 10;
	static final const int HEADLINE_INTERVAL = 15;
	static final const int HEADLINE_EFFECT_TIME = 120;
	static final const int HEADLINE_RATE = 10;
	static final const int BREAK_WAIT = 150;
//	static final const int BREAK_WAIT = 30;
	
	static final const int STAFF_STEP_MAX = 13;

	static final const uint START_TXT_MS = 141*1000;	// テキストフェーズ開始ミリ秒	
	static final const uint START_END_MS = 190*1000;	// エンドフェーズ開始ミリ秒
	static final const uint START_COMMAND_MS = 176*1000;
	static final const uint START_END_TELOP_MS = 198*1000;
	static final const uint START_END_TASK_MS = 223*1000;

	enum Name : int {KOW=0,NICHI,G9,ALICE,AMUA,SUOU,TATUWO,HAZUKI,ANZAI,HARUHI,HARA};
	enum ROLE_POS : int {SCENARIO,SCENARIO_EDIT,INTERFACE,PLAN,CREATE};
	static final const int[2][] rolePos = [
		  [85,112],		// シナリオ
		  [285,355],	// シナリオ演出
		  [30,80],		// インターフェース
		  [105,80],		// 企画
		  [105,345],	// 作成
	];
	enum NAME_POS : int {SCENARIO,SCENARIO_EDIT,PLAN,CREATE};
	static final const int[2][] namePos = [
		  [345,132],	// シナリオ @lice
		  [55,375],		// シナリオ演出 g9
		  [300,100],	// 企画
		  [288,365],	// 作成
	];

	static final const char[][] SURFACE_NAME = [
		"img/ending/bg/place12.png",
		"img/ending/bg/place13.png",
		"img/ending/bg/place11.png",
		"img/ending/bg/place13.png",
		"img/ending/bg/place15.png",
		"img/ending/bg/place14.png",
		"img/ending/bg/place13.png",
		"img/ending/bg/place06.png",
		"img/ending/bg/place05.png",
		"img/ending/bg/place04.png",
		"img/ending/bg/place01.png",
		"img/ending/bg/place07.png",
		"img/ending/bg/place08.png",
	];
	
	static Rand rand;
	/// 現在のＦＳＰと６０との比率
	static int FSP_RATE = 1;

	GameInfo info;
	Sound bgm;
	bool init = false;
	bool initAfter = false;
	FontRepository fr;

	bool headline;
	bool drop;

	int screenX;
	int screenY;

	int[] rolex;
	int[] roley;
	int[] namex;
	int[] namey;
	bool countAlpha;
	
	RootCounterS roleAlpha;
	RootCounterS rtAlpha;

	RipplingTexture rt;		// 波紋描画テクスチャークラス
	Surface[] surfaces;
	
	Texture t;
	Texture bg;
	Texture role1;
	Texture role2;
	Texture role3;
	Texture[] drawRole;

	Texture name1;
	Texture name2;
	Texture[] drawName;
	
	SpriteLoader sl;
	ReduceHeadlinear headlinear1;
	ReduceHeadlinear headlinear2;

	ScatteredTexture breakDrop1;
	ScatteredTexture breakDrop2;
	ScatteredTexture breakBg;
	bool initDrop;

	TextureLineNoise tln1;
	TextureLineNoise tln2;

	int step;

	bool twoObject;

	DropObjectManager sm;	// 雪
	
	MoveViewSmooth moveView;
	
	// 追加分
	bool intro = true;	// イントロ部分
	bool text;			// テキスト部分
	bool textDrawEnd = true;
	bool staff;			// スタッフ部分
	bool endStep;		// 終了部分
	bool initTimer;
	Texture caption;
	Texture heading;
	Texture endTelop;	// エンドテロップ
	bool bEndTelop;
	
	int mx;		// マウスの位置を保存しておく
	int my;
	int mstop;
	bool mshow;
	MouseInput mouse;
	
	SwallowDraw[] sds;	// 吸い込まれテキストテクスチャ配列
	char[][] message;	// ↑で使う、メッセージ配列
	FixTimer timer;		// タイミング調整タイマ
	
	ShellEmulatorDraw sed;
	
}
