local GUN = GUN_Troops
--#==============================================================================#
--Dedicated functions for spawning effects. Most use the MT_GUNAUTOFRAME object to spare having to needing billions of freeslots.
--#==============================================================================#

--A generic expanding wave. GUN.Circlewave"		GUN.CircleWave(s, STYLE, COLOR, FUSE, CSCALE, YOFFSET)
GUN.CircleWave = function(s, STYLE, COLOR, FUSE, CSCALE, YOFFSET)
	local ghs = P_SpawnMobjFromMobj(s, s.momx, s.momy, 0, MT_GUNAUTOFRAME)	
	ghs.frame = B|FF_TRANS20
	ghs.blendmode = AST_ADD
	ghs.fuse = (FUSE) or 23
	ghs.sttfade = (FUSE) and FUSE/2 or 14
	ghs.destscale = FRACUNIT*999
	ghs.scalespeed = FRACUNIT/5
	if (COLOR)
		ghs.color = COLOR
		ghs.colorized = true
	end
	ghs.spriteyoffset = $+((YOFFSET) or 0)
	if CSCALE
		ghs.spriteyscale = CSCALE
		ghs.spritexscale = CSCALE
	end	
	if STYLE --Turn into a papersprite or a floorsprite? 1 = papersprite. 2 = floorsprite!
		if (STYLE > 1) --FLAT
			ghs.renderflags = RF_FLOORSPRITE|RF_NOSPLATROLLANGLE|RF_NOSPLATBILLBOARD
			ghs.flags2 = $|MF2_SPLAT
			ghs.frame = C|FF_TRANS30
		elseif STYLE == 1 --PAPER!
			ghs.tracer = s
			ghs.ditchtracer = 2
			ghs.renderflags = $|RF_PAPERSPRITE|RF_SEMIBRIGHT
			ghs.angle = ((s.momx) or (s.momy)) and R_PointToAngle2(s.x, s.y, s.x+s.momx, s.momy)+ANGLE_90 or s.angle+ANGLE_90
			ghs.sttYspeed = -(ghs.scalespeed/3)
		end
	end return ghs --
end

--A quick, blinding flash" of pure light!	 GUN.LightFlash(s, COLOR, FUSE, CSCALE, YOFFSET)	
GUN.LightFlash = function(s, COLOR, FUSE, CSCALE, YOFFSET)	
	local ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_GUNAUTOFRAME)	
	ghs.blendmode = AST_ADD
	ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
	ghs.frame = E|TR_TRANS20
	ghs.fuse = (FUSE) or 15
	ghs.color = (COLOR) or SKINCOLOR_GOLDENROD
	if (CSCALE)
		ghs.spritexscale = CSCALE
		ghs.spriteyscale = CSCALE
	end
	ghs.spriteyoffset = $+((YOFFSET) or 0)
	ghs.scalespeed = $*3
	ghs.destscale = $*99
	ghs.sttfade = true
	return ghs --
end

--Spawn the Crimson Eye", usually to signify extra tough bots or to add some menace in dark areas.
--Though, it CAN be a different color if desired.
GUN.CrimsonEye = function(s, COLOR, BEETLE)
	local yu = (BEETLE) or s.GUN_HunterTable
	local ghs

	if s.target and s.target.valid
	or s.momz or s.momx or s.momy
	
		if not (s.flags2 & MF2_DONTDRAW)
		and not (((s.state == S_GUNH_INACTIVE) or (s.state == S_GUNB_AMBUSH)) and yu.anim == nil)

			local FRAME = (s.frame & FF_FRAMEMASK)
			local YSCALE = FixedDiv(FixedMul(s.scale, s.spriteyscale), FRACUNIT)
			local HEIGHT = s.height-(12*YSCALE) --Height is 118*s.scale
			-- HEIGHT = HEIGHT + (16 * FRACUNIT) -- Fixing height issues -garrean
			-- HEIGHT = FixedDiv(FixedMul($, s.spriteyscale), FRACUNIT) --Multiply with their spriteyscale.
			
			local ANGSHIFT,PLUS = 0,1
			if (yu.lastangle != nil)
				ANGSHIFT, PLUS = GUN.AngleDifference(s.angle, yu.lastangle, 2, ANG30)
			end
			local ANGLE = s.angle+(ANGSHIFT*PLUS)
			local OFFSETX,OFFSETY,OFFSETZ = 0,0,0 --Adjust offsets with some frames.
			
			if not BEETLE
				if (FRAME >= L) --Shooting/aiming states.
					OFFSETX = FixedMul((FRAME == L) and 7*YSCALE or 9*YSCALE, cos(ANGLE+ANGLE_90)) --Shift light to the right.
					OFFSETY = FixedMul((FRAME == L) and 7*YSCALE or 9*YSCALE, sin(ANGLE+ANGLE_90))
					OFFSETZ = (FRAME == L) and -8*YSCALE or -10*YSCALE
				elseif (FRAME >= G) and (FRAME < J) --Landing states.
					OFFSETZ = 
					(FRAME == G) and -16*YSCALE or
					(FRAME == H) and -13*YSCALE or
					-10*YSCALE
				elseif (FRAME <= E) and (FRAME >= B) --Awakening states.
					OFFSETZ = 
					(FRAME == E) and -20*YSCALE or
					(FRAME == D) and -30*YSCALE or 
					-40*YSCALE
				end
			else
				OFFSETZ = $-20*YSCALE --For GUN beetle.
			end
			if (YSCALE > FRACUNIT+25000) --Hacky debug.
				if (YSCALE > FRACUNIT*2)
					OFFSETZ = $-55*YSCALE
					OFFSETX = $/2
					OFFSETY = $/2
				else
					OFFSETZ = $-35*YSCALE
					OFFSETX = $*2/3
					OFFSETY = $*2/3					
				end
			end
			
			--Setup out of the way, now spawn the object!
			ghs = P_SpawnMobjFromMobj(s, 
			FixedMul(2*YSCALE, cos(ANGLE))+OFFSETX,
			FixedMul(2*YSCALE, sin(ANGLE))+OFFSETY,
			HEIGHT+OFFSETZ, MT_GUNAUTOFRAME)
			ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
			ghs.blendmode = AST_ADD
			ghs.frame = X|TR_TRANS10 --Different frame?

			if s.momx or s.momy or s.momz --Do the regular long glow if they're moving and it's actually noticable.
			or (ANGSHIFT >= ANG2)
			or (leveltime % 33 == 0)
				ghs.fuse = 66
				ghs.sttfade = 9
				ghs.scalespeed = YSCALE/44
				P_SetObjectMomZ(ghs, GUN.RNG(1, 89999, s), true)
				ghs.destscale = 1
				ghs.spritexscale = FRACUNIT+GUN.RNG(5000, 255000, s)
			else --Save on resources otherwise.
				ghs.fuse = 4
				ghs.spritexscale = FRACUNIT+GUN.RNG(5000, 355000, s)
		--		P_SetObjectMomZ(ghs, GUN.RNG(2, 169999, s), true)
			end
			if (yu.eyeglow != SKINCOLOR_RED) or (COLOR)
				ghs.color = (COLOR) or yu.eyeglow
				ghs.colorized = true
			end
			ghs.spriteyscale = ghs.spritexscale
			ghs.dispoffset = 1
			
			if yu.awakenanim == 2
				local ghs = GUN.LightFlash(ghs, yu.eyeglow)	
				ghs.scalespeed = FRACUNIT/3
				ghs.destscale = FRACUNIT*999
				P_SetObjectMomZ(ghs, -FRACUNIT, true)
			end
		end
		yu.lastangle = s.angle
	end
	return ghs --
end

--SA2 style explosion
GUN.SA2Explosion = function(s, CSCALE, COLOR)
	local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_GUNAUTOFRAME)	
	ghs.sprite = SPR_GPLZ
	ghs.frame = A|FF_TRANS10
	ghs.blendmode = AST_ADD
	ghs.fuse = 18
	ghs.sttfade = 8
	ghs.sttspeed = 1
	ghs.dispoffset = 2
	ghs.destscale = FRACUNIT*999
	ghs.scalespeed = FRACUNIT/6
	ghs.spriteyscale = (CSCALE) or FRACUNIT+35000
	ghs.spritexscale = (CSCALE) or FRACUNIT+35000
	ghs.sttfinalframe = P
	if COLOR
		ghs.color = COLOR
		ghs.colorized = true
	end
	return ghs --	
end
--Pulse Electricity from your body "ElectricBody"
GUN.ElectricBody = function(s, FUSE, COLOR)				
	local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_GUNAUTOFRAME)	
	ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
	ghs.frame = Z+5|TR_TRANS10
	ghs.blendmode = AST_ADD
	ghs.fuse = (FUSE) or 6
	ghs.dispoffset = 3
	if COLOR
		ghs.color = COLOR
		ghs.colorized = true
	end
	ghs.sttspeed = 1
	ghs.sttfirstframe = Z+5
	ghs.sttfinalframe = Z+9
	ghs.tracer = s
	return ghs --
end

--SMSreborn's stretch" function. Not used often for the actual robots, but their effects do sometimes.
GUN.Stretch = function(s)
local yu = s.GUNstretch

	--Cancel Conditions	
	if not yu.timer	
	or (s.spritexscale == FRACUNIT and s.spriteyscale == FRACUNIT) --Uhh, we're already done!
	or yu.air and P_IsObjectOnGround(s) --Cancels instantly when we hit a floor.		
	or yu.ground and not P_IsObjectOnGround(s) --Cancels instantly if we leave the floor.
		s.spritexscale,s.spriteyscale = FRACUNIT,FRACUNIT
		s.spritexoffset,s.spriteyoffset = 0,0
		s.GUNstretch = nil --Remove the table.
		return false --fin
	end
	
	if yu.Xspeed == nil yu.Yspeed = 5000 yu.Xspeed = 5000 end  --Default values are not set yet?

	yu.timer = $-1
	
	if s.spritexscale != FRACUNIT
		s.spritexscale = (s.spritexscale > FRACUNIT) and max($-yu.Xspeed, FRACUNIT) or min($+yu.Xspeed, FRACUNIT)
	end
	if s.spriteyscale != FRACUNIT
		s.spriteyscale = (s.spriteyscale > FRACUNIT) and max($-yu.Yspeed, FRACUNIT) or min($+yu.Yspeed, FRACUNIT)
	end	
	--Bonus yoffset movement? 
	if s.spriteyoffset != 0 
		s.spriteyoffset = (s.spriteyoffset > 0) and max($-FRACUNIT, 0) or min($+FRACUNIT, 0)
		if s.spritexoffset != 0 
			s.spritexoffset = (s.spriteyoffset > 0) and max($-2*FRACUNIT, 0) or min($+2*FRACUNIT, 0)
		end		
	end return s --Still squash&stretching!
end

--Draw a dense trail of ghosts from point 1 to point 2. A billion options since I'll use it alot. GhostTrail"
-- GUN.GhostTrail(s, COLOR, FUSE, TRANS, CSCALE, DESTSCALE, SPRITE, FRAME, DENSITY)
GUN.GhostTrail = function(s, COLOR, FUSE, TRANS, CSCALE, DESTSCALE, SPRITE, FRAME, DENSITY)
	if not (s.momx or s.momy or s.momz)
	or not s.health
		return --Don't draw...
	end 
	local density = (DENSITY) or 16*FRACUNIT
	local dist = FixedDiv(FixedMul((R_PointToDist2(0, 0, R_PointToDist2(0, 0, s.momx, s.momy), s.momz) / density), FRACUNIT), s.scale)
	dist = max(1, min($,180))
		
	local xdistog = ((s.momx) or 1)/dist
	local ydistog = ((s.momy) or 1)/dist
	local zdistog = ((s.momz) or 1)/dist
	
	local xdist,ydist,zdist = 0,0,0
	TRANS = (TRANS) or FF_TRANS80
	FUSE = (FUSE) or 7
	COLOR = (COLOR) or s.color
	DESTSCALE = (DESTSCALE) or 1
	SPRITE = (SPRITE) or s.sprite
	FRAME = (FRAME) or s.frame

	for i = dist,1,-1
			if s.scale != FRACUNIT
				xdist = FixedDiv(FixedMul((s.momx/dist)*i, FRACUNIT), s.scale)
				ydist = FixedDiv(FixedMul((s.momy/dist)*i, FRACUNIT), s.scale)
				zdist = FixedDiv(FixedMul(((s.momz)/dist)*i, FRACUNIT), s.scale)
			else
				xdist = xdistog*i
				ydist = ydistog*i
				zdist = zdistog*i
			end		
			local zip = P_SpawnMobjFromMobj(s, xdist-s.momx, ydist-s.momy, zdist-(s.momz), MT_THOK)
			zip.sprite = SPRITE
			zip.frame = (FRAME & ~FF_TRANSMASK)|TRANS
			zip.angle = s.angle
			zip.rollangle = s.rollangle
			zip.spritexoffset = s.spritexoffset
			zip.spriteyoffset = s.spriteyoffset
			zip.color = COLOR
			zip.colorized = true
			zip.renderflags = RF_SEMIBRIGHT
			zip.blendmode = AST_ADD
			zip.tics = FUSE+15
			zip.fuse = FUSE
			zip.scalespeed = $*2
			zip.destscale = DESTSCALE
			if CSCALE
				zip.spritexscale = CSCALE
				zip.spriteyscale = CSCALE
			end
	end
end

--Speeding wind" lines for falling and rising! Mostly mean to make Blur's skydiving sprites look cooler.
GUN.zwind = function(s, NUM)
	NUM = (NUM) or 2
	local tmomz = s.momz
	local ghs,INVX,INVY,INVZ,SCALE,SCALESPEED
	
	--Spawn vertical wind-lines. Every second one spawned is an opposite-sided replica of the first.
	for d = 1,NUM	
		if not INVX
			INVX = GUN.RNG(9, 55,s)*s.scale
			INVY = P_RandomRange(9, 55)*s.scale
			INVZ = GUN.RNG(1, 128,s)*P_MobjFlip(s)*s.scale
			
			ghs = P_SpawnMobjFromMobj(s, INVX, INVY, INVZ, MT_THOK)
			ghs.scale = max( s.scale/3, ghs.scale-P_RandomRange(20000,0) )
			ghs.destscale = 1
			ghs.scalespeed = FRACUNIT/P_RandomRange(33,4)
			
			SCALE = ghs.scale
			SCALESPEED = ghs.scalespeed
		else
			ghs = P_SpawnMobjFromMobj(s, INVX*-1, INVY*-1, INVZ, MT_THOK)
			ghs.destscale = 1
			ghs.scale = SCALE
			ghs.scalespeed = SCALESPEED				
			INVX = nil
		end		

		
		if (s.eflags & MFE_UNDERWATER) --Use bubble-sprites instead?
			ghs.fuse = 7
			ghs.state = (leveltime % 2) and S_MEDIUMBUBBLE or S_SMALLBUBBLE
		else --Main sprite.
			ghs.sprite = SPR_G1FX
			ghs.frame = F|FF_TRANS30
			ghs.renderflags = RF_SEMIBRIGHT	
			ghs.fuse = 9 ghs.tics = 99
			ghs.momz = s.momz/-2			
		end
		ghs.momx = s.momx/3
		ghs.momy = s.momy/3
		ghs.spriteyoffset = (s.momz < 0) and 40*FRACUNIT or -10*FRACUNIT		
	 end
end

--Edit of the Shiny Splat function to work as a reticule instead.
GUN.FloorTarget = function(s, COLOR, FUSE, CSCALE, BLENDMODE, TRANS)
	local sec = s.subsector.sector
	local cslope,fslope
	TRANS = (TRANS) or FF_TRANS10

	if sec != nil --Adjust to slopes?
		if not (s.eflags & MFE_VERTICALFLIP)
		and (s.ceilingrover and s.ceilingrover.b_slope and s.ceilingrover.b_slope.zdelta)
		and (s.ceilingrover.flags & FF_RENDERPLANES) and (s.ceilingrover.flags & FF_EXISTS)
		and not (s.ceilingrover.flags & FF_CUTSPRITES) and not (s.ceilingrover.flags & FF_FOG)		
			cslope = s.ceilingrover.b_slope
		elseif sec.c_slope and sec.c_slope.zdelta and sec.ceilingpic != "F_SKY1"
			cslope = sec.c_slope		
		end
		if sec.f_slope and sec.f_slope.zdelta and sec.floorpic != "F_SKY1"
			fslope = sec.f_slope		
		end
	end
	
	local ghs
	for d = -1,1,2 --Now let's spawn some splats!
		if d == -1 and not (s.eflags & MFE_VERTICALFLIP) continue end
		if d == 1 and (s.eflags & MFE_VERTICALFLIP) continue end
		
		if ((d >= 1) and not (s.z > s.floorz+250*FRACUNIT) )
		or ((d < 0) and not (s.z < s.ceilingz-250*FRACUNIT) )
		
			if (d < 0)
				ghs = P_SpawnMobj(s.x,s.y,s.ceilingz-5600, MMT_GUNAUTOFRAME)
				ghs.eflags = $|MFE_VERTICALFLIP ghs.flags2 = $|MF2_OBJECTFLIP
				ghs.floordist = s.z-s.ceilingz-(250*FRACUNIT) --Calculate distance to floor/ceiling.
				ghs.renderflags = $|RF_FULLBRIGHT|RF_FLOORSPRITE|RF_ABSOLUTEOFFSETS
				ghs.z = s.ceilingz-5600
				
				if cslope 
					P_CreateFloorSpriteSlope(ghs)
					ghs.flags2 = $|MF2_SPLAT
					ghs.renderflags = $|RF_FLOORSPRITE|RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
					ghs.floorspriteslope.o = {x = s.x, y = s.y, z = s.ceilingz}
					ghs.floorspriteslope.xydirection = cslope.xydirection
					ghs.floorspriteslope.zangle = cslope.zangle
				end			
			else
				ghs = P_SpawnMobj(s.x,s.y,s.floorz, MT_GUNAUTOFRAME)
				ghs.floordist = s.z-s.floorz-(250*FRACUNIT)
				ghs.renderflags = RF_FULLBRIGHT|RF_FLOORSPRITE|RF_SHADOWDRAW|RF_ABSOLUTEOFFSETS
				if fslope
					P_CreateFloorSpriteSlope(ghs)
					ghs.flags2 = $|MF2_SPLAT
					ghs.renderflags = $|RF_FLOORSPRITE|RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
					ghs.floorspriteslope.o = {x = s.x, y = s.y, z = s.floorz}
					ghs.floorspriteslope.xydirection = fslope.xydirection
					ghs.floorspriteslope.zangle = fslope.zangle
				end	
				ghs.flags = $ & ~MF_NOCLIPHEIGHT
			end
			
			ghs.flags2 = $|MF2_SPLAT
			ghs.scale = s.scale	
			ghs.sprite = SPR_TARG
			ghs.frame = D|TRANS
			ghs.spritexoffset = 32*FRACUNIT
			ghs.spriteyoffset = 31*FRACUNIT
			
			--Force color adjustments or nah?
			if COLOR
				ghs.colorized = true
				ghs.color = COLOR
			end
			if CSCALE
				ghs.spritexscale = CSCALE
				ghs.spriteyscale = CSCALE
			end
			if BLENDMDOE
				ghs.blendmode = BLENDMODE
			end
			P_MoveOrigin(ghs, s.x+s.momx, s.y+s.momy, ghs.z)
			ghs.fuse = FUSE
			ghs.tics = FUSE+9
		end		
	end
	if ghs then ghs.flags2 = $ | MF2_DONTDRAW end -- this is intrusive -garrean
	return ghs
end

--Function stolen from SA-Sonic to spawn splats on any closeby ceilings/floors. They're final demo coronas, basically. ShinySplat"
GUN.ShinySplat = function(s, color, fuse, scalemult, nolight)
	local lightlevel = 0
	local sec = s.subsector.sector
	local cslope,fslope
	scalemult = (scalemult) or 100

	if sec != nil 
		--Determine what's a slope and what isn't.
		if not (s.eflags & MFE_VERTICALFLIP)
		and (s.ceilingrover and s.ceilingrover.b_slope and s.ceilingrover.b_slope.zdelta)
		and (s.ceilingrover.flags & FF_RENDERPLANES) and (s.ceilingrover.flags & FF_EXISTS)
		and not (s.ceilingrover.flags & FF_CUTSPRITES) and not (s.ceilingrover.flags & FF_FOG)		
			cslope = s.ceilingrover.b_slope
		elseif sec.c_slope and sec.c_slope.zdelta and sec.ceilingpic != "F_SKY1"
			cslope = sec.c_slope		
		end
		if sec.f_slope and sec.f_slope.zdelta and sec.floorpic != "F_SKY1"
			fslope = sec.f_slope		
		end
		if not nolight --Ignore lightlevel if this is checked.
			lightlevel = sec.lightlevel --First, calculate our light!
			for fof in sec.ffloors()
				if fof and (fof.flags & FF_EXISTS) 
					if not (fof.flags & FF_NOSHADE) and not (fof.flags & FF_DOUBLESHADOW)
					and (s.z < fof.bottomheight)
						lightlevel = fof.toplightlevel

					elseif (fof.flags & FF_CUTSPRITES) and ((s.z >= fof.bottomheight) and (s.z+(s.height/2) < fof.topheight))
						lightlevel = fof.toplightlevel+20
					end
				end
			end
			if lightlevel and (lightlevel > 239) return true end --Too bright, don't spawn!
		end
	end
	
	local lightswitch = false
	local ghs,ths	

	for d = -1,1,2 --Now let's spawn some splats!
		if ((d >= 1) and not (s.z > s.floorz+150*FRACUNIT) )
		or ((d < 0) and not (s.z < s.ceilingz-150*FRACUNIT) )
		
			if (d < 0)
				ghs = P_SpawnMobj(s.x,s.y,s.ceilingz-5600, MMT_GUNAUTOFRAME)
				ghs.eflags = $|MFE_VERTICALFLIP ghs.flags2 = $|MF2_OBJECTFLIP
				ghs.floordist = s.z-s.ceilingz-(150*FRACUNIT) --Calculate distance to floor/ceiling.
				ghs.renderflags = $|RF_FULLBRIGHT|RF_FLOORSPRITE
				ghs.z = s.ceilingz-5600
				
				if cslope 
					P_CreateFloorSpriteSlope(ghs)
					ghs.flags2 = $|MF2_SPLAT
					ghs.renderflags = $|RF_FLOORSPRITE|RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
					ghs.floorspriteslope.o = {x = s.x, y = s.y, z = s.ceilingz}
					ghs.floorspriteslope.xydirection = cslope.xydirection
					ghs.floorspriteslope.zangle = cslope.zangle
				elseif sec.ceilingpic == "F_SKY1" and sec.ceilingheight == s.ceilingz
					ghs.flags2 = MF2_DONTDRAW
					continue
				end	
				
				
			else
				ghs = P_SpawnMobj(s.x,s.y,s.floorz, MT_GUNAUTOFRAME)
				ghs.floordist = s.z-s.floorz-(150*FRACUNIT)
				ghs.renderflags = RF_FULLBRIGHT|RF_FLOORSPRITE|RF_SHADOWDRAW
				if fslope
					P_CreateFloorSpriteSlope(ghs)
					ghs.flags2 = $|MF2_SPLAT
					ghs.renderflags = $|RF_FLOORSPRITE|RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
					ghs.floorspriteslope.o = {x = s.x, y = s.y, z = s.floorz}
					ghs.floorspriteslope.xydirection = fslope.xydirection
					ghs.floorspriteslope.zangle = fslope.zangle
				elseif sec.floorheight == s.floorz and sec.floorpic == "F_SKY1"
					ghs.flags2 = MF2_DONTDRAW
					continue --
				end	
				ghs.flags = $ & ~MF_NOCLIPHEIGHT
			end
			
			ghs.flags2 = $|MF2_SPLAT
			ghs.scale = s.scale
			ghs.trframe = 0
			
			if ghs.floordist
				ghs.floordist = ($/FRACUNIT)+150	
				if ghs.floordist < 0
					ghs.floordist = $*-1
				end	
				if d == -1 and not (s.eflags & MFE_VERTICALFLIP)
					ghs.floordist = max($-50, 0)
				end
				ghs.trframe = (ghs.floordist/29)*FRACUNIT
			end	
			
			if not nolight and lightlevel and (lightlevel > 199)
				ghs.trframe = $+((lightlevel-199)/7)*FRACUNIT
				if (lightlevel > 239) lightswitch = true end --
			end
			
			ghs.trframe = min($, 8*FRACUNIT) --Never go over 8 FRAC!
							
			ghs.sprite = SPR_G1FX
			ghs.frame = J|min(TR_TRANS70+ghs.trframe,TR_TRANS90)	
			if leveltime % 2 == 0 --Flickering effect.
				ghs.scale = $*10/9
			elseif leveltime % 3 == 0
				ghs.scale = $*20/19
			end
			
			if scalemult != 100 --Multiply the splat's base scale?
				ghs.scale = FixedDiv(FixedMul($, 100), scalemult)
			end
			
			--Force color adjustments or nah?
			if color
				ghs.colorized = true
				ghs.color = color
			end
			
			--Adjust size depending on distance to floor/ceiling.
			if d == -1 and not (s.eflags & MFE_VERTICALFLIP)
				ghs.scale = max(
				FixedDiv(FixedMul(($-(200*ghs.floordist)), 100), scalemult-7) ,
				888)
			else
				ghs.scale = max(
				FixedDiv(FixedMul(($-(440*-ghs.floordist)), 100), scalemult) ,
				888)
			end
			
			ghs.blendmode = AST_ADD
			P_MoveOrigin(ghs, s.x+s.momx, s.y+s.momy, ghs.z)
			ghs.fuse = fuse ghs.tics = fuse+9
			if i == 1
			ths = ghs
			end
		end		
	end return ghs,ths,lightswitch --
end


--A charging vortex" effect, used for snipers.
GUN.Vortex = function(s, FUSE, COLOR, CSCALE, CROLL)	
	local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_GUNAUTOFRAME)	
	ghs.frame = (ALTFRAME) or R|TR_TRANS10 --Different frame?
	ghs.fuse = (FUSE) or 16
	ghs.blendmode = AST_ADD
	ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
	ghs.destscale = FRACUNIT*999
	ghs.sttfade = true	
	ghs.spriteyscale = (CSCALE) or FRACUNIT
	ghs.spritexscale = ghs.spriteyscale
	ghs.sttroll = (CROLL) or (leveltime % 2) and ANG20*3 or -ANG20*3
	if COLOR
		ghs.color = COLOR
		ghs.colorized = true
	end	
	return ghs --
end

--Debris" flinging everywhere when you kill a mech. Or gibs" as is the popular name with SRB2. i is the inflictor, but isn't needed.
GUN.gibs = function(s, i, NUM, SPEED)
	SPEED = (SPEED) or max(FRACUNIT, abs(i.momx)+abs(i.momy)+abs(i.momz/3))
	NUM = (NUM) or max(1, min(8, FixedInt(SPEED/12)) )
	i = (i) or s
	for d = 1,NUM --Fling debris when killed.
		local ghs = P_SpawnMobj(
		s.x+(GUN.RNG(-40-(d*3),40+(d*3), i)*s.scale), 
		s.y+(GUN.RNG(-40-(d*3),40+(d*3), s)*s.scale), 
		s.z+(GUN.RNG(d,115+(d*3), i)*s.scale),
		MT_BOSSJUNK) //s.x, s.y, s.z+(s.height/2)+(d*3),
		if ghs and ghs.valid
			ghs.flags = MF_BOUNCE|MF_GRENADEBOUNCE|MF_NOCLIPTHING|MF_SOLID|MF_NOBLOCKMAP
			ghs.angle = (i == s) and s.angle+ANGLE_180 or i.angle
			ghs.angle = $+(GUN.RNG(125-(d*3),-123+d, ghs)*ANG1) // (P_RandomRange(-120,120)*ANG1) //
			ghs.sprite = SPR_G1DB
			ghs.scale = s.scale
			ghs.rollangle = ANG1*GUN.RNG(0,359,ghs)
			ghs.spriteyscale = GUN.RNG(FRACUNIT+(d*24366),FRACUNIT*5,ghs)
			ghs.spritexscale = ghs.spriteyscale
			P_InstaThrust(ghs, ghs.angle, 12*i.scale)
			P_SetObjectMomZ(ghs, (GUN.RNG(-d,d,ghs)+(SPEED/(FRACUNIT*8)) )*i.scale, true)
			ghs.momx = $+(i.momx)
			ghs.momy = $+(i.momy)
			ghs.frame = GUN.RNG(A, E, ghs)
			ghs.fuse = 44
			ghs.color = (s.color) or SKINCOLOR_GREY
		end
	end
	local ghs = GUN.WindBlast(s) //, nil, AST_ADD)
	if ghs and ghs.valid
		ghs.spriteyoffset = 16*FRACUNIT
		ghs.fuse = 7
		ghs.frame = $+(FRACUNIT*2)
		ghs.sttfade = true
	end
	GUN.QuickDust(s, SKINCOLOR_SUPERSILVER1)
end

--Rocks flying out of the ground or from the walls.
--Higher range number means higher spewing rocks with less horizontal distance. Crater" Spew"
GUN.CraterSpew = function(s, ANGLE, RANGE)
	local RNG1 = P_RandomRange(5,20)
	local RNG2 = P_RandomRange(1,360)
	local HEIGHT = (not P_IsObjectOnGround(s)) and (s.height/2) or 0
	RANGE = (RANGE) or 8

	local ghs = P_SpawnMobjFromMobj(s, 0, 0, HEIGHT, MT_GUNDEBRIS)
	if ghs and ghs.valid
		ghs.angle = RNG2*ANG1
		if ANGLE
			P_InstaThrust(ghs, ghs.angle, ((50+RNG1*2)*(FRACUNIT/2))/RANGE)
			P_Thrust(ghs, ANGLE, ((50+RNG1*2)*(FRACUNIT/2))/RANGE)
		else
			P_InstaThrust(ghs, ghs.angle, ((50+RNG1*2)*FRACUNIT)/RANGE)
		end
		P_SetObjectMomZ(ghs, P_RandomRange(-4,RANGE)*FRACUNIT)
		ghs.sprite = SPR_ROIJ
		ghs.frame = min(E, RNG1/4)
		ghs.scale = $/4
		ghs.spriteyscale = $*(RNG1/5)
		ghs.spritexscale = $*(RNG1/5)
		ghs.shadowscale = FRACUNIT*8
		ghs.ROCK = true
	end return ghs --
end

--Grounded circle wind blast. Windblast"
GUN.WindBlast = function(s, COLOR, BLENDMODE)
	local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_GUNAUTOFRAME)	
	ghs.blendmode = (BLENDMODE) or $
	ghs.frame = N|TR_TRANS20
	ghs.fuse = 16
	ghs.color = (COLOR) or SKINCOLOR_SILVER
	ghs.scalespeed = $*3
	ghs.sttspeed = 3
	ghs.destscale = $*99
	ghs.sttfinalframe = P
	ghs.sttfade = true
	return ghs --
end

--Leave behind a super-quick kickup of dust"
GUN.QuickDust = function(s, COLOR, BLENDMODE, YOFFSET, TRACER, TRANS)
	local ANGLE = s.angle //((s.momx) or (s.momy)) and R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy) 
	TRANS = (TRANS) or FF_TRANS10
	local ths,ghs
	for i = -1,1,2
		ghs = P_SpawnMobjFromMobj(s, FixedMul(36*s.scale, cos(ANGLE+(ANGLE_90*i))), FixedMul(36*s.scale, sin(ANGLE+(ANGLE_90*i))), 0, MT_GUNAUTOFRAME)	
		ghs.renderflags = RF_PAPERSPRITE|RF_SEMIBRIGHT
		ghs.angle = ANGLE-(ANG1*39*i)
		ghs.frame = (i != 1) and C|TRANS or C|TRANS|FF_HORIZONTALFLIP	
		P_Thrust(ghs, ANGLE+(ANG1*39*i), 5*s.scale) 
	--	ghs.scale = s.scale/3
	--	ghs.scalespeed = $*4
	--	ghs.destscale = FRACUNIT*99
		ghs.sttfade = true
		ghs.sttspeed = 3
		ghs.sttfinalframe = D
		ghs.spriteyoffset = (YOFFSET) or 0
		if COLOR
			ghs.color = COLOR
			ghs.colorized = true
		end
		ghs.blendmode = BLENDMODE or $
		ghs.tracer = TRACER or nil
		ghs.fuse = 7
		if i == -1 ths = ghs end
	end return ths,ghs --
end

--Leave behind a medium-sized kickup of dust" Stolen from SMSreborn.
GUN.MediumDust = function(s, COLOR, BLENDMODE, FRAME)
	local ANGLE = ((s.momx) or (s.momy)) and R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy) or s.angle
	FRAME = (FRAME) or Q|FF_TRANS30
	local ghs,ths
	for i = -1,1,2
		ghs = P_SpawnMobjFromMobj(s,
		s.momx+FixedMul((s.radius+10*s.scale)*i, cos(ANGLE+ANGLE_90)),
		s.momy+FixedMul((s.radius+10*s.scale)*i, sin(ANGLE+ANGLE_90)),
		0, MT_GUNAUTOFRAME)	
		ghs.renderflags = RF_PAPERSPRITE
		ghs.angle = ANGLE-(ANG1*39*i)
		P_Thrust(ghs, ANGLE+(ANG1*39*i), 5*s.scale) 
		ghs.frame = (i == 1) and FRAME or FRAME|FF_HORIZONTALFLIP
		ghs.fuse = 17
		ghs.scalespeed = $*3
		ghs.destscale = FRACUNIT*99
		ghs.sttfade = true
		ghs.sttspeed = 2
		ghs.sttfinalframe = W
		ghs.color = (COLOR) or SKINCOLOR_BEIGE
		ghs.blendmode = BLENDMODE or $	
		if i != 1
			ths = ghs
		end
	end return ghs,ths --
end



--Shortcut for directional dust" Best used for landing effects!
GUN.SpawnDust = function(s, SPEED, SCALER, SIDESPAWN)
	if (s.eflags & (MFE_GOOWATER|MFE_TOUCHLAVA)) return end --
	SPEED = (SPEED) or -10*FRACUNIT
	SCALER = (SCALER) or 10
	
	 --Loops within loops for ultimate power!
	for d = -1,1
	
		for i = 0,1
		
			local extra = 0
			if i == 1 extra = SPEED/3 end
			
			local offset = -ANGLE_22h*i
			local ghs
			
			if (s.eflags & MFE_UNDERWATER) --Bubbles when underwater
				ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_SMALLBUBBLE)
				ghs.fuse = 8
			else
				if SIDESPAWN --Spawn big dustclouds from your sides instead.
				
					if d == 0 or i == 1 continue end
					
					local RNG1 = GUN.RNG(30+d,53,s)
					
					ghs = P_SpawnMobjFromMobj(s,
					FixedMul((RNG1/3)*s.scale*d, cos(s.angle+ANGLE_90)), 
					FixedMul((RNG1/3)*s.scale*d, sin(s.angle+ANGLE_90)), 0, MT_GUNAUTOFRAME)
					
					ghs.scalespeed = $+ ( (32000+RNG1*3999) /5) 
					ghs.scale = ($/3)+(RNG1*1000)
					ghs.sprite = SPR_DUST
					if leveltime % 4 == 0
						ghs.sttspeed = 4
						ghs.frame = B|FF_TRANS40
					else
						ghs.frame = A|FF_TRANS50
						ghs.sttspeed = 3
					end
					ghs.fuse = 25
					ghs.sttfade = 25
					ghs.sttfinalframe = D
					ghs.sttYspeed = -52000
				else
					ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_SPINDUST)
					ghs.renderflags = $|RF_PAPERSPRITE
					ghs.flags2 = $|MF2_SHADOW
					ghs.angle = (ANGLE_45*d)+ANGLE_90+offset+s.angle
					ghs.fuse = 30-i-SCALER
				end
				if (s.eflags & MFE_TOUCHWATER)
					ghs.flags2 = $|MF2_SHADOW
					ghs.frame = ($ & ~FF_TRANSMASK)|FF_TRANS90
					ghs.color = SKINCOLOR_AETHER
				else
					ghs.color = SKINCOLOR_BEIGE
				end
				ghs.colorized = true
			end
			P_InstaThrust(ghs, (ANGLE_45*d)-offset+s.angle, SPEED+extra)
			ghs.scalespeed = $*10/SCALER
			ghs.scale = $/3
			ghs.destscale = $*99
		end
	end
end

--Shortcut for a jump-boosting dust"
GUN.SpawnJumpDust = function(s, SPEED, SCALER)
	SPEED = (SPEED) or 10*FRACUNIT
	SCALER = (SCALER) or 10
	local ANGLE = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
	local EXTRA = 0
	local OFFSET = 0
	
	for d = 1,8 --Loops within loops for ultimate power!
		for i = 0,1
			local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_SPINDUST)
			if i == 1
				OFFSET = ANGLE_22h
				EXTRA = FixedDiv(FixedMul(SPEED, 40), 18)
			end
			P_InstaThrust(ghs, (ANGLE_45*d)-OFFSET, SPEED+EXTRA)
			ghs.renderflags = RF_PAPERSPRITE
			ghs.angle = (ANGLE_45*d)+ANGLE_90-OFFSET
			ghs.scalespeed = $*10/SCALER
			ghs.destscale = $*99
			ghs.flags2 = $|MF2_SHADOW
			if (s.eflags & (MFE_TOUCHWATER|MFE_TOUCHLAVA))
				ghs.color = SKINCOLOR_AETHER
			else
				ghs.color = SKINCOLOR_BEIGE
				ghs.z = s.floorz
			end
			ghs.colorized = true
			ghs.fuse = 35-i
		end
	end
end

--Basic particle sparkles! "GUN.particles" or "GUN.sparkles" 
GUN.particles = function(s, RAD, NUM, THRUST)
	RAD = (RAD) or 48
	NUM = (NUM) or 6
	for i = 1,NUM,1 	
		local rng = P_RandomRange(-RAD+6, RAD-6) if leveltime % 2 rng = $*-1 end
		local rng2 = P_RandomRange(-RAD,RAD)
		
		local ghs = P_SpawnMobjFromMobj(s, rng*s.scale, rng*s.scale, (s.height/2)+(rng2*s.scale)-s.momz, MT_THOK)
		ghs.state = mobjinfo[MT_NIGHTSPARKLE].spawnstate
		ghs.colorized = true
		ghs.color = (s.color) or SKINCOLOR_GOLDENROD
		ghs.blendmode = AST_ADD	
		ghs.fuse = 15
		ghs.frame = $|TR_TRANS10
		ghs.tics = ghs.fuse+1
		ghs.destscale = $*99
		if THRUST
			ghs.angle = R_PointToAngle2(ghs.x, ghs.y, s.x, s.y)+ANGLE_180
			P_Thrust(ghs, ghs.angle, THRUST*89500)
			P_SetObjectMomZ(ghs, rng2*(THRUST or 1)*(s.scale/50), true)
			ghs.momx = $+s.momx
			ghs.momy = $+s.momy
		end
	end
end

