// 2.1 Maces System - Ported from 2.1.25

freeslot(
	// Sprites
	"SPR_21MC",
	// Objects
	"MT_21MACEPOINT",
	"MT_21SWINGMACEPOINT",
	"MT_21HANGMACEPOINT",
	"MT_21SPINMACEPOINT",
	"MT_21_HIDDEN_SLING",
	"MT_21SMALLMACECHAIN",
	"MT_21BIGMACECHAIN",
	"MT_21SMALLMACE",
	"MT_21BIGMACE",
	// States
	"S_21SLING1",
	"S_21SLING2",
	"S_21SMALLMACECHAIN",
	"S_21BIGMACECHAIN",
	"S_21SMALLMACE",
	"S_21BIGMACE"
)

// Let the player jump off of a hanging chain without removing its outermost link
addHook("JumpSpecial", function(player)
	// Don't let the player immediately jump off if they're holding the jump button
	if not (player.pflags & PF_JUMPDOWN)
		if player.powers[pw_carry] == CR_GENERIC and player.mo.tracer and (player.mo.tracer.type == MT_21SMALLMACECHAIN or player.mo.tracer.type == MT_21BIGMACECHAIN)
			player.powers[pw_carry] = CR_NONE
			P_DoJump(player, true)
			player.mo.momz = 9*FRACUNIT
			return true
		end
	end
end)

// 2.1 Mace Player Behavior - Ported from 2.1.25 with fixups
// Let the player move the chain
addHook("PlayerThink", function(player)
		if player.powers[pw_carry] == CR_MACESPIN and player.mo.tracer and player.mo.tracer.tracer
		and (player.mo.tracer.type == MT_21SMALLMACECHAIN or player.mo.tracer.type == MT_21BIGMACECHAIN)
			local chain = player.mo.tracer
			local macecenter = player.mo.tracer.tracer
			//player.mo.height = P_GetPlayerSpinHeight(player)
			// tracer is what you're hanging onto....
			//player.mo.momx = (chain.x - player.mo.x)*2
			//player.mo.momy = (chain.y - player.mo.y)*2
			//player.mo.momz = (chain.z - (player.mo.height-chain.height/2) - player.mo.z)*2
			//P_TeleportMove(player.mo, chain.x, chain.y, chain.z - (player.mo.height-chain.height/2))
			//player.pflags = $|PF_JUMPED
			//player.secondjump = 0
			//player.pflags = $ & ~PF_THOKKED
			
			if player.cmd.forwardmove > 0
				macecenter.lastlook = $+2
			elseif player.cmd.forwardmove < 0 and macecenter.lastlook > macecenter.movecount
				macecenter.lastlook = $-2
			end
			
			if not (macecenter.flags & MF_SLIDEME) // Noclimb on chain parameters gives this
			and not (twodlevel or (player.mo.flags2 & MF2_TWOD)) // why on earth would you want to turn them in 2D mode?
				/*
				// This allows the player to rotate the horizontal angle at which they want to be launched with the spin button
				// This behavior was introduced in 2.0 and removed in 2.1.5, presumably because it was seen as redundant
				if (player.cmd.buttons & BT_SPIN) // do we actually still want this?
					macecenter.health = $+50
					player.mo.angle = $+(50*524288)
				end
				*/
				macecenter.health = $+player.cmd.sidemove
				player.mo.angle = $+(player.cmd.sidemove*524288)
			end
		elseif player.powers[pw_carry] == CR_GENERIC and player.mo.tracer and player.mo.tracer.tracer
		and (player.mo.tracer.type == MT_21SMALLMACECHAIN or player.mo.tracer.type == MT_21BIGMACECHAIN)
			// Force the player to face wherever the camera is pointing
			player.drawangle = player.mo.angle
			/*
			if player.followmobj and player.followmobj.valid
				player.followmobj.angle = player.mo.angle
			end
			*/
		end
end)

function A_MaceRotate(actor)
	local v0, v1, v2//, v3
	local xangle, zangle
	local cosrad, sinrad
	local r1_0, r1_1, r1_2//, r1_3
	local r2_0, r2_1, r2_2//, r2_3
	local radius
	local tempx, tempy, tempz
	
	// Target was removed
	if not actor.tracer
		P_RemoveMobj(actor)
		return
	end
	
	// Radius of the link's rotation.
	radius = FixedMul(actor.info.speed * actor.reactiontime, actor.tracer.scale)
	
	// Double the radius if the chain links are made up of maces.
	if actor.tracer.type == MT_AXIS and (actor.type == MT_21SMALLMACE or actor.type == MT_21BIGMACE)
		radius = $*2
	end
	
	// Axis offset for the axis.
	radius = $+actor.tracer.extravalue1
	
	// Smoothly move the link into position.
	if actor.extravalue1
		radius = FixedMul(radius, FixedDiv(actor.extravalue1, 100))
		actor.extravalue1 = $+1
		if actor.extravalue1 >= 100
			actor.extravalue1 = 0
		end
	end
	
	tempx = actor.tracer.x
	tempy = actor.tracer.y
	tempz = actor.tracer.z
	
	// Cut the height to align the link with the axis.
	if actor.type == MT_21SMALLMACECHAIN or actor.type == MT_21BIGMACECHAIN
		tempz = $-(actor.height/4)
	else
		tempz = $-(actor.height/2)
	end
	
	// Set the top speed for the link if it happens to be over that speed.
	if actor.tracer.lastlook > actor.tracer.friction
		actor.tracer.lastlook = actor.tracer.friction
	end
	
	// Swinging Chain.
	if actor.tracer.type == MT_21HANGMACEPOINT or actor.tracer.type == MT_21SWINGMACEPOINT
		actor.movecount = $+actor.tracer.lastlook
		actor.movecount = $%8192
		
		actor.threshold = FixedMul(cos(actor.movecount*524288), actor.tracer.lastlook * (2^FRACBITS))
		
		v0 = FRACUNIT
		v1 = 0
		v2 = -radius
		//v3 = FRACUNIT
		
		// Calculate the angle matrixes for the link.
		xangle = FixedAngle(actor.threshold)
		zangle = FixedAngle(actor.tracer.health*2880)
		
		/*
		x00 = FRACUNIT,	x10 = 0,		x20 = 0,		x30 = 0
		x01 = 0,		x11 = cosrad,	x21 = -sinrad,	x31 = 0
		x02 = 0,		x12 = sinrad,	x22 = cosrad,	x32 = 0
		x03 = 0,		x13 = 0,		x23 = 0,		x33 = FRACUNIT
		*/
		
		cosrad = cos(xangle)
		sinrad = sin(xangle)
		
		r1_0 = FixedMul(v0, FRACUNIT)
		r1_1 = FixedMul(v1, cosrad) + FixedMul(v2, -sinrad)
		r1_2 = FixedMul(v1, sinrad) + FixedMul(v2, cosrad)
		//r1_3 = FixedMul(v3, FRACUNIT)
		
		/*
		z00 = cosrad,	z10 = -sinrad,	z20 = 0,		z30 = 0
		z01 = sinrad,	z11 = cosrad,	z21 = 0,		z31 = 0
		z02 = 0,		z12 = 0,		z22 = FRACUNIT,	z32 = 0
		z03 = 0,		z13 = 0,		z23 = 0,		z33 = FRACUNIT
		*/
		
		cosrad = cos(zangle)
		sinrad = sin(zangle)
		
		r2_0 = FixedMul(r1_0, cosrad) + FixedMul(r1_1, -sinrad)
		r2_1 = FixedMul(r1_0, sinrad) + FixedMul(r1_1, cosrad)
		r2_2 = FixedMul(r1_2, FRACUNIT)
		//r2_3 = FixedMul(r1_3, FRACUNIT)
	// Rotating Chain.
	else
		local fa

		actor.threshold = $+actor.tracer.lastlook
		actor.threshold = $%8192
		actor.tracer.health = $%8192
		
		fa = FixedAngle(actor.threshold*2880)
		v0 = FixedMul(cos(fa), radius)
		v1 = 0
		v2 = FixedMul(sin(fa), radius)
		//v3 = FRACUNIT
		
		// Calculate the angle matrixes for the link.
		xangle = FixedAngle(actor.tracer.threshold*2880)
		zangle = FixedAngle(actor.tracer.health*2880)
		
		/*
		x00 = FRACUNIT,	x10 = 0,		x20 = 0,		x30 = 0
		x01 = 0,		x11 = cosrad,	x21 = -sinrad,	x31 = 0
		x02 = 0,		x12 = sinrad,	x22 = cosrad,	x32 = 0
		x03 = 0,		x13 = 0,		x23 = 0,		x33 = FRACUNIT
		*/
		
		cosrad = cos(xangle)
		sinrad = sin(xangle)
		
		r1_0 = FixedMul(v0, FRACUNIT)
		r1_1 = FixedMul(v1, cosrad) + FixedMul(v2, -sinrad)
		r1_2 = FixedMul(v1, sinrad) + FixedMul(v2, cosrad)
		//r1_3 = FixedMul(v3, FRACUNIT)
		
		/*
		z00 = cosrad,	z10 = -sinrad,	z20 = 0,		z30 = 0
		z01 = sinrad,	z11 = cosrad,	z21 = 0,		z31 = 0
		z02 = 0,		z12 = 0,		z22 = FRACUNIT,	z32 = 0
		z03 = 0,		z13 = 0,		z23 = 0,		z33 = FRACUNIT
		*/
		
		cosrad = cos(zangle)
		sinrad = sin(zangle)
		
		r2_0 = FixedMul(r1_0, cosrad) + FixedMul(r1_1, -sinrad)
		r2_1 = FixedMul(r1_0, sinrad) + FixedMul(r1_1, cosrad)
		r2_2 = FixedMul(r1_2, FRACUNIT)
		//r2_3 = FixedMul(r1_3, FRACUNIT)
	end
	
	// Add on the appropriate distances to the actor's co-ordinates.
	P_TeleportMove(actor, tempx + r2_0, tempy + r2_1, tempz + r2_2)
	
	if not (actor.tracer.flags2 & MF2_BOSSNOTRAP) // flag the makes maces shut up on request
	and not (leveltime & 63) and (actor.type == MT_21BIGMACE or actor.type == MT_21SMALLMACE) and actor.tracer.type == MT_21MACEPOINT
		S_StartSound(actor, actor.info.activesound)
	end
end

// 2.1 Mace Points

local function P_Setup21Mace(mobj, mthing)
	local mlength, mspeed, mxspeed, mzspeed, mstartangle, mmaxspeed
	local chainlink = MT_21SMALLMACECHAIN
	local macetype = MT_21SMALLMACE
	local firsttime
	local spawnee
	local line
	
	local multi = FixedDiv(8192, 360)
	
	line = P_FindSpecialLineFromTag(9, mthing.angle, -1)
	
	if line == -1
		print("Mace chain needs to be tagged to a #9 parameter line")
		return
	end
	
	/*
	No deaf - small mace
	Deaf - big mace
	
	ML_NOCLIMB : Direction (originally not) controllable
	*/
	
	mlength = abs(lines[line].dx / (2^FRACBITS))
	mspeed = abs(lines[line].dy / (2^FRACBITS))
	mxspeed = sides[lines[line].sidenum[0]].textureoffset / (2^FRACBITS)
	mzspeed = sides[lines[line].sidenum[0]].rowoffset / (2^FRACBITS)
	mstartangle = lines[line].frontsector.floorheight / (2^FRACBITS)
	mmaxspeed = lines[line].frontsector.ceilingheight / (2^FRACBITS)
	
	mstartangle = $%360
	mxspeed = $%360
	mzspeed = $%360
	
	//CONS_Debug
	
	mobj.lastlook = mspeed * (2^4)
	mobj.movecount = mobj.lastlook
	mobj.health = FixedMul(mzspeed, multi) + FixedMul(mstartangle, multi)
	mobj.threshold = FixedMul(mxspeed, multi) + FixedMul(mstartangle, multi)
	mobj.movefactor = mobj.threshold
	mobj.friction = mmaxspeed
	
	if not (lines[line].flags & ML_NOCLIMB)
		mobj.flags = $|MF_SLIDEME
	end
	
	mobj.reactiontime = 0
	
	if (mthing.options & MTF_AMBUSH)
		chainlink = MT_21BIGMACECHAIN
		macetype = MT_21BIGMACE
	end
	
	if (mthing.options & MTF_OBJECTSPECIAL)
		mobj.flags2 = $|MF2_BOSSNOTRAP // shut up maces.
	end
	
	if mobj.type == MT_21HANGMACEPOINT or mobj.type == MT_21SPINMACEPOINT
		firsttime = true
	else
		firsttime = false
		
		spawnee = P_SpawnMobj(mobj.x, mobj.y, mobj.z, macetype)
		spawnee.tracer = mobj // Make this a tracer if necessary
		
		if mobj.type == MT_21SWINGMACEPOINT
			spawnee.movecount = FixedMul(mstartangle, multi)
		else
			spawnee.movecount = 0
		end
		
		spawnee.threshold = FixedMul(mstartangle, multi)
		spawnee.reactiontime = mlength+1
	end
	
	while mlength > 0 do
		spawnee = P_SpawnMobj(mobj.x, mobj.y, mobj.z, chainlink)
		
		spawnee.tracer = mobj // Make this a tracer if necessary
		
		if mobj.type == MT_21HANGMACEPOINT or mobj.type == MT_21SWINGMACEPOINT
			spawnee.movecount = FixedMul(mstartangle, multi)
		else
			spawnee.movecount = 0
		end
		
		spawnee.threshold = FixedMul(mstartangle, multi)
		spawnee.reactiontime = mlength
		
		if firsttime
			// This is the outermost link in the chain
			spawnee.flags2 = $|MF2_AMBUSH
			firsttime = false
		end
		
		mlength = $-1
	end
end

addHook("MapThingSpawn", function(mobj, mthing)
	P_Setup21Mace(mobj, mthing)
end, MT_21MACEPOINT)

mobjinfo[MT_21MACEPOINT] = {
	//$Name 2.1 Mace Spawnpoint
	//$Sprite OBMCA0
	//$Category 2.1 Castle Eggman
	doomednum = 3104,
	spawnstate = S_UNKNOWN,
	spawnhealth = 1000,
	speed = 10*FRACUNIT,
	radius = 128*FRACUNIT,
	height = 1*FRACUNIT,
	mass = 10000,
	flags = MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

addHook("MapThingSpawn", function(mobj, mthing)
	P_Setup21Mace(mobj, mthing)
end, MT_21SWINGMACEPOINT)

mobjinfo[MT_21SWINGMACEPOINT] = {
	//$Name 2.1 Swinging Mace Spawnpoint
	//$Sprite OBMHA0
	//$Category 2.1 Castle Eggman
	doomednum = 3105,
	spawnstate = S_INVISIBLE,
	spawnhealth = 1000,
	speed = 10*FRACUNIT,
	radius = 128*FRACUNIT,
	height = 1*FRACUNIT,
	mass = 10000,
	flags = MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

addHook("MapThingSpawn", function(mobj, mthing)
	P_Setup21Mace(mobj, mthing)
end, MT_21HANGMACEPOINT)

mobjinfo[MT_21HANGMACEPOINT] = {
	//$Name 2.1 Hanging Mace Spawnpoint
	//$Sprite OBMHA0
	//$Category 2.1 Castle Eggman
	doomednum = 3106,
	spawnstate = S_INVISIBLE,
	spawnhealth = 1000,
	speed = 10*FRACUNIT,
	radius = 128*FRACUNIT,
	height = 1*FRACUNIT,
	mass = 10000,
	flags = MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

addHook("MapThingSpawn", function(mobj, mthing)
	P_Setup21Mace(mobj, mthing)
end, MT_21SPINMACEPOINT)

addHook("MobjThinker", function(mobj)
	if (leveltime & 1)
		if mobj.lastlook > mobj.movecount
			mobj.lastlook = $-1
		end
	end
end, MT_21SPINMACEPOINT)

mobjinfo[MT_21SPINMACEPOINT] = {
	//$Name 2.1 Spinning Mace Spawnpoint
	//$Sprite OBMHA0
	//$Category 2.1 Castle Eggman
	doomednum = 3107,
	spawnstate = S_INVISIBLE,
	spawnhealth = 1000,
	speed = 10*FRACUNIT,
	radius = 128*FRACUNIT,
	height = 1*FRACUNIT,
	mass = 10000,
	flags = MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

function A_21SlingAppear(actor, var1, var2)
	local firsttime = true
	local mlength = 4
	local spawnee
	
	actor.flags = $ & ~(MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT)
	actor.lastlook = 128
	actor.movecount = actor.lastlook
	actor.health = actor.angle/525488
	actor.threshold = 0
	actor.movefactor = actor.threshold
	actor.friction = 128
	
	actor.flags = $|MF_SLIDEME
	
	while mlength > 0 do
		spawnee = P_SpawnMobj(actor.x, actor.y, actor.z, MT_21SMALLMACECHAIN)
		
		spawnee.tracer = actor // Make the target a tracer
		
		spawnee.movecount = 0
		spawnee.threshold = 0
		spawnee.reactiontime = mlength
		
		if firsttime
			// This is the outermost link in the chain
			spawnee.flags2 = $|MF2_AMBUSH
			firsttime = false
		end
		
		mlength = $-1
	end
end

mobjinfo[MT_21_HIDDEN_SLING] = {
	//$Name 2.1 Hidden Chain Spawnpoint
	//Sprite OBMCA0
	//$Category 2.1 Castle Eggman
	doomednum = 3108,
	spawnstate = S_21SLING1,
	spawnhealth = 1000,
	speed = 10*FRACUNIT,
	radius = 8*FRACUNIT,
	height = 8*FRACUNIT,
	flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_21SLING1] = {
	sprite = SPR_NULL,
	frame = A,
	tics = -1,
	nextstate = S_21SLING2
}

states[S_21SLING2] = {
	sprite = SPR_NULL,
	frame = A,
	tics = -1,
	action = A_21SlingAppear
}

// 2.1 Maces

local function P_21MaceTouch(special, toucher)
	// Is this the last link in the chain?
	if P_MobjFlip(toucher)*toucher.momz > 0 or not (special.flags2 & MF2_AMBUSH)
		or toucher.player.powers[pw_carry] == CR_GENERIC or toucher.player.powers[pw_carry] == CR_MACESPIN
		return
	end
	
	if toucher.z > special.z + special.height/2
		return
	end
	
	if toucher.z + toucher.height/2 < special.z
		return
	end
	
	if toucher.player.powers[pw_flashing]
		return
	end
	
	P_ResetPlayer(toucher.player)
	toucher.tracer = special
	
	if special.tracer and (special.tracer.type == MT_21SPINMACEPOINT or special.tracer.type == MT_21_HIDDEN_SLING)
		toucher.player.powers[pw_carry] = CR_MACESPIN
		S_StartSound(toucher, sfx_spin)
		toucher.state = S_PLAY_ROLL
	else
		toucher.player.powers[pw_carry] = CR_GENERIC
	end
	
	// Can't jump first frame
	toucher.player.pflags = $|PF_JUMPSTASIS
end

addHook("TouchSpecial", function(special, toucher)
	P_21MaceTouch(special, toucher)
	return true
end, MT_21SMALLMACECHAIN)

mobjinfo[MT_21SMALLMACECHAIN] = {
	doomednum = -1,
	spawnstate = S_21SMALLMACECHAIN,
	reactiontime = 8,
	speed = 24*FRACUNIT,
	radius = 24*FRACUNIT,
	height = 48*FRACUNIT,
	//mass = 100,
	damage = 1,
	flags = MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT
}

states[S_21SMALLMACECHAIN] = {
	sprite = SPR_21MC,
	frame = A,
	tics = 1,
	action = A_MaceRotate,
	nextstate = S_21SMALLMACECHAIN
}

addHook("TouchSpecial", function(special, toucher)
	P_21MaceTouch(special, toucher)
	return true
end, MT_21BIGMACECHAIN)

mobjinfo[MT_21BIGMACECHAIN] = {
	doomednum = -1,
	spawnstate = S_21BIGMACECHAIN,
	spawnhealth = 1000,
	reactiontime = 8,
	speed = 48*FRACUNIT,
	radius = 48*FRACUNIT,
	height = 96*FRACUNIT,
	//mass = 100,
	damage = 1,
	flags = MF_NOGRAVITY|MF_SPECIAL|MF_NOCLIPHEIGHT
}

states[S_21BIGMACECHAIN] = {
	sprite = SPR_21MC,
	frame = B,
	tics = 1,
	action = A_MaceRotate,
	nextstate = S_21BIGMACECHAIN
}

mobjinfo[MT_21SMALLMACE] = {
	doomednum = -1,
	spawnstate = S_21SMALLMACE,
	spawnhealth = 1000,
	reactiontime = 8,
	speed = 24*FRACUNIT,
	radius = 17*FRACUNIT,
	height = 34*FRACUNIT,
	//mass = 100,
	damage = 1,
	activesound = sfx_mswing,
	flags = MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_21SMALLMACE] = {
	sprite = SPR_21MC,
	frame = C,
	tics = 1,
	action = A_MaceRotate,
	nextstate = S_21SMALLMACE
}

mobjinfo[MT_21BIGMACE] = {
	doomednum = -1,
	spawnstate = S_21BIGMACE,
	spawnhealth = 1000,
	reactiontime = 8,
	speed = 48*FRACUNIT,
	radius = 34*FRACUNIT,
	height = 68*FRACUNIT,
	//mass = 100,
	damage = 1,
	activesound = sfx_mswing,
	flags = MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT
}

states[S_21BIGMACE] = {
	sprite = SPR_21MC,
	frame = D,
	tics = 1,
	action = A_MaceRotate,
	nextstate = S_21BIGMACE
}
