require "prefabutil"
require "scheduler"
require "simutil"
require "behaviours/doaction"

local assets =
{
	Asset("ANIM", "anim/yuyi_firefighter.zip"),
	Asset("ANIM", "anim/firefighter_placement.zip"),
	Asset("ANIM", "anim/firefighter_meter.zip"),
	Asset("IMAGE", "images/yuyitabs/yuyi_firesuppressor.tex"),
	Asset("ATLAS", "images/yuyitabs/yuyi_firesuppressor.xml"),
}

local projectile_assets = 
{
	Asset("ANIM", "anim/firefighter_projectile.zip"),
}

local prefabs = 
{
	"firesuppressorprojectile",
	"splash_snow_fx",
	"collapse_small",
}

local YESTAGS = {"burnable"}
local NOTAGS = {"FX", "campfire", "NOCLICK", "DECOR", "INLIMBO","flingomatic_freeze_immune"}

local function LaunchProjectile(inst, targetpos)
	local projectile = SpawnPrefab("firesuppressorprojectile")
	projectile.owner = inst
	projectile.Transform:SetPosition(inst:GetPosition():Get())
	projectile.components.complexprojectile:Launch(targetpos)
end

local function OnFindFire(inst, firePos)
	inst:PushEvent("putoutfire", {firePos = firePos})
end

local function ontimerdone(inst, data)
    if data.name == "Reload" then
        inst.canFire = true
    end
end

local function TurnOff(inst, instant)
	inst.on = false
	inst.components.firedetector:Deactivate()
	inst.components.fueled:StopConsuming()
	inst.components.container:Close(GetPlayer())
	if instant then
		inst.sg:GoToState("idle_off")
	else
		inst.sg:GoToState("turn_off")
	end
end

local function TurnOn(inst, instant)
	inst.on = true
	local randomizedStartTime = POPULATING
	inst.components.firedetector:Activate(randomizedStartTime)
	inst.components.fueled:StartConsuming()
	inst.components.container:Open(GetPlayer())
	if instant then
		inst.sg:GoToState("idle_on")
	else
		inst.sg:GoToState("turn_on")
	end
end

local function OnFuelEmpty(inst)
	inst.components.machine:TurnOff()
end

local function OnFuelSectionChange(old, new, inst)
	local fuelAnim = inst.components.fueled:GetCurrentSection()
	inst.AnimState:OverrideSymbol("swap_meter", "firefighter_meter", fuelAnim)
	-----------------------------------------------------------------------------------------------------------------------------------
	if inst.components.fueled and (inst.components.fueled.currentfuel / inst.components.fueled.maxfuel) <= .75 then
	if inst.components.container:Has("poop", 1) then
		inst.components.container:ConsumeByName("poop", 1)
		inst.components.fueled:DoDelta(TUNING.MED_FUEL*5)
	elseif inst.components.container:Has("guano", 1) then
		inst.components.container:ConsumeByName("guano", 1)
		inst.components.fueled:DoDelta(TUNING.MED_FUEL*5)
	elseif inst.components.container:Has("spoiled_food", 1) then
		inst.components.container:ConsumeByName("spoiled_food", 1)
		inst.components.fueled:DoDelta(TUNING.SMALL_FUEL*5)
	elseif inst.components.container:Has("rottenegg", 1) then
		inst.components.container:ConsumeByName("rottenegg", 1)
		inst.components.fueled:DoDelta(TUNING.SMALL_FUEL*5)
	elseif inst.components.container:Has("glommerfuel", 1) then
		inst.components.container:ConsumeByName("glommerfuel", 1)
		inst.components.fueled:DoDelta(TUNING.LARGE_FUEL*5)
	end
	end
end

local function CanInteract(inst)
	return not inst.components.fueled:IsEmpty() and not (inst.components.floodable and inst.components.floodable.flooded)
end

local function RemoveAllWitherProtection(inst)
	if #inst.protected_plants > 0 then
		for k,v in pairs(inst.protected_plants) do
			if v then
				if v.components.crop then
					v.makewitherabletask = v:DoTaskInTime(TUNING.WITHER_BUFFER_TIME, function(v) 
						v.components.crop:MakeWitherable() 
						v.components.crop.protected = false
						v:RemoveTag("protected")
					end)
				end
				if v.components.pickable then
					v.makewitherabletask = v:DoTaskInTime(TUNING.WITHER_BUFFER_TIME, function(v) 
						v.components.pickable:MakeWitherable()
						v.components.pickable.protected = false 
						v:RemoveTag("protected")
					end)
				end
			end
		end
	end
	inst.protected_plants = {}
end

local function UnprotectPlant(inst, plant)
	if plant then
		local index = -1
		if plant and #inst.protected_plants > 0 then
			for k,v in ipairs(inst.protected_plants) do
				if v and v == plant then
					inst:RemoveEventCallback("picked", v.UnprotectPlant, v)
					v:RemoveTag("protected")
					v.components.pickable.protected = false
					v.makewitherabletask = v:DoTaskInTime(TUNING.WITHER_BUFFER_TIME, function(v) 
						v.components.pickable:MakeWitherable()
					end)
					index = k
					break
				end
			end
		end
		if index > 0 then
			table.remove(inst.protected_plants, index)
		end
	end
end

local function onhammered(inst, worker)
	if inst:HasTag("fire") and inst.components.burnable then
		inst.components.burnable:Extinguish()
	end
	inst.SoundEmitter:KillSound("idleloop")
	inst.components.lootdropper:DropLoot()
	SpawnPrefab("collapse_small").Transform:SetPosition(inst.Transform:GetWorldPosition())
	inst.SoundEmitter:PlaySound("dontstarve/common/destroy_wood")

	RemoveAllWitherProtection(inst)

	inst:Remove()
end

local function onhit(inst, worker)
	if not inst:HasTag("burnt") then
		if not inst.sg:HasStateTag("busy") then
			inst.sg:GoToState("hit")
		end
	end
end

local function getstatus(inst, viewer)
	local pos = Point(inst.Transform:GetWorldPosition())
	local range_indicators = TheSim:FindEntities(pos.x,pos.y,pos.z, 2, {"yuyi_firerange"} )
	if #range_indicators < 1 then
	local range = SpawnPrefab("yuyi_firerange")
	range.Transform:SetPosition(pos.x, pos.y, pos.z)
	elseif #range_indicators >= 1 then
		for i,v in ipairs(range_indicators) do if v:IsValid() then v:Remove() end end
	end
	if inst.on then
		if inst.components.fueled and (inst.components.fueled.currentfuel / inst.components.fueled.maxfuel) <= .25 then
			return "LOWFUEL"
		else
			return "ON"
		end
	else
		return "OFF"
	end
end

local function OnEntitySleep(inst)
    inst.SoundEmitter:KillSound("firesuppressor_idle")
end

local function HitPlants(inst, dist, noextinguish)
	
	local protector = inst.owner or inst
	dist = dist or 4

	local x,y,z = inst:GetPosition():Get()

	local ents = TheSim:FindEntities(x,y,z, dist, YESTAGS, NOTAGS)

	for k,v in pairs(ents) do
		if v then
			if v.makewitherabletask then
				v.makewitherabletask:Cancel()
				v.makewitherabletask = nil
				table.insert(protector.protected_plants, v)
				v:AddTag("protected")
				if v.components.pickable then
					v.UnprotectPlant = function(v)
						protector:UnprotectPlant(v)
					end
					protector:ListenForEvent("picked", v.UnprotectPlant, v)
				end
				if v.components.crop then
					v.components.crop.protected = true
				elseif v.components.pickable then
					v.components.pickable.protected = true
				end
			elseif v.components.crop and v.components.crop.witherable then
				v.components.crop.protected = true
				table.insert(protector.protected_plants, v)
				v:AddTag("protected")
			elseif v.components.pickable and v.components.pickable.witherable then
				v.components.pickable.protected = true
				if v.components.pickable.withered or v.components.pickable.shouldwither then
					if v.components.pickable.cycles_left and v.components.pickable.cycles_left <= 0 then
		    			v.components.pickable:MakeBarren()
		    		else
		    			v.components.pickable:MakeEmpty()
		    		end
		    		v.components.pickable.withered = false
		    		v.components.pickable.shouldwither = false
		    		v:RemoveTag("withered")
				end
				table.insert(protector.protected_plants, v)
				v:AddTag("protected")
				v.UnprotectPlant = function(v)
					protector:UnprotectPlant(v)
				end
				protector:ListenForEvent("picked", v.UnprotectPlant, v)
			end

			if not noextinguish then
				if v.components.burnable then
					if v.components.burnable:IsBurning() then
						v.components.burnable:Extinguish(true, TUNING.FIRESUPPRESSOR_EXTINGUISH_HEAT_PERCENT)
					elseif v.components.burnable:IsSmoldering() then
						v.components.burnable:Extinguish(true)
					end
				end
				if v.components.freezable then
					v.components.freezable:AddColdness(2) 
				end
				if v.components.temperature then
					local temp = v.components.temperature:GetCurrent()
	        		v.components.temperature:SetTemperature(temp - TUNING.FIRE_SUPPRESSOR_TEMP_REDUCTION)
				end
			end
		end
	end
end

local function onsave(inst, data)
	if inst:HasTag("burnt") or inst:HasTag("fire") then
        data.burnt = true
    end
    data.on = inst.on
end

local function onload(inst, data)
	if data and data.burnt and inst.components.burnable and inst.components.burnable.onburnt then
        inst.components.burnable.onburnt(inst)
    end
    inst.on = data.on and data.on or false
end

local function OnLoadPostPass(inst, data)
	if not inst.components.fueled:IsEmpty() then
		HitPlants(inst, TUNING.FIRE_DETECTOR_RANGE, true)
	end
end

local function onbuilt(inst)
	inst.AnimState:PlayAnimation("place")
	inst.AnimState:PushAnimation("idle_off")
	inst.SoundEmitter:PlaySound("dontstarve_DLC001/common/craftable/firesupressor")
end

local function onFloodedStart(inst)
	if inst.on then 
		TurnOff(inst, true)
	end 
end 

local slotpos = {	Vector3(0,64+32+8+4,0), 
					Vector3(0,32+4,0),
					Vector3(0,-(32+4),0), 
					Vector3(0,-(64+32+8+4),0)}

local function itemtest(inst, item, slot)
	if item.prefab == "fertilizer" then return false end
	if item and item.components.fertilizer then return true end
	return false
end

local function SpawnEffect(inst)
    local pt = inst:GetPosition()
    local fx = SpawnPrefab("small_puff")
    fx.Transform:SetPosition(pt.x, pt.y, pt.z)
    fx.Transform:SetScale(0.5,0.5,0.5)
end
	
local function Hitmonsters(inst, dist, noextinguish)
	local protector = inst.owner or inst
	local x,y,z = inst:GetPosition():Get()
	local ents = TheSim:FindEntities(x,y,z, 8)
	for k,v in pairs(ents) do
		if v then
		if v.components.combat and v.components.health and not v.components.health:IsDead() 
		and (v.components.combat.target and v.components.combat.target == GetPlayer())
		and not v:HasTag("yuyi") and not v:HasTag("wall") and not (v.components.inventoryitem 
		and v.components.inventoryitem.owner) and not (v.components.follower 
		and v.components.follower.leader == GetPlayer()) then
		if v.sg and v.sg.sg and v.sg.sg.states and v.sg.sg.states.hit and not v.components.health:IsDead() then v.sg:GoToState("hit") end
		if v.sg and v.sg.sg and v.sg.sg.states and v.sg.sg.states.idle and not v.components.health:IsDead() then v.sg:GoToState("idle") end
		if v.components.health and not (v.components.inventoryitem and v.components.inventoryitem.owner) then v.components.combat:GetAttacked(GetPlayer(), 25) end
		end
		end
	end
end

local function OnpoopHit(inst, dist)
	inst.SoundEmitter:PlaySound("dontstarve_DLC001/common/firesupressor_impact")
	SpawnPrefab("splash_snow_fx").Transform:SetPosition(inst:GetPosition():Get())
	Hitmonsters(inst)
--	inst:AddTag("yuyi_poop")
--	inst:Remove()
end

local function Hityuyicrops(inst, dist, noextinguish)
	local protector = inst.owner or inst
	local x,y,z = inst:GetPosition():Get()
	local ents = TheSim:FindEntities(x,y,z, 8)
	for k,v in pairs(ents) do
		if v and v.components.crop and not v.components.crop:IsReadyForHarvest() and not v.components.crop:IsWithered() then
			if v.components.crop:Fertilize(inst) then
				v:RemoveTag("yuyi_withered")
				return true
			else
				return false
			end
		elseif v.components.grower and v.components.grower:IsEmpty() then
			v.components.grower:Fertilize(inst)
			v:RemoveTag("yuyi_withered")
		elseif v.components.pickable and v.components.pickable:CanBeFertilized() then
			v.components.pickable:Fertilize(inst)
			v:RemoveTag("yuyi_withered")
			return true     
		end
	end
end

local function Onpoopfertilizer(inst, dist)
	inst.SoundEmitter:PlaySound("dontstarve_DLC001/common/firesupressor_impact")
	SpawnPrefab("splash_snow_fx").Transform:SetPosition(inst:GetPosition():Get())	
	Hityuyicrops(inst)
	inst:AddTag("yuyi_poop")
end

local function Launchpoop(inst)
	if inst.on then
	local pos = Vector3(inst.Transform:GetWorldPosition())
	local ents = TheSim:FindEntities(pos.x,pos.y,pos.z, 15)


		for k,v in pairs(ents) do
		if v.components.crop and not v.components.crop:IsReadyForHarvest() then
			v:AddTag("yuyi_withered")
		elseif v.components.grower and v.components.grower:IsEmpty() and not v.components.grower:IsFullFertile() then
			v:AddTag("yuyi_withered")
		elseif v.components.pickable and v.components.pickable:CanBeFertilized() then
			v:AddTag("yuyi_withered")
		end

		if v and v:HasTag("yuyi_poop") then
			v:RemoveTag("yuyi_poop")
			inst.components.container:GiveItem(v)
			SpawnEffect(v)
		end

		if v and v.components.combat and v.components.health and not v.components.health:IsDead() 
		and (v.components.combat.target and v.components.combat.target == GetPlayer())
		and not v:HasTag("yuyi") and not v:HasTag("wall") and not (v.components.inventoryitem 
		and v.components.inventoryitem.owner) and not (v.components.follower 
		and v.components.follower.leader == GetPlayer()) then

		local targetpos = v:GetPosition()
		if targetpos and inst.components.container:Has("poop", 1) then
		local projectile = SpawnPrefab("poop")
		inst.components.container:ConsumeByName("poop", 1)
		projectile:AddComponent("locomotor")
		projectile:AddComponent("complexprojectile")
		projectile.components.complexprojectile:SetOnHit(OnpoopHit)
		projectile.components.complexprojectile.yOffset = 2.5
		projectile.components.complexprojectile.horizontalSpeed = 10
		projectile.owner = inst
		projectile.Transform:SetPosition(inst:GetPosition():Get())
		projectile.components.complexprojectile:Launch(targetpos)
		end
		end

		end

		local yuyi_fertilizer = nil
		local crops = TheSim:FindFirstEntityWithTag("yuyi_withered")
		if crops then
		local yuyicroppos = crops:GetPosition()
		if inst.components.container:Has("fertilizer", 1) then
			yuyi_fertilizer = "fertilizer"
			inst.components.container:ConsumeByName(yuyi_fertilizer, 1)
		elseif inst.components.container:Has("spoiled_food", 1) then
			yuyi_fertilizer = "spoiled_food"
			inst.components.container:ConsumeByName(yuyi_fertilizer, 1)
		elseif inst.components.container:Has("poop", 1) then
			yuyi_fertilizer = "poop"
			inst.components.container:ConsumeByName(yuyi_fertilizer, 1)
		elseif inst.components.container:Has("guano", 1) then
			yuyi_fertilizer = "guano"
			inst.components.container:ConsumeByName(yuyi_fertilizer, 1)
		elseif inst.components.container:Has("glommerfuel", 1) then
			yuyi_fertilizer = "glommerfuel"
			inst.components.container:ConsumeByName(yuyi_fertilizer, 1)
		elseif inst.components.container:Has("rottenegg", 1) then
			yuyi_fertilizer = "rottenegg"
			inst.components.container:ConsumeByName(yuyi_fertilizer, 1)
		else
			yuyi_fertilizer = nil
		end

		if yuyi_fertilizer then
		local projectile = SpawnPrefab(yuyi_fertilizer)
		projectile:AddComponent("locomotor")
		projectile:AddComponent("complexprojectile")
		projectile.components.complexprojectile:SetOnHit(Onpoopfertilizer)
		projectile.components.complexprojectile.yOffset = 2.5
		projectile.components.complexprojectile.horizontalSpeed = 10
		projectile.owner = inst
		projectile.Transform:SetPosition(inst:GetPosition():Get())
		projectile.components.complexprojectile:Launch(yuyicroppos)
		end
		end

	end
end

local function yuyi_firesuppressorfn()
	local inst = CreateEntity()
	local trans = inst.entity:AddTransform()
	local anim = inst.entity:AddAnimState()
	local sound = inst.entity:AddSoundEmitter()

	local minimap = inst.entity:AddMiniMapEntity()	
	minimap:SetPriority( 5 )
	minimap:SetIcon( "yuyi_firesuppressor.tex" )
	MakeObstaclePhysics(inst, 1)

	anim:SetBank("firefighter")
	anim:SetBuild("yuyi_firefighter")
	anim:PlayAnimation("idle_off")
	inst.on = false

	inst:AddComponent("inspectable")
	inst.components.inspectable.getstatus = getstatus

	inst:AddComponent("machine")
	inst.components.machine.turnonfn = TurnOn
	inst.components.machine.turnofffn = TurnOff
	inst.components.machine.caninteractfn = CanInteract
	inst.components.machine.cooldowntime = 0.5

	inst:AddComponent("fueled")
	inst.components.fueled:SetDepletedFn(OnFuelEmpty)
	inst.components.fueled.accepting = true
	inst.components.fueled:SetSections(10)--小节
	inst.components.fueled:SetSectionCallback(OnFuelSectionChange)
	inst.components.fueled:InitializeFuelLevel(TUNING.FIRESUPPRESSOR_MAX_FUEL_TIME)
	inst.components.fueled.bonusmult = 5--奖金
	inst.components.fueled.secondaryfueltype = "CHEMICAL"--化学

	inst.AnimState:OverrideSymbol("swap_meter", "firefighter_meter", 10)

	inst:AddComponent("firedetector")--火警检测器
	inst.components.firedetector:SetOnFindFireFn(OnFindFire)
	inst.protected_plants = {}
	inst.UnprotectPlant = UnprotectPlant
	
	inst:AddComponent("timer")
    inst:ListenForEvent("timerdone", ontimerdone)

	inst:AddComponent("lootdropper")
	inst:AddComponent("workable")
	inst.components.workable:SetWorkAction(ACTIONS.HAMMER)
	inst.components.workable:SetWorkLeft(4)
	inst.components.workable:SetOnFinishCallback(onhammered)
	inst.components.workable:SetOnWorkCallback(onhit)

	inst.LaunchProjectile = LaunchProjectile
	inst:SetStateGraph("SGfiresuppressor")

	inst.OnSave = onsave 
    inst.OnLoad = onload
    inst.OnLoadPostPass = OnLoadPostPass
    inst.OnEntitySleep = OnEntitySleep
	inst:ListenForEvent( "onbuilt", onbuilt)

    inst:AddComponent("container")
    inst.components.container:SetNumSlots(4)
    inst.components.container.widgetslotpos = slotpos
    inst.components.container.widgetanimbank = "ui_cookpot_1x4"
    inst.components.container.widgetanimbuild = "ui_cookpot_1x4"
    inst.components.container.widgetpos = Vector3(200,0,0)
    inst.components.container.side_align_tip = 100
    inst.components.container.itemtestfn = itemtest
--	inst.components.container.canbeopened = false
    inst.components.container.onopenfn = function(inst) GetPlayer().SoundEmitter:PlaySound("dontstarve/wilson/equip_item_gold") end
    inst.components.container.onclosefn = function(inst) GetPlayer().SoundEmitter:PlaySound("dontstarve/wilson/equip_item_gold") end

    if IsDLCEnabled(CAPY_DLC) then
	inst:AddComponent("floodable")
	inst.components.floodable.onStartFlooded = onFloodedStart
	inst.components.floodable.floodEffect = "shock_machines_fx"
	inst.components.floodable.floodSound = "dontstarve_DLC002/creatures/jellyfish/electric_land"
	end

	inst.task_yuyfirefighter = inst:DoPeriodicTask(1, function() Launchpoop(inst) end)

	return inst
end

local function OnsnowHit(inst, dist)
	inst.SoundEmitter:PlaySound("dontstarve_DLC001/common/firesupressor_impact")
	SpawnPrefab("splash_snow_fx").Transform:SetPosition(inst:GetPosition():Get())	
	HitPlants(inst)
	inst:Remove()
end

local function projectile_fn()
	local inst = CreateEntity()
	local trans = inst.entity:AddTransform()
	local anim = inst.entity:AddAnimState()
	local sound = inst.entity:AddSoundEmitter()
    
    local physics = inst.entity:AddPhysics()
    physics:SetMass(1)
    physics:SetCapsule(0.2, 0.2)
    inst.Physics:SetFriction(10)
    inst.Physics:SetDamping(5)
    inst.Physics:SetCollisionGroup(COLLISION.CHARACTERS)
    inst.Physics:ClearCollisionMask()
    inst.Physics:CollidesWith(COLLISION.WORLD)

	anim:SetBank("firefighter_projectile")
	anim:SetBuild("firefighter_projectile")
	anim:PlayAnimation("spin_loop", true)

    inst.persists = false

	inst:AddComponent("locomotor")
	inst:AddComponent("complexprojectile")
	inst.components.complexprojectile:SetOnHit(OnsnowHit)
	inst.components.complexprojectile.yOffset = 2.5

	return inst
end

return Prefab("yuyi_firesuppressor", yuyi_firesuppressorfn, assets, prefabs), 
		Prefab("firesuppressorprojectile", projectile_fn, projectile_assets),
		MakePlacer( "common/firesuppressor_placer", "firefighter_placement", "firefighter_placement", "idle", true, nil, nil, 1.55)