require "brains/beequeenbrain"
require "stategraphs/SGbeequeen"

local assets =
{
	Asset("ANIM", "anim/bee_queen_basic.zip"),
    Asset("ANIM", "anim/bee_queen_actions.zip"),
    Asset("ANIM", "anim/bee_queen_build.zip"),
	Asset("SOUND", "sound/bat.fsb"),
	Asset("ANIM", "anim/bee_guard.zip"),
    Asset("ANIM", "anim/bee_guard_build.zip"),
    Asset("ANIM", "anim/bee_guard_puffy_build.zip"),
}
    
local prefabs =
{
	"honey",
    "honeycomb",
    "bee",
    "killerbee",
	"minibeehive",
	"hivehat",
}

local workersounds = 
{
	takeoff = "dontstarve/bee/bee_takeoff",
	attack = "dontstarve/bee/bee_attack",
	buzz = "dontstarve/bee/bee_fly_LP",
	hit = "dontstarve/bee/bee_hurt",
	death = "dontstarve/bee/bee_death",
}

local killersounds = 
{
	takeoff = "dontstarve/bee/killerbee_takeoff",
	attack = "dontstarve/bee/killerbee_attack",
	buzz = "dontstarve/bee/killerbee_fly_LP",
	hit = "dontstarve/bee/killerbee_hurt",
	death = "dontstarve/bee/killerbee_death",
}

local function NormalRetarget(inst)
	local range = 10
	return FindEntity(inst, range, function(guy)
			return inst.components.combat:CanTarget(guy)
		end, nil, {"insect"}, {"character", "animal", "monster"})
end

local function KeepTargetfn(inst, target)
   return target
          and target.components.combat
          and target.components.health
          and not target.components.health:IsDead()
end

local function OnAttacked(inst, data)
    inst.components.combat:SetTarget(data.attacker)
    inst.components.combat:ShareTarget(data.attacker, 30, function(dude)
        return dude:HasTag("bee")
               and not dude.components.health:IsDead()
    end, 10)
end

local function GuardSpeedBuff(inst)
	inst.AnimState:SetBuild("bee_guard_puffy_build")
	inst.components.locomotor.walkspeed = 8
	inst.sounds = killersounds
	if inst.SoundEmitter:PlayingSound("buzz") then
		inst.SoundEmitter:KillSound("buzz")
		inst.SoundEmitter:PlaySound(inst.sounds.buzz, "buzz")
	end
    inst:DoTaskInTime(14, function(inst)
		inst.AnimState:SetBuild("bee_guard_build")
		inst.components.locomotor.walkspeed = 3
		inst.sounds = workersounds
		if inst.SoundEmitter:PlayingSound("buzz") then
			inst.SoundEmitter:KillSound("buzz")
			inst.SoundEmitter:PlaySound(inst.sounds.buzz, "buzz")
		end
	end)
end

function GetBeeGuards(inst)
	local x,y,z = inst.Transform:GetWorldPosition()
	local ents = TheSim:FindEntities(x,y,z,45, {"beeguard"}, {"FX", "NOCLICK", "DECOR","INLIMBO"})
    return ents
end

function GetBees(inst)
	local x,y,z = inst.Transform:GetWorldPosition()
	local ents = TheSim:FindEntities(x,y,z,60, {"bee"}, {"FX", "NOCLICK", "DECOR","INLIMBO"})
    return ents
end

local function OnNewTarget(inst, data)
	local focus = math.random(5,15)	
	local beearound = 0
	local beecheck = GetBeeGuards(inst)
	for k,v in pairs(beecheck) do
		beearound = beearound + 1
	end
	inst:DoTaskInTime(focus,function(inst) 
		if not (inst.components.sleeper:IsAsleep() or inst.components.freezable:IsFrozen() or inst.components.health:IsDead() or inst.sg:HasStateTag("attack") or inst.sg:HasStateTag("spawnbees") or inst.calledfocus) and beearound > 0 then
			inst.calledfocus = true
			inst:DoTaskInTime(4,function(inst) 
				inst.calledfocus = false
			end)		
			inst.sg:GoToState("focustarget")
			inst.components.combat:ShareTarget(data.target,30,function(dude) return dude:HasTag("bee") end, 60)	
			local beeguards = GetBeeGuards(inst)
			for k,v in pairs(beeguards) do
				if v.components.combat and v.components.follower.leader == inst then
					v.components.combat:SetTarget(nil)
					v.components.combat:SuggestTarget(data.target)
					if v.components.locomotor and v.components.locomotor.walkspeed < 8 then
						GuardSpeedBuff(v)
					end
				end
			end
		end	
	end)
end

local function SpawnBeeRestart(inst)
	SpawnBee(inst)
end

local function SpawnBee(inst)
	inst:DoTaskInTime(inst.spawnperiod,function(inst) 
		local bees = GetBees(inst)
		local numbee = 0
		for k,v in pairs(bees) do
			numbee = numbee + 1 
		end
		if inst.components.leader.numfollowers < inst.maxguard and not (inst.components.sleeper:IsAsleep() or inst.components.freezable:IsFrozen() or inst.components.health:IsDead()) then
			inst.sg:GoToState("spawnbees")
		--elseif not (numbee > 15 or inst.components.sleeper:IsAsleep() or inst.components.freezable:IsFrozen() or inst.components.health:IsDead()) then
			--inst.sg:GoToState("spawnbees")
		end
		SpawnBee(inst)
	end)
end	

local function SanityAura(inst, observer)
    return -TUNING.SANITYAURA_SMALL
end

local function create_beequeen(Sim)
	local inst = CreateEntity()
    inst.entity:AddTransform()
	inst.entity:AddAnimState()
	inst.entity:AddSoundEmitter()
	inst.entity:AddLightWatcher()
	local shadow = inst.entity:AddDynamicShadow()
	shadow:SetSize(4, 2)
    inst.Transform:SetSixFaced()
    inst.Transform:SetScale(1.4, 1.4, 1.4)   
	local minimap = inst.entity:AddMiniMapEntity()
	minimap:SetIcon( "beequeen.tex" )
	inst:AddTag("epic")
    inst:AddTag("monster")
    inst:AddTag("hostile")
    inst:AddTag("beequeen")
	inst:AddTag("bee")
	inst:AddTag("insect")
	inst:AddTag("flying")
    inst:AddTag("scarytoprey")
    inst:AddTag("largecreature")
    MakeCharacterPhysics(inst, 10, .5)
	inst.Physics:SetCollisionGroup(COLLISION.FLYERS)
	inst.Physics:ClearCollisionMask()
	inst.Physics:CollidesWith(COLLISION.WORLD)
	inst.Physics:CollidesWith(COLLISION.FLYERS)
	inst.AnimState:SetBank("bee_queen")
    inst.AnimState:SetBuild("bee_queen_build")
    inst.AnimState:PlayAnimation("idle_loop", true)
    
    inst:AddComponent("locomotor")
	inst.components.locomotor.walkspeed = 4
    inst.components.locomotor.runspeed = 6
    inst.components.locomotor:EnableGroundSpeedMultiplier(false)
	inst.components.locomotor:SetTriggersCreep(false)
    
    inst:AddComponent("lootdropper")
    inst.components.lootdropper:SetLoot({"honey","honey","honey","honey","honey","honey","honey","honey","honeycomb","honeycomb","honeycomb","stinger"})
	inst.components.lootdropper:AddChanceLoot('minibeehive',1.00)
	inst.components.lootdropper:AddChanceLoot('minibeehive',0.50)
	inst.components.lootdropper:AddChanceLoot('minibeehive',0.25)
	inst.components.lootdropper:AddChanceLoot('hivehat',0.50)
        
    MakeMediumBurnableCharacter(inst, "body")
    MakeMediumFreezableCharacter(inst, "body") 
    
    inst:AddComponent("health")
	inst.components.health:SetMaxHealth(3500)
	inst.components.health:StartRegen(50,30)
    
    inst:AddComponent("combat")
    inst.components.combat.hiteffectsymbol = "body"
	inst.components.combat:SetDefaultDamage(120)
	inst.components.combat.playerdamagepercent = .75
    inst.components.combat:SetAttackPeriod(3)
    inst.components.combat:SetRetargetFunction(1, NormalRetarget)
    inst.components.combat:SetKeepTargetFunction(KeepTargetfn)
    
    inst:AddComponent("sleeper")
    inst.components.sleeper:SetResistance(4)
    
    inst:AddComponent("knownlocations")
	
	inst:AddComponent("follower")
	
	inst:AddComponent("leader")
    
    inst:AddComponent("inspectable")

	inst:AddComponent("sanityaura")
    inst.components.sanityaura.aurafn = SanityAura  

	inst.maxguard = 4
	inst.spawnperiod = 20
	inst.triedspawn = false
	inst:DoPeriodicTask(2,function(inst) 
		if inst.components.health then
			local healthpct = inst.components.health:GetPercent()
			if healthpct >= .75 then
				inst.maxguard = 4
				inst.spawnperiod = math.random(12,20)
			elseif healthpct >= .50 and healthpct < .75 then
				inst.maxguard = 6
				inst.spawnperiod = math.random(10,16)
			elseif healthpct >= .25 and healthpct < .50 then
				inst.maxguard = 8
				inst.spawnperiod = math.random(8,14)
			elseif healthpct < .25 then
				inst.maxguard = 10
				inst.spawnperiod = math.random(4,11)
			end
		end
	end)
	
	inst:DoTaskInTime(3,function(inst) 
		SpawnBee(inst)
	end)	
	
	local brain = require "brains/beequeenbrain"
    inst:SetBrain(brain)
	
	inst:SetStateGraph("SGbeequeen")
	
	inst.OnEntitySleep = OnEntitySleep	
    inst:ListenForEvent("attacked", OnAttacked)
	inst:ListenForEvent("doattack", OnNewTarget)
	inst:ListenForEvent("newcombattarget", OnNewTarget)
    return inst
end

return Prefab( "forest/monsters/beequeen", create_beequeen, assets, prefabs)