--[[
BY
 _____   _____   __   _  
|  _  \ /  _  \ |  \ | | 
| | | | | | | | |   \| | 
| | | | | | | | | |\   | 
| |_| | | |_| | | | \  | 
|_____/ \_____/ |_|  \_| 

]]
local PET_BRAIN = require("brains/lfy_packimbrain")
local PET_SG = "SGpackim"
require ("stategraphs/" .. PET_SG)

--GERAL:
local STR_PETTAG = "Pet"
local STR_BEFR = "Befriend a"
local WAKE_TO_FOLLOW_DISTANCE = 6
local SLEEP_NEAR_LEADER_DISTANCE = 5

local HUNGRY_PERISH_PERCENT = 0.5
local STARVING_PERISH_PERCENT = 0.2

local function turnon(inst)
    inst.components.machine.ison = true
	if inst.components.follower then
		if inst.components.follower.leader and inst.components.follower.leader.lfy_packim then
			inst.components.follower.leader.lfy_packim=nil
		end
	end
    inst:Remove()

end


----------------------

--PACKIM
local packimname = "Packim Baggims"

STRINGS.NAMES.PETDONPACKIM_BUILDER = ("小鹈鹕")
STRINGS.RECIPE_DESC.PETDONPACKIM_BUILDER = ("小鹈鹕")

local packimanimzip =
{
	Asset("ANIM", "anim/packim.zip"),
	Asset("ANIM", "anim/lfy_packim_build.zip"),
}

local packimconfiganim = 
{
	bank = "packim",
	build = "lfy_packim_build",
}


local packimanims = 
{
	idle = "idle_loop", --parado
	hungry = "hit", --fome
	eat = "swallow", --comer
	sleep_pre = "sleep_pre", --dormir
	sleep_pst = "sleep_pst", --dormir
	sleep_loop = "sleep_loop", --dormir
	walk_pre = "walk_pre", --andar
	walk_pst = "walk_pst", --andar
	walk_loop = "walk_loop", --andar
	
	emote_pet = "transform", --carinho
	emote_nuzzle = "takeoff", --carinho 2
	emote_playful = "takeoff", --brincar
}

local packimsounds = 
{
	walk = "petdonpackimsounds/petdonpackimsounds/DSS_packim_fly_02", --andar
	
	sleep = "petdonpackimsounds/petdonpackimsounds/PACKIM_Death_01", --dormir
	yell = "petdonpackimsounds/petdonpackimsounds/DSS_packim_fat_Open_01", --grito/carinho
	eat = "petdonpackimsounds/petdonpackimsounds/PACKIM_Open_1", --comer
	chew = "petdonpackimsounds/petdonpackimsounds/PACKIM_Open_11", --mastigar
	hungry = "petdonpackimsounds/petdonpackimsounds/DSS_packim_swallow_v2_5", --fome
	grunt = "petdonpackimsounds/petdonpackimsounds/DSS_packim_fat_hit_08", --grunhido
	
	bodyfall = "dontstarve/creatures/together/sheepington/bodyfall", --cair
}
----------------------


----------------------






local function IsLeaderSleeping(inst)
    return inst.components.follower.leader and inst.components.follower.leader:HasTag("sleeping")
end

local function ShouldWakeUp(inst)
    return (DefaultWakeTest(inst) and not IsLeaderSleeping(inst)) or not inst.components.follower:IsNearLeader(WAKE_TO_FOLLOW_DISTANCE)
end

local function ShouldSleep(inst)
    return (DefaultSleepTest(inst) 
            or IsLeaderSleeping(inst))
            and inst.components.follower:IsNearLeader(SLEEP_NEAR_LEADER_DISTANCE)
end

local function oneat(inst, food)
	local perish = inst.components.perishable:GetPercent()
	local is_wellfed = inst.components.crittertraits:IsDominantTrait("wellfed")
	if food and food.prefab=="meatballs" then
		inst:AddTag("packimchop")
		inst:DoTaskInTime(120, function()
            inst:RemoveTag("packimchop")
		end)   
	end
	if food and food.prefab=="kabobs"  then
		inst:AddTag("packimmine")
		inst:DoTaskInTime(90, function()
            inst:RemoveTag("packimmine")
		end)   
	end
	
	if perish <= STARVING_PERISH_PERCENT then
		inst.components.perishable.perishtime = math.max(inst.components.perishable.perishtime - TUNING.CRITTER_HUNGERTIME_DELTA, is_wellfed and TUNING.CRITTER_DOMINANTTRAIT_HUNGERTIME_MIN or TUNING.CRITTER_HUNGERTIME_MIN)
	elseif perish <= HUNGRY_PERISH_PERCENT then
		inst.components.perishable.perishtime = math.min(inst.components.perishable.perishtime + TUNING.CRITTER_HUNGERTIME_DELTA, is_wellfed and TUNING.CRITTER_DOMINANTTRAIT_HUNGERTIME_MAX or TUNING.CRITTER_HUNGERTIME_MAX)
	else
		if is_wellfed and inst.components.perishable.perishtime < TUNING.CRITTER_DOMINANTTRAIT_HUNGERTIME_MIN then
			inst.components.perishable.perishtime = TUNING.CRITTER_DOMINANTTRAIT_HUNGERTIME_MIN
		end
	end
	
    inst.components.perishable:SetPercent(1)
    inst.components.perishable:StartPerishing()
	
	if food ~= nil then
		if inst.favoritefood == food.prefab then
			inst.isfavoritefood = 1
		else
			inst.isfavoritefood = 0
		end
	end
	
end

-------------------------------------------------------------------------------
local function GetPeepChance(inst)
    local hunger_percent = inst.components.perishable:GetPercent()
    if hunger_percent <= 0 then
        return 0.8
    elseif hunger_percent < STARVING_PERISH_PERCENT then -- matches spoiled tag
        return (0.2 - inst.components.perishable:GetPercent()) * 2
    elseif hunger_percent < HUNGRY_PERISH_PERCENT then
        return 0.025
    end

    return 0
end

local function IsAffectionate(inst)
    return (inst.components.perishable == nil or inst.components.perishable:GetPercent() > STARVING_PERISH_PERCENT)
            or false
end

local function IsPlayful(inst)
	return IsAffectionate(inst)
end

local function IsSuperCute(inst)
	return true
end

-------------------------------------------------------------------------------

local function OnSave(inst, data)
    if inst.wormlight ~= nil then
        data.wormlight = inst.wormlight:GetSaveRecord()
    end
end

local function OnLoad(inst, data)
    if data ~= nil and data.wormlight ~= nil and inst.wormlight == nil then
        local wormlight = SpawnSaveRecord(data.wormlight)
        if wormlight ~= nil and wormlight.components.spell ~= nil then
            wormlight.components.spell:SetTarget(inst)
            if wormlight:IsValid() then
                if wormlight.components.spell.target == nil then
                    wormlight:Remove()
                else
                    wormlight.components.spell:ResumeSpell()
                end
            end
        end
    end
end
local function unlinktoplayer(inst)
	if inst._playerlink and inst._playerlink.lfy_packim then
		inst._playerlink.lfy_packim = nil
		inst._playerlink = nil
	end
end

local function linktoplayer(inst, player)
	inst.persists = false
	inst._playerlink = player
	--inst.components.named:SetName("宝宝")
	player.lfy_packim = inst
	player.components.leader:AddFollower(inst)
	player:ListenForEvent("onremove", unlinktoplayer, inst)
end
-------------------------------------------------------------------------------

local function MakeDonPet(name, petname, face, gwalktype, petscale, diet, flying, animszip, configanim, petanims, petsounds, data)

    local function fn()
        local inst = CreateEntity()

        inst.entity:AddTransform()
        inst.entity:AddAnimState()
        inst.entity:AddSoundEmitter()
        inst.entity:AddDynamicShadow()
        inst.entity:AddNetwork()

        inst.DynamicShadow:SetSize(2, .75)
		
		
				
		inst.animsdon = petanims
		inst.soundsdon = petsounds

        if face == 0 then
            inst.Transform:SetNoFaced()
        elseif face == 2 then
			inst.Transform:SetTwoFaced()
        elseif face == 4 then
            inst.Transform:SetFourFaced()
        elseif face == 6 then
            inst.Transform:SetSixFaced()
        elseif face == 8 then
            inst.Transform:SetEightFaced()
        end

        inst.AnimState:SetBank(configanim.bank)
        inst.AnimState:SetBuild(configanim.build)
        inst.AnimState:PlayAnimation(inst.animsdon.idle)
		
		
		
        if flying then
            inst.entity:AddPhysics()
            inst.Physics:SetMass(1)
            inst.Physics:SetFriction(0)
            inst.Physics:SetDamping(5)
            inst.Physics:SetCollisionGroup(COLLISION.CHARACTERS)
            inst.Physics:ClearCollisionMask()
            inst.Physics:CollidesWith(COLLISION.WORLD)
            inst.Physics:CollidesWith(COLLISION.FLYERS)
            inst.Physics:CollidesWith(COLLISION.CHARACTERS)
            inst.Physics:SetCapsule(.5, 1)

            inst:AddTag("flying")
        else
            MakeCharacterPhysics(inst, 1, .5)
        end

		inst.Physics:SetDontRemoveOnSleep(true)

        inst:AddTag("critter")
        inst:AddTag("companion")
        inst:AddTag("notraptrigger")
        inst:AddTag("noauradamage")
        inst:AddTag("small_livestock")
        inst:AddTag("NOBLOCK")
		inst:AddTag("lfy_packim")
        if data ~= nil and data.flyingsoundloop ~= nil then
            inst.SoundEmitter:PlaySound(data.flyingsoundloop, "flying")
        end
		
		if petscale > 0 then
			inst.Transform:SetScale(petscale, petscale, petscale)
		end

        inst:AddComponent("spawnfader")

        inst.entity:SetPristine()

        if not TheWorld.ismastersim then
           inst:DoTaskInTime(0, function()
                    inst.replica.container:WidgetSetup("chester")
                end)
            return inst
        end
		
		inst.Transform:SetScale(0.5,0.5,0.5)
		
		inst:DoPeriodicTask(5,function()
			local x,y,z=inst.Transform:GetWorldPosition()
			local ents=TheSim:FindEntities(x,y,z,5,{"level3"})
			for k,v in pairs(ents) do
				if v and v:HasTag("level3") then
					if inst.components.machine==nil then
						inst:AddComponent("machine")
						inst.components.machine.turnonfn = turnon
					end
				else
					if inst.components.machine then	
						inst:RemoveComponent("machine")
					end
				end
				
			end
	    end)
		
		
		inst:AddComponent("container")
        inst.components.container:WidgetSetup("chester")

		inst.favoritefood = data.favoritefood

        inst.GetPeepChance = GetPeepChance
        inst.IsAffectionate = IsAffectionate
        inst.IsSuperCute = IsSuperCute
        inst.IsPlayful = IsPlayful
        
		inst.playmatetags = {"critter"}
		if data ~= nil and data.playmatetags ~= nil then
			inst.playmatetags = JoinArrays(inst.playmatetags, data.playmatetags)
		end
	
        inst:AddComponent("inspectable")



        inst:AddComponent("follower")
        inst.components.follower:KeepLeaderOnAttacked()
        inst.components.follower.keepdeadleader = true

        inst:AddComponent("knownlocations")

        inst:AddComponent("sleeper")
        inst.components.sleeper:SetResistance(3)
        inst.components.sleeper.testperiod = GetRandomWithVariance(6, 2)
        inst.components.sleeper:SetSleepTest(ShouldSleep)
        inst.components.sleeper:SetWakeTest(ShouldWakeUp)

		local isfavoritefood = 0
		inst.isfavoritefood = 0		
		
		local walktype = "walk"
		inst.walktype = gwalktype
		
		local checkpetdonsize = petscale
		inst.checkpetdonsize = petscale

        inst:AddComponent("eater")
        inst.components.eater:SetDiet(diet, diet)
        inst.components.eater:SetOnEatFn(oneat)

        inst:AddComponent("perishable")
        inst.components.perishable:SetPerishTime(480*5)
        inst.components.perishable:StartPerishing()

        inst:AddComponent("locomotor")
        inst.components.locomotor:EnableGroundSpeedMultiplier(not flying)
        inst.components.locomotor:SetTriggersCreep(false)
        inst.components.locomotor.softstop = true
        inst.components.locomotor.walkspeed = 9

        inst:AddComponent("crittertraits")
        inst:AddComponent("timer")

        inst:SetBrain(PET_BRAIN)
        inst:SetStateGraph(PET_SG)
		
		inst.LinkToPlayer = linktoplayer
		inst.UnlinkToPlayer = unlinktoplayer
        inst.OnSave = OnSave
        inst.OnLoad = OnLoad

        return inst
    end

    return Prefab(name, fn, animszip)
end

-------------------------------------------------------------------------------
local function builder_onbuiltdon(inst, builder)
    local theta = math.random() * 2 * PI
    local pt = builder:GetPosition()
    local radius = 1
    local offset = FindWalkableOffset(pt, theta, radius, 6, true)
    if offset ~= nil then
        pt.x = pt.x + offset.x
        pt.z = pt.z + offset.z
    end
    builder.components.petleash:SpawnPetAt(pt.x, 0, pt.z, inst.pettype, inst.skin_name)
    inst:Remove()
end

local function MakeDonPetBuilder(prefab)
    local function fn()
        local inst = CreateEntity()

        inst.entity:AddTransform()

        inst:AddTag("CLASSIFIED")

        inst.persists = false

        inst:DoTaskInTime(0, inst.Remove)

        if not TheWorld.ismastersim then
            return inst
        end

        inst.pettype = prefab
        inst.OnBuiltFn = builder_onbuiltdon

        return inst
    end

    return Prefab(prefab.."_builder", fn, nil, { prefab })
end

-------------------------------------------------------------------------------

local standard_diet = { FOODGROUP.OMNI }

return MakeDonPet("lfy_packim", packimname, 6, "walkfly1", 1, standard_diet, true, packimanimzip, packimconfiganim, packimanims, packimsounds, {favoritefood="fish"}),
	   MakeDonPetBuilder("lfy_packim")