--- Fixed func by @Elyon God of Code ---
--- Normal random distribution
local function LabRecipes_generateNormalRandom2(mean, stdDev)
    local u1 = ZombRandFloat(0.01,0.99);
    local u2 = ZombRandFloat(0.01,0.99);
    local z0 = math.sqrt(-2.0 * math.log(u1)) * math.cos(2.0 * math.pi * u2)
    return z0 * stdDev + mean
end

local function LabRecipes_scaleToRange2(value, originalMin, originalMax, targetMin, targetMax)
    local scaleFactor = (targetMax - targetMin) / (originalMax - originalMin)
    return (value - originalMin) * scaleFactor + targetMin
end

local function LabRecipes_RandNorm2(min, max, mean, dev)
    local normalRandom = LabRecipes_generateNormalRandom2(mean, dev)
    local originalMin = mean - 3 * dev
    local originalMax = mean + 3 * dev
    local scaledValue = LabRecipes_scaleToRange2(normalRandom, originalMin, originalMax, min, max)
    scaledValue = math.max(min, math.min(max, scaledValue))
    return math.floor(scaledValue + 0.5)
end
--[[ -- old func
local function LabRecipes_RandNorm2(min, max, mean, dev)
	local u1 = ZombRandFloat(0.01,0.99);
	local u2 = ZombRandFloat(0.01,0.99);
	local rnd = mean*math.abs(1+math.sqrt(-2*(math.log(u1)))*math.cos(2*math.pi*u2)*dev);
	return min+math.floor(rnd/2*(max-min)+0.5);
end
--]]

-- Check vaccine effects
local function LabRecipes_AdjustPlayerHealth()
	local pBody = getPlayer():getBodyDamage();
	local pMod = getPlayer():getModData();
		
	if pBody:isInfected() then
		if pMod.VaccineRecess and pMod.VaccineRecess > 0 and LabRecipes_InfectionRate(getPlayer()) > 0.30 then
			pMod.VaccineRecess = pMod.VaccineRecess - 1;
			pBody:setInfectionTime(pBody:getInfectionTime()+pBody:getInfectionMortalityDuration()*LabRecipes_RandNorm2(9, 25, 1.1, 0.35)/100);
		end
		if pMod.VaccineTime and pMod.VaccineTime > 0 then
			if pMod.VaccineStrength > ZombRand(100) then
				pBody:setInfected(false);
				pBody:setInfectionLevel(0);
				pBody:setInfectionMortalityDuration(-1);
				pBody:setInfectionTime(-1);
				local parts = pBody:getBodyParts();
				for i = 0, parts:size()-1 do
					parts:get(i):SetInfected(false);
				end
			end
		end
	end
	if pMod.VaccineTime and pMod.VaccineTime > 0 then
		pMod.VaccineTime = pMod.VaccineTime-1;
	end
end

local function LabRecipes_AdjustPlayerStress()
	local player = getPlayer();
	local pBody = player:getBodyDamage();
	local pMod = player:getModData();
	local pStats = player:getStats();
	local pChangesStress = 0;
	local pChangerStress = 0.084;	-- accumulate ~0.0125 stress per 10 ingame min					-- 0,075 per hour
	local pChangerStress2 = 0.078;	-- accumulate ~0.0125 stress per 10 ingame min (for antibodies) -- 0,075 per hour
	
	if pBody:isInfected() then
		if pMod.VaccineRecess and pMod.VaccineRecess > 0 and not player:HasTrait("zReAntibodies") then
			pChangesStress = pStats:getStress() - pChangerStress;
			if pChangesStress < 0 then
				pChangesStress = 0;
			end
			pStats:setStress(pChangesStress);
		end
		if player:HasTrait("zReAntibodies") then
			pChangesStress = pStats:getStress() - pChangerStress2;
			if pChangesStress < 0 then
				pChangesStress = 0;
			end
			pStats:setStress(pChangesStress);
		end
	end
end

local function LabRecipes_AdjustPlayerAntibodies()
	local player = getPlayer();
	local pBody = player:getBodyDamage();
	
	if not (pBody:isInfected() and player:HasTrait("zReAntibodies")) then return end
	
	local pMod = player:getModData();
	local antibodyPowerRATE = {
	[1] = 0.8,
	[2] = 0.6,
	[3] = 0.4,
	[4] = 0.2,
	};
	local antibodyPower = SandboxVars.zReV2.AntibodyPower;
	local antibodyPower2 = SandboxVars.zReV2.AntibodyPower2;
	
	if (LabRecipes_InfectionRate(player) > antibodyPowerRATE[antibodyPower]) and (pMod.zReAntibodyed == nil or pMod.zReAntibodyed == 0) then
		pMod.zReAntibodyed = 1;
	end
	if pMod.zReAntibodyed == 1 then
		pBody:setInfectionTime(pBody:getInfectionTime()+pBody:getInfectionMortalityDuration()*antibodyPower2/100);
		if LabRecipes_InfectionRate(player) < 0.1 then
			pBody:setInfected(false);
			pBody:setInfectionLevel(0);
			pBody:setInfectionMortalityDuration(-1);
			pBody:setInfectionTime(-1);
			local parts = pBody:getBodyParts();
			for i = 0, parts:size()-1 do
				parts:get(i):SetInfected(false);
			end
			pMod.zReAntibodyed = 0;
		end
	end
end


---------- TRANSFER SOLUTION ----------
--------- BIG THANKS TO @Elyon --------
local function zReVACTransferFromV1toV2()
	local player = getPlayer();
	if not player then return end
	if player:isDead() then return end
	if player:getModData().zReVAC_TransferFlag == true then return end
	
	if (player:getModData().zReVAC2ResearchBegin == nil) or (player:getModData().zReVAC2ResearchBegin == 0) then
		if player:getKnownRecipes():contains("ChmSynthesizeSerum") then
			player:learnRecipe("LabResearchNotebookVaccineStart");
			player:getModData().zReVAC2ResearchBegin = 4;
		elseif player:getKnownRecipes():contains("ChmSynthesizeCure") then
			player:learnRecipe("LabResearchNotebookVaccineStart");
			player:learnRecipe("LabResearchToVaccineTo4lvl");
			player:getModData().zReVAC2ResearchBegin = 3;
		elseif player:getKnownRecipes():contains("ChmSynthesizeQualityVaccine") then
			player:learnRecipe("LabResearchNotebookVaccineStart");
			player:learnRecipe("LabResearchToVaccineTo3lvl");
			player:getModData().zReVAC2ResearchBegin = 2;
		elseif player:getKnownRecipes():contains("ChmSynthesizePlainVaccine") and not player:getKnownRecipes():contains("LabResearchNotebookVaccineStart") then
			player:getKnownRecipes():remove("ChmSynthesizePlainVaccine");
		end
	end
	
	if player:getKnownRecipes():contains("ChmSynthesizeSerum") and player:getModData().zReVAC2ResearchBegin < 4 then
		player:getKnownRecipes():remove("ChmSynthesizeSerum");
	end
	if player:getKnownRecipes():contains("ChmSynthesizeCure") and player:getModData().zReVAC2ResearchBegin < 3 then
		player:getKnownRecipes():remove("ChmSynthesizeCure");
	end
	if player:getKnownRecipes():contains("ChmSynthesizeQualityVaccine") and player:getModData().zReVAC2ResearchBegin < 2 then
		player:getKnownRecipes():remove("ChmSynthesizeQualityVaccine");
	end
	player:getModData().zReVAC_TransferFlag = true;
end

---------------------------------------- Events ----------------------------------------
Events.EveryHours.Add(LabRecipes_AdjustPlayerHealth);
Events.EveryHours.Add(LabRecipes_AdjustPlayerStress);
Events.EveryHours.Add(LabRecipes_AdjustPlayerAntibodies);

Events.OnCreatePlayer.Add(zReVACTransferFromV1toV2);
Events.OnCreateLivingCharacter.Add(zReVACTransferFromV1toV2);