#include "GPlayerManager.h"

#include <hpllib/action/HPLActionMoveTool.h>

#ifdef _DXLIB
#include "GStaticDataDX.h"
#else
#include "GStaticData.h"
#endif

using namespace GPlayerManagerConsts;
using namespace std;
using namespace GEnum;

GSetting* getSetting() {
	return &getStaticData()->m_CommonWork.m_Setting;
}

float getZoom( GPlayer* lpPlayer ) {
	float fZoom = 1.f;
	if( lpPlayer->getType() == PlayerType::ELLIN ) {
		fZoom = 2.f;
	}
	return fZoom;
}


void movePlayer(GPlayer* player, HPLVector* velocityAngle,
				int direction)
{
	float RESIST = getSetting()->resist;

	float SPEED = getSetting()->player.walkMaxSpeed;
	float ACCEL = getSetting()->player.walkAccel;

	float fZoom = getZoom( player );
	SPEED *= fZoom;
	ACCEL *= fZoom;

	SPEED += RESIST;

	//////
	// 空中/地上で速度を変える
	if(player->getTrigger()->getTrigger(TriggerType::ON_THE_GROUND)){
		ACCEL += RESIST;

		// 地上では即MAXすぷーになる
		if( direction != 0 ) {
			velocityAngle->setX( static_cast<float>( direction ) * SPEED);
		}
		
	}else{
		SPEED = getSetting()->player.airMaxSpeed;
		ACCEL = getSetting()->player.airAccel;
		SPEED *= fZoom;
		ACCEL *= fZoom;

		ACCEL += RESIST/2;

		// 空中は加速移動にする
		HPLActionMoveTool::accelAndResistX(
			velocityAngle,
			HPLVector(direction * ACCEL,0),
			HPLVector(RESIST, 0),
			SPEED);
	}

}

void GPlayerManager::standToWalk(GPlayer* player, HPLVector* velocityAngle){
	// 状態
	int st = player->getState()->getState();


	bool right = player->isPressed(GEnum::KeyMap::RIGHT);
	bool left = player->isPressed(GEnum::KeyMap::LEFT);
	bool down = player->isPressed(GEnum::KeyMap::DOWN);


	// キー入力によって方向を変える
	int faceDirection = 0;
	if( player->getState()->isAttackState() ) {

		// 攻撃中は左右を振り向かない
	} else {
		if(right){
			faceDirection = FaceDirection::RIGHT;
		}
		if(left){
			faceDirection = FaceDirection::LEFT;
		}
	}

	{
		if(faceDirection != 0 && faceDirection != player->getFaceDirection()){
			/////
			// 左右キーを押して方向が変わった
			// ステートリセット
			if(player->getState()->isAttackGunState()){
				player->changeState(StateType::STAND);
				st = player->getState()->getState();
			}
		}
		if(faceDirection != 0){
			player->setFaceDirection(faceDirection);
		}
	}

	// シーケンス情報
	HPLSequenceState seqState = player->getSequence()->getState();

	// 接地している
	bool isOnTheGround = player->getTrigger()->getTrigger(TriggerType::ON_THE_GROUND);

	// 歩ける状態か	
	bool isReadyToWalk = player->getState()->isAttackState() == false;
		//player->getState()->isDeadState();
	


	if(player->isNoPlayerControllableState()){// && player->getState()->isDeadState() == false){
		// 操作不可能な状態
		isReadyToWalk = false;
	}

	
	if( player->getTrigger()->getTrigger( TriggerType::ON_THE_GROUND ) ) {
		// 地面にいる
		if( down ) {
			// ↓を押している

			// 横移動できない
			isReadyToWalk = false;
		}

		if( isReadyToWalk && player->isPressedNow(KeyMap::D) ) {
			// 歩ける状態
			// 'A'キー
			//		→Taunt
			player->changeState(StateType::CAKE );
			isReadyToWalk = false;
		}
	}

	if( isReadyToWalk ||
		
		player->getState()->isReadyToWalkState() ||
		st == StateType::BORING ||
		st == StateType::FLYUP ||
		st == StateType::FLYDOWN )
	{
		// 移動可能なステート

		// 左右移動
		movePlayer(player, velocityAngle, faceDirection);

		if(isOnTheGround){
			// 接地
			if(st != StateType::WALK && (left || right) && !down){
				// 歩きになる
				player->changeState(StateType::WALK);
			}
		}else{
			////
			// 空中
			// 状態は変えない
		}
	} else if(st == StateType::CROUCH || st == StateType::BORING_CROUCH) {
		// しゃがみ状態

/*		if( down == false && player->isAutoCrouch( AUTO_CROUCH_HP_THRESHOLD, GEnum::KeyMap::A) ) {
			// 下を押していない＆自動しゃがみ状態

			///////////
			// ↓キー以外の座り状態
			//		→歩ける！
			movePlayer(player, velocityAngle, faceDirection);

			// 歩きになる
			player->changeState(StateType::WALK);

		}else*/
		{
			///////
			// アニメーションが終わったら立つ
			if(isOnTheGround && seqState.isFinishAnimation && !down){
				player->changeState(StateType::WALK);
			}
		}
	}else if( player->getState()->isFlyingState() ){

		/////
		// 飛んでる！

		movePlayer(player, velocityAngle, faceDirection);
		

	}else if(st == StateType::ATTACK_PUNCH){

		// パンチ攻撃
		// 移動可能
		movePlayer(player, velocityAngle, faceDirection);

	}else if(st == StateType::ATTACK_PINEAPPLE){

		// 投擲攻撃

		if(isOnTheGround){
			/////
			// 地上移動不可
		}else{
			/////
			// 空中移動可能
			movePlayer(player, velocityAngle, faceDirection);
		}


	}else if(player->getState()->isAttackGunState()){
		int wtype = player->getUsingWeaponTypeIndex();

/*		if(wtype == WeaponType::SemiAutoColt){
			if(isOnTheGround){
				//////
				// 動く
				//movePlayer(player, velocityAngle, faceDirection);
				// 歩く?
				if(faceDirection != 0){
					player->changeState(StateType::WALK);
				}
			}else {
				flyMovePlayer(player, velocityAngle, faceDirection);
			}
		}else */
		/*if(true){//player->isUsingHeavyWeapon()){
			if(isOnTheGround){
				/////
				// 地上移動不可
			}else{
				/////
				// 空中移動可能(というか撃てないだけ)
				flyMovePlayer(player, velocityAngle, faceDirection);
			}
		}else{
			if(isOnTheGround){
				/////
				// 地上移動不可
			}else{
				/////
				// 空中移動可能
				flyMovePlayer(player, velocityAngle, faceDirection);
			}
		}*/
	}/*else if(st == StateType::LYING || st == StateType::BORN){

		////
		// 倒れてた
		if(player->isBaby()){
			player->setBaby(false);
		}else{
			//  →CROUCH状態（で、その後歩く、と。）
			player->changeState(StateType::CROUCH);
		}

	}*/
}

void GPlayerManager::jump(GPlayer* player, HPLVector* velocityAngle){

	int jumpMaxNum = 2;

	/*if(player->getType() == PlayerType::Trellama){
		jumpMaxNum = 3;
	}*/
	player->getJumpManager()->setJumpNumMax(jumpMaxNum);

	int st = player->getState()->getState();

	///////
	// Xキーでジャンプ
	bool sp = false;

	/*////
	// パンチ、パイナップル、あるいは、重火器以外の火器使用時はジャンプ可能
	*/
	if(st == StateType::ATTACK_PUNCH || st == StateType::ATTACK_PINEAPPLE){
	
		sp = true;
	}

	int wtype = player->getUsingWeaponTypeIndex();

	bool isStateTypeOK = (sp ||
		st == StateType::STAND || 
		st == StateType::BORING ||
		st == StateType::WALK ||
		st == StateType::WALK_READY ||
		st == StateType::FLYDOWN ||
		st == StateType::FLYUP ||
		st == StateType::CROUCH ||
		st == StateType::BORING_CROUCH);

	bool isJumpableOK = (player->getJumpManager()->isJumpable() || getStaticData()->m_CommonWork.m_Game.isCheat());

	bool isPressedJumpKey = player->isPressedNow(GEnum::KeyMap::UP);

	//////
	// never jump when tank
	if( isStateTypeOK && 
		isJumpableOK && 
		isPressedJumpKey )
	{

			this->playerJump(player, velocityAngle);
	}

}

void GPlayerManager::playerJump(GPlayer* player, HPLVector* velocityAngle){
	float JUMP_VELOCITY = getSetting()->player.jumpSpeed;

	velocityAngle->setY(-JUMP_VELOCITY);

	if(getStaticData()->m_CommonWork.m_Game.isCheat() == false){
		player->getJumpManager()->jump();
	}

	player->changeState(StateType::FLYUP);
}

void GPlayerManager::walkToStand(GPlayer* player, HPLVector* velocityAngle){
	//////////////////
	// 歩行中移動キーを話すと止まる


	bool right = player->isPressed(GEnum::KeyMap::RIGHT);
	bool left = player->isPressed(GEnum::KeyMap::LEFT);

	int st = player->getState()->getState();
	if((st == StateType::WALK ||
		st == StateType::WALK_READY ||

		st == StateType::STAND)&&
		right == false &&
		left == false)
	{

		/*if(player->isAutoCrouch(AUTO_CROUCH_HP_THRESHOLD, GEnum::KeyMap::A)){
			/////
			// ダメージ状態だとしゃがむ
			player->changeState(StateType::CROUCH);
		}else
		*/
		{
			player->changeState(StateType::STAND);
		}
	}

	//
	////////////

}

void GPlayerManager::crouch(GPlayer* player, HPLVector* velocityAngle){
	int st = player->getState()->getState();

	bool down = player->isPressed(GEnum::KeyMap::DOWN);
	///////////
	// 立ち中、ライフが残り30%以下なら座り込む
	/*if((st == StateType::STAND || st == StateType::BORING)&& player->isAutoCrouch(AUTO_CROUCH_HP_THRESHOLD, GEnum::KeyMap::A)){
			player->changeState(StateType::CROUCH);
	}else 
	*/
	if((st == StateType::STAND ||
		st == StateType::BORING ||
		st == StateType::WALK) &&

		down){
		////////
		// 下キーでしゃがむ

		player->changeState(StateType::CROUCH);

	}else{
		HPLSequence* seq = player->getSequence();

		if( //player->isAutoCrouch(AUTO_CROUCH_HP_THRESHOLD, GEnum::KeyMap::A) == false &&
			(st == StateType::CROUCH || st == StateType::BORING_CROUCH) &&
			seq->getState().isFinishAnimation &&
			down == false )
		{
			//////
			// しゃがみ状態で下キーを離した
			// 　→立ち上がる
			player->changeState(StateType::STAND);
		}
	}
}

static bool isHittable( GPlayer* lpPlayer, float* lpfSpeed, float* lpfDamage ) {
	if( lpPlayer->getType() == PlayerType::PESERU ) {
		if( lpPlayer->getState()->getState() == StateType::ATTACK_2 ) {
			// スライディング
			*lpfSpeed = PESERU_SLIDING_BLOW_SPEED;
			*lpfDamage = PESERU_SLIDING_DAMAGE;

			return true;
		}

	} else if( lpPlayer->getType() == PlayerType::DURANDANA ) {

		if( lpPlayer->getState()->getState() == StateType::ATTACK_GUN ) {
			// グランドタイパー
			*lpfSpeed = DURANDANA_GRAND_TIPER_BLOW_SPEED;
			*lpfDamage = DURANDANA_GRAND_TIPER_DAMAGE;

			return true;

		} else if( lpPlayer->getState()->getState() == StateType::ATTACK_2 ) {
			// KATANA
			*lpfSpeed = DURANDANA_ATTACK_2_BLOW_SPEED;
			*lpfDamage = DURANDANA_ATTACK_2_DAMAGE;

			return true;

		}
	} 
	return false;
}

bool GPlayerManager::checkHitToOnePlayer( GPlayer* lpPlayer, GPlayer* lpTargetPlayer ) {
	if( this->isSkipToSearch( lpPlayer, lpTargetPlayer ) ) {
		return false;
	}

	// ヒットする対象
	bool bIsHittable = false;


	float fSpeed = 0;
	float fDamage = 0;
	float fDummy = 0;
	if( isHittable( lpPlayer, &fSpeed, &fDamage ) ) {

		if( getStaticData()->m_CommonWork.isHit( lpPlayer, lpTargetPlayer ) == false ) {

			// 領域がかぶっていない
			return false;
		}

		// エフェクト生成
		GEffect* lpEffect = getStaticData()->m_CommonWork.createEffect(
			Sequence::Effect::HIT,
			lpPlayer->getCenter(),
			lpTargetPlayer->getCenter(), 0, -1 );
		if( isHittable( lpTargetPlayer, &fDummy, &fDummy ) ) {
			// 相打ち
			// 互いに吹っ飛ぶ

			// 吹っ飛びの速度は、ダメージ量によらない
			getStaticData()->m_CommonWork.blowAway( lpPlayer, lpTargetPlayer, TWO_PLAYER_BOTH_BLOW_AWAY_SPEED );
			getStaticData()->m_CommonWork.blowAway( lpTargetPlayer, lpPlayer, TWO_PLAYER_BOTH_BLOW_AWAY_SPEED );

			// ダメージ状態
			getStaticData()->m_CommonWork.changeState( lpPlayer, StateType::DAMAGE );
			getStaticData()->m_CommonWork.changeState( lpTargetPlayer, StateType::DAMAGE );


		} else {
			// ヒット
			getStaticData()->m_CommonWork.hitToPlayer( lpPlayer, lpTargetPlayer, fSpeed, fDamage );

		}
		return true;
	}

	return false;
}

void GPlayerManager::checkHitToPlayer( GPlayer* lpPlayer) {

	for( int i = 0; i < PLAYER_MAX_NUM; i ++ ) {
		this->checkHitToOnePlayer( lpPlayer, &getStaticData()->m_ObjectManager.m_aryPlayerList[i] );
	}

	for( list<GPlayer*>::iterator it = getStaticData()->m_ObjectManager.m_EnemyManager.getList()->begin();
		it != getStaticData()->m_ObjectManager.m_EnemyManager.getList()->end();
		it ++ )
	{
		this->checkHitToOnePlayer( lpPlayer, *it );
	}
}

