#include "CS_Kanpa.h"
#include "CS_PeSmoke.h"
#include "CS_PeLevelUp.h"
#include "CS_PeSweat.h"
#include "CS_Exp.h"
#include "CS_Heart.h"
#include <PeSmog.h>
CS_Kanpa::CS_Kanpa()
{
	type = 1;
	//初始动画设置
	ani.png = L"CS_CaveStoryMod";
	//启用碰撞
	cbRect.enableCbRect = true;
	cbRect.enableSoild = true;
	//设置碰撞框
	cbRect.left = cbRect.right = 5;
	cbRect.top = 6;
	cbRect.bottom = 8;
	//初始数值
	uiName = L"mimiga";
	saveName = CS_KANPA_CREATENAME;
	throwItem = 0;
	throwItem_max = 0;
	throwItem_type = 1;
	hp_max = 3;
	hp = 3;
	mp_max = 20;
	mp = 0;
}

void CS_Kanpa::Init(std::weak_ptr<Entity> self)
{
	//添加状态控制器（也是执行顺序）
	AddState(&stateFlash);
	AddState(&stateInvincible);
	AddState(&stateGravity);
	AddState(&stateWater);
	AddState(&stateDrown);
	AddState(&stateControl);
	AddState(&stateResist);//在stateControl后面
	AddState(&stateJump);
	AddState(&stateStand);
	AddState(&stateMove);
	AddState(&stateAir);
	AddState(&stateFaceToBack);
	AddState(&stateHurt);
	//添加技能
	AddSkill(&skillStepOn);
	AddSkill(&skillFishing);
	AddSkill(&skillGrapplingHook);
	//设置初始状态
	ChangeState(stateStand.GetStateID());
	//设置初始物理状态
	SetPhysice(false);
	//设置初始技能绑定
	SetSkillBindIndex(&skillFishing, 1);
	skillFishing.lock = false;
	/*SetSkillBindIndex(&skillGrapplingHook, 2);
	skillGrapplingHook.lock = false;*/
	stateStand.Step();
	AnimateStep();
	MyCharEntity::Init(self);
}

void CS_Kanpa::Step()
{
	//防止掉地图外面
	Entity::KeepInMap();
	//跟上移动平台
	Entity::BeginMovingPlatform();
	//图层动画
	AnimateStep();
	//检测被移动平台压死
	if (CheckCrush(&crushEvent))
		CrushDeath();
	//状态机
	if (stateID == 0 && type == 1)
	{
		//玩家控制
		for (auto& p : stateList)
			p->Step();
		if (atkFeedBack > 0)
			atkFeedBack--;
		else if (action_timecounter > 0)
			action_timecounter--;
	}
	else if (type == 0 || stateID != 0)
	{
		//动画
		switch (stateID)
		{
		case 0://站立
			stateStand.State();
			vx = 0;
			//重力
			stateGravity.State();
			break;
		case 1://走路
			stateMove.State();
			stateGravity.State();
			break;
		case 6://后跳
			for (auto& p : stateList)
				p->Step();
			break;
		case 7:
		case 8:
			vx = 0;
			vy = 0;
			break;
		case 9://吊钩动画
			vx = 0;
			vy = 0;
			break;
		case 10:
			stateResist.Step();
			break;
		case 11://庆祝
			vx = 0;
			if (cbRect.cbBottom)
				vy = -0x400 / ts;
			stateGravity.SetGravityScale(0.4f);
			stateGravity.State();
			break;
		case 12://结尾致辞动画
			vx = 0;
			stateGravity.State();
			break;
		}
	}
	//更新UI
	MyCharEntity::UpdateUI();
	//风场
	Entity::Wind();
	//跟上移动平台
	Entity::EndMovingPlatform();
	//清除最后一次碰撞结果
	Entity::ClearCollisionResult();
	//动画延迟一帧
	if (animation_delay)
		animation_delay = false;
	else
		Entity::Step();//执行运动
	//执行碰撞
	Entity::Collision();
	//维持在斜坡上
	Entity::KeepOnSlopes();
}

void CS_Kanpa::SetState(int stateID, int lr)
{
	if (stateID < 200)
	{
		this->stateID = stateID;
		this->lr = lr;
		//设置动画
		switch (stateID)
		{
		case 0://没有动画（恢复玩家控制）
			faceToBack = false;
			break;
		case 1://走路
			{
				animation_delay = true;
				if (lr == 0)
					vx = -animation_moveSpeed;
				else
					vx = animation_moveSpeed;
				stateMove.State();
				//重力
				stateGravity.State();
			}
			break;
		case 2://背对着
			vx = 0;
			ani.sprite_index = lr == 0 ? L"mc_kanpa_back_l" : L"mc_kanpa_back_r";
			//重力
			stateGravity.State();
			break;
		case 3://坐着
			vx = vy = 0;
			ani.sprite_index = lr == 0 ? L"mc_kanpa_sit_l" : L"mc_kanpa_sit_r";
			break;
		case 4://开始推动
			showSweat = true;
			face = 1;
			cbRect.enableMovePlatform = true;
			animation_delay = true;
			if (lr == 0)
				vx = -animation_moveSpeed / 4;
			else
				vx = animation_moveSpeed / 4;
			ani.sprite_index = lr == 0 ? L"mc_kanpa_push_l" : L"mc_kanpa_push_r";
			//重力
			stateGravity.State();
			break;
		case 5://结束推动
			showSweat = false;
			face = 0;
			cbRect.enableMovePlatform = false;
			stateID = 0;
			vx = 0;
			ani.sprite_index = lr == 0 ? L"mc_kanpa_stand_l" : L"mc_kanpa_stand_r";
			break;
		case 6://后跳
			vy = -2;
			if (lr == 0)//左
				vx = 1;
			else//右
				vx = -1;
			break;
		case 7://躺下
			ani.sprite_index = lr == 0 ? L"mc_kanpa_lie_l" : L"mc_kanpa_lie_r";
			break;
		case 8://向上看
			ani.sprite_index = lr == 0 ? L"mc_kanpa_stand_lu" : L"mc_kanpa_stand_ru";
			break;
		case 9://吊钩动画
			ani.sprite_index = L"mc_kanpa_hookani";
			ani.image_index = lr;
			break;
		case 10://翻倒
			ani.sprite_index = lr == 0 ? L"mc_kanpa_down_l" : L"mc_kanpa_down_r";
			vx = lr == 0 ? 0x800 / ts : -0x800 / ts;
			gameFunc->PlaySound(L"CS_070_expl_small");
			SetPeSmog(shared_from_this(), x, y, 1, 1, 135);
			SetPeSmog(shared_from_this(), x, y, 1, 1, 45);
			break;
		case 11://庆祝
			ani.sprite_index = lr == 0 ? L"mc_kanpa_cheer_l" : L"mc_kanpa_cheer_r";
			break;
		case 12://结尾致辞
			ani.sprite_index = lr == 0 ? L"mc_kanpa_move_l" : L"mc_kanpa_move_r";
			ani.image_counter_speed = 0.5f;
			break;
		}
	}
	else
	{
		//设置动画属性
		switch (stateID)
		{
		case 200://显示鱼竿
			showFishingRod = true;
			break;
		case 201://隐藏鱼竿
			showFishingRod = false;
			break;
		case 202://睁眼
			ani.image_index = 0;
			break;
		case 203://闭眼
			ani.image_index = 1;
			break;
		case 204://移动模式2
			moveMode = 1;
			break;
		case 205://移动模式1
			moveMode = 0;
			break;
		case 206://打开流汗
			showSweat = true;
			break;
		case 207://关闭流汗
			showSweat = false;
			break;
		case 208://默认脸
			face = 0;
			break;
		case 209://> <脸
			face = 1;
			break;
		}
	}
}

void CS_Kanpa::SetState(std::wstring stateName, int lr)
{
	if (hook_ani_set_target)
	{
		hook_ani_set_target = false;
		auto waniHook = aniHook.lock();
		if (waniHook)
		{
			auto& allRes = *gameFunc->GetLoadedEntity(gameFunc->entityRes);
			EntityLayer* eLayer = nullptr;
			for (auto& res : allRes)
			{
				if (res.first->layerType == 0)
				{
					eLayer = &res.second;
					break;
				}
			}
			if (eLayer)
			{
				bool bFound = false;
				//在全局实体里寻找
				auto& allPlayer = *gameFunc->GetGlobalEntityTable(gameFunc->game);
				for (auto& p : allPlayer)
				{
					auto wplayer = p.second.lock();
					if (wplayer && wplayer->el.name == stateName)
					{
						waniHook->HookSetTarget(wplayer);
						bFound = true;
						break;
					}
				}
				//在地图实体层里寻找
				if (!bFound)
				{
					for (auto& e : eLayer->Ls)
					{
						if (e->el.eventName == stateName)
						{
							waniHook->HookSetTarget(e);
							break;
						}
					}
				}
			}
		}
	}
	else
	{
		MyCharEntity::SetState(stateName, lr);
		if (stateName == L"show_sweat")
			SetState(206, lr);
		else if (stateName == L"hide_sweat")
			SetState(207, lr);
		else if (stateName == L"normal_face")
			face = 0;
		else if (stateName == L"> <_face")
			face = 1;
		else if (stateName == L"normal")
			SetState(0, lr);
		else if (stateName == L"back")
			SetState(2, lr);
		else if (stateName == L"sit")
			SetState(3, lr);
		else if (stateName == L"start_push")
			SetState(4, lr);
		else if (stateName == L"end_push")
			SetState(5, lr);
		else if (stateName == L"MYB")
			SetState(6, 0);
		else if (stateName == L"walk")
			SetState(1, lr);
		else if (stateName == L"lie")
			SetState(7, lr);
		else if (stateName == L"up_look")
			SetState(8, lr);
		else if (stateName == L"hook_ani")
			SetState(9, lr);
		else if (stateName == L"down")
			SetState(10, lr);
		else if (stateName == L"cheer")
			SetState(11, lr);
		else if (stateName == L"hook_ani_throw")
		{
			auto waniHook = std::make_shared<CS_KanpaAniHook>(shared_from_this());
			aniHook = waniHook;
			gameFunc->SetEntity(shared_from_this(), waniHook);
		}
		else if (stateName == L"hook_ani_set_target")
		{
			hook_ani_set_target = true;
		}
		else if (stateName == L"hook_finish")
		{
			auto waniHook = aniHook.lock();
			if (waniHook)
				waniHook->Leave();
			aniHook.reset();
		}
		else if (stateName == L"show_fishing_rod")
			SetState(200, lr);
		else if (stateName == L"hide_fishing_rod")
			SetState(201, lr);
		else if (stateName == L"open_the_eyes")
			SetState(202, lr);
		else if (stateName == L"close_the_eyes")
			SetState(203, lr);
		else if (stateName == L"grappling_hook")
		{
			SetSkillBindAdd(&skillGrapplingHook);
			skillGrapplingHook.lock = false;
		}
		else if (stateName == L"dx")
			x += lr;
		else if (stateName == L"credit_walk")
			SetState(12, lr);
		else if (stateName == L"topdraw")
			topDraw = lr != 0;
	}
}

void CS_Kanpa::LoadSaveData()
{
	MyCharEntity::LoadSaveData();
	//读取移动模式
	showFishingRod = std::stoi(gameFunc->ReadData(CS_KANPA_CREATENAME, L"showFishingRod", L"0")) != 0;
	moveMode = std::stoi(gameFunc->ReadData(CS_KANPA_CREATENAME, L"moveMode", L"0"));
}

void CS_Kanpa::WriteSaveData()
{
	MyCharEntity::WriteSaveData();
	//写入移动模式
	gameFunc->WriteData(CS_KANPA_CREATENAME, L"showFishingRod", std::to_wstring(showFishingRod ? 1 : 0).c_str());
	gameFunc->WriteData(CS_KANPA_CREATENAME, L"moveMode", std::to_wstring(moveMode).c_str());
}

bool CS_Kanpa::Hurt(std::weak_ptr<Entity> src, int getDamage, float angle, bool bTakedown, int elemType, float shockForce, float heavy, int* outRealDamage)
{
	//运行事件时，无敌状态
	if (gameFunc->ScriptIsRunning)
	{
		if (gameFunc->ScriptIsRunning(gameFunc->gameScript))
			return false;
	}
	//状态处理
	for (auto& p : stateList)
	{
		bool retVal = true;
		if (p->Hurt(src, &getDamage, &angle, &bTakedown, &elemType, &shockForce, &heavy, outRealDamage, &retVal))
			return retVal;
	}
	//技能处理
	for (auto& p : skillList)
	{
		bool retVal = true;
		if (p->Hurt(src, &getDamage, &angle, &bTakedown, &elemType, &shockForce, &heavy, outRealDamage, &retVal))
			return retVal;
	}
	if (getDamage == 0)
		return false;
	*outRealDamage = getDamage;
	stateInvincible.SetDamage(getDamage);
	hp -= getDamage;
	if (hp > 0)
	{
		gameFunc->PlaySound(L"CS_050_mimiga_squeak");
		//触发等级下降
		if ((mp >= 10 && mp - 2 * getDamage < 10) ||
			(mp >= 5 && mp - 2 * getDamage < 5))
			SetCS_PeLevelDown(shared_from_this(), x, y);
	}
	else
	{
		//创建云团
		SetCS_PeSmokeMedium(shared_from_this(), x, y);
		hp = 0;
		UpdateUI();
		//游戏结束
		hide = true;
		//设置
		if (gameFunc->StartEvent)
		{
			gameFunc->PlaySound(L"CS_017_quote_die");
			gameFunc->StopMusic();
			gameFunc->StartEvent(gameFunc->gameScript, L"Died", L"tDeath");
		}
	}
	//掉经验
	mp -= 2 * getDamage;
	if (mp < 0)
		mp = 0;
	//伤害冲击处理
	if (shockForce > 0)
	{
		//被攻击弹反
		float radian = angle * deg2rad;
		vx = shockForce * cosf(radian);
		vy = shockForce * sinf(radian);
		vy -= 1;
	}
	//设置闪光
	stateFlash.flash_counter = 5;
	//显示伤害值
	if (gameFunc->dmgNum)
		gameFunc->SetDmgNum(gameFunc->dmgNum, getDamage, x, y - 16, 1, shared_from_this());
	//转换状态
	ChangeState(stateHurt.GetStateID());
	return true;
}

void CS_Kanpa::Gain(std::weak_ptr<Entity> item)
{
	auto witem = item.lock();
	if (!witem)
		return;

	//拾取到了经验
	if (witem->el.name == CS_EXP_CREATENAME && witem->inUsing)
	{
		//Mp条闪烁
		if (gameFunc->GetPlayerIndex)
		{
			int playerIndex = gameFunc->GetPlayerIndex(gameFunc->game, shared_from_this());
			if (playerIndex >= 0)
			{
				auto& ui = *gameFunc->GetPlayerUIData(gameFunc->gameUI, playerIndex);
				ui.MpBar_flash_counter = 30;
			}
		}
		//触发等级上升
		if ((mp < 5 && mp + witem->dropExp >= 5) ||
			(mp < 10 && mp + witem->dropExp >= 10))
			SetCS_PeLevelUp(shared_from_this(), x, y);
		mp += witem->dropExp;
		if (mp > mp_max)
			mp = mp_max;
		gameFunc->PlaySound(L"CS_014_get_xp");
		//显示经验值
		if (gameFunc->dmgNum)
			gameFunc->SetDmgNum(gameFunc->dmgNum, witem->dropExp, x, y - 16, 3, shared_from_this());
		witem->Destroy();
	}
	//拾取到了生命
	else if (witem->el.name == CS_HEART_CREATENAME && witem->inUsing)
	{
		//生命恢复
		hp += witem->hp;
		if (hp > hp_max)
			hp = hp_max;
		gameFunc->PlaySound(L"CS_020_health_refill");
		witem->Destroy();
	}
}

void CS_Kanpa::GetCameraPos(float* outX, float* outY)
{
	auto wfishhook = skillFishing.fishhook.lock();
	if (wfishhook)
	{
		*outX = wfishhook->x;
		*outY = wfishhook->y;
	}
	else
	{
		*outX = x;
		*outY = y;
	}
}

void CS_Kanpa::GetIcon(std::wstring& png, std::wstring& sprite_index, int& image_index, std::set<int>& hideLayerList)
{
	png = L"CS_CaveStoryMod";
	sprite_index = L"mc_kanpa_stand_r";
	image_index = 0;
	hideLayerList = ani.hideLayerList;
}

void CS_Kanpa::CrushDeath()
{
	//创建云团
	SetCS_PeSmokeMedium(shared_from_this(), x, y);
	hp = 0;
	UpdateUI();
	//游戏结束
	hide = true;
	//游戏结束
	if (gameFunc->StartEvent)
	{
		gameFunc->PlaySound(L"CS_017_quote_die");
		gameFunc->StopMusic();
		if (crushEvent.length())
			gameFunc->StartEvent(gameFunc->gameScript, crushEvent.c_str(), L"tCrush");
		else
			gameFunc->StartEvent(gameFunc->gameScript, L"DeathByMovingPlatform", L"tCrush");
	}
}

void CS_Kanpa::AnimateStep()
{
	ani.hideLayerList.insert(0);
	ani.hideLayerList.insert(1);
	ani.hideLayerList.insert(2);
	ani.hideLayerList.insert(3);
	ani.hideLayerList.insert(4);
	ani.hideLayerList.insert(5);
	if(moveMode == 0)
		ani.hideLayerList.erase(3);
	else
		ani.hideLayerList.erase(4);
	if (showFishingRod)
	{
		ani.hideLayerList.erase(0);
		ani.hideLayerList.erase(5);
	}
	if(face == 0)
		ani.hideLayerList.erase(1);
	else
		ani.hideLayerList.erase(2);
	if (showSweat)
	{
		if (showSweat_counter == 0)
		{
			SetCS_PeSweat(shared_from_this());
			showSweat_counter = showSweat_counter_max;
		}
		if (showSweat_counter > 0)
			showSweat_counter--;
	}
}

std::shared_ptr<Entity> CreateCS_Kanpa()
{
	return std::make_shared<CS_Kanpa>();
}
