
local MakePlayerCharacter = require "prefabs/player_common"


local assets = {
    Asset("SCRIPT", "scripts/prefabs/player_common.lua"),
	Asset("ANIM", "anim/verniy.zip"),
}
local prefabs = {
	"werebeaver_transform_fx"
}

-- Custom starting items
local start_inv = {
}

local function applyupgrades(inst)
	if TUNING.HIBIKI.TRUSTWORTHY == true then
		local max_upgrades = 10
		inst.level = math.min(inst.level, max_upgrades)

		local hunger_percent = inst.components.hunger:GetPercent()
		local health_percent = inst.components.health:GetPercent()
		local sanity_percent = inst.components.sanity:GetPercent()

		inst.components.hunger.max = math.ceil(TUNING.HIBIKI.BASEHUNGER + inst.level * (TUNING.HIBIKI.MAXHUNGER - TUNING.HIBIKI.BASEHUNGER) / max_upgrades)
		inst.components.health.maxhealth = math.ceil(TUNING.HIBIKI.BASEHEALTH + inst.level * (TUNING.HIBIKI.MAXHEALTH - TUNING.WX78_MIN_HEALTH) / max_upgrades)
		inst.components.sanity.max = math.ceil(TUNING.HIBIKI.BASESANITY + inst.level * (TUNING.HIBIKI.MAXSANITY - TUNING.HIBIKI.BASESANITY) / max_upgrades)

		inst.components.hunger:SetPercent(hunger_percent)
		inst.components.health:SetPercent(health_percent)
		inst.components.sanity:SetPercent(sanity_percent)
		
		if TUNING.HIBIKI.PHOENIX_RESILIENCE == true then
			inst.components.health:SetAbsorptionAmount(0.1 + (0.01 * inst.level))
		end
		
		if TUNING.HIBIKI.GENERAL_WINTER == true then
			inst.components.temperature.inherentinsulation = (TUNING.INSULATION_MED * (0.2 * inst.level))
		end
		
		if TUNING.HIBIKI.SURVIVOR_GUILT == true then
			inst.components.sanity.rate_modifier = 1.15 - (0.01 * inst.level)
		end
		
		if inst.level == max_upgrades then
			inst.components.combat.damagemultiplier = 1.25
			inst.components.locomotor.walkspeed = (TUNING.WILSON_WALK_SPEED * 1.1)
			inst.components.locomotor.runspeed = (TUNING.WILSON_RUN_SPEED * 1.1)
		else
			inst.components.combat.damagemultiplier = 1
			inst.components.locomotor.walkspeed = (TUNING.WILSON_WALK_SPEED)
			inst.components.locomotor.runspeed = (TUNING.WILSON_RUN_SPEED)
		end
	end
end

local function checksuffering(inst)
	if inst.level < 10 and TUNING.HIBIKI.TRUSTWORTHY == true and not inst:HasTag("playerghost") then
		local suffering_nextlevel = 75 + 25 * inst.level
		if inst.suffering >= suffering_nextlevel then
			inst.suffering = 0
			inst.level = inst.level + 1
			if inst.level == 1 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_1")))
			elseif inst.level == 2 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_2")))
			elseif inst.level == 3 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_3")))
			elseif inst.level == 4 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_4")))
			elseif inst.level == 5 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_5")))
			elseif inst.level == 6 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_6")))
			elseif inst.level == 7 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_7")))
			elseif inst.level == 8 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_8")))
			elseif inst.level == 9 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_LEVELUP_9")))
			elseif inst.level == 10 then
				inst.components.talker:Say((GetString(inst, "ANNOUNCE_VERNIY")))
				SpawnPrefab("werebeaver_transform_fx").Transform:SetPosition(inst.Transform:GetWorldPosition())
				inst.AnimState:SetBuild("verniy")
			end
			applyupgrades(inst)
			inst.SoundEmitter:PlaySound("dontstarve/characters/wx78/levelup")
		end
	else
		inst.suffering = 0
	end
end

--Level test, comment this whole function out if done.
-- local function oneat(inst, food)
    -- if food and food.components.edible then
        -- inst.level = inst.level + 1
        -- applyupgrades(inst) 
        -- inst.SoundEmitter:PlaySound("dontstarve/characters/wx78/levelup")
    -- end
-- end

local function ondeath(inst)
	if inst.level == 10 then
		SpawnPrefab("werebeaver_transform_fx").Transform:SetPosition(inst.Transform:GetWorldPosition())
		inst.AnimState:SetBuild("hibiki")
		inst.components.talker:Say((GetString(inst, "ANNOUNCE_DEATH_RUSSIAN")))
	else
		inst.components.talker:Say((GetString(inst, "ANNOUNCE_DEATH")))
	end
	if inst.level >= 5 then
		inst.level = 5
	end
	inst.sufffering = 0
	applyupgrades(inst)
end

-- When the character is revived from human
local function onbecamehuman(inst)
	-- Set speed when reviving from ghost (optional)
	inst.components.locomotor:SetExternalSpeedMultiplier(inst, "hibiki_speed_mod", 1)
end

local function onbecameghost(inst)
	-- Remove speed modifier when becoming a ghost
   inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "hibiki_speed_mod")
end

-- When loading or spawning the character
local function onload(inst)
    inst:ListenForEvent("ms_respawnedfromghost", onbecamehuman)
    inst:ListenForEvent("ms_becameghost", onbecameghost)

    if inst:HasTag("playerghost") then
        onbecameghost(inst)
    else
        onbecamehuman(inst)
    end
	
	if inst.level == 10 then
		inst.AnimState:SetBuild("verniy")
	end
end

local function onpreload(inst, data)
    if data ~= nil and data.level ~= nil and data.suffering ~= nil and TUNING.HIBIKI.TRUSTWORTHY == true then
        inst.level = data.level
		inst.suffering = data.suffering
        applyupgrades(inst)
        --re-set these from the save data, because of load-order clipping issues
        if data.health and data.health.health then inst.components.health:SetCurrentHealth(data.health.health) end
        if data.hunger and data.hunger.hunger then inst.components.hunger.current = data.hunger.hunger end
        if data.sanity and data.sanity.current then inst.components.sanity.current = data.sanity.current end
        inst.components.health:DoDelta(0)
        inst.components.hunger:DoDelta(0)
        inst.components.sanity:DoDelta(0)
    end
end

local function onsave(inst, data)
    data.level = inst.level
	data.suffering = inst.suffering
    --data.charge_time = inst.charge_time > 0 and inst.charge_time or nil
end

-- This initializes for both the server and client. Tags can be added here.
local common_postinit = function(inst) 
	-- Minimap icon
	inst.MiniMapEntity:SetIcon( "hibiki.tex" )
	inst:AddTag("anchor_builder")
end

-- This initializes for the server only. Components are added here.
local master_postinit = function(inst)
	-- choose which sounds this character will play
	inst.soundsname = "willow"
	inst.level = 0
	inst.suffering = 0
	
	-- Uncomment if "wathgrithr"(Wigfrid) or "webber" voice is used
    --inst.talker_path_override = "dontstarve_DLC001/characters/"
	
	-- Stats	
	if TUNING.HIBIKI.TRUSTWORTHY == true then
		inst.components.health:SetMaxHealth(150)
		inst.components.hunger:SetMax(100)
		inst.components.sanity:SetMax(100)
	else
		inst.components.health:SetMaxHealth(200)
		inst.components.hunger:SetMax(150)
		inst.components.sanity:SetMax(100)
	end
	
	-- Sanity gain from nearby players (taken from http://steamcommunity.com/sharedfiles/filedetails/?id=368230903)
	if TUNING.HIBIKI.SURVIVOR_GUILT == false then
		inst.components.sanity.rate_modifier = 1
	else
		if TUNING.HIBIKI.TRUSTWORTHY == true then
			inst.components.sanity.rate_modifier = 1.15
		else
			inst.components.sanity.rate_modifier = 1.1
		end
	end
	
	local function sanityfn(inst)
		if TUNING.HIBIKI.SURVIVOR_GUILT == false then
			return 0
		else
			local x,y,z = inst.Transform:GetWorldPosition()   
			local delta = 0
			local rad = 20
			local rad_sq = rad*rad
			for k,v in pairs(AllPlayers) do
				if v ~= inst then
					local distsq = inst:GetDistanceSqToInst(v)
					if distsq < rad_sq then
						local sz = (TUNING.SANITYAURA_TINY * rad) * 0.2
						delta = delta + sz/math.max(1, distsq)
					end
				end
			end
			return delta
		end
	end
	inst.components.sanity.custom_rate_fn = sanityfn
	
	-- Damage multiplier (optional)
    inst.components.combat.damagemultiplier = 1
	if TUNING.HIBIKI.PHOENIX_RESILIENCE == true then
		inst.components.health:SetAbsorptionAmount(0.1)
	end
	inst:ListenForEvent("death", ondeath)
	
	-- inst._GetAttacked = inst.components.combat.GetAttacked
	-- inst.components.combat.GetAttacked = function(attacker, damage, weapon, stimuli)
		-- inst._GetAttacked(attacker, damage, weapon, stimuli) 
		-- inst.suffering = inst.suffering + damage
	-- end
	
	inst:ListenForEvent("healthdelta", function(inst, data)
		local sufferingdamage = (data.oldpercent - data.newpercent) * inst.components.health.maxhealth
		if sufferingdamage > 0 then
			inst.suffering = inst.suffering + sufferingdamage
			checksuffering(inst)
			--inst.components.talker:Say(tostring(sufferingdamage))
		end
	end)
	
	inst:ListenForEvent("sanitydelta", function(inst, data)
		local sufferingsanity = (data.oldpercent - data.newpercent) * inst.components.sanity.max
		if sufferingsanity > 0 then
			inst.suffering = inst.suffering + sufferingsanity
			checksuffering(inst)
			--inst.components.talker:Say(tostring(sufferingdamage))
		end
	end)
	
	-- Cold Resistance
	if TUNING.HIBIKI.GENERAL_WINTER == true then
		if TUNING.HIBIKI.TRUSTWORTHY == true then
			inst.components.temperature.inherentinsulation = TUNING.INSULATION_MED
		else
			inst.components.temperature.inherentinsulation = TUNING.INSULATION_LARGE
		end
	end
	
	-- Hunger rate (optional)
	inst.components.hunger.hungerrate = 1 * TUNING.WILSON_HUNGER_RATE
	-- inst.components.eater:SetOnEatFn(oneat)
	
	applyupgrades(inst)
	
	inst.OnSave = onsave
    inst.OnPreLoad = onpreload
	inst.OnLoad = onload
    inst.OnNewSpawn = onload
	
end

return MakePlayerCharacter("hibiki", prefabs, assets, common_postinit, master_postinit, start_inv)
