// ----------------------------------
// RSDK Project: Sonic 2
// Script Description: Swing Spikes Object
// Script Author: Christian Whitehead/Simon Thomley
// Unpacked by Rubberduckycooly's script unpacker
// ----------------------------------

// ========================
// Aliases
// ========================

private alias object.propertyValue : object.length

private alias object.value0 : object.timer
private alias object.value1 : object.drawPos.x
private alias object.value2 : object.drawPos.y
private alias object.value3 : object.collisionOffset.x
private alias object.value4 : object.collisionOffset.y
private alias object.value5 : object.moveDir
private alias object.value6 : object.swingAngle

private alias 0 : SWINGSPIKES_AWAITPLAYER
private alias 1 : SWINGSPIKES_MOVEDELAY
private alias 2 : SWINGSPIKES_MOVING
private alias 3 : SWINGSPIKES_FINISHEDMOVE
private alias 4 : SWINGSPIKES_RETURN

// Player Aliases
private alias object.xpos : player.xpos
private alias object.ypos : player.ypos


// ========================
// Function Declarations
// ========================

reserve function SwingSpikes_DebugDraw
reserve function SwingSpikes_DebugSpawn


// ========================
// Function Definitions
// ========================

private function SwingSpikes_DebugDraw
	DrawSprite(0)
end function


private function SwingSpikes_DebugSpawn
	CreateTempObject(TypeName[Swing Spikes], 8, object.xpos, object.ypos)
	object[tempObjectPos].moveDir = object.direction
	if object[tempObjectPos].moveDir == FACING_RIGHT
		// Rotating clockwise
		object[tempObjectPos].swingAngle = 0x8000
	else
		// Rotating counter-clockwise
		object[tempObjectPos].swingAngle = 0x0000
	end if
end function


// ========================
// Events
// ========================

event ObjectUpdate
	switch object.state
	case SWINGSPIKES_AWAITPLAYER
		foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
			BoxCollisionTest(C_TOUCH, object.entityPos, -30, 0, 30, 128, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
			if checkResult == true
				object.state = SWINGSPIKES_MOVEDELAY

				if object.priority != PRIORITY_XBOUNDS_DESTROY
					object.priority = PRIORITY_ACTIVE
				end if
			end if
		next
		break

	case SWINGSPIKES_MOVEDELAY
		object.timer++
		if object.timer == 60
			object.timer = 0
			object.state++
		end if
		break

	case SWINGSPIKES_MOVING
		object.speed += 8
		if object.moveDir == 0
			object.swingAngle -= object.speed

			if object.swingAngle <= 0x4000
				object.speed = 0
				object.swingAngle = 0x4000
				object.state++
			end if
		else
			object.swingAngle += object.speed

			if object.swingAngle >= 0x4000
				object.speed = 0
				object.swingAngle = 0x4000
				object.state++
			end if
		end if
		break

	case SWINGSPIKES_FINISHEDMOVE
		object.timer++
		if object.timer == 60
			object.timer = 0
			object.state++
		end if
		break

	case SWINGSPIKES_RETURN
		object.speed += 8
		if object.moveDir == 0
			object.swingAngle += object.speed

			if object.swingAngle >= 0x8000
				object.speed = 0
				object.swingAngle = 0x8000
				object.state = SWINGSPIKES_MOVEDELAY
			end if
		else
			object.swingAngle -= object.speed

			if object.swingAngle <= 0
				object.speed = 0
				object.swingAngle = 0x0000
				object.state = SWINGSPIKES_MOVEDELAY
			end if
		end if
		break
		
	end switch

	// Backup object position
	temp2 = object.xpos
	temp3 = object.ypos

	// Get the "actual" angle for the upcoming trigonometry calculations
	object.angle = object.swingAngle
	object.angle >>= 7

	temp1 = object.length
	temp1++
	temp1 <<= 4
	temp1 -= 8
	object.xpos = object.drawPos.x
	object.ypos = object.drawPos.y

	// Calculate pplatform X Pos
	Cos(object.collisionOffset.x, object.angle)
	object.collisionOffset.x *= temp1
	object.collisionOffset.x <<= 7
	object.collisionOffset.x += temp2
	object.collisionOffset.x &= 0xFFFF0000
	object.drawPos.x = object.collisionOffset.x
	object.collisionOffset.x -= object.xpos

	// And then calculate pplatform Y Pos
	Sin(object.collisionOffset.y, object.angle)
	object.collisionOffset.y *= temp1
	object.collisionOffset.y <<= 7
	object.collisionOffset.y += temp3
	object.collisionOffset.y &= 0xFFFF0000
	object.drawPos.y = object.collisionOffset.y
	object.collisionOffset.y -= object.ypos

	foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
		BoxCollisionTest(C_SOLID2, object.entityPos, -30, -8, 30, 8, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
		switch checkResult
		case COL_TOP
			player[currentPlayer].xpos += object.collisionOffset.x
			player[currentPlayer].ypos += object.collisionOffset.y
			break

		case COL_LEFT
			CallFunction(Player_Hit)
			break

		case COL_RIGHT
			CallFunction(Player_Hit)
			break
			
		end switch
	next

	// Restore the object's position
	object.xpos = temp2
	object.ypos = temp3

	if object.outOfBounds == true
		if object.priority != PRIORITY_XBOUNDS_DESTROY
			object.priority = PRIORITY_BOUNDS

			if object.moveDir == FACING_RIGHT
				object.swingAngle = 0x8000
			else
				object.swingAngle = 0x0000
			end if
		end if
	end if
end event


event ObjectDraw
	// Draw all the chains first
	temp0 = 0
	temp1 = 16
	while temp0 < object.length
		Cos(temp2, object.angle)
		temp2 *= temp1
		temp2 <<= 7
		temp2 += object.xpos
		Sin(temp3, object.angle)
		temp3 *= temp1
		temp3 <<= 7
		temp3 += object.ypos
		DrawSpriteXY(1, temp2, temp3)
		temp0++
		temp1 += 16
	loop
	temp1 -= 8

	// Calculate where to draw the platform
	Cos(object.drawPos.x, object.angle)
	object.drawPos.x *= temp1
	object.drawPos.x <<= 7
	object.drawPos.x += object.xpos
	object.drawPos.x &= 0xFFFF0000

	Sin(object.drawPos.y, object.angle)
	object.drawPos.y *= temp1
	object.drawPos.y <<= 7
	object.drawPos.y += object.ypos
	object.drawPos.y &= 0xFFFF0000

	// Rock base
	DrawSprite(0)

	// Platform
	DrawSpriteXY(2, object.drawPos.x, object.drawPos.y)
end event


event ObjectStartup
	LoadSpriteSheet("MCZ/Objects.gif")

	SpriteFrame(-12, -12, 23, 33, 152, 131) // 0 - Rock frame
	SpriteFrame(-8, -8, 16, 16, 135, 148)   // 1 - Chain frame
	SpriteFrame(-31, -8, 62, 16, 30, 32)    // 2 - Platform frame

	foreach (TypeName[Swing Spikes], arrayPos0, ALL_ENTITIES)
		if object[arrayPos0].propertyValue > 0
			object[arrayPos0].propertyValue--
		end if

		// Spin direction is the 4th bit in the property value
		// Many Swing Spikes objects in the scene have the FlipX attr too, though that isn't used in-game
		object[arrayPos0].moveDir = object[arrayPos0].propertyValue
		object[arrayPos0].moveDir >>= 3
		object[arrayPos0].moveDir &= 1
		if object[arrayPos0].moveDir == 0
			object[arrayPos0].swingAngle = 0x8000
		else
			object[arrayPos0].swingAngle = 0x0000
		end if

		// First three bits in property value are chain length
		object[arrayPos0].propertyValue &= 7
		object[arrayPos0].propertyValue++
	next

	SetTableValue(TypeName[Swing Spikes], DebugMode_ObjCount, DebugMode_TypesTable)
	SetTableValue(SwingSpikes_DebugDraw, DebugMode_ObjCount, DebugMode_DrawTable)
	SetTableValue(SwingSpikes_DebugSpawn, DebugMode_ObjCount, DebugMode_SpawnTable)
	DebugMode_ObjCount++
end event


// ========================
// Editor Events
// ========================

event RSDKEdit
	if editor.returnVariable == true
		switch editor.variableID
		case EDIT_VAR_PROPVAL // property value
			checkResult = object.propertyValue
			break
			
		case 0 // length
			checkResult = object.propertyValue
			checkResult &= 7
			break
			
		case 1 // swingDir
			GetBit(checkResult, object.propertyValue, 4)
			break
			
		end switch
	else
		switch editor.variableID
		case EDIT_VAR_PROPVAL // property value
			object.propertyValue = editor.variableValue
			break
			
		case 0 // length
			temp0 = 7
			Not(temp0)
			object.propertyValue &= temp0
			editor.variableValue &= 7

			object.propertyValue |= editor.variableValue
			break
			
		case 1 // swingDir
			CheckNotEqual(editor.variableValue, 0)
			SetBit(object.propertyValue, 4, checkResult)
			break
			
		end switch
	end if
end event


event RSDKDraw
	GetBit(temp0, object.propertyValue, 4)
	if temp0 == 0
		temp6 = 0x3e
	else
		temp6 = 0x00
	end if

	temp7 = object.propertyValue
	temp7 &= 7

	// Draw all the chains first
	temp0 = 0
	temp1 = 16
	while temp0 < temp7
		Cos(temp2, temp6)
		temp2 *= temp1
		temp2 <<= 7
		temp2 += object.xpos
		Sin(temp3, temp6)

		temp3 *= temp1
		temp3 <<= 7
		temp3 += object.ypos

		DrawSpriteXY(1, temp2, temp3)

		temp0++
		temp1 += 16
	loop
	temp1 -= 8

	// Calculate where to draw the platform
	Cos(temp2, temp6)
	temp2 *= temp1
	temp2 <<= 7
	temp2 += object.xpos
	temp2 &= 0xFFFF0000

	Sin(temp3, temp6)
	temp3 *= temp1
	temp3 <<= 7
	temp3 += object.ypos
	temp3 &= 0xFFFF0000

	// Rock base
	DrawSprite(0)

	// Platform
	DrawSpriteXY(2, temp2, temp3)
end event


event RSDKLoad
	LoadSpriteSheet("MCZ/Objects.gif")
	SpriteFrame(-12, -12, 23, 33, 152, 131)
	SpriteFrame(-8, -8, 16, 16, 135, 148)
	SpriteFrame(-31, -8, 62, 16, 30, 32)

	AddEditorVariable("length")
	SetActiveVariable("length")

	AddEditorVariable("swingDir")
	SetActiveVariable("swingDir")
	AddEnumVariable("left", 0)
	AddEnumVariable("right", 1)
end event
