freeslot(
"MT_WIDOSLASH",
"S_WIDOSLASH",
"S_WIDOSLASH2",
"MT_WIDOPARRY",
"MT_WIDOELEMENTAL",
"S_WIDOELEMENTAL",
"S_WIDOPARRY",
"S_WIDOPARRY1",
"S_WIDOPARRY2",
"S_WIDOPARRY3",
"S_WIDOPARRY4",
"S_WIDOPARRY5",
"S_PLAY_WIDOWALLRUN1",
"S_PLAY_WIDOWALLRUN2",
"S_PLAY_WIDOWALLRUN3",
"S_PLAY_WIDOTRANS",
"MT_WIDOFOLLOW",
"S_WIDOFOLLOW",
"SPR_WSLA"
)



local function A_WidoFollow(actor, var1, var2)
	if not (actor.target.player) then
		actor.state = S_NULL
		return
	end
	if (actor.target.player.powers[pw_super] == 0) then
		actor.state = S_NULL
		return
	end
	
	actor.renderflags = actor.target.renderflags
	if (actor.target.eflags & MFE_VERTICALFLIP) then
		P_TeleportMove(actor, actor.target.x, actor.target.y, actor.target.z-actor.height/4)
		actor.renderflags =  $| RF_VERTICALFLIP
	else
		P_TeleportMove(actor, actor.target.x, actor.target.y, actor.target.z)	
		actor.renderflags =  $1&~ RF_VERTICALFLIP
	end
	actor.rollangle = actor.target.rollangle
	actor.scale = actor.target.scale
	actor.sprite2 = actor.target.sprite2
	actor.frame = actor.target.frame|TR_TRANS40
	actor.angle = actor.target.player.drawangle
	if (actor.reactiontime == 0) then
		actor.threshold = P_RandomRange(0,8)
	end
	actor.color = (69+(actor.reactiontime/2))+(actor.threshold*5)
	actor.reactiontime = ($+1)%9
end
local wallRunHighlight = CV_RegisterVar({
	name = "wallRunHighlight",
	defaultvalue = 0,
	flags = CV_SHOWMODIF|CV_NETVAR,
	PossibleValue = CV_OnOff
})

local function lerp (var1, var2, t) do
	var1 = FixedMul($1*FRACUNIT, FRACUNIT-t)
	var2 = FixedMul($1*FRACUNIT, t)
	local r = var1+var2
	r = $1/FRACUNIT
	return r
	end
end

if not(widoParryBlacklist)
	rawset(_G, "widoParryBlacklist", {})
end

//Blacklisted objects can still be parried, but won't be reflected. 
//It should be used for things that glitch the game out in weird ways when they target an MT_PLAYER
widoParryBlacklist[MT_CRUSHCLAW] = 1
widoParryBlacklist[MT_CRUSHCHAIN] = 1
widoParryBlacklist[MT_CRUSHSTACEAN] = 1
widoParryBlacklist[MT_EGGSHIELD] = 1
widoParryBlacklist[MT_PTERABYTE] = 1
widoParryBlacklist[MT_PLAYER] = 1

local function WidoSearch(refmob, foundmob) 
	if not (foundmob) then
		return nil
	end
	local dist = R_PointToDist2(refmob.x, refmob.y, foundmob.x, foundmob.y)
	if (dist > FRACUNIT*512) then
		return nil
	end
	if (foundmob.type == MT_PLAYER) then
		return nil
	end
	if ((foundmob.flags & MF_SHOOTABLE) or (foundmob.flags2 & MF2_INVERTAIMABLE)) and (foundmob.health > 0) and (not (foundmob.flags2 & MF2_FRET and foundmob.doubleTapped)) then
		if (P_CheckSight(refmob, foundmob)) and (foundmob.z > refmob.z-(256*FRACUNIT)) and (foundmob.z < refmob.z+(256*FRACUNIT)) then
			if (refmob.player.target)
				if (dist < R_PointToDist2(refmob.x, refmob.y, refmob.player.target.x, refmob.player.target.y)) then
					refmob.player.target = foundmob
				end
			else
				refmob.player.target = foundmob
			end
		end
	end

end



local function WidoWallBust(player, sector) 
	for fof in sector.ffloors()
		if (fof.flags & FF_BUSTUP) and (fof.flags & FF_EXISTS)
			if ((player.mo.z <= fof.topheight and player.mo.z+player.mo.height >= fof.bottomheight)
			or (player.mo.eflags & MFE_VERTICALFLIP and (player.mo.z>=fof.bottomheight and player.mo.z-player.mo.height<=fof.topheight))) then
				EV_CrumbleChain(sector, fof)
			end
		end
	end

end


local function WidoWallJump(p) 

		S_StartSound(p,sfx_jump,player)
		p.state = S_PLAY_SPRING
		local horizAngle
		if (p.player.wallRunLine) then
			horizAngle = R_PointToAngle2(p.player.wallRunLine.v1.x, p.player.wallRunLine.v1.y, p.player.wallRunLine.v2.x, p.player.wallRunLine.v2.y)+ANGLE_90
			if (not P_PointOnLineSide(p.x, p.y, p.player.wallRunLine)) then
				horizAngle = $+ANGLE_180
			end
		else
			horizAngle = p.player.drawangle
		end
		p.player.drawangle = horizAngle
		if (p.player.wallRunSpeed > 15*FRACUNIT) then
			p.player.wallRunSpeed = 15*FRACUNIT
		end
		P_Thrust(p, horizAngle, (p.player.wallRunSpeed*2)/3)
		P_SetObjectMomZ(p, (p.player.wallRunSpeed*2)/3)
end

local function ClosestPointOnLineSegment(x, y, line) 
	local epsilon = FRACUNIT
	local interX, interY = P_ClosestPointOnLine(x, y, line)
	local dist1 = R_PointToDist2(interX, interY, line.v1.x, line.v1.y)
	local dist2 = R_PointToDist2(interX, interY, line.v2.x, line.v2.y)
	local dist3 = R_PointToDist2(line.v1.x, line.v1.y, line.v2.x, line.v2.y)
	local distDiff = (dist1+dist2)-dist3
	if (-epsilon < distDiff) and (distDiff < epsilon) then
		return interX, interY
	elseif ( dist1 < dist2) then
		return line.v1.x, line.v1.y
	else
		return line.v2.x, line.v2.y
	end


end

local function IsPointInWall(sector, x, y, z)

	local isUnderFloor = false
	local isOverCeiling = false
	local isInFOF = false
	local floor = sector.floorheight
	if (sector.f_slope) then
		floor = P_GetZAt(sector.f_slope,x,y)
	end
	if (z < floor and sector.floorpic ~= "F_SKY1") then 
		isUnderFloor = true
	end
	
	local ceiling = sector.ceilingheight
	if (sector.c_slope) then
		ceiling = P_GetZAt(sector.c_slope,x,y)
	end
	if (z > ceiling and sector.ceilingpic ~= "F_SKY1") then 
		isOverCeiling = true
	end	
	
	
	for fof in sector.ffloors()
		local foffloor
		local fofceiling
		if (fof.flags & FF_SOLID) and (fof.flags & FF_EXISTS) then
			fofceiling = fof.topheight
			if (fof.t_slope) then
				fofceiling = P_GetZAt(fof.t_slope,x,y)
			end
			
			foffloor = fof.bottomheight
			if (fof.b_slope) then
				foffloor = P_GetZAt(fof.b_slope,x,y)
			end
			
			if (z > foffloor) and (z < fofceiling) then
				isInFOF = true
			end
		end
	
	end
	
	return isUnderFloor or isOverCeiling or isInFOF
	
end

local function CheckHasVertex(vert, line)
	if (line.v1 == vert) then return true end
	if (line.v2 == vert) then return true end
	return false
end

local function HighlightLine(line, z)
	print("highlighting "+line)
		print (line.v1.x/FRACUNIT +" , "+ line.v1.y/FRACUNIT +" to "+ line.v2.x/FRACUNIT +" , "+ line.v2.y/FRACUNIT)
	
	local v1x = line.v1.x/FRACUNIT
	local v1y = line.v1.y/FRACUNIT
	local v2x = line.v2.x/FRACUNIT
	local v2y = line.v2.y/FRACUNIT
	for i = 1, 10
		local x = ((v1x*i)+(v2x*(10-i)))/10
		x = $+P_RandomRange(-16,16)
		x = $*FRACUNIT
		local y = ((v1y*i)+(v2y*(10-i)))/10
		y = $+P_RandomRange(-16,16)
		y = $*FRACUNIT
		P_SpawnMobj(x, y, z, MT_THOK)
	end
end
local function WidoWallRunSearch(p, foundline) 
	if (foundline == nil) then return nil end
	if CheckHasVertex(p.player.closestVertex, foundline) == false then return nil end

	local targetX = p.x+p.momx
	local targetY = p.y+p.momy
	local closeX, closeY = ClosestPointOnLineSegment(targetX, targetY, foundline)
	local distX = p.x-closeX
	local distY = p.y-closeY
	local foundLineDist = R_PointToDist2(targetX, targetY, closeX, closeY)
	if (foundLineDist > 128*FRACUNIT) then
		return nil
	end
	

	local collisionCheck
	if (P_PointOnLineSide(p.x, p.y, foundline) and (foundline.frontsector)) then
		collisionCheck = IsPointInWall(foundline.frontsector, closeX, closeY, p.z)
	elseif (foundline.backsector)
		collisionCheck = IsPointInWall(foundline.backsector, closeX, closeY, p.z)
	end
	
	if (collisionCheck == false) then
		return nil
	end
	if (p.player.lineDist == nil) then 
		p.player.lineDist = foundLineDist
		p.player.wallRunLine = foundline
		return nil
	end
	if (foundLineDist < p.player.lineDist) then
		p.player.lineDist = foundLineDist
		p.player.wallRunLine = foundline
		return nil
	end
	return nil
end


local function WidoWallRun(p) 
		p.player.lineDist = nil
		p.player.lastWallRunLine = p.player.wallRunLine
		if (R_PointToDist2(p.player.lastWallRunLine.v1.x, p.player.lastWallRunLine.v1.y, p.x, p.y) < R_PointToDist2(p.player.lastWallRunLine.v2.x, p.player.lastWallRunLine.v2.y, p.x, p.y)) then
			p.player.closestVertex = p.player.lastWallRunLine.v1
		else
			p.player.closestVertex = p.player.lastWallRunLine.v2
		end
		p.player.wallRunLine = nil
		local searchRadius = 512*FRACUNIT
		searchBlockmap("lines", WidoWallRunSearch, p, p.x-searchRadius, p.x+searchRadius, p.y-searchRadius,p.y+searchRadius)
		
		if (p.player.wallRunLine and wallRunHighlight.value) then
			HighlightLine(p.player.wallRunLine, p.z, p.player.lastWallRunLine)
			print (p.player.wallRunLine)
			print (p.player.wallRunLine.v1.x/FRACUNIT +" , "+ p.player.wallRunLine.v1.y/FRACUNIT +" to "+ p.player.wallRunLine.v2.x/FRACUNIT +" , "+ p.player.wallRunLine.v2.y/FRACUNIT)
		end
		
		local xytSpeed
		local tSpeed
		if (p.player.lastX ~= nil) then
			xytSpeed = R_PointToDist2(p.x, p.y, p.player.lastX, p.player.lastY)
			tSpeed = R_PointToDist2(0, p.z, xytSpeed, p.player.lastZ)
		end
		
		if (p.player.wallRunLine == nil) or (p.player.lineDist == nil) or (p.player.jumpDown == 0) or (p.player.wallRunSpeed < 4*FRACUNIT) 
		or ((tSpeed) and (tSpeed < 4*FRACUNIT) and (p.player.lastX))  then 
			p.player.wallRunAngleOffset = 0
			p.player.lastX = nil
			WidoWallJump(p)
			p.player.mo.renderflags =  $1&~RF_HORIZONTALFLIP
			return 
		end
		local closeX, closeY = ClosestPointOnLineSegment(p.x, p.y, p.player.wallRunLine)
		//local horizAngle = R_PointToAngle2(p.x, p.y, closeX, closeY)
		local lastHorizAngle
		if (p.player.wallRunLine ~= p.player.lastWallRunLine) then
			lastHorizAngle = R_PointToAngle2(p.player.lastWallRunLine.v1.x, p.player.lastWallRunLine.v1.y, p.player.lastWallRunLine.v2.x, p.player.lastWallRunLine.v2.y)+ANGLE_90
					if (P_PointOnLineSide(p.x, p.y, p.player.lastWallRunLine)) then
						lastHorizAngle = $+ANGLE_180
					end
		end
		local horizAngle = R_PointToAngle2(p.player.wallRunLine.v1.x, p.player.wallRunLine.v1.y, p.player.wallRunLine.v2.x, p.player.wallRunLine.v2.y)+ANGLE_90
		if (P_PointOnLineSide(p.x, p.y, p.player.wallRunLine)) then
			horizAngle = $+ANGLE_180
		end
		
		
		if (p.player.wallRunLine ~= p.player.lastWallRunLine) then
			p.player.wallRunAngleOffset = $+(horizAngle-lastHorizAngle)
		end
		
		
		if ( p.player.wallRunAngleOffset ~= 0) and not (p.player.pflags & PF_ANALOGMODE) then
			local delta = p.player.wallRunAngleOffset/10
			if (delta > ANG1) then
				delta = ANG1
			elseif (delta < -ANG1) then
				delta = -ANG1
			end
			p.player.wallRunAngleOffset = $-delta
			p.angle = $+delta
		end
		
		
		p.player.drawangle = horizAngle+ANGLE_90
		local vertAngle = (horizAngle)-((p.player.cmd.angleturn<<16)+p.player.wallRunAngleOffset)
		
		if (vertAngle < -ANGLE_90) then
			vertAngle = -ANGLE_90+1
		elseif (vertAngle > ANGLE_90) then
			vertAngle = ANGLE_90-1
		end
		vertAngle = $+ANGLE_90
		 
		if (p.player.powers[pw_sneakers] > 0) or (p.player.powers[pw_super] > 0) then
			if (p.player.wallRunSpeed < 30*FRACUNIT) then
				p.player.wallRunSpeed = $+(FRACUNIT/5)
			end
		else
			p.player.wallRunSpeed = $+((sin(vertAngle)*-19)/10)-(FRACUNIT/10)
		end
			
		P_InstaThrust(p, horizAngle+ANGLE_90, FixedMul(cos(vertAngle),p.player.wallRunSpeed))
		//P_Thrust(p, horizAngle, p.player.lineDist/10)
		P_Thrust(p, horizAngle, 5*FRACUNIT)
		P_SetObjectMomZ(p, FixedMul(sin(vertAngle),p.player.wallRunSpeed))

		if (vertAngle < ANG30) or (vertAngle > ANG30*5) then
			p.state = S_PLAY_WIDOWALLRUN1
			if (vertAngle > ANGLE_90) then
				p.player.drawangle = $+ANGLE_180
				p.player.mo.renderflags =  $1|RF_HORIZONTALFLIP
			else
				p.player.mo.renderflags =  $1&~RF_HORIZONTALFLIP
			end
		elseif (vertAngle < ANG60) or (vertAngle > ANG30*5) then
			p.state = S_PLAY_WIDOWALLRUN2
			if (vertAngle > ANGLE_90) then
				p.player.drawangle = $+ANGLE_180
				p.player.mo.renderflags =  $1|RF_HORIZONTALFLIP
			else
				p.player.mo.renderflags =  $1&~RF_HORIZONTALFLIP
			end
		else
			p.state = S_PLAY_WIDOWALLRUN3
			p.player.drawangle = $-ANGLE_90
			p.player.mo.renderflags =  $1&~RF_HORIZONTALFLIP
		end
		local minTics = (40-(p.player.wallRunSpeed/FRACUNIT))/10
		if (p.tics > minTics) then
			p.tics = minTics
		end
		p.player.lastX = p.x
		p.player.lastY = p.y
		p.player.lastZ = p.z

end

local function DoParry(p, inflictor, source)
		
		if (p.player.parryTime > 0) then
			S_StartSound(p,sfx_s1af,p.player)
			local xOffset = cos(p.player.drawangle)*50
			local yOffset = sin(p.player.drawangle)*50
			local parryItem = P_SpawnMobj(p.x+xOffset,p.y+yOffset, p.z+(p.height),MT_WIDOPARRY)
			parryItem.state = S_WIDOPARRY1
			parryItem.angle = p.player.drawangle+ANGLE_90
			parryItem.scale = 0
			parryItem.destscale = FRACUNIT*10
			parryItem.scalespeed = FRACUNIT
			parryItem.blendmode = AST_ADD
		
		end
		local parryObject
		if (source == nil) then
			p.player.parryTime = 0
			p.player.powers[pw_flashing] = 35
			return false
		end
		
		p.momx = 0
		p.momy = 0
		if (p.player.parryTime > 0) then 
			P_SetObjectMomZ(p, 5*FRACUNIT)
		else
			P_SetObjectMomZ(p, 0)
		end
		p.state = S_PLAY_MELEE
		if (inflictor) and (widoParryBlacklist[inflictor.type] == nil) and (inflictor.valid) then
			if (inflictor.flags & MF_MISSILE) and (inflictor.target ~= p) then 
				//local newTarget = P_LookForEnemies(p.player, true, true)
				if (source) then 
					P_SpawnMissile(p, source, inflictor.type)
				end
				inflictor.state = S_NULL
				
				if (p.player.parryTime > 0) then
					p.player.parryTime = -10
				end
				return false
				
			end
			if (inflictor.health == 1) and not (inflictor.flags & MF_BOSS) then
				parryObject = inflictor
			else
				if (p.player.parryTime > 0) then
					p.player.parryTime = -10
				end
				p.player.powers[pw_flashing] = 35
				return false
			end
		elseif (source.valid) and (source.health == 1) and (widoParryBlacklist[source.type] == nil) and not (source.flags & MF_MONITOR) 
			parryObject = source
		else
			return false
		end
		parryObject.target = p
		parryObject.tics = -1
		parryObject.flags = MF_MISSILE|MF_NOGRAVITY|MF_NOBLOCKMAP
		local newTarget = P_LookForEnemies(p.player, true, true)
		if (newTarget) then
			parryObject.momx = (newTarget.x-parryObject.x)/10
			parryObject.momy = (newTarget.y-parryObject.y)/10
			parryObject.momz = (newTarget.z-parryObject.z)/10
		
		else
			parryObject.momx = cos(p.angle)*50
			parryObject.momy = sin(p.angle)*50
			parryObject.momz = 0
		end
		
		if (p.player.parryTime > 0) then
			p.player.parryTime = -10
		end
		return false

end
function A_SlashScale(actor, var1, var2) 
	
	actor.spritexscale = FRACUNIT*actor.reactiontime/4
	if (var1) then
		actor.spriteyscale = (FRACUNIT*(8-actor.reactiontime))/2
	end
	actor.reactiontime = $-1
	if (actor.reactiontime == 0) then
		actor.state = S_NULL
	end
	
end




mobjinfo[MT_WIDOFOLLOW] = {
spawnstate = S_WIDOFOLLOW,
speed = 1,
radius = 32*FRACUNIT,
height = 64*FRACUNIT,
reactiontime = 8,
damage = 3,
spawnhealth = 1,
dispoffset = 0,
flags =  	MF_NOBLOCKMAP|MF_NOGRAVITY
}

states[S_WIDOFOLLOW] = {
sprite = SPR_PLAY,
frame = A,
tics = 1,
action = A_WidoFollow,
nextstate = S_WIDOFOLLOW
}

mobjinfo[MT_WIDOELEMENTAL] = {
spawnstate = S_WIDOELEMENTAL,
speed = 1,
radius = 32*FRACUNIT,
height = 38*FRACUNIT,
reactiontime = 8,
damage = 3,
spawnhealth = 1,
dispoffset = 0,
flags =  	MF_NOBLOCKMAP|MF_NOGRAVITY
}

states[S_WIDOELEMENTAL] = {
sprite = SPR_WSLA,
frame = A|FF_ANIMATE,
tics = 10,
var1 = 2,
var2 = 1,
nextstate = S_NULL
}


mobjinfo[MT_WIDOSLASH] = {
spawnstate = S_WIDOSLASH,
speed = 1,
radius = 32*FRACUNIT,
height = 38*FRACUNIT,
reactiontime = 8,
damage = 3,
spawnhealth = 1,
dispoffset = 0,
flags =  	MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_PAPERCOLLISION
}

states[S_WIDOSLASH] = {
sprite = SPR_WSLA,
frame = A,
tics = 1,
action = A_SlashScale,
nextstate = S_WIDOSLASH
}

states[S_WIDOSLASH2] = {
sprite = SPR_WSLA,
frame = A|TR_TRANS30,
tics = 1,
action = A_SlashScale,
var1 = 1,
nextstate = S_WIDOSLASH2
}


mobjinfo[MT_WIDOPARRY] = {
spawnstate = S_WIDOPARRY,
speed = 1,
radius = 32*FRACUNIT,
height = 38*FRACUNIT,
reactiontime = 8,
damage = 3,
spawnhealth = 1,
dispoffset = 0,
flags =  	MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_WIDOPARRY] = {
sprite = SPR_WSLA,
frame = B|FF_PAPERSPRITE|TR_TRANS70,
tics = 2,
nextstate = S_NULL
}


states[S_WIDOPARRY1] = {
sprite = SPR_WSLA,
frame = C|FF_PAPERSPRITE|TR_TRANS50,
tics = 3,
nextstate = S_WIDOPARRY2
}
states[S_WIDOPARRY2] = {
sprite = SPR_WSLA,
frame = C|FF_PAPERSPRITE|TR_TRANS60,
tics = 2,
nextstate = S_WIDOPARRY3
}
states[S_WIDOPARRY3] = {
sprite = SPR_WSLA,
frame = C|FF_PAPERSPRITE|TR_TRANS70,
tics = 2,
nextstate = S_WIDOPARRY4
}
states[S_WIDOPARRY4] = {
sprite = SPR_WSLA,
frame = C|FF_PAPERSPRITE|TR_TRANS80,
tics = 2,
nextstate = S_WIDOPARRY5
}
states[S_WIDOPARRY5] = {
sprite = SPR_WSLA,
frame = C|FF_PAPERSPRITE|TR_TRANS90,
tics = 2,
nextstate = S_NULL
}


states[S_PLAY_WIDOWALLRUN1] = {
sprite = SPR_PLAY,
frame = 21,
tics = 10,
nextstate = S_PLAY_WIDOWALLRUN1
}
states[S_PLAY_WIDOWALLRUN2] = {
sprite = SPR_PLAY,
frame = 23,
tics = 10,
nextstate = S_PLAY_WIDOWALLRUN2
}
states[S_PLAY_WIDOWALLRUN3] = {
sprite = SPR_PLAY,
frame = 24,
tics = 10,
nextstate = S_PLAY_WIDOWALLRUN3
}
states[S_PLAY_WIDOTRANS] = {
sprite = SPR_PLAY,
frame = 20,
tics = 2,
nextstate = S_PLAY_FALL
}

local function WidoGetAura(player)

		player.slashAuraSprite = nil
		player.slashAuraSubFrame = nil
		player.slashAuraVar2 = nil
		player.slashAuraScale = nil
	if (player.powers[pw_shield] & SH_WHIRLWIND) then
		player.slashAuraSprite = SPR_DUST
		player.slashAuraSubFrame = B|TR_TRANS70|FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM
		player.slashAuraVar2 = 1
		player.slashAuraScale = FRACUNIT*2
	end
	if (player.powers[pw_shield] & SH_PROTECTWATER) then
		player.slashAuraSprite = SPR_BUBL
		player.slashAuraSubFrame = B|TR_TRANS70|FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM
		player.slashAuraVar2 = 10
		player.slashAuraScale = FRACUNIT+(FRACUNIT/2)
	end
	if (player.powers[pw_shield] & SH_PROTECTFIRE) then
		if (P_RandomByte() > 128) and (player.powers[pw_shield] & SH_PROTECTWATER) then return end
		player.slashAuraSprite = SPR_FLME
		player.slashAuraSubFrame = A|TR_TRANS70|FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM
		player.slashAuraVar2 = 1
		player.slashAuraScale = FRACUNIT/2
	end
	if (player.powers[pw_shield] & SH_FORCE) then
		player.slashAuraSprite = SPR_FORC
		player.slashAuraSubFrame = U|TR_TRANS70|FF_FULLBRIGHT
		player.slashAuraVar2 = 10
		player.slashAuraScale = FRACUNIT/10
	end
	if (player.powers[pw_shield] & SH_PROTECTELECTRIC) then
		player.slashAuraSprite = SPR_WZAP
		player.slashAuraSubFrame = A|TR_TRANS70|FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM
		player.slashAuraVar2 = 1
		player.slashAuraScale = FRACUNIT*2
	end
	if (player.powers[pw_shield] == SH_ARMAGEDDON) then
		player.slashAuraSprite = SPR_SSPK
		player.slashAuraSubFrame = A|TR_TRANS70|FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM
		player.slashAuraVar2 = 1
		player.slashAuraScale = FRACUNIT
	end
		

end

addHook("MapLoad", do
    for player in players.iterate
		if player.mo.skin ~= "wido" then
			continue
		end
		player.parryTime = 0
		player.slashTime = 0
		player.spinDown = 0
		player.jumpDown = 0
		player.wallJumpTime = 0
		player.wallJumpLine = 0
		player.wallRunSpeed = 0
		player.wallRunAngleOffset = 0
		player.transTime = 0
		player.widoFollow = nil
	end
end)

addHook("PlayerThink", function(player)
	if not (player.mo.skin == "wido") then 	return end
	
	
	if (player.parryTime == nil)  then
		player.parryTime = 0
		player.slashTime = 0
		player.spinDown = 0
		player.jumpDown = 0
		player.wallJumpTime = 0
		player.wallJumpLine = 0
		player.wallRunSpeed = 0
		player.wallRunAngleOffset = 0
		player.transTime = 0
		player.widoFollow = nil
	end
	
	if (player.cmd.buttons & BT_USE) then
		player.spinDown = $+1
	else
		player.spinDown = 0
	end
	if (All7Emeralds(emeralds)) and (((player.cmd.buttons & BT_CUSTOM1) or (player.transTime >= 18)) and (player.transTime >= 0)) and not (player.pflags & PF_STASIS) and not (player.pflags & PF_JUMPSTASIS) and not (player.exiting) then
		if (P_IsObjectOnGround(player.mo) or (player.transTime >= 18)) then
			player.transTime = $+1
			player.mo.momx = 0
			player.mo.momy = 0
			if ((player.powers[pw_super] == 0) or (player.transTime >= 18)) then
				player.mo.state = S_PLAY_WIDOTRANS
				
				if (player.transTime < 4) then
					player.mo.frame = 0
				elseif (player.transTime < 8) then
					player.mo.frame = 1
				elseif (player.transTime < 16) then
					player.mo.frame = 2
				elseif (player.transTime < 18) then
					player.mo.frame = 3
				elseif (player.transTime < 20) then
					player.mo.frame = 4
				elseif (player.transTime < 22) then
					player.mo.frame = 5
				elseif (player.transTime % 5 == 0) then
				
				for i = 0, 16		
					local shockwave = P_SpawnPointMissile(player.mo, player.mo.x, player.mo.y, player.mo.z+FRACUNIT, MT_WIDOSLASH, player.mo.x, player.mo.y, player.mo.z)
					if (shockwave) then
						shockwave.target = player.mo
						shockwave.reactiontime = 8
						shockwave.state = S_WIDOSLASH2
						shockwave.flags2 = MF2_SPLAT
						shockwave.blendmode = AST_ADD
						shockwave.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
						shockwave.angle = i*ANGLE_22h
						P_InstaThrust(shockwave, shockwave.angle+ANGLE_90, 32*FRACUNIT)
					end
				end
					
				end
				if (player.transTime == 22) then
					//emeralds = EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7
					player.charflags = $|SF_SUPER
					S_StartSound(player.mo,sfx_supert,player)
					P_StartQuake(FRACUNIT*2, 28)
					player.powers[pw_super] = 1
					hud.disable("rings")
				end
				if (player.transTime >= 50) then
					player.transTime = -1
					player.mo.state = S_PLAY_FALL
				end
				
			end
			if (player.powers[pw_super]) then
				player.mo.frame = 0
			end
		end
	elseif (player.transTime > 0) then
		player.transTime = 0
	end
	if (player.transTime == -1) and not (player.cmd.buttons & BT_CUSTOM1) then
		player.transTime = -2
	end
	if (player.transTime == -2) and (player.cmd.buttons & BT_CUSTOM1) then
		player.powers[pw_super] = 0
		S_StartSound(player.mo,sfx_s3k66,player)
	end
	if (player.transTime < 0) and (player.powers[pw_super] == 0) then
		player.mo.color = player.skincolor
		player.rings = 0
		player.charflags = $1&~SF_SUPER
		hud.enable("rings")
		player.transTime = 0
	end
	
	if (player.powers[pw_super]) then
		if not ((player.widoFollow) and (player.widoFollow.valid)) then
		
			player.widoFollow = P_SpawnMobj(player.mo.x,player.mo.y,player.mo.z,MT_WIDOFOLLOW)
			player.widoFollow.skin = "antlers"
			player.widoFollow.target = player.mo
			player.widoFollow.angle = player.drawangle
			player.widoFollow.blendmode = AST_ADD
		
		end
		player.mo.color = player.skincolor
		if (player.rings < 2) then
			player.rings = 2
		end
		if (leveltime % 35 == 0) then
			player.rings = $+1
		end
	end
	
	
	if (player.cmd.buttons & BT_JUMP) then
		player.jumpDown = $+1
	else
		player.jumpDown = 0
	end
	
	if (player.wallJumpTime) then
		player.wallJumpTime = $-1
	end
	
	player.mo.lastline = nil
	if (player.mo.state == S_PLAY_RUN) then
		if (player.mo.tics > 1) then player.mo.tics = 1 end
	end
	if (player.mo.state == S_PLAY_SPRING) or (player.mo.state == S_PLAY_RIDE) then
		player.slashTime = 0
	end
	
	if (player.mo.state == S_PLAY_WIDOWALLRUN1) or (player.mo.state == S_PLAY_WIDOWALLRUN2) or (player.mo.state == S_PLAY_WIDOWALLRUN3) then
		WidoWallRun(player.mo)
	elseif (player.mo.state ~= S_PLAY_MELEE) then
		if (player.mo.renderflags & RF_HORIZONTALFLIP) then
			player.mo.renderflags =  $1&~RF_HORIZONTALFLIP
		end
	end
	
	if (player.mo.state == S_PLAY_WAIT) then
		if ((player.mo.frame % 4) < 3) then
			if (player.mo.anim_duration > 2) then
				player.mo.anim_duration = 2
			end
		else
			player.mo.anim_duration = 16
		end
	end
	if (player.mo.state == S_PLAY_STND) then
		if (player.mo.tics > 35) then
			player.mo.tics = 35
		end
	end
	if (player.mo.state == S_PLAY_ROLL) then
		WidoGetAura(player)
		
		
		local spinAngle = (player.mo.frame+14)*ANGLE_22h
		local slashItemStart = 0
		local slashItemCount = 0
		if (player.powers[pw_super]) then
			slashItemStart = -1
			slashItemCount = 1
		end
		
		for i = slashItemStart, slashItemCount
			local xOffset = (FixedMul(cos(spinAngle),cos(player.mo.angle)) )*50
			xOffset = $+(cos(player.mo.angle+ANGLE_90)*(i*20))
			local yOffset = (FixedMul(cos(spinAngle),sin(player.mo.angle)) )*50
			xOffset = $+(sin(player.mo.angle+ANGLE_90)*(i*20))
			local zOffset = sin(spinAngle)*50
			local slashItem = P_SpawnMobj(player.mo.x+xOffset,player.mo.y+yOffset,player.mo.z+zOffset,MT_WIDOSLASH)
			slashItem.target = player.mo
			slashItem.angle = player.drawangle+ANG1
			slashItem.renderflags = RF_PAPERSPRITE
			slashItem.blendmode = AST_ADD
			slashItem.rollangle = spinAngle
			slashItem.spriteyscale = FRACUNIT*2
			slashItem.reactiontime = 4
			slashItem.momx = player.mo.momx
			slashItem.momy = player.mo.momy
			slashItem.momz = player.mo.momz
		end
		if (player.slashAuraSprite) then
			local xOffset = (FixedMul(cos(spinAngle),cos(player.mo.angle)) )*50
			local yOffset = (FixedMul(cos(spinAngle),sin(player.mo.angle)) )*50
			local zOffset = sin(spinAngle)*50
			local slashAura = P_SpawnMobj(player.mo.x+xOffset,player.mo.y+yOffset,player.mo.z+zOffset,MT_WIDOELEMENTAL)
			slashAura.sprite  = player.slashAuraSprite
			slashAura.frame = player.slashAuraSubFrame
			slashAura.anim_duration = player.slashAuraVar2
			
			slashAura.blendmode = AST_ADD
			slashAura.scale = P_RandomFixed()+player.slashAuraScale
			slashAura.fuse = 10
			slashAura.rollangle = P_RandomKey(360)*ANG1
		end
	end
		
	
		if (player.cmd.forwardmove == 0) and (player.cmd.sidemove == 0) then
			if (player.parryTime == 0) then 
				player.parryTime = -1 
			end
		elseif (player.parryTime == -1) and (player.powers[pw_flashing] == 0) and not (player.pflags & PF_STASIS) and (player.mo.health) then
			player.parryTime = 10
				if (player.mo.state == S_PLAY_WAIT) then
					player.parryTime = $+10
				end
				if (player.powers[pw_super] > 0) then
					player.parryTime = $+10
				end
		end
		if (player.parryTime <= -2) then
			player.parryTime = $+1
			if (player.parryTime == -1) then
				player.mo.state = S_PLAY_FALL
				player.powers[pw_flashing] = 20
			end
		
		end
		if (player.parryTime > 0) then
			player.parryTime = $-1
			local xOffset = cos(player.drawangle)*((player.parryTime%10)-5)*5
			local yOffset = sin(player.drawangle)*((player.parryTime%10)-5)*5
			local parryItem = P_SpawnMobj(player.mo.x+xOffset,player.mo.y+yOffset,player.mo.z+(player.mo.height/2),MT_WIDOPARRY)
			parryItem.angle = player.drawangle+ANGLE_90
			parryItem.scale = abs( sin(player.parryTime*ANG15) )
			parryItem.color = 10-(player.parryTime%10)
			if (player.parryTime > 10) then
				parryItem.color = SKINCOLOR_BLUEBELL
				parryItem.scale = ($*3)/2
			end
			parryItem.blendmode = AST_ADD
		end
		
	local targetradius = 512*FRACUNIT
	player.target = nil
	local searchcenterx = player.mo.x + FixedMul(cos(player.mo.angle),targetradius)
	local searchcentery = player.mo.y + FixedMul(sin(player.mo.angle),targetradius)
	searchBlockmap("objects",WidoSearch, player.mo,
			searchcenterx-targetradius,searchcenterx+targetradius,
			searchcentery-targetradius,searchcentery+targetradius)
			
	if (player.target) then
		P_SpawnLockOn(player, player.target, S_LOCKON1)
	end
	if (player.slashTime) then
		player.wallJumpTime = 0
		if (player.slashDir) then
			player.mo.state = S_PLAY_MELEE
			player.mo.tics = -1
			player.slashTime = $+1
			if (player.slashTime < 6) then
				player.mo.frame = 1
				player.mo.momx = ($*7)/10
				player.mo.momy = ($*7)/10
				player.mo.momz = ($*7)/10
				player.mo.target = player.slashTarget
				A_FaceTarget(player.mo,0,0)
				player.drawangle = player.mo.angle
				
				if ( not (player.slashTarget.flags2 & MF2_FRET) and (player.slashTarget.doubleTapped)) then
				player.slashTarget.doubleTapped = false
				end
			elseif (player.slashTime < 14) then
				if (player.slashTarget) and (player.slashTarget.valid) then
					if (player.slashTime == 7) then
						S_StartSound(player.mo,sfx_s3k42,player)
						player.mo.momx = (player.slashTarget.x-player.mo.x)/5
						player.mo.momy = (player.slashTarget.y-player.mo.y)/5
						player.mo.momz = (player.slashTarget.z-player.mo.z)/5
						P_Thrust(player.mo, player.mo.angle+(ANGLE_90*player.slashDir), 15*FRACUNIT)
						
						if (player.slashTarget.flags2 & MF2_FRET) and not (player.slashTarget.doubleTapped) then
							player.slashTarget.flags2 = $1&~MF2_FRET
							player.slashTarget.doubleTapped = true
						end
						if (player.powers[pw_super] == 0) then
							player.slashTarget.doubleTapped = true
						end
					elseif (player.slashTime == 13) then
					end
				end
				
				local xyDist = R_PointToDist2(player.mo.x, player.mo.y, player.slashTarget.x, player.slashTarget.y)
				local dist = R_PointToDist2(0, player.mo.z, xyDist, player.slashTarget.z)
				if (dist < FRACUNIT*128 and player.slashTime > 7) then
					if (player.parryTime > 0 and player.slashTarget.health == 1 and not (player.slashTarget.flags & MF_BOSS) and not (player.slashTarget.flags & MF_MONITOR)) then
						DoParry(player.mo, nil, player.slashTarget)
						player.slashTarget = nil
						player.slashTime = 13
						P_SetObjectMomZ(player.mo, 10*FRACUNIT)
					else

						P_DamageMobj(player.slashTarget, player.mo, player.mo)
						player.slashTarget = nil
						player.slashTime = 13
						P_SetObjectMomZ(player.mo, 10*FRACUNIT)
					end
				end
				local slashAngle = (player.cmd.angleturn<<16)+((player.slashTime-10)*(ANGLE_11hh*player.slashDir))
				local slashDist = 150
				local slashItemX = player.mo.x+(cos(slashAngle)*slashDist)
				local slashItemY = player.mo.y+(sin(slashAngle)*slashDist)
				local slashItemZ = player.mo.z
				
				if (player.slashTime > 7) then
					
					local slashItem = P_SpawnXYZMissile(player.mo, player.mo, MT_WIDOSLASH, slashItemX, slashItemY, slashItemZ)
					if(slashItem) then
						slashItem.flags2 = MF2_SPLAT
						slashItem.blendmode = AST_ADD
						slashItem.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
						P_CreateFloorSpriteSlope(slashItem)
						slashItem.angle = R_PointToAngle2(slashItem.x, slashItem.y, player.lastSlashx, player.lastSlashy)
						local distToLast = R_PointToDist2(slashItem.x, slashItem.y, player.lastSlashx, player.lastSlashy)
						slashItem.spriteyscale = distToLast/32
						slashItem.floorspriteslope.o = {
							x = slashItem.x,
							y = slashItem.y,
							z = slashItem.z
						}
						if ((distToLast/FRACUNIT) == 0) then distToLast = $+1 end
						if (distToLast/FRACUNIT == 0) then distToLast = FRACUNIT end
						slashItem.floorspriteslope.zdelta = (slashItem.z-player.lastSlashz)/(distToLast/FRACUNIT)
						slashItem.floorspriteslope.xydirection = slashItem.angle
						if (player.powers[pw_super] > 0) then
							for i = -1, 1, 2
								local slashItem2 = P_SpawnXYZMissile(player.mo, player.mo, MT_WIDOSLASH, slashItemX, slashItemY, slashItemZ+i*(FRACUNIT*32))
								if(slashItem2) then
									slashItem2.flags2 = MF2_SPLAT
									slashItem2.blendmode = AST_ADD
									slashItem2.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
									P_CreateFloorSpriteSlope(slashItem2)
									slashItem2.angle = slashItem.angle
									slashItem2.spriteyscale = slashItem.spriteyscale
									slashItem2.floorspriteslope.o = {
										x = slashItem2.x,
										y = slashItem2.y,
										z = slashItem2.z
									}
									slashItem2.floorspriteslope.zdelta = slashItem.floorspriteslope.zdelta
									slashItem2.floorspriteslope.xydirection = slashItem.floorspriteslope.xydirection
								end
							end
						end
					end
				end
				
				player.lastSlashx = slashItemX
				player.lastSlashy = slashItemY
				player.lastSlashz = slashItemZ
				player.mo.frame = (player.slashTime-6)
			elseif (player.slashTime < 28) then
				player.mo.frame = 7
				player.mo.momx = ($*9)/10
				player.mo.momy = ($*9)/10
				player.mo.momz = ($*9)/10
			else
				player.slashTime = 0
				player.mo.renderflags =  $1&~RF_HORIZONTALFLIP
				player.pflags  =  $1|PF_JUMPED
				player.mo.state = S_PLAY_FALL
			
			end
			
			
				
		else //Forward Slash
			
			player.slashTime = $+1
			if (player.slashTime == 2) then
				S_StartSound(player.mo,sfx_spndsh,player)
			end
			if (player.slashTime < 12) then
				player.drawangle = player.cmd.angleturn<<16
				player.mo.state = S_PLAY_MELEE_LANDING
				player.mo.frame = player.slashTime/3
			if (player.slashTime == 11) then
				if (player.powers[pw_shield] & SH_FORCE) and (player.cmd.buttons & BT_USE) then
					player.mo.momx = 0
					player.mo.momy = 0
					player.mo.momz = 0
					player.slashTime = 10
				end
			end
			elseif (player.slashTime == 12) then
				local vertiAngle = -ANG10
				if (player.powers[pw_shield] & SH_WHIRLWIND) then
					vertiAngle = ANG20
				end
				local horizAngle = (player.cmd.angleturn<<16)
				if (player.slashTarget) and (player.slashTarget.valid) and (player.powers[pw_shield] & SH_PROTECTELECTRIC) then
					horizAngle = R_PointToAngle2(player.mo.x, player.mo.y, player.slashTarget.x, player.slashTarget.y)
					local dist = R_PointToDist2(player.mo.x, player.mo.y, player.slashTarget.x, player.slashTarget.y)
					vertiAngle = R_PointToAngle2(0, 0, dist, player.slashTarget.z-player.mo.z)
				end
				
				local horizMom = cos(vertiAngle)*40
				local vertiMom = sin(vertiAngle)*40
				P_InstaThrust(player.mo, horizAngle, horizMom)
				P_SetObjectMomZ(player.mo, vertiMom)
				player.mo.state = S_PLAY_ROLL
				player.drawangle = horizAngle
				
			else
			
				if (player.cmd.buttons & BT_USE) and (player.slashTime == 13) and ((player.powers[pw_shield] & SH_PROTECTWATER) or (player.powers[pw_shield] & SH_PROTECTFIRE)) then
					if (player.speed > FRACUNIT*30)
						player.slashTime = 12
						if (player.mo.z-player.mo.floorz < FRACUNIT*64) then
							local targetMomZ = (player.mo.floorz+(FRACUNIT*64))-player.mo.z
							if (targetMomZ > 16*FRACUNIT) then
								targetMomZ = 16*FRACUNIT
							end
							P_SetObjectMomZ(player.mo, targetMomZ)
							player.mo.state = S_PLAY_ROLL
						end
					end
				elseif (player.powers[pw_shield] & SH_PROTECTELECTRIC) and (player.slashTarget) and (player.slashTarget.valid) and (player.slashTarget.health > 0) and (player.slashTime < 60) then
				
					local horizAngle = R_PointToAngle2(player.mo.x, player.mo.y, player.slashTarget.x, player.slashTarget.y)
					local dist = R_PointToDist2(player.mo.x, player.mo.y, player.slashTarget.x, player.slashTarget.y)
					local realDist = R_PointToDist2(0, player.mo.z, dist, player.slashTarget.z)
					local vertiAngle = R_PointToAngle2(0, 0, dist, player.slashTarget.z-player.mo.z)
					local horizMom = cos(vertiAngle)*40
					local vertiMom = sin(vertiAngle)*40
					P_InstaThrust(player.mo, horizAngle, horizMom)
					P_SetObjectMomZ(player.mo, vertiMom)
					player.mo.state = S_PLAY_ROLL
					if (realDist < 128*FRACUNIT) then
						P_DamageMobj(player.slashTarget, player.mo, player.mo)
						player.slashTarget = nil
						player.slashTime = 0
						P_SetObjectMomZ(player.mo, 10*FRACUNIT)
							player.mo.state = S_PLAY_SPRING
					end
					
					
				elseif (P_IsObjectOnGround(player.mo)) then
				
					if (player.powers[pw_shield] == SH_ARMAGEDDON) then
						P_BlackOw(player)
					end
					player.slashTarget = nil
					for i = 0, 16		
						local shockwave = P_SpawnPointMissile(player.mo, player.mo.x, player.mo.y, player.mo.z+FRACUNIT, MT_WIDOSLASH, player.mo.x, player.mo.y, player.mo.z)
						if (shockwave) then
							shockwave.target = player.mo
							shockwave.reactiontime = 8
							shockwave.state = S_WIDOSLASH2
							shockwave.flags2 = MF2_SPLAT
							shockwave.blendmode = AST_ADD
							shockwave.renderflags = RF_SLOPESPLAT|RF_NOSPLATBILLBOARD
							shockwave.angle = i*ANGLE_22h
							P_InstaThrust(shockwave, shockwave.angle+ANGLE_90, 32*FRACUNIT)
							
							if (player.slashAuraSprite) then
								local slashAura = P_SpawnMobj(player.mo.x,player.mo.y,player.mo.z,MT_WIDOELEMENTAL)
								slashAura.sprite  = player.slashAuraSprite
								slashAura.frame = player.slashAuraSubFrame
								slashAura.anim_duration = player.slashAuraVar2
								slashAura.blendmode = AST_ADD
								slashAura.scale = P_RandomFixed()+player.slashAuraScale
								slashAura.fuse = 10
								slashAura.rollangle = P_RandomKey(360)*ANG1
								slashAura.angle = i*ANGLE_22h
								P_InstaThrust(slashAura, slashAura.angle+ANGLE_90, 32*FRACUNIT)
							end
						end
					end
					player.slashTime = 0
					S_StartSound(player.mo,sfx_doord2,player)
					WidoWallBust(player, player.mo.subsector.sector) 
				end
			end
			
		end
		
	end
	
	
end, false)




addHook("SpinSpecial", function(player)
	if not (player.mo.skin == "wido") then return end
	if (player.gotflag) then return end
	if (player.pflags  & PF_STASIS) or (player.pflags & PF_JUMPSTASIS) or (player.exiting) then return end
	
	if (player.mo.state == S_PLAY_SPRING) then return end
	if (player.slashTime > 0) and ((player.powers[pw_super] == 0) or (player.slashTime < 20)) then return end
	if (player.spinDown > 1) then return end
	player.slashTime = 1
	if (player.target) and (player.target.valid) then
			player.slashTarget = player.target
			local relativeAngle = (player.cmd.angleturn<<16)-R_PointToAngle2(player.mo.x, player.mo.y, player.slashTarget.x, player.slashTarget.y)
			if ( relativeAngle < 0) then
				player.slashDir = 1
				player.mo.renderflags =  $1&~RF_HORIZONTALFLIP
			else
				player.slashDir = -1
				player.mo.renderflags =  $1|RF_HORIZONTALFLIP
			end
			if (player.cmd.sidemove <= -35) then
				player.slashDir = 1
				player.mo.renderflags =  $1&~RF_HORIZONTALFLIP
			elseif(player.cmd.sidemove >= 35)
				player.slashDir = -1
				player.mo.renderflags =  $1|RF_HORIZONTALFLIP
			end
			if (player.powers[pw_shield] & SH_PROTECTELECTRIC) or (player.mo.flags2 & MF2_TWOD) or (twodlevel) then
				player.slashDir = 0
			end
	else
		player.slashDir = 0
		player.slashTarget = nil
	end
	P_SetObjectMomZ(player.mo, 10*FRACUNIT)
end, false)


addHook("ShouldDamage", function(p, inflictor, source, damage, damagetype)
	if (p.player == nil) then return end
	if (p.skin ~= "wido") then return end
	if (damagetype & DMG_DEATHMASK) then return end
	if (p.player.slashTime) then
		return false
	end
	if (source == p) then return false end
	if (inflictor == p) then return false end
	if	(p.player.parryTime > 0) or (p.player.parryTime <= -2) then	
		return DoParry(p, inflictor, source)
	end
	if (p.player.powers[pw_shield]) then
		p.player.parryTime = 1
		p.player.powers[pw_shield] = 0
		return DoParry(p, inflictor, source)
	end
	if (p.player.powers[pw_super] > 0) and (p.player.powers[pw_flashing] == 0) and (p.player.powers[pw_invulnerability] == 0)  then
		p.player.powers[pw_super] = 0
		p.player.rings = 0
		P_KillMobj(p)
		return false
	end
		return nil
end, MT_PLAYER)

addHook("PlayerCanDamage", function(player, mob)
	if not (player.mo) then return end
	if (player.mo.skin ~= "wido") then return end
	if (player.slashTime) then return end
	if (player.powers[pw_super] > 0) and (player.powers[pw_flashing] == 0) and (player.powers[pw_invulnerability] == 0)  then
		return false
	end
	
end)


addHook("MobjLineCollide", function(p, line) 
if (p.player == nil) then return end
if (p.skin ~= "wido") then return end
if (p.player.gotflag) then return end
	if (p.lastline) then
		local closeXLast, closeYLast = ClosestPointOnLineSegment(p.x, p.y, p.lastline)
		local distLast = R_PointToDist2(p.x, p.y, closeXLast, closeYLast)
		local closeX, closeY = ClosestPointOnLineSegment(p.x, p.y, line)
		local dist = R_PointToDist2(p.x, p.y, closeX, closeY)
		
		if (dist > distLast) then 
			return
		end
		
	end
	p.lastline = line
	return nil

end, MT_PLAYER)


addHook("MobjMoveBlocked", function(p)
if (p.player == nil) then return end
if (p.skin ~= "wido") then return end
if (p.player.gotflag) then return end
if (p.player.slashTime >= 12) and (p.player.slashDir == 0) then
	if (p.lastline) then
		if (p.lastline.frontsector) and (p.lastline.frontsector.valid) then
			WidoWallBust(p.player, p.lastline.frontsector)
		end
		if (p.lastline.backsector) and (p.lastline.backsector.valid) then
			WidoWallBust(p.player, p.lastline.backsector)
		end
	end
end

if (p.lastline) and (((p.player.slashTime == 0) or (p.player.powers[pw_super])) and (p.state ~= S_PLAY_WIDOWALLRUN1) and (p.state ~= S_PLAY_WIDOWALLRUN2) and (p.state ~= S_PLAY_WIDOWALLRUN3) and ((p.z - p.floorz) > 32*FRACUNIT)) then
	p.player.wallRunLine = p.lastline
	if (p.player.jumpDown > 2) then
		if (p.lastline.frontsector) then
			if (p.lastline.frontsector.ceilingpic == "F_SKY1") then
				if (p.z > p.lastline.frontsector.ceilingheight) then
					return
				end
			end
			if (p.lastline.frontsector.floorpic == "F_SKY1") then
				if (p.z < p.lastline.frontsector.floorheight) then
					return
				end
			end
			for fof in p.lastline.frontsector.ffloors()
				if (fof.flags & FF_SOLID) and (fof.flags & FF_EXISTS)
					if ((p.z <= fof.topheight and p.z+p.height >= fof.bottomheight)
					or (p.eflags & MFE_VERTICALFLIP and (p.z>=fof.bottomheight and p.z-p.height<=fof.topheight))) then
						if (fof.toppic == "F_SKY1" or fof.bottompic == "F_SKY1") then
							return
						end
					end
				end
			end
			
		end
		if (p.lastline.backsector) then
			if (p.lastline.backsector.ceilingpic == "F_SKY1") then
				if (p.z > p.lastline.backsector.ceilingheight) then
					return
				end
			end
			if (p.lastline.backsector.floorpic == "F_SKY1") then
				if (p.z < p.lastline.backsector.floorheight) then
					return
				end
			end
			for fof in p.lastline.backsector.ffloors()
				if (fof.flags & FF_SOLID) and (fof.flags & FF_EXISTS)
					if ((p.z <= fof.topheight and p.z+p.height >= fof.bottomheight)
					or (p.eflags & MFE_VERTICALFLIP and (p.z>=fof.bottomheight and p.z-p.height<=fof.topheight))) then
						if (fof.toppic == "F_SKY1" or fof.bottompic == "F_SKY1") then
							return
						end
					end
				end
			end
		end
		p.player.wallRunSpeed = R_PointToDist2(0,0, p.player.speed, p.momz/10)
		if (p.player.wallRunSpeed < 20*FRACUNIT) then
			p.player.wallRunSpeed = 20*FRACUNIT
		end
		WidoWallRun(p)		
	end
end

end, MT_PLAYER)