if pcall(do return _G["MT_FLYBOOSTER"] end)
    print("\131NOTICE:\128 Fly Booster objects already loaded.")
    return
end


freeslot(
"MT_FLYBOOSTER",
"S_FLYBOOSTER",
"S_FLYBOOSTERCD1",
"S_FLYBOOSTERCD2",
"MT_FLYBOOSTERGLOW",
"S_FLYBOOSTERGLOW",
"S_FLYBOOSTERGLOW2",
"S_FLYBOOSTERGLOW3",
"S_FLYBOOSTERGLOW4",
"S_FLYBOOSTERGLOW5",
"S_FLYBOOSTERFRONT",
"S_FLYBOOSTERARROWS",
"SPR_FLYB"
)


function A_FlyBoostTeleport(actor, var1, var2) 
	if (actor.target) then
			P_TeleportMove(actor.target, actor.x, actor.y, actor.z+actor.height/2)
	end
end



mobjinfo[MT_FLYBOOSTER] = {
//$Name Flight Booster
//$Category Springs and Fans
//$Sprite FLYBA0
//$Flags1Text Weak Booster
//$Flags4Text Strong Booster
//$Flags8Text Retain Momentum
//$ParameterText Pitch (0-15)
//$AngleText Yaw
spawnstate = S_FLYBOOSTER,
seestate = S_FLYBOOSTERCD1,
activesound = sfx_cdfm62,
doomednum = 345,
reactiontime = 16,
speed = 10*FRACUNIT,
radius = 64*FRACUNIT,
height = 128*FRACUNIT,
damage = 3,
spawnhealth = 0,
dispoffset = 0,
flags = MF_NOGRAVITY|MF_SPECIAL
}


states[S_FLYBOOSTER] = {
sprite = SPR_FLYB,
frame = A,
tics = -1,
nextstate = S_FLYBOOSTER
}

states[S_FLYBOOSTERCD1] = {
sprite = SPR_FLYB,
frame = A,
tics = 2,
nextstate = S_FLYBOOSTERCD2
}
states[S_FLYBOOSTERCD2] = {
sprite = SPR_FLYB,
frame = A,
action = A_FlyBoostTeleport,
var1 = 0,
tics = 18,
nextstate = S_FLYBOOSTER
}


mobjinfo[MT_FLYBOOSTERGLOW] = {
spawnstate = S_FLYBOOSTERGLOW,
reactiontime = 16,
speed = 10*FRACUNIT,
radius = 128*FRACUNIT,
height = 128*FRACUNIT,
damage = 3,
spawnhealth = 0,
dispoffset = 0,
flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT
}


states[S_FLYBOOSTERGLOW] = {
sprite = SPR_FLYB,
frame = B|FF_FULLBRIGHT|TR_TRANS80,
tics = -1,
nextstate = S_FLYBOOSTERGLOW
}
states[S_FLYBOOSTERGLOW2] = {
sprite = SPR_FLYB,
frame = B|FF_FULLBRIGHT,
tics = 5,
nextstate = S_FLYBOOSTERGLOW3
}
states[S_FLYBOOSTERGLOW3] = {
sprite = SPR_FLYB,
frame = B|FF_FULLBRIGHT|TR_TRANS20,
tics = 5,
nextstate = S_FLYBOOSTERGLOW4
}
states[S_FLYBOOSTERGLOW4] = {
sprite = SPR_FLYB,
frame = B|FF_FULLBRIGHT|TR_TRANS40,
tics = 5,
nextstate = S_FLYBOOSTERGLOW5
}
states[S_FLYBOOSTERGLOW5] = {
sprite = SPR_FLYB,
frame = B|FF_FULLBRIGHT|TR_TRANS60,
tics = 5,
nextstate = S_FLYBOOSTERGLOW
}
states[S_FLYBOOSTERFRONT] = {
sprite = SPR_FLYB,
frame = C,
tics = -1,
nextstate = S_FLYBOOSTERFRONT
}

states[S_FLYBOOSTERARROWS] = {
sprite = SPR_FLYB,
frame = D|FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS40,
var1 = 3,
var2 = 4,
tics = -1,
nextstate = S_FLYBOOSTERARROWS
}

addHook("MapThingSpawn", function(actor, spawnpoint)
	actor.reactiontime = (spawnpoint.extrainfo*-1125)/100
	if (actor.reactiontime == 90) then
		actor.reactiontime = 1
	elseif (actor.reactiontime == 180) then
		actor.reactiontime = 181
	elseif (actor.reactiontime == -90) then
		actor.reactiontime = -91
	elseif (actor.reactiontime == -180) then
		actor.reactiontime = -181
	end
	
	local targetColor = SKINCOLOR_YELLOW
	actor.mass = 0
	if (spawnpoint.options & (MTF_AMBUSH)) then
		targetColor = SKINCOLOR_GREEN
		actor.mass = 1
	end
	
	actor.speed = 20
	
	//There are way more effecient ways to do this, but it only runs once for each object on mapload, so who cares?
	//Discord got me self conscious about my if chains ;<
	if (spawnpoint.options & (MTF_EXTRA)) then
		if (spawnpoint.options & MTF_AMBUSH) then
			targetColor = SKINCOLOR_TEAL
		else
			targetColor = SKINCOLOR_BLUE
		end
		actor.speed = 10
	end
	if (spawnpoint.options & (MTF_OBJECTSPECIAL)) then
		if (spawnpoint.options & MTF_AMBUSH) then
			targetColor = SKINCOLOR_GOLD
		else
			targetColor = SKINCOLOR_RED
		end
		actor.speed = 30
	end	
	if ((spawnpoint.options & MTF_EXTRA) and (spawnpoint.options & MTF_OBJECTSPECIAL)) then
		if (spawnpoint.options & MTF_AMBUSH) then
			targetColor = SKINCOLOR_JET
		else
			targetColor = SKINCOLOR_WHITE
		end
		actor.speed = 40
	end
	
	
	actor.flags2 = MF2_SPLAT
	actor.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
	P_CreateFloorSpriteSlope(actor)
	actor.floorspriteslope.o = {
		x = actor.x,
		y = actor.y,
		z = actor.z+(actor.height/2)
	}
	actor.angle = (spawnpoint.angle%360)*ANG1
	actor.floorspriteslope.xydirection = actor.angle
	actor.floorspriteslope.zangle = actor.reactiontime*ANG1
	actor.spriteyscale = abs(cos(actor.reactiontime*-ANG1))
	
	local horizOffset = cos((actor.reactiontime+90)*ANG1)*10
	local xOffset = FixedMul(cos(actor.angle),horizOffset)
	local yOffset = FixedMul(sin(actor.angle),horizOffset)
	local zOffset = sin((actor.reactiontime+90)*ANG1)*10
	actor.color = targetColor
	
	local glow = P_SpawnMobj(actor.x-xOffset,actor.y-yOffset,actor.z-zOffset, MT_FLYBOOSTERGLOW)
	glow.angle = actor.angle
	glow.flags2 = MF2_SPLAT
	glow.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
	glow.blendmode = AST_ADD
	P_CreateFloorSpriteSlope(glow)
	glow.floorspriteslope.o = {
		x = glow.x,
		y = glow.y,
		z = glow.z+(actor.height/2)
	}
	glow.floorspriteslope.zangle = actor.floorspriteslope.zangle
	glow.floorspriteslope.xydirection = actor.floorspriteslope.xydirection
	glow.spriteyscale = actor.spriteyscale
	glow.color = targetColor
	actor.tracer = glow
	
	local arrows = P_SpawnMobj(actor.x-xOffset/2,actor.y-yOffset/2,actor.z-zOffset/2, MT_FLYBOOSTERGLOW)
	arrows.angle = actor.angle
	arrows.state = S_FLYBOOSTERARROWS
	arrows.flags2 = MF2_SPLAT
	arrows.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
	arrows.blendmode = AST_ADD
	P_CreateFloorSpriteSlope(arrows)
	arrows.floorspriteslope.o = {
		x = arrows.x,
		y = arrows.y,
		z = arrows.z+(actor.height/2)
	}
	arrows.floorspriteslope.zangle = actor.floorspriteslope.zangle
	arrows.floorspriteslope.xydirection = actor.floorspriteslope.xydirection
	arrows.spriteyscale = actor.spriteyscale
	arrows.color = targetColor
	
	local front = P_SpawnMobj(actor.x+xOffset,actor.y+yOffset,actor.z+zOffset, MT_FLYBOOSTERGLOW)
	front.angle = actor.angle
	front.state = S_FLYBOOSTERFRONT
	front.flags2 = MF2_SPLAT
	front.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
	P_CreateFloorSpriteSlope(front)
	front.floorspriteslope.o = {
		x = front.x,
		y = front.y,
		z = front.z+(actor.height/2)
	}
	front.floorspriteslope.zangle = actor.floorspriteslope.zangle
	front.floorspriteslope.xydirection = actor.floorspriteslope.xydirection
	front.spriteyscale = actor.spriteyscale
	front.color = targetColor
	actor.front = front
	
	
end, MT_FLYBOOSTER)

addHook("MobjThinker", function(actor)
	if (actor.speed == 40 and leveltime % 4 == 0) then
		if (actor.mass > 0) then
			actor.color = (($+1)%9)+1
			actor.tracer.color = (($+1)%9)+1
			actor.front.color = (($+1)%9)+1
		
		else
			actor.color = ($+1)%69
			actor.tracer.color = ($+1)%69
			actor.front.color = ($+1)%69
		end
	end

end, MT_FLYBOOSTER)

addHook("TouchSpecial", function(actor, toucher)
    if (actor.state == S_FLYBOOSTER) then
        local player = toucher.player
		actor.target = toucher
        actor.state = S_FLYBOOSTERCD1
        if (player) then
            if (toucher.state == S_PLAY_FLY or toucher.state == S_PLAY_FLY_TIRED) then //tails has special interactions with the booster
                player.powers[pw_tailsfly] = tailsflytics
                toucher.state = S_PLAY_FLY
            elseif (player.aether) //allowing aether to have special interactions with the booster
                Silverhorn.Aether.StartFlight(player)    
			elseif (toucher.skin == "shadow")  then //shadow also gets to be special!
				player.shadow.snaps = 2
                player.pflags = $1&~PF_THOKKED
			elseif (toucher.skin == "flame")  then //as does flame
				toucher.flamewep.recharge = 3
                player.pflags = $1&~PF_THOKKED
            else
                toucher.state = S_PLAY_JUMP
                player.pflags = $1&~PF_THOKKED
                player.pflags = $1&~PF_GLIDING
                player.pflags = $1|PF_JUMPED
                player.pflags = $1&~PF_STARTJUMP
            end
        end
		
		if (actor.mass > 0) then
		
			local boostForce = max(actor.speed, player.speed/FRACUNIT);
			local horizMom = cos((actor.reactiontime+90)*ANG1)*boostForce
			local vertiMom = sin((actor.reactiontime+90)*ANG1)*boostForce
			P_InstaThrust(toucher, actor.angle, horizMom)
			P_SetObjectMomZ(toucher, vertiMom, false)
			toucher.angle = actor.angle
		
		else
			local boostForce = actor.speed 
			local horizMom = cos((actor.reactiontime+90)*ANG1)*boostForce
			local vertiMom = sin((actor.reactiontime+90)*ANG1)*boostForce
			P_InstaThrust(toucher, actor.angle, horizMom)
			P_SetObjectMomZ(toucher, vertiMom, false)
			toucher.angle = actor.angle
		end
		
        if (actor.tracer) then
            actor.tracer.state = S_FLYBOOSTERGLOW2
        end
        A_PlayActiveSound(actor, 0, 0)
        
    end
    return true
end, MT_FLYBOOSTER)