--========================== CARPET BOMBING EVENT ==========================--
--CARPET BOMBING sẽ ngẫu nhiên hàng tiếng. Tỉ lệ giảm dần theo tuổi của thế giới
--Sau 14 ngày mới xuất hiện sự kiện này
--Thông báo trên Radio các chiến dịch thả bomb và nhắc lại 3 tiếng 1 lần. 
--Khi đến thời gian thả bomb, máy bay sẽ ném bomb xung quanh khu vực được đánh dấu
--Để nghe được tin tức thì luôn phải có Radio đang bật và cầm trên tay hoặc đứng trong khu vực có thể nghe được tiếng Radio đang bật. 
	--Radio chỉ cần bật, bất kì tần số MHz nào cũng có thể nhận tin
	--Player ngủ không thể nghe được tin
--CALL EVENT ngay lập tức: VLECB.TryTriggerCarpetBombing(true)
--=========================================================================--

require "vl_quest_utils"
require "vl_quest_player_utils"
require "vl_quest_globalmoddata"

VLECB = VLECB or {}
VLECB.displayCarpetBombingPlan = VLECB.displayCarpetBombingPlan or {}
VLECB.needHoursToStartCBEvent = 336	--FIXME: 336
VLECB.bomb_DropAfterHours = 24	--FIXME: 24
VLECB.bombEffectRadius = 6

local displayCarpetBombingPlan = VLECB.displayCarpetBombingPlan
local bombEffectRadius = VLECB.bombEffectRadius
local bomb_DropAfterHours = VLECB.bomb_DropAfterHours

local GetQuestGlobalModData = VLGMD.GetQuestGlobalModData
local GetPlayerGlobalModData = VLGMD.GetPlayerGlobalModData
local PlayerCanHearAnyRadio = VLPL.PlayerCanHearAnyRadio
local PlayAnimation = VLF.PlayAnimation
local Caldistance = VLF.Caldistance
local CaldistanceCoordinates = VLF.CaldistanceCoordinates
local PlaySound = VLF.PlaySound
local StopSound = VLF.StopSound
local StopSoundFadeout = VLF.StopSoundFadeout
local PlaySoundFadeIn = VLF.PlaySoundFadeIn
local SetNormalGameSpeed = VLF.SetNormalGameSpeed

local qtype = getText("IGUI_VLQ_TimeLimitedEvent")
local questMarker = getTexture("media/textures/carpetbombing_96.png")

--Lấy Global ModData cho sự kiện CarpetBombing
function VLECB.GetModDataCarpetBombingEvent()	--local questMD_Events_CarpetBombing = VLECB.GetModDataCarpetBombingEvent()
	local questMD = GetQuestGlobalModData(nil)
	questMD.Events["CarpetBombing"] = questMD.Events["CarpetBombing"] or {}
	questMD.Events["CarpetBombing"]["Plan"] = questMD.Events["CarpetBombing"]["Plan"] or {}
	
	return questMD.Events["CarpetBombing"]
end
local GetModDataCarpetBombingEvent = VLECB.GetModDataCarpetBombingEvent

--Lưu dữ liệu cho bombPlanCode
function VLECB.RegisterCarpetBombingEvent(areaID, x, y, bombPlanCode, activateStartHour, bombDropAfterHours, distAreaCheck)
	print("Shared---RegisterCarpetBombingEvent---areaID, x, y, bombPlanCode, activateStartHour, bombDropAfterHours, distAreaCheck= ", areaID, x, y, bombPlanCode, activateStartHour, bombDropAfterHours, distAreaCheck)
	local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
	questMD_Events_CarpetBombing["Plan"][bombPlanCode] = {
		areaID = areaID,
		x = x,
		y = y,
		activateStartHour = activateStartHour,
		bombDropAfterHours = bombDropAfterHours,
		distAreaCheck = distAreaCheck,
		dropped = false
	}
	 
	if isServer() then
		sendServerCommand("Event_CarpetBombing_C", "RegisterDataStartEvent_C", {
			bombPlanCode = bombPlanCode,
			areaID = areaID,
			x = x,
			y = y,
			activateStartHour = activateStartHour,
			bombDropAfterHours = bombDropAfterHours,
			distAreaCheck = distAreaCheck,
			dropped = false
		})
	end
end

--Clear data CarpetBombing
function VLECB.ClearDataCarpetBombingEvent(bombPlanCode)
	local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
	if questMD_Events_CarpetBombing["Plan"] and questMD_Events_CarpetBombing["Plan"][bombPlanCode] then
		--print("Shared---ClearDataCarpetBombingEvent---bombPlanCode= ", bombPlanCode)
		questMD_Events_CarpetBombing["Plan"][bombPlanCode] = nil
	end
	
	if isServer() then
		sendServerCommand("Event_CarpetBombing_C", "ClearDataEvent_C", {bombPlanCode = bombPlanCode})
	end
end
local ClearDataCarpetBombingEvent = VLECB.ClearDataCarpetBombingEvent
	
--Update data danh sách địa điểm bomb sẽ nổ
function VLECB.UpdateDataBombsToPlan(bombPlanCode, bombCount, bombs, weatherCondition, endBombingMinute)
	if not bombPlanCode or type(bombs) ~= "table" then
		return false
	end

	local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
	local bombingData = questMD_Events_CarpetBombing["Plan"][bombPlanCode]
	if not bombingData then return false end
	
	print("Shared---UpdateDataBombsToPlan---bombPlanCode, bombCount, weatherCondition= ", bombPlanCode, bombCount, weatherCondition, endBombingMinute)
	--gán bombs
	bombingData["bombs"] = bombs
	bombingData["bombCount"] = bombCount
	bombingData["dropped"] = true
	bombingData["weatherCondition"] = weatherCondition
	bombingData["endBombingMinute"] = endBombingMinute
	
	--transmit cho client
	if isServer() then
		sendServerCommand("Event_CarpetBombing_C", "UpdateBombsData_C", {bombPlanCode = bombPlanCode, bombCount = bombCount, bombs = bombs, weatherCondition = weatherCondition, endBombingMinute = endBombingMinute})
	end

	return true
end

function VLECB.RemoveDataBombs(bombPlanCode, bombID)
	if not bombPlanCode and not bombID then return false end

	local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
	local bombingData = questMD_Events_CarpetBombing["Plan"][bombPlanCode]
	if not bombingData or not bombingData["bombs"] then return false end
	
	--print("Shared---RemoveDataBombs---bombPlanCode, bombID= ", bombPlanCode, bombID)
	--Xóa data bombID đã nổ
	bombingData["bombs"][bombID] = nil
	
	--Xóa data bombs nếu rỗng	--bomb đã nổ hết các điểm
	local empty = true
	for bombID, data in pairs(bombingData["bombs"]) do
		empty = false
		break
	end
	
	if empty == true then
		print("Shared---RemoveDataBombs---bombs IS EMPTY---bombPlanCode, empty= ", bombPlanCode, empty)
		ClearDataCarpetBombingEvent(bombPlanCode)
	end
	
	--transmit cho client
	if isServer() then
		sendServerCommand("Event_CarpetBombing_C", "RemoveDataBombs_C", {bombPlanCode = bombPlanCode, bombID = bombID})
	end

	return true
end

--Kiểm tra có phải bomb nổ ngay lúc này
function VLECB.ShouldExplodeNow(explodeMinute)
	local gameTime = getGameTime()
	local currentMinute = gameTime:getMinutesStamp()
	
	if currentMinute == explodeMinute then
		return true
	end
	return false
end

--player ảnh hưởng khi bị nổ bomb
local function OnPlayerHitByExplosion(player, damMin, damMax, rateHitEachPart, rateBurn, rateFracture, rateKnockedDown, rateHaveBullet, rateBleeding)
	rateHitEachPart = rateHitEachPart or 0
	rateBurn = rateBurn or 0
	rateFracture = rateFracture or 0
	rateKnockedDown = rateKnockedDown or 0
	rateHaveBullet = rateHaveBullet or 0
	rateBleeding = rateBleeding or 0
	
	local bodydamage = player:getBodyDamage()
	local stats = player:getStats()
	
	--player đang chạy sẽ thì bị xô --sử dụng vì setKnockedDown không stop sprinting
	if player:isSprinting() then 
		player:setBumpType("left")
		player:setVariable("BumpDone", true)
		player:setVariable("BumpFall", true)
	else
		--player hitReaction khi không phải sprinting
		if ZombRand(100) < rateKnockedDown then 
			player:setKnockedDown(true)
			player:dropHandItems()
		else 
			player:setHitReaction("CrawlerBite")
			player:setVariable("hitReaction", "CrawlerBite")
		end
	end
	
	--bị thương
	for i = 0 , bodydamage:getBodyParts():size() - 1 do
		local b = bodydamage:getBodyParts():get(i)
		if ZombRand(100) < rateHitEachPart then
		
			b:setScratched(true, true)
			b:AddDamage(ZombRandFloat(damMin, damMax))
			stats:add(CharacterStat.PAIN, damMax)
			player:addHole(BloodBodyPartType.FromIndex(BodyPartType.ToIndex(b:getType())))
			
			if ZombRand(100) < rateBurn then
				b:setBurned()
				b:setBurnTime(ZombRandFloat(damMin, damMax * 2))
				b:setNeedBurnWash(true)
			end
			
			if ZombRand(100) < rateFracture then
				b:setFractureTime(ZombRandFloat(damMax, damMax * 2))
				if ZombRand(100) < rateBleeding then
					b:generateBleeding()
				end
			end
			
			if ZombRand(100) < rateHaveBullet then
				b:setHaveBullet(true, 0)
				b:generateBleeding()
			end
		end
	end
end

--Play Animation và Sound khi bomb nổ	--Client Only
function VLECB.PlayBombEffect(x, y, z)
	if not x or not y or not z then return end
	
	local cell = getCell()
	local sq = cell:getGridSquare(x, y, z)
	if not sq then return end
	
	local player = getPlayer()
	if not player then return end
	
	--sound bomb nổ
	player:getEmitter():playSound("vl_explode")
	
	--play animation explode
	PlayAnimation(sq, "Base.VL_Explode_Anim_512_", 7, 1.7, 1.7, 0.15, 3)
	
	--lóe sáng khi nổ
	local lightSource = IsoLightSource.new(x, y, z, 0.8, 0.8, 0.7, 20, 4)
	cell:addLamppost(lightSource)
	
	--play bị ảnh hưởng bởi bomb nổ
	local dist = Caldistance(player, sq, true)

	if dist < 1.5 then
		OnPlayerHitByExplosion(player, 15, 30, 50, 70, 40, 100, 70, 50)
	elseif dist < 3 then
		OnPlayerHitByExplosion(player, 10, 20, 20, 30, 15, 75, 30, 40)
	elseif dist <= bombEffectRadius then
		OnPlayerHitByExplosion(player, 5, 15, 8, 10, 5, 40, 20, 30)
	end
end

--play sound máy bay thả bom trong chiến dịch
function VLECB.PlaySound_B52Appeared(player, bombPlanCode)
	local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
	local bombingData = questMD_Events_CarpetBombing["Plan"][bombPlanCode]
	if not bombingData then return false end
	
	local soundHandle = nil
	
	local function everyOneMinute()
		--Nếu đang ở trong khoảng cách Check của area
		local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
		local bombingData = questMD_Events_CarpetBombing["Plan"][bombPlanCode]
		local currentMinute = getGameTime():getMinutesStamp()
		
		--Nếu còn trong thời gian thả bomb thì sẽ play sound B52
		if bombingData and bombingData.endBombingMinute and currentMinute < bombingData.endBombingMinute then
			local px, py = player:getX(), player:getY()
			local distToAreaCentre = CaldistanceCoordinates(player:getX(), player:getY(), bombingData.x, bombingData.y)

			if distToAreaCentre <= bombingData.distAreaCheck then
				if not soundHandle then
					soundHandle = PlaySound(player, "vl_b52bomber")
				end
				
				--Nếu player đang ngủ thì bị tỉnh giấc
				if player:isAsleep() then
					player:forceAwake()
				end
			else
				if soundHandle then
					StopSoundFadeout(player, soundHandle, 180)
					soundHandle = nil
				end
			end
		else
			--Nếu đã thả xong bomb hoặc bombingData đã xóa thì xóa event này
			if soundHandle then
				StopSoundFadeout(player, soundHandle, 180)
				soundHandle = nil
			end
			Events.EveryOneMinute.Remove(everyOneMinute)
		end
	end	
	
	Events.EveryOneMinute.Remove(everyOneMinute)
	Events.EveryOneMinute.Add(everyOneMinute)
end

--Bật sound Helicopter và cảnh báo thả bomb trong 3 tiếng tới với các player trong khu vực thả bomb --CLIENT ONLY
function VLECB.HelicopterBombWarning(player, bombPlanCode)
	local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
	local bombingData = questMD_Events_CarpetBombing["Plan"][bombPlanCode]
	if not bombingData then return false end

	local px, py = player:getX(), player:getY()
	local distToAreaCentre = CaldistanceCoordinates(player:getX(), player:getY(), bombingData.x, bombingData.y)
	
	if distToAreaCentre <= bombingData.distAreaCheck then
		PlaySoundFadeIn(player, "Helicopter", 120)
		SetNormalGameSpeed()
		
		--Nếu player đang ngủ thì bị tỉnh giấc
		if player:isAsleep() then
			player:forceAwake()
		end
		
		local passedHour = getGameTime():getWorldAgeHours() - bombingData.activateStartHour
		local bombDropInHours = math.floor((bombingData.bombDropAfterHours - passedHour) + 0.5)
		local _tick = 0
		
		local function onTick()
			_tick = _tick + 1
			if _tick <= 1800 then
				if _tick % 180 == 0 then	
					HaloTextHelper.addBadText(player, getText("IGUI_VLQ_CarpetBombing_Warning", bombDropInHours))
					
				elseif _tick == 60 then
					PlaySound(player, "RadioZap")
					PlaySound(player, "RadioStatic")
				
				elseif _tick == 170 then
					PlaySound(player, "RadioTalk")
				end
				return
			end
			
			StopSound(player, "RadioStatic")
			StopSound(player, "RadioTalk")
			StopSound(player, "Helicopter")
			Events.OnTick.Remove(onTick)
		end
		Events.OnTick.Add(onTick)
	end
end

--=======================================================================--

function VLECB.GetPlayerGMDCarpetBombing(player, bombPlanCode)	--local playerGMD_Data_knewCarpetBombings = VLECB.GetPlayerGMDCarpetBombing(player, bombPlanCode)
	local playerGMD = GetPlayerGlobalModData(player)
	if not playerGMD.Data["knewCarpetBombings"] then playerGMD.Data["knewCarpetBombings"] = {} end
	
	if bombPlanCode then
		if not playerGMD.Data["knewCarpetBombings"][bombPlanCode] then playerGMD.Data["knewCarpetBombings"][bombPlanCode] = {} end
	end
	
	return playerGMD.Data["knewCarpetBombings"]
end
local GetPlayerGMDCarpetBombing = VLECB.GetPlayerGMDCarpetBombing

--Cập nhật data khi player đã nghe được tin tức về Supply
function VLECB.UpdatePlayerGMDKnewCarpetBombing(player, bombPlanCode)
	local playerGMD_Data_knewCarpetBombings = GetPlayerGMDCarpetBombing(player, bombPlanCode)
	local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
	local bombingData = questMD_Events_CarpetBombing["Plan"][bombPlanCode]
	if not bombingData then return end

	playerGMD_Data_knewCarpetBombings[bombPlanCode]["x"] = bombingData.x
	playerGMD_Data_knewCarpetBombings[bombPlanCode]["y"] = bombingData.y
	playerGMD_Data_knewCarpetBombings[bombPlanCode]["activateStartHour"] = bombingData.activateStartHour
	playerGMD_Data_knewCarpetBombings[bombPlanCode]["bombDropAfterHours"] = bombingData.bombDropAfterHours

	if isClient() then
		sendClientCommand(player, "Event_CarpetBombing", "UpdatePlayerGMDCB", {bombPlanCode = bombPlanCode})
	end
end
local UpdatePlayerGMDKnewCarpetBombing = VLECB.UpdatePlayerGMDKnewCarpetBombing

--Thêm hiển thị trên Quest List
local function EventCB_QuestList_AddItem(text, itemData) --EventCB_QuestList_AddItem("Q"..tostring(id), {id = id, qStep = qStep, isDone = args.isDone, qtype = args.qtype, name = getText("IGUI_VLQ_CarpetBombing_Name", args.bombPlanCode), task = getText("IGUI_VLQ_CarpetBombing_Task", supplyType), desc = getText("IGUI_VLQ_CarpetBombing_Desc", supplyType, args.elapsedHours)})
    if not text or not itemData then return end
	local id,qStep  = itemData.id, itemData.qStep
	local isDone = itemData.isDone or false
	local isCollection, currentCollection, requestCollection = itemData.isCollection or false, itemData.currentCollection, itemData.requestCollection
	local collectQItemName = itemData.collectQItemName or nil
	local qtype = itemData.qtype or getText("IGUI_VLQ_TimeLimitedEvent")
	if not id or not qStep then return end
	
    VLF.QuestListShowOnUI[text] = {id = id, qStep = qStep, isDone = isDone, qtype = qtype, isCollection = isCollection, currentCollection = currentCollection, requestCollection = requestCollection, collectQItemName = collectQItemName, name = itemData.name, task = itemData.task, desc = itemData.desc}
end

--USING quest ID ECB1 -> ECBxxx
local function EventCB_DoQuestList_AddItem(args) --EventCB_DoQuestList_AddItem({id = id, qStep = qStep, isDone = false, qtype = qtype, bombPlanCode = bombPlanCode, elapsedHours = elapsedHours})
	local id, qStep = args.id, args.qStep
	if not id or not qStep then return end
	
	local bombPlanCode = args.bombPlanCode
	local hoursUntilStart = bomb_DropAfterHours - args.elapsedHours
	
	EventCB_QuestList_AddItem("Q"..tostring(id), {id = id, qStep = qStep, isDone = args.isDone, qtype = args.qtype, name = getText("IGUI_VLQ_CarpetBombing_Name", bombPlanCode), task = getText("IGUI_VLQ_CarpetBombing_Task", hoursUntilStart), desc = getText("IGUI_VLQ_CarpetBombing_Desc", hoursUntilStart)})
end

--Function cố định để show event trên bảng Quest List
function VLECB.AddToCBQuestList(player, bombPlanCode)
	local playerGMD_Data_knewCarpetBombings = GetPlayerGMDCarpetBombing(player)
	local sData = playerGMD_Data_knewCarpetBombings[bombPlanCode]
	if not sData then return end
	
	local id = "ECB" .. tostring(bombPlanCode)
	local qStep = "q" .. id .. "s001"
	
	local currentHour = getGameTime():getWorldAgeHours()
	local elapsedHours = math.floor(currentHour - (sData.activateStartHour or currentHour))
	
	EventCB_DoQuestList_AddItem({id = id, qStep = qStep, isDone = false, qtype = qtype, bombPlanCode = bombPlanCode, elapsedHours = elapsedHours})
	VLF.MarkerList_Add({qStep = qStep, x = sData.x, y = sData.y, texture = questMarker, bombPlanCode = bombPlanCode})
end
local AddToCBQuestList = VLECB.AddToCBQuestList

--Xóa hiển thị trên Quest List
local function EventCB_QuestList_RemoveItem(text) --EventCB_QuestList_RemoveItem("Q".."ECB"..tostring(bombPlanCode))
    if not text then return end
    if VLF.QuestListShowOnUI[text] then
        VLF.QuestListShowOnUI[text] = nil
    end
end

--Xóa hiển thị trên Quest List --CLIENT only
function VLECB.EventCB_RemoveQuestList(bombPlanCode, weatherCondition)
	if isServer() then return end
	weatherCondition = weatherCondition or "normal"
	
	local player = getPlayer()
	if not player then return end
	
	local playerGMD_Data_knewCarpetBombings = GetPlayerGMDCarpetBombing(player)
	if playerGMD_Data_knewCarpetBombings[bombPlanCode] then
		playerGMD_Data_knewCarpetBombings[bombPlanCode] = nil
		displayCarpetBombingPlan[bombPlanCode] = nil
		EventCB_QuestList_RemoveItem("Q" .. "ECB" .. tostring(bombPlanCode))
		VLF.MarkerList_Remove("q" .. "ECB" .. tostring(bombPlanCode) .. "s001")
		
		--Popup 
		local isCanHear, radio = PlayerCanHearAnyRadio(player)
		if isCanHear == true then
			if weatherCondition == "verybad" then
				VLF.QuestUpdatedPopIn("radio_CB", "cancel")
			else
				VLF.QuestUpdatedPopIn("radio_CB", "start")
			end
		end
	end
end

--Player đang nghe được radio thì hiện quest, hiện halo --SP + Client
function VLECB.BroadCastAboutCarpetBombing(player, bombPlanCode)
	if not bombPlanCode then return end
	player = player or getPlayer()
	
	--Nếu player nghe được tiếng Radio
	local isCanHear, radio = PlayerCanHearAnyRadio(player)
	if isCanHear == true then
		local playerGMD_Data_knewCarpetBombings = GetPlayerGMDCarpetBombing(player)
		
		local questMD_Events_CarpetBombing = GetModDataCarpetBombingEvent()
		local bombingData = questMD_Events_CarpetBombing["Plan"][bombPlanCode]
		if not bombingData then return end
		
		--Nếu bombPlanCode này chưa từng nghe được tin tức THÌ show Quest List và update Data
		if not playerGMD_Data_knewCarpetBombings[bombPlanCode] then
			print("Shared---BroadCastAboutCarpetBombing---Heard News---bombPlanCode= ", bombPlanCode)
			--update ModData Player đã nghe được tin tức
			UpdatePlayerGMDKnewCarpetBombing(player, bombPlanCode)
			
			--Tạo function theo bombPlanCode để show trên Quest List
			displayCarpetBombingPlan[bombPlanCode] = AddToCBQuestList
			
			--Popup
			VLF.QuestUpdatedPopIn("radio_CB")
	
			--hiện HaloTextHelper
			HaloTextHelper.addGoodText(player, getText("IGUI_VLQ_CarpetBombing_GetNews"))
		--else
			--print("Shared---BroadCastAboutSupplyDropped---KNEW ABOUT THIS SUPPLY---bombPlanCode= ", bombPlanCode)
		end
	end
end
