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

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

private alias object.value0  : object.timer
private alias object.value2  : object.blendAmount
private alias object.value3  : object.tornadoTimer
// values 4-13 are unused...
private alias object.value14 : object.paletteTimer
private alias object.value15 : object.bgTowerLightPalIndex
private alias object.value16 : object.rainbowLightPalIndex
private alias object.value17 : object.chemLiquidPalIndex1
private alias object.value18 : object.chemLiquidPalIndex2
private alias object.value19 : object.chemLiquidPalIndex3

private alias object.value20 : object.srcBlendPal

private alias 0 : ENDSETUP_INIT
private alias 1 : ENDSETUP_FADEINIMAGE
private alias 2 : ENDSETUP_DISPLAYIMAGE
private alias 3 : ENDSETUP_FADEOUTIMAGE
private alias 4 : ENDSETUP_ENTERPLAYER
private alias 5 : ENDSETUP_PLAYERFALLING
private alias 6 : ENDSETUP_SPAWNTORNADO
private alias 7 : ENDSETUP_TORNADOSPAWNED

// Player Aliases
private alias object.type			 :	player.type
private alias object.state			 :	player.state
private alias object.visible		 :	player.visible
private alias object.xpos			 :	player.xpos
private alias object.ypos			 :	player.ypos
private alias object.speed			 :	player.speed
private alias object.frame			 :	player.frame
private alias object.animation		 :	player.animation
private alias object.prevAnimation	 :	player.prevAnimation

private alias object.value0  : player.rings
private alias object.value7  : player.invincibleTimer
private alias object.value8  : player.blinkTimer
private alias object.value18 : player.sortedDrawOrder

// Tracks
private alias 0 : TRACK_STAGE

// Super States
private alias 1 : SUPERSTATE_SUPER


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

public value EndingSetup_scrollVelocity.x = 0
public value EndingSetup_scrollVelocity.y = 0


// ========================
// Tables
// ========================

// All these tables are copies of DEZ's tables
private table EndingSetup_bgTowerPalTable
	0xE00000, 0xC00000, 0xA00000, 0x800000, 0x600000, 0x400000, 0x200000, 0x400000
	0x600000, 0x800000, 0xA00000, 0xC00000, 0xE00000, 0xE02000, 0xE04000, 0xE02000
end table

private table EndingSetup_blendLightPalTable
	0x00E000, 0x20C000, 0x40A000, 0x608000, 0x806000, 0xA04000, 0xC02000
	0xE00000, 0xC00020, 0xA00040, 0x800060, 0x600080, 0x4000A0, 0x2000C0
	0x0000E0, 0x0020C0, 0x0040A0, 0x006080, 0x008060, 0x00A040, 0x00C020
end table

private table EndingSetup_chemLiquidPalTable
	0x0040E0, 0x0000C0, 0x0000C0
	0x0060E0, 0x0020C0, 0x0000C0
	0x0040E0, 0x0040E0, 0x0000C0
	0x0020C0, 0x0060E0, 0x0020C0
	0x0000C0, 0x0040E0, 0x0040C0
	0x0000C0, 0x0020C0, 0x0040E0
	0x0000C0, 0x0000C0, 0x0060E0
	0x0020C0, 0x0000C0, 0x0040E0
	0x0020E0, 0x0000C0, 0x0020C0
end table

// Unused table, also in CPZ and DEZ
// See CPZSetup/DEZSetup for full explanation
private table EndingSetup_unusedPalette
	0x00E000, 0x00A000, 0x006000, 0x002000, 0x000000, 0x000020, 0x000060, 0x0020A0
	0x0060E0, 0x0020A0, 0x000060, 0x000020, 0x000000, 0x200000, 0x600000, 0xA00000
	0xE00000, 0xE04000, 0xE00000, 0xA00000, 0x600000, 0x200000, 0x000000, 0x202000
	0x606000, 0xA0A000, 0xE0E000, 0xA0A000, 0x606000, 0x202000, 0x000000, 0x002000
	0x006000, 0x00A000
end table


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

event ObjectUpdate
	// Update palette cycling
	// (This is just a duplicate of the DEZ palette cycle code, here so that DEZ will look normal for the short moment it appears)
	object.paletteTimer++
	if object.paletteTimer == 8
		object.paletteTimer = 0

		object.bgTowerLightPalIndex++
		object.bgTowerLightPalIndex &= 15
		GetTableValue(temp0, object.bgTowerLightPalIndex, EndingSetup_bgTowerPalTable)
		SetPaletteEntry(0, 175, temp0)

		object.rainbowLightPalIndex++
		object.rainbowLightPalIndex %= 21
		GetTableValue(temp0, object.rainbowLightPalIndex, EndingSetup_blendLightPalTable)
		SetPaletteEntry(0, 191, temp0)

		object.chemLiquidPalIndex1 += 3
		object.chemLiquidPalIndex1 %= 27
		GetTableValue(temp0, object.chemLiquidPalIndex1, EndingSetup_chemLiquidPalTable)
		SetPaletteEntry(0, 188, temp0)

		object.chemLiquidPalIndex2 += 3
		object.chemLiquidPalIndex2 %= 27
		GetTableValue(temp0, object.chemLiquidPalIndex2, EndingSetup_chemLiquidPalTable)
		SetPaletteEntry(0, 189, temp0)

		object.chemLiquidPalIndex3 += 3
		object.chemLiquidPalIndex3 %= 27
		GetTableValue(temp0, object.chemLiquidPalIndex3, EndingSetup_chemLiquidPalTable)
		SetPaletteEntry(0, 190, temp0)
	end if

	switch object.state
	case ENDSETUP_INIT
		// Start off with making the clouds go really fast, to give the illusion Sonic himself is falling really fast
		EndingSetup_scrollVelocity.x = -0x06000
		EndingSetup_scrollVelocity.y = -0x10000

		object.state = ENDSETUP_FADEINIMAGE
		player[0].animation = ANI_FANROTATE

		temp0 = 0
		while temp0 < 256
			// Set up palettes for the fades

			// Quick palette map:
			//  > Palette ID 0 is the normal one with everything on it
			//  > Palette ID 1 is global (main-character-only)
			//  > Palette ID 2 is off-white, used when the picture slides of Tails are playing
			//  > Palette ID 3 is full white, used when Sonic's falling in the void

			SetPaletteEntry(2, temp0, 0xE0E0E0)
			SetPaletteEntry(3, temp0, 0xFFFFFF)
			temp0++
		loop

		// Start the music!
		PlayMusic(TRACK_STAGE)

		// Check if it's the good ending
		if specialStage.emeralds >= 0x7F

			// Do some anti-Tails checks in case his Super form is turned off
			// (Which it always is, meaning Tails never really gets a good ending)
			CheckEqual(stage.playerListPos, PLAYER_TAILS_ALONE)
			temp0 = checkResult
			CheckEqual(options.superTails, false)
			temp0 &= checkResult

			if temp0 == false
				// Make the player go Super
				Player_superState = SUPERSTATE_SUPER

				player[0].sortedDrawOrder = 5

				if stage.playerListPos == PLAYER_KNUX_ALONE
					// Knuckles gets to glide down all cool and all
					player[0].animation = ANI_GLIDING
					player[0].prevAnimation = ANI_GLIDING
					player[0].frame = 2
				else
					// Tails gets to fly down
					// (Though again, this doesn't get used since the variable for it is turned off)
					player[0].animation = ANI_FLYING
				end if

				player[0].speed 			= 0x100000
				player[0].invincibleTimer 	= 60
				player[0].blinkTimer 		= 0
				player[0].visible 			= true
				player[0].rings 			= 0xFFFF // Don't know if this even does anything...

				switch stage.playerListPos
				case PLAYER_SONIC_ALONE
				case PLAYER_SONIC_AND_TAILS
					// Super Sonic does his air run when descending
					player[0].animation = ANI_RUNNING

					// Make Super Sonic appear rather than just standard Sonic
					arrayPos0 = stage.entityPos
					stage.entityPos = 0
					LoadAnimation("SuperSonic.ani")
					stage.entityPos = arrayPos0
					break

				end switch
			end if
		end if

		object.srcBlendPal = 3
		SetPaletteFade(1, 0, object.srcBlendPal, object.blendAmount, 0, 255)
		if stage.playerListPos != PLAYER_SONIC_ALONE
			if stage.playerListPos != PLAYER_SONIC_AND_TAILS
				// Don't display the images for other characters and make them fall for a really long time instead

				// Set the active layer to space
				stage.activeLayer[0] = 1

				// And put the player up in the sky
				player[0].xpos = 0x00D40000
				player[0].ypos = 0x01050000

				object.frame 		= 4
				object.blendAmount 	= 976
				object.state 		= ENDSETUP_ENTERPLAYER
			end if
		end if

		SetActivePalette(1, 0, screen.ysize)
		break

	case ENDSETUP_FADEINIMAGE
		object.blendAmount -= 8
		SetPaletteFade(1, 0, object.srcBlendPal, object.blendAmount, 0, 255)
		if object.blendAmount <= 0
			object.timer = 360
			object.state = ENDSETUP_DISPLAYIMAGE
		end if
		break

	case ENDSETUP_DISPLAYIMAGE
		object.timer--
		if object.timer == 0
			object.state = ENDSETUP_FADEOUTIMAGE
			if object.frame == 3
				// Final image was just shown, use the full white palette for the fade
				object.srcBlendPal = 3
			else
				// Use the off-white/grey palette
				object.srcBlendPal = 2
			end if
		end if
		break

	case ENDSETUP_FADEOUTIMAGE
		object.blendAmount += 8
		SetPaletteFade(1, 0, object.srcBlendPal, object.blendAmount, 0, 255)
		if object.blendAmount >= 736
			object.frame++
			if object.frame == 4
				// Final image was just displayed - go on to the in-game portion of the cutscene now
				
				// Set the active layer to space
				stage.activeLayer[0] = 1

				player[0].xpos = 0x00D40000
				player[0].ypos = 0x01050000

				object.state = ENDSETUP_ENTERPLAYER
			else
				// Start the next image
				object.state = ENDSETUP_FADEINIMAGE
			end if
		end if
		break

	case ENDSETUP_ENTERPLAYER
		object.blendAmount -= 8
		temp0 = object.blendAmount
		temp0 -= 512
		if temp0 < 0
			temp0 = 0
		end if

		SetPaletteFade(1, 0, object.srcBlendPal, temp0, 0, 63)
		SetPaletteFade(1, 0, object.srcBlendPal, object.blendAmount, 64, 255)

		if object.blendAmount <= 0
			object.state = ENDSETUP_PLAYERFALLING
			SetActivePalette(0, 0, screen.ysize)
		end if
		// [Fallthrough]
	case ENDSETUP_PLAYERFALLING
		object.tornadoTimer++

		player[0].ypos += 0x10000
		if player[0].ypos >= 0x1E00000
			object.state = ENDSETUP_SPAWNTORNADO
		end if
		break

	case ENDSETUP_SPAWNTORNADO
		object.tornadoTimer++
		object.timer--
		if object.timer < 0
			Rand(object.timer, 32)
			temp0 = screen.ysize
			temp0 += camera[0].ypos
			temp0 += 16
			temp0 <<= 16
			CreateTempObject(TypeName[Cloud], 0, 0, temp0)
			Rand(object[tempObjectPos].frame, 4)
			if object[tempObjectPos].frame == 3
				object[tempObjectPos].frame = 2
			else
				FlipSign(object[tempObjectPos].frame)
				object[tempObjectPos].frame += 2
			end if
			object[tempObjectPos].drawOrder = object[tempObjectPos].frame
			object[tempObjectPos].drawOrder++

			temp0 = screen.xsize
			Rand(object[tempObjectPos].xpos, temp0)
			object[tempObjectPos].xpos <<= 16
			
			temp0 = screen.ysize
			temp0 += camera[0].ypos
			temp0 += 16
			temp0 <<= 16
			CreateTempObject(TypeName[Cloud], 0, 0, temp0)
			Rand(object[tempObjectPos].frame, 4)
			if object[tempObjectPos].frame == 3
				object[tempObjectPos].frame = 2
			else
				FlipSign(object[tempObjectPos].frame)
				object[tempObjectPos].frame += 2
			end if

			object[tempObjectPos].drawOrder = object[tempObjectPos].frame
			object[tempObjectPos].drawOrder++

			temp0 = screen.xsize
			Rand(object[tempObjectPos].xpos, temp0)
			object[tempObjectPos].xpos += temp0
			object[tempObjectPos].xpos <<= 16
		end if

		temp0 = 488

		if stage.playerListPos != PLAYER_SONIC_ALONE
			if stage.playerListPos != PLAYER_SONIC_AND_TAILS
				// The other characters don't get special images at all, so make their timer ridiculously long
				temp0 = 2608
			end if
		end if

		if object.tornadoTimer == temp0
			// Spawn the Tornado

			object[33].type = TypeName[Tornado]
			object[33].priority = PRIORITY_ACTIVE

			object[33].ypos = screen.ycenter
			object[33].ypos += camera[0].ypos
			object[33].ypos += 21
			if stage.playerListPos != PLAYER_TAILS_ALONE
				// Shift the Tornado a bit for other characters since they have a different hitbox than Tails
				object[33].ypos += 4
			end if

			// Turn the YPos from screen-space into world-space
			object[33].ypos <<= 16

			// Although the Tornado itself doesn't use transparency, the logo rendered by it does
			object[33].inkEffect = INK_ALPHA
			object[33].alpha = 0
		end if

		// (Clouds are stabalized by Tornado object, not here)

		if EndingSetup_scrollVelocity.y >= 0
			object.state = ENDSETUP_TORNADOSPAWNED
		end if
		break

	case ENDSETUP_TORNADOSPAWNED
		object.timer--
		if object.timer < 0
			Rand(object.timer, 32)
			temp0 = screen.xsize
			temp0 += 16
			temp0 <<= 17
			CreateTempObject(TypeName[Cloud], 0, temp0, 0)

			Rand(object[tempObjectPos].frame, 4)
			if object[tempObjectPos].frame == 3
				object[tempObjectPos].frame = 2
			else
				FlipSign(object[tempObjectPos].frame)
				object[tempObjectPos].frame += 2
			end if

			object[tempObjectPos].drawOrder = object[tempObjectPos].frame
			object[tempObjectPos].drawOrder++
			object[tempObjectPos].priority = PRIORITY_ACTIVE

			temp0 = screen.ysize
			Rand(object[tempObjectPos].ypos, temp0)
			object[tempObjectPos].ypos += camera[0].ypos
			object[tempObjectPos].ypos -= screen.ycenter
			object[tempObjectPos].ypos <<= 16
		end if
		break

	end switch

	// Hide the touch controls
	options.touchControls = false
end event


event ObjectDraw
	if object.frame < 4
		temp0 = screen.xcenter
		temp0 <<= 16
		temp1 = screen.ycenter
		temp1 <<= 16
		DrawSpriteXY(object.frame, temp0, temp1)
	end if
end event


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

	// Ending pictures
	SpriteFrame(-48, -36, 96, 72, 318, 1)  // Animals looking up at the sky
	SpriteFrame(-48, -36, 96, 72, 415, 1)  // Tails among the crowd of animals
	SpriteFrame(-48, -36, 96, 72, 318, 74) // Tails firing up the Tornado
	SpriteFrame(-48, -36, 96, 72, 415, 74) // Tornado in the air with a couple of flickies in tow

	SetMusicTrack("Ending.ogg", TRACK_STAGE, false)

	// No badniks appear in this stage, so no freed animals should appear, either
	// (The flickies are just spawned directly)
	animalType1 = TypeName[Blank Object]
	animalType2 = TypeName[Blank Object]

	// Remove P2
	player[1].type = TypeName[Blank Object]
	playerCount = 1

	// Place this object into the level and setup its values
	object[10].type        			= TypeName[Ending Setup]
	object[10].priority    			= PRIORITY_ACTIVE
	object[10].chemLiquidPalIndex2	= 1
	object[10].chemLiquidPalIndex3	= 2
	object[10].blendAmount 			= 0x100

	// P1 is controlled via other objects, so blank its state
	player[0].state = Player_State_Static
	
#platform: USE_ORIGINS
	if specialStage.emeralds >= 0x7F
		CallNativeFunction2(NotifyCallback, NOTIFY_GOOD_ENDING, 0)
	end if
#endplatform
end event


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

event RSDKDraw
	DrawSprite(0)
end event


event RSDKLoad
	LoadSpriteSheet("Ending/Objects.gif")
	SpriteFrame(-48, -36, 96, 72, 318, 1)  // Ending Cutscene Image 1 - #0
	
	SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
end event
