/*
			SCRIPT FOR Dodge MOD FOR TES V: SKYRIM
					BY tktk

					REQUIRES SKYRIM SCRIPT DRAGON BY:

					(C) Alexander Blade 2011
				http://Alexander.SannyBuilder.com
*/

#include "common\skyscript.h"
#include "common\obscript.h"
#include "common\types.h"
#include "common\enums.h"
#include "common\plugin.h"
#include "grutils.h"

#define CONFIG_FILE "dodge.ini"
#define ESP_NAME "dodge.esp"

// NotWorkingUserMode＝true Normal=false
bool NotWorkMode=false;

// 新規スペル取得
namespace ID_SpellItem
{	
	enum {
		aaaTKDodgeSpellEthereal = 0x0000182A
	};
}

// 新規マジックエフェクト取得
namespace ID_EffectSetting
{	
	enum {
		aaaTKDodgeEthereal = 0x00001829
	};
}

// アニメーションID
namespace ID_TESIdleForms
{
    enum {
//ノットワーク版 既存ID置き換え
		CiceroDance1 = 0x000F7C8A,
		CiceroDance2 = 0x000F7C8B,
		CiceroDance3 = 0x00103653,
		CiceroHappy  = 0x00103654,
		TestLooseIdle= 0x00014308,
//通常版　新規ID　
		DodgeBack	 = 0x00000D62,
		DodgeLeft	 = 0x00000D63,
		DodgeRight	 = 0x00000D64,
		DodgeForward = 0x00003316,
		AttackStop	 = 0x00003DDB,
//共通 既存ID
		SneakStart	 = 0x0002F3F8,
		SneakStop	 = 0x0002F3F9

    };
}

// キーコード
static BYTE grActionKey;
static BYTE grBackKey;
static BYTE grRightKey;
static BYTE grLeftKey;
static BYTE grForwardKey;
// KeyCommandMode Both = 0 ActionKey Only = 1 Doubletap Only = 2
static BYTE CommandMode;
static BYTE SpendStamina;


// 回避方向
enum Direction {
	drBack,
	drLeft,
	drRight,
	drForward,
};

// イベントステータス
enum EventStatus {
	EV_None,			// 何もなし
	EV_ActBack,			// 後回避（アクションキー）
	EV_ActLeft,			// 左回避（アクションキー）
	EV_ActRight,		// 右回避（アクションキー）
	EV_DTapBack,		// 後回避（ダブルタップ）
	EV_DTapLeft,		// 左回避（ダブルタップ）
	EV_DTapRight,		// 右回避（ダブルタップ）
	EV_DTapForward,		// 前回避（ダブルタップ）
};

static bool init(void)
{
	bool ret = false;
	SpendStamina = IniReadInt(CONFIG_FILE, "main", "SpendStamina", 0);
	CommandMode = IniReadInt(CONFIG_FILE, "main", "CommandMode", 0);
	grActionKey = IniReadInt(CONFIG_FILE, "main", "ActionKey", 0);
	grBackKey	= IniReadInt(CONFIG_FILE, "main", "BackKey", 0);
	grRightKey	= IniReadInt(CONFIG_FILE, "main", "RightKey", 0);
	grLeftKey	= IniReadInt(CONFIG_FILE, "main", "LeftKey", 0);
	grForwardKey	= IniReadInt(CONFIG_FILE, "main", "ForwardKey", 0);
	// ESPファイルがロードオーダーにちゃんと含まれているかチェック
	ret = GRLoadOrder::Initialize();
		if (ret && (GRLoadOrder::GetOrderNoFromName(ESP_NAME) > 0)) {
		ret = true;
	}
	return ret;
}

//
// 回避アクション実行
//
static void DoDodgeAction(Direction dir)
{
	uint spellID;
	uint formID;
	uint forwardID;
	uint magicID;
	uint silentrollID =ID_BGSPerk::SilentRoll ;	 
	uint sneakstopID = ID_TESIdleForms::SneakStop;
	uint sneakID = ID_TESIdleForms::SneakStart ;
	CActor *player = Game::GetPlayer();
	TESObjectREFR *oplayer = (TESObjectREFR * ) Game::GetPlayer();
	BGSPerk *silentroll = (BGSPerk *)dyn_cast(Game::GetFormById(silentrollID), "TESForm", "BGSPerk");
	TESIdleForm *sneak = (TESIdleForm *)dyn_cast(Game::GetFormById(sneakID), "TESForm", "TESIdleForm");
	TESIdleForm *sneakstop = (TESIdleForm *)dyn_cast(Game::GetFormById(sneakstopID), "TESForm", "TESIdleForm");
	bool animflag;
//　ノットワーキング版の挙動
	if(NotWorkMode == true){
		switch(dir) {
			case drBack:	formID = ID_TESIdleForms::CiceroDance1; break;
			case drLeft:	formID = ID_TESIdleForms::CiceroDance2; break;
			case drRight:	formID = ID_TESIdleForms::CiceroDance3; break;
			case drForward:	forwardID = ID_TESIdleForms::CiceroHappy; break;
					}
			uint attackstopID = ID_TESIdleForms::TestLooseIdle;
			magicID = ID_EffectSetting::TestPolymorphSkeeverEffect;
			spellID = ID_SpellItem::PolymorphSkeever;
			SpellItem *Spellethereal = (SpellItem *)dyn_cast(Game::GetFormById(spellID), "TESForm", "SpellItem");
			EffectSetting *Magicethereal = (EffectSetting *)dyn_cast(Game::GetFormById(magicID), "TESForm", "EffectSetting");
			TESIdleForm *anim = (TESIdleForm *)dyn_cast(Game::GetFormById(formID), "TESForm", "TESIdleForm");
			TESIdleForm *fanim = (TESIdleForm *)dyn_cast(Game::GetFormById(forwardID), "TESForm", "TESIdleForm");
			TESIdleForm *attackstop = (TESIdleForm *)dyn_cast(Game::GetFormById(attackstopID), "TESForm", "TESIdleForm");

		if( dir == 3 && Actor::HasPerk(player, silentroll) == true && Actor::IsSneaking(player) == false ){
			Actor::PlayIdle(player, sneak);
			animflag =	Actor::PlayIdle(player, fanim);
			Actor::PlayIdle(player, sneakstop);
		} 
		else{
			Actor::PlayIdle(player, attackstop);
			animflag = Actor::PlayIdle(player, anim);

		}
// スタミナ消費と無敵化の処理	条件文が完璧でなくてpapyrusログでスタックしてしまう。
		if(Actor::HasMagicEffect(player,Magicethereal) == false && animflag == true){
			Actor::DamageActorValue(player, "Stamina", SpendStamina);
			Spell::Cast(Spellethereal, oplayer, oplayer);
		}	
		Wait(0);
	}
//通常版
	if(NotWorkMode == false){
		switch(dir) {
			case drBack:	formID = ID_TESIdleForms::DodgeBack; break;
			case drLeft:	formID = ID_TESIdleForms::DodgeLeft; break;
			case drRight:	formID = ID_TESIdleForms::DodgeRight; break;
			case drForward:	forwardID = ID_TESIdleForms::DodgeForward; break;
					}
			uint attackstopID = ID_TESIdleForms::AttackStop;
			magicID = ID_EffectSetting::aaaTKDodgeEthereal;
			spellID = ID_SpellItem::aaaTKDodgeSpellEthereal;
			EffectSetting *Magicethereal = (EffectSetting *)dyn_cast(GRLoadOrder::GetExtraFormByID(magicID, ESP_NAME, false), "TESForm", "EffectSetting");
			SpellItem *ethereal = (SpellItem *)dyn_cast(GRLoadOrder::GetExtraFormByID(spellID, ESP_NAME, false), "TESForm", "SpellItem");
			TESIdleForm *anim = (TESIdleForm *)dyn_cast(GRLoadOrder::GetExtraFormByID(formID, ESP_NAME, false), "TESForm", "TESIdleForm");
			TESIdleForm *fanim = (TESIdleForm *)dyn_cast(GRLoadOrder::GetExtraFormByID(forwardID, ESP_NAME, false), "TESForm", "TESIdleForm");
			TESIdleForm *attackstop = (TESIdleForm *)dyn_cast(GRLoadOrder::GetExtraFormByID(attackstopID, ESP_NAME, false), "TESForm", "TESIdleForm");
// 前転の部分
		if( dir == 3 && Actor::HasPerk(player, silentroll) == true && Actor::IsSneaking(player) == false) {
			Actor::PlayIdle(player, sneak);
			animflag = Actor::PlayIdle(player, fanim);
			Actor::PlayIdle(player, sneakstop);
		} 
		else{
// 魔法の部分
//			int magicL = Actor::GetEquippedItemType(player, 0);
			SpellItem *spellLeft = Actor::GetEquippedSpell(player, 0);
			Actor::UnequipSpell(player, spellLeft , 0) ;
			Actor::PlayIdle(player, attackstop);
			animflag = Actor::PlayIdle(player, anim);
//			Actor::EquipSpell(player, spellLeft, 0); 

		}
// スタミナ消費と無敵化の処理	条件文が完璧でなくてpapyrusログでスタックしてしまう。
		if(Actor::HasMagicEffect(player,Magicethereal) == false && animflag == true ){
			Actor::DamageActorValue(player, "Stamina", SpendStamina);
			Spell::Cast(ethereal, oplayer, oplayer);
		}
			Wait(0);
	}
	
}


//
// イベントステータス取得
//
EventStatus GetEventStatus(void)
{

	// ダブルタップ関連変数
	static BYTE DTapKey1 = 0;
	static BYTE DTapKey2 = 0;
	static BYTE ReleasedKey = 0;
	static DWORD DTapStart = 0;

	// イベント
	EventStatus ev = EV_None;

	if (GetKeyPressed(grActionKey) && (CommandMode == 0 || CommandMode==1) ) {

		// 回避キーが押された場合
		if (GetKeyPressed(grLeftKey)) {
			ev = EV_ActLeft;
		} else if (GetKeyPressed(grRightKey)) { 
			ev = EV_ActRight;
		} else if (GetKeyPressed(grBackKey)) {
			ev = EV_ActBack;
		}
		// ダブルタップ判定用変数のリセットを誘発
		DTapStart = 0;

	} else if (DTapKey1 && (DTapKey1 == ReleasedKey) && (ReleasedKey == DTapKey2) && (CommandMode==0 || CommandMode==2) ) {

		// ダブルタップの場合
		if (DTapKey1 == grBackKey) {
			ev = EV_DTapBack;
		} else if (DTapKey1 == grLeftKey) {
			ev = EV_DTapLeft;
		} else if (DTapKey1 == grRightKey) {
			ev = EV_DTapRight;
		}
		else if (DTapKey1 == grForwardKey) {
			ev = EV_DTapForward;
		}
		// ダブルタップ判定用変数のリセットを誘発
		DTapStart = 0;

// PrintNote("Double Tap");
	}

	// タイマーが500ミリ秒を超えたらダブルタップ関連変数リセット
	if ((GetTickCount() - DTapStart) > 500) {
		DTapKey1 = DTapKey2 = ReleasedKey = 0;
		DTapStart = 0;
	}

	// ダブルタップ判定用変数の設定
	// キー押下状態によって DTapKey1 -> ReleaseKey -> DTapKey2 の順で値が入る
	// 複数キー同時押しでも、後回避のキーを優先する
	if (!DTapKey1) {
		if (GetKeyPressed(grLeftKey))	DTapKey1 = grLeftKey;
		if (GetKeyPressed(grRightKey))	DTapKey1 = grRightKey;
		if (GetKeyPressed(grBackKey))	DTapKey1 = grBackKey;
		if (GetKeyPressed(grForwardKey))	DTapKey1 = grForwardKey;
		// タイマースタート
		if (DTapKey1)	DTapStart = GetTickCount();
// if (DTapStart)	PrintNote("DTap1 : %s", GetKeyName(DTapKey1).c_str());
	} else if (!ReleasedKey) {
		if (!GetKeyPressed(DTapKey1))	ReleasedKey = DTapKey1;
// if (ReleasedKey)	PrintNote("Release : %s", GetKeyName(ReleasedKey).c_str());
	} else if (!DTapKey2) {
		if (GetKeyPressed(DTapKey1))	DTapKey2 = DTapKey1;
// if (DTapKey2)	PrintNote("DTap2 : %s", GetKeyName(DTapKey2).c_str());
	}

	return ev;
}

//
// イベントディスパッチ
//
static bool Dispatch(EventStatus status)
{
	switch(status) {
	case EV_ActBack:
	case EV_DTapBack:		DoDodgeAction(drBack); return true;
	case EV_ActLeft:
	case EV_DTapLeft:		DoDodgeAction(drLeft); return true;
	case EV_ActRight:
	case EV_DTapRight:		DoDodgeAction(drRight); return true;
	case EV_DTapForward:	DoDodgeAction(drForward); return true;
	}
	return false;
}

void main()
{
	if (!init())	return;
	if(CommandMode == 0 ){	PrintNote("TK Dodge Lanched. Use Actionkey: '%s' or DoubleTapping", GetKeyName(grActionKey).c_str());}
	if(CommandMode == 1 ){	PrintNote("TK Dodge Lanched. Use Actionkey: '%s'", GetKeyName(grActionKey).c_str());}
	if(CommandMode == 2 ){	PrintNote("TK Dodge Lanched. Use DoubleTapping DirectionKey");}
	while (true) {
		Dispatch(GetEventStatus());
		Wait(0);
	}
}