
local MakePlayerCharacter = require "prefabs/player_common"


local assets = {

        Asset( "ANIM", "anim/player_basic.zip" ),
        Asset( "ANIM", "anim/player_idles_shiver.zip" ),
        Asset( "ANIM", "anim/player_actions.zip" ),
        Asset( "ANIM", "anim/player_actions_axe.zip" ),
        Asset( "ANIM", "anim/player_actions_pickaxe.zip" ),
        Asset( "ANIM", "anim/player_actions_shovel.zip" ),
        Asset( "ANIM", "anim/player_actions_blowdart.zip" ),
        Asset( "ANIM", "anim/player_actions_eat.zip" ),
        Asset( "ANIM", "anim/player_actions_item.zip" ),
        Asset( "ANIM", "anim/player_actions_uniqueitem.zip" ),
        Asset( "ANIM", "anim/player_actions_bugnet.zip" ),
        Asset( "ANIM", "anim/player_actions_fishing.zip" ),
        Asset( "ANIM", "anim/player_actions_boomerang.zip" ),
        Asset( "ANIM", "anim/player_bush_hat.zip" ),
        Asset( "ANIM", "anim/player_attacks.zip" ),
        Asset( "ANIM", "anim/player_idles.zip" ),
        Asset( "ANIM", "anim/player_rebirth.zip" ),
        Asset( "ANIM", "anim/player_jump.zip" ),
        Asset( "ANIM", "anim/player_amulet_resurrect.zip" ),
        Asset( "ANIM", "anim/player_teleport.zip" ),
        Asset( "ANIM", "anim/wilson_fx.zip" ),
        Asset( "ANIM", "anim/player_one_man_band.zip" ),
        Asset( "ANIM", "anim/shadow_hands.zip" ),
        Asset( "SOUND", "sound/sfx.fsb" ),
        Asset( "SOUND", "sound/wilson.fsb" ),
        Asset( "ANIM", "anim/beard.zip" ),

        Asset( "ANIM", "anim/rem.zip" ),
		Asset( "ANIM", "anim/rem2.zip" ),
        Asset( "ANIM", "anim/ghost_rem_build.zip" ),
		
		Asset( "ATLAS", "images/remtab.xml" ),
		
		Asset( "ATLAS", "images/rem_li.xml" ),
		Asset( "ATLAS", "images/rem_su.xml" ),
		Asset( "ATLAS", "images/rem_xue.xml" ),
		
		Asset("SOUNDPACKAGE", "sound/rem_music.fev"),
		Asset("SOUND", "sound/rem_music.fsb"),
		
		Asset( "ATLAS", "images/izayoi_theworld.xml" ),
		
}
local prefabs = {}

-- Custom starting items
local start_inv = {
	"rem_bola", "rem_armor",
}

--------------------------------------------------------------------------------------------------
local MONSTERVISION_COLOURCUBES =
{
    day = "images/colour_cubes/beaver_vision_cc.tex",
    dusk = "images/colour_cubes/beaver_vision_cc.tex",
    night = "images/colour_cubes/beaver_vision_cc.tex",
    full_moon = "images/colour_cubes/beaver_vision_cc.tex",
}

----黑暗视野
local function NightVision(inst)
	if not TheWorld.state.isday then
		local sanitypercent = inst.replica.sanity:GetPercent()
		if sanitypercent <= .5 then
			inst.components.playervision:ForceNightVision(true)
			inst.components.playervision:SetCustomCCTable(MONSTERVISION_COLOURCUBES)
		else
			inst.components.playervision:ForceNightVision(false)
			inst.components.playervision:SetCustomCCTable(nil)
		end
    else
        inst.components.playervision:ForceNightVision(false)
        inst.components.playervision:SetCustomCCTable(nil)
	end
end

----等级
local function applyupgrades(inst)
    local max_upgrades = 5
    inst.level_li = math.min(inst.level_li, max_upgrades)
	inst.level_su = math.min(inst.level_su, max_upgrades)
	inst.level_xue = math.min(inst.level_xue, max_upgrades)
	
	----同步一下网络
	local detail_ushortint1 = 
	{	
		"level_li", "level_su", "level_xue"
	}
	for k, v in pairs(detail_ushortint1) do
		if inst["u"..v] then
			inst["net_u"..v]:set(inst[v])
		end
	end
	
	local str = "Level Strength"..( inst.level_li >= max_upgrades and " Max" or "")..": "..inst.level_li
	str = str .. "\n".."Level Speed"..( inst.level_su >= max_upgrades and " Max" or "")..": "..inst.level_su
	str = str .. "\n".."Level Blood"..( inst.level_xue >= max_upgrades and " Max" or "")..": "..inst.level_xue
	
	inst.components.talker:Say( str )
end

local function oneat(inst, food)
    if food and food.components.edible and food.prefab == "redgem" then
		
		----升级算法
		local skilltable = {}
		local hastable = {"li", "su", "xue"}
		
		--选取具有升级空间的项
		for k,v in pairs(hastable) do
			if inst["level_"..v] < 5 then
				table.insert(skilltable, v)
			end
		end
		
		--从选取的具有升级空间项选一个
		if #skilltable > 0 then 
			local skill_str = "level_"..skilltable[math.random(#skilltable)]
			inst[skill_str] = inst[skill_str] + 1
		end
		
		--通用作用
		applyupgrades(inst) 
		inst.SoundEmitter:PlaySound("dontstarve/characters/wx78/levelup")
		inst.components.health:DoDelta(100)
			
    end
end

local function onpreload(inst, data)
    if data then
        inst.level_li = data.level_li or 0
		inst.level_su = data.level_su or 0
		inst.level_xue = data.level_xue or 0
        applyupgrades(inst)
    end
end
local function onsave(inst, data)
    data.level_li = inst.level_li or 0
	data.level_su = inst.level_su or 0
	data.level_xue = inst.level_xue or 0
end

--------------------------------------------------------------------------------------------------
-- When the character is revived from human
local function onbecamehuman(inst)
	-- Set speed when loading or reviving from ghost (optional)
	inst.components.locomotor.walkspeed = 4
	inst.components.locomotor.runspeed = 6
	applyupgrades(inst) 
end

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

    if not inst:HasTag("playerghost") then
        onbecamehuman(inst)
    end
end

-- This initializes for both the server and client. Tags can be added here.
local common_postinit = function(inst) 
	-- Minimap icon
	inst.MiniMapEntity:SetIcon( "rem.tex" )
	inst:AddTag("rembuilder")
	inst:AddTag("rem_music")
	
	--夜视
	inst:AddTag("nightvision")
	inst:DoPeriodicTask(1, function()
		NightVision(inst)
	end)
	--inst:WatchWorldState("startnight", NightVision)
	--inst:WatchWorldState("startday", NightVision)
	
	--属性点
	inst:AddTag("rem_skiller")
	
	----整型新体系
	local detail_ushortint1 = 
	{	
		"ulevel_li", "ulevel_su", "ulevel_xue"
	}
	for k, v in pairs(detail_ushortint1) do
		inst[v] = 0
		inst["net_"..v] = net_ushortint( inst.GUID, v, v.."_dirty" )
			inst:ListenForEvent( v.."_dirty", function()
			inst[v] = inst["net_"..v]:value()
		end)
	end
	
	inst:AddComponent("zg_keyhandler_rem")
	inst.components.zg_keyhandler_rem:AddActionListener("rem", KEY_R, "r_skill")
	
	--计时器
	inst:AddComponent("timer")
	inst:ListenForEvent("timerdone", function(inst, data)
		local name = data.name
		if name == "respawn_ok" then
			inst[name] = true
		elseif name == "r_skill" then
			inst[name] = true
		end
	end)
	
	inst["respawn_ok_cd"] = 600
	inst["r_skill_cd"] = 120			----120
	
	inst["respawn_ok"] = true
	if not (inst["respawn_ok"] or inst.components.timer:TimerExists("respawn_ok")) then
		inst.components.timer:StartTimer("respawn_ok", inst["respawn_ok_cd"])
	end
	if not (inst["r_skill"] or inst.components.timer:TimerExists("r_skill")) then
		inst.components.timer:StartTimer("r_skill", inst["r_skill_cd"])
	end
	
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"
	
	-- Uncomment if "wathgrithr"(Wigfrid) or "webber" voice is used
    --inst.talker_path_override = "dontstarve_DLC001/characters/"
	
	-- Stats	
	inst.components.health:SetMaxHealth(250)
	inst.components.hunger:SetMax(150)
	inst.components.sanity:SetMax(100)
	
	-- Damage multiplier (optional)
    inst.components.combat.damagemultiplier = 1
	
	-- Hunger rate (optional)
	inst.components.hunger.hungerrate = 1 * TUNING.WILSON_HUNGER_RATE
	
	--无视怪物的恐惧光环
	inst.components.sanity.neg_aura_mult = 0
	
	--等级, 鬼族之力，鬼族之速，鬼族之血
	inst.level_li = 0
	inst.level_su = 0
	inst.level_xue = 0
	
	--吃红宝石增加实力
	local eater = inst.components.eater
	table.insert(eater.preferseating, FOODTYPE.ELEMENTAL)
    table.insert(eater.caneat, FOODTYPE.ELEMENTAL)
    inst:AddTag(FOODTYPE.ELEMENTAL.."_eater")
	eater:SetOnEatFn(oneat)
	
	--
	applyupgrades(inst)
	
	--每次攻击自己也会受到5点真实伤害, 鬼化时为10
	local function OnHitOther(inst, data)
		local sanitypercent = inst.components.sanity:GetPercent()
		--inst.components.health:DoDelta( (-5) * ( sanitypercent <= .5 and 2 or 1 ), nil, nil, nil, nil, true)
		inst.components.health:DoDelta( 20 )
		
		local x,y,z = inst.Transform:GetWorldPosition()
		local ents = TheSim:FindEntities(x,y,z,10,{"ram_music"}, {"playerghost"})
		for k, v in pairs(ents) do
			if v and not v.components.health:IsDead() then
				v.components.health:DoDelta(20)
			end
		end
		
		local target = data.target
		if target then
			if math.random() < .2 then
				--被动R技能
				local fx = SpawnPrefab("rem_icespike")
				fx.Transform:SetPosition( inst.Transform:GetWorldPosition() )
				fx.Transform:SetScale(2,2,2)
				fx._mult = 2
				fx.master = inst
				fx.Transform:SetRotation( inst:GetAngleToPoint( target:GetPosition():Get() ) )
				fx.Physics:SetMotorVelOverride(5,0,0) 
			end
		end
		
	end
	inst:ListenForEvent("onhitother", OnHitOther)
	
	--联体婴儿效应
	local combat = inst.components.combat
	local old_getattacked = combat.GetAttacked
	function combat:GetAttacked(attacker, damage, weapon, stimuli)
	
		--if inst.components.health:IsDead() or inst:HasTag("playerghost") then
		--	return 
		--end
	
		--拉姆效应
		local count = 1
		local x,y,z = inst.Transform:GetWorldPosition()
		local ents = TheSim:FindEntities(x,y,z,10,{"ram_music"}, {"playerghost"})
		for k, v in pairs(ents) do
			if v then
				count = count + 1
			end
		end
		
		local damage = damage / count
		
		for k, v in pairs(ents) do
			if v and not v.components.health:IsDead() then
				
				local damage2 = damage
				if v.components.inventory ~= nil then
					damage2 = v.components.inventory:ApplyDamage(damage2, attacker, weapon)
				end
				v.components.health:DoDelta(-damage2)
				
			end
		end
		
		return old_getattacked(self, attacker, damage, weapon, stimuli)
		
	end
	
	inst.ram_effect = 1
	
	--精神到一半时鬼化状态
	local function OnSanityDelta(inst, data)
		if not inst.components.health:IsDead() and not inst:HasTag("playerghost") then
			local newpercent = data.newpercent
			--样貌
			inst.AnimState:SetBuild( "rem".. ( (inst.ram_effect == 2 or newpercent <= .5) and "2" or "") )
			--攻击倍数
			inst.components.combat.damagemultiplier = (newpercent <= .5 and ( 1 + inst.level_li * 0.2 ) or 1) * inst.ram_effect
			--速度
			inst.components.locomotor:SetExternalSpeedMultiplier(inst, "rem_speed_mod", newpercent <= .5 and ( 1 + inst.level_su * 0.1 ) or 1)
		end
	end
	inst:ListenForEvent("sanitydelta", OnSanityDelta)
	
	--回血, 和拉姆在一起的效果
	inst:DoPeriodicTask(1, function()
		--NightVision(inst)
		local sanitypercent = inst.components.sanity:GetPercent()
		if sanitypercent <= .5 then
			if not inst.components.health:IsDead() and not inst:HasTag("playerghost") then
				inst.components.health:DoDelta( ( 20 + (inst.level_xue - 1)*10 ) * 1/60 , true)
			end
		end
		
		--拉姆效应
		local x,y,z = inst.Transform:GetWorldPosition()
		local ents = TheSim:FindEntities(x,y,z,10,{"ram_music"}, {"playerghost"})
		for k, v in pairs(ents) do
			if v then
				if not inst.components.health:IsDead() and not inst:HasTag("playerghost") then
					inst.components.hunger:DoDelta( 1 , true )
					inst.components.sanity:DoDelta( 1 , true )
				end
			end
		end
		
	end)
	
	--死后30s自动复活
	inst:ListenForEvent("death", function(inst, data)
		inst:DoTaskInTime(30, function()
			if inst:HasTag("playerghost") then
				inst:PushEvent("respawnfromghost")
				inst.components.health:DoDelta(50)
				inst.components.sanity:DoDelta(50)
				--inst.components.health:SetPercent(1)
				--inst.components.sanity:SetPercent(1)
				inst.components.hunger:SetPercent(1)
				
			end
		end)
	end)
	
	inst.OnSave = onsave
	inst.OnLoad = onload
    inst.OnNewSpawn = onload
	inst.OnPreLoad = onpreload
end

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