//Hi :]
local function propel()
	for player in players.iterate
        if player.mo.skin == "propeller_box" then
			if player.mo.state == S_PLAY_DEAD 
			or (player.mo.state == S_PLAY_PAIN and (not (player.pflags & PF_SLIDING))) then
				return
			end
			
			if (maptol & TOL_NIGHTS) then
				return
			end
			
			if not player.propelled then
				player.propelled = false
			end
			
			if not player.propelcount then
				player.propelcount = 0
			end
			
			if not player.beingcarried then
				player.beingcarried = false
			end
			
			if not (player.cmd.buttons & BT_CUSTOM1) then 
				player.c1tapready = true
				player.c1tapping = false
			elseif player.c1tapready then
				player.c1tapping = true
				player.c1tapready = false
			else
				player.c1tapping = false
			end
			
			if P_IsObjectOnGround(player.mo)
			or (player.powers[pw_justsprung])
			or (player.powers[pw_carry] == CR_MACESPIN) then
				player.propelled = false
				player.propelcount = 0
				player.pflags = $ & ~PF_CANCARRY
				if player.mo.state == S_PLAY_FLY then
					player.mo.state = S_PLAY_STND
				end
			end
			
			if P_IsObjectOnGround(player.mo) then
				if player.c1tapping then
					if player.speed <= 5*FRACUNIT then
						player.mo.state = S_PLAY_FLY
						player.mo.momz = 15*FRACUNIT*P_MobjFlip(player.mo)
						player.propelcount = 1
						S_StartSound(player.mo, 469)
					end
				elseif player.cmd.buttons & BT_USE then
					return
				end
			end
			
			if player.mo.state == S_PLAY_FLY or player.mo.state == S_PLAY_SWIM then
				player.pflags = $|PF_CANCARRY|PF_JUMPED
				player.pflags = $ & ~PF_STARTJUMP
				player.pflags = $ & ~PF_SPINNING
				
				
				if (not (player.mo.eflags & MFE_UNDERWATER))
				and not S_SoundPlaying(player.mo, 508) then
					S_StartSound(player.mo, 508)
				end
			end
			
			
			if (player.cmd.buttons & BT_JUMP) then
				if player.mo.state != S_PLAY_FLY
				and (not (player.propboxsearch and player.propboxsearch.valid)) then
					if (not (player.mo.eflags & MFE_UNDERWATER))then
						S_StartSound(player.mo, 195)
					end
					player.mo.state = S_PLAY_FLY
				end
				
				if player.propelled == false
				or player.powers[pw_super] then
					player.mo.momz = $ + 1*FRACUNIT*P_MobjFlip(player.mo)
					if player.mo.momz == 0 then
						if (player.mo.eflags & MFE_VERTICALFLIP) then
							player.mo.momz = -1*FRACUNIT
						else
							player.mo.momz = 1*FRACUNIT
						end
					end
					player.propelcount = $ + 1
					if player.propelghost and player.propelghost.valid then // Prevents the first ghost from showing, preventing weird visuals. Thanks to L_CloneFighter-v2.pk3 on Discord for helping with this.
						player.propelghost.flags2 = $ & ~MF2_DONTDRAW
					end
					player.propelghost = P_SpawnGhostMobj(player.mo) //spawns afterimages
					player.propelghost.fuse = 4 //amount of afterimages
					player.propelghost.flags2 = $|MF2_DONTDRAW // Part of preventing the first ghost from showing
					if player.propelcount == 24
					or ((player.mo.eflags & MFE_UNDERWATER) and player.propelcount == 12) then
						player.propelled = true
					end
				else
					if (player.mo.eflags & MFE_VERTICALFLIP) then
						if player.mo.momz > 1*FRACUNIT then
							player.mo.momz = $ - 1*FRACUNIT
						end
					else
						if (player.mo.momz < -1*FRACUNIT) then
							player.mo.momz = $ + 1*FRACUNIT
						end
					end
				end
			end
			
			if (player.propelcount > 0)
			and (player.mo.state == S_PLAY_FLY or player.mo.state == S_PLAY_SWIM)
			and (player.cmd.buttons & BT_USE) then
				player.mo.momz = $ - 1*FRACUNIT*P_MobjFlip(player.mo)
				if (not (player.mo.eflags & MFE_UNDERWATER))
				and not S_SoundPlaying(player.mo, 354) then
					S_StartSoundAtVolume(player.mo, 354, 100)
				end
				if player.propelghost and player.propelghost.valid then // Prevents the first ghost from showing, preventing weird visuals. Thanks to L_CloneFighter-v2.pk3 on Discord for helping with this.
					player.propelghost.flags2 = $ & ~MF2_DONTDRAW
				end
				player.propelghost = P_SpawnGhostMobj(player.mo) //spawns afterimages
				player.propelghost.fuse = 4 //amount of afterimages
				player.propelghost.flags2 = $|MF2_DONTDRAW // Part of preventing the first ghost from showing
				if player.propelcount == 20 then
					player.propelled = true
				end
			else
				S_StopSoundByID(player.mo, 354)
			end
			
		end
	end
end

addHook("ThinkFrame", propel)


//function that checks if a wall is bustable, then crumbles it, by Tatsuru
local function CheckAndCrumble(mo, sec)
  for fof in sec.ffloors()
    if not (fof.flags & FF_EXISTS) then continue end
    if not (fof.flags & FF_BUSTUP) then continue end
    
    if mo.z + mo.height < fof.bottomheight - 10*FRACUNIT - mo.momz then continue end 
    if mo.z > fof.topheight + 10*FRACUNIT - mo.momz then continue end

    EV_CrumbleChain(fof)
  end
end

//calls the function every time you launch down
addHook("PlayerThink", function(player)
  if not player.mo return end
  if (player.mo.skin != "propeller_box") and (not (player.propboxsearch and player.propboxsearch.valid)) return end
  if player.mo.state != S_PLAY_FLY and player.mo.state != S_PLAY_RIDE and player.mo.state != S_PLAY_SWIM then return end
  if not (player.cmd.buttons & BT_USE) then return end

  CheckAndCrumble(player.mo, player.mo.subsector.sector)
end)

//also required
addHook("MobjLineCollide", function(mo, line)
  if not mo.player return end
  if mo.skin != "propeller_box" and (not (mo.player.propboxsearch and mo.player.propboxsearch.valid)) return end
  if mo.state != S_PLAY_FLY and mo.state != S_PLAY_RIDE and mo.state != S_PLAY_SWIM then return end
  if not (mo.player.cmd.buttons & BT_USE) then return end

  for _, sec in ipairs({line.frontsector, line.backsector})
    CheckAndCrumble(mo, sec)
  end
end, MT_PLAYER)


		

addHook("PlayerCanDamage", function(player, mohit)
	if player.mo.skin == "propeller_box" then
		if player.mo.state == S_PLAY_FLY then
			if mohit.flags & MF_ENEMY
			or mohit.flags & MF_MONITOR
			or mohit.flags & MF_SHOOTABLE
			or mohit.flags & MF_BOSS then
				return true
			end
		end
	end
end)

//command switch for being carried
local function PBoxCarrySwitch(player, arg)
	if player.mo and player.mo.valid then
		if player.mo.skin == "propeller_box" then //Checks if you're playing as PBox
			if arg then //Arg is short for argument, aka what a player types in the console after the command
				arg = arg:lower() //lower() switches the argument to all lowercase - it's easier to manage
				if arg == "off"
				or arg == "no"
				or arg == "disable"
				or arg == "disabled"
				or arg == "0"
				or arg == "false"
					player.allowcarry = "Not Allowed" //Turns off carrying
					CONS_Printf(player, "Players can no longer carry you.") //Prints this message, only for the player who activate the command
				elseif arg == "on"
				or arg == "yes"
				or arg == "enable"
				or arg == "enabled"
				or arg == "1"
				or arg == "true" then
					player.allowcarry = "Allowed" //Turns on carrying
					CONS_Printf(player, "Players can carry you.")
				else
					CONS_Printf(player, "Invalid Input. Options are on and off.")
				end
			else
				CONS_Printf(player, "Toggles other players' ability to carry you. Current option is: " + player.allowcarry) //Printed when no argument is present
			end
		else
			CONS_Printf(player, "You're not playing as Propeller Box. Swap skins first!") //Printed for obvious reasons
		end
	else
		CONS_Printf(player, "This can only be done in a level.") //Same as above
	end
end

//Registers the command under the name specified
COM_AddCommand("pbox_carryswitch", function(player, arg)
	PBoxCarrySwitch(player, arg)
end)

//Code for picking him up
local function pickup()
	for player in players.iterate
		if player.mo.skin == "propeller_box" then
			if not player.allowcarry then
				player.allowcarry = "Allowed"
			end
		end
		
		if not (player.cmd.buttons & BT_CUSTOM3) then
			player.custom3tapready = true
			player.custom3tapping = false
		elseif player.custom3tapready then
			player.custom3tapping = true
			player.custom3tapready = false
		else
			player.custom3tapping = false
		end
		
		if not player.holdingpbox then
			player.holdingpbox = false
		end
		
		
		if not player.propelled then
			player.propelled = false
		end
		
		if leveltime == 0*TICRATE then
			player.holdingpbox = false
			player.beingcarried = false
		end
		
		if not player.propelcount then
			player.propelcount = 0
		end
			
		if P_IsObjectOnGround(player.mo)
		or (player.powers[pw_justsprung])
		or (player.powers[pw_carry] == CR_MACESPIN) then
			player.propelled = false
			player.propelcount = 0
			player.pflags = $ & ~PF_CANCARRY
		end
		
		if player.custom3tapping then
			if player.holdingpbox == false then
				local searchmo = player.mo
				searchBlockmap("objects", function(searchmo, otherplayer)
					if otherplayer and otherplayer.valid then
						if otherplayer.skin == "propeller_box" then
							if (otherplayer.player.propboxsearch and otherplayer.player.propboxsearch.valid)
							or otherplayer.player.beingcarried
							or otherplayer.player.allowcarry == "Not Allowed" then
								return
							end
							player.propboxsearch = otherplayer
						end
					end	
				end, player.mo, player.mo.x - 20, player.mo.x + 20, player.mo.y - 20, player.mo.y + 20)
					
				if player.propboxsearch and player.propboxsearch.valid then
					player.holdingpbox = true
					player.propboxsearch.player.beingcarried = true
				end
			else
				player.holdingpbox = false
				player.propboxsearch.player.beingcarried = false
				player.propboxsearch = nil
			end
		end
				
				
		if not (player.propboxsearch and player.propboxsearch.valid) then
			player.holdingpbox = false
		end
		
		
		if player.propboxsearch and player.propboxsearch.valid
		and player.holdingpbox then
			if player.propboxsearch.skin != "propeller_box" then
				player.propboxsearch.player.beingcarried = false
				player.holdingpbox = false
			end
			player.propboxsearch.player.pflags = $ & ~PF_CANCARRY
			P_MoveOrigin(player.propboxsearch, player.mo.x, player.mo.y, (player.mo.z + (player.mo.height*P_MobjFlip(player.mo))))
			player.propboxsearch.momz = 0
			//player.propboxsearch.angle = player.drawangle
			player.propboxsearch.player.drawangle = player.drawangle
			
			if player.mo.state == S_PLAY_RIDE then
				player.pflags = $|PF_CANCARRY|PF_JUMPED
				player.pflags = $ & ~PF_STARTJUMP
				player.pflags = $ & ~PF_SPINNING
			end
			
			if P_IsObjectOnGround(player.mo) then
				if player.propboxsearch.state == S_PLAY_FLY then
					player.propboxsearch.state = S_PLAY_STND
				end
				if (player.propboxsearch.player.cmd.buttons & BT_JUMP) then
					player.propboxsearch.player.beingcarried = false
					player.holdingpbox = false
				end
			end
			
			if player.propboxsearch.state == S_PLAY_ROLL
			or player.propboxsearch.state == S_PLAY_DEAD
			or player.mo.state == S_PLAY_DEAD
			or player.pflags & PF_STASIS
			or player.pflags & PF_FULLSTASIS then
				player.holdingpbox = false
			end
			
			if player.mo.state == S_PLAY_STND then
				if player.propboxsearch.state == S_PLAY_FLY then
					player.propboxsearch.state = S_PLAY_STND
				end
				if (player.propboxsearch.player.cmd.buttons & BT_JUMP) then
					player.holdingpbox = false
				end
			end
			
			if P_IsObjectOnGround(player.mo) then
				if player.c1tapping then
					if player.speed <= 5*FRACUNIT then
						player.mo.state = S_PLAY_RIDE
						player.propboxsearch.state = S_PLAY_FLY
						player.mo.momz = 15*FRACUNIT*P_MobjFlip(player.mo)
						player.propelcount = 1
						S_StartSound(player.mo, 469)
					end
				elseif player.cmd.buttons & BT_USE then
					return
				end
			end
			
			if (player.cmd.buttons & BT_JUMP) then
				if player.mo.state != S_PLAY_RIDE then
					if (not (player.mo.eflags & MFE_UNDERWATER)) then
						S_StartSound(player.mo, 195)
					end
					player.mo.state = S_PLAY_RIDE
					player.propboxsearch.state = S_PLAY_FLY
				end
				
				if player.propelled == false
				or player.propboxsearch.player.powers[pw_super] then
					player.mo.momz = $ + 1*FRACUNIT*P_MobjFlip(player.mo)
					if player.mo.momz == 0 then
						if (player.mo.eflags & MFE_VERTICALFLIP) then
							player.mo.momz = -1*FRACUNIT
						else
							player.mo.momz = 1*FRACUNIT
						end
					end
					player.propelcount = $ + 1
					if player.propelghost and player.propelghost.valid then // Prevents the first ghost from showing, preventing weird visuals. Thanks to L_CloneFighter-v2.pk3 on Discord for helping with this.
						player.propelghost.flags2 = $ & ~MF2_DONTDRAW
					end
					player.propelghost = P_SpawnGhostMobj(player.mo) //spawns afterimages
					player.propelghost.fuse = 4 //amount of afterimages
					player.propelghost.flags2 = $|MF2_DONTDRAW // Part of preventing the first ghost from showing
					if player.propelcount == 24
					or ((player.mo.eflags & MFE_UNDERWATER) and player.propelcount == 12) then
						player.propelled = true
					end
				else
					if (player.mo.eflags & MFE_VERTICALFLIP) then
						if player.mo.momz > 1*FRACUNIT then
							player.mo.momz = $ - 1*FRACUNIT
						end
					else
						if (player.mo.momz < -1*FRACUNIT) then
							player.mo.momz = $ + 1*FRACUNIT
						end
					end
				end
			end
			
			if (player.propelcount > 0)
			and player.mo.state == S_PLAY_RIDE
			and (player.cmd.buttons & BT_USE) then
				player.mo.momz = $ - 1*FRACUNIT*P_MobjFlip(player.mo)
				if (not (player.mo.eflags & MFE_UNDERWATER))
				and not S_SoundPlaying(player.mo, 354) then
					S_StartSoundAtVolume(player.mo, 354, 100)
				end
				if player.propelghost and player.propelghost.valid then // Prevents the first ghost from showing, preventing weird visuals. Thanks to L_CloneFighter-v2.pk3 on Discord for helping with this.
					player.propelghost.flags2 = $ & ~MF2_DONTDRAW
				end
				player.propelghost = P_SpawnGhostMobj(player.mo) //spawns afterimages
				player.propelghost.fuse = 4 //amount of afterimages
				player.propelghost.flags2 = $|MF2_DONTDRAW // Part of preventing the first ghost from showing
				if player.propelcount == 20 then
					player.propelled = true
				end
			else
				S_StopSoundByID(player.mo, 354)
			end
			
		end
		
		
		
		
	end
end

addHook("ThinkFrame", pickup)

			
				
				


addHook("JumpSpecial", function(player) 
	if player.mo.skin == "propeller_box" then
		if (player.powers[pw_carry] == CR_ROLLOUT)
		or (player.powers[pw_carry] == CR_PLAYER)
		or (player.powers[pw_carry] == CR_BRAKGOOP)
		or (player.powers[pw_carry] == CR_ZOOMTUBE)
		or (player.powers[pw_carry] == CR_ROPEHANG)
		or (player.powers[pw_carry] == CR_MACESPIN)
		or (player.powers[pw_carry] == CR_MINECART)
		or (player.powers[pw_carry] == CR_PTERABYTE)
		or (player.powers[pw_carry] == CR_DUSTDEVIL)
		or (player.powers[pw_carry] == CR_GENERIC)
		or (player.powers[pw_carry] == CR_NIGHTSMODE)
		or player.mo.state == S_PLAY_ROLL 
		or player.mo.state == S_PLAY_RIDE
		or player.mo.state == S_PLAY_SPRING then
			return false
		else
			return true
		end
	else
		if player.holdingpbox then
			return true
		end
	end
end)



local function customtunes()
	for player in players.iterate
		if player.mo.skin == "propeller_box" then
			//if player.isxmomentum then //prevents these during xmomentum since it has its own supermusic that would cause lag if this tried to run too
			//	return
			//end
			
			if player.powers[pw_invulnerability] == 20*TICRATE
			and not player.powers[pw_super] then
				COM_BufInsertText(player, "tunes _minv")
			end
			
			if not player.powers[pw_invulnerability] then
				if S_MusicName() == "_minv" then
					COM_BufInsertText(player, "tunes -default")
				end
			end
		end
	end
end

addHook("ThinkFrame", customtunes)			

			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			