// Sonic + Dash Mode 
// This is the older version of dash mode. Before it was used for Metal Sonic.
// Created by Wolfy to teach Iceman404 shit about lua
// Requested, revamped, and continued by Iceman404 
// Guidance from HellHawkX, Zipper, katsy, RedEnchilada and Sryder13.
// toaster understands how scale works, makes Wolfs sad by threatening to remove this lump, and catches him from doing terrible things like overriding all players' attributes with their default every tic
// PLEASE VIEW WITH NOTEPAD++ FOR FORMATTING SANITY.
// Lua ported to 2.2 by DirkTheHusky

assert(VERSION ~= nil, "script does not support game version")

freeslot("S_DASHSPARK1", "S_DASHSPARK2", "S_DASHSPARK3", "SPR_DSPK")

states[S_DASHSPARK1] = {SPR_DSPK,0,2,nil,0,0,S_DASHSPARK2}
states[S_DASHSPARK2] = {SPR_DSPK,1,2,nil,0,0,S_DASHSPARK3}
states[S_DASHSPARK3] = {SPR_DSPK,0,2,nil,0,0,S_NULL}

//PREPARATION
addHook("MobjThinker", function(mobj) 	// This is a MobjThinker hook, it runs for every tic the mobj is on the map.
	local player = mobj.player 			// A little alias I do to make these similar to ThinkFrame hooks.
	
	if not (player and player.valid) then return end
	if (maptol & TOL_NIGHTS) return end

	if (mobj.skin == "nitro") then
		if not player.sonicdashmode then 
			player.sonicdashmode = 0 			//This makes sure the variable starts at 0, and not nil. Otherwise, you can't perform arithmetic on it.
			player.sonicdashmodeflag = false
		end
		
		player.defspeed = skins["nitro"].normalspeed 	// Default normalspeed.
		player.maxtop = skins[mobj.skin].normalspeed * 55/36
		
		if player.powers[pw_super] then
			player.actionspd = 55*FRACUNIT
		end
		
		//HOW DASH MODE COUNTER WORKS
		local speed = FixedDiv(player.speed, mobj.scale) // toast is fixing all the everythings.
		if not (speed > player.normalspeed) and not player.powers[pw_super] then		//are we currently exceeding our normalspeed?
			player.actionspd = player.normalspeed	//if not, force thok to normalspeed
		elseif not player.powers[pw_super] then
			player.actionspd = speed			//otherwise, thok at your current speed (this fixes super and speedshoes thok slowing you down)
		end
		if speed >= (player.defspeed - 5*FRACUNIT) or (player.pflags & PF_STARTDASH) then
			if not (player.powers[pw_super]) then
				player.sonicdashmode = $1 + 1 	// Counter. Adds 1 to dash mode per tic in top speed.
				if player.sonicdashmode == 3*TICRATE				// This isn't in the ">=" equation because it'd cause the sound to play infinitely.
					S_StartSound (mobj, sfx_s3ka2) 	// If the player enters sonicsonicdashmode, play this sound on the the tic it starts.
				end
			else
				player.sonicdashmode = 0
			end
		elseif not (player.pflags & PF_SPINNING) then
			if player.sonicdashmode > 0 then
				player.sonicdashmode = $1 - 3	// Rather than lose it all, it gently counts back down!
			elseif player.sonicdashmode < 0 then 
				player.sonicdashmode = 0
			end
		end	
		
		if player.speed <= 0
			if not (player.pflags & PF_STARTDASH)
			and not (player.pflags & PF_SPINNING)
				player.sonicdashmode = 0
			end
		end
	
		//PARAMETERS FOR DASH MODE TO EVEN HAPPEN
		if player.sonicdashmode >= 3*TICRATE and P_IsObjectOnGround(mobj) then  // Dash Mode can continue counting in the air, but will only activate on floor touch.
			player.sonicdashmodeflag = true												
		end
		
		if player.sonicdashmode < 3*TICRATE then			// Exits Dash Mode if you drop below speed/dash counter tics. Not in the above block so it doesn't keep disabling in midair.
			player.normalspeed = player.defspeed 	// Reset to default if not capable of entering dash mode.
			player.jumpfactor = 1*FRACUNIT
			player.sonicdashmodeflag = false
		end
		
		if player.sonicdashmode == 3*TICRATE	and P_IsObjectOnGround(mobj) and not (player.pflags & PF_STARTDASH) then
			if speed >= (player.defspeed - 5*FRACUNIT) then
				local spark = P_SpawnMobj(mobj.x, mobj.y, (verticalflip and (mobj.ceilingz or -1) or mobj.floorz), MT_PARTICLE)
				spark.state = S_DASHSPARK1
			end
		end
		
		//WHEN PARAMETERS ARE MET, REWARD THE DASH MODE EFFECTS
		if player.sonicdashmodeflag then
			if player.normalspeed < player.maxtop then  	// If the player is not currently at 50 normalspeed in dash mode, add speed each tic
				player.normalspeed = $1 + 1*FRACUNIT/5 			// Enter Dash Mode smoothly.
				if player.jumpfactor < 5*FRACUNIT/4 then
					player.jumpfactor = $1 + 1*FRACUNIT/300 	// Boosts his jumpheight. Remember fractions instead of decimals. "1.5*FRACUNIT = 3*FRACUNIT/2"				
				end
			end		
		end
		
		//COSMETIC STUPIDITY!
		if player.sonicdashmode > 108 then	//Dash Mode will go down a tic a bit above activation, this makes dust spawn every other tic.
			player.sonicdashmode = 107
		end 
		
		local dashdust = (leveltime) % 5
		
		if player.sonicdashmode >= 2*TICRATE
		and player.sonicdashmode < 3*TICRATE
		and P_IsObjectOnGround(mobj)
		and speed >= (player.defspeed - 5*FRACUNIT)
		and not (player.pflags & PF_STARTDASH)
			if dashdust < 2
				if mobj.eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) then
					local runbubble =  P_SpawnMobj(mobj.x, mobj.y, (verticalflip and (mobj.ceilingz or -1) or mobj.floorz), MT_PARTICLE)
					runbubble.scale = mobj.scale
					runbubble.state = S_SPINDUST_BUBBLE1
					runbubble.fuse = 10
				elseif not (player.powers[pw_shield] == SH_ELEMENTAL) then
					local rundust = P_SpawnMobj(mobj.x, mobj.y, (verticalflip and (mobj.ceilingz or -1) or mobj.floorz), MT_PARTICLE)
					rundust.scale = mobj.scale
					rundust.destscale = 3*mobj.scale
					rundust.scalespeed = mobj.scale/6
					rundust.fuse = 5
				elseif player.powers[pw_shield] == SH_ELEMENTAL then
					local runfire = P_SpawnMobj(mobj.x, mobj.y, (verticalflip and (mobj.ceilingz or -1) or mobj.floorz), MT_PARTICLE)
					runfire.scale = mobj.scale
					runfire.destscale = 3*mobj.scale
					runfire.scalespeed = mobj.scale/6
					runfire.state = S_SPINDUST_FIRE1
					runfire.fuse = 5
				end
			end
		end	
			
		if player.sonicdashmodeflag and P_IsObjectOnGround(mobj) and player.sonicdashmode == 107 and not (player.pflags & PF_STARTDASH) then
			local verticalflip = mobj.eflags & MFE_VERTICALFLIP
			if mobj.eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) then
				local bubble = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z + ((player.mo.eflags & MFE_VERTICALFLIP)/MFE_VERTICALFLIP * (player.mo.height - mobjinfo[MT_PARTICLE].height)), MT_PARTICLE)
				bubble.scale = mobj.scale
				bubble.state = S_SPINDUST_BUBBLE1
				bubble.fuse = 10
			elseif not (player.powers[pw_shield] == SH_ELEMENTAL) then
				local dust = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z + ((player.mo.eflags & MFE_VERTICALFLIP)/MFE_VERTICALFLIP * (player.mo.height - mobjinfo[MT_PARTICLE].height)), MT_PARTICLE)
				dust.state = S_DASHSPARK1
				dust.fuse = 20
				P_SetObjectMomZ(dust, player.dashspeed/50+P_RandomByte()<<10, false)
			elseif player.powers[pw_shield] == SH_ELEMENTAL then
				local fire = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z + ((player.mo.eflags & MFE_VERTICALFLIP)/MFE_VERTICALFLIP * (player.mo.height - mobjinfo[MT_PARTICLE].height)), MT_PARTICLE)
				fire.scale = mobj.scale
				fire.destscale = 3*mobj.scale
				fire.scalespeed = mobj.scale/6
				fire.state = S_SPINDUST_FIRE1
				fire.fuse = 5
			end
		end
		
		local aftimg = (leveltime) % 4
		
		if player.normalspeed >= player.maxtop then
			if aftimg < 2 then
				local afterimg = P_SpawnGhostMobj(mobj) 	// Spawns afterimages
				afterimg.fuse = 2
				
				local afterimg2 = P_SpawnGhostMobj(mobj) 
				afterimg2.fuse = 2
				
			else
				local afterimg = P_SpawnGhostMobj(mobj) 	// Spawns afterimages
				afterimg.fuse = 1
				
				local afterimg2 = P_SpawnGhostMobj(mobj) 
				afterimg2.fuse = 1
				
			end
		end
			
		if player.normalspeed >= player.maxtop then
			player.charflags = $1|SF_RUNONWATER
		else
			player.charflags = $1 & ~SF_RUNONWATER
		end
	/*else // NO! Bad. Breaks scripts which manipulate jumpfactor and normalspeed. We will assume these things are successfully set via the act of changing skins, which the source code is responsible for and which other scripts may also chose to amend.
		player.jumpfactor = skins[mobj.skin].jumpfactor
		player.normalspeed = skins[mobj.skin].normalspeed*/
	end
end, MT_PLAYER)	// End of the hook, MT_PLAYER specifies that this should be run for player mobjs only.