//@STATE=嶌惉拞
//@DESCRIPTION ---------------------------------------------------------------
// Game.cpp: Game 僋儔僗偺僀儞僾儕儊儞僥乕僔儑儞
// $Log: Game.cpp,v $
// Revision 1.1  2001/10/28 21:40:36  fujiwara
// DLL偵暘妱
//
// Revision 1.12  2001/07/09 20:30:08  fujiwara
// 椺奜張棟偺慻傒崬傒
//
// Revision 1.11  2001/07/01 21:30:34  fujiwara
// 儊儌儕儕乕僋僠僃僢僋尒捈偟
//
// Revision 1.10  2001/07/01 01:03:44  fujiwara
// const 偺尒捈偟
// 攝抲僄僨傿僞偼搑拞宱夁
//
// Revision 1.9  2001/06/10 21:17:54  fujiwara
// 抧忋梡捛壛
//
// Revision 1.8  2001/06/03 09:22:32  fujiwara
// 抧忋揋僋儔僗偍傛傃嶨嫑揋偺旝挷惍
//
// Revision 1.7  2001/05/17 12:34:10  fujiwara
// 抧忋揋僒儞僾儖嶌惉
//
// Revision 1.6  2001/05/13 20:04:24  fujiwara
// 儊儌儕乕儕乕僋偑敪惗偟偨偺偱庢傝彍偔丅
// 帺抏偺僒僂儞僪僥僗僩
//
// Revision 1.5  2001/05/12 12:48:28  fujiwara
// 攝抲僄僨傿僞嶌惉偵敽偆曄峏丒捛壛
//
// Revision 1.4  2001/05/12 08:17:12  fujiwara
// 堦斒曐岇堘斀偑婲偙傞BUG廋惓
//
// Revision 1.3  2001/05/12 00:50:33  fujiwara
// 俠倁俽傪摫擖偟丄儘僌昞帵傪捛壛
//
//@DESCRIPTION_END -----------------------------------------------------------
//@AUTHOR=S.F.
// Copyright (C) 2000 Satoshi Fujiwara. All Rights Reserved.
///////////////////////////////////////////////////////////////////////////////
#pragma warning( disable : 4786 )	//STL偺寈崘奜偟

// SYSTEM INCLUDES //
// 儊儌儕乕儕乕僋専弌梡
#include "sfdebug.h"


#include <stack>
#include <list>
#include <iostream>
#include <fstream>
#include <vector>
#include	<map>
#include <string>
#include "math.h"

// PROJECT INCLUDES //

#include "exception.h"
#include "singleton.h"
#include "system.h"
#include "sound.h"
#include "console.h"
#include "Obj.h"
#include "Obj2D.h"
#include "ObjRectangle.h"
#include "ObjQuadrangle.h"
#include "Obj3DL.h"
#include "Background.h"
#include "input.h"
#include "Scene.h"
#include "main.h"
#include "AbstractScene.h"
#include "character.h"
#include "Hit.h"
#include "MyShip.h"
#include "Enemys.h"
#include "Armys.h"
#include "EnemyBullets.h"


#include "Game.h"
#include "GameImpl.h"

#include "DispositionControl.h"
#include "AbstractCharacter.h"
#include "MyBullets.h"
#include "MyGroundBullets.h"
#include "Effects.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//#include "ZK01.H"

//////////////////////////////////////////////////////////////////////
// 峔抸/徚柵
//////////////////////////////////////////////////////////////////////
using namespace sf::application::scene;
using namespace sf::system::console;
using namespace sf;

// 僐儞僗僩儔僋僞 -------------------------------------------------------------
Game::Game() : AbstractScene()
{
	mbKeyboardListening = false;
	mState = INITIALIZE;
	mTimer = 0;
	
	mpController = new sf::application::disposition::Controller;
	mpController->game(this);
	
	mpMyShip = new player::Ship(this);
	
	mpBullets = sf::application::player::bullet::Bullets::instance();
	mpBullets->initialize();

	mpEnemys = sf::application::enemy::Enemys::instance();
	mpEnemys->initialize();

	mpArmys = sf::application::enemy::Armys::instance();
	mpArmys->initialize();

	mpEffects = sf::application::effect::Effects::instance();
	mpEffects->initialize();

	mpEnemyBullets = sf::application::enemy::Bullets::instance();
	mpEnemyBullets->initialize();


	mpGroundBullets = sf::application::player::bullet::GroundBullets::instance();
	mpGroundBullets->initialize();

	mScore = 0;
	mStageNo = 0;

	mbEdit = false;
}// Game()

// 僨僗僩儔僋僞 ---------------------------------------------------------------
Game::~Game()
{
	if(mpInput)
		mpInput->removeKeyboardListener(this);

	delete mpController;
	delete mpMyShip;

	if(mpStart){
		mpStart->removeListener(this);
		mpStart = NULL;
	}

}// ~Game()

// 僗働僕儏乕儔 ---------------------------------------------------------------
void Game::move(void )
{
	mTimer ++;

	switch(mState)
	{
	case INITIALIZE:
		initialize();
		break;
	case START:
		mBackground.visibility(true);
		mpMyShip->initialize();
		mState = MAIN;
		mbKeyboardListening = true;
		break;
	case MAIN:
		main();
		return;
	case RESTART:
		restart();
		return;
	case CLEAR:

	case OVER:
		over();
		return;
		;
	}
	
}// move()

// 弶婜壔 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::initialize()
{
	mpConsole->print(
			0,
			viewport::X + viewport::WIDTH / 2.0f - 32.0f / 2.0f * text::COLUMN_PITCH,
			viewport::Y + viewport::HEIGHT / 2.0f,
			0.0f,
			1.0f,
			0xffffffff,
			"Loading Game Data. Please Wait!");
	
	if(mTimer < 10) return;

	mStageNo = 0;
	mScore = 0;
	difficulty(EASY);
	mScrollY = 0.0f;

	mBackground.startOffsetY(0.0f);
	mBackground.startOffsetX(0.0f);

	// 僎乕儉僗僞乕僩夋柺
	mpInput->addKeyboardListener(this);
	StartParameter start_param;
	mpStart = start_param.createScene();
	
	mpStart->addListener(this);

	mState = START;

	load("game.dat");
	
	loadStageData();
	
	mpMyShip->life(sf::application::player::Ship::INIT_LIFE);
}//

// 屻巒枛 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::resetObjects(){
	
	mpEnemys->initialize();
	mpEffects->initialize();
	mpBullets->initialize();
	mpEnemyBullets->initialize();
	mpArmys->initialize();
	mpGroundBullets->initialize();

}// resetObjects()

// 儊僀儞 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::main()
{
	using namespace sf::system::console;
	// Exit Key偑墴偝傟偨偐丠
	if(mpInput != NULL && mpInput->exit(false))
	{
		mState = OVER;
		return;
	}

	printPlayerInfo();

	// 暥帤楍傪僽儕儞僋昞帵
	if(mTimer & 0x8)
	{
		mpConsole->print(
			0,
			viewport::X + viewport::WIDTH / 2.0f - 14.0f / 2.0f * text::COLUMN_PITCH,
			viewport::Y + viewport::HEIGHT / 2.0f,
			0.0f,
			1.0f,
			0xffffffff,
			"Exit Esc Key!!");
	}

//	if(!(mTimer & 0xf))
//		mpEnemys->create(sf::application::enemy::Enemys::ZK01,sf::system::console::viewport::X + 400.0f * (float)rand() / 32768.0f ,-48.0f,0.5f,this);

	mpController->exec(mScrollY);

	mpMyShip->move();
	mpBullets->move();
	mpGroundBullets->move();
	mpEnemys->move();
	mpEffects->move();
	mpEnemyBullets->move();
	mpArmys->move();

	mpEnemys->hitCheck(mpBullets);
	mpEnemys->hitCheck(mpMyShip);
	mpEnemyBullets->hitCheck(mpMyShip);
	mpArmys->hitCheck(mpGroundBullets);

	// 攝抲儅僢僾偐傜僨乕僞庢傝弌偟 //
	
	mBackground.offsetY(mScrollY);
	mScrollY = mScrollY + mScrollSpeed;
}// main()

// 僎乕儉僆乕僶乕 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::over()
{
	resetObjects();	
	callSceneEvent(&sf::application::scene::Listener::endOfScene);
	delete this;
	
	// 僎乕儉僆乕僶乕僔乕儞傊堏峴
	OverParameter param;
	param.createScene();

	// 僞僀僩儖夋柺傊偺堏峴
	//TitleParameter param;
	//param.createScene();
}// over() 

// 僔乕儞偺廔椆 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::endOfScene(Scene *pScene)
{

	switch(pScene->type())
	{
	case EDITOR:
		mbKeyboardListening = true;
		active();
		mbEdit = false;
		break;
	case DISPOSITION_EDITOR:
		mbKeyboardListening = true;
		active();
		mbEdit = false;
		break;
	case sf::application::scene::START:
		if(!mbEdit) {
			sf::system::instance()->sound()->play(mBgmId,1,true,true);
			active();
		}
		mpStart = NULL;
		break;
	default:
		active();
		break;
	}
	;// 壗傕偟側偄
}// endOfScene()

// 俤倃俬俿僉乕偑墴偝傟偨丂亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::exitKeyPressed(Scene *pScene)
{
	callSceneEvent(&sf::application::scene::Listener::exitKeyPressed);

	// 僞僀僩儖夋柺傊偺堏峴
	TitleParameter param;
	param.createScene();

	// 揋側偳傪僋儕傾偡傞
	resetObjects();
	delete this;
}// exitKeyPressed()

// 僉乕偑墴偝傟偨偲偒偺張棟 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::keyDown(DWORD keyCode,DWORD extKeyCode)
{
	Scene *pscene;
	BGEditorParameter edit_param;
	DispositionEditorParameter d_param;
	
	switch((char)keyCode)
	{
	case 'B':
		resetObjects();
		edit_param.game(this);
		pscene = edit_param.createScene();
		pscene->addListener(this);
		mbKeyboardListening = false;
		sleep();
		mbEdit = true;
		break;
	case 'D':
		resetObjects();
		d_param.game(this);
		pscene = d_param.createScene();
		pscene->addListener(this);
		mbKeyboardListening = false;
		sleep();
		mbEdit = true;
		break;
	}

}// keyDown()

// 僾儗僀儎乕忣曬偺昞帵 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::printPlayerInfo()
{
	using  namespace sf::system::console;

	// 僗僐傾昞帵 //
	mpConsole->print(
		0,
		viewport::X + (viewport::WIDTH - 5.0f * text::COLUMN_PITCH) / 2.0f,
		viewport::Y,
		0.0f,
		1.0f,
		0xffffffff,
		"SCORE"
	);

	mpConsole->print(
		0,
		viewport::X + (viewport::WIDTH - 8.0f * text::COLUMN_PITCH )/ 2.0f,
		viewport::Y + (1.0f * text::LINE_PITCH),
		0.0f,
		1.0f,
		0xffffffff,
		"%08d",mScore
	);

	// 僾儗僀儎乕巆悢昞帵 //

}// printScore()

// 僾儗僀儎乕忣曬偺昞帵 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::printEditInfo()
{
	using  namespace sf::system::console;

	// 僗僐傾昞帵 //
	mpConsole->print(
		0,
		viewport::X + 1.0f * text::COLUMN_PITCH,
		viewport::Y + (2.0f * text::LINE_PITCH),
		0.0f,
		1.0f,
		0xffffffff,
		"pos:"
	);

	mpConsole->print(
		0,
		viewport::X + 5.0f * text::COLUMN_PITCH,
		viewport::Y +(2.0f * text::LINE_PITCH) ,
		0.0f,
		1.0f,
		0xffffffff,
		"%f",mBackground.offsetY()
	);

	mpConsole->print(
		0,
		viewport::X + 1.0f * text::COLUMN_PITCH,
		viewport::Y + (3.0f * text::LINE_PITCH),
		0.0f,
		1.0f,
		0xffffffff,
		"ofx:"
	);

	mpConsole->print(
		0,
		viewport::X + 5.0f * text::COLUMN_PITCH,
		viewport::Y + (3.0f * text::LINE_PITCH),
		0.0f,
		1.0f,
		0xffffffff,
		"%f",mBackground.startOffsetX()
	);

	mpConsole->print(
		0,
		viewport::X + 1.0f * text::COLUMN_PITCH,
		viewport::Y + (4.0f * text::LINE_PITCH),
		0.0f,
		1.0f,
		0xffffffff,
		"ofy:"
	);

	mpConsole->print(
		0,
		viewport::X + 5.0f * text::COLUMN_PITCH,
		viewport::Y + (4.0f * text::LINE_PITCH),
		0.0f,
		1.0f,
		0xffffffff,
		"%f",mBackground.startOffsetY()
	);

	// 僾儗僀儎乕巆悢昞帵 //

}// printScore()

// 僗僥乕僕僨乕僞偺儘乕僪 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::loadStageData(){

	mBackground.load(mStageData[mStageNo].mapFileName.c_str());
	mpController->load(mStageData[mStageNo].dispositionFileName.c_str());
	mBgmId = sf::system::instance()->sound()->load(mStageData[mStageNo].bgmFileName.c_str());

}// loadStageData()

void Game::clear(){
	;
}// clear()

std::ostream & operator <<
                ( std::ostream &rOStrm    // cStrStrm
                , const Game::Data &rGameData )    // cInt
{
    return rOStrm << rGameData.mapFileName << " " << rGameData.dispositionFileName;    // 婛懚偺娭悢傪屇傃弌偟傑偡丅
}

std::istream& operator >> ( std::istream& rIStrm, Game::Data &rGameData)
{
	rIStrm >> rGameData.mapFileName;
	rIStrm >> rGameData.dispositionFileName;
	rIStrm >> rGameData.bgmFileName;
	return rIStrm;
}

// 僎乕儉僨乕僞偺儘乕僪 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::load(const char * const pFileName)
{
	char err_loadstr[] = "Game::load() Error!";
	
	std::fstream file(pFileName,std::ios::in);
	if(!file.is_open()){
		throw FatalErrorException("Game File Not Found",__FILE__,__LINE__);
	}
	file >> mStageMax;
	Data temp_data;
	for(int i = 0 ; i < mStageMax ; i++){
		file >> temp_data;
		if(file.fail() != 0){
			throw FatalErrorException(err_loadstr,__FILE__,__LINE__);
		}
		mStageData.push_back(temp_data);
	}
}// load()

// 儕僗僞乕僩 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Game::restart()
{

	resetObjects();
	mBackground.visibility(false);
	mpMyShip->restart();
	scrollY(restartPosition());
	mBackground.offsetY(restartPosition());
	mpController->restart(restartPosition());
	mState = START;
	
	StartParameter start_param;
	Scene * pscene = start_param.createScene();
	pscene->addListener(this);

}// restart()

void Game::difficulty(const DIFFICULTY value){
	mDifficulty = value;
	mCurrentDifficulty = (float)value + fmod(currentDifficulty(),1.0f); 
}


