freeslot(
"MT_PNKY",
"SPR_PNKY",
"S_PNKY_STND",
"S_PNKY_WALK1",
"S_PNKY_WALK2",
"S_PNKY_FWALK1",
"S_PNKY_FWALK2")

freeslot("sfx_vase","sfx_vplt","sfx_wflw","sfx_swut","sfx_swat","sfx_evyekd","sfx_bere","sfx_bers","sfx_berl","sfx_axe","sfx_chef","sfx_meas","sfx_papr","sfx_glass","sfx_glas","sfx_leaf","sfx_olady","sfx_odrone","sfx_pber","sfx_metc","sfx_mdor","sfx_news","sfx_moona","sfx_moonb")

states[S_PNKY_STND] = {SPR_PNKY, A, 2, A_Look, 0, 0, S_PNKY_STND}
states[S_PNKY_WALK1] = {SPR_PNKY, B, 3, nil, 3, 0, S_PNKY_WALK2}
states[S_PNKY_WALK2] = {SPR_PNKY, A, 3, nil, 3, 0, S_PNKY_WALK1}

states[S_PNKY_FWALK1] = {SPR_PNKY, B, 3, A_Look, 0, 0, S_PNKY_FWALK2}
states[S_PNKY_FWALK2] = {SPR_PNKY, A, 3, A_Look, 0, 0, S_PNKY_FWALK1}

mobjinfo[MT_PNKY]={
	doomednum = 1578,
	painstate = S_PNKY_WALK2,
	deathsound = sfx_bere,
	deathstate = S_XPLD_FLICKY,
	spawnstate = S_PNKY_STND,
	seestate = S_PNKY_WALK1,
	seesound = sfx_berl,
	spawnhealth = 1,
	reactiontime = 16,
	painchance = 1000,
	speed = 7*FRACUNIT,
	mass = 100,
	damage = 1,
	radius = 40*FRACUNIT,
	height = 64*FRACUNIT,	
	flags = MF_ENEMY|MF_SHOOTABLE|MF_SPECIAL
}

local function ValidFlag(mo)
	local flegs = 0
	if mo.flags & MF_ENEMY
		flegs = $|MF_ENEMY
	end
	if mo.flags & MF_BOSS
		flegs = $|MF_BOSS
	end
	if mo.flags & MF_SHOOTABLE
		flegs = $|MF_SHOOTABLE
	end
	if flegs
		return flegs
	else
		return false
	end	
end

local function N_Negative()
	if P_RandomRange(1, 2) == 1
		return 1
	else
		return -1
	end
end

local function N_SetRotateVelocity(mo, velocity, ran)
	if ran
		mo.rotatevel = velocity*N_Negative()
	else
		mo.rotatevel = velocity
	end	
	mo.noresetvel = 15
end

freeslot("S_SQUISHEDTODEATH", "SPR_SSUC", "S_SMASHCLOUD")
states[S_SQUISHEDTODEATH] = {SPR_NULL, A, TICRATE/2+2, nil, 0, 0, S_NULL}
states[S_SMASHCLOUD] = {SPR_SSUC, A, TICRATE/2, nil, 0, 0, S_NULL}

local function HasBeenSquished(mo, nosound, yesvel, thefuse)
	local fusetimes = TICRATE/2
	if thefuse
		fusetimes = tonumber(thefuse)
	else
		fusetimes = TICRATE/2
	end

	mo.deadspriteinfo = {
	["sprite"] = mo.sprite,
	["sprite2"] = mo.sprite2,
	["frame"] = mo.frame}
	mo.state = S_SQUISHEDTODEATH
	mo.sprite = mo.deadspriteinfo["sprite"]
	mo.sprite2 = mo.deadspriteinfo["sprite2"]
	mo.frame = mo.deadspriteinfo["frame"]
	mo.tics = fusetimes+2
	mo.fuse = fusetimes+2
	
	mo.alreadydead = true
	if not yesvel
		mo.momx = 0
		mo.momy = 0
		mo.momz = 0
		mo.rotatevel = 0
		mo.angvel = 0
	end	
				
	local enemyq = ValidFlag(mo)
	mo.flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY|enemyq
	mo.plsdienow = fusetimes
	if not nosound
		S_StartSound(mo, sfx_crumbl)
	end	
end

local function GetInflictorAndSource(mo)
	local hittable = {}
	
	if mo.finisherhit and mo.finisherhit.valid
		hittable.lasthit = mo.finisherhit
		if mo.finisherhit.target and mo.finisherhit.target.valid
			hittable.sourcehit = mo.finisherhit.target
		else
			hittable.sourcehit = mo.finisherhit
		end
	end
	
	return hittable
end

addHook("MobjMoveBlocked", function(mo, mobj, line)
	if mo and mo.valid
		if line and line.valid
			if mo.thrownrealhard
				local lineang = R_PointToAngle2(0, 0, line.dx, line.dy)
				mo.renderflags = $|RF_PAPERSPRITE
				mo.angle = lineang
				mo.renderflags = $|RF_PAPERSPRITE
				mo.shadowscale = 0
				
				mo.radius = FRACUNIT
				mo.scale = FRACUNIT*2
				mo.scalespeed = FRACUNIT/5
				mo.destscale = FRACUNIT/2*3
				mo.radius = FRACUNIT
				
				HasBeenSquished(mo)
			end
		end
	end
end, MT_PNKY)

local function SpawnSmashTrailEffect(mo, power)
	local ranx = FixedMul(P_RandomRange(0, mo.radius/FRACUNIT)*FRACUNIT, cos(P_RandomRange(0, 360)*ANG1))
	local rany = FixedMul(P_RandomRange(0, mo.radius/FRACUNIT)*FRACUNIT, sin(P_RandomRange(0, 360)*ANG1))
	local ranz = P_RandomRange(0, mo.height/FRACUNIT)*FRACUNIT
	
	local cloud = P_SpawnMobjFromMobj(mo, ranx, rany, ranz, MT_THOK)
	cloud.state = S_SMASHCLOUD
	cloud.fuse = TICRATE/2
	cloud.tics = TICRATE/2
	cloud.scale = (FRACUNIT/2*3)/P_RandomRange(1, 3)
	cloud.destscale = (FRACUNIT/2*3)/P_RandomRange(1, 3)
	cloud.rollangle = P_RandomRange(-15, 15)*ANG1*N_Negative()
	cloud.color = SKINCOLOR_BLUEBELL
	
	if power
		for i = 1, tonumber(power)
			local ranx2 = FixedMul(P_RandomRange(0, (mo.radius/2*3)/FRACUNIT)*FRACUNIT, cos(P_RandomRange(0, 360)*ANG1))
			local rany2 = FixedMul(P_RandomRange(0, (mo.radius/2*3)/FRACUNIT)*FRACUNIT, sin(P_RandomRange(0, 360)*ANG1))
			local ranz2 = P_RandomRange(0, (mo.height/2*3)/FRACUNIT)*FRACUNIT - (mo.height/4)
			
			local smoke = P_SpawnMobjFromMobj(mo, ranx2, rany2, ranz2, MT_SMOKE)
		end
	end
end

local function GSnapperCircle(mo, fx, fy)
	local x0 = mo.x
	local y0 = mo.y
	local xs
	local ys
	local x1
	local y1
	local dist
	
	xs = x0
	ys = x0
	
	if fx and fy
		x1 = fx
		y1 = fy
	end
	
	dist = P_AproxDistance(x1-x0, y1-y0)
	
	local speed = mo.info.speed + mo.info.reactiontime - mo.reactiontime
	
	local maxang = FixedAngle(speed*FRACUNIT/2)
	local ang = mo.angle
	local realang = R_PointToAngle2(x0, y0, x1, y1)
	local dif = realang - ang
	
	if (dif < ANGLE_180 or dif > maxang)
		return 1
	elseif (dif >= ANGLE_180 or dif < InvAngle(maxang))
		return 2
	else
		return 3
	end
end

addHook("MobjMoveBlocked", function(mo) //No questions, jump.
	if mo and mo.valid
	and P_IsObjectOnGround(mo)
		P_SetObjectMomZ(mo, FRACUNIT*12, true)
		S_StartSound(mo, sfx_jump)
	end
end, MT_PNKY)

addHook("MobjThinker", function(mo)
	if mo and mo.valid
		if mo.state == S_PNKY_STND
		and mo.target and mo.target.valid
			if mo.target.type == MT_PARTICLE //he is actually searchin for a player
				if mo.state == S_PNKY_WALK1
					mo.state = S_PNKY_FWALK1
				elseif mo.state == S_PNKY_WALK2
					mo.state = S_PNKY_FWALK2
				end
			else
				if mo.state == S_PNKY_FWALK1
					mo.state = S_PNKY_WALK1
				elseif mo.state == S_PNKY_FWALK2
					mo.state = S_PNKY_WALK2
				end
			end
		end
		mo.ignorepls = $ or 0
		mo.plsstop = $ or 0
		mo.towang = $ or 0
		mo.towdist = $ or 0
		if mo.plsstop
			mo.plsstop = $ - 1
		end
		if (mo.state == S_PNKY_WALK1
		or mo.state == S_PNKY_WALK2
		or mo.state == S_PNKY_FWALK1
		or mo.state == S_PNKY_FWALK2)
		and mo.target and mo.target.valid //This mf is so dumb that it wont stop targeting the player
			if P_CheckSight(mo, mo.target)
			and not mo.reallyignore
				local targang = R_PointToAngle2(mo.x, mo.y, mo.target.x, mo.target.y) //Moving
				local momang = R_PointToAngle2(mo.x, mo.y, mo.target.x+mo.target.momx*2, mo.target.y+mo.target.momy*2)
				
				local gang = GSnapperCircle(mo, mo.target.x, mo.target.y)
				local speed = mo.info.speed/FRACUNIT + (R_PointToDist2(0, 0, mo.momx, mo.momy)/FRACUNIT/2)
				local maxang = FixedAngle(speed*FRACUNIT/2)
				if gang == 1
					mo.angle = $ + maxang
				elseif gang == 2
					mo.angle = $ - maxang
				elseif gang == 3
					mo.angle = maxang
				end
				
				P_InstaThrust(mo, mo.angle, speed*FRACUNIT)
				
				local dists = R_PointToDist2(mo.x, mo.y, mo.target.x, mo.target.y) //Jumping
				local zdist = R_PointToDist2(0, mo.z, 0, mo.target.z)
				
				local plr = 0
				if mo.target.player and mo.target.player.valid
					plr = P_PlayerCanDamage(mo.target.player, mo)
				else
					plr = 0
				end
				if P_IsObjectOnGround(mo)
					if (dists <= 150*FRACUNIT)
						if ((zdist >= 50*FRACUNIT)
						or (mo.target.floorz - mo.z) >= 50*FRACUNIT)
						and not plr
							P_SetObjectMomZ(mo, FRACUNIT*12, true)
							S_StartSound(mo, sfx_jump)
						end
					end
				end
				
				local dist = R_PointToDist2(mo.x, mo.y, mo.target.x, mo.target.y) //Predicting
				local diff2 = targang-momang
				if abs(diff2) > 0
					mo.towang = targang+ANG15
				elseif abs(diff2) < 0
					mo.towang = targang-ANG15
				else
					mo.towang = targang
				end
				mo.towdist = dist
				mo.lastcord = {}
				mo.lastcord.x = mo.target.x
				mo.lastcord.y = mo.target.y
				mo.lastcord.z = mo.target.z
				
			elseif mo.towang //Move the last place player was +offsets
				if not mo.ignorepls
				and not mo.reallyignore
					mo.ignorepls = TICRATE
					mo.reallyignore = true
				end
				if mo.ignorepls
					mo.ignorepls = $ - 1
				else
					if mo.reallyignore
					and not mo.plsstop
						mo.reallyignore = false
						mo.plsstop = TICRATE
					end
				end
				local gang = GSnapperCircle(mo, FixedMul(mo.towdist, cos(mo.towang)), FixedMul(mo.towdist, sin(mo.towang))) //Move towarsds the place
				local speed = (mo.info.speed + mo.info.reactiontime - mo.reactiontime)/FRACUNIT
				local maxang = FixedAngle(speed*FRACUNIT/2)
				if gang == 1
					mo.angle = $ + maxang
				elseif gang == 2
					mo.angle = $ - maxang
				elseif gang == 3
					mo.angle = maxang
				end
				P_InstaThrust(mo, mo.angle, mobjinfo[mo.type].speed)
				
				if mo.lastcord
					local dists = R_PointToDist2(mo.x, mo.y, mo.lastcord.x, mo.lastcord.y)
					local zdist = R_PointToDist2(0, mo.z, 0, mo.lastcord.z)
					
					if P_IsObjectOnGround(mo)
						if dists <= 100*FRACUNIT
							if zdist >= 50*FRACUNIT
								P_SetObjectMomZ(mo, FRACUNIT*12, true)
								S_StartSound(mo, sfx_jump)
							end
						end
					end
				end
			end
		end
		if not mo.noresetvel
			if not P_IsObjectOnGround(mo)
				mo.premom = {
				x = mo.momx,
				y = mo.momy,
				z = mo.momz}
				mo.wasntonground = true
			else
				if mo.wasntonground
					if mo.washitverymuch
						HasBeenSquished(mo)
						mo.rollangle = 0
						mo.spriteyscale = FRACUNIT/3
						mo.spritexscale = FRACUNIT*3
						mo.squishto2 = true
					end
				else
					if mo.state == S_SQUISHEDTODEATH
					and not mo.alreadydead
					and not mo.plsdienow
					and mo.thrownrealhard
						if mo.type != MT_GSNAPPER
							mo.state = mobjinfo[mo.type].spawnstate
							if not (mobjinfo[mo.type].flags & MF_MISSILE)
							and (mo.flags & MF_MISSILE)
								mo.flags = $ & ~MF_MISSILE
							end
						else
							local ded = GetInflictorAndSource(mo)
							P_DamageMobj(mo, ded.lasthit, ded.sourcehit, 1, DMG_INSTAKILL)
						end	
					end
				end	
				mo.wasntonground = false
			end
		end	
		if mo.squishto2
			if mo.spriteyscale < FRACUNIT/2
				if (mo.spriteyscale + FRACUNIT/5) < FRACUNIT/2
					mo.spriteyscale = $ + FRACUNIT/5
				else
					mo.spriteyscale = FRACUNIT/2
				end	
			end
			if mo.spritexscale > FRACUNIT*2
				if (mo.spritexscale - FRACUNIT/5) > FRACUNIT*2
					mo.spritexscale = $ - FRACUNIT/5
				else
					mo.spritexscale = FRACUNIT*2
				end	
			end
			if mo.spriteyscale == FRACUNIT/2
			and mo.spritexscale == FRACUNIT*2
				mo.squishto2 = false
			end
		end
	
		mo.combo = $ or 0
		if P_IsObjectOnGround(mo)
		and not mo.noresetvel
			mo.thrownrealhard = false
			mo.combo = 0
			if mobjinfo[mo.type].flags & MF_NOGRAVITY
			and not (mo.flags & MF_NOGRAVITY)
				mo.flags = $|MF_NOGRAVITY
			end
		end
		
		mo.wasjusthit = $ or 0
		if mo.wasjusthit
			mo.wasjusthit = $ - 1
		end
		
		mo.wasjustthrown = $ or 0
		if mo.wasjustthrown
			mo.wasjustthrown = $ - 1
		end
	
		mo.noresetvel = $ or 0
		if mo.noresetvel
			mo.noresetvel = $ - 1
		end
		
		if mo.angvel
			if P_IsObjectOnGround(mo)
				mo.angvel = $/10*7
			else
				mo.angvel = $/(TICRATE*60)*((TICRATE*60)-1)
			end
			mo.angle = $ + mo.angvel
		end
		
		if mo.rotatevel
			if P_IsObjectOnGround(mo)
				if not mo.noresetvel
					if mo.washitverymuch
						mo.rotatevel = 0
						mo.stopnow = true
						mo.rollangle = 0
						if R_PointToDist2(0, 0, mo.momx, mo.momy) > mo.info.speed/2*3
							local heg = 0
							if P_MobjFlip(mo) == 1
								heg = 0
							else
								heg = mo.height
							end
							
							for i = 1, 6
								local ranx = FixedMul(P_RandomRange(0, mo.radius/FRACUNIT)*FRACUNIT, cos(P_RandomRange(0, 360)*ANG1))
								local rany = FixedMul(P_RandomRange(0, mo.radius/FRACUNIT)*FRACUNIT, sin(P_RandomRange(0, 360)*ANG1))
								P_SpawnMobjFromMobj(mo, ranx, rany, heg, MT_DUST)
							end	
							S_StartSound(mo, sfx_skid)
						end
						mo.washitverymuch = false
					end	
				else
					mo.rotatevel = $/10*7
				end	
			else
				mo.rotatevel = $/(TICRATE*60)*((TICRATE*60)-1)
				SpawnSmashTrailEffect(mo, mo.combo/FRACUNIT)
			end
			if not mo.stopnow
				mo.rollangle = $ + mo.rotatevel
			else
				mo.rollangle = 0
				mo.stopnow = false
			end	
		end
		
		mo.plsdienow = $ or 0
		if mo.plsdienow
			mo.plsdienow = $ - 1
			mo.plsdienow2 = true
			if not (mo.flags & MF_NOGRAVITY)
				mo.momz = $/100*75
			end
		else
			if mo.plsdienow2
				mo.plsdienow2 = false
				
				local heg = 0
				if P_MobjFlip(mo) == 1
					heg = 0
				else
					heg = mo.height
				end
				local dead = P_SpawnMobj(mo.x, mo.y, mo.z+heg, mo.type)
				if P_MobjFlip(mo) == 1
					dead.flags2 = $ & ~MF2_OBJECTFLIP
					dead.eflags = $ & ~MFE_VERTICALFLIP
				else
					dead.flags2 = $ & ~MF2_OBJECTFLIP
					dead.eflags = $ & ~MFE_VERTICALFLIP
				end
					
				local hittable = GetInflictorAndSource(mo)
				P_DamageMobj(dead, hittable.lasthit, hittable.sourcehit, 1, DMG_INSTAKILL)
			end
		end
	end
end, MT_PNKY)

addHook("MobjDeath", function(mobj)
	if mobj and mobj.valid
		mobj.rotatevel = 0
		mobj.rollangle = 0
		local sound = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_THOK)
		sound.tics = TICRATE*2
		sound.fuse = TICRATE*2
		sound.flags2 = $|MF2_DONTDRAW
		S_StartSound(sound, sfx_bere)
	end
end, MT_PNKY)

local function IsInZ(mobj, mo)
	if mo.z > (mobj.z+mobj.height)
		return
	end
	if (mobj.z-mobj.height) > (mo.z+mo.height)
		return
	end
	return true
end

local DMG_ENEMYKILL = 6

addHook("MobjMoveCollide", function(mobj, mo)
	if mobj and mobj.valid
		if mobj.washitverymuch
			if mo and mo.valid
			and mobj.type == MT_PNKY
			and IsInZ(mobj, mo)
			and not mo.alreadydead
			and not mo.plsdienow
			and not mo.washitverymuch
				if mobj.finisherhit and mobj.finisherhit.valid
					mo.wasactuallyhitby = mobj
					P_DamageMobj(mo, mobj.finisherhit, mobj.finisherhit, 1, DMG_ENEMYKILL)
				end
			end
		end
	end
end, MT_PNKY)

addHook("MobjDamage", function(mobj, mo, source, dmg, dmgtype)
	if mobj and mobj.valid
		if mobj.health == 1
			if mobj.alreadydead
			and not (dmgtype & DMG_DEATHMASK)
			and not (dmgtype == DMG_INSTAKILL
			or dmgtype == DMG_CRUSHED
			or dmgtype == DMG_DROWNED
			or dmgtype & DMG_SPACEDROWN
			or dmgtype & DMG_DROWNED
			or dmgtype == DMG_DEATHPIT)
				return true
			end
			
			if mo and mo.valid
			and not (dmgtype & DMG_DEATHMASK)
			and not (dmgtype == DMG_INSTAKILL
			or dmgtype == DMG_CRUSHED
			or dmgtype == DMG_DROWNED
			or dmgtype & DMG_SPACEDROWN
			or dmgtype & DMG_DROWNED
			or dmgtype == DMG_DEATHPIT)
				if ((mo.player and mo.player.valid
				and P_PlayerCanDamage(mo.player, mobj))
				or (mo.flags & MF_MISSILE
				and mo.target and mo.target.valid
				and mo.target.player and mo.target.player.valid))
					if mo.player and mo.player.valid
						mo.player.homing = 0
					end	
					if not P_IsObjectOnGround(mobj)
					and not mobj.wasjusthit
						if mobj.combo
							mobj.combo = tonumber($) + FRACUNIT
						else
							mobj.combo = FRACUNIT
						end	
					end
					if not mobj.wasjusthit
						S_StartSound(mobj, sfx_bers)
					end
					if not mobj.wasjusthit
					and mobj.state != S_SQUISHEDTODEATH
						mobj.wasbuzz = {}
						mobj.wasbuzz.sprite = mobj.sprite
						mobj.wasbuzz.frame = mobj.frame
						mobj.state = S_SQUISHEDTODEATH
						mobj.tics = -1
						mobj.sprite = mobj.wasbuzz.sprite
						mobj.frame = mobj.wasbuzz.frame
					end
					local washitby = mo
					if mobj.wasactuallyhitby and mobj.wasactuallyhitby.valid
						washitby = mobj.wasactuallyhitby
					else
						washitby = mo
					end
					if R_PointToDist2(0, 0, washitby.momx, washitby.momy) < 16*FRACUNIT
						if not mobj.wasjustthrown
						and not mobj.wasjusthit
							P_SetObjectMomZ(mobj, 12*FRACUNIT+mobj.combo)
							P_InstaThrust(mobj, R_PointToAngle2(washitby.x, washitby.y, mobj.x, mobj.y), R_PointToDist2(washitby.x, washitby.y, mobj.x, mobj.y)/10)
						end	
						if not mobj.wasjusthit
							if not mobj.wasjustthrown
								N_SetRotateVelocity(mobj, 20*ANG1, true)
								mobj.angvel = 20*ANG1*N_Negative()
							end	
							S_StartSound(mobj, sfx_bnce1)
							mobj.wasjusthit = TICRATE
							mobj.finisherhit = mo
						end
					else
						if mo.momz*P_MobjFlip(mo) >= -FRACUNIT/2
							P_SetObjectMomZ(mobj, 3*FRACUNIT+(mobj.combo/2*3))
						end
						P_InstaThrust(mobj, R_PointToAngle2(washitby.x, washitby.y, mobj.x, mobj.y), R_PointToDist2(0, 0, washitby.momx, washitby.momy))
						if not mobj.wasjustthrown
							N_SetRotateVelocity(mobj, 30*ANG1, true)
							mobj.angvel = 30*ANG1*N_Negative()
							S_StartSound(mobj, sfx_bnce2)
							mobj.wasjustthrown = TICRATE
							mobj.finisherhit = mo
						end	
						mobj.thrownrealhard = true
						if not (washitby.flags & MF_MISSILE
						and washitby.target and washitby.target.valid
						and washitby.target.player and washitby.target.player.valid)
							P_SetObjectMomZ(washitby, 3*FRACUNIT)
							P_InstaThrust(washitby, R_PointToAngle2(washitby.x, washitby.y, mobj.x, mobj.y), -5*FRACUNIT)
						end	
						mobj.diehit = false
					end
					mobj.washitverymuch = true
					mobj.flags = $ & ~MF_NOGRAVITY
					return true
				end
			end
		end	
	end
end, MT_PNKY)