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

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

private alias object.value0 : object.timer
private alias object.value1 : object.offset.x
private alias object.value2 : object.offset.y
private alias object.value3 : object.bounceCount
private alias object.value4 : object.frameOffset
private alias object.value5 : object.comboType
private alias object.value6 : object.playerTimers

// States
private alias 0 : TARGETBUMPER_IDLE
private alias 1 : TARGETBUMPER_BUMPED

// Player Aliases
private alias object.state : player.state
private alias object.xpos : player.xpos
private alias object.ypos : player.ypos
private alias object.xvel : player.xvel
private alias object.yvel : player.yvel
private alias object.speed : player.speed
private alias object.gravity : player.gravity
private alias object.animation : player.animation
private alias object.tileCollisions : player.tileCollisions

private alias object.value1  : player.timer
private alias object.value16 : player.isSidekick			// 0/false is player 1, 1/true if player 2
private alias object.value17 : debugMode.currentSelection
private alias object.value36 : player.flyCarryTimer		// Tails assist lockout timer

// Global Variable ID Aliases
private alias 22 : GLOBAL_PLAYERSCORE


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

reserve function TargetBumper_DebugDraw
reserve function TargetBumper_DebugSpawn
reserve function TargetBumper_ProcessHit

// ========================
// Static Values
// ========================

private value TargetBumper_startDebugID = 0


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

private function TargetBumper_DebugDraw
	temp0 = debugMode[0].currentSelection
	temp0 -= TargetBumper_startDebugID
	temp1 = object.direction
	switch temp0
	case 0
		object.direction = FLIP_NONE
		temp0 = 0
		break
		
	case 1
		object.direction = FLIP_NONE
		temp0 = 3
		break
		
	case 2
		object.direction = FLIP_X
		temp0 = 3
		break
		
	case 3
		object.direction = FLIP_NONE
		temp0 = 6
		break
		
	case 4
		object.direction = FLIP_X
		temp0 = 6
		break
		
	end switch

	DrawSpriteFX(temp0, FX_FLIP, object.xpos, object.ypos)
	object.direction = temp1
end function


private function TargetBumper_DebugSpawn
	temp0 = debugMode[0].currentSelection
	temp0 -= TargetBumper_startDebugID
	CreateTempObject(TypeName[Target Bumper], temp0, object.xpos, object.ypos)

	object[tempObjectPos].drawOrder = 4
	switch object[tempObjectPos].propertyValue
	case 0
		object[tempObjectPos].direction = FLIP_NONE
		object[tempObjectPos].frameOffset = 0
		object[tempObjectPos].offset.x = 0
		object[tempObjectPos].offset.y = 0x20000
		break

	case 1
		object[tempObjectPos].direction = FLIP_NONE
		object[tempObjectPos].frameOffset = 3
		object[tempObjectPos].offset.x = -0x20000
		object[tempObjectPos].offset.y = 0x20000
		break

	case 2
		object[tempObjectPos].direction = FLIP_X
		object[tempObjectPos].frameOffset = 3
		object[tempObjectPos].offset.x = 0x20000
		object[tempObjectPos].offset.y = 0x20000
		break

	case 3
		object[tempObjectPos].direction = FLIP_NONE
		object[tempObjectPos].frameOffset = 6
		object[tempObjectPos].offset.x = -0x20000
		object[tempObjectPos].offset.y = 0
		break

	case 4
		object[tempObjectPos].direction = FLIP_X
		object[tempObjectPos].frameOffset = 6
		object[tempObjectPos].offset.x = 0x20000
		object[tempObjectPos].offset.y = 0
		break
		
	end switch
end function


private function TargetBumper_ProcessHit
	switch object.propertyValue
	case 0
		object.xvel = player[currentPlayer].xvel
		if player[currentPlayer].ypos > object.ypos
			object.yvel = 0x70000
		else
			object.yvel = -0x70000
		end if
		break

	case 1
		ATan2(temp0, player[currentPlayer].xvel, player[currentPlayer].yvel)
		temp0 -= 96
		temp1 = temp0
		Abs(temp1)
		FlipSign(temp0)
		temp0 += 96
		temp2 = temp1
		temp2 &= 0xFF
		if temp2 >= 64
			temp1 -= 128
			FlipSign(temp1)
			temp2 = temp1
			temp2 &= 0xFF
			if temp2 >= 56
				temp0 = 96
				temp0 += 128
			end if
		else
			if temp2 >= 56
				temp0 = 96
			end if
		end if
		temp0 &= 0xFF
		Cos256(object.xvel, temp0)
		Sin256(object.yvel, temp0)
		object.xvel *= -0x700
		object.yvel *= -0x700
		break

	case 2
		ATan2(temp0, player[currentPlayer].xvel, player[currentPlayer].yvel)
		temp0 -= 32
		temp1 = temp0
		Abs(temp1)
		FlipSign(temp0)
		temp0 += 32
		temp2 = temp1
		temp2 &= 0xFF
		if temp2 >= 64
			temp1 -= 128
			FlipSign(temp1)
			temp2 = temp1
			temp2 &= 0xFF
			if temp2 >= 56
				temp0 = 32
				temp0 += 128
			end if
		else
			if temp2 >= 56
				temp0 = 32
			end if
		end if
		temp0 &= 0xFF
		Cos256(object.xvel, temp0)
		Sin256(object.yvel, temp0)
		object.xvel *= -0x700
		object.yvel *= -0x700
		break

	case 3
		object.yvel = player[currentPlayer].yvel
		if player[currentPlayer].xpos > object.xpos
			object.xvel = 0x70000
		else
			object.xvel = -0x70000
		end if
		break

	case 4
		object.yvel = player[currentPlayer].yvel
		if player[currentPlayer].xpos > object.xpos
			object.xvel = 0x70000
		else
			object.xvel = -0x70000
		end if
		break
		
	end switch

	if player[currentPlayer].state == Player_State_Carried
		player[1].flyCarryTimer = 30
	end if

	CheckEqual(player[currentPlayer].animation, ANI_GLIDING)
	temp2 = checkResult
	CheckEqual(player[currentPlayer].animation, ANI_GLIDING_STOP)
	temp2 |= checkResult
	CheckEqual(player[currentPlayer].animation, ANI_FLYING)
	temp2 |= checkResult
	CheckEqual(player[currentPlayer].state, Player_State_TubeRoll)
	temp2 |= checkResult
	CheckEqual(player[currentPlayer].state, Player_State_TubeAirRoll)
	temp2 |= checkResult
	if temp2 == false
		player[currentPlayer].state = Player_State_Air
		if player[currentPlayer].animation != ANI_JUMPING
			if player[currentPlayer].animation != ANI_RUNNING
				player[currentPlayer].animation = ANI_WALKING
			end if
		end if
	end if

	if player[currentPlayer].animation == ANI_GLIDING
		if object.xvel > 0
			if player[currentPlayer].xvel < 0
				player[currentPlayer].animation = ANI_GLIDING_DROP
				player[currentPlayer].state = Player_State_GlideDrop
			else
				player[currentPlayer].state = Player_State_GlideRight
			end if
		else
			if player[currentPlayer].xvel > 0
				player[currentPlayer].animation = ANI_GLIDING_DROP
				player[currentPlayer].state = Player_State_GlideDrop
			else
				player[currentPlayer].state = Player_State_GlideLeft
			end if
		end if
	end if

	player[currentPlayer].xvel = object.xvel
	player[currentPlayer].speed = player[currentPlayer].xvel
	if player[currentPlayer].animation == ANI_GLIDING
		if object.xvel < 0
			FlipSign(player[currentPlayer].speed)
		end if
	end if

	player[currentPlayer].timer = 0
	player[currentPlayer].yvel = object.yvel
	player[currentPlayer].gravity = GRAVITY_AIR
	player[currentPlayer].tileCollisions = true
end function


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

event ObjectUpdate
	if object.state > TARGETBUMPER_IDLE
		object.animationTimer = object.timer
		object.animationTimer >>= 2
		object.animationTimer++

		object.timer++
		if object.timer > 12
			object.timer = 0
			object.state = TARGETBUMPER_IDLE
			object.animationTimer = 0
			if object.bounceCount > 2
				object.type = TypeName[Blank Object]
			end if
		end if
	end if

	if object.visible == true
		temp7 = 0
		foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
			temp6 = object.playerTimers
			temp6 >>= temp7
			temp6 &= 0xFF
			if temp6 == false
				switch object.propertyValue
				case 0
					BoxCollisionTest(C_TOUCH, object.entityPos, -14, -4, 14, 4, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
					break

				case 1
					BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
					break

				case 2
					BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
					break

				case 3
					BoxCollisionTest(C_TOUCH, object.entityPos, -4, -14, 4, 14, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
					break

				case 4
					BoxCollisionTest(C_TOUCH, object.entityPos, -4, -14, 4, 14, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
					break
				end switch

				if checkResult == true
					if object.state == TARGETBUMPER_IDLE
						PlaySfx(SfxName[Target Bumper], false)
						if object.bounceCount < 3
							switch object.comboType
							case 0
								CheckNotEqual(object[+1].type, TypeName[Target Bumper])
								temp0 = checkResult
								CheckNotEqual(object[+2].type, TypeName[Target Bumper])
								temp0 &= checkResult
								break

							case 1
								CheckNotEqual(object[-1].type, TypeName[Target Bumper])
								temp0 = checkResult
								CheckNotEqual(object[+1].type, TypeName[Target Bumper])
								temp0 &= checkResult
								break

							case 2
								CheckNotEqual(object[-1].type, TypeName[Target Bumper])
								temp0 = checkResult
								CheckNotEqual(object[-2].type, TypeName[Target Bumper])
								temp0 &= checkResult
								break
							end switch

							CheckEqual(object.bounceCount, 2)
							temp0 &= checkResult

							// global variable "array" (yes, this is actually how its done)
							arrayPos0 = GLOBAL_PLAYERSCORE
#platform: USE_DECOMP
							arrayPos0 = VarName[player.score]
#endplatform
							if player[currentPlayer].isSidekick == false
								arrayPos0 += currentPlayer
							end if

							if temp0 == false
								CreateTempObject(TypeName[Object Score], 16, object.xpos, object.ypos)
								global[arrayPos0] += 10
							else
								CreateTempObject(TypeName[Object Score], 2, object.xpos, object.ypos)
								global[arrayPos0] += 500
							end if
							object.bounceCount++
						end if

						CallFunction(TargetBumper_ProcessHit)
					else
						if object.timer > 5
							PlaySfx(SfxName[Target Bumper], false)
							CallFunction(TargetBumper_ProcessHit)
						end if
					end if
					object.state = TARGETBUMPER_BUMPED

					object.priority = PRIORITY_ACTIVE
					temp6 = 3
					temp6 <<= temp7
					object.playerTimers |= temp6
				end if
			else
				temp5 = 1
				temp5 <<= temp7
				object.playerTimers -= temp5
			end if
			temp7 += 8
		next
	end if
end event


event ObjectDraw
	if object.visible == true
		temp0 = object.animationTimer
		temp0 &= 1

		object.frame = object.frameOffset
		if object.bounceCount < 2
			object.frame += object.bounceCount
		else
			object.frame += 2
		end if

		if temp0 == 0
			DrawSpriteFX(object.frame, FX_FLIP, object.xpos, object.ypos)
		else
			temp1 = object.xpos
			temp1 += object.offset.x
			temp2 = object.ypos
			temp2 += object.offset.y
			DrawSpriteFX(object.frame, FX_FLIP, temp1, temp2)
		end if
	end if
end event


event ObjectStartup
	LoadSpriteSheet("CNZ/Objects.gif")
	SpriteFrame(-16, -6, 32, 12, 1, 166) 	// Green  (V) - #0
	SpriteFrame(-16, -6, 32, 12, 1, 153) 	// Yellow (V) - #1
	SpriteFrame(-16, -6, 32, 12, 1, 140) 	// Red    (V) - #2

	SpriteFrame(-12, -12, 24, 24, 1, 229)	// Green  (D) - #3
	SpriteFrame(-12, -12, 24, 24, 1, 204)	// Yellow (D) - #4
	SpriteFrame(-12, -12, 24, 24, 1, 179)	// Red    (D) - #5

	SpriteFrame(-6, -16, 12, 32, 60, 140)	// Green  (H) - #6
	SpriteFrame(-6, -16, 12, 32, 47, 140)	// Yellow (H) - #7
	SpriteFrame(-6, -16, 12, 32, 34, 140)	// Red    (H) - #8

	foreach (TypeName[Target Bumper], arrayPos0, ALL_ENTITIES)
		object[arrayPos0].comboType = object[arrayPos0].propertyValue
		object[arrayPos0].comboType >>= 6

		// Orientation
		object[arrayPos0].propertyValue &= 0x3F
		switch object[arrayPos0].propertyValue
		case 0
			object[arrayPos0].direction = FACING_RIGHT
			object[arrayPos0].frameOffset = 0
			object[arrayPos0].offset.x = 0
			object[arrayPos0].offset.y = 0x20000
			break

		case 1
			object[arrayPos0].direction = FACING_RIGHT
			object[arrayPos0].frameOffset = 3
			object[arrayPos0].offset.x = -0x20000
			object[arrayPos0].offset.y = 0x20000
			break

		case 2
			object[arrayPos0].direction = FACING_LEFT
			object[arrayPos0].frameOffset = 3
			object[arrayPos0].offset.x = 0x20000
			object[arrayPos0].offset.y = 0x20000
			break

		case 3
			object[arrayPos0].direction = FACING_RIGHT
			object[arrayPos0].frameOffset = 6
			object[arrayPos0].offset.x = -0x20000
			object[arrayPos0].offset.y = 0
			break

		case 4
			object[arrayPos0].direction = FACING_LEFT
			object[arrayPos0].frameOffset = 6
			object[arrayPos0].offset.x = 0x20000
			object[arrayPos0].offset.y = 0
			break
			
		end switch
	next

	temp0 = 0
	TargetBumper_startDebugID = DebugMode_ObjCount
	while temp0 < 5
		SetTableValue(TypeName[Target Bumper], DebugMode_ObjCount, DebugMode_TypesTable)
		SetTableValue(TargetBumper_DebugDraw, DebugMode_ObjCount, DebugMode_DrawTable)
		SetTableValue(TargetBumper_DebugSpawn, DebugMode_ObjCount, DebugMode_SpawnTable)
		DebugMode_ObjCount++
		temp0++
	loop
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 // type
			checkResult = object.propertyValue
			checkResult &= 0x3F
			break
			
		case 1 // comboType
			checkResult = object.propertyValue
			checkResult >>= 6
			break
			
		end switch
	else
		switch editor.variableID
		case EDIT_VAR_PROPVAL // property value
			object.propertyValue = editor.variableValue
			break
			
		case 0 // type
			editor.variableValue &= 0x3F
			object.propertyValue &= 0xC0

			object.propertyValue |= editor.variableValue
			break
			
		case 1 // comboType
			editor.variableValue &= 3
			editor.variableValue <<= 6
			object.propertyValue &= 0x3F

			object.propertyValue |= editor.variableValue
			break
			
		end switch
	end if
end event


event RSDKDraw
	temp0 = object.propertyValue
	temp0 &= 0x3F

	switch temp0
	case 0
	default
		object.direction = FLIP_NONE
		object.frame = 0
		break

	case 1
		object.direction = FLIP_NONE
		object.frame = 1
		break

	case 2
		object.direction = FLIP_X
		object.frame = 1
		break

	case 3
		object.direction = FLIP_NONE
		object.frame = 2
		break

	case 4
		object.direction = FLIP_X
		object.frame = 2
		break
		
	end switch
	
	DrawSpriteFX(object.frame, FX_FLIP, object.xpos, object.ypos)
	
	if editor.showGizmos == true
		editor.drawingOverlay = true
		
		// Draw lines to this Bumper's combo set
		
		// First, find combo type
		temp0 = object.propertyValue
		temp0 >>= 6
		
		// Now, jump as needed
		// -> case 3, the standalone type, won't do anything here
		switch temp0
		case 0
			DrawArrow(object.xpos, object.ypos, object[+1].xpos, object[+1].ypos, 255, 255, 0)
			DrawArrow(object.xpos, object.ypos, object[+2].xpos, object[+2].ypos, 255, 255, 0)
			break
			
		case 1
			DrawArrow(object.xpos, object.ypos, object[-1].xpos, object[-1].ypos, 255, 255, 0)
			DrawArrow(object.xpos, object.ypos, object[+1].xpos, object[+1].ypos, 255, 255, 0)
			break
			
		case 2
			DrawArrow(object.xpos, object.ypos, object[-1].xpos, object[-1].ypos, 255, 255, 0)
			DrawArrow(object.xpos, object.ypos, object[-2].xpos, object[-2].ypos, 255, 255, 0)
			break
			
		end switch
		
		editor.drawingOverlay = false
	end if
end event


event RSDKLoad
	LoadSpriteSheet("CNZ/Objects.gif")
	SpriteFrame(-16, -6, 32, 12, 1, 166) 	// Green  (V) - #0
	SpriteFrame(-12, -12, 24, 24, 1, 229)	// Green  (D) - #1
	SpriteFrame(-6, -16, 12, 32, 60, 140)	// Green  (H) - #2

	AddEditorVariable("type")
	SetActiveVariable("type")
	AddEnumVariable("Vertical", 0)
	AddEnumVariable("Diagonal (Right)", 1)
	AddEnumVariable("Diagonal (Left)", 2)
	AddEnumVariable("Horizontal (Right)", 3)
	AddEnumVariable("Horizontal (Left)", 4)

	AddEditorVariable("comboType")
	SetActiveVariable("comboType")
	AddEnumVariable("Left (slot+1 & slot+2 are required)", 0)
	AddEnumVariable("Middle (slot-1 & slot+1 are required)", 1)
	AddEnumVariable("Right (slot-1 & slot-2 are required)", 2)
	AddEnumVariable("Standalone", 3)
end event
