--============= Active Event Survivalist_InHouse =============--
--Spawn FreeNPC_xxx
--FreeNPC có thể bị nhiệm hoặc không bị nhiễm - 4/6
--============================================================--

require "vl_quest_npc_server"

VLOCC["FreeNPCCM"] = VLOCC["FreeNPCCM"] or {}

assert(VLZB, "Stack trace: Missing dependency: VLZB - vl_event_survivalist_npc_s.lua")

local IsAnyPlayerNearObjectByXY = VLF.IsAnyPlayerNearObjectByXY
local RemoveZombiesInAreaExceptNPC = VLZB.RemoveZombiesInAreaExceptNPC
local GetQuestGlobalModData = VLGMD.GetQuestGlobalModData
local SpawnZombieNPCQuest = VLF.SpawnZombieNPCQuest
local DelayFunction = VLF.DelayFunction
local GetStaticCoordOfBuilding = VLF.GetStaticCoordOfBuilding
local AddBarricade = VLF.AddBarricade
local IsMultiplayerMode = VLF.IsMultiplayerMode
local GetZombieOnlineIDorUID = VLZB.GetZombieOnlineIDorUID
local GetZombieByOnlineIDOrUID = VLZB.GetZombieByOnlineIDOrUID
local BarricadeOnObject = VLF.BarricadeOnObject
local GetDoorOrWindowOfRoom = VLF.GetDoorOrWindowOfRoom
local IsBuildingInIgnoredList = VLF.IsBuildingInIgnoredList

--Lấy building từ tọa độ thuộc trong building
local function GetBuildingFromCoord(x, y, z)
    local square = getCell():getGridSquare(x, y, z)
    if square then
        local building = square:getBuilding()
        if building then
            return building
        end
    end
    return nil
end

--Check ModData của Building
local function CheckBuildingCooldownEvent(building, args) --CheckBuildingCooldownEvent(building, {event = "Survivalist_InHouse", hoursToNextActive = 168})
	local buildingDef = building:getDef()
	if buildingDef then
		local x, y, z = GetStaticCoordOfBuilding(buildingDef)
		local bSquare = getCell():getGridSquare(x, y, z)
		if bSquare then
			local sqData = bSquare:getModData()
			local event = args.event
            local hoursToNextActive = args.hoursToNextActive or 24
            if event == "Survivalist_InHouse" then
                --building chưa từng kích hoạt event Survivalist_InHouse
                if not sqData.event_Survivalist_InHouse then
                    return true
                elseif sqData.event_Survivalist_InHouse and sqData.event_Survivalist_InHouse.lastActive then
                    local nowHour = getGameTime():getWorldAgeHours()
                    --đã quá thời gian giới hạn, có thể kích hoạt tiếp
					local hoursPassed = nowHour - sqData.event_Survivalist_InHouse.lastActive
                    if hoursPassed >= hoursToNextActive then
                       return true
                    else
                        print("Server---CheckBuildingCooldownEvent---Declined---In Cooldown Time=", hoursPassed, hoursToNextActive)
                    end
                end
            end
        end
    end
    return false
end

--Set ModData cho building
local function SetBuildingModDataEvent(building, args) --SetBuildingModDataEvent(building, {event = "Survivalist_InHouse"})
	local buildingDef = building:getDef()
	if buildingDef then
		local x, y, z = GetStaticCoordOfBuilding(buildingDef)
		local bSquare = getCell():getGridSquare(x, y, z)
		if bSquare then
			local sqData = bSquare:getModData()
			local event = args.event
            if event == "Survivalist_InHouse" then
                if not sqData.event_Survivalist_InHouse then sqData.event_Survivalist_InHouse = {} end
                sqData.event_Survivalist_InHouse.lastActive = getGameTime():getWorldAgeHours()
                bSquare:transmitModdata()
                --print("Server-----------SetBuildingModDataEvent: 4444= "..tostring(sqData.event_Survivalist_InHouse.lastActive))
                return true
            end
        end
    end
    return false
end

--Xóa gia cố barricade
local function RemoveBarricade(obj)
	if not obj then return end
	
    local function DoRemove(_barricade)
        if _barricade:isMetalBar() then _barricade:removeMetalBar(nil)
        elseif _barricade:isMetal() then _barricade:removeMetal(nil)
        elseif _barricade:getNumPlanks() > 0 then
            for i = 1, _barricade:getNumPlanks() do
                _barricade:removePlank(nil)
            end
        end
    end
    
	local barricade = obj:getBarricadeOnSameSquare()
    if barricade then
        DoRemove(barricade)
    end
    barricade = obj:getBarricadeOnOppositeSquare()
    if barricade then
        DoRemove(barricade)
    end
end
  
--Đập vỡ kính cửa sổ
local function SmashWindows(room, number) --SmashWindows(room, 1)
    local windowTab, sideTab = GetDoorOrWindowOfRoom(room, "window")
    local num = 0
    for i, window in ipairs(windowTab) do
        if num >= number then return end
        if window:isBarricaded() then
            RemoveBarricade(window)
        end        
        window:smashWindow(true)
        num = num + 1
    end
end

--Lấy IsoRoom phòng bên ngoài bedroom: livingroom, hall, kitchen
local function GetOutsideRoomOfBedRoom(building)
    return building:getRandomRoom("livingroom") or building:getRandomRoom("hall") or building:getRandomRoom("kitchen")
end

--Spawn zombies trong room
local function AddZombiesInRoom(x, y, z, roomName, zMaxNumber) --AddZombiesInRoom(x, y, z, roomName, 10)
	local square = getCell():getGridSquare(x, y, z)
    if square then
        local building = square:getBuilding()
        if building then
            local room = building:getRandomRoom(roomName)
            if room then
                local number = ZombRand(math.floor(zMaxNumber / 2 + 0.5), zMaxNumber + 1)
                for i = 1, number do
                    room:spawnZombies()
                end
            end
        end
    end
end

local soundEvent = {}
soundEvent.pistol = {"pistoloutside1", "pistoloutside2"}
soundEvent.shotgun = {"shotgun", "shotgun2"}
soundEvent.assaultrifle = {"assaultrifledistant1", "assaultrifledistant2", "assaultrifledistant3", "assaultrifledistant4", "assaultrifledistant5", "assaultrifledistant8"}
soundEvent.scream_f = {"distscream2_female", "distscream4_female", "distscream5_female"}
soundEvent.scream_m = {"distscream6_male", "distscream7_male", "distscream8_male"}

local function ActiveEvent_Survivalist_InHouse(player, building) --ActiveEvent_Survivalist_InHouse(player, building)
    local bedroom = building:getRandomRoom("bedroom")
	if bedroom then
		--yêu cầu server xóa zombie trong room
		local roomDef = bedroom:getRoomDef()
		local x1, y1, x2, y2, z = roomDef:getX(), roomDef:getY(), roomDef:getX2(), roomDef:getY2(), roomDef:getZ()
		RemoveZombiesInAreaExceptNPC(x1, y1, x2, y2, z)
        
		local female = ZombRand(2)
		local ghoul = ZombRand(100)
		--spawn npc trong bedroom
		local square = bedroom:getRandomFreeSquare()
		if square then
			local x, y, z = square:getX(), square:getY(), square:getZ()
            local sameQStep, femaleChance
            --Các bước để tạo và update FreeNPC
            --1, tạo ngẫu nhiên qStep, không có trong list qStep. qStep này chưa định nghĩa NPC nào cả
            --2, yêu cầu các client trỏ qStep này tới qStep của 1 trong 4 qStep dưới, tùy server đã chọn được qStep nào. sendClientCommand, qStep = sameQStep
            --3, các client đăng nhập sau thì: check tất cả qStep trong questMD.NPC, nếu có questMD.NPC[qStep].sameQStep thì cập nhật VLF.npcData[qStep] = VLF.npcData[sameQStep]
            --4, trường hợp thoát game và login chỗ có FreeNPC. nếu VLF.npcData[sameQStep] thì trỏ VLF.npcData[qStep] = VLF.npcData[sameQStep]
            
            --set outfit
			local outfit
			local outfitRate = ZombRand(100)
			if outfitRate < 50 then outfit = "Survivalist0"..tostring(ZombRand(2,6))
			elseif outfitRate < 80 then outfit = "Survivalist0"..tostring(ZombRand(2,6)).."_Mid"
			else outfit = "Survivalist0"..tostring(ZombRand(2,6)).."_Late"
			end
            
            --set sameQStep để client update qStep thành sameQStep
			if female == 1 then
				if ghoul < 40 then
					sameQStep, femaleChance = "freeNPC_female_ghoul", 100
				else
					sameQStep, femaleChance = "freeNPC_female", 100
				end
			else
				if ghoul < 40 then
					sameQStep, femaleChance = "freeNPC_male_ghoul", 0
				else
					sameQStep, femaleChance = "freeNPC_male", 0
				end
			end
			
			--[[
			if female == 1 and ghoul == 1 then sameQStep, femaleChance = "freeNPC_female_ghoul", 100
			elseif female == 1 and ghoul == 0 then sameQStep, femaleChance = "freeNPC_female", 100
			elseif female == 0 and ghoul == 0 then sameQStep, femaleChance = "freeNPC_male", 0
			else sameQStep, femaleChance = "freeNPC_male_ghoul", 0
			end
            ]]
			
            --khởi tạo qStep
            local questMD = GetQuestGlobalModData(nil)
            local qStep
            for i = 1, 10 do
                qStep = "freeNPC_"..tostring(ZombRand(10000))
                local exist = false
                --kiểm tra qStep có tồn tại không
                for _qStep, tab in pairs(questMD.NPC) do
                    if _qStep == qStep then
                        exist = true
                    end                    
                end
                if exist == false then
                    break
                end
            end
            
			if qStep then
                --spawn NPC và NPC qStep cố định có sẵn VLF.npcData[sameQStep]
                local zNPC = SpawnZombieNPCQuest({qStep = qStep, x = x, y = y, z = z, num = 1, outfit = outfit, femaleChance = femaleChance, crawler = false, isFallOnFront = false, isFakeDead = false, knockedDown = false, isInvulnerable = true, isSitting = false, health = 5})
                if zNPC then
					--print("Server---NPC Event Survivalist_InHouse---Spawned=", qStep, x, y, z)
					print("------- getPlayer():teleportTo("..tostring(x)..","..tostring(y)..","..tostring(z)..")")
					
                    local questMD = GetQuestGlobalModData(qStep)
                    --update data trường hợp không phải Client-Server vì trong SinglePlayer sẽ không nhận sendServerCommand
                    questMD.NPC[qStep]["sameQStep"] = sameQStep
                    if not isServer() then --SP
                        VLF.npcData[qStep] = VLF.npcData[sameQStep]
                    end
                    --yêu cầu client update qStep NPC này --SinglePlayer không nhận command này
                    sendServerCommand("FreeNPCCM_C", "FreeNPCSameQStep_C", {qStep = qStep, sameQStep = sameQStep})
                end
            end
        end
        
		--Nếu có door thì đóng lại và barricade
		local doorTab, sideTab = GetDoorOrWindowOfRoom(bedroom, "door")
        for i, door in ipairs(doorTab) do		
            BarricadeOnObject({x = door:getSquare():getX(), y = door:getSquare():getY(), z = door:getSquare():getZ(), objFlag = "door", side = sideTab[i], barItem = "Base.Plank"})
		end
		--Nếu có window thì đóng lại và barricade
		local windowTab, sideTab = GetDoorOrWindowOfRoom(bedroom, "window")
        for i, window in ipairs(windowTab) do
			--barricade
            BarricadeOnObject({x = window:getSquare():getX(), y = window:getSquare():getY(), z = window:getSquare():getZ(), objFlag = "window", side = sideTab[i], barItem = "Base.Plank"})
		end	
        
        local outsideRoom = GetOutsideRoomOfBedRoom(building)
        if outsideRoom then
            --Đập vỡ kính cửa sổ
            SmashWindows(outsideRoom, ZombRand(1,3))
            
            --Spawn zombies trong livingroom
            AddZombiesInRoom(x1, y1, z, outsideRoom:getName(), 6)
            
            local soundGun
            local r = ZombRand(2)
            if r == 0 then soundGun = soundEvent.pistol[ZombRand(1,3)]
            elseif r == 1 then soundGun = soundEvent.shotgun[ZombRand(1,3)]
            end
            
			--Tiếng súng sự kiện
			local sq = outsideRoom:getRandomFreeSquare()
			if sq then
				local sound
				if female == 1 then sound = soundEvent.scream_f[ZombRand(1,4)]
				else sound = soundEvent.scream_m[ZombRand(1,4)]
				end
				if sound then
                    --print("Server-----------PlayWorldSound: 2222")
                    addSound(sq:getFloor(), sq:getX(), sq:getY(), sq:getZ(), 30, 100) --thu hút zombie 30 ô
					getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                    if ZombRand(100) < 75 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(15,25))
                    end
                    if ZombRand(100) < 70 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(30,40))
                    end
                    if ZombRand(100) < 65 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(45,55))
                    end
                    if ZombRand(100) < 60 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(60,70))
                    end
                    if ZombRand(100) < 55 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(80,90))
                    end
                    if ZombRand(100) < 50 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(100,110))
                    end
                    if ZombRand(100) < 45 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(120,130))
                    end
                    if ZombRand(100) < 40 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(140,150))
                    end
                    if ZombRand(100) < 35 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(160,170))
                    end
                    if ZombRand(100) < 30 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(soundGun, false, sq, 200, 0, 1, false)
                        end, ZombRand(180,190))
                    end
                    if ghoul == 1 then
                        DelayFunction(function()
                            getSoundManager():PlayWorldSound(sound, false, sq, 200, 0, 1, false)
                        end, ZombRand(25,100))
                    end
				end
			end
		end
		
		--Hiển thị HaloText ở SinglePlayer
		if not isServer() then
			HaloTextHelper.addGoodText(player, getText("IGUI_VLQ_Halotext_SurvivalistInHouse"))
		end
		
        --Set ModData
        SetBuildingModDataEvent(building, {event = "Survivalist_InHouse"})
	else
		print("Server---No BedRoom To Active Event=")
	end
end

local function RequestEvents(player, args) --RequestEvents(player, {x = x, y = y, z = z, event = args.event, hoursToNextActive = args.hoursToNextActive})
	local event = args.event
	if event == "Survivalist_InHouse" then
		--print("Server---Get Event Request---Survivalist_InHouse=")
		local building = GetBuildingFromCoord(args.x, args.y, args.z)
		if building then
			local countFalse = 0
			
			--check ModData có thể active không
			local canActive = CheckBuildingCooldownEvent(building, args)
			if not canActive then
				countFalse = countFalse + 1
			end
			
			--Multiplayer mode: check Player có ở gần xung quanh
			if IsMultiplayerMode() then
				--Kiểm tra có player nào trong bán kính maxDist không
				local player = IsAnyPlayerNearObjectByXY(nil, building:getDef():getX(), building:getDef():getY(), 27) --FIXME
									 
				if player then
					print("Server---Declined---hasPlayerNearby=", player:getUsername())
					countFalse = countFalse + 1
				end
			   
				--Kiểm tra building có phải SafeHouse không
				local square = getCell():getGridSquare(args.x, args.y, args.z)
				if square then
					local isSH = SafeHouse.getSafeHouse(square)
					if isSH then
						print("Server---Declined---IsSafeHouse=")
						countFalse = countFalse + 1
					end
				end
			end
			
			--Kiểm tra building có trong danh sách ignoredPositionList
			local bIgnored = IsBuildingInIgnoredList(building)
			if bIgnored == true then
				countFalse = countFalse + 1
			end

			--Nếu countFalse vẫn == 0 thì đủ điều kiện kích hoạt Event
			if countFalse == 0 then
				--active event
				print("Server---Accepted---Start---ActiveEvent_Survivalist_InHouse= ")
				ActiveEvent_Survivalist_InHouse(player, building)
			end
		end
	end
end


--================ SinglePlayer Only ================--
--Update lại dữ liệu của FreeNPC khi zombie bị reset
local function UpdateFreeNPCs(qStep, zID)
	local questMD = GetQuestGlobalModData(qStep)
	local zombie = GetZombieByOnlineIDOrUID(zID)
	if zombie and not zombie:isDead() and zombie:getHealth() > 0 then
		--SinglePlayer update luôn
		questMD.NPC[qStep]["uid"] = zombie:getUID() --dùng cho server kiểm tra zombie nếu không tồn tại thì xóa spawned, chỉ dùng UID vì tính duy nhất
		questMD.NPC[qStep]["zID"] = zID
		--Xóa questMD.NPCqStep cũ
		for _zID, _qStep in pairs(questMD.NPCqStep) do
			if _qStep == qStep then
				questMD.NPCqStep[_zID] = nil
				break
			end
		end
		--Thêm questMD.NPCqStep mới
		questMD.NPCqStep[zID] = qStep
		
		--Multi: yêu cầu các clients update data freeNPC
		sendServerCommand("FreeNPCCM_C", "UpdateFreeNPCCM_C", {qStep = qStep, zID = zID})
	else
		print("Server---UpdateFreeNPCs= no zombie")
	end
end
--===================================================--


--================= ONCLIENTCOMMAND =================--
VLOCC["FreeNPCCM"]["RequestEvents"] = function(player, args)	--{x = x, y = y, z = z, event = args.event, hoursToNextActive = args.hoursToNextActive}
	RequestEvents(player, args)
end

VLOCC["FreeNPCCM"]["UpdateFreeNPCs"] = function(player, args)	--{qStep = qStep, zID = zID}
	UpdateFreeNPCs(args.qStep, args.zID)
end

VLOCC["FreeNPCCM"]["CheckedAllFreeNPCs"] = function(player, args)	--nil
	VLF.var.freeNPCsUpdated = true
end




