--================= Spawn NPC by LoadGridSquare =================--
--Tự động spawn các NPC có trong list chờ Spawn khi chạy Events.LoadGridsquare
--Thêm vào danh sách chờ spawn bằng cách thêm qStep của NPC active trong questMD.NPCsQueueToSpawn, yêu cầu cả Server cũng active để đồng bộ
--===============================================================--

require "npc/vl_quest_npc_client"

assert(VLPL, "Stack trace: Missing dependency: VLPL - vl_npc_spawn_loadgridsquare.lua")
assert(VLZB, "Stack trace: Missing dependency: VLZB - vl_npc_spawn_loadgridsquare.lua")
assert(VLF.npcData,  "Stack trace: Missing dependency: VLF.npcData - vl_npc_spawn_loadgridsquare.lua")

local GetPlayerID = VLPL.GetPlayerID
local GetQuestGlobalModData = VLGMD.GetQuestGlobalModData
local IsAnyNPCQueueToSpawn = VLZB.IsAnyNPCQueueToSpawn
local GetOrCreateSquare = VLF.GetOrCreateSquare
local RemoveObjectOnSquare = VLF.RemoveObjectOnSquare
local AddObjectToSquare = VLF.AddObjectToSquare
local SpawnNPCOnClient = VLZB.SpawnNPCOnClient

--Kiểm tra điểm spawn có thể spawn, nếu không thì tìm điểm spawn mới
local function CheckNPCSpawnPoint(square, qStep, range) --CheckNPCSpawnPoint(square, qStep, 3)
    local x, y, z = square:getX(), square:getY(), square:getZ() --z = 0 vì square luôn lấy load tầng 1
    if not x or not y or not z then return end
    range = range or 3
    local npcZ = VLF.npcData[qStep].startZ or 0
    local sq = getCell():getGridSquare(x, y, npcZ)
    --local sq = GetOrCreateSquare(x, y, npcZ)
    --kiểm tra square này có spawn được ko
    if sq and sq:isSolidFloor() and sq:isFree(true) then return sq end
    
    --nếu z >= 0 thì tìm các square xung quanh và tầng dưới cho đến khi z = 0
    --nếu z < 0 thì chỉ tìm square tại tầng đó rồi thoát lặp
    if range ~= 0 then    --range == 0 thì bỏ qua, 
        local newX, newY, newZ
        local step = npcZ >= 0 and 1 or -1
        for h = 0, npcZ, step do
            for i = -range, range do
                for j = -range, range do
                    newX, newY, newZ = x + i, y + j, npcZ - h
                    local newSq = getCell():getGridSquare(newX, newY, newZ)
                    if newSq and newSq:isSolidFloor() and newSq:isFree(true) then return newSq end
                end
            end
            if newZ <= 0 then break end
        end
    end

    print("Client---CheckNPCSpawnPoint= no square for NPC spawn") 
    return nil
end

--Tìm NPC có điểm startpoint chính là square đang load
--Có thể lỗi khi các NPC cùng tọa độ x, y và khác z. --FIXME
local function GetNPCStartPointSameAsSquare(square)
    local sqX, sqY = square:getX(), square:getY()
    
    --lấy điểm start trực tiếp từ bảng
    local npcData = VLF.npcData
    for qStep, data in pairs(npcData) do
        if data.startX == sqX and data.startY == sqY then --startPoint cùng tọa độ với square
            local questMD = GetQuestGlobalModData(nil)
            if questMD.NPCsQueueToSpawn[qStep] == true then
                return qStep
            end
        
        --[[
            local playerGMD_Quest_Q1 = GetPlayerGlobalModDataQ1(getPlayer(), qStep)
            if qStep == "q1s014_2" then --NPC Dr. Bassler luôn spawn cùng Dr. Venter khi qStep q1s011 == true
                if playerGMD_Quest_Q1.q1s011.active == true then
                    return qStep
                end
            end
            --local _qStep = string.sub(qStep, 1, 6) --lấy 6 ký tự đầu của qStep --để các NPC phụ cùng spawn có qStep "q1s014_2" cũng có thể check được qStep q1s014 có đang active
            if playerGMD_Quest_Q1[qStep].active == true then --NPC có qStep đang được kích hoạt mới spawn. --để phân biệt NPC cùng vị trí startPoint
                return qStep
            end
            ]]
        end
    end
    return nil
end


--CALL FUNCTION 
--Khi client load square thì spawn NPC
--Tầng 1 luôn có sàn, tầng 2 phá sàn thì LoadGridsquare không load square này nữa
local function LoadGridsquare(square)
    if square:getZ() ~= 0 then return end --Chỉ check square tầng 1, không thể phá sàn
    if IsAnyNPCQueueToSpawn() == false then return end 

    --Tìm NPC có startPoint là square này
    local qStep = GetNPCStartPointSameAsSquare(square)
    if qStep then        
        local questMD = GetQuestGlobalModData(qStep)
        
        --Nếu NPC có qStep này đang được kích hoạt = true VÀ turnToZombie chưa kích hoạt
        if questMD.NPCsQueueToSpawn[qStep] == true and not questMD.NPC[qStep]["turnToZombie"] then
            local tick = 0
            local npcSpawned = false
            
            local function OnTick()
                tick = tick + 1    
                if tick % 60 == 0 then
                    --tìm điểm spawn cho NPC
                    local range = VLF.npcData[qStep].spawnRange or 1
                    local spawnPoint = CheckNPCSpawnPoint(square, qStep, range)
                    
                    if spawnPoint then
                        local x, y, z = spawnPoint:getX(), spawnPoint:getY(), spawnPoint:getZ()
                        
                        if x and y and z then
                            npcSpawned = true
                            local pID = GetPlayerID(getPlayer())
                            local femaleChance = VLF.npcData[qStep].femaleChance
                            local outfit = VLF.npcData[qStep].outfit
                            print("Client---LoadGridsquare---Request Spawn NPC= ", qStep, x, y, z) 
                            
                            --yêu cầu server spawn NPC
                            sendClientCommand(getPlayer(), "NPCQuestCM", "RequestSpawnNPC", {qStep = qStep, pID = pID, outfit = outfit, x = x, y = y, z = z, removeZRange = 5, femaleChance = femaleChance})
                            Events.OnTick.Remove(OnTick)
                            return
                        end
                    end
                end
                
                if tick >= 120 then
                    --Nếu không tìm được square để spawn NPC thì chuyển qua spawn NPC bằng OnPlayerUpdate
                    if npcSpawned == false then
                        print("Client---LoadGridsquare---Spawn NPC by OnPlayerUpdate")
                        local _tick = 1
                        
                        local function onPlayerUpdate(player)
                            if _tick % 20 == 0 then
                                local npcData = VLF.npcData[qStep]
                                local sq = getCell():getGridSquare(npcData.startX, npcData.startY, npcData.startZ)
                                if sq and sq:isSolidFloor() then
                                    SpawnNPCOnClient(qStep, 0)
                                    Events.OnPlayerUpdate.Remove(onPlayerUpdate)
                                    return
                                end
                            end
                            
                            --Nếu player cùng tầng và cách ít hơn 15 ô vẫn chưa spawn thì thêm sàn, rồi spawn
                            --Đến lúc này khả năng do không có square nào có sàn để spawn hoặc not Free
                            if _tick % 100 == 0 then
                                local npcData = VLF.npcData[qStep]
                                local sq = GetOrCreateSquare(npcData.startX, npcData.startY, npcData.startZ)
                                if sq then
                                    local isTransmit = true
                                    RemoveObjectOnSquare(sq, nil, isTransmit, true)
                                    local _floor = AddObjectToSquare(sq, "floors_burnt_01_0", {isTransmit = isTransmit, x = -1, y = -1, z = 0, objType = "IsoObject"})
                                    if _floor and sq:isSolidFloor() then
                                        SpawnNPCOnClient(qStep, 0)
                                        Events.OnPlayerUpdate.Remove(onPlayerUpdate)
                                        return
                                    end
                                end
                            end                            
                            
                            _tick = _tick + 1
                        end
                        Events.OnPlayerUpdate.Remove(onPlayerUpdate)
                        Events.OnPlayerUpdate.Add(onPlayerUpdate)
                    end
                    
                    Events.OnTick.Remove(OnTick) 
                end
            end
            Events.OnTick.Add(OnTick)
        else
            print("Client---LoadGridsquare---Can not Spawn= ", qStep, questMD.NPCsQueueToSpawn[qStep], questMD.NPC[qStep]["turnToZombie"])
        end
    end
end
Events.LoadGridsquare.Remove(LoadGridsquare)
Events.LoadGridsquare.Add(LoadGridsquare)



