#include "GameScript.h"
#include "Entity.h"
#include "GameInput.h"
#include "GameMap.h"
#include "EntityRes.h"
#include "GameFade.h"
#include "MyCamera.h"
#include "ScriptCmd.h"
#include "GameMsgbox.h"
#include "MyGame.h"
#include "main.h"
void GameScript::Init(MyGame* pGame)
{
    this->pGame = pGame;
    this->globalEntity = &pGame->globalEntity;
    this->pGameMap = &pGame->gameMap;
    this->pEntityRes = &pGame->entityRes;
    this->pGameFade = &pGame->gameFade;
    this->pMyCamera = &pGame->myCamera;
    this->pGameMsgbox = &pGame->gameMsgbox;
    scriptL_ptr = pGameMap->GetScriptLPtr();
}

void GameScript::EachNOD(bool bEachNOD, int targetNOD_playerIndex)
{
    this->bEachNOD = bEachNOD;
    this->targetNOD_playerIndex = targetNOD_playerIndex;
}

bool GameScript::IsRunning()
{
    return !eventStack.empty();
}

void GameScript::StartEvent(const wchar_t* eventName, const wchar_t* triggerType)
{
    //检查列表里是否已经有相同的事件
    bool bPush = true;
    for (auto& p : eventStack)
    {
        if (p.eventName == eventName)
        {
            bPush = false;
            break;
        }
    }
    if (bPush)
    {
        EventInfo info;
        info.eventName = eventName;
        info.triggerType = triggerType;
        eventStack.push_back(info);
        cmd_W99 = false;
    }
}

void GameScript::EndEvent()
{
    if (bTRA)
        return;
    cmd_PRI = false;
    cmd_KEY = false;
    cmd_WAI = 0;
    mainGameCmd->GIT();
    if (!eventStack.empty())
        eventStack.pop_back();
    if (cmd_W99)
        pGameMsgbox->TUR(false);
    else
        pGameMsgbox->EndEvent();
}

void GameScript::TRA(const wchar_t* mapName, const wchar_t* eventName)
{
    bTRA = true;
    mapTRA = mapName;
    eventStack.back().eventName = eventName;
    for (auto& wplayer : *globalEntity)
        wplayer->faceToBackEnd = true;
   /* if (cmd_PRI)
        cmd_KEY = true;*/
    cmd_PRI = false;
    cmd_KEY = false;
}

void GameScript::Step()
{
    if (eventStack.empty() || //如果脚本没有在运行
        cmd_WAS || //如果处于等待所有玩家落地
        pGameFade->GetFadeIn() || //如果还有玩家在渐入状态中
        pGameFade->GetFadeOut())
        return;
    //阻止玩家快进文本时跳过NOD
    if (NOD_block)
        PreventJumpNOD();
    //等待玩家选择YesNo
    if (cmd_YNJ)
    {
        if (YesNoControl())
            return;
    }
    //文本框等待键盘继续响应
    if (cmd_NOD)
    {
        if (NOD_block)
            return;
        //NOD被打开
        if (NODStep())
            return;
    }
    //等待计时器
    if (cmd_WAI > 0)
    {
        cmd_WAI--;
        return;
    }
    do
    {
        lua_State* scriptL = *scriptL_ptr;
        bTRA = false;
        //运行事件
        if (!eventStack.back().eventName.length())
        {
            eventStack.pop_back();
            return;
        }
        if (!bYield)
        {
            UTF16ToUTF8(eventStack.back().eventName.c_str(), &utf8);
            lua_getglobal(scriptL, utf8.data());
        }
        auto res = lua_resume(scriptL, nullptr, 0);
        if (res == LUA_YIELD)
        {
            bYield = true;
        }
        if (res != LUA_OK && res != LUA_YIELD)
        {
            std::string err = lua_tostring(scriptL, -1);
            UTF8ToUTF16(err.c_str(), &wbuff);
            wchar_t title[MAX_PATH];
            swprintf_s(title, L"脚本发生错误%s", pGameMap->GetMapFileName().c_str());
            MessageBox(hwnd, wbuff.data(), title, MB_ICONWARNING);
            lua_pop(scriptL, 1);

            for (auto& wplayer : *globalEntity)
                wplayer->faceToBackEnd = true;
            EndEvent();
        }
        if (res == LUA_OK)
        {
            bYield = false;
            if (bTRA)//载入新地图
            {
                pGameMap->LoadMap(mapTRA.c_str());
                //立即切换镜头
                pMyCamera->FocusOnce();
                //立即加载地图数据
                for (auto& layer : *pGameMap->GetLayerList())
                {
                    if (!layer.visible)
                        continue;
                    pEntityRes->LoadLayer(&layer);
                }
            }
            for (auto& wplayer : *globalEntity)
                wplayer->faceToBackEnd = true;
            EndEvent();
        }
    } while (bTRA);
    
}

void GameScript::SetWait(int wait)
{
    if (wait < 0)
        wait = 0;
    cmd_WAI = wait;
}

bool GameScript::GetNOD()
{
    return cmd_NOD;
}

void GameScript::SetNOD(bool nod)
{
    cmd_NOD = nod;
}

bool GameScript::GetPRI()
{
    return cmd_PRI;
}

void GameScript::SetPRI(bool pri)
{
    cmd_PRI = pri;
}

bool GameScript::GetKEY()
{
    return cmd_KEY;
}

void GameScript::SetKEY(bool key)
{
    cmd_KEY = key;
}

void GameScript::Reset()
{
    eventStack.clear();
    cmd_PRI = false;
    cmd_KEY = false;
    cmd_WAS = false;
    cmd_NOD = false;
    cmd_YNJ = false;
    cmd_WAI = 0;
    cmd_W99 = false;
    bTRA = false;
    NOD_block = false;
    pGameMsgbox->EndEvent();
}

void GameScript::SetWAS(bool was)
{
    if (was)
    {
        cmd_WAS = true;
        cmd_PRI = false;
    }
    else
    {
        cmd_WAS = false;
    }
}

void GameScript::SetYNJ()
{
    PlaySound(L"YNJ");
    pGameMsgbox->YNJ();
    cmd_YNJ = true;
    bYes = true;
    if (bEachNOD)
    {
        std::weak_ptr<Entity> players[2];
        players[0] = pEntityRes->GetMyChar_Player1();
        players[1] = pEntityRes->GetMyChar_Player2();
        auto wplayer = players[targetNOD_playerIndex].lock();
        if (wplayer)
        {
            wplayer->input.SetOk(false);
            wplayer->inputLock.SetOk(true);
        }
    }
    else
    {
        for (auto& wplayer : *globalEntity)
        {
            wplayer->input.SetOk(false);
            wplayer->inputLock.SetOk(true);
        }
    }
}

bool GameScript::GetYES()
{
    return bYes;
}

void GameScript::SetW99(bool w99)
{
    cmd_W99 = w99;
    if (w99)
    {
        if (bEachNOD)
        {
            std::weak_ptr<Entity> players[2];
            players[0] = pEntityRes->GetMyChar_Player1();
            players[1] = pEntityRes->GetMyChar_Player2();
            auto wplayer = players[targetNOD_playerIndex].lock();
            if (wplayer)
            {
                wplayer->input.SetOk(false);
                wplayer->inputLock.SetOk(true);
            }
        }
        else
        {
            for (auto& wplayer : *globalEntity)
            {
                wplayer->input.SetOk(false);
                wplayer->inputLock.SetOk(true);
            }
        }
    }
}

bool GameScript::GetW99()
{
    return cmd_W99;
}

void GameScript::SetNODBlock()
{
    NOD_block = true;
}

const wchar_t* GameScript::GetTriggerType()
{
    return triggerType.c_str();
}

void GameScript::SetCheckEntity(std::weak_ptr<Entity> e)
{
    checkEntity = e;
}

std::weak_ptr<Entity> GameScript::GetCheckEntity()
{
    return checkEntity;
}

void GameScript::SetCheckItemIndex(int itemIndex)
{
    checkItemIndex = itemIndex;
}

int GameScript::GetCheckItemIndex()
{
    return checkItemIndex;
}

void GameScript::PreventJumpNOD()
{
    if (bEachNOD)
    {
        std::weak_ptr<Entity> players[2];
        players[0] = pEntityRes->GetMyChar_Player1();
        players[1] = pEntityRes->GetMyChar_Player2();
        auto wplayer = players[targetNOD_playerIndex].lock();
        bool bPress = false;
        if (wplayer)
        {
            if (wplayer->input.GetOk())
                bPress = true;
        }
        if (!bPress)
            NOD_block = false;
    }
    else
    {
        bool bPress = false;
        for (auto& wplayer : *globalEntity)
        {
            if (wplayer->input.GetOk())
                bPress = true;
        }
        if (!bPress)
            NOD_block = false;
    }
}

bool GameScript::YesNoControl()
{
    bool bRet = true;
    if (bEachNOD)
    {
        std::weak_ptr<Entity> players[2];
        players[0] = pEntityRes->GetMyChar_Player1();
        players[1] = pEntityRes->GetMyChar_Player2();
        auto wplayer = players[targetNOD_playerIndex].lock();
        if (wplayer)
        {
            if (wplayer->enableAI == false)
            {
                if (wplayer->input.GetLeft())
                {
                    //设为Yes
                    bYes = true;
                    pGameMsgbox->JNYSetYesNo(true);
                    wplayer->inputLock.SetLeft(true);
                    PlaySound(L"YNJSelect");
                }
                else if (wplayer->input.GetRight())
                {
                    //设为No
                    bYes = false;
                    pGameMsgbox->JNYSetYesNo(false);
                    wplayer->inputLock.SetRight(true);
                    PlaySound(L"YNJSelect");
                }
                if (wplayer->input.GetOk())
                {
                    //确定选择
                    bRet = false;
                    PlaySound(L"YNJOk");
                    pGameMsgbox->YNJEnd();
                    cmd_YNJ = false;
                    //防止事件结束后起跳
                    wplayer->blockJump = true;
                    ((MyGame*)pGame)->LockAllPlayerJump();
                }
            }
        }
    }
    else
    {
        for (auto& wplayer : *globalEntity)
        {
            if (wplayer->enableAI)
                continue;
            if (wplayer->input.GetLeft())
            {
                //设为Yes
                bYes = true;
                pGameMsgbox->JNYSetYesNo(true);
                wplayer->inputLock.SetLeft(true);
                PlaySound(L"YNJSelect");
            }
            else if (wplayer->input.GetRight())
            {
                //设为No
                bYes = false;
                pGameMsgbox->JNYSetYesNo(false);
                wplayer->inputLock.SetRight(true);
                PlaySound(L"YNJSelect");
            }
            if (wplayer->input.GetOk())
            {
                //确定选择
                bRet = false;
                PlaySound(L"YNJOk");
                pGameMsgbox->YNJEnd();
                cmd_YNJ = false;
                //防止事件结束后起跳
                wplayer->blockJump = true;
                ((MyGame*)pGame)->LockAllPlayerJump();
            }
        }
    }
    return bRet;
}

bool GameScript::NODStep()
{
    bool bRet = true;
    std::weak_ptr<Entity> players[2];
    players[0] = pEntityRes->GetMyChar_Player1();
    players[1] = pEntityRes->GetMyChar_Player2();
    auto wplayer = players[targetNOD_playerIndex].lock();
    if (wplayer)
    {
        if (wplayer->input.GetOk())
        {
            bRet = false;
            cmd_NOD = false;
            //防止事件结束后起跳
            wplayer->blockJump = true;
            ((MyGame*)pGame)->LockAllPlayerJump();
        }
    }
    return bRet;
}
