--=============================Wall Jump FUNCTIONS=======================================
--Functions, thinkers, and death hooks belonging to the new revamped walljump.
--=======================================================================================

--Perform the SMSreborn Walljump! It's a million times more complicated in 3.0.
--NOTE: This is called from a PreThinkFrame, allowing me to edit player controls in this function!
rawset(_G, "SMSDoWallJump", function(s,p)
	if (s.SMS_WallJumpTable and s.SMS_WallJumpTable.timer == 22)
	or not s.SMS_hitwall
	or P_PlayerInPain(p)
	or (s.SMS_HomingBolt and s.SMS_HomingBolt.preptimer)
		return --Literally just walljumped, wait a few tics...
	end	
	if s.SMS_WJpenalty == nil --Convenience sake.
	or (p.pflags & PF_STARTJUMP) and (s.momz*P_MobjFlip(s) > 2*s.scale) and (p.pflags & PF_JUMPED)
	and not (p.pflags & (PF_THOKKED|PF_NOJUMPDAMAGE)) and (p.panim == PA_JUMP)
		s.SMS_WJpenalty = 0
	elseif s.SMS_preWJautopenalty != nil 
		if (s.SMS_WJpenalty > s.SMS_preWJautopenalty)
		and (s.state != S_SMS_AIRBOOST) and not p.sms_stompanim
			s.SMS_WJpenalty = s.SMS_preWJautopenalty --Don't screw over players using the old thok method.
		end
	end
	local AUTOJUMP = s.SMS_WJauto
	s.SMS_preWJautopenalty = nil
	s.SMS_WJauto = 0
	if s.SMS_squashtable
		s.spritexscale,s.spriteyscale = FRACUNIT, FRACUNIT
		s.spriteyoffset,s.spritexoffset = 0,0
		s.SMS_squashtable = nil
	end
	
	local DIST = 36*s.scale --45
	local HEIGHT = 13*FRACUNIT --18. Must be FRACUNITs. Jumped up about 3 squares over the runshoes in GFZ2 in pre v2.6 SMSreborn.
	local BSPEED = 20*s.scale --Burst Speed, the initial burst of speed you get from a walljump.
	local BHEIGHT = 9*s.scale --Burst height
	local UW = ((s.eflags & MFE_UNDERWATER) or p.powers[pw_underwater]) and true or false --is false if we're not underwater.
	
	local PENALTY = 0 --How much will be subtracted from your height.
		--Underwater debuff!
		if UW 
			if (s.eflags & MFE_GOOWATER)
				s.SMS_WJpenalty = 0 --Punished enough already.
			elseif s.SMS_WJpenalty
				s.SMS_WJpenalty = $/2
			end
			if not (p.powers[pw_sneakers] and (G_PlatformGametype() and not s.battlemodsms))
				HEIGHT = 5*FRACUNIT+9001
				DIST = 18*s.scale
				BHEIGHT = 7*s.scale-9001
			end
		end	
		--Minor modifiers...
		if not (DIST >= 26*s.scale)
			if p.sms_stompanim or p.sms_afterstompthok
				P_SpawnMobjFromMobj(s, 0,0,0, MT_SPINDUST)
				S_StartSoundAtVolume(s, sfx_skid, 144)
			end	
		else --Full Power Walljump!
			A_SMSquake(s, 19*FRACUNIT, 3, 255, true)			
		end
		
	--Setup for more stuff.	
	local JUMPANGLE = s.angle+ANGLE_180
	local LINE = nil --NOTE: Can actually be an object at times! Check if frontsector and v1 are both nil for that.
	local LINEX = s.x
	local LINEY = s.y
	local LINEANGLE = JUMPANGLE --Our found angle TOWARDS the line. Will be messed with sometimes.
	local LINEANGLEOG = LINEANGLE --Will remain the first-picked LINEANGLE value before it's messed with.
	local ANGSHIFT,PLUS = 0,1 --We don't always HAVE to shift angle from the wall. But we might.
	
	local STRAIGHTJUMP = false --The styles of walljump we'll end up doing.
	local SIDEFLIP = 0 --0 is no sideflip, 1 is sideflip, 2 is handstand sideflip(weak jump)!
	local WALLBOUNCE = false
	local KICKJUMP = false
	local TURNAROUND = false
	
	local NUM = nil --Can be nil at times
	local FORWARDMOVE = p.cmd.forwardmove --Our controls BEFORE we start messing with it.
	local SIDEMOVE = p.cmd.sidemove
	local SMOMZ = s.momz --Our momentum BEFORE we start messing with it.
	
	local yu = p.smsrtable or {}
	yu.turnang = (p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, FORWARDMOVE<<16, -(SIDEMOVE<<16)))
		
		--=============================WALLS + ANGLES=======================================	
		
		local FOUNDAWALL --Keep track of if we find at least 1 wall.
		if s.SMS_hitwall --Sometimes you walljump off objects, so it's not ALWAYS valid!	
					
			local PRIORITIES = SMS_SetPriority(s,p) --This functions orders the missiles based on preferred priority!
			--Missile numbers are -from: FRONT[0], LEFT[1], BACK[2], RIGHT[3]			
			for d = 1,4 local i = PRIORITIES[d] --Check all the missiles in our table!	
				if PRIORITIES[d] == nil or not (s.SMS_hitwall[i] and s.SMS_hitwall[i].valid)
					continue --No wall found in this direction. Try the next one!
				end
				FOUNDAWALL = true		
				NUM = i
				LINE = s.SMS_hitwall[i] --This is the line we found!
				
				if not twodlevel
				and not (s.flags2 & MF2_TWOD)
					if (p.pflags & PF_ANALOGMODE)
					and (FORWARDMOVE or SIDEMOVE) --We need to alter controls to make more sense in analog mode.
						local TURNANG = SMS_PlayerAngle(s,p)
						local MOMANG = SMS_PlayerAngle(s,p, true)
						local trueturn = (SMS_PlayerAngle(s,p)-SMS_PlayerAngle(s,p, true))
						if trueturn
							trueturn = abs(abs($/ANG1)-90)							
							if i == 0 and (p.speed < 3*s.scale)
							and (abs(FORWARDMOVE) < 4) and (abs(SIDEMOVE) > 46) --hyperspecific situation.
								FORWARDMOVE = 50
								SIDEMOVE = 0
							elseif (trueturn < 38) --Convert forwardmove into positive and include some sidemove!
								FORWARDMOVE = min(abs(FORWARDMOVE)+abs(SIDEMOVE/3), 50)
								if SIDEMOVE < 0
									SIDEMOVE = min($+FORWARDMOVE, 0)
								else
									SIDEMOVE = max($-FORWARDMOVE, 0)
								end
							end
						end
					end
				end
				
					if LINE.frontsector == nil and LINE.v1 == nil  --The line is actually a Mobj?! ...pretend it's a line anyway.	
					local mX,mY = (NUM == 0 or LINE.SlopedJump) and s.momx/2 or 0, (NUM == 0 or LINE.SlopedJump) and s.momy/2 or 0
					local PX,PY = s.x-mX, s.y-mY	
					
						--Use previously recorded coordinates for mobjs for better accuracy?
						if LINE.SMS_LastWJX != nil
						and not (FixedHypot(s.x-LINE.SMS_LastWJX, s.y-LINE.SMS_LastWJY) > 320*s.scale+(abs(s.momx)+abs(s.momy)))
							PX,PY = LINE.SMS_LastWJX-mX, LINE.SMS_LastWJY-mY
						end

						--Angle towards the mobj.
						if LINE.SlopedJump and LINE.SlopedJump.xydirection != nil --Use slope direction instead!
							LINEANGLE = LINE.SlopedJump.xydirection+((LINE.SlopedJump.zdelta > 0) and ANGLE_180 or 0)
						else
							LINEANGLE = R_PointToAngle2(PX, PY, LINE.x, LINE.y)
						end
						LINE.SMS_LastWJX, LINE.SMS_LastWJY = nil
						LINEX,LINEY = LINE.x, LINE.y
						
				/*		--DEBUG MOBJ, shows where our reference point is.
						for i = 1,9,8
							local ghs = P_SpawnMobj(LINE.x, LINE.y, s.z, MT_THOK) 
							ghs.color = i == 1 and SKINCOLOR_SUPERSILVER1 or SKINCOLOR_BLACK
							ghs.frame = ($ & ~FF_TRANSMASK)|(i == 1 and FF_TRANS10 or FF_TRANS70)
							ghs.renderflags = RF_FULLBRIGHT|RF_NOCOLORMAPS
							ghs.scale = $*i
							ghs.spriteyoffset = (i != 1) and -22*FRACUNIT or 0
							ghs.state = S_THOK ghs.tics = 199 ghs.fuse = 199
						end */
						
					else --Angle towards the line.
					
						LINEX,LINEY = P_ClosestPointOnLine(s.x, s.y, LINE)
						LINEANGLE = R_PointToAngle2(s.x, s.y, LINEX, LINEY) 
						
					end
							
				LINEANGLEOG = LINEANGLE
							
				--Okay, make sure we're not on a floor, that could curl our jumps wrong.
				if (s.eflags & MFE_VERTICALFLIP)
					if (s.ceilingz-(99*s.scale) < s.z+s.momz)
						s.z = $-s.scale*4
					end
				elseif (s.floorz > s.z+s.momz+(99*s.scale) )
					s.z = $+s.scale*4
				end
				if (s.momz*P_MobjFlip(s) < s.scale)
					P_SetObjectMomZ(s, FRACUNIT)
					s.eflags = $ & ~MFE_JUSTHITFLOOR
				end
				
				--Now that we have our info, let's make some calculations happen!
				if i == 0 --The wall is in FRONT of you!

					if SMS_AngleDifference(s.angle, R_PointToAngle2(s.x, s.y, LINEX, LINEY), 2) > ANG1*130
						LINEX = $-FixedMul(199*s.scale+abs(s.momx), cos(s.angle))
						LINEY = $-FixedMul(199*s.scale+abs(s.momy), sin(s.angle))
						LINEANGLE = R_PointToAngle2(s.y, s.x, LINEX, LINEY) --Emergency snap from front missile.
					end	
					
					if (FORWARDMOVE > 22) --Putting in input for the straightjump, referencing SMSunleashed20!
					and not ((abs(SIDEMOVE) > 10) and not AUTOJUMP)
					
						STRAIGHTJUMP = true --Record this input so we keep facing the wall.
						DIST = $/3
						
						if UW --Underwater slow-as-crap jump.
						
							HEIGHT = $+(5*FRACUNIT/3)
							BHEIGHT = max($-4*s.scale, 0) --Reduce bonus height and increase regular height.
							
						elseif ((p.sms_boostlevel > 64) or (p.powers[pw_sneakers]))
						and not (p.cmd.buttons & (BT_TOSSFLAG|BT_CUSTOM2|BT_CUSTOM3))
						and (s.SMS_WJpenalty < 101) --Sacrifice speed for a huge jump.
							
							local ghs = P_SpawnMobjFromMobj(s,0,0,-s.height*2,MT_THOK)
							ghs.flags2 = $|MF2_DONTDRAW 
							ghs.tics = 99
							S_StartSound(ghs, sfx_s251)
							S_StartSound(ghs, sfx_s3k81)
							S_StartSoundAtVolume(ghs, sfx_doord2, 140)
							
							s.sms_boostloss = 0
							STRAIGHTJUMP = 777
							DIST = $/3
							HEIGHT = $+11*FRACUNIT+9999
							BHEIGHT = $+FRACUNIT+9999
							A_SMSquake(s, 69*FRACUNIT, 5, 310)
							if SMS_Graphix(s) != 2
								SMS_ElectricRecoil(s)
								SMS_RisingFlames(s)
							end
							
							if (p.sms_boostlevel > 65)
								s.SMS_WJpenalty = max( ((p.sms_didairboost) and $-31 or (($ or 1)/2)-42) ,0)  --Remove more penalty
								if p.powers[pw_sneakers] --Speeeeeeeeeed
									BHEIGHT = $+12*FRACUNIT
								end
								p.sms_boostlevel = 0
							else
								s.SMS_WJpenalty = $+25
							end
						else
							HEIGHT = $+4*FRACUNIT
							BHEIGHT = $+5*FRACUNIT+999
						end
						if (s.SMS_WJpenalty < 17)
							s.SMS_WJpenalty = 0
						end
						JUMPANGLE = LINEANGLEOG+ANGLE_180 --The new wall-facing angle!
						if LINE.v1 == nil and LINE.frontsector == nil and LINE.SlopedJump != nil
							DIST = 1
							BSPEED = 1
						end
						
					elseif (abs(FORWARDMOVE) < 3) and (abs(SIDEMOVE) < 3) //and not UW
					or ((FORWARDMOVE < -22) and not (abs(SIDEMOVE) > 20) and not (p.pflags & PF_ANALOGMODE))
					
						HEIGHT = $+FRACUNIT --Doing a turn-around jump from the wall in front of you!
						BHEIGHT = $+(3*FRACUNIT)
						JUMPANGLE = LINEANGLEOG+ANGLE_180 --The new wall-facing angle!
						TURNAROUND = true
						if ((p.sms_boostlevel > 64) or p.powers[pw_sneakers]) --Add more AGAIN!
						and not (s.eflags & MFE_UNDERWATER)
							HEIGHT = $+10555
							BHEIGHT = $+113535
							DIST = $+2*FRACUNIT
						end
						
					else
						JUMPANGLE = LINEANGLEOG+ANGLE_180
						WALLBOUNCE = true --Backflipping off the wall.
						HEIGHT = min($, 11*FRACUNIT+28005)  --Limit on this one.				
					end
					
				--=====================================================================	
				else --It's NOT the wall in front of you!  Missile numbers are -from: FRONT[0], LEFT[1], BACK[2], RIGHT[3]
				--=====================================================================	
				
					JUMPANGLE = LINEANGLE+ANGLE_180 --Jump AWAY from the wall rather than towards.

					if i == 2 --The wall's BEHIND you!
						if not UW
							HEIGHT = $+(FRACUNIT+450)
							BHEIGHT = $+(3*FRACUNIT)
						end
						s.spritexscale = FRACUNIT+14000
						s.spriteyscale = FRACUNIT-9000
						KICKJUMP = true
						if not s.SMS_ControlAlter
							s.SMS_ControlAlter = {timer = 6, minforwardmove = 0}
						else
							s.SMS_ControlAlter.minforwardmove = 0
							s.SMS_ControlAlter.timer = $+3
						end
						if ((p.sms_boostlevel > 64) or p.powers[pw_sneakers]) 
						and not (s.eflags & MFE_UNDERWATER)
							HEIGHT = $+14500
							BHEIGHT = $+9900
							DIST = $+3*FRACUNIT
						end
					else --You're jumping from the SIDE walls!
					
						local XANG,RIGHTLEFT = SMS_AngleDifference(s.angle, R_PointToAngle2(s.x, s.y, LINEX, LINEY), 2)
						if RIGHTLEFT == -1 and i == 3 --Right is 3. It needs 1 to function. If we got to -1, we're fucking up.
						or RIGHTLEFT == 1 and i == 1
							LINEX = $+FixedMul(199*s.scale+abs(s.momx), cos(s.angle+(ANGLE_90*i)))
							LINEY = $+FixedMul(199*s.scale+abs(s.momy), sin(s.angle+(ANGLE_90*i)))
							LINEANGLE = R_PointToAngle2(s.y, s.x, LINEX, LINEY)
							JUMPANGLE = LINEANGLE+ANGLE_180 --Jump AWAY from the wall rather than towards.
						end
						
						if LINE.v1 == nil --Be more rigid from mobjs.
							p.cmd.forwardmove,p.cmd.sidemove = 0,0 //,s.momx,s.momy,yu.direct = 0,0,0,0,0
						elseif SIDEMOVE --Force player to hold away from the wall at least a bit.
							if (abs(SIDEMOVE) > 35)
								p.cmd.forwardmove = $/3
							end
							p.cmd.sidemove = 0
						end
						
						--Don't allow steering back to the wall a tic.
						s.SMS_ControlAlter = {
						timer =  LINE.v1 == nil and 15 or 1,
						maxsidemove = (NUM != 3) and 50 or 0,
						minsidemove = (NUM == 3) and -50 or 0,
						sidemove = p.cmd.sidemove,
						forwardmove = p.cmd.forwardmove,
				--		analogangle = yu.turnang,
				--		analogdiff = 30,
				--		analogpunish = 100,
						}
						SIDEFLIP = 1
					end
				end	

				LINEANGLE = JUMPANGLE --Final angle determined.
				break --Everything checks out for this one, so call off the calculations for the rest!
			end
		end
		
		if not FOUNDAWALL return end --None found at all...???
		
		--=============================PLAYER INPUT ANGLE=======================================			
		--If we're holding a strong direction, influence SMS' final walljump angle, as well as height/speed.
		
		if not STRAIGHTJUMP
			if (p.sms_boostlevel < 65) --Gain boostlevel to help with struggling recoveries or just gain a bit of speed.
				if p.sms_didairboost 
					if SIDEFLIP --THIS looks real cool, I wanna reward it.
						p.sms_boostlevel = $+14
					end
				elseif (s.SMS_WJpenalty < 55)
				or (not WALLBOUNCE and (s.SMS_WJpenalty < 99))
					p.sms_boostlevel = (SIDEFLIP or WALLBOUNCE) and $+4 or $+7
				end
			end
			local maxang = (WALLBOUNCE) and ANG1*25 or ANG1*16 --Maximum amount SMS can instantly shift angle off the wall.	
			if (p.sms_boostlevel > 64) --Increase jumpspeed massively in boostmode or from airboosts.
			or p.sms_didairboost
				BSPEED = $*2
				DIST = $+(DIST/2)
				BHEIGHT = $+40000
				PENALTY = -40000
				maxang = (ANG1*30)
			end
			if (yu.direct > 4)
			and not TURNAROUND
			and LINE.v1 != nil --Not on Mobjs/Slopes!
				if SIDEFLIP
				or WALLBOUNCE and (abs(p.cmd.sidemove) > 30)
				or KICKJUMP and (abs(p.cmd.forwardmove) > 30)
					local WALLTURNANGLE = (p.cmd.angleturn<<16)+(R_PointToAngle2(0, 0, FORWARDMOVE<<16,-(SIDEMOVE<<16)))
					ANGSHIFT,PLUS = SMS_AngleDifference(JUMPANGLE, WALLTURNANGLE, 2)
					JUMPANGLE = $-(min(maxang, ANGSHIFT)*PLUS)/2
					
				--	local ghs = P_SpawnMobjFromMobj(s,0,0,0, MT_THOK) DEBUG THOK.
				--	P_Thrust(ghs, JUMPANGLE, 6*FRACUNIT)
				--	ghs.tics,ghs.fuse = 199,199
				end
			end
		end
		
		--=============================HEIGHT PENALTIES=======================================	
		--Now calculate the height penalties to your walljump!
		
		--State penalty! Some states give various penalties to your walljumpheight, like airboosting/thokking/stomping.
		if (s.SMS_WJpenalty > 83)
			PENALTY = $+ ((s.SMS_WJpenalty*FRACUNIT)/9)
		elseif s.SMS_WJpenalty
			PENALTY = $+ ((s.SMS_WJpenalty*FRACUNIT)/11)
		end
		
		--Repetitive walljump penalty! Keep jumping off similar angled walls and you won't gain height for long.
		if s.SMS_lastwallANG != nil and LINEANGLE != nil 
			local prevANG = s.SMS_lastwallANG	
			local nextANG = LINEANGLE		
			--Compare angles real quick...
			local diff = (nextANG-prevANG)
			if (diff > ANGLE_180)
				diff = InvAngle(InvAngle(diff)/2)
 			else
				diff = $/2
			end
			if (diff > 0)
				diff = AngleFixed(diff)
			elseif diff
				diff = abs(AngleFixed(diff)-360*FRACUNIT)
			end
			local AnglePenalty = max(0, 11*FRACUNIT-(diff/6))
			if (AnglePenalty <= 2*FRACUNIT) --A bit of forgiveness.
				AnglePenalty = 0
			end
			PENALTY = $+AnglePenalty	
		end		
		if NUM != nil and s.SMS_lastwallNUM == NUM
			PENALTY = $+(FRACUNIT*2+18000) --Trying the same wallside, 2 FRAC penalty!
		end
		--Falling fast subtracts somewhat from walljump height.
		if (SMOMZ*P_MobjFlip(s) < -10*FRACUNIT) --Don't use *s.scale!
			if (HEIGHT-PENALTY > 4*FRACUNIT)
				PENALTY = $+ min(abs(SMOMZ), 50*FRACUNIT)/25 --Up to 2*FRAC penalty.
			else
				PENALTY = $+ min(abs(SMOMZ), 50*FRACUNIT)/40
			end
		--PERFECT jump? Gain extra height for the turnaround/kickjumps!	
		elseif (PENALTY >= -40000) and not (s.eflags & MFE_UNDERWATER)
			if (p.sms_boostlevel > 64)  
				if PENALTY != 0
					PENALTY = $*5/6
				end
				if (TURNAROUND or KICKJUMP)
					HEIGHT = $+40000 
					BHEIGHT = $+FRACUNIT
					BSPEED = $+4*s.scale
					S_StartSoundAtVolume(s, sfx_s227, 70)
				end
			end
		end
		
		--=============================APPLY JUMP=======================================
		--Lastly, subtract penalties from total height and set a height cap!
		HEIGHT = max($-PENALTY, -29*FRACUNIT)
		if (HEIGHT < 0) HEIGHT = $/2 end
		
		if (HEIGHT < FRACUNIT)
			BHEIGHT = 0
			if not STRAIGHTJUMP and not WALLBOUNCE //(p.cmd.forwardmove > 30) --No bonus speed here.
				BSPEED = 0
			end
		end

		--Finally, LAUNCH! Walljump away!
		P_InstaThrust(s, JUMPANGLE, DIST)
		if (s.eflags & MFE_GOOWATER) and (HEIGHT < 12*FRACUNIT) and UW
			P_SetObjectMomZ(s, FRACUNIT*12)	--Minimum amount for goowater.
			HEIGHT = 12*FRACUNIT
		elseif (HEIGHT >= FRACUNIT) and (SMOMZ*P_MobjFlip(s) > HEIGHT)
			if STRAIGHTJUMP and (HEIGHT >= 8*FRACUNIT)
				P_SetObjectMomZ(s, (HEIGHT/5), true) --P_SetObjectMomZ scales, so use FRACUNIT instead of *s.scale
			else
				if (p.sms_boostlevel > 64) and (TURNAROUND or KICKJUMP)
					P_SetObjectMomZ(s, (HEIGHT/8)+FRACUNIT, true)
				else
					P_SetObjectMomZ(s, (HEIGHT/8), true)
				end
			end
		else
			P_SetObjectMomZ(s, HEIGHT)
		end
		if (twodlevel or (s.flags2 & MF2_TWOD))
			s.momy = 0
		end
		
		--Sneakers give a WILD walljump
	/*	if p.powers[pw_sneakers] and not G_GametypeHasSpectators()	
			A_SMSSTOMPSMOKE(s, 24, MT_THOK, nil, nil, nil, s.color)
			P_SetObjectMomZ(s, 27*FRACUNIT, true)
			s.sneakerjcd = 4
			s.sneakerwc = true
			if UW
				s.sneakjuw = 7
			else
				s.sneakjuw = 10
			end
			s.sneakerjumpgfx = true
		end */

		--=============================SET ANIMATION+VARIABLES=======================================

		s.SMS_HomingBolt = nil
		S_StopSoundByID(s, skins["sms"].soundsid[SKSTHOK])
		s.airboostroll = 0
		s.rollangle = 0
		s.state = S_SMS_WALLJUMP --Set state, even if we might use different frames entirely.
		if p.powers[pw_flashing] and p.powers[pw_flashing] < 47 --Stop some extra ringburst properties!
		and p.sms_flamedelay and p.sms_flamedelay < 47
			p.powers[pw_flashing] = 0
			s.flags2 = $ & ~MF2_DONTDRAW
			if s.smssoundobj9 and s.smssoundobj9.valid
				P_KillMobj(s.smssoundobj9)
			end
			S_StopSoundByID(s, sfx_smsrbt)			
		end

		--Determine our animation!
		if STRAIGHTJUMP --Straight up the wall! Resembles the old-school walljump a little.
		
			p.cmd.forwardmove = 0
			s.SMS_ControlAlter = {
			timer = 40,
			maxforwardmove = 28,
			minforwardmove = -28,
			maxsidemove = 28,
			minsidemove = -28,
			freecondition = 1
			}	
			s.SMS_WJpenalty = $+85
			s.spritexscale = FRACUNIT-20000
			s.spriteyscale = FRACUNIT+20000
			
		else --Most other walljumps.
		
			SMSWindLines(s, p, true)
			s.SMS_WJpenalty = $+11 --Always add 11.
			
			if NUM == 1 or NUM == 3  --Jumped from side walls?
				if NUM == 1 --From the left!
					s.rollangle = -ANG1*70
				else --From the right!
					s.rollangle = ANG1*70
				end
				s.sprite = SPR_SMSO
				s.frame = ($ & ~FF_FRAMEMASK)|Q
				s.spritexscale = FRACUNIT+5000
				s.spriteyscale = FRACUNIT-5000

			else --Jumping from back or front walls.
			
				s.spritexscale = FRACUNIT-12000
				s.spriteyscale = FRACUNIT+12000		
				
				if not (abs(p.cmd.sidemove) > 10)
					if not s.SMS_ControlAlter
						s.SMS_ControlAlter = {timer = 3,turnangle = JUMPANGLE}
					else
						s.SMS_ControlAlter.turnangle = JUMPANGLE
					end
					s.angle = JUMPANGLE
					p.drawangle = JUMPANGLE
				end
				
				if NUM == 0 --Jumped from the wall in front of you?
					if not STRAIGHTJUMP
						if (abs(p.cmd.sidemove) > 10) and (p.cmd.forwardmove > 24)
							s.SMS_WJpenalty = $+15
							TURNAROUND = false
						end
					end
				elseif NUM == 2
					SIDEFLIP = 0
					WALLBOUNCE = false
					KICKJUMP = true
					if (s.SMS_WJpenalty > 90)
						s.SMS_WJpenalty = $-12 --Refund for backwards walljumps!
					end
				end
			end
			if WALLBOUNCE
				SIDEFLIP = 0
				s.SMS_WJpenalty = $+2 --Very minor extra penalty.
				s.SMS_ControlAlter = {
				timer = 5,
				maxforwardmove = 35,
				minforwardmove = -35,
				freecondition = 1
				}	
			elseif SIDEFLIP == 1
				s.SMS_WJpenalty = $+2
				if (HEIGHT < 5*FRACUNIT) and not UW 
				or (HEIGHT < 3*FRACUNIT-15000)
					SIDEFLIP = 2 --Use handstand walljump for weakened ones.
					s.sprite = SPR_SMSO
					s.frame = ($ & ~FF_FRAMEMASK)|N
					s.spriteyscale = FRACUNIT-12000
					s.spritexscale = FRACUNIT+15000
					if NUM == 1
						p.drawangle = $-ANGLE_45
					elseif NUM == 3
						p.drawangle = $+ANGLE_45
					end
				end
			end	
		end
		if p.sms_didairboost and (s.SMS_WJpenalty > 60) --Recover quicker!
			s.SMS_WJpenalty = max($-30,0)
		end
		s.SMS_wallwait = 1
		--Snap to walls horizontally, but not mobjs and ESPECIALLY not slopes!
		if LINE.v1 != nil and LINE.frontsector != nil --Only linedefs have v1 and frontsector normally.
			for SNAP = 1,60 --Snap to your origin wall and jump from there! Capping at 60 for sanity.
				if not P_TryMove(s, s.x+FixedMul(s.scale*3, cos(LINEANGLEOG)), s.y+FixedMul(s.scale*3, sin(LINEANGLEOG)), true)
					break --
				end
			end
		elseif LINE.SlopedJump
			s.SMS_wallwait = 7
			s.eflags = $ & ~MFE_JUSTHITFLOOR
		end	
		s.SMS_locked = true --Crucial frame to be protected!
		p.secondjump = 0
		p.pflags = $|PF_JUMPED|PF_JUMPDOWN & ~(PF_THOKKED|PF_STARTJUMP|PF_SPINNING|PF_STARTDASH|PF_SLIDING|PF_NOJUMPDAMAGE)
		p.smsmeleebutton = 850
		if (p.cmd.buttons & BT_CUSTOM1)
			p.sms_c1 = 850
		end
		p.hometrickanim = false
		p.homingtrickcharge = 0		
		p.sms_stompanim = 0 --Cancel stomp properties
		p.sms_afterstompthok = false
		p.sms_didairboost = 0
		
		if LINEANGLE != nil and LINE and LINE.valid
			s.SMS_lastwallANG = LINEANGLE --Record this as the last wallangle we used
		else
			s.SMS_lastwallANG = nil
		end
		if NUM != nil
			s.SMS_lastwallNUM = NUM
		end
		s.SMS_removeWD = 0
		s.SMS_wallready = 0
		SMS_WallJumpDelete(s, true) --Delete remaining wall "checkers" and table.
		
		--Setup walljump table, a temporary haven to store our data.
		s.SMS_WallJumpTable = {
		timer = 22,  --Amount of tics to keep table alive.
		straightjump = STRAIGHTJUMP, --Did we jump straight up?
		turnaround = TURNAROUND, --Incase of a frontal non-straight walljump, did we turn?
		sideflip = SIDEFLIP, --do a sideflip?
		wallbounce = WALLBOUNCE, --a backflip?
		kickjump = KICKJUMP, --Kick from a wall behind you?
		angle = JUMPANGLE, --Final angle we're actualy jumping
		line = LINE, --Wall
		lineangle = LINEANGLE, --Wall angle
		angshift = ANGSHIFT,  --Amount we've shifted from the wallangle
		plus = PLUS,
		number = NUM, --Which direction we've walljumped from
		BSPEED = BSPEED, --Bonus speed.
		BHEIGHT = BHEIGHT, --Bonus height.
		jumpheight = HEIGHT, --Regular walljumpheight 
		underwater = UW --Where we underwater before this began?
		}
		
		--You cannot chain walljumps in matches/battlemod!
		if G_GametypeHasSpectators() or s.battlemodsms
			s.SMS_WJpenalty = max($, 180)
		end
		--=============================SPAWN WALLJUMP GFX=======================================	
		
		if UW --Underwater effect.
			for i = 1,4 
				A_BossScream(s, 0, MT_SMALLBUBBLE)
			end
		else --Regular.
			if (BHEIGHT > FRACUNIT) --Big enough jump?		
				SMS_WallJumpGFX(s)
				if STRAIGHTJUMP 		
					local ghs = SMS_WindJumpGFX(s)
					if ghs and ghs.valid
						ghs.fuse = 7
						ghs.flags2 = $|MF2_SHADOW
					end	
					local ghs = SMS_GroundWindBlast(s)
					if ghs and ghs.valid
						ghs.spriteyscale = FRACUNIT-15000
					end
				end
			else --Minor effect.
				local ghs = SMS_WallJumpGFX(s, true)
				if ghs and ghs.valid
					ghs.spritexscale = $/2
					ghs.spriteyscale = $/2
				end
			end
		end
		--=============================WALLJUMP SFX=======================================
		
		local SOUND = sfx_smsfx2 --Struggling walljump as default
		if STRAIGHTJUMP
			if (HEIGHT >= 6*FRACUNIT)
				if STRAIGHTJUMP == 777
					SOUND = sfx_bljp
					SMS_WallBustPower(s,p)
					local ghs = SMS_ElectricBody(s, 3, SKINCOLOR_SMS5R)
					ghs.mirrored = true
					if SMS_Graphix(s) != 2
						SMS_LightClash(s, SKINCOLOR_WHITE, s)
						for i = 0,1
							ghs = SMS_LightningStrike(s, SKINCOLOR_SMS4R, R)
							ghs.dispoffset = 50
							ghs.z = $+s.momz//-(150*s.scale*i)
							ghs.frame = (i == 1) and $|FF_VERTICALFLIP or $
							ghs.scalespeed = $/2
							ghs.destscale = $*99
							ghs.momz = FixedDiv(FixedMul(s.momz, 25), 31)
							ghs.momx = FixedDiv(FixedMul(s.momx, 25), 36)
							ghs.momy = FixedDiv(FixedMul(s.momy, 25), 36)
						end
					end
				else
					SOUND = sfx_smsfx3
					local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK)
					ghs.flags2 = MF2_DONTDRAW ghs.tics = 99
					S_StartSoundAtVolume(ghs, sfx_s3k81, 122)					
				end
			end	
		elseif WALLBOUNCE
			SOUND = sfx_smsfx4
		elseif (SIDEFLIP == 1) or (HEIGHT >= 5*FRACUNIT)
		or (HEIGHT >= 3*FRACUNIT-15000) and UW
			SOUND = sfx_bljpw
		end
		if TURNAROUND 
			s.spritexscale = FRACUNIT+14000
			s.spriteyscale = FRACUNIT-9000
		end
		local ghs = P_SpawnMobjFromMobj(s, 0,0,0, MT_THOK) --Always add this sound.
		ghs.flags2 = MF2_DONTDRAW ghs.tics = 69
		S_StartSound(ghs, sfx_s251)
		
		S_StartSound(s, SOUND) --Chosen walljump sound!
		return true --You did it!
end)

--Actively walljumping! 
--This is the main walljumping hook after performing the move, it keeps track of everything!
--"WJ" is s.SMS_WallJumpTable, while "yu" is p.smsrtable. Basically, the walljumpthinker"
rawset(_G, "SMS_WallJumping", function(s,p, WJ, yu)
	if WJ.timer <= 1 --Cancel!
		SMS_WallJumpDelete(s, true)
		return false --
	end
	if (s.eflags & MFE_UNDERWATER) --Penalty for entering water mid-walljump
		if not WJ.underwater
			WJ.underwater = true
			s.momz = $/3
			s.momx = $/2 s.momy = $/2
		end
	end
	if WJ.timer
		WJ.timer = $-1
		if WJ.straightjump
			s.spritexscale = min($+6000, FRACUNIT)
			s.spriteyscale = max($-6000, FRACUNIT)
			s.spriteyoffset = max($-2*FRACUNIT, 0)
		end
		if (WJ.timer > 18) --Initial boost and animation!
		
			if WJ.timer >= 21
				s.SMS_locked = true --Crucial frame.
				SMS_WallJumpDelete(s) --No info at this stage!
			end
			
			if WJ.straightjump --Doing an upwards spring jump!
				if WJ.timer == 19
					p.pflags = $|PF_JUMPED|PF_THOKKED & ~PF_STARTJUMP & ~PF_STARTDASH				
					if (s.momz*P_MobjFlip(s) > 10*s.scale)
					or (s.eflags & MFE_UNDERWATER) and (s.momz*P_MobjFlip(s) > 4*s.scale)
						s.state = S_PLAY_SPRING
						s.eflags = $ & ~MFE_SPRUNG
						p.hometrickanim = false
						if (p.cmd.buttons & BT_CUSTOM2)
							p.smsmeleebutton = 850
							SMS_SideFlip(s, p)
						else
							local ghs = SMS_GroundWindBlast(s)
							ghs.flags2 = $|MF2_SPLAT
							ghs.spriteyscale = $/2
							ghs.spritexscale = $/2
							ghs.tracer = s
							ghs.ditchtracer = 3		
							ghs.GSoffsetX = -s.scale
							ghs.GSoffsetY = -s.scale
							ghs.GSoffsetZ = -s.height/2
						end
					else
						s.state = S_PLAY_ROLL
					end
				elseif (WJ.timer > 19)
					p.smsmeleebutton = 850
					s.SMS_wallwait = 4
					if WJ.timer == 21 --The very first tic we experience in this thinker.
						s.spritexscale = FRACUNIT-22000
						s.spriteyscale = FRACUNIT+22000
						s.spriteyoffset = 13*FRACUNIT
					end
				end 
			else --Doing ANY other kind of walljump!
				if WJ.sideflip and not WJ.wallbounce
					if WJ.timer == 19
						if WJ.sideflip != 2
							s.rollangle = (WJ.number == 1) and -ANG1*80 or ANG1*80
							SMS_SideFlip(s, p)
						end				
						if (WJ.number == 1) --Override!
							s.hmsrotateright = true
						else
							s.hmsrotateright = false
						end
						SMS_WallJumpGFX(s, nil, true)
						s.spritexscale = FRACUNIT
						s.spriteyscale = FRACUNIT
					end
				end
				
				 --Jumped from walls to your left or right? 
				if (WJ.number == 1) or (WJ.number == 3) 
					if (WJ.timer > 19) and WJ.sideflip != 2
						s.rollangle = (WJ.number == 1) and -ANG1*65 or ANG1*65		
						s.sprite = SPR_SMSO
						s.frame = ($ & ~FF_FRAMEMASK)|Q
						s.spritexscale = min($+5000, FRACUNIT+22000)
						s.spriteyscale = max($-5000, FRACUNIT-22000)
					end
				else --Nope, front or back wall.
					s.spritexscale = max($-4000, FRACUNIT)
					s.spriteyscale = min($+2500, FRACUNIT)
				end
				
				SMSRSpawnGhost(s, 5) --Always spawn these in the first few tics.
			end
			
			p.pflags = $|PF_JUMPDOWN
			
			--Rapidly rise!
			if WJ.BHEIGHT 
				if (s.eflags & MFE_VERTICALFLIP)
					for i = 1,8
						if (s.z-(WJ.BHEIGHT/8) > s.floorz)
							s.z = $-(WJ.BHEIGHT/8)
						end
					end
				else --non-flipped.
					for i = 1,8
						if (s.z+(WJ.BHEIGHT/8) < s.ceilingz)
							s.z = $+(WJ.BHEIGHT/8)
						end
					end
				end
			end
			
			--Rapidly shoot forwards.
			if WJ.BSPEED 
				if (twodlevel or (s.flags2 & MF2_TWOD))
					s.momy = 0
				else
					local no = (s.eflags & MFE_UNDERWATER) and 3 or 7
					for i = 1,no
						if (P_TryMove(s, 
						s.x+FixedMul(WJ.BSPEED/5, cos(WJ.angle)),
						s.y+FixedMul(WJ.BSPEED/5, sin(WJ.angle)),
						true) )
							local ghs = P_SpawnGhostMobj(s)
							ghs.blendmode = AST_ADD
							ghs.tics = 3+(i/2)
							ghs.scale = (s.scale/8)*i
							ghs.colorized = true
							ghs.color = SKINCOLOR_MYSTICAL3
							ghs.momx = s.momx/4
							ghs.momy = s.momy/4
							ghs.momz = s.momz/2
							ghs.frame = ($ & ~FF_TRANSMASK)|FF_TRANS90-((i/3)*FRACUNIT)
						end
					end
					if not WJ.straightjump
						SMSWindLines(s, p, true)				
					end
				end
			end
			if (WJ.number == 0 or WJ.wallbounce) --Push further away from the wall!
			and not (twodlevel or (s.flags2 & MF2_TWOD))
				if WJ.lineangle != nil
				and not WJ.straightjump
					local SPED = WJ.BSPEED or 14*s.scale
					for i = 1,7
						P_TryMove(s, s.x+FixedMul(SPED/3, cos(WJ.lineangle)), s.y+FixedMul(SPED/3, sin(WJ.lineangle)), true)
					end
				end
			end				

			--Jump sparkle trail!
			local rng = SMSLocalRNG(11,22,s)-10
			local ghs = P_SpawnMobjFromMobj(s,s.momx*2,s.momy*2,(s.height/rng)+s.momz, MT_IVSP)
			ghs.fuse = 6+(rng/2)
			ghs.tics = 99
			ghs.anim_duration = 99
			ghs.scale = max(s.scale,(s.scale*8/rng))
			ghs.colorized = true	
			ghs.momx = s.momx/3
			ghs.momy = s.momy/3
			ghs.momz = s.momz/3
			if (WJ.timer % 2 == 0)
				ghs.color = SKINCOLOR_EMERALD
				ghs.blendmode = AST_ADD
				ghs.frame = (rng-1)|TR_TRANS40
			else
				ghs.frame = (rng-1)|TR_TRANS60
				ghs.color = SKINCOLOR_RED
			end
			
		else --if WJ.timer <= 18. The aftermath, basically.	
		
			if (WJ.timer == 18)
				if not WJ.straightjump
					if not WJ.kickjump
						s.spritexscale = FRACUNIT
						s.spriteyscale = FRACUNIT
					end
					local ghs = SMS_WallJumpGFX(s, true, true)
					if ghs.valid and ghs.valid
						ghs.spritexscale = $*2/3
						ghs.spriteyscale = $*2/3
					end
				else
					p.pflags = $ & ~PF_THOKKED
				end
			end			
		end
		if WJ.straightjump == 777 --SUPER straight jump effects.
		and (s.momz*P_MobjFlip(s) > 17*s.scale)
			local ghs
			if SMS_Graphix(s) != 2
				if WJ.timer == 21
					ghs = SMS_FlatWave(s, SKINCOLOR_SMS3R, 10, 12)
					ghs.tracer = s
					ghs.GSoffsetX = 0
					ghs.GSoffsetY = 0
					ghs.GSoffsetZ = s.height/4
				elseif (WJ.timer % 4 == 0)
					if (s.momz*P_MobjFlip(s) > 22*s.scale)
						SMS_LightClash(s, nil, s)
					end
					ghs = SMS_FlatWave(s, SKINCOLOR_SMS5R, 7, 12)
					if SMSLocalRNG(0, 1, s)
						ghs.momz = s.momz/2
						ghs.scalespeed = max($-FRACUNIT, 9001)
					else
						ghs.color = SKINCOLOR_SMS1R
						ghs.frame = $+FF_TRANS20
						ghs.scalespeed = max($-115356, 9001)
					end
				end
			end
			ghs = P_SpawnGhostMobj(s)
			ghs.colorized = true
			ghs.blendmode = AST_ADD
			ghs.scale = s.scale*5/4
			ghs.destscale = ghs.scalespeed+1
			ghs.dispoffset = 3
		end	
		--Sweatdrops if you're starting to screw up.
		if (WJ.jumpheight < 5*FRACUNIT)
		and not (s.eflags & MFE_UNDERWATER)
			if (WJ.jumpheight < 0)
			or WJ.timer % 3 == 0 --Sweatdrops.
				--Sweatdrops gfx.
				local rng = P_RandomRange(-30,30) or 1
				local ghs = P_SpawnMobjFromMobj(s, s.momx+(rng*s.scale), s.momy+(rng*s.scale), s.momz+s.height, MT_SMSAUTOFRAME)
				ghs.sprite = SPR_DRIP
				ghs.frame = D|FF_TRANS20
				ghs.rollangle = s.rollangle+(rng*ANG2) 
				ghs.scale = ($*15)/(30+abs(rng))
				ghs.destscale = $*99
				ghs.colorized = true
				ghs.color = SKINCOLOR_SKY
				ghs.fuse = 16 ghs.tics = 16

				ghs.sttfade = true
				ghs.tracer = s
				ghs.ditchtracer = 1
				ghs.momx = s.momx/2
				ghs.momy = s.momy/2
				ghs.momz = (s.momz/3)-(23*s.scale*P_MobjFlip(ghs))
				ghs.GSoffsetX = FixedMul(rng*(s.scale*3), cos(s.angle))
				ghs.GSoffsetY = FixedMul(rng*(s.scale*3), sin(s.angle))
				ghs.GSoffsetZ = (s.height/2)+(abs(rng)*5000)
				ghs.shadowscale = FRACUNIT
			end
		end
		
		--Undo this one.
		if s.hmscchange
			s.hmscchange = false
			p.viewrollangle = 0
		end		

		if WJ.straightjump return end --
		
		--Cancel if player's thokking or airboosting.	
		if (p.pflags & PF_THOKKED) and (p.pflags & PF_JUMPED)
			if (s.state != S_SMSTHOKANIM)
				s.state = S_SMSTHOKANIM
			end
			s.rollangle = 0
			if (WJ.timer < 18) WJ.timer = 1 end
			return --
		end


		
		if WJ.wallbounce --Backflipping diagionally from the wall in front of you.		
			
			if (WJ.timer > 17) --start
					s.spritexscale = min($+6000, FRACUNIT)
					s.spriteyscale = max($-6000, FRACUNIT)	
					if (WJ.timer == 21)
						s.SMS_wallwait = 10
						s.rollangle = 0
						s.spritexscale = FRACUNIT-18000
						s.spriteyscale = FRACUNIT+15000						
					else
						if (WJ.timer < 19)
							s.sprite = SPR_PLAY
							s.sprite2 = SPR2_SPNG
							s.frame = $ & ~FF_FRAMEMASK
						end
					end
					if (abs(p.cmd.sidemove) > 3)
						s.rollangle = (p.cmd.sidemove*(-ANG1/2))
					end
					
			else --Backflip back into position.
			
					if (WJ.timer > 12)
						s.sprite = SPR_PLAY
						s.sprite2 = SPR2_ROLL
						s.spritexscale = min($+7000, FRACUNIT)
						s.spriteyscale = max($-7000, FRACUNIT)							
						if (WJ.timer > 16)
							s.frame = ($ & ~FF_FRAMEMASK)|A
							if (WJ.timer == 17)
								s.spritexscale = FRACUNIT-18000
								s.spriteyscale = FRACUNIT+24000
							end
						elseif (WJ.timer > 14)
							s.frame = ($ & ~FF_FRAMEMASK)|C
						else
							s.frame = ($ & ~FF_FRAMEMASK)|B
						end
						if (abs(p.cmd.sidemove) > 3)
							s.rollangle = (p.cmd.sidemove*(-ANG1/2))
						end
						
					else

						if s.rollangle != 0
							s.rollangle = $+(WJ.righty and ANG1*2 or ANG1*-2)
						end
						if WJ.timer > 4
							if WJ.timer == 12 
								s.spritexscale = FRACUNIT+24000
								s.spriteyscale = FRACUNIT-20000
								s.rollangle = 0
								for i = 1,3
									local ghs = SMS_GroundWindBlast(s)
									ghs.spriteyscale = FRACUNIT/i
									ghs.spritexscale = (FRACUNIT*3)/(5+i)
									ghs.blendmode = AST_ADD
									ghs.tracer = s
									ghs.sttfade = true
									ghs.fuse = 8-i
									ghs.frame = ($ & ~FF_TRANSMASK)|((4-i)*FRACUNIT)
									ghs.sttspeed = 1
									ghs.GSoffsetX = 0
									ghs.GSoffsetY = 0
									ghs.GSoffsetZ = (s.height/2)-(i*s.scale*3)
									if i != 2
										ghs.colorized = true
										ghs.color = s.color
									end
								end
							end						
							s.spritexscale = max($-4500, FRACUNIT)
							s.spriteyscale = min($+7500, FRACUNIT)	
							s.sprite = SPR_PLAY
							s.sprite2 = SPR2_FALL
							if WJ.timer % 2 == 0
								s.frame = ($ & ~FF_FRAMEMASK)|B
							else
								s.frame = ($ & ~FF_FRAMEMASK)|A
							end
						else
							s.spritexscale = min($+14000, FRACUNIT)
							s.spriteyscale = max($-14000, FRACUNIT)	
							if WJ.timer == 4
								s.spritexscale = FRACUNIT-22500
								s.spriteyscale = FRACUNIT+29000
								s.state = S_PLAY_ROLL	
							end							
						end
					end				
			end		
			s.tics = 3
			s.anim_duration = 3

		--Handstand sideflip!
		elseif WJ.sideflip == 2 //and (WJ.timer < 20)	
			if WJ.timer == 4
				s.state = S_SMS_ADVFALL1
			elseif (WJ.timer > 4)
				p.pflags = $|PF_JUMPED & ~PF_NOJUMPDAMAGE
				s.tics = WJ.timer 
				s.anim_duration = s.tics
			
				s.sprite = SPR_SMSO
				s.frame = ($ & ~FF_FRAMEMASK)|N
			end
			local MULT = (WJ.number == 1) and 1 or -1
			if (WJ.timer > 20) --Start a bit more realistically.
				local ANG = (WJ.timer-16)*(ANG1*5)
				s.rollangle = (ANG+ANGLE_45)*MULT
			else
				s.rollangle = WJ.timer*(ANG1*17)*MULT
			end
			
		elseif WJ.kickjump --Kickjump from the wall behind you?
		
			if (WJ.timer > 19)
				s.spritexscale = min($-9000, FRACUNIT)	
				s.spriteyscale = max($+9000, FRACUNIT)	
				if (WJ.timer == 21)
					s.spritexscale = FRACUNIT+29000
					s.spriteyscale = FRACUNIT-25000
					s.rollangle = 0
				end
			elseif (WJ.timer > 13)
				s.spritexscale = min($+6000, FRACUNIT)
				s.spriteyscale = max($-6000, FRACUNIT)
				if WJ.timer == 19
					s.spritexscale = FRACUNIT-28000
					s.spriteyscale = FRACUNIT+28000	
				end
				s.sprite = SPR_SMSO
				s.frame = ($ & ~FF_FRAMEMASK)|R
				s.tics = 3
				s.anim_duration = 3
			else
				s.spritexscale = FRACUNIT
				s.spriteyscale = FRACUNIT
			end
		end
		return true --
	end
end)

--The New Walljump checker" for SMSreborn 2.6+
rawset(_G, "SMS_WallJumpCheck", function(s,p)
	local ANGLE = ((p.pflags & PF_ANALOGMODE) and (p.speed > 76*s.scale)) and SMS_PlayerAngle(s,p, true) or s.angle
	local NOBACK = false
	local NOFRONT = false
	
	if not (twodlevel or (s.flags2 & MF2_TWOD)) 
		if (p.pflags & PF_ANALOGMODE)
			if (abs(p.cmd.sidemove) > 18) and not (p.cmd.forwardmove > 40) --Analog mode needs a bit of help...
				NOBACK = true
			end
		elseif (abs(p.cmd.sidemove) > 18)
			if (p.cmd.forwardmove > 18)
				NOBACK = true
			elseif (p.cmd.forwardmove < -18)
				NOFRONT = true
			end
		end
	end
	if not s.SMS_walltable --Make a table incase none exist.
		s.SMS_walltable = {}
	end	
	
	--0 checks for walls in FRONT of you, 1 checks for walls to the LEFT, 2 for walls BEHIND you, 3 for walls on the RIGHT.
	for i = 0,3
		if s.SMS_walltable[i] and s.SMS_walltable[i].valid --Delete previously existing missiles.
			s.SMS_walltable[i].state = S_NULL
		end
		if s.SMS_WJauto
			if s.SMS_WallJumpTable and (s.SMS_WallJumpTable.timer > 12)
			and s.SMS_WallJumpTable.straightjump
				continue --This walljump only checks the wall in front of you.
			end
			if i != 0
				if not (i == 2 and (p.cmd.forwardmove < -41) and (p.pflags & PF_ANALOGMODE))
					continue --
				end
			end
		end
		if (twodlevel or (s.flags2 & MF2_TWOD))
			if i != 0 break end --2D only requires the front-checker.
		elseif not (i == 0 and (abs(p.cmd.sidemove) < 3) and (abs(p.cmd.forwardmove) < 3))
			--Allow super-rapid walljumps, but only on opposite wall-sides or when turn-around walljumping.
			if s.SMS_WallJumpTable 
			and (s.SMS_WallJumpTable.timer > 8)
				if s.SMS_WallJumpTable.number == 0 and i != 2
				or s.SMS_WallJumpTable.number == 2 and i != 0
				or s.SMS_WallJumpTable.number == 1 and i != 3
				or s.SMS_WallJumpTable.number == 3 and i != 1
					continue --	
				end
			end	
		end	
		if i == 0 --Hitting the wall at your front.
			if NOFRONT continue end
		elseif i == 2 --Only hit walls RIGHT behind you, don't fire these too far back.	
			if NOBACK continue end
		end		
		
		 --Speed to fire our wall-checking projectile.
		local SPEED = 
		(i == 0) and min( FixedDiv(FixedMul(p.speed, 100), 133), 53*s.scale)+6*s.scale --Forwards speed
		or 
		(i != 2) and min(  FixedDiv(FixedMul(p.speed, 100), 114)  , 60*s.scale)+6*s.scale --Sideways speed
		or
		((p.cmd.forwardmove < -41) and (p.pflags & PF_ANALOGMODE)) and p.speed+6*s.scale or 6*s.scale --Backwards speed.
		
		s.SMS_walltable[i] = P_SpawnMobjFromMobj(s,0,0,0,MT_SMSWALLJUMP) 
		local ghs = s.SMS_walltable[i]
		ghs.target,ghs.tracer = s,s --We don't use tracer, but why not....
		ghs.fuse = 5
		ghs.eflags = $ & ~MFE_VERTICALFLIP --Don't allow the missile to be flipped!
		ghs.flags2 = $ & ~MF2_OBJECTFLIP
		ghs.SMS_number = i
		ghs.flags = MF_NOBLOCKMAP|MF_NOGRAVITY|MF_MISSILE|MF_NOSECTOR
		if i == 1 or i == 3 --Aim a tiny bit backwards.
			ghs.angle = ANGLE+((ANG1*93)*i)
			P_InstaThrust(ghs, ANGLE+((ANG1*93)*i), SPEED)
		else
			ghs.angle = ANGLE+(ANGLE_90*i)
			P_InstaThrust(ghs, ANGLE+(ANGLE_90*i), SPEED) --FIRE AWAY, at this speed, in this direction!
		end
		
		--DEBUG HITBOX CHECKER
/*		local ths = P_SpawnMobjFromMobj(ghs, 0,0,0, MT_THOK)
		ths.scale = $/3
		ths.tics = 4
		ths.momx = ghs.momx
		ths.momy = ghs.momy	
		if i == 0 --Front is 0!
			ths.color = SKINCOLOR_RED
		elseif i == 2 --Back is 2
			ths.color = SKINCOLOR_COBALT
		elseif i == 1 --Left is 1!
			ths.color = SKINCOLOR_SUPERGOLD5
		else --Right is 3!
			ths.color = SKINCOLOR_SUPERSILVER1
		end */
	end
end)

--Keeping track of walljump stats right after your walljump! Returns true if walljump is ongoing.
rawset(_G, "SMS_WallJumpStats", function(s,p)
		--Cancel conditions.
		if (P_IsObjectOnGround(s) or not (p.pflags & PF_JUMPED)) and not (s.momz*P_MobjFlip(s) > 9)
		or (p.panim == PA_PAIN)
		or p.hypermysticsonic
		or p.powers[pw_carry]
		or (p.pflags & (PF_STARTDASH|PF_SLIDING))			
		or (s.skin != "sms")
			p.sms_wallstat = 0
			s.retmhtsfx = 0
			s.spriteyscale = FRACUNIT
			s.spritexscale = FRACUNIT
			return false --
			
		elseif p.sms_wallstat == 1 --Our last stat tic?
		
			S_StartSound(s, sfx_cdfm50) --You've recovered your walljump cooldown!
			s.retmhtsfx = 0
			local ghs = P_SpawnMobjFromMobj(s,0,0,s.momz, MT_THUNDERCOIN_SPARK)
			if ghs and ghs.valid
				ghs.fuse = 12
				ghs.scalespeed = $*5
				ghs.destscale = $*99
				ghs.momx = s.momx/2
				ghs.momy = s.momy/2
				ghs.momz = s.momz/2
			end
			return false --
		end
			
		--Main behaviour.
			
		if not (p.pflags & PF_THOKKED)
				if not s.retmhtsfx			
					s.retmhtsfx = 50 
					--Wall Thok gfx
					for i = -1,1,2
						local ghs = P_SpawnMobjFromMobj(s, 
						FixedMul(9*s.scale*i, cos(s.angle+ANGLE_90)), 
						FixedMul(9*s.scale*i, sin(s.angle+ANGLE_90)),
						(s.height/3), MT_THOK)
						
						ghs.renderflags = $|RF_SEMIBRIGHT|RF_PAPERSPRITE
						ghs.angle = s.angle+ANGLE_90
						ghs.fuse = 10 ghs.tics = 99
						ghs.scalespeed = $*(2-i)
						ghs.destscale = ghs.scalespeed+1
						ghs.momx = s.momx/(3-i)
						ghs.momy = s.momy/(3-i)
						if (p.smscoatc5 == SKINCOLOR_GREY)
						or (s.color >= SKINCOLOR_CARBON and s.color <= SKINCOLOR_BLACK)
						or (s.color >= SKINCOLOR_RUBY and s.color <= SKINCOLOR_KETCHUP)
							ghs.color = SKINCOLOR_SUPERGOLD3
						else
							ghs.color = s.color
						end
						ghs.frame = ($ & ~FF_TRANSMASK)|TR_TRANS70
					end
				end
				
		else --if (p.pflags & PF_THOKKED)
				
			if s.retmhtsfx --Smoketrail and walltouch sfx timer. Your walljump is on cooldown!		
				s.retmhtsfx = $-1
				
				if (s.retmhtsfx == 46)
					S_StartSound(s, sfx_s238)
				elseif (s.retmhtsfx < 46) --Smoketrail from walljump cooldown.		
					for i = -1,1,2
						local ghs = P_SpawnMobjFromMobj(s, 
						FixedMul(15*s.scale*i, cos(s.angle+ANGLE_90)), 
						FixedMul(15*s.scale*i, sin(s.angle+ANGLE_90)),
						s.height/2, MT_SPINDUST)				
						if (s.eflags & MFE_UNDERWATER)
							ghs.state = S_SPINDUST_BUBBLE1
						elseif (leveltime % 2 == 0)
							ghs.state = S_SPINDUST3
						end
						if (leveltime % 3 == 0)
							ghs.scale = $*2/3
						end
						ghs.frame = ($ & ~FF_TRANSMASK)|TR_TRANS60
					end
				end
			end
		end
		if (p.sms_wallstat == 59) and (p.pflags & PF_DIRECTIONCHAR) --Force player angle for a second...
			s.forcesmsangletimer = 2
			s.forcesmsangle = s.angle
		end
		return true --
end)

--Delete all walljump detector info.
rawset(_G, "SMS_WallJumpDelete", function(s, ExitWJ)
	if s.SMS_walltable
		for i = 0,3
			if s.SMS_walltable[i] and s.SMS_walltable[i].valid --Delete wallcheckers first!
				s.SMS_walltable[i].state = S_NULL
			end
		end
	end
	
	s.SMS_hitwall = {} --Remove any data of walls we've hit.
	s.SMS_walltable = {}
	s.SMS_removeWD = 0 --Nothing left to remove.
	s.SMS_wallready = 0 --Nothing left to be ready for.
	
	if ExitWJ 
	and s.SMS_WallJumpTable --Remove our walljumping state and table too?
		s.rollangle = 0
		if not s.SMS_squashtable
			s.spriteyscale = FRACUNIT
			s.spritexscale = FRACUNIT
			s.spriteyoffset = 0
		end
		s.SMS_WallJumpTable = nil --Delete the table now that we're done.
		if (s.player and not s.player.powers[pw_carry] and not s.player.hypermysticsonic)
			local p = s.player
			if P_IsObjectOnGround(s) and not (s.momz*P_MobjFlip(s) > 0) --Prevent rare animation errors.
				p.pflags = $ & ~(PF_JUMPED|PF_THOKKED|PF_NOJUMPDAMAGE|PF_STARTJUMP)
				s.SMS_WJpenalty = 0
				s.SMS_lastwallANG = nil
				s.SMS_lastwallNUM = nil
				if (s.state == S_SMS_WALLJUMP) or (s.state == S_SMS_SIDET)
					s.state = S_PLAY_FALL
				end
			elseif ((s.state == S_SMS_WALLJUMP) or (s.state == S_SMS_SIDET) or (s.state == S_PLAY_FALL))
			and not ((p.pflags & PF_JUMPED) or p.hometrickanim)
				s.state = S_PLAY_ROLL
				p.pflags = $|PF_JUMPED & ~PF_NOJUMPDAMAGE
			end
		end
	end
end)

//Depending whether you're in match/CTF/Team Match or not, you'll get a stronger or weaker walljump.
--Var1 and var2 do absolutely nothing.
function A_MATCHORNOTSPAWN(s, var1, var2)
	if not (s.target and s.target.valid and s.target.health and s.target.player) return end --
	local t = s.target
	local p = s.target.player
	
	--Legend Mode includes the 2.0 SMSunleashed walljump!
	if p.smsblastboost 
	
		if p.secondjump == 167 return end
		if p.bot t.angle = $+ANGLE_180-ANG20 return end
		
		P_SpawnMobjFromMobj(s, 0, 0, 0, MT_BURSTLIGHT)
		p.secondjump = 0
		p.homing = 0
		p.pflags = $|PF_JUMPED|PF_JUMPDOWN & ~PF_THOKKED & ~PF_STARTJUMP & ~PF_SPINNING	
		t.state = S_PLAY_SPRING
		t.eflags = $|MFE_SPRUNG
		p.powers[pw_nocontrol] = max($,3)
		p.pflags = $ & ~PF_NOJUMPDAMAGE & ~PF_THOKKED & ~PF_JUMPED & ~PF_JUMPDOWN
		if (t.eflags & MFE_UNDERWATER) or G_GametypeHasSpectators() or t.battlemodsms
			P_InstaThrust(t, t.angle, -2*FRACUNIT)
			S_StartSound(t, sfx_bljpw)
			P_SetObjectMomZ(t, 14*FRACUNIT, false)
		else
			P_InstaThrust(t, t.angle, -5*FRACUNIT)
			S_StartSound(t, sfx_bljp)
			P_SetObjectMomZ(t, 29*FRACUNIT, false)
		end
		SMS_WallJumpDelete(t)
		t.SMS_wallready = 0
		p.secondjump = 167
		
	else --The SMS reborn walljump feeds all lines we find into a table when you hold spin. 
		--SMS then picks which one's best suited to jump off, taking his angle, the wall angle, and player input into consideration.
		--Basically, we're just prepping data for the walljump here, nothing's happening yet!
		
		if s.lastwall and s.SMS_number != nil
			if not t.SMS_hitwall --Incase there's no table, make one!
				t.SMS_hitwall = {}
			end
			if (leveltime % 3 == 0) 
			and not (t.SMS_walltwitch != nil and (t.SMS_walltwitch > s.SMS_number))
			and not t.SMS_WJauto
				S_StartSound(t, sfx_s3k7e)
				t.SMS_walltwitch = s.SMS_number
				if s.SMS_number != 3
					local ghs = P_SpawnMobjFromMobj(t, FixedMul(13*t.scale, cos(t.angle+ANGLE_90)),FixedMul(13*s.scale, sin(t.angle+ANGLE_90)), t.height+t.momz, MT_SPINDUST)
					ghs.frame = SMSLocalRNG(4,2,t)-2|FF_TRANS10
					ghs.tics = 1
					ghs.momz = $+(4*s.scale*P_MobjFlip(s))
				end
				if s.SMS_number != 1
					local ghs = P_SpawnMobjFromMobj(t, FixedMul(13*t.scale, cos(t.angle-ANGLE_90)), FixedMul(13*s.scale, sin(t.angle-ANGLE_90)), t.height+t.momz, MT_SPINDUST)
					ghs.frame = SMSLocalRNG(0,2,t)|FF_TRANS10
					ghs.tics = 1
					ghs.momz = $+(4*s.scale*P_MobjFlip(s))
				end
				if not t.SMS_squashtable
					t.spritexscale = FRACUNIT-2100
					t.spriteyscale = FRACUNIT+3100
					t.spriteyoffset = SMSLocalRNG(-21,21,t)*(FRACUNIT/25)
					t.spritexoffset = SMSLocalRNG(-20,20,t)*(FRACUNIT/7)
					t.SMS_squashtable = {timer = 1, Xspeed = 1800, Yspeed = 3000, air = true}
				end
			end

			
			t.SMS_hitwall[s.SMS_number] = s.lastwall --Save the line into our table!
		end
		t.SMS_wallready = 6 --Get the walljump ready.
		t.SMS_removeWD = 6
	end
	if s.valid s.state = S_NULL end	--Great! Now RIP, missile!
end

--Jump ONLY off the steepest slopes. Btw, the missile object is NEVER flipped!
local function SMSWJ_SlopeCollide(s, t) --t is s.target.

	local SEC = (s.subsector) and s.subsector.sector
	
	if SEC and (SEC.c_slope or SEC.f_slope) --Needs a slope and valid sector.	
	
		if (abs((s.z+s.height)-s.ceilingz) < (255*t.scale)+t.momz+t.height) --We're close enough to the ground or ceiling?
		or (abs(s.z-s.floorz) < (80*t.scale)+t.momz)
		
		local SLOPE = SEC.f_slope
		local STEEPNESSNEEDED = (FRACUNIT*2)-17000 --Steepness needed for me to consider this walljumpable.
			
			--Zdelta is calculated different! FRACUNIT is about an angle of 30, while 4*FRACUNIT is closer to 80.	
			if abs(s.z+s.height-s.ceilingz) < (abs(s.z-s.floorz)+t.scale*10) --We're closer to the ceiling!
				SLOPE = SEC.c_slope
				if not (t.eflags & MFE_VERTICALFLIP)
					STEEPNESSNEEDED = 39000 --Be more generous with ceiling slope jumps
				end
			elseif (t.eflags & MFE_VERTICALFLIP)
				STEEPNESSNEEDED = 39000
			end
			if not (SLOPE and SLOPE.zdelta)
				return
			end
			if (SLOPE.zdelta < STEEPNESSNEEDED) --Need steeper slope!
				return --
			end
			
			--Make a reference item. Placement is EXTREMELY important here...
			local ghs
			if s.SMS_number == 2 --Back jump.
				ghs = P_SpawnMobj(s.x+FixedMul(99*t.scale, cos(s.angle)), s.y+FixedMul(99*t.scale, sin(s.angle)), t.z,MT_SMS_THOK)	
				ghs.SMS_LastWJX = s.x
				ghs.SMS_LastWJY = s.y			
			else		
				if s.SMS_number == 0 --Front jump.
					ghs = P_SpawnMobj(s.x+t.momx+FixedMul(abs(t.momx)+16*t.scale, cos(s.angle)), s.y+t.momy+FixedMul(abs(t.momy)+16*t.scale, sin(s.angle)), t.z, MT_SMS_THOK)
				else --side jumps.
					ghs = P_SpawnMobj(s.x+(t.momx/3)+FixedMul(abs(t.momx)+48*t.scale, cos(s.angle)), s.y+(t.momy/3)+FixedMul(abs(t.momy)+48*t.scale, sin(s.angle)), t.z, MT_SMS_THOK)
				end
				ghs.SMS_LastWJX = s.x+s.momx
				ghs.SMS_LastWJY = s.y+s.momy				
			end
			ghs.tics,ghs.fuse = 9,9
			ghs.SlopedJump = SLOPE
			
			s.SlopedJump = SLOPE
			s.flags = $|MF_NOCLIPTHING|MF_NOCLIP|MF_NOCLIPHEIGHT
			s.lastwall = ghs
			A_MATCHORNOTSPAWN(s, 45*FRACUNIT, 26*FRACUNIT) --Forcibly add it to the list.
			return ghs
		end	
	end
end

//We need to do an extra check to see if we're in a "projectile-only" wall, 
//or hit an impassable linedef which projectiles apparently just pass through normally.
addHook("MobjThinker", function(s)
	if (s.state == S_SMSWALLJUMP4)
	and not s.lastwall
	and not (s.flags & MF_NOCLIPTHING)
		if s.target and s.target.valid
		local SEC = (s.subsector) and s.subsector.sector
			if SEC
			local t = s.target
				if SEC.ffloors()
					for fof in SEC.ffloors()
						if (fof.flags & FF_EXISTS) and (fof.flags & FF_BLOCKPLAYER) --If it blocks the player, it'll block YOU too!
						and not (s.z > fof.topheight)
						and not (s.z+s.height < fof.bottomheight)
							P_KillMobj(s)
							return --
						end
					end
				end
				SMSWJ_SlopeCollide(s, t)
			end
		end
	end
end, MT_SMSWALLJUMP)

--Run walljump action on death, but not from a skybox.
addHook("MobjRemoved", function(s)
	if s.target and s.target.valid and not s.SlopedJump
		if s.lastwall and (s.flags & MF_NOCLIPTHING) --We've exploded?
			local t = s.target
			--Broke sanity-distance. Cancel. The missile probably clipped way up a wall or something.
			if (abs(s.z-t.z) > (180*t.scale+abs(t.momz)))
			or (FixedHypot(s.x-t.x, s.y-t.y) > 320*t.scale+(abs(t.momx)+abs(t.momy)))
				return --
			end
			--Comparison time, boys..	
			if (s.lastwall.frontsector == nil and s.lastwall.v1 == nil) --It's a mobj, so don't bother with skybox check.	
			or not SMS_SkyBoxWall(s, s.lastwall, 0) --IF we didn't hit a skybox wall, continue!
				A_MATCHORNOTSPAWN(s, 45*FRACUNIT, 26*FRACUNIT)
			end
		else
			SMSWJ_SlopeCollide(s, s.target) --Check slope!
		end
	end
end, MT_SMSWALLJUMP)

--Record all lines you've hit before death.
addHook("MobjMoveBlocked", function(s, m, line)
	if (s.flags2 & MF_NOCLIPTHING) --The projectile exploded already, stop registering these! (MF_NOCLIP means destroyed missile!)
	or not (s.target and s.target.valid) 
	or s.SMS_number == nil --Projectile wasn't set up correctly...
		return --
	end	
	local t = s.target	
	if line and line.valid
		s.lastwall = line --Save the last line you've hit, then pass your info to SMS on the MobjRemoved hook.
		t.SMS_removeWD = 6
	elseif m and m.valid and m != s and m != t
		s.lastwall = m --You hit a mobj?! Hmm...I can make it work!
		m.SMS_LastWJX = s.x
		m.SMS_LastWJY = s.y
		t.SMS_removeWD = 6
	end
end, MT_SMSWALLJUMP)

--Yes, I can treat mobjs likes lines and you can't stop me.
local function SMS_WJcollide(s, v)
	if not (s.flags2 & MF_NOCLIPTHING) --Why is this even necessary?
	and v and v.valid and (v.type != s.type)
	
		if (v.flags & MF_PUSHABLE) --Pushables get a freebie.
		
		
		or not (v.type == MT_PLAYER) and ((v.flags & MF_SOLID) or (v.flags & MF_PAPERCOLLISION))
		--Now for the great list of "fuck you" flags.
		and not (v.flags & (MF_MONITOR|MF_FIRE|MF_SPECIAL|MF_MISSILE|MF_ENEMY|MF_SHOOTABLE|MF_PAIN|MF_SPRING))
		and not (v.flags & (MF_BOUNCE|MF_NOTHINK|MF_NOBLOCKMAP|MF_NIGHTSITEM|MF_BOSS|MF_NOSECTOR|MF_BOXICON|MF_NOCLIPTHING))
		and not (v.sprite == SPR_NULL)
		
			if not (s.z> v.z+v.height-s.target.momz) --Height check.
			and not (v.z-s.target.momz > s.z)
				if s.SMS_number != nil
				and s.target and s.target.valid	
				and not (s.lastwall and s.lastwall.frontsector and s.lastwall.v1) --Lines take priority.
					s.lastwall = v --Wow, it's a valid target!
					s.target.SMS_removeWD = 6
				end
				return --
			end
		end
	end
	return false --
end
addHook("MobjCollide", SMS_WJcollide, MT_SMSWALLJUMP)
addHook("MobjMoveCollide", SMS_WJcollide, MT_SMSWALLJUMP)

--What order do we check in? Missile numbers are -from: FRONT[0], LEFT[1], BACK[2], RIGHT[3]
rawset(_G, "SMS_SetPriority", function(s, p)
	--Default priority is checking our backs first, then checking our front, THEN the sides.
	--Reason is that the back has the least range, and the sides have the MOST range. Inputs still take priority.
	local P1,P2,P3,P4 = 2,0,1,3
	local ANALOG = (p.pflags & PF_ANALOGMODE) and true or false
	local SLOPE = nil
	local MOBJJUMP = nil
	for i = 0,3
		if s.SMS_hitwall[i] and s.SMS_hitwall[i].valid and s.SMS_hitwall[i].v1 == nil and s.SMS_hitwall[i].x != nil
			MOBJJUMP = true
			if s.SMS_hitwall[i].SlopedJump
				SLOPE = s.SMS_hitwall[i].SlopedJump break --
			end
		end
	end
	if MOBJJUMP != nil
		P1,P2,P3,P4 = 0,2,1,3 --Different default priority on mobjs.
		if SLOPE and SLOPE.xydirection != nil
			local PLAYERANGLE = (SLOPE.zdelta > 0) and s.angle+ANGLE_180 or s.angle
			local DIFF,PLUS = SMS_AngleDifference(PLAYERANGLE, SLOPE.xydirection, 2)
			if (DIFF < ANG10)
				P1,P2,P3,P4 = 0,3,1,nil --Backward-jumps are literally impossible on these.
				return {P1,P2,P3,P4} --Force it.
			elseif (DIFF < ANG1*155) --Sidejumps from the slope are still just a suggestion.
				if PLUS == 1 
					P1,P2,P3,P4 = 1,3,0,2
				else
					P1,P2,P3,P4 = 3,1,0,2
				end
				return {P1,P2,P3,P4} --Force it.
			else
				P1,P2,P3,P4 = 2,1,3,nil
				return {P1,P2,P3,P4} --Force it.
			end
		end
	elseif not (abs(p.cmd.sidemove) > 4) and not (abs(p.cmd.forwardmove) > 4)
		ANALOG = true --Will calculate as analog too!
	end
	
	--ANALOG! Missile numbers are -from: FRONT[0], LEFT[1], BACK[2], RIGHT[3]
	if (ANALOG == true)
		if (p.cmd.forwardmove > 34) and (p.speed < 100*s.scale) --Prioritize wall in front!
			P1,P2,P3,P4 = 0,3,2,1
		else
			local TURNANG = SMS_PlayerAngle(s,p) 
			local MOMANG = SMS_PlayerAngle(s,p, true) 
			local trueturn = (MOMANG-TURNANG)
			if trueturn != 0
			
				trueturn = abs(abs($/ANG1)-90)
				if (trueturn >= 31) --Sideways walljump priority!
					P1 = (p.cmd.sidemove > 0) and 1 or 3
					P2 = (p.cmd.sidemove > 0) and 3 or 1
					if (p.cmd.forwardmove >= 0)
						P3 = 0
						P4 = 2	
					else
						P3 = 2
						P4 = 0
					end
				end				
			end
		end
	
	else --Non-ANALOG! Missile numbers are -from: FRONT[0], LEFT[1], BACK[2], RIGHT[3]
		if (abs(p.cmd.sidemove) > 20) 
			P1 = (p.cmd.sidemove > 0) and 1 or 3
			P2 = (p.cmd.sidemove > 0) and 3 or 1
			if (p.cmd.forwardmove >= 0)
				P3 = 0
				P4 = 2	
			else
				P3 = 2
				P4 = 0
			end
		elseif (abs(p.cmd.forwardmove) > 10)
			if (p.cmd.forwardmove < 10) --Holding backwards.
				P1 = 2
				P2 = 0
			else
				P1 = 0 --As it should be!
				P2 = 2
			end
			P3 = (p.cmd.sidemove > 0) and 1 or 3
			P4 = (p.cmd.sidemove > 0) and 3 or 1
		end
	end
	return {P1,P2,P3,P4} --This is our final determined order! What a hassle!
end)
