#include "CS_Boss_Arowana.h"
#include "CS_PeSmoke.h"
#include "CS_Exp.h"
#include "CS_PeWaterDrop.h"
#include "CS_FallRock_Locator.h"
#include "CS_PeGunShotHit.h"
#include "PeLightTail.h"
CS_Boss_Arowana::CS_Boss_Arowana()
{
	type = 2;
	ani.png = L"CS_CaveStoryMod";
	cbRect.enableCbRect = true;
	cbRect.enableSoild = true;
	//设置实体框
	cbRect.left = 24;
	cbRect.right = 24;
	cbRect.bottom = cbRect.top = 8;
	cbRect.fullWaterBlock = true;
	//生命
	hp_max = hp = 100;
	hp = 100;
	//攻击重启
	damage_reset_counter = 60;
	attackState_reset_counter_max = 60;
	caughtDifficulty = 0.8f;
	//忽略陷阱
	ignoreTrap = true;
	bSetLightTail = true;
}

void CS_Boss_Arowana::Init(std::weak_ptr<Entity> self)
{
	if (gameFunc->pGameOption_difficulty)
		if (*gameFunc->pGameOption_difficulty == 0)
			bNormalMode = true;
	stateGravity.Init(shared_from_this());
	stateResist.Init(shared_from_this());
	Entity::Init(self);
}

void CS_Boss_Arowana::SetState(int stateID, int lr)
{
	this->lr = lr;
	ani.sprite_index = lr == 0 ? L"ls_arowana_swim_l" : L"ls_arowana_swim_r";
	face = 3;
	AnimateStep();
}

void CS_Boss_Arowana::SetState(std::wstring stateName, int lr)
{
	if (stateName == L"set_player_type")
		type = 1;
	if (stateName == L"hide")
	{
		hide = true;
		auto wpeDizzy = peDizzy.lock();
		if (wpeDizzy)
			wpeDizzy->hide = true;
	}
	else if (stateName == L"lside")
		leftSide = lr;
	else if (stateName == L"rside")
		rightSide = lr;
}

void CS_Boss_Arowana::Step()
{
	if (cbRect.inWater)
		drawBeforeOtherEntity = false;
	else
		drawBeforeOtherEntity = true;
	if (hp == 0)
	{
		ani.sprite_index = lr == 0 ? L"ls_arowana_swim_l" : L"ls_arowana_swim_r";
		face = 2;
		bShowDizzy = true;
		cbRect.left = 24;
		cbRect.right = 24;
		cbRect.bottom = cbRect.top = 8;
		cbRect.enableSoild = true;
		AnimateStep();
		if (bCaught)
			return;
		stateGravity.Step();
		stateResist.Step();
		//清除最后一次碰撞结果
		Entity::ClearCollisionResult();
		//执行运动
		Entity::Step();
		//执行碰撞
		Entity::Collision();
		return;
	}
	if (bCaught)
	{
		vx = vy = 0;
		ani.sprite_index = lr == 0 ? L"ls_arowana_swim_l" : L"ls_arowana_swim_r";
		face = 1;
	}
	else
	{
		if (flee_counter > 0)
			flee_counter--;
		switch (stateID)
		{
		case 0://加速开始冲撞
			DashStep();
			break;
		case 1://落入水中
			FallToWaterStep();
			break;
		case 2://游泳
			SwimStep();
			break;
		case 3://跳跃阶段
			JumpStep();
			break;
		}
	}
	//限制移动范围
	if (leftSide >= 0)
	{
		if (x < leftSide * 16.0f)
			last_x = x = leftSide * 16.0f;
	}
	if (rightSide >= 0)
	{
		if (x > rightSide * 16.0f)
			last_x = x = rightSide * 16.0f;
	}
	//无敌帧
	if (flee_counter > 0)
	{
		if (flee_counter / 2 % 2 == 0)
			color = RGBA(0xff, 0xff, 0xff, 0x40);
		else
			color = RGBA(0xff, 0xff, 0xff, 0xc0);
	}
	else
	{
		color = RGBA(0xff, 0xff, 0xff, 0xff);
	}
	AnimateStep();
	//清除最后一次碰撞结果
	Entity::ClearCollisionResult();
	//执行运动
	Entity::Step();
	//执行碰撞
	Entity::Collision();
}

void CS_Boss_Arowana::Attack(std::weak_ptr<Entity> dst, int* outDamage, float* outAngle, bool* outTakedown, int* outElemType, float* outShockForce, float* outHeavy)
{
	if (hp == 0)
		return;
	if (hp > 20 || cbRect.inWater)
		*outDamage = 4;
	else
		return;
	auto wdst = dst.lock();
	if (wdst)
	{
		if (wdst->lr == 0)
		{
			*outAngle = 315;
		}
		else
		{
			*outAngle = 225;
		}
	}
	*outTakedown = true;
	*outElemType = 0;
	*outShockForce = 0x200 / ts;
	*outHeavy = 2;
}

bool CS_Boss_Arowana::Hurt(std::weak_ptr<Entity> src, int getDamage, float angle, bool bTakedown, int elemType, float shockForce, float heavy, int* outRealDamage)
{
	if (getDamage == 0)
		return false;
	if (elemType == 0)
	{
		if (getDamage < 5)
		{
			*outRealDamage = 0;
			return true;
		}
	}
	*outRealDamage = getDamage;
	shock_counter = 30;
	hp -= getDamage;
	if (hp > 0)
	{
		stateID = 1;
		gameFunc->PlaySound(L"CS_055_enemy_squeak2");
		//创建云团
		if (getDamage >= 20)
		{
			gameFunc->PlaySound(L"CS_071_little_crash");
			SetCS_PeSmokeMedium(shared_from_this(), x, y);
		}
	}
	else
	{
		gameFunc->PlaySound(L"CS_071_little_crash");
		//创建云团
		SetCS_PeSmokeMedium(shared_from_this(), x, y);
		hp = 0;
	}
	//显示伤害值
	if (gameFunc->dmgNum)
		gameFunc->SetDmgNum(gameFunc->dmgNum, getDamage, x, y - 16, 0, shared_from_this());
	return true;
}

std::weak_ptr<Entity> CS_Boss_Arowana::BeginCaught(std::weak_ptr<Entity> e)
{
	//避免两个玩家掉同一条鱼
	if (stateID != 2)
		return std::weak_ptr<Entity>();
	if (bCaught)
		return  std::weak_ptr<Entity>();
	if (flee_counter > 0)
		return  std::weak_ptr<Entity>();
	if (!cbRect.inWater)
		return  std::weak_ptr<Entity>();
	gameFunc->PlaySound(L"CS_055_enemy_squeak2");
	bCaught = true;
	return shared_from_this();
}

void CS_Boss_Arowana::EndCaught(std::weak_ptr<Entity> e)
{
	bCaught = false;
	flee_counter = 180;
}

void CS_Boss_Arowana::Destroy()
{
	auto wpeDizzy = peDizzy.lock();
	if (wpeDizzy)
		wpeDizzy->Destroy();
	Entity::Destroy();
}

void CS_Boss_Arowana::AnimateStep()
{
	auto wpeDizzy = peDizzy.lock();
	if (!wpeDizzy && gameFunc)
	{
		peDizzy = wpeDizzy = std::make_shared<CS_PeDizzy>(shared_from_this());
		gameFunc->SetEntity(shared_from_this(), wpeDizzy);
	}
	if (wpeDizzy)
		wpeDizzy->hide = !bShowDizzy;
	ani.hideLayerList.insert(0);
	ani.hideLayerList.insert(1);
	ani.hideLayerList.insert(2);
	ani.hideLayerList.insert(3);
	ani.hideLayerList.insert(4);
	ani.hideLayerList.insert(5);
	ani.hideLayerList.insert(6);

	ani.hideLayerList.insert(7);
	ani.hideLayerList.insert(8);
	ani.hideLayerList.insert(9);
	if (bShowSilkRibbon)
		ani.hideLayerList.erase(7);
	else
		ani.hideLayerList.insert(7);
	switch (face)
	{
	case 0://正常
		ani.hideLayerList.erase(4);
		ani.hideLayerList.erase(8);
		break;
	case 1://受伤
		ani.hideLayerList.erase(3);
		ani.hideLayerList.erase(9);
		break;
	case 2://眩晕
		ani.hideLayerList.erase(2);
		ani.hideLayerList.erase(9);
		break;
	case 3://生气
		ani.hideLayerList.erase(0);
		ani.hideLayerList.erase(1);
		ani.hideLayerList.erase(9);
		break;
	case 4://睡觉
		ani.hideLayerList.erase(5);
		ani.hideLayerList.erase(8);
		break;
	case 5://惊讶
		ani.hideLayerList.erase(6);
		ani.hideLayerList.erase(8);
		break;
	}
}

void CS_Boss_Arowana::DashStep()
{
	face = 3;
	float dashMaxSpeed = 0x900 / ts;
	float dashAcc = 0x80 / ts;
	if (bNormalMode)
	{
		float dashMaxSpeed = 0x600 / ts;
		float dashAcc = 0x40 / ts;
	}
	vy = 0;
	if (bSetLightTail)
	{
		bSetLightTail = false;
		SetLightTail();
	}
	//加速直到撞到墙壁
	if (lr == 0)
	{
		if (vx - dashAcc > -dashMaxSpeed)
			vx -= dashAcc;
		else
			vx = -dashMaxSpeed;
		if (cbRect.cbLeft && stateID == 0)
		{
			SetQuake();
			//切换到冲撞结束状态
			stateID = 1;
			vy = -0x400 / ts;
		}
	}
	else
	{
		if (vx + dashAcc < dashMaxSpeed)
			vx += dashAcc;
		else
			vx = dashMaxSpeed;
		if (cbRect.cbRight && stateID == 0)
		{
			SetQuake();
			//切换到冲撞结束状态
			stateID = 1;
			vy = -0x400 / ts;
		}
	}
	ani.sprite_index = lr == 0 ? L"ls_arowana_swim_l" : L"ls_arowana_swim_r";
}

void CS_Boss_Arowana::FallToWaterStep()
{
	//无视地形
	cbRect.enableSoild = false;
	//反弹跳跃
	if (lr == 0)
	{
		vx = 0x200 / ts;
	}
	else
	{
		vx = -0x200 / ts;
	}
	cbRect.left = 8;
	cbRect.right = 8;
	cbRect.bottom = cbRect.top = 24;
	if (vy < 0)
		stateGravity.SetGravityScale(0.4f);
	else
		stateGravity.SetGravityScale(1);
	stateGravity.Step();
	ani.sprite_index = lr == 0 ? L"ls_arowana_jump_l" : L"ls_arowana_jump_r";
	face = 0;
	//如果落入水中，跳转去游泳状态
	if (cbRect.inWater && cbRect.cbBottom)
	{
		stateID = 2;
		//左右互换
		lr = lr == 0 ? 1 : 0;
		SearchJumpPlace();
	}
}

void CS_Boss_Arowana::SwimStep()
{
	//游泳阶段
	cbRect.enableSoild = false;
	cbRect.left = 24;
	cbRect.right = 24;
	cbRect.bottom = cbRect.top = 8;
	vy = 0;
	int X = (int)(x / 16);
	int Y = (int)(y / 16);
	if (X == targetX)
	{
		if (Random(0, 100) < 50 && flee_counter == 0)
		{
			SearchJumpPlace();
		}
		else
		{
			//如果游到了目标，去跳跃阶段
			stateID = 3;
			cbRect.enableSoild = true;
		}
	}
	else
	{
		float speed = 0x500 / ts;
		if (bNormalMode)
			speed = 0x350 / ts;
		if (X > targetX)
			vx = -speed;
		else
			vx = speed;
		if (vx < 0)
			lr = 0;
		else
			lr = 1;
	}
	face = 0;
	ani.sprite_index = lr == 0 ? L"ls_arowana_swim_l" : L"ls_arowana_swim_r";
}

void CS_Boss_Arowana::JumpStep()
{
	cbRect.enableSoild = false;
	//取最近的玩家
	if (!gameFunc->GetPlayerDistance)
		return;
	auto wplayer = gameFunc->GetPlayerDistance(gameFunc->game, x, y).lock();
	if (!wplayer)
		return;
	//上升到和玩家一样的高度
	if (y > wplayer->y)
	{
		if (bNormalMode)
			vy = -0x400 / ts;
		else
			vy = -1800 / ts;
	}
	else
	{
		//上升到了这个高度
		//回到冲撞状态
		if (wplayer->x > x)
			lr = 1;
		else
			lr = 0;
		cbRect.enableSoild = true;
		stateID = 0;
		bSetLightTail = true;
	}
	vx = 0;
	ani.sprite_index = L"ls_arowana_waterjump";
}

void CS_Boss_Arowana::SetQuake()
{
	//屏幕震动
	gameFunc->PlaySound(L"CS_071_little_crash");
	SetCS_PeSmokeMedium(shared_from_this(), x, y);
	if (gameFunc->SetQuake)
		gameFunc->SetQuake(gameFunc->game, 30, 0);
	//下落石块
	//激活一次房间里所有的落石定位器
	auto& roomRes = *gameFunc->GetLoadedEntity(gameFunc->entityRes);
	std::list<std::shared_ptr<Entity>>* pLs = nullptr;
	for (auto& p : roomRes)
	{
		if (p.first->layerType == 0)
		{
			pLs = &p.second.Ls;
			break;
		}
	}
	if (pLs)
	{
		for (auto& e : *pLs)
		{
			if (e->el.name == CS_FALLROCK_LOCATOR_CREATENAME)
			{
				if (bNormalMode)
				{
					if (Random(0, 10) < 3)
						e->SetState(L"fallrock", 0);
				}
				else
					e->SetState(L"fallrock", 0);
			}
		}		
	}
}

void CS_Boss_Arowana::SearchJumpPlace()
{
	//玩家附近坐标左右垂直延展，和自己x位置进行直线测试
	targetX = -1;
	jumpX.clear();
	//1.随机挑选一个目标玩家
	std::weak_ptr<Entity> player;
	auto& allPlayer = *gameFunc->GetGlobalEntityTable(gameFunc->game);
	std::vector<std::weak_ptr<Entity>> tempArr;
	for (auto& p : allPlayer)
	{
		auto we = p.second.lock();
		if (we)
		{
			if (we->el.name.length() == 0)
				continue;
			if (we->el.name == L"null")
				continue;
			tempArr.push_back(we);
		}
	}
	if (tempArr.size() == 1)
	{
		player = tempArr.front();
	}
	else
	{
		int index = Random(0, (int)(tempArr.size() - 1));
		player = tempArr[index];
	}
	int mapW, mapH;
	gameFunc->GetMapSize(gameFunc->mapSizeGetter, &mapW, &mapH);
	//2.对该玩家的附近进行区域搜索
	//寻找玩家左侧的可跳跃区域
	auto wplayer = player.lock();
	if (wplayer)
	{
		int startPos = (int)(wplayer->x / 16);
		//和自己的相对x位置进行直线测试
		for (int X = startPos; X >= 0; X--)
			if (!gameFunc->LineTest(shared_from_this(), (float)X, y / 16, (float)X, wplayer->y / 16))//直线测试
				jumpX.push_back(X);
		//寻找玩家右侧的可跳跃区域
		for (int X = startPos; X < mapW; X++)
			if (!gameFunc->LineTest(shared_from_this(), (float)X, y / 16, (float)X, wplayer->y / 16))//直线测试
				jumpX.push_back(X);
	}
	//选一个离当前位置至少5格x距离的跳跃点
	for (auto X : jumpX)
		if (abs(X - x / 16) >= 5)
			targetX = X;
}

bool CS_Boss_Arowana::LightTail_Leave(std::weak_ptr<Entity> e)
{
	auto we = e.lock();
	if (we)
	{
		auto _this = std::static_pointer_cast<CS_Boss_Arowana>(we);
		return _this->stateID != 0;
	}
	return true;
}

void CS_Boss_Arowana::SetLightTail()
{
	//特效
	auto nE = std::make_shared<PeLightTail>(shared_from_this(), 80, 16);
	nE->SetLeaveFunc(&CS_Boss_Arowana::LightTail_Leave);
	gameFunc->SetEntity(shared_from_this(), nE);
}

std::shared_ptr<Entity> CreateCS_Boss_Arowana()
{
	return std::make_shared<CS_Boss_Arowana>();
}
