airstrikeprojectileHandler = {
	shellNum = 1,
	shells = {},
	defaultShell = {active=false}
}

function init()
	RegisterTool("airstrike", "Air Strike", "MOD/vox/airstrike.vox")
	SetBool("game.tool.airstrike.enabled", true)
	SetString("game.tool.airstrike.ammo.display","")
	SetFloat("game.tool.airstrike.ammo", 101)

	nocd = GetBool("savegame.mod.nocd")

	for i=1, 250 do
		airstrikeprojectileHandler.shells[i] = deepcopy(airstrikeprojectileHandler.defaultShell)
	end

	flycamenabled = false
	airstrikeenabled = false
	firing = false
	radioactivated = false
	
	damage = 1
	gravity = Vec(0, 0, 0)
	velocity = 0.6
	shotDelay = 0.05

	shockwave = {
		strength = 3,
		maxDist = 4,
		maxMass = 2000
	}

	zoomlevel = 6
	maxzoom = 12
	minzoom = 0.5

	lightTimer = 0
	equipTimer = 0

	selectedshell = 1
	shoottimers = {}
	for i=1, 6 do
		shoottimers[i] = 0
	end

	shellsprites = {}
	shellsprites[1] = LoadSprite("MOD/img/25mm.png")
	shellsprites[2] = LoadSprite("MOD/img/40mm.png")
	shellsprites[3] = LoadSprite("MOD/img/105mm.png")

	gunsounds = {}
	gunsounds[1] = LoadLoop("MOD/snd/gun1.ogg")
	gunsounds[2] = LoadSound("MOD/snd/gun2.ogg")
	gunsounds[3] = LoadSound("MOD/snd/gun3.ogg")
	planesound = LoadLoop("MOD/snd/planeloop.ogg")

	splashsound = LoadSound("MOD/snd/splash0.ogg")
	firesound = LoadSound("MOD/snd/fire0.ogg")

	fireloop = LoadLoop("MOD/snd/fireloop.ogg")
	waterloop = LoadLoop("MOD/snd/water.ogg")

	explosionsounds = {}
	explosionsounds[1] = LoadSound("explosion/s0.ogg")

	switchsound = LoadSound("MOD/snd/switch.ogg")
	beepsound = LoadSound("MOD/snd/radiobeep.ogg")

	plane = {}
	plane.pos = Vec(0, 0 ,0)
	plane.rot = QuatRotateQuat(Quat(), QuatEuler(-90, -90, 0))

	plane.barrel = {}
	plane.barrel.rot = Quat()

	plane.pos[2] = 100
	plane.pos[1] = plane.pos[1] + 100
end

function clamp(value, mi, ma)
	if value < mi then value = mi end
	if value > ma then value = ma end
	return value
end

function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, deepcopy(getmetatable(orig)))
    else
        copy = orig
    end
    return copy
end

function rnd(mi, ma)
	return math.random(0, 1000)/1000*(ma-mi)+mi
end

function SpawnFireParticles(pos, dir, amount, life, hittype)
	ParticleReset()
	ParticleType("plain")
	ParticleColor(1, 0.6, 0.4, 1, 0.3, 0.2)
	ParticleAlpha(1, 0)
	ParticleRadius(rnd(0.25, 0.35), rnd(0.35, 0.45))
	ParticleGravity(0, rnd(0, 3), "easeout")
	ParticleDrag(0.4)
	ParticleEmissive(rnd(2, 5), 0, "easeout")
	ParticleTile(5)
	for i=1, amount do
		if hittype == "ground" then
			dir = Vec(rnd(-1, 1), rnd(-1,1), rnd(-1,1))
			life = math.min(rnd(life-1, life+1), 7)
			
			ParticleCollide(0, 1)
			ParticleSticky(0.4)
			if i % 10 == 0 then
				local randpos = Vec(rnd(-0.5, 0.5), rnd(-0.5, 0.5), rnd(-0.5, 0.5))
				SpawnFire(VecAdd(pos, randpos))
			end
		elseif hittype == "air" then
			dir = VecAdd(dir, Vec(rnd(-0.3, 0.3), rnd(-0.3, 0.3), rnd(-0.3, 0.3)))
		end
		SpawnParticle(pos, VecScale(dir, 10), life)
	end
end

function SpawnAcidParticles(pos, dir, amount, life, hittype)
	ParticleReset()
	ParticleType("plain")
	ParticleColor(0.3, 1, 0.2, 0.5, 1, 0.4)
	ParticleAlpha(1, 0.5)
	ParticleRadius(rnd(0.15, 0.2), 0)
	ParticleGravity(-5, -rnd(10, 12.5), "easein")
	ParticleDrag(0.5)
	ParticleEmissive(rnd(1, 3), 0, "easeout")
	ParticleTile(1)
	for i=1, amount do
		if hittype == "ground" then
			dir = Vec(rnd(-1, 1), rnd(-1,1), rnd(-1,1))
			life = math.min(rnd(life-1, life+1), 5)
			
			ParticleCollide(0, 1)
			ParticleSticky(0.3)
			local randpos = Vec(rnd(-0.8, 0.8), rnd(-0.8, 0.8), rnd(-0.8, 0.8))
			MakeHole(VecAdd(pos, randpos), rnd(0.15, 0.25), rnd(0.15, 0.25), rnd(0.15, 0.25), true)

		elseif hittype == "air" then
			dir = VecAdd(dir, Vec(rnd(-0.2, 0.2), rnd(-0.2, 0.2), rnd(-0.2, 0.2)))
		end
		SpawnParticle(pos, VecScale(dir, 10), life)
	end
end

function SpawnWaterParticles(pos, dir, amount, life, hittype)
	ParticleReset()
	ParticleType("smoke")
	ParticleAlpha(1)
	ParticleDrag(0.2)
	ParticleGravity(-5, -rnd(10, 12.5), "easein")
	ParticleFlags(256)
	ParticleRadius(rnd(0.5, 0.75), 0, "easeout")
	ParticleEmissive(rnd(0.1, 0.3), 0, "easeout")
	ParticleTile(3)
	for i=1, amount do
		if i % 3 == 0 then
			ParticleColor(0.7, 0.75, 1)
		else
			ParticleColor(0.5, 0.6, 1)
		end
		if hittype == "ground" then
			dir = Vec(rnd(-1, 1), rnd(-1,0), rnd(-1,1))
			life = math.min(rnd(life-1, life+1), 7)
			ParticleCollide(0, 0.5)
			ParticleSticky(0.1)
		elseif hittype == "water" then
			dir = Vec(rnd(-1, 1), 0, rnd(-1,1))
			ParticleGravity(rnd(3,6), -rnd(5,7), "easeout")
		end
		SpawnParticle(pos, VecScale(dir, 15), life)
	end
end

function Shockwave(pos)
	--Get all physical and dynamic bodies in front of the tank
	local mi = VecAdd(pos, Vec(-shockwave.maxDist/2, -1, -shockwave.maxDist/2))
	local ma = VecAdd(pos, Vec(shockwave.maxDist/2, 2, shockwave.maxDist/2))
	
	QueryRequire("physical dynamic")
	QueryRejectBody(body)
	local bodies = QueryAabbBodies(mi, ma)		
	--Loop through bodies and push them
	for i=1,#bodies do
		local b = bodies[i]

		--Compute body center point and distance
		local bmi, bma = GetBodyBounds(b)
		local bc = VecLerp(bmi, bma, 0.5)
		local dir = VecSub(bc, pos)
		local dist = VecLength(dir)
		dir = VecScale(dir, 1.0/dist)

		--Get body mass
		local mass = GetBodyMass(b)
		
		--Make sure direction is always pointing slightly upwards
		dir[2] = 0.5
		dir = VecNormalize(dir)	
		
		--Compute how much velocity to add
		local massScale = 1 - math.min(mass/shockwave.maxMass, 1.0)
		local distScale = 1 - math.min(dist/shockwave.maxDist, 1.0)
		local add = VecScale(dir, shockwave.strength * massScale * distScale)

		local vel = GetBodyVelocity(b)
		vel = VecAdd(vel, add)
		SetBodyVelocity(b, vel)
	end
end

function GetAimPos()
	local ct = GetCameraTransform()
	local forwardPos = TransformToParentPoint(ct, Vec(0, 0, -150))
    local direction = VecSub(forwardPos, ct.pos)
    local distance = VecLength(direction)
	local direction = VecNormalize(direction)
	local hit, hitDistance = QueryRaycast(ct.pos, direction, distance)
	if hit then
		forwardPos = TransformToParentPoint(ct, Vec(0, 0, -hitDistance))
		distance = hitDistance
	end
	return forwardPos, hit, distance
end

function GetCamLookPos()
	local forwardPos = TransformToParentPoint(plane.barrel, Vec(0, 0, -150))
    local direction = VecSub(forwardPos, plane.barrel.pos)
    local distance = VecLength(direction)
	local direction = VecNormalize(direction)
	local hit, hitDistance = QueryRaycast(plane.barrel.pos, direction, distance)
	if hit then
		forwardPos = TransformToParentPoint(plane.barrel, Vec(0, 0, -hitDistance))
		distance = hitDistance
	end
	return forwardPos, hit, distance
end

function GetShootDistance()
    local direction = VecSub(aimpos, plane.barrel.pos)
    local distance = VecLength(direction)
	local direction = VecNormalize(direction)
	local hit, hitDistance = QueryRaycast(plane.barrel.pos, direction, distance)
	if hit then
		forwardPos = TransformToParentPoint(plane.barrel, Vec(0, 0, -hitDistance))
		distance = hitDistance
	end
	return distance
end

-- function FlyCam()
-- 	local mousewheel = InputValue("mousewheel")
-- 	if mousewheel ~= 0 then
-- 		zoomlevel = clamp(zoomlevel - mousewheel/2, minzoom, maxzoom)
-- 	end

-- 	local mx, my, a, d = InputValue("mousedx"), InputValue("mousedy"), InputDown("A"), InputDown("D")

-- 	local turn = 0
-- 	if a then turn = 1 elseif d then turn = -1 end

-- 	local rotdiv = 200/zoomlevel
-- 	if planevox ~= 0 then rotdiv = rotdiv * 2 end
-- 	plane.barrel.rot = QuatRotateQuat(plane.barrel.rot, QuatEuler(-my/rotdiv, -mx/rotdiv, 0))
-- 	plane.barrel.rot = QuatRotateQuat(plane.barrel.rot, QuatEuler(0, 0, turn))
-- 	local newT = Transform(plane.barrel.pos, plane.barrel.rot)
-- 	SetCameraTransform(newT, zoomlevel*10)
-- 	SetPlayerTransform(GetPlayerTransform())
-- 	PlayLoop(planesound, GetCameraTransform().pos, 0.5)
-- end

function FlyCam()
	local mousewheel = InputValue("mousewheel")
	if mousewheel ~= 0 then
		zoomlevel = clamp(zoomlevel - mousewheel/2, minzoom, maxzoom)
	end

	local mx, my = InputValue("mousedx"), InputValue("mousedy")

	local rotdiv = 200/zoomlevel
	if planevox ~= 0 then rotdiv = rotdiv * 2 end

	local CameraRot = QuatLookAt(plane.barrel.pos, aimpos)
	CameraRot = QuatRotateQuat(CameraRot, QuatEuler(-my/rotdiv, -mx/rotdiv, 0))
	plane.barrel.rot = CameraRot

	local newT = Transform(plane.barrel.pos, CameraRot)
	SetCameraTransform(newT, zoomlevel*10)
	SetPlayerTransform(GetPlayerTransform())
	PlayLoop(planesound, GetCameraTransform().pos, 0.5)
end

function Shoot()
	if shoottimers[selectedshell] > 0 then
		return
	end

	local distance = GetShootDistance()
	local barrelEnd = TransformToParentPoint(plane.barrel, Vec(0, -1, -2))
	local dir = VecSub(aimpos, barrelEnd)

	airstrikeprojectileHandler.shells[airstrikeprojectileHandler.shellNum] = deepcopy(airstrikeprojectileHandler.defaultShell)
	loadedShell = airstrikeprojectileHandler.shells[airstrikeprojectileHandler.shellNum]
	loadedShell.active = true
	loadedShell.pos = barrelEnd
	loadedShell.cannonLoc = plane.barrel
	loadedShell.type = selectedshell
	loadedShell.predictedBulletVelocity = VecScale(dir, velocity)
	airstrikeprojectileHandler.shellNum = (airstrikeprojectileHandler.shellNum%#airstrikeprojectileHandler.shells) +1

	if nocd then
		if selectedshell == 2 or selectedshell == 3 then
			shoottimers[selectedshell] = shotDelay * selectedshell
		else
			shoottimers[selectedshell] = shotDelay
		end
	else
		if selectedshell == 6 or selectedshell == 4 or selectedshell == 1 then
			shoottimers[selectedshell] = shotDelay
		elseif selectedshell == 5 then
			shoottimers[selectedshell] = shotDelay * 2
		else 
			shoottimers[selectedshell] = shotDelay * (selectedshell^(selectedshell*1.2))
		end
	end

	if selectedshell ~= 1 or selectedshell ~= 5 or selectedshell ~= 6 then PlaySound(gunsounds[selectedshell], plane.barrel.pos, 10) end
	lightTimer = 0.05
end

function ProjectileOperations(projectile, dt)
    projectile.predictedBulletVelocity = VecAdd(projectile.predictedBulletVelocity,(VecScale(gravity, dt)))
    local point2 = VecAdd(projectile.pos,VecScale(projectile.predictedBulletVelocity,dt))
	local dir = VecNormalize(VecSub(point2, projectile.pos))
    local hit, dist1 = QueryRaycast(projectile.pos, dir, VecLength(VecSub(point2, projectile.pos)))
    if hit then 
        hitPos = VecAdd(projectile.pos, VecScale(VecNormalize(VecSub(point2,projectile.pos)),dist1))
		projectile.active = false
		if projectile.type == 1 then
			MakeHole(hitPos, 1, 0.85, 0.7)
			SpawnParticle("smoke", hitPos, Vec(0, 1.0+math.random(1,10)*0.1, 0), 1.5, 1.5)
			PlaySound(explosionsounds[selectedshell], hitPos, 0.5)
		elseif projectile.type == 2 then
			Explosion(hitPos, 1.5)
		elseif projectile.type == 3 then
			Explosion(hitPos, 8)
		elseif projectile.type == 4 then
			SpawnFireParticles(hitPos, dir, 40, 5, "ground")
			PlaySound(firesound, hitPos, 0.6)
		elseif projectile.type == 5 then
			SpawnWaterParticles(hitPos, dir, 75, 5, "ground")
			Shockwave(hitPos)
			PlaySound(splashsound, hitPos, 0.7)
		else
			SpawnAcidParticles(hitPos, dir, 50, 3, "ground")
			PlaySound(firesound, hitPos, 0.6)
		end
	end

	if projectile.type == 4 then
		SpawnFireParticles(projectile.pos, dir, 3, 1, "air")
	elseif projectile.type == 5 then
		SpawnWaterParticles(projectile.pos, dir, 3, 1, "air")
	elseif projectile.type == 6 then
		SpawnAcidParticles(projectile.pos, dir, 3, 1, "air")
	else
		SpawnParticle("smoke", projectile.pos, Vec(0, 0, 0), 0.25*projectile.type, 0.25)
	end

	if IsPointInWater(projectile.pos) and projectile.type == 5 then
		projectile.active = false
		SpawnWaterParticles(projectile.pos, dir, 75, 5, "water")
		Shockwave(projectile.pos)
		PlaySound(splashsound, projectile.pos, 0.7)
	end

	local width = 0.35
	local length = 1
	local rot = QuatLookAt(projectile.pos, point2)
	local spritepos = TransformToParentPoint(Transform(projectile.pos, rot), Vec(0, 0, -1))
	rot = QuatRotateQuat(rot, QuatEuler(-90, 0, 0))
	local transform = Transform(spritepos, rot)
	if projectile.type < 4 then
		DrawSprite(shellsprites[projectile.type], transform, width, length, 1, 1, 1, 1, true, false)
	end
    projectile.pos = point2
end

function tick(dt)
	for key, shell in ipairs(airstrikeprojectileHandler.shells) do
		if shell.active then
			ProjectileOperations(shell, dt)
		end
	end

	if GetString("game.player.tool") == "airstrike" and GetPlayerVehicle() == 0 then
		SetBool("game.input.locktool", flycamenabled)
		firing = InputDown("usetool")
		airstrikeenabled = true
		if equipTimer < 1 then
			equipTimer = equipTimer + dt * 2
		end

		if firing then
			Shoot()
			if selectedshell == 1 then PlayLoop(gunsounds[selectedshell], plane.barrel.pos, 0.4) end
			if selectedshell == 4 or selectedshell == 6 then PlayLoop(fireloop, plane.barrel.pos, 0.2) end
			if selectedshell == 5 then PlayLoop(waterloop, plane.barrel.pos, 0.8) end
		end

		if InputPressed("R") then
			PlaySound(switchsound, GetCameraTransform().pos, 0.4)
			if selectedshell == 6 then selectedshell = 1 else selectedshell = selectedshell + 1 end
		end

		if InputPressed("rmb") then flycamenabled = not flycamenabled end
		if InputPressed("esc") then flycamenabled = false end
		if flycamenabled then FlyCam() end

		aimpos = flycamenabled and GetCamLookPos() or GetAimPos()

		local b = GetToolBody()
		if b ~= 0 then
			toolTrans = GetBodyTransform(b)
			toolPos = TransformToParentPoint(toolTrans, Vec(0.35, -0.6, -2.1))

			if lightTimer > 0 then
				PointLight(plane.barrel.pos, 1, 1, 1, 1)
				lightTimer = lightTimer - dt
			end

			if body ~= b then
				body = b
				local shapes = GetBodyShapes(b)
				radioshape = shapes[1]
				antennashape = shapes[2]
				planeshape = shapes[3]
				blinkshape = shapes[4]
				radiotransformation = GetShapeLocalTransform(radioshape)
				antennatransformation = GetShapeLocalTransform(antennashape)
				planetransformation = GetShapeLocalTransform(planeshape)
				blinktransformation = GetShapeLocalTransform(blinkshape)
			end
			
			if equipTimer > 1 and not radioactivated then
				PlaySound(beepsound, GetCameraTransform().pos, 0.4)
				radioactivated = true
			end

			if radioactivated then
				SetShapeEmissiveScale(radioshape, 0.5)
			else
				SetShapeEmissiveScale(radioshape, 0)
			end

			if InputDown("lmb") then
				SetShapeEmissiveScale(blinkshape, 5)
			else
				SetShapeEmissiveScale(blinkshape, 0)
			end

			rt = TransformCopy(radiotransformation)
			rt.rot = QuatRotateQuat(rt.rot, QuatEuler(0, 0, -15))
			SetShapeLocalTransform(radioshape, rt)

			bt = TransformCopy(blinktransformation)
			bt.rot = QuatRotateQuat(bt.rot, QuatEuler(0, 0, -15))
			SetShapeLocalTransform(blinkshape, bt)

			at = TransformCopy(antennatransformation)
			at.pos = VecAdd(at.pos, Vec(0, equipTimer*0.4, 0))
			at.rot = QuatRotateQuat(at.rot, QuatEuler(0, 0, -15))
			SetShapeLocalTransform(antennashape, at)

			SetShapeLocalTransform(planeshape, TransformToLocalTransform(GetBodyTransform(GetToolBody()), plane))
		end

		planefwdpos = TransformToParentPoint(plane, Vec(-0.15, 0, 0))
		planerotation = QuatRotateQuat(plane.rot, QuatEuler(0, 0, 0.1))
		plane.pos = planefwdpos
		plane.rot = planerotation
		plane.barrel.pos = TransformToParentPoint(plane, Vec(2.5, 4.5, 0))
	else
		airstrikeenabled = false
		radioactivated = false
		equipTimer = 0
	end

	for i=1, #shoottimers do
		if shoottimers[i] > 0 then
			shoottimers[i] = shoottimers[i] - dt
		else
			shoottimers[i] = 0
		end
	end
end

function draw()
	if flycamenabled and GetPlayerVehicle() == 0 then
		UiPush()
			UiTranslate(UiCenter(), UiMiddle())
			UiColor(1, 1, 1, 0.5)
			UiAlign("center middle")
			local crosshairid = selectedshell > 3 and 2 or selectedshell
			UiImage("MOD/img/AC130crosshair"..crosshairid..".png")
		UiPop()

		UiPush()
			UiTranslate(UiCenter(), UiMiddle()+UiMiddle()/2+50)
			UiColor(1, 1, 1)
			UiAlign("center")
			UiFont("regular.ttf", 26)
			if selectedshell ~= 3 or shoottimers[selectedshell] == 0 then
				UiText("Ready")
			else
				UiText(tostring(math.ceil(shoottimers[selectedshell])))
			end
		UiPop()
	end
	if airstrikeenabled and GetPlayerVehicle() == 0 then
		UiPush()
			UiTranslate(80, UiMiddle()+UiMiddle()/2)
			UiColor(0.4, 0.4, 0.4)
			UiAlign("left")
			UiFont("regular.ttf", 26)
			UiTextOutline(0,0,0,1,0.2)

			UiPush()
				UiColor(1, 1, 1)
				UiText("R: Change ammo")
				UiTranslate(0, 30)
				UiText("Right-Click: Plane-view")
			UiPop()

			UiTranslate(0, 70)
			UiPush()
				if selectedshell == 1 then UiColor(1, 1, 1) end
				UiText("25mm")
			UiPop()

			UiTranslate(0, 30)
			UiPush()
				if selectedshell == 2 then UiColor(1, 1, 1) end
				UiText("40mm")
			UiPop()

			UiTranslate(0, 30)
			UiPush()
				if selectedshell == 3 then UiColor(1, 1, 1) end
				UiText("105mm")
			UiPop()
			UiTranslate(0, 30)
			UiPush()
				if selectedshell == 4 then UiColor(1, 1, 1) end
				UiText("Napalm")
			UiPop()
			UiTranslate(0, 30)
			UiPush()
				if selectedshell == 5 then UiColor(1, 1, 1) end
				UiText("Water Cannon")
			UiPop()
			UiTranslate(0, 30)
			UiPush()
				if selectedshell == 6 then UiColor(1, 1, 1) end
				UiText("Acid")
			UiPop()
		UiPop()
	end
end