--=============================HMS FUNCTIONS=========================================
--This lump houses functions for HMS-exclusive stuff. HMS-exclusive GFX are in LUA_GFX2.
--If a function is meant for both SMS and HMS, then it'll probably be in LUA_FUNCTIONS.
--===================================================================================

//Because people will make that joke
function A_TOGOEVENFURTHERBEYOND(s)
	if not (s.valid and s.skin == "sms" and s.player) return end --
	local p = s.player

	--CANCEL CONDITIONS!
	if p.hypermysticsonic or p.sms_intoship return end --
	
	if p.hmstransformdisable == 2 --HMS doesn't use Chaos Emeralds for the transformation normally.
	or CBW_Chaos and (gametype == GT_CHAOS)
		if not All7Emeralds(emeralds)
			if CBW_Chaos and (gametype == GT_CHAOS)
				CONS_Printf(p, "Chaos Mode needs the 7 Chaos Emeralds to transform into HMS!") return --
			elseif not SMS_NerfedMode(p)
				CONS_Printf(p, "You currently need the 7 Chaos Emeralds to transform into HMS.") return --
			end
		end
	end
	if p.hmstransformdisable == 1 and not SMS_NerfedMode(p) --Can't disable HMS in match/CTF.
	or p.smsnoracegame == 2 and (gametype == GT_RACE) --Can't go HMS in race with the "all-super" setting!
		CONS_Printf(p, "HMS is currently disabled.") return --
	end
	if p.hmshascome and SMS_NerfedMode(p) --1 HMS per match.
		CONS_Printf(p, "\x89"+"Can't transform under all this pressure!") return --
	end
	if (p.speedbombactive or p.g2gfast4lifeactive or p.hmsrushactive or p.skillstripcv) and (gametype == GT_COOP) 
		CONS_Printf(p, "You cannot transform in these gamemodes!") return --SMSchallenges modes.
	end
		
	--Hyper Mystic Sonic is INCREDIBLY game intensive and chaotic.
	--It helps to let servers control how many HMS' can be present, for lag or sanity reasons.
	if netgame
		local AUTO = false
		local ztotal = 0
		local zmaxplayers = 0						
		for z in players.iterate
			zmaxplayers = $+1
			if z.hypermysticsonic
				ztotal = $+1
			end
			if z.smsautographix
				AUTO = true
			end
		end
		if p.hmsmlimit != nil and (ztotal >= p.hmsmlimit)
			CONS_Printf(p, "\x85"+"Server limit for Hyper Mystic Sonic players already reached!\x80 ("+p.hmsmlimit+")")	
			return --
		end	
		--If HMS appears, the tolerance for high graphics goes down.
		if AUTO and zmaxplayers
			if (zmaxplayers < 7) --Small netgame with 6 or less people, full steam ahead!
				for z in players.iterate
					if z.smsgraphix != 0
						CONS_Printf(z, "SMS graphics auto-adjusted to\x83 full")	
						z.smsgraphix = 0
					end
				end
		 	elseif (zmaxplayers < 9) --Medium netgame, slow it down a notch...
				for z in players.iterate
					if z.smsgraphix != 1
						CONS_Printf(z, "SMS graphics auto-adjusted to\x84 medium")	
						z.smsgraphix = 1
					end
				end
		 	else --Busy netgame, minimum graphics!
				for z in players.iterate 
					if z.smsgraphix != 2
						CONS_Printf(z, "SMS graphics auto-adjusted to\x85 minimum")	
						z.smsgraphix = 2
					end
				end
			end
		end
	end
	s.SMS_AllowFlickies = nil
	s.SMS_MineCarting = nil
	s.forceHMSyellanim = nil --From player warp.
	s.HayMakerPunch = nil
	s.SMS_DLtrail = nil
	p.wasHMS = true --We've been HMS, remember that for later.
	s.SMS_locked = true
	p.smsmeleebutton = 850
	p.smsdivefloat = 0
	p.smsatomicdivefail = 0
	p.homing = 0
	
	p.sms_attracttl = nil
	p.sms_sontransform = 0
	p.sms_hugeflametoss = 0
	p.footsweep01 = 0
	p.footsweep02 = 0
	p.footsweep03 = 0
	p.footsweepanim = false
	p.hometrickanim = false
	p.smsboostpanim = false
	s.hmsroflstomped = false
	s.hmsspinpass = 0
	s.sdodgecd = 0
	s.sdodgelvl = 0
	s.SMS_BDboostloss = nil
	s.hmgodmticket = nil
	
--	s.flags = $ & ~MF_SHOOTABLE
	s.flags2 = $|MF2_FRET
	p.charability = CA_NONE
	p.charflags = $|SF_RUNONWATER & ~SF_NOSKID
	p.pflags = $ & ~(PF_STARTDASH|PF_SPINNING|PF_THOKKED|PF_STARTJUMP|PF_SLIDING|PF_FULLSTASIS)
	s.prehmscolor = s.color
	s.prehmspcolor = p.skincolor
	p.hypermysticsonic = 1
	
	s.hmgodticket = false
	p.powers[pw_nocontrol] = 16
	s.boostpass = false
	
	--Reset some special values...
	p.novafire = 35
	p.hmsblackhole = 35
	s.hms_jumprisen = 0
	s.HMS_warpselectcooldown = nil
	s.hmsspinpass = nil
	s.hmsusebuffer = 0
	s.hmsgalaxystorm = 35
	s.hmspowerbombcam = 0
	p.hms_gravburstcd = 35
	p.hms_explosion = 0
	p.hms_instamove = 0
	p.hms_instamovew = 0
	p.hmswarpcooldown = 35	
	p.hmsdash = 0
	
	s.SMS_squashtable,s.spriteyoffset,s.spritexscale,s.spriteyscale = nil,0,FRACUNIT,FRACUNIT
	s.spritexoffset = 0
	s.rollangle = 0		
	
	s.state = S_HMSTRANSFORM1
	s.momx,s.momy,s.momz = 0,0,0
	p.sms_wallstat = 0
	s.hmsshieldconsume = 0
	s.HMSlr = max(5, p.rings)
	
	A_SMSquake(s, 10<<16, 22, 8022) --A bigger quake comes later in the animation.
	P_NukeEnemies(s, s, 750*s.scale)
	
	if SMS_Graphix(s) != 2
		SMS_Embers(s, s, 0)
		HMS_AuraStorm(s, nil, SKINCOLOR_BONE, nil, G|FF_TRANS50)
		local ghs = HMS_GigaJetBolt(s, FRACUNIT/2, 24)
		ghs.tracer = s
		ghs.dispoffset = -5
	else
		local ghs = P_SpawnMobjFromMobj(s, 
		FixedMul(-2*s.scale, cos(s.angle)), 
		FixedMul(-2*s.scale, sin(s.angle)),
		0, MT_HMSLIPILLAR)
		ghs.scalespeed = 17500
		ghs.fuse = 38
		ghs.target = s
		ghs.color = SKINCOLOR_BONE
	end
	SMS_WallJumpDelete(s, true)

	S_StartSound(nil, sfx_hypemt)
	P_RestoreMusic(p)
	
	if not p.nohmstheme
		if p == consoleplayer
			COM_BufInsertText(p, "tunes HMS") --Otherwise it'll go back to the main stage theme after 1-up sounds...
		end
	/*	if s.hmsmpos
			S_ChangeMusic("HMS", true, p, 0, s.hmsmpos, 150, 150)
		elseif not s.hmsmpos
			s.hmsmpos = 1
		end */
	end
	//P_RestoreMusic(p)
	
	--Darken the heavens, everybody is screwed now....!
	if SMS_NerfedMode(p) and not modeattacking
		P_StartQuake(35<<16, 45)
		if mapheaderinfo[gamemap] and mapheaderinfo[gamemap].skynum
			p.hfear = mapheaderinfo[gamemap].skynum --Remember the sky number to reload later.
			if mapheaderinfo[gamemap].skynum != (21 or 22) --Outter space can just remain outter space.
				P_SetupLevelSky(11)
			end
		else
			p.hfear = 1
		end
		for z in players.iterate
			z.hmshascome = p
			if z.mo and (z.mo != s) --Warn everyone
				z.mo.hmsfearmessage = 64
			end
			P_FlashPal(z, PAL_NUKE, 12)
		end
		for sector in sectors.iterate --Darken the world.
			sector.lightlevel = max(($-31), 0)
		end
	end	
	return true --Success!
end

--We were HMS, but no longer are? Reset stats!
rawset(_G, "HMS_UntransformedStats", function(s, p, FORGETSTUFF) 
	if s.prehmscolor --Reset colors!
		s.color = s.prehmscolor
		p.skincolor = s.prehmspcolor
	end
	
	--Don't need to remember this stuff.
	s.prehmscolor = nil
	s.prehmspcolor = nil
	s.hmslivesc = nil
	s.HMSlr = nil
	s.tniy6 = nil
	s.tniy5 = nil
	s.tniy4 = nil
	s.tniy3 = nil
	s.tniy2 = nil
	s.tniy = nil
	s.HMS_7flame = nil
	s.HMS_SkipHBnext = nil
	s.HMS_FireCoords = nil	
	s.HMS_FireCoords2 = nil	
	s.HMS_FireCoords3 = nil
	s.HMS_warpselectcooldown = nil	
	s.HMS_lastNB = nil
	s.wvspwncd = nil
	s.haltthespam = nil
	s.hmgodmticket = nil
	s.hmsdashDOWN = nil
	s.HMS_airboostspeedtimer = nil
	
	if FORGETSTUFF == true return true end --
		
	if s.starthmscombo
		s.starthmscombo = nil
		s.flags = $ & ~(MF_NOCLIPTHING|MF_BOUNCE)
	end
	if s.hmscarryset
		s.hmscarryset = false
		p.pflags = $ & ~PF_CANCARRY
	end
	p.pflags = $ & ~PF_GODMODE
	s.flags = $|MF_SHOOTABLE
	s.flags2 = $ & ~MF2_FRET
	if (p.powers[pw_flashing] == -1) or (p.powers[pw_flashing] > 30000)
		p.powers[pw_flashing] = 0
	end
	s.hmsgodmode = nil
	if s.hmsforcedspin or s.hmsspinang
		s.hmsforcedspin = nil
		s.hmsspinang = 0
		s.rollangle = 0
	end
	if p.hypermystictaxi
		p.hypermystictaxi = false
	end		
	p.sms_sontransform = 0
	p.powers[pw_ignorelatch] = 0
	p.wasHMS = nil
	p.hypermysticsonic = 0
	if p.accelstart == 140
		p.accelstart = skins[s.skin].accelstart
	end
	if not p.nohmstheme
		COM_BufInsertText(p, "tunes -default")
		P_RestoreMusic(p)
	end
	
	if (s.skin == "sms")
		if leveltime
			HMS_UntransformGFX(s)
		end
		if (p.maxdash != skins[s.skin].maxdash) and not p.gotflag
			p.maxdash = skins[s.skin].maxdash
		end
		if p.powers[pw_sneakers] or SMSSHIELD(p, SH_WHIRLWIND)
			p.jumpfactor = 87250
		else
			p.jumpfactor = skins[s.skin].jumpfactor
		end
	else
		if (p.maxdash != skins[s.skin].maxdash)
			p.maxdash = skins[s.skin].maxdash
		end
		p.jumpfactor = skins[s.skin].jumpfactor
	end
	return true --
end)

//Var1 determines if you lose rings or not when untransforming! Var2 is momentum
function A_TOGOBACKTOTHEWAYYOUWERE(s, var1, var2)
	if not s.player return end --	
	local p = s.player
	local RESTOREDMUSIC = false
	--End Hyper Mystic Panic?
	if p.hfear
		if SMS_NerfedMode(p) and leveltime
			for sector in sectors.iterate
				sector.lightlevel = ($+31)
			end
			S_StartSound(nil, sfx_s3k66)
			P_SetupLevelSky(p.hfear)
	 	end
		for z in players.iterate
			z.hmshascome = nil
			p.hfear = nil
			P_FlashPal(z, PAL_MIXUP, 3)	
			if not z.nohmstheme
				COM_BufInsertText(z, "tunes -default")
				P_RestoreMusic(z)
				RESTOREDMUSIC = true
			end
		end
	end
	--Remove HMS theme.
	if not p.nohmstheme and p.hypermysticsonic 
	and not RESTOREDMUSIC
		COM_BufInsertText(p, "tunes -default")
		P_RestoreMusic(p)
	end
	
	s.rollangle = 0
	
	--No effects if you just switched level.
	if leveltime
		P_FlashPal(p, PAL_MIXUP, 7)
		S_StartSound(s, sfx_s3k66)
		P_RadiusAttack(s, s, 250*s.scale)
		if SMS_Graphix(s) != 2
			for d = 0,15
				P_SpawnParaloop(s.x, s.y, s.z+FixedMul(20<<16, s.scale), 10<<16, 16, MT_NIGHTSPARKLE, d*ANGLE_22h, S_SMSTSPARK1, false)
			end
		end				
	end
	
	--End manual transformation sequence?
	if p.sms_transformstate
		if leveltime
			local ghs = P_SpawnGhostMobj(s)
			ghs.destscale = $*99
			ghs.fuse = 20 ghs.tics = 22
			ghs.blendmode = AST_ADD
			ghs.colorized = true
		end	
		if p.presmsskin
			R_SetPlayerSkin(p, p.presmsskin)
			s.skin = p.presmsskin
			COM_BufInsertText(p, "skin "+p.presmsskin)
		else
			R_SetPlayerSkin(p, "sonic")
			s.skin = "sonic"
			COM_BufInsertText(p, "skin sonic")
		end
		
		p.sms_transformstate = 0	
		p.ffdelaycs = 3
		
		if not (p.powers[pw_shield] & SH_FIREFLOWER)
		and not ((mariomode) and p.powers[pw_invulnerability])
			s.color = p.sms_originalcolor
		else
			s.color = SKINCOLOR_WHITE
		end				
		p.skincolor = p.sms_originalcolor
		
	elseif not var1 and leveltime
		P_GivePlayerRings(p, -20)
	end			
	if SMS_NerfedMode(p)
		p.rings = 0
		p.hms_drain = 1
	end
	
	HMS_UntransformedStats(s, p) --Remove all stats associated with HMS.
	p.hypermysticsonic = 0			
	p.pflags = $ & ~PF_GODMODE	
	
	//Continue the atomdive!
	if not p.smsdivetimer
		if (p.pflags & PF_STARTDASH)
			p.pflags = $ & ~PF_STARTDASH & ~PF_SPINNING
			p.dashspeed = 0
		end
		if var2
			s.momx = $/4
			s.momy = $/4
			s.momz = $/3
		else
   			P_InstaThrust(s, s.angle, 0)
		end
		if not var1
			p.powers[pw_nocontrol] = $+16
		end
		if not (p.powers[pw_carry] == CR_NIGHTSMODE)
			s.state = S_PLAY_FALL
			p.pflags = $ & ~PF_JUMPED
		end
	else
		s.dcadsms = true
		p.smsdivetimer = 37
		s.state = S_PLAY_ROLL
		p.panim = PA_ROLL
	end			
end

--VAR1 = Optional Custom Object. MT_SPINFIRE by default.
function A_HMSfiretrail(s, var1) //Var1 = Optional Custom Object
	if (s.eflags & MFE_TOUCHWATER) or SMS_Graphix(s) == 2
	or not s.health	
		return --Cancel!
	end
	--Get setup out of the way.
	var1 = (var1) and $ or MT_SPINFIRE
	
	local ang = R_PointToAngle2(s.x, s.y, s.x+s.momx, s.y+s.momy)
	local SPEED = abs(s.momx)+abs(s.momy)
	local dist = SMSLocalRNG(13,24,s)*s.scale
	local ths, ZCORRECT
	if not P_IsObjectOnGround(s)
		if (s.eflags & MFE_VERTICALFLIP)
			ZCORRECT = s.ceilingz
		else
			ZCORRECT = s.floorz
		end	
	end
	
	for d = -1,1,2 --skip 0.
		local ghs = P_SpawnMobjFromMobj(s, 
		FixedMul(dist, cos(ang+(ANGLE_90*d))), 
		FixedMul(dist, sin(ang+(ANGLE_90*d))), 
		0,
		var1)
				
		if ghs and ghs.valid
			ghs.target = s
			ghs.angle = s.angle+(ANG2*2*d)
			
			if SPEED > 40*s.scale
				ghs.momx = s.momx/2
				ghs.momy = s.momy/2
				P_Thrust(ghs, ang, SPEED/SMSLocalRNG(32, 128,s))
			end
			if ZCORRECT
				ghs.z = ZCORRECT
			end			

			if (ghs.type == MT_SPINFIRE)
				ghs.state = S_HMSFPILLAR1
				ghs.tics = SMSLocalRNG(1,4, ghs)
				ghs.scale = (s.scale*10)/SMSLocalRNG(10, 12,ghs)
				if not s.momx
					s.momx = 8
				end
				ghs.health = 1
				ghs.flags = MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_FIRE & ~MF_NOCLIPHEIGHT
				--Do we still exist after becoming a missile? Then stop entirely IF....
				if ghs.valid and (abs(ghs.z-s.z) > 88*s.scale)
					ghs.state = S_NULL return nil
				end				
			end
		end
		if d != 1 --Return first flame as "ths"
			ths = ghs
		end
	end
	return ths,ghs --Return both flames.
end

--HMSstomp is the HMS stomp, for stomping as HMS.
rawset(_G, "HMS_stomp", function(s, p)
	if (p.cmd.buttons & BT_CUSTOM2)
	
		if (p.pflags & PF_JUMPED)
	
			if not (p.cmd.buttons & BT_CUSTOM1 and (p.cmd.forwardmove < -20) and (p.smsmeleebutton < 17) and not (abs(p.cmd.sidemove) > 6) )
			and not SMS_Locked(s, p)
			and not (p.pflags & PF_SLIDING)
			and not (p.cmd.buttons & (BT_WEAPONPREV|BT_JUMP|BT_TOSSFLAG))
			and not P_IsObjectOnGround(s)
			
				if not s.hmsspinfreeze
				and not (p.cmd.buttons & BT_TOSSFLAG)
					s.rollangle = ANGLE_180
					s.hmsroflstomped = true
				end
				if (s.momz*P_MobjFlip(s) > -29*s.scale) --Minimum stomp speed.
					P_SetObjectMomZ(s, -29<<16)
				end
				
				local ghs 				
				if not s.hmsstompsfx
					if SMS_Graphix(s) == 0
						HMS_StompGFX(s, p)
						if not s.haltthespam
							ghs = P_SpawnMobjFromMobj(s, 0, 0, s.height, MT_HMSNOVAWAVE) 
							ghs.scale = (s.scale*10)/SMSLocalRNG(9,15,s)
							A_SMSSTOMPSMOKE(s, SMSLocalRNG(30,10,s), MT_DUST)
							A_SMSSTOMPSMOKE(s, 20, MT_ENERGYBALL, 200)
						end
						ghs = SMS_LightFlash(s, SKINCOLOR_SMS5R, FRACUNIT-26000, nil, Z+3|FF_TRANS30)
						ghs.tracer = s
						ghs.sttfade = 14
						ghs.fuse = 7
						ghs.scalespeed = FRACUNIT-18000	
						
						ghs = SMS_ElectricBody(s, 5, SKINCOLOR_RED)
						ghs.spriteyscale = FRACUNIT+42000
						ghs.spritexscale = FRACUNIT+45000								
					end
					
					s.hmsstompsfx = true
					P_SetObjectMomZ(s, -12<<16, true)
					S_StartSound(s, sfx_stst)
					s.haltthespam = 5
					
					if (s.momz*P_MobjFlip(s) < 0) --Quake depends on vertical speed.

						A_SMSquake(s,
						max( 10<<16, min(180<<16, abs(s.momz/2)) ),
						max( min( 12 , abs(s.momz)/(FRACUNIT/12) ), 2)
						)
						
						if not (s.SMS_squashtable and s.SMS_squashtable.timer > 2)
							s.spritexscale = FRACUNIT-15100
							s.spriteyscale = FRACUNIT+19100
							s.spriteyoffset = -5<<16
							s.SMS_squashtable = {timer = 3, Xspeed = 6500, Yspeed = 7500, air = true}
						end							
					
						if not s.SMS_DLtrail and not SMS_Graphix(s)					
							s.SMS_lastz = s.z-s.momz+(s.height*2)
							s.SMS_DLtrail = {timer = 3, color = SKINCOLOR_SKY, colorized = true,
							momx = s.momx, momy = s.momy, fuse = 5, spritexscale = FRACUNIT*2}
							SMS_ContinuousTrail(s, s.SMS_DLtrail)
							s.SMS_lastz = s.z
						end							
					end
				end
				if not (s.eflags & MFE_GOOWATER)
				and SMS_Graphix(s) != 2
					if (leveltime % 3 == 0)
						if (leveltime % 3 == 0)
							P_NukeEnemies(s, s, 400*s.scale)
						else
							A_SMSSTOMPSMOKE(s, SMSLocalRNG(12,20,s), MT_WATERZAP)
						end			
					elseif (leveltime % 2 == 0)
						A_SMSSTOMPSMOKE(s, SMSLocalRNG(12,40,s), MT_BOSSEXPLODE)
						if leveltime % 14 == 0
							HMS_StompGFX(s, p)
						end			
					end
				end
				
				if (leveltime % 2 == 0)
					ghs = SMS_FootSweepSlash(s, FF_TRANS10, leveltime*(ANG1*33))
					if ghs and ghs.valid
						ghs.momz = $+(s.momz/3)
						ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
					end
					
					local ghs = P_SpawnMobjFromMobj(s, s.momx, s.momy, 0, MT_HMSSTOMPAURA)
					ghs.scale = (s.scale*20)/SMSLocalRNG(4,8,s)
					if (ghs.scale <= (s.scale*20)/7)
						ghs.z = $-14*s.scale*P_MobjFlip(s)
					elseif (ghs.scale >= (s.scale*20)/5)
						ghs.z = $+9*s.scale*P_MobjFlip(s)
					end
					if (s.eflags & MFE_VERTICALFLIP)
						ghs.z = $-(20*s.scale)
					end
					ghs.target = s
					ghs.color = SMSLocalRNG(SKINCOLOR_SUPERORANGE1, SKINCOLOR_SUPERORANGE5,s)
					ghs.frame = SMSLocalRNG(5, 7,ghs)|FF_TRANS30
					
					--A ghost of a ghost!
					ghs.ghostaura = P_SpawnGhostMobj(ghs)
					ghs.ghostaura.scalespeed = $/2
					ghs.ghostaura.destscale = ghs.ghostaura.scalespeed+1
					ghs.ghostaura.momx = s.momx/2
					ghs.ghostaura.momy = s.momy/2
					ghs.ghostaura.tics = 5
					ghs.ghostaura.blendmode = AST_ADD
					ghs.ghostaura.momz = $+10*s.scale*P_MobjFlip(s)
								
				else
					local ghs = P_SpawnMobjFromMobj(s, s.momx, s.momy, 0, MT_HMSSTOMPAURA)
					ghs.scale = (s.scale*20)/SMSLocalRNG(4,9,s)
					ghs.renderflags = $|RF_FULLBRIGHT|RF_NOCOLORMAPS
					ghs.blendmode = AST_ADD
					if (s.eflags & MFE_VERTICALFLIP)
						ghs.z = $-(20*s.scale)
					end
					ghs.target = s
					ghs.color = SMSLocalRNG(SKINCOLOR_SUPERRED1, SKINCOLOR_SUPERGOLD5,ghs)
					ghs.frame = T|FF_TRANS40
				end
				if (not s.bhlcamtimer or s.bhlcamtimer == 1) --Zoom out camera a bit for better visibility.
					p.camerascale =  FRACUNIT*3/2
					s.bhlcamtimer = 2
				end
				local ghs = SMSRSpawnGhost(s)
				if not s.hmsspinfreeze and not (p.cmd.buttons & BT_TOSSFLAG)
					s.hmsspinpass = 8
				end
				if s.hmsspinpass and s.hmsspinang != nil and ghs
					ghs.angle = s.hmsspinang
				end
				p.hms_stompbreak = $+1
				s.SMS_stompmom = (p.hms_stompbreak > 2) and s.momz or 0
			else
				p.hms_stompbreak = 0
			end
		end
		
		--LANDING!
		if (s.eflags & MFE_JUSTHITFLOOR)
			if ( (p.hms_stompbreak > 2) or (p.speed > 137*s.scale))
			and not A_HMSCheckDeathPit(s)
				SMS_stompimpact(s, p, 3)
			end
			return true --
		end

	   //Little feature that lets HMS float like Super Sonic. Not that useful, but hey, why not?

		if (p.cmd.buttons & BT_TOSSFLAG)
		or ((p.cmd.buttons & BT_JUMP) and s.hms_jumprisen)
	   		if (p.pflags & PF_JUMPED)
	  		and not P_IsObjectOnGround(s)
	   			if s.hmsspinpass or s.hmsroflstomped
					s.hmsroflstomped = false
					s.hmsstompsfx = false
					s.rollangle = 0
					s.hmsspinpass = 0
				end
				s.hms_jumphold = 10
				s.hms_readyriseboost = 0
	   			s.hms_jumprisen = 2
	   			s.hmgodticket = true
				s.momz = 0
			end
		end
	else
		if (leveltime % 14 == 0)
			if s.rollangle == ANGLE_180
			and (s.momz*P_MobjFlip(s) < -30*s.scale)
			and not(p.cmd.buttons & BT_TOSSFLAG)
				s.hmsstompsfx = true
				HMS_StompGFX(s, p)
			end
		end
		if s.hmsstompsfx
			s.hmsstompsfx = false
		end		
	end 
end)

--Warp Dash
rawset(_G, "HMS_Warp", function(s, p)
	if s.forcewarp1
		if (s.forcewarp1 == 1)
			s.state = S_HMS_INSTANTWARP2
			p.pflags = $|PF_USEDOWN
		else
			s.state = S_HMS_INSTANTWARP1
		end
		p.pflags = $ & ~PF_SPINNING
		s.forcewarp1 = $-1
	end
	if s.forcewarp2
		if (s.forcewarp2 == 1)
			s.state = S_HMS_INSTANTWARP3
			p.pflags = $|PF_USEDOWN
		else
			s.state = S_HMS_INSTANTWARP2
		end
		p.pflags = $ & ~PF_SPINNING
		s.forcewarp2 = $-1
	end
	if s.state == S_HMS_INSTANTWARP2
		if (p.pflags  & PF_SPINNING)
			s.forcewarp2 = 2
			p.pflags = $ & ~PF_SPINNING
		end
		p.pflags = $|PF_JUMPED|PF_USEDOWN
		
	--	A_FindTarget (s, MT_HMSWARPPOINT, 0)
		if (s.target and s.target.type == MT_HMSWARPPOINT) and not s.target.dontwarptome
			local secheck = R_PointInSubsector(s.target.x, s.target.y).sector
			for fof in secheck.ffloors()
				if (fof.flags & FF_EXISTS) and ((fof.flags & FF_STRONGBUST) or (fof.flags & FF_BUSTUP))
				and not (s.target.z-99<<16 >= fof.topheight)
				and not (s.target.z+99<<16 < fof.bottomheight)
					EV_CrumbleChain(secheck, fof)
				end
			end			
			
			if P_CheckPosition(s, s.target.x, s.target.y, s.target.z)
			and not (secheck.ceilingheight-secheck.floorheight < (P_GetPlayerSpinHeight(p)))
			and not s.target.dontwarptome
			
				S_StartSound(s, sfx_s3k83)
                P_NukeEnemies(s, s, 850*s.scale)
				
				local QuickDetour = s.target
				A_FindTarget(s, MT_HMSWARPPOINTRETURN, 0)
				if (s.target and s.target.type == MT_HMSWARPPOINTRETURN)
					local ghs = HMS_BigBangVortex(s, 33, FRACUNIT/2, ANG1*69, E|FF_TRANS10, SKINCOLOR_ZEEJIN5)
					ghs.dispoffset = -2
					ghs.blendmode = AST_TRANSLUCENT
					P_MoveOrigin(ghs, s.target.x, s.target.y, s.target.z)
					
					local ths = HMS_GigaJetBolt(ghs, FRACUNIT, 35)
					ths.colorized = true
					ths.color = SKINCOLOR_DUSK
					ths.dispoffset = 1
					
					ths = P_SpawnMobjFromMobj(ghs, 0,0,0, MT_HMSNOVAWAVE)
					ths = P_SpawnMobjFromMobj(ghs, 0,0,0, MT_HMSNOVAWAVE)
					ths.rollangle = ANGLE_90
					ths.dispoffset = 6
					ths = P_SpawnMobjFromMobj(ghs, 0,0,0, MT_HMSNOVAWAVE)
					ths.rollerwave = 16<<16
					ths.dispoffset = 11

					ths = P_SpawnGhostMobj(s)
					ths.tics = 29
					ths.dispoffset = 3
					ths.colorized = true
					ths.color = SKINCOLOR_SMSROVERGLOW
					ths.scalespeed = $*3
					ths.destscale = $*20
					P_MoveOrigin(ths, s.target.x, s.target.y, s.target.z)
				end	
				s.target = QuickDetour
				
				if (s.subsector.sector == s.target.subsector.sector)
				and s.subsector.sector.floorpic == s.target.subsector.sector.floorpic //Same sector...be careful.
				and not s.target.ihavetped
					s.z = s.target.z
					P_TryMove(s, s.target.x, s.target.y, true) //Fake warp! (to prevent us clipping through walls)
				else
					P_MoveOrigin(s, s.target.x, s.target.y, s.target.z) //True Warp!
				end
				s.momx,s.momy,s.momz = 0,0,0
				P_FlashPal(p, 1, 2) //Brings up a bright white flash.
				local ghs = P_SpawnGhostMobj(s)
				ghs.tics = 20
				ghs.color = SKINCOLOR_RED
				ghs.colorized = true
				ghs.scalespeed = $*3
				ghs.destscale = $*20
			else
				P_KillMobj(s.target)
			end
			if s.tics == 2
				local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSNOVAWAVE)
				ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSNOVAWAVE)
				ghs.rollangle = ANGLE_90
				ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSNOVAWAVE)
				ghs.rollerwave = 16<<16
				
				S_StartSound(s, sfx_s3k83)
                P_NukeEnemies(s, s, 850*s.scale)
				
				local ghs = HMS_GigaJetBolt(s, nil, 14)
				ghs.tracer = s
				ghs.dispoffset = 1
				ghs.tracer = s
				ghs.frame = $+FRACUNIT
				ghs.colorized = true
				ghs.color = SKINCOLOR_ORANGE
				ghs.GSoffsetX = -9*s.scale
				ghs.GSoffsetY = -9*s.scale
				ghs.GSoffsetZ = 0
			
				ghs = SMS_LightFlash(s, SKINCOLOR_COBALT)
				ghs.tracer = s
				ghs.frame = $+FRACUNIT*3
				ghs.fuse = 14
				ghs.GSoffsetX = -16*s.scale
				ghs.GSoffsetY = -16*s.scale
				ghs.GSoffsetZ = -4*s.scale	
				
				ghs = SMS_ElectricBody(s,10)
				ghs.blendmode = AST_SUBTRACT
				ghs.mirrored = true

			end
		end
		SMS_StompGFX(s, p, true, true)
		
	elseif (s.state == S_HMS_INSTANTWARP3 or (p.hmswarpcooldown == 2 or p.hmswarpcooldown == 1))
	and not p.smsdivetimer
	
		if not P_IsObjectOnGround(s)
			s.momz = 0
		else
			p.pflags = $|PF_JUMPDOWN|PF_USEDOWN
		end
		
		s.momx = 0 s.momy = 0
		s.hmsgcheck = true
	
		local secheck = R_PointInSubsector(s.x, s.y).sector
		if (secheck.ceilingheight-secheck.floorheight < (P_GetPlayerSpinHeight(p)))
		or (p.pflags & PF_SPINNING)
		or not secheck
			A_FindTarget(s, MT_HMSWARPPOINTRETURN, 0)
			if (s.target and s.target.type == MT_HMSWARPPOINTRETURN)
				P_MoveOrigin(s, s.target.x, s.target.y, s.target.z) //Warp back!
				p.pflags = $ & ~PF_SPINNING
			end
		end
		if p.hmswarpcooldown == 2
			local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSNOVAWAVE)
			ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSNOVAWAVE)
			ghs.rollangle = ANGLE_90
			ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSNOVAWAVE)
			ghs.scale = s.scale
			ghs.rollerwave = -16<<16
		end
	end
end)

--Is our target a properly existing destination?
rawset(_G, "HMS_InstantMoveCheck", function(s, p)
	if p.warpedtoguy == nil or (p.warpedtoguy > 31)
		p.warpedtoguy = 0
	elseif (p.warpedtoguy < 0)
		p.warpedtoguy = 31
	end
	local tp = players[p.warpedtoguy]
	if tp and tp.valid 
	and tp.mo
	and tp.mo != s 
	and tp.mo.health
		return true --
	else
		return false --
	end
end)

--Instant Transmis--Instant Movement! Appear in front of anyone in multiplayer instantly!
rawset(_G, "HMS_InstantMovement", function(s, p)
	--Concentrating, finding target!
	if (s.state == S_HMS_INSTANTMOVE1) --Concentrating!
		s.momx,s.momy,s.momz = 0,0,0
		p.normalspeed = 0
		p.pflags = $ & ~PF_JUMPED & ~PF_SPINNING

		if not (p.cmd.buttons & BT_WEAPONNEXT)	
		
			for i = 1,33
				if HMS_InstantMoveCheck(s, p)
					s.state = S_HMS_INSTANTMOVE2 break
				end
				p.warpedtoguy = $+1
				if i >= 33
					s.state = S_PLAY_FALL
				end
			end
			
		elseif not s.HMS_warpselectcooldown

			local cancel = false
			
			if (p.cmd.buttons & BT_SPIN) --Cancel
			and (p.spinhold < 2)
			
				cancel = true
				
			--Selecting process
			elseif ((p.cmd.buttons & BT_CAMRIGHT) or (p.cmd.sidemove > 15))
			or (p.cmd.buttons & BT_CAMLEFT) or (p.cmd.sidemove < -15)
				local leftright = ((p.cmd.buttons & BT_CAMRIGHT) or (p.cmd.sidemove > 15)) and 1 or -1
				for i = 1,33
					if p.warpedtoguy == nil
						p.warpedtoguy = 0
					elseif p.warpedtoguy == 0 and leftright == -1
						p.warpedtoguy = 31
					else
						p.warpedtoguy = $+leftright
					end
					if HMS_InstantMoveCheck(s, p) --Success!
						S_StartSound(s, sfx_rail2)
						s.HMS_warpselectcooldown = 8
						break
					elseif (i >= 33)
						cancel = true
					end
				end						
			end
			
			if cancel
				S_StartSound(s, sfx_ngskid) --fail!
				p.hms_instamove = 50
				s.state = S_PLAY_FALL
			else
				if HMS_InstantMoveCheck(s, p) --Aim at target!				
					local tg = players[p.warpedtoguy].mo
					p.getpersonname = tg.player.name
					s.angle = R_PointToAngle2(s.x, s.y, tg.x, tg.y)
				else
					p.getpersonname = "-"
				end						
			end
		end

	elseif (s.state == S_HMS_INSTANTMOVE2) --The warping state.
	and not p.powers[pw_carry]
		
		if HMS_InstantMoveCheck(s, p)
		and not p.hms_instamove
			
			local tg = players[p.warpedtoguy]
			s.momz = 0
			
			if SMS_NerfedMode(p) or s.battlemodsms
				if not (G_GametypeHasTeams() and (p.ctfteam == tg.mo.player.ctfteam))
				
					if not p.hms_instamovew
						if tg.powers[pw_sneakers] or (tg.mo.skin == "sms")
							p.hms_instamovew = 40 //Get other SMS players quicker.
							tg.mo.eyesareuponyou = 40
						else
							p.hms_instamovew = 66
							tg.mo.eyesareuponyou = 65
						end
						s.momx,s.momy,s.momz = 0,0,0
						p.powers[pw_nocontrol] = p.hms_instamovew
						s.EvilGlare = tg.mo
							
						P_StartQuake(10<<16, 75)
						P_NukeEnemies(s, s, 750<<16)
						P_FlashPal(tg.mo.player, PAL_NUKE, 8)
						P_FlashPal(p, PAL_NUKE, 8)
						S_StartSound(tg.mo, sfx_bgxpld)
						S_StartSound(tg.mo, sfx_rail2)
						S_StartSound(tg.mo, sfx_litng2)
						S_StartSound(s, sfx_rumble)
						
						local ghs = P_SpawnMobj(tg.mo.x, tg.mo.y, tg.mo.z, MT_HMSLIPILLAR)
						A_ChangeColorAbsolute(ghs, 0, SKINCOLOR_RED)
						
						P_SpawnMobj(tg.mo.x, tg.mo.y, tg.mo.z, MT_HMSLIPILLAR)
						P_SpawnMobj(s.x, s.y, s.z+20<<16, MT_HMSLIPILLAR)
						
						A_ChangeColorAbsolute(ghs, 0, SKINCOLOR_RED)
						p.instalocx,p.instalocy,p.instalocz = tg.mo.x, tg.mo.y, tg.mo.z
	
					elseif (p.hms_instamovew > 1)
						
						if (leveltime % 2 == 0)
							local ghs = P_SpawnMobj(s.x, s.y, s.z, MT_HMSNOVAWAVE) //Bigger and of the Super Mystic variety this time!
							ghs.scale = s.scale*10/P_RandomRange(5, 30)
							ghs.rollangle = P_RandomRange(1,359)*ANG1
							ghs.color = P_RandomRange(SKINCOLOR_BLACK, SKINCOLOR_SUPERGOLD5)
						end
						
						s.state = S_HMS_INSTANTMOVE2
						p.powers[pw_nocontrol] = 2
						p.novafire = 38
						s.momx,s.momy,s.momz = 0,0,0
						p.normalspeed = 0
						p.pflags = $ & ~PF_JUMPED
					end
				end
			end
				
			if tg and (not SMS_NerfedMode(p) and not s.battlemodsms)
			or G_GametypeHasTeams() and (p.ctfteam == tg.mo.player.ctfteam)
			or p.hms_instamovew == 1
				
				P_FlashPal(p, 1, 4)
				P_FlashPal(tg, 1, 4)
				
				--Leave ghost before you move.
				local ghs = P_SpawnGhostMobj(s)
				ghs.sprite = SPR_HMSO
				ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.blendmode = AST_ADD
				ghs.frame = I|FF_TRANS20
				ghs.tics = 60
				ghs.color = SKINCOLOR_SUPERSKY5
				ghs.scalespeed = $*5
				ghs.destscale = $*30
				
				local TPTYPE --Teleport?
				if not SMS_NerfedMode(p) and not s.battlemodsms
				or G_GametypeHasTeams() and (p.ctfteam == tg.mo.player.ctfteam) --Feel free to right to your teammate.
					TPTYPE = 1
				elseif p.instalocx != nil and p.instalocy != nil and p.instalocz != nil
					TPTYPE = 2
				end
				if TPTYPE 
					if TPTYPE == 1
						P_MoveOrigin(s, tg.mo.x, tg.mo.y, tg.mo.z)
					else
						P_MoveOrigin(s, p.instalocx, p.instalocy, p.instalocz)
					end
					s.spritexscale = FRACUNIT-60000
					s.spriteyscale = FRACUNIT*3
					s.SMS_squashtable = {timer = 7, Xspeed = 9800, Yspeed = FRACUNIT/2}	
				end
				s.SMS_ControlAlter = {
				timer = 23,
				removebuttons = (BT_WEAPONNEXT|BT_WEAPONPREV)
				}					
				p.instalocx,p.instalocy,p.instalocz = nil,nil,nil	
				
				--Show up uninvited.
				S_StopSound(s)
				P_SetObjectMomZ(s, 2<<16)
				S_StartSound(s, sfx_s3k83)
				s.angle = tg.mo.angle
				s.eflags = tg.mo.eflags
				
				s.EvilGlare = nil
				
				--Spoop them.
				ghs = P_SpawnGhostMobj(s)
				ghs.sprite = SPR_HMSO
				ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
				ghs.frame = I|FF_TRANS20
				ghs.tics = 50
				ghs.color = SKINCOLOR_RED
				ghs.flags2 = $ & ~MF2_SHADOW
				ghs.scalespeed = $*5
				ghs.destscale = $*30
				
				--Nuke them.
				s.momx,s.momy = 0,0
				P_NukeEnemies(s, s, 1234*s.scale)
				
				--And dazzle them with shiny effects.
				local ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_HMSNOVAWAVE)
				ghs.scale = s.scale*2
				ghs.color = SKINCOLOR_CRIMSON
				
				ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_HMSNOVAWAVE)
				ghs.scale = s.scale*2
				ghs.rollerwave = 16<<16
				ghs.color = SKINCOLOR_EMERALD
				
				
				if SMS_Graphix(s) != 2
					ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSNOVAWAVE)
					ghs.scale = s.scale*2
					ghs.color = SKINCOLOR_SUPERGOLD5
					ghs.rollangle = ANGLE_90
					
					for i = -2,1
						SMS_FlameWalls(s, FRACUNIT, 60<<16, 256*i<<16, A|FF_TRANS10, SKINCOLOR_SMS5R, 42, s)
					end
					A_SMSSTOMPQUAKE(s, 55, 14, FRACUNIT, 0, 0, 0, 0, SKINCOLOR_FLAME)
					SMS_SparkleFlash(tg.mo, nil, nil, FRACUNIT*2)
					
					if SMS_Graphix(s) == 0
						local ghs = SMS_LightFlash(s, SKINCOLOR_WHITE, FRACUNIT, 8, nil)	
						ghs.fuse = 20
				
						SMS_ElectricBody(s)					
						SMS_SmokeCircle(s)
					end
				end
				s.forceHMSyellanim = 24
				
				s.bhlcamtimer = 5
				p.camerascale = FRACUNIT*2
				
				--Cooldown and animation stuff.
				p.hms_instamove = 37
				p.hms_instamovew = 0
				
				//Special flag sync.
				if not (tg.mo.flags2 & MF2_TWOD) 
					s.flags2 = $ & ~MF2_TWOD
				else
					s.flags2 = $|MF2_TWOD
				end
				if not (tg.mo.flags2 & MF2_OBJECTFLIP)
					s.flags2 = $ & ~MF2_OBJECTFLIP
				else
					s.flags2 = $|MF2_OBJECTFLIP
				end						
			end
		end
	end
end)

--Getting Warp Conditions+Input down?
rawset(_G, "HMS_WarpInput", function(s, p)
	if not SMS_Locked(s, p)
	and not p.smsdivetimer
	and not p.hmsthrownnorise
	
		if P_IsObjectOnGround(s) 
			if (p.pflags & PF_SPINNING) and (s.z < s.floorz)
				s.z = s.floorz //Fix for lava stuckage.
			end
			s.z = $+(16*s.scale*P_MobjFlip(s))
		end
		P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSWARPPOINTRETURN)
		P_SetObjectMomZ(s, 3<<16)

		
		local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_HMSWARPPOINT)
		ghs.angle = s.angle
		ghs.hmst = s
		ghs.ogz = ghs.z
		s.target = ghs
		P_InstaThrust(ghs, s.angle, ((gamemap>700) and 300 or 150)*s.scale)
		p.hmswarpcooldown = 11
		if (p.pflags  & PF_SPINNING)
			s.forcewarp1 = 2
			p.pflags = $ & ~PF_SPINNING
		end
		s.state = S_HMS_INSTANTWARP1
		
		ghs = P_SpawnGhostMobj(s)
		ghs.tics = 20
		ghs.color = SKINCOLOR_SUPERSKY5
		ghs.scalespeed = $*3
		ghs.destscale = $*20
		
		s.momx,s.momy = 0,0 
		return true
	end
	return false
end)

--Calculate Hyper Mystic Sonic's timeshatter trajectory
/*
rawset(_G, "HMS_TimeShatter", function(s)
	for d = 1,9999
		if s
		return
		end
	end
end) */

--Cause a tornado as Hyper Mystic Sonic!
rawset(_G, "HMStornado", function (s, v, total, sprite, frame)
	--Set up wind!
	
	local wind = s.hmstor
	local wind2 = s.hmstor2
	while (wind and wind.valid)		
		P_MoveOrigin(wind,
		wind.x+40*FixedMul(s.scale, cos(wind.angle)),
		wind.y+40*FixedMul(s.scale, sin(wind.angle)),
		wind.z)
		
		wind.angle = $+(ANG1*5)
		wind.frame = ($ & FF_FRAMEMASK)|FF_TRANS50
		wind = wind.tracer --Chain to the last spawned object.
	end
	while (wind2 and wind2.valid)
		P_MoveOrigin(wind2, 
		wind2.x-40*FixedMul(s.scale, cos(wind2.angle)),
		wind2.y-40*FixedMul(s.scale, sin(wind2.angle)),
		wind2.z)
		
		wind2.angle = $-(ANG1*5)
		wind2.frame = ($ & FF_FRAMEMASK)|FF_TRANS50
		wind2 = wind2.tracer
	end
	
	--Sound object.
	if (leveltime % 70 == 0)
		s.tormobj = P_SpawnMobjFromMobj(s, 0,0, 80*s.scale, MT_THOK)
		s.tormobj.flags2 = $|MF2_DONTDRAW
		s.tormobj.tics = 72
		s.tormobj.fuse = 72
		S_StartSound(s.tormobj, sfx_s3kcel)
	end
					
	--Tornado hitbox.
	local ghs = P_SpawnMobj(s.x, s.y, s.z-9000<<16, MT_SMSECHECK)

	if (leveltime % 5 == 0)
		if ghs and ghs.valid
			ghs.hmstornado = true
			ghs.target = s
			ghs.height = 99900<<16
			ghs.radius = 1800<<16
		end
	end
	
	//DNA-like tornado!
	if (leveltime % 12 == 0) 
		//We set the local wind variables at the top of the script!
		wind = P_SpawnMobj(s.x+560*FixedMul(s.scale, cos(ANGLE_90)), s.y+560*FixedMul(s.scale, sin(ANGLE_90)), s.z-(s.scale*80), MT_DUSTLAYER)
		wind.angle = ANGLE_180 //Remember that it's a papersprite!
		wind.flags = $|MF_NOCLIPHEIGHT
		wind.momz = (40*P_MobjFlip(s))*s.scale
		wind.scale = s.scale*8
		wind.momx = s.momx
		wind.momy = s.momy
		wind.tracer = s.hmstor
		s.hmstor = wind
		
	elseif (leveltime % 6 == 0) --Must be an elseif
		
		wind2 = P_SpawnMobj(s.x-560*FixedMul(s.scale, cos(ANGLE_90)), s.y-560*FixedMul(s.scale, sin(ANGLE_90)), s.z-(s.scale*80), MT_DUSTLAYER)
		wind2.angle = 0
		wind2.flags = $|MF_NOCLIPHEIGHT
		wind2.momz = (40*P_MobjFlip(s))*s.scale
		wind2.scale = s.scale*8
		wind2.momx = s.momx
		wind2.momy = s.momy
		wind2.tracer = s.hmstor2
		s.hmstor2 = wind2
	end
	
	local rng1 = P_RandomRange(-100,100) --Do a few less RNG calls if we can...
	local rng2 = P_RandomRange(-100,100)
	
	--Tornado ground effects.
	for d = 1,4,3
		ghs = P_SpawnMobj(
		s.x+s.momx+FixedMul( (rng1<<16), cos(s.angle+(ANGLE_90*d))),
		s.y+s.momy+FixedMul( (rng2<<16), sin(s.angle+(ANGLE_90*d))),
		s.z+(((rng2 or 1)/5)-d)<<16,
		MT_HMSSTOMPAURA)
		
		ghs.scale = (s.scale*2)*10/(2+d)
		ghs.eflags = s.eflags
		ghs.tics = 10
		P_SetObjectMomZ(ghs, (6+(d*4))<<16)
		if (s.eflags & MFE_VERTICALFLIP)
			ghs.z = $-(20*s.scale)
		end
		ghs.target = s
		ghs.color = P_RandomRange(SKINCOLOR_SUPERRED1, SKINCOLOR_SUPERGOLD5)
		ghs.frame = T|FF_FULLBRIGHT|FF_TRANS70
		ghs.scalespeed = $*10/(10+d)
		ghs.destscale = ghs.scalespeed+1
	end
	
	--Rocks flying out of the ground.
	if leveltime % 2
		if (s.eflags & MFE_VERTICALFLIP)
			ghs = P_SpawnMobj(
			s.x+((rng1*7)<<16),
			s.y+((rng2*7)<<16),
			s.ceilingz,
			MT_THOK)
		else
			ghs = P_SpawnMobj(
			s.x+((rng1*7)<<16),
			s.y+((rng2*7)<<16),
			s.floorz,
			MT_THOK)
		end
		
		P_SetObjectMomZ(ghs, max(10, 5+abs((rng1 or 1)/10) )
		<<16 )
		
		if leveltime % 8 == 0			
		elseif leveltime % 6 == 0
			ghs.scale = (s.scale*5)/3				
		elseif leveltime % 4 == 0
			ghs.scale = s.scale/3
		else
			ghs.scale = s.scale/2
		end
		ghs.eflags = s.eflags
		ghs.fuse = 70
		ghs.target = s
		if ghs.floorz == ghs.ceilingz
			ghs.state = S_NULL
		else
			ghs.state = S_ROCKCRUMBLEA
		end
	end
end)

/*
--Hyper Mystic Sonic's Hyper Rise.
rawset(_G, "HMS_HyperRise", function(s, p) 
	--Envelop in a golden aura when rising fast!
	if (abs(s.momz) > 2*s.scale)
		if (leveltime % 2 == 0) and not (p.smsgraphix == 2)
			A_SMSSTOMPSMOKE(s, P_RandomRange(5, 20), MT_NIGHTSPARKLE, P_RandomRange(1, 75)<<16, nil, nil, SKINCOLOR_SUPERGOLD5)
		end
		if s.jumprsmoke and s.jumprsmoke.valid
			s.jumprsmoke.fed = 2
			s.jumprsmoke.fuse = 3
		else
			s.jumprsmoke = P_SpawnMobjFromMobj(s,0,0,0, MT_HMSRISEAURA)
			s.jumprsmoke.initscale = s.scale*3/2
			s.jumprsmoke.target = s
			s.jumprsmoke.fed = 2
			s.jumprsmoke.fuse = 3
		end
		
		local ghs = P_SpawnGhostMobj(s)
		ghs.rollangle = s.rollangle
		ghs.blendmode = AST_ADD
		if s.hmsspinang != nil and s.hmsspinpass
			ghs.angle = s.hmsspinang
		end
		if s.momz
			ghs.z = $-(24*s.scale*P_MobjFlip(s))
		end
	end
	 --Starting boost!
	if (s.hms_jumprisen == 4)
		p.pflags = $|PF_JUMPED & ~PF_STARTJUMP
		S_StartSound(s, sfx_kc5b)
		s.hms_jumprisen = 3
		
		--Colorful explosion on initial burst
		if not p.smsgraphix
		and not s.haltthespam
			local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_HMSNOVAWAVE) 
			ghs.scale = s.scale*10/P_RandomRange(9,15)	
			A_SMSSTOMPSMOKE(s, 20, MT_ENERGYBALL, 200)
		end
		if not s.haltthespam
			s.haltthespam = 2
		else
			s.haltthespam = max($,2)
		end
		
		P_SetObjectMomZ(s, 8<<16+25000, true) //Spam the button to rise even faster.
	
		if (s.momz > 0) and not (s.eflags & MFE_VERTICALFLIP)
		or (s.momz < 0) and (s.eflags & MFE_VERTICALFLIP)
			A_SMSquake(s, s.momz/2, (s.momz/FRACUNIT)/12)
		end
	elseif s.hms_jumprisen 
		s.hms_jumprisen = $-1
	end		
end)

--HMS rising flight function. Fly up, my pretty!
rawset(_G, "HMS_Rise", function(s, p) 

	if (p.cmd.buttons & BT_CUSTOM2) and (p.cmd.buttons & BT_TOSSFLAG)
	and not (p.cmd.buttons & BT_JUMP)
		s.hms_readyriseboost = 2
		s.hms_jumphold = 10
		print("SUPERFLY!")
		HMS_SuperFly(s, p) --Final demo style superfly instead?	
		return --
	end
	
	if (p.cmd.buttons & BT_TOSSFLAG) --Good to go right away!
		s.hms_jumphold = 10
		s.hms_readyriseboost = 0
	else
		s.hms_jumphold = 0
		s.hms_readyriseboost = 2 
	end
	
	print(s.hms_jumprisen)
	
	--We keep jumprisen at 3 to fuel it, otherwise...
	if not s.hms_jumprisen
		s.hms_jumprisen = 4 --Blast skywards!
	else
		s.hms_jumprisen = 3 --Uphold boost dash instead!
	end	
	
	if s.momz and not s.hmsspinfreeze
		s.hmsspinpass = 16
	end			
	 --Don't need to set this if you're already going over 40.
	if not (s.momz*P_MobjFlip(s) >= 40*s.scale) 
		P_SetObjectMomZ(s, 40<<16)
	end
	
	s.hmgodticket = true
	s.hmsstompsfx = false
	
	--Fly and rise normally?
	if not (p.cmd.buttons & BT_TOSSFLAG)
	and not ((p.pflags & PF_STARTJUMP) and (s.momz*P_MobjFlip(s)) > s.scale)
	and not (s.momz*(P_MobjFlip(s)) > 12*s.scale)
		if (s.state == S_PLAY_SPRING) or (p.panim == PA_SPRING)
			s.state = S_PLAY_RUN
		end
		p.sms_jumphold = 0				
		if (p.cmd.buttons & BT_FIRENORMAL)
		and (s.z > s.ceilingz-120<<16) and (s.floorz < s.ceilingz-300<<16) //Not in extremely tight spaces.
			s.momz = 0
		else
			P_SetObjectMomZ(s, 7<<16, false)
		end
		p.pflags = $|PF_JUMPED & ~PF_STARTJUMP & ~PF_SPINNING
	end		
end)

--final demo style superfly
rawset(_G, "HMS_SuperFly", function(s, p)  //Recreating the old superfly.
	if not (p.pflags & PF_STARTDASH)
	and not P_IsObjectOnGround(s)
		if (p.cmd.buttons & BT_FIRENORMAL)
		and (s.z > s.ceilingz-120<<16) and (s.floorz < s.ceilingz-300<<16) //Not in extremely tight spaces.
			s.momz = 0
		end
		p.pflags = $|PF_JUMPED & ~PF_STARTJUMP & ~PF_SPINNING
		return true
	end	
end) */

--Fire the NovaBlast!
rawset(_G, "HMS_FireNovaBlast", function(s, p, instant)	
	s.novazaim = false
	if instant != nil
		p.novafire = 101
		s.state = S_HMSNOVAFIRE2
		s.tics = 61 s.anim_duration = 61
		s.momz = 0
		p.hypermysticsonic = max($, 41)
		P_FlashPal(p, PAL_NUKE,6)
		S_StartSound(s, sfx_smsfx8)
		A_SMSquake(s, 80<<16, 60, 1800)
		HMS_NovaBlastShine(s, 100)
		SMS_Embers(s, s,0)	
		SMS_GroundWindBlast(s)
	else
		s.state = S_HMSNOVAFIRE1
		p.novafire = 125
	end
	p.pflags = $|PF_ATTACKDOWN
	s.hmgodticket = true
	S_StartSound(s, sfx_beeyow)
	s.spritexscale = FRACUNIT+12100
	s.spriteyscale = FRACUNIT-10000
	s.spriteyoffset = 5<<16
	s.SMS_squashtable = {timer = 6, Xspeed = 4200, Yspeed = 4500, air = true}	
			
	local ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_HMSNOVAWAVE)
	ghs.color = SKINCOLOR_CRIMSON
	ghs.followmenoz = s
			
	ghs = P_SpawnMobjFromMobj(s, 0, 0, 0, MT_HMSLIGHTNING2)
	ghs.followsms = s
	ghs.ltimershort = true 
	ghs.color = SKINCOLOR_CRIMSON
	
	if not P_IsObjectOnGround(s)		
		p.pflags = $|PF_JUMPED	& ~(PF_SPINNING|PF_THOKKED)
	end
	return true --
end)


--HMScombo, the God Breaker! Toss Flag + Custom 2 on nearby enemies.
--Ridiculously stupidly made code, but won't cause lag with the way it's laid out.
rawset(_G, "HMS_GodBreaker", function(s, p)

	s.SMS_locked = true --overkill, tbh.
	p.powers[pw_noautobrake] = max($,2)
	p.powers[pw_ignorelatch] = 32768
	p.powers[pw_nocontrol] = 2 --You can shift your angle, but otherwise it's "no controls" thing.
	s.flags = $|MF_NOCLIPTHING --Don't clip on stuff for a bit.
	p.pflags = $ & ~(PF_SPINNING|PF_STARTDASH)
	s.starthmscombo = max($-1, 0)
   
	local t = s.hmsspint2
	
	if t.player --Special behaviour for players.
		local tp = t.player
		P_FlashPal(tp, PAL_MIXUP, 10)
		tp.powers[pw_nocontrol] = 2
		tp.powers[pw_flashing] = -1
		tp.powers[pw_tailsfly] = 0
		tp.secondjump = 0
		tp.fly1 = 0
		if not tp.MSsettings
			tp.viewrollangle = t.rollangle
		end
		tp.pflags = $|PF_JUMPDOWN|PF_USEDOWN & ~(PF_JUMPED|PF_SLIDING|PF_SPINNING)
		tp.cmd.buttons = $ & ~(BT_CUSTOM3|BT_CUSTOM2|BT_CUSTOM1|BT_TOSSFLAG)
		t.hmscchange = true
		tp.smsmeleebutton = 850
		t.SMS_locked = true
		t.sprite = SPR_PLAY --Force painframe without the state.
		t.sprite2 = SPR2_PAIN
		t.frame = $ & ~FF_FRAMEMASK
		t.tics = 500
		t.anim_duration = 500
		t.nuuuuuuuuu = true
	end
	
	--15 tics after the last hit, continue!
	if (s.starthmscombo == 1) or (p.rings <= 1)
	
		HMS_AuraStorm(s)
		local ghs = SMS_LightFlash(s, SKINCOLOR_MYSTICAL1)
		ghs.tracer = s
		ghs.frame = $+(2<<16)
		ghs.fuse = 50
		ghs.spriteyoffset = -16<<16
		
		p.powers[pw_ignorelatch] = 0
		s.flags = $ & ~(MF_NOCLIPTHING|MF_BOUNCE)
		P_SpawnMobjFromMobj(s, 0,0,0, MT_SMSGROUNDBOOST)
		P_SetObjectMomZ(s, 8<<16)
		P_AddPlayerScore(p, 100)
		s.state = S_PLAY_FALL
		if not P_IsObjectOnGround(s)
			p.pflags = $|PF_JUMPED & ~PF_THOKKED
		end
		if t.valid
			if t.facc
				t.facc.health = t.facc.phase P_DamageMobj(m)
			elseif t.health 
			and not (t.player and t.player.hypermysticsonic)
			and not (t.type == MT_CRUSHSTACEAN) and not (t.type == MT_BANPYURA) //These two crash the game for some reason.
				t.rollangle = 0		
				if t.player and p		
					P_PlayerFlagBurst(t.player)
					print("RIP: "+t.player.name+". You will be missed. But not by "+p.name+", who clearly hates you.")
				end
				P_KillMobj(t, nil, (not (SMS_NerfedMode(p))) and s or nil)
			end
		end
	--	if (p.rings <= 1) --...??
	--		P_GivePlayerRings(p, -2)
	--	end
		s.hmsspint2 = nil
		s.starthmscombo = 0
		return --
	end
	
	if not t.player
		if (t.type == MT_EGGMOBILE4)
			t.flags2 = $|MF2_BOSSNOTRAP
			P_MoveOrigin(s, s.x, s.y, s.z+450<<16) --Teleport above him so you don't get stuck in the cage.
		else
			if t.target and t.target.player
				t.target = nil //Forget your target. Think about yourself!
			end
			if t.tracer and t.tracer.player
				t.tracer = s
			end
		end	
		t.hmscombopreflags = t.flags
		if (t.type != MT_FANG)
			t.flags = $|MF_NOCLIPTHING & ~(MF_NOGRAVITY|MF_SHOOTABLE|MF_FLOAT)
		end
	else
		t.tracer = s
	end
	
	if (s.starthmscombo <= 160 and s.starthmscombo > 1)	
	
		if (t.health <= 1) --You keep your ass alive until we're done.
			t.health = 3
		end
		
		t.anim_duration = 5
		t.godbreakervictim = true
		
		if t.fuse
			t.fuse = $+1 //Extend their fuse.
		end
		if (t.z+t.height > t.ceilingz)
			t.z = t.ceilingz-t.height
		end
		if (s.starthmscombo > 80)
			t.rollangle = leveltime*FixedAngle(55<<16)
		elseif (s.starthmscombo > 30)
			t.rollangle = leveltime*FixedAngle(40<<16)
		else
			t.rollangle = leveltime*FixedAngle(16<<16)
		end
		if t.player
			t.player.rings = 2
			P_PlayerFlagBurst(t.player)
		end
	end
	if (s.starthmscombo <= 160 and s.starthmscombo > 105)
	
		if (s.starthmscombo < 160)
			if (t.type == MT_MINUS)
				t.state = S_MINUS_AERIAL2
				t.flags = $|MF_SHOOTABLE|MF_SPECIAL
			elseif (t.info.painstate == S_NULL)
				P_SetMobjStateNF(t, t.info.spawnstate)
			else
				P_SetMobjStateNF(t, t.info.painstate)
			end
		end
		if (t.type == MT_GOLDBUZZ) or (t.type == MT_REDBUZZ)
			P_TryMove(t, t.x+FixedMul(44<<16, cos(s.angle)), t.y+FixedMul(44<<16, sin(s.angle)) , true)
			P_TryMove(s, s.x+FixedMul(44<<16, cos(s.angle)), s.y+FixedMul(44<<16, sin(s.angle)) , true)
		end
		
		t.angle = t.angle+ANGLE_45
		t.tics = 106
		t.reactiontime = 106 //Set these so nothing'll change
		s.momx = t.momx
		s.momy = t.momy
		s.momz = t.momz
		s.state = S_PLAY_HMSCOMBO1
		
		if t.player
			t.target = nil //Forget your target. Think about yourself!
		end
		if t.tracer and t.tracer.player //Trace HMS, not any other player
			t.tracer = s
		elseif t.tracer and t.tracer.valid and (t.type == MT_GSNAPPER)
			t.tracer.momx = t.momx
			t.tracer.momy = t.momy
			t.tracer.momz = t.momz
			t.tracer.rollangle = t.rollangle
		end

		if s.starthmscombo == 159
			SMS_PunchSmear(s,p)
			SMS_GroundWindBlast(s)
			SMS_RisingCraterFlames(s)
			A_SMSSTOMPSMOKE(s, 70, MT_HMSLIGHTNING2, nil, -5<<16, nil, SKINCOLOR_SUPERGOLD5)
			S_StartSound(s, sfx_bkpoof)
			S_StartSound(s, sfx_nerf)
			P_FlashPal(p, PAL_NUKE, 10)
			A_SMSquake(s, 60<<16, 6, 6022)
			P_InstaThrust(t, s.angle, 40<<16)
			P_SpawnMobjFromMobj(t, 0, 0, 0, MT_BURSTWAVE)
			P_SpawnMobjFromMobj(s, 0,0,0, MT_BURSTLIGHT)
			P_SetObjectMomZ(t, 10<<16)
			s.state = S_PLAY_RUN
			local ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_RADIALBOOST)
			ghs.color = SKINCOLOR_YELLOW
			s.z = t.z
			P_TryMove(s, t.x, t.y, true)

		elseif s.starthmscombo == 149
			SMS_PunchSmear(s,p)
			SMS_RisingFlames(s)
			SMS_WindBlast(s)
			S_StartSound(s, sfx_nerf)
			A_SMSquake(s, 54<<16, 5, 6022)
			P_InstaThrust(t, s.angle-ANGLE_22h, 55<<16)
			P_SpawnMobjFromMobj(t, 0,0,0, MT_BURSTWAVE)
			P_SetObjectMomZ(t, 1<<16)

		elseif s.starthmscombo == 141
			SMS_ElectricRecoil(s)
			S_StartSound(s, sfx_nerf)
			P_InstaThrust(t, s.angle+ANGLE_22h, 40<<16)
			A_SMSquake(s, 52<<16, 8, 6022)
			P_SetObjectMomZ(t, 16<<16)
			P_SpawnMobj(t.x, t.y, t.z, MT_BURSTWAVE)
			P_SpawnMobj(t.x-175<<16, t.y+150<<16, t.z+100<<16, MT_BURSTLIGHT)
			P_SpawnMobj(t.x+175<<16, t.y-160<<16, t.z-10<<16, MT_BURSTLIGHT)
			
		elseif (s.starthmscombo == 137 or s.starthmscombo == 114 or s.starthmscombo == 154)
			local COLORTABLE = {SKINCOLOR_SMS1R, SKINCOLOR_SMS3R, SKINCOLOR_SMS5R, SKINCOLOR_ORANGE, SKINCOLOR_RED, SKINCOLOR_LIME, SKINCOLOR_EMERALD, SKINCOLOR_MINT, SKINCOLOR_WHITE}
			SMS_PunchSmear(s,p)
			SMS_WindBlast(t)
			S_StartSound(t, sfx_nerf)
			P_SpawnMobj(t.x+80<<16, t.y-70<<16, t.z+25<<16, MT_BURSTWAVE)
			P_SpawnMobj(t.x+120<<16, t.y-150<<16, t.z+50<<16, MT_BOSSEXPLODE)
			P_SpawnMobj(t.x-140<<16, t.y+170<<16, t.z-5<<16, MT_BOSSEXPLODE)
			P_SpawnMobj(t.x+300<<16, t.y+290<<16, t.z+77<<16, MT_BURSTLIGHT)
			P_SpawnMobj(t.x-280<<16, t.y-277<<16, t.z-33<<16, MT_BURSTLIGHT)	
			
			--Draw an attack line!
			local ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_SMSAUTOFRAME)
			ghs.sprite = SPR_HMSO
			ghs.renderflags = RF_NOCOLORMAPS|RF_FULLBRIGHT
			ghs.frame = G|FF_TRANS90
			ghs.frame = (s.starthmscombo == 114) and $|FF_HORIZONTALFLIP or $
			ghs.blendmode = AST_ADD
			ghs.fuse = 11 ghs.tics = 99
			ghs.scalespeed = FRACUNIT/10
			ghs.sttfade = 9
			ghs.sttYspeed = FRACUNIT*4
			ghs.destscale = 1
			ghs.COLORT_trail = COLORTABLE
			ghs.COLORT_trailno = 9
			ghs.ENDtrans = 0
			
			local ANGLE = s.angle+(SMSLocalRNG(-60, 60, s)*ANG1)
			P_SetOrigin(ghs,
			t.x+t.momx+FixedMul(-300*s.scale, cos(ANGLE)),
			t.y+t.momy+FixedMul(-300*s.scale, sin(ANGLE)),
			t.z+(t.height/4)+(SMSLocalRNG(-199, 199, s)*s.scale))
			SMS_DrawTrail(s, ghs, MT_SMSAUTOFRAME)
			ghs.state = S_NULL
			
			local ghs = SMS_DashGFX(s, SKINCOLOR_RED) 
			ghs.fuse = 8
			ghs.sttspeed = 1
			ghs.sttfade = true
			ghs.frame = (s.starthmscombo == 114) and ($|FF_HORIZONTALFLIP & ~FF_TRANSMASK) or ($ & ~FF_TRANSMASK)


		elseif s.starthmscombo == 132
			SMS_ElectricRecoil(s)
			S_StartSound(s, sfx_nerf)
			P_InstaThrust(t, s.angle-ANGLE_11hh, 47<<16)
			A_SMSquake(s, 80<<16, 10, 6022)
			P_SpawnMobj(t.x, t.y, t.z, MT_BURSTWAVE)
			P_SpawnMobj(t.x-150<<16, t.y-200<<16, t.z+70<<16, MT_BURSTWAVE)
			P_SpawnMobj(t.x+240<<16, t.y+190<<16, t.z+50<<16, MT_BURSTWAVE)
			P_SetObjectMomZ(t, -10<<16)
			
		elseif s.starthmscombo == 120
			SMS_ElectricRecoil(s)
			SMS_PunchSmear(s,p)
			SMS_RisingCraterFlames(s)
			S_StartSound(s, sfx_nerf)
			A_SMSquake(s, 64<<16, 6, 6022)
			P_InstaThrust(t, s.angle+ANGLE_11hh, 43<<16)
			P_SpawnMobj(t.x, t.y, t.z, MT_BURSTWAVE)
			P_SpawnMobj(t.x+195<<16, t.y-180<<16, t.z+80<<16, MT_BURSTLIGHT)
			P_SpawnMobj(t.x-186<<16, t.y+177<<16, t.z-20<<16, MT_BURSTLIGHT)
			P_SetObjectMomZ(t, 14<<16)
		end

	--Below 105 now!
	
	elseif (s.starthmscombo <= 105 and s.starthmscombo > 80)
	
		if (t.type == MT_MINUS)
			t.state = S_MINUS_AERIAL2
			t.flags = $|MF_SHOOTABLE|MF_SPECIAL
		elseif ((t.info.deathstate != S_NULL) and (t.player or t.flags & MF_BOSS) and (t.skin != "sms"))
			P_SetMobjStateNF(t, t.info.deathstate)
		elseif ((t.info.painstate != S_NULL) and (t.player or t.flags & MF_BOSS))
			P_SetMobjStateNF(t, t.info.painstate)
		else
			P_SetMobjStateNF(t, t.info.spawnstate)
		end

		P_SpawnMobjFromMobj(t, 
		((P_RandomRange(FixedMul(-56, t.scale), FixedMul(56, t.scale)))<<16), 
		((P_RandomRange(FixedMul(-56, t.scale), FixedMul(56, t.scale)))<<16), 
		((P_RandomRange(FixedMul(1, t.scale), FixedMul(65, t.scale)))<<16),
		MT_BOSSEXPLODE)

		t.angle = s.angle+ANGLE_180
		s.momx,s.momy,s.momz = 0,0,1
		
		if s.starthmscombo == 105
			SMS_RisingCraterFlames(s)
			SMS_RisingFlames(s)
			S_StartSound(s, sfx_nerf)
			A_SMSquake(s, 93<<16, 5, 10022)
			P_InstaThrust(t, s.angle+ANGLE_11hh, 56<<16)
			P_SpawnMobj(t.x, t.y, t.z, MT_BURSTWAVE)
			t.momz = 0
			s.state = S_PLAY_RUN
			
		elseif s.starthmscombo == 100
			SMS_RisingCraterFlames(s)
			S_StartSound(t, sfx_s3k4b)
			S_StartSound(s, sfx_s3kbcs)
			P_InstaThrust(t, s.angle, 0)
			P_SpawnMobj(t.x, t.y, t.z, MT_BURSTLIGHT)
			P_SetObjectMomZ(t, 16<<16)
		end
			
	--80 or below	
	
	elseif (s.starthmscombo > 15 and s.starthmscombo <= 80)
		if (t.type == MT_MINUS)
			t.state = S_MINUS_AERIAL2
		elseif (t.info.painstate == S_NULL)
			P_SetMobjStateNF(t, t.info.spawnstate)
		else
			P_SetMobjStateNF(t, t.info.painstate)
		end
		t.angle = t.angle-(ANGLE_11hh/2)
		s.hmgodticket = true
		s.state = S_PLAY_HMSCOMBO2
		s.momx,s.momy = 0,0
		if (t.z+190<<16 < s.z) and ((s.starthmscombo < 45) or (t.flags & MF_BOSS))
			s.momz = -50<<16
			t.momz = $/2
		elseif (t.z-190<<16 > s.z) and ((s.starthmscombo < 45) or (t.flags & MF_BOSS))
			s.momz = 50<<16
			t.momz = $/2
		else
			s.momz = 1
		end
		if (s.starthmscombo > 20 and s.starthmscombo < 63)
			SMS_StompGFX(s, p, true, true)
		end				
		if (t.momz < 2<<16)
			if (s.starthmscombo >= 63)
				P_SetObjectMomZ(t, -6<<16)
				P_InstaThrust(t, s.angle, 7<<16)
				HMS_NegativeZone(s, s, true, SKINCOLOR_BLACK, A|FF_TRANS70)
			elseif (s.starthmscombo > 45)
				P_SetObjectMomZ(t, -4<<16)
				P_InstaThrust(t, s.angle, 3<<16)
				HMS_NegativeZone(s, s, true, SKINCOLOR_BLACK, A|FF_TRANS50)
			else
				P_SetObjectMomZ(t, -105355)
				P_InstaThrust(t, s.angle, 0)
				P_FlashPal(p, PAL_MIXUP, 2)
				if t.player
					P_FlashPal(t.player, PAL_MIXUP, 2)
				end
			end
		end	
		
		if s.starthmscombo == 80
			SMS_QuickDustGFX(s)
			s.SMS_DLtrail = {timer = 1, colorized = true, color = SKINCOLOR_RED}
			s.z = max(t.z-140*s.scale, s.floorz+10*s.scale) --Warp!
			P_TryMove(s, t.x, t.y, true)
			SMS_ContinuousTrail(s, s.SMS_DLtrail)
			S_StartSound(t, sfx_s3k7c)
			S_StartSound(t, sfx_s3k83)
			P_FlashPal(p, PAL_MIXUP, 4)
			P_InstaThrust(s, s.angle, 0)
			P_SpawnMobjFromMobj(s, 0, 0, 0, MT_BURSTLIGHT)
			s.state = S_PLAY_HMSCOMBO2
			SMS_GroundWindBlast(s)
			SMS_MediumDustGFX(s)
			SMS_GoldWaves(s,p)
			SMS_ElectricBody(s, 35)
				
		elseif s.starthmscombo == 63
		
			SMS_GroundWindBlast(s)
			s.bhlcamtimer = 130
			S_StartSound(s, sfx_s3ka0)
			P_FlashPal(p, 3, 3)
			local ghs = P_SpawnMobjFromMobj(s, 0,0, -5<<16, MT_BURSTWAVE)
			ghs.color = SKINCOLOR_RED
			SMS_ElectricBody(s, 43)	
				
		elseif s.starthmscombo == 45
			s.bhlcamtimer = 30
			p.camerascale = FRACUNIT*4
			S_StartSound(t, sfx_s3k9c)
			S_StartSound(s, sfx_beeyow)
		end
		
	 --The last 15 tics. Not counting exact 1.	
	elseif (s.starthmscombo <= 15 and s.starthmscombo > 1)
		local ghs
		if (t.type == MT_MINUS)
			t.state = S_MINUS_AERIAL2
		elseif (t.info.painstate == S_NULL)
			P_SetMobjStateNF(t, t.info.spawnstate)
		else
			P_SetMobjStateNF(t, t.info.painstate)
		end

		P_SpawnMobjFromMobj(t,
		((P_RandomRange(FixedMul(-150, t.scale), FixedMul(150, t.scale)))<<16), 
		((P_RandomRange(FixedMul(-150, t.scale), FixedMul(150, t.scale)))<<16), 
		((P_RandomRange(FixedMul(-20, t.scale), FixedMul(130, t.scale)))<<16),
		MT_BOSSEXPLODE)

		t.angle = t.angle-(ANGLE_11hh/4)
		s.momx,s.momy,s.momz = 0,0,1
		t.momz = 0
		s.hmgodticket = true
		s.state = S_PLAY_HMSCOMBO3
					
		local COLORTABLE = {SKINCOLOR_SMS1R, SKINCOLOR_SMS3R, SKINCOLOR_SMS5R, SKINCOLOR_ORANGE, SKINCOLOR_RED, SKINCOLOR_LIME, SKINCOLOR_EMERALD, SKINCOLOR_MINT, SKINCOLOR_WHITE}
		local HMSCOLOR = COLORTABLE[SMS_TimeFrame(9, 1)]
		HMS_AuraStorm(s, nil, HMSCOLOR, nil, nil, nil)
		HMS_BoltStorm(s, HMSCOLOR, 7, SMSLocalRNG(1,37, s)*ANG1, SMSLocalRNG(-50,550, s))
		
		COLORTABLE = {SKINCOLOR_SMS1R, SKINCOLOR_SMS3R, SKINCOLOR_SMS5R, SKINCOLOR_ORANGE, SKINCOLOR_RED, SKINCOLOR_SMS4R, SKINCOLOR_SMS2R, SKINCOLOR_SMS1R, SKINCOLOR_MYSTICAL5}
		HMSCOLOR = COLORTABLE[SMS_TimeFrame(5, 1)]
		
		if s.starthmscombo == 15 --The final hit! Make it count!
		
			p.camerascale = FRACUNIT
			s.bhlcamtimer = 0
			A_SMSquake(s, 87<<16, 34, 21022)
			S_StartSound(t, sfx_s3k81)
			P_FlashPal(p, 4, 4)
			S_StartSound(s, sfx_pwbmb)
			S_StartSound(t, sfx_s3k54)
			
			SMS_GoldWaves(s,p) --Kitchen sink, goooo!
			
			local ghs = HMS_GigaJetBolt(s)
			ghs.tracer = s
			
			SMS_GroundWindBlast(s)
			SMS_WindBlast(s)
		
	 		for m in mobjs.iterate(mobjs)
				if (m.flags & (MF_ENEMY|MF_BOSS))
				and m.health and not m.hmscombod and not (m == t)
					if (FixedHypot(m.x-ghs.x, m.y-ghs.y) < 3200<<16)
						P_KillMobj(m, ghs, s)
					end
				end
				if SMS_NerfedMode(p)
				and m.player and m.health
				and not m.hmscombod
				and not m.player.hypermysticsonic
				and not (m.player.ctfteam and (m.player.ctfteam == p.ctfteam))
					if ((FixedHypot(m.x-ghs.x, m.y-ghs.y)) < 2800<<16)
						P_DamageMobj(m, ghs, s)
						P_InstaThrust(m, m.angle, -10<<16)
						P_SetObjectMomZ(m, 24<<16)
					end
				end
	 		end

			for i = -1,1,2
				local ghs = P_SpawnMobjFromMobj(s, (400<<16*i), (400<<16*i), -100<<16, MT_HMSLIPILLAR)
				ghs.color = COLORTABLE[P_RandomRange(1,9)]
			
				ghs = P_SpawnMobjFromMobj(s, -(400<<16*i), (400<<16*i), -100<<16, MT_HMSLIPILLAR)
				ghs.color = COLORTABLE[P_RandomRange(1,9)]
			
				ghs = P_SpawnMobjFromMobj(s, (400<<16*i), 0, -100<<16, MT_HMSLIPILLAR)
				ghs.color = COLORTABLE[P_RandomRange(1,9)]
			end

			local ghs = P_SpawnMobjFromMobj(t, 0, 0, -10<<16, MT_BURSTWAVE)
			ghs.color = SKINCOLOR_RED

		elseif s.starthmscombo == 7
		
		S_StartSound(s, sfx_s3k54)

			for i = -1,1,2 --Why am I bothering to improve this mess...
			local ghs = P_SpawnMobjFromMobj(s, 1250<<16, (1250<<16*i), s.z-1000<<16, MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]
			ghs = P_SpawnMobjFromMobj(s, -(1250<<16*i), -(1250<<16*i), s.z-1000<<16, MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]

			ghs = P_SpawnMobjFromMobj(s, -(1250<<16*i), (1250<<16*i), s.z-1000<<16, MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]

			ghs = P_SpawnMobjFromMobj(s,0,(1250<<16*i),-(1250<<16*i), MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]

			ghs = P_SpawnMobjFromMobj(s,(1250<<16*i),0,-(1250<<16*i), MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]
			end

		elseif s.starthmscombo == 2
		
			if not t.hmscombopreflags == nil
				t.flags = t.hmscombopreflags
				t.rollangle = 0
				t.flags = $|MF_NOCLIPTHING
			end
			
			local ghs = P_SpawnMobjFromMobj(s,0,0,-5<<16, MT_BURSTWAVE)
			ghs.color = SKINCOLOR_RED

			S_StartSound(t, sfx_s3k54)
		
			for i = -1,1,2 
			ghs = P_SpawnMobjFromMobj(s,(2600<<16*i), (2600<<16*i), 0, MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]
			ghs = P_SpawnMobjFromMobj(s,-(2600<<16*i), -(2600<<16*i), 0, MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]

			ghs = P_SpawnMobjFromMobj(s,-(2600<<16*i), (2600<<16*i), 0, MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]

			ghs = P_SpawnMobjFromMobj(s,0,(2600<<16*i), 0, MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]

			ghs = P_SpawnMobjFromMobj(s,(2600<<16*i), 0, 0, MT_HMSLIPILLAR)
			ghs.color = COLORTABLE[P_RandomRange(1,9)]
			end
			
		end				
		return --
	end
end)

--Some minor things when you're moving above 6*s.scale speed.
rawset(_G, "HMS_SpeedingBehaviour", function(s, p) 
	--Spawn rising floor flames!
	if not (s.eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) //No flames when underwater, ofcourse.
	and not A_HMSCheckDeathPit(s) //Not when on a death pit....
	
	//	A_SMSquake(s, p.speed/3, 1, (p.speed/65355)*700, true)
		if (p.speed > 138*s.scale)
		s.hmsmwh = 1
			if (p.pflags & PF_SPINNING)
				s.hmsfsfx = false
				A_SMSSpinFire(s, MT_SMSSPINFIRE, 65357)
				A_SMSSpinFire(s, MT_SMSSPINFIRE, 65357, 5<<16)
			else
				if not s.hmsfsfx
					s.hmsfsfx = true
					S_StartSound(s, sfx_s3k43) //S_StartSound(s, sfx_s3k48)
				end
				A_HMSfiretrail(s)
			end
			if s.maxtimex == nil
				s.maxtimex = 0
				s.maxtimey = 0
				s.maxtimers = 0
			end
			if s.x == s.maxtimex and s.y == s.maxtimey
				if s.maxtimers == nil
					s.maxtimers = 1							
				else
				s.maxtimers = $+1
					if (s.maxtimers > 31)
						s.z = s.floorz+5<<16
						P_DoJump(p, false) //SRB2's colission is screwing you. Stop this madness.
						s.momx = 0
						s.momy = 0
						s.momz = 0
					end
				end
			else
				s.maxtimers = 0				
			end
		
			s.maxtimex = s.x
			s.maxtimey = s.y
		else
			if not s.hmsfsfx
				s.hmsfsfx = true
				S_StartSound(s, sfx_s3k43) //S_StartSound(s, sfx_s3k48)
			end
	  		if SMS_Graphix(s) != 2
				if (s.eflags & MFE_JUSTHITFLOOR)
				or (leveltime % 2 == 0)
				or (p.speed > 56*s.scale)
					A_HMSfiretrail(s)
				end
     		end
		end
	end
	if (p.speed >= 137*s.scale) --We've got alot of speed!
		s.hmsmwh = 1
		if (leveltime % 2 == 0)
			if (leveltime % 4 == 0)
				P_NukeEnemies(s, s, 650*s.scale)
			else
				for i = -1,1
					local ghs = SMS_CraterSpew(s, s.angle+(ANG1*120*i), 13)
					if ghs and ghs.valid
						ghs.spritexscale = $*3/2
						ghs.spriteyscale = $*3/2
						ghs.momx = ($*9)+FixedDiv(FixedMul(s.momx, 2),3)
						ghs.momy = ($*9)+FixedDiv(FixedMul(s.momy, 2),3)
						ghs.smsrgtimer = 23
					end
				end
			end
		end
		local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_SMSGROUNDBOOST)
		ghs.tracer = s
		A_SMSquake(s, 14<<16, 1, 4122, true)
		s.hmsrunquake = 1
	end
	return true --
end)

--Includes HMS 7-flames, Novablast, and Black Hole attack.
rawset(_G, "HMS_AirAttacks", function(s, p) 
	local GRAPHIX = SMS_Graphix(s) --So I only have to check it once.

	//Here's a crazy attack for you; HMS' Hypernova blast!
	//He fires a stream of concentrated energy spheres with incredible explosive power!
	
	if (s.state == S_HMSNOVAFIRE1) --Firing the NovaBlast!
	
		s.momz = 0
		
		if (s.z >= s.ceilingz-150*s.scale) and (s.floorz < s.ceilingz-150*s.scale)
			s.momz = -10*s.scale
		elseif (s.z < s.floorz+70*s.scale)
			s.momz = 10*s.scale
		end
		if (p.novafire == 124 or p.novafire == 117)
			s.momx = FixedDiv(FixedMul($, 100), 121)
			s.momy = FixedDiv(FixedMul($, 100), 121)
			if p.novafire == 124
				p.camerascale =  FRACUNIT*5/3
				P_NukeEnemies(s, s, 200*s.scale) //Nuke-stars are mostly for show.
				HMS_AuraStorm(s, nil, SKINCOLOR_RED)
				local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK)
				ghs.scalespeed = $*42
				P_SetObjectMomZ(ghs, ghs.scalespeed*7, true)
				ghs.destscale = $*99
				ghs.blendmode = AST_SUBTRACT
				ghs.frame = A|FF_TRANS30
				ghs.momx = s.momx
				ghs.momy = s.momy
				s.HMS_FireCoords3 = nil
			elseif GRAPHIX == 0
				SMS_ElectricBody(s, 24, SKINCOLOR_RED)
				HMS_BoltStorm(s, SKINCOLOR_FLAME, 10, nil, -100)
				for i = 0,1
					local ghs = SMS_LightningStrike(s, SKINCOLOR_RED, R)
					ghs.dispoffset = 50
					ghs.frame = (i == 1) and $|FF_VERTICALFLIP or $
					ghs.destscale = $*99
					ghs.momx = s.momx
					ghs.momy = s.momy
				end							
			end
		end
		
		p.camerascale =  max($-50, FRACUNIT*10/9)
		s.bhlcamtimer = 2
		s.smspickupCD = 3
		if p.aiming --Limit vertical aiming for a sec.
			p.aiming = max(-8800<<16, min(p.aiming, 8800<<16))
		end
		if (s.tics > 4)
			HMS_NegativeZone(s, s, true, SKINCOLOR_BLACK, (s.tics > 16) and A|FF_TRANS80 or A|FF_TRANS60)
		else
			if s.tics == 4
			s.HMS_SkipHBnext = nil
				if GRAPHIX == 0					
					local ths,ghs = SMS_WindBlast(s)
					for i = 1,2
						ghs = (i == 2) and ths or $
						ghs.color = (i == 2) and SKINCOLOR_SKY or SKINCOLOR_SMS3R
						ghs.scale = $*5/(1+i)
						ghs.destscale = $*99
						ghs.momx = $+s.momx
						ghs.momy = $+s.momy
						ghs.dispoffset = 20
						ghs.scalespeed = FRACUNIT/4
						ghs.spriteyoffset = $-28<<16
						ghs.blendmode = AST_ADD
					end	
				end
				HMS_InitialFlameGFX(s, p, nil, true)
			end
			HMS_NegativeZone(s, s, true, SKINCOLOR_SMSROVERGLOW, A|FF_TRANS30)
		end	
		return 1 --
				
	elseif (s.state == S_HMSNOVAFIRE2)
				
		if (p.cmd.buttons & BT_SPIN) --Aiming assist buttons for gamepad/keyboard.
			p.aiming = -4500<<16*P_MobjFlip(s)
			s.novazaim = true
		elseif (p.cmd.buttons & BT_JUMP)
			p.aiming = 3600<<16*P_MobjFlip(s)
			s.novazaim = true
		elseif s.novazaim
			s.novazaim = false
			p.aiming = 0
		end
		
		if (s.tics > 53)
			local ghs = HMS_NovaBlastShine(s, 80-(s.tics/2))
			if ghs and ghs.valid
				P_Thrust(ghs, s.angle+(s.tics*(ANG1*78)), 18*s.scale)
			end
			if (s.tics == 60)
				s.spritexscale = FRACUNIT-19100
				s.spriteyscale = FRACUNIT+27100
				s.spriteyoffset = -7<<16
				s.SMS_squashtable = {timer = 4, Xspeed = 9000, Yspeed = 11500, air = true}
			
				S_StartSound(s, sfx_hmsnof)
				P_FlashPal(p, 4, 7) //Only 1 flash to not cause seizures.
				s.momx = FixedDiv(FixedMul($, 100), 143)
				s.momy = FixedDiv(FixedMul($, 100), 143)							
			end
		else
			if (s.tics == 1)
				if s.novazaim
					s.novazaim = false
					p.aiming = 0
				end
			else
				s.spritexscale = FRACUNIT-2
				s.spriteyscale = FRACUNIT+2
				s.spritexoffset = SMSLocalRNG(-3<<16-35000,3<<16+35001,s) --Shaking HMS' sprite is more effective than the camera at this point.
				s.spriteyoffset = SMSLocalRNG(3<<16+35000,-3<<16-35000,s)
				s.SMS_squashtable = {timer = 2, Xspeed = 1, Yspeed = 1, air = true}						
				if s.tics % 5 == 0
					local ghs = SMS_ElectricBody(s, 5, SKINCOLOR_CRIMSON)
					ghs.blendmode = AST_TRANSLUCENT
					ghs.spriteyscale = $+29000
					ghs.spriteyoffset = 4<<16
					ghs.spritexscale = $+12000
					ghs.rollangle = SMSLocalRNG(-20,20,s)*ANG1
					if s.tics % 10 == 0
						ghs.mirrored = true
						ghs.color = SKINCOLOR_SMS4R
					end
				end						
			end
		end
		
		p.pflags = $|PF_ATTACKDOWN
		p.camerascale = FRACUNIT*5/2
		s.bhlcamtimer = 2
		s.smspickupCD = 3
		
		if (s.z >= s.ceilingz-150*s.scale) and (s.floorz < s.ceilingz-150*s.scale)
			s.momz = -10*s.scale
		else
			s.momz = 0
		end
		if not p.sms_flamedelay
			local ghs = P_SpawnPlayerMissile(s, MT_HMSNOVABLAST, MF2_RAILRING) --Firing the NovaBlast!
			if ghs and ghs.valid //Did it spawn correctly?
				ghs.scale = s.scale*3
				ghs.destscale = 285000 //Roughly 4.3
				ghs.color = SKINCOLOR_SMS5R
				if s.HMS_SkipHBnext
					ghs.frame = D|FF_TRANS50 --Use frame D!
					ghs.blendmode = AST_TRANSLUCENT
					ghs.NOhitbox = true
					s.HMS_SkipHBnext = nil
				else
					s.HMS_SkipHBnext = true
				end
			end
			A_SMSquake(s, 8<<16, 3, 8901)
			if GRAPHIX == 2
				p.sms_flamedelay = 5 //Slow it down so SRB2's engine can keep up
			else
				p.sms_flamedelay = 3						
			end
		end
		return 1 --
				
	elseif (s.state == S_HMSBLACKHOLE) --HMS creating a black hole.
		s.SMS_ControlAlter = {
		timer = 2,
		forwardmove = 0,
		sidemove = 0,
		removebuttons = 0}
		
		if (p.hmsblackhole > 64)
			p.aiming = 1600<<16
	  		if GRAPHIX != 2
				if p.hmsblackhole == 124
					A_SMSSTOMPSMOKE(s, 30, MT_HMSLIGHTNING2, 0, 20<<16, FRACUNIT/2, SKINCOLOR_JET)
				elseif p.hmsblackhole == 117
					S_StartSound(s, sfx_s3k45)
					A_SMSSTOMPSMOKE(s, 28, MT_HMSLIGHTNING2, 0, -20<<16, FRACUNIT/2, SKINCOLOR_JET)
				elseif p.hmsblackhole == 76
					A_SMSSTOMPSMOKE(s, SMSLocalRNG(12, 27,s), MT_HMSLIGHTNING2, -5, SMSLocalRNG(20, -20,s)<<16, FRACUNIT/SMSLocalRNG(4,1,s), SKINCOLOR_JET)
				end
			end	
			if p.hmsblackhole == 174
				p.sweepangle = s.angle
				P_FlashPal(p, 4, 10) //Quick red flash.
				A_SMSquake(s, 44<<16, 140, 6901)
			elseif (p.hmsblackhole < 174)
				s.angle = p.sweepangle
				p.drawangle = s.angle
				if p.hmsblackhole == 65
					S_StartSound(s, sfx_kc4d)
					A_SMSSTOMPSMOKE(s, 50, MT_HMSLIGHTNING2, 0, 0, nil, SKINCOLOR_JET)
				end
			end
		else
			p.aiming = 0
	  	end
		
		s.smspickupCD = 3
		s.hmgodticket = true
		s.momz = 0
		s.momx = 0
		s.momy = 0
		
		if (p.lddiscount == 1 or p.lddiscount == 3) --Black Hole smoke.
		
		/*	local TARGET = P_LookForEnemies(p, 4000, true, false)
			if TARGET and TARGET.valid and not TARGET.bkhltracker and TARGET.bkhltracker.valid
			TARGET.bkhltracker = P_SpawnMobjFromMobj(m, 0, 0, 0, MT_CMPHTRACKER)
			TARGET.bkhltracker.bkhl = true
			TARGET.bkhltracker.target = s
			TARGET.bkhltracker.tracer = s
			end */
			
			local ghs = P_SpawnMobjFromMobj(s,
			SMSLocalRNG(-1700, 1700+p.lddiscount, s)*s.scale,
			SMSLocalRNG(-1700-p.lddiscount, 1700, s)*s.scale, 
			SMSLocalRNG(-750, 750+p.lddiscount, s)*s.scale,
			MT_HMSPBC)
			if ghs and ghs.valid
				ghs.bkhl = true
				ghs.target = s
			end
		end
		return 2 --
	end
	
	local STARTMOVE = 0
	
	--Start the Hyper Nova Blast or Black Hole?	
	if (p.cmd.buttons & BT_ATTACK) and (p.cmd.buttons & BT_FIRENORMAL)
		STARTMOVE = 2
	elseif (p.cmd.buttons & BT_ATTACK) and not (p.pflags & PF_ATTACKDOWN)
		STARTMOVE = 1	
	else
		if (p.cmd.buttons & BT_FIRENORMAL) --Ehh, this one's really not air-limited, but here goes anyway!
		and not SMS_Locked(s, p)
		and not p.objectplacer --Not with SMScheats objectplacer on!
		
			if (leveltime % 8 == 0)
			and not (p.sms_nflamehold == 1 and not p.sms_flamedelay)
				HMS_InitialFlameGFX(s, p)
			end	
			
			if not p.sms_flamedelay
			
			s.hmgodticket = true --Enables visual aura effect.
			
				local ghs --Set this now to prevent headaches later.
					
				--HMS 7 flames" projectile spam! HMS flames. HMS normalflames. 7flames"
				if p.sms_nflamehold == 1
					s.HMS_7flame = true
					HMS_InitialFlameGFX(s, p)
				end
				
				if (s.z > s.ceilingz-100*s.scale)
				and (s.floorz < s.ceilingz-300*s.scale) --Not in extremely tight spaces.
					s.z = $-19*s.scale
				end
				local ANGLE = s.angle
				if (s.hmsspinpass and s.hmsspinang != nil) --Fire in wild circles!
					ANGLE = s.hmsspinang
					local ghs = P_SpawnPlayerMissile(s, MT_HMSFIREBLAST, MF2_RAILRING)
					if ghs ghs.mainflame = 1 ghs.GRAPHIX = GRAPHIX ghs.HMS_7flame = s.HMS_7flame end --
				else
					local ghs = P_SPMAngle(s, MT_HMSFIREBLAST, ANGLE, 1, MF2_RAILRING)
					if ghs ghs.mainflame = 1 ghs.GRAPHIX = GRAPHIX ghs.HMS_7flame = s.HMS_7flame end --
				end
				local ghs
				--Now fire 6 more!
				for i = -1,1,2
					ghs = P_SPMAngle(s, MT_HMSFIREBLAST, ANGLE+(ANG10*i), 1, MF2_RAILRING)
					if ghs ghs.GRAPHIX = GRAPHIX ghs.midflame = i ghs.HMS_7flame = s.HMS_7flame end --
				end
				for i = -1,1,2
					ghs = P_SPMAngle(s, MT_HMSFIREBLAST, ANGLE+(ANG2*2*i), 1, MF2_RAILRING)
					if ghs ghs.GRAPHIX = GRAPHIX ghs.HMS_7flame = s.HMS_7flame end --
				end
				for i = -1,1,2
					ghs = P_SPMAngle(s, MT_HMSFIREBLAST, ANGLE+(ANG15*i), 1, MF2_RAILRING)
					if ghs 
						ghs.GRAPHIX = GRAPHIX 
						ghs.outterflame = i 
						ghs.HMS_7flame = s.HMS_7flame
					end
				end			
				S_StartSound(s, sfx_s3kbcs)
				p.sms_flamedelay = 3 //This small detail makes all the difference.
				if s.HMS_7flame
					s.HMS_7flame = false
				else
					s.HMS_7flame = true
				end
				return 3 --
			end
		end
		return --
	end
	if STARTMOVE		
		if P_IsObjectOnGround(s)
		or SMS_Locked(s, p)
			return --
		end
		if STARTMOVE == 1
			if not p.sms_flamedelay
			and not (p.sms_flamebuttonhold > 1)
			and not p.novafire --Not at ALL on this one!
			and not (p.smspickup and p.smspickup.valid)				
				HMS_FireNovaBlast(s, p)
				return STARTMOVE --
			end
		elseif (p.pflags & PF_JUMPED)
			
			//D-did he just....yep, HMS just summoned a goddamn black hole!
			//This move has some serious cooldown.
			
			s.state = S_HMSBLACKHOLE
			p.hmsblackhole = 175
			s.bhlcamtimer = 150
			local ghs = P_SpawnPlayerMissile(s, MT_HMSBLACKHOLE)
			if ghs and ghs.valid
				searchBlockmap("objects",function(t,m)
					if m.valid and (m.flags & (MF_ENEMY|MF_BOSS)) and not m.bkhltracked
						if (FixedHypot(FixedHypot(s.x-m.x, s.y-m.y), s.z-m.z) < 4300*s.scale)
							local ths = P_SpawnMobjFromMobj(m, 0,0,0, MT_CMPHTRACKER) --Assign black hole tracker.
							ths.bkhl = true
							ths.target = ghs
							ths.tracer = s
						end
					end
				end,s, s.x-4400*s.scale,s.x+4400*s.scale, s.y-4400*s.scale,s.y+4400*s.scale)
			end
			return STARTMOVE --
		end
	end
end)