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

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

private alias object.value0  : object.deformTimer
private alias object.value1  : object.paletteTimer1
private alias object.value2  : object.beltPaletteTimer
private alias object.value3  : object.beltPaletteIndex
private alias object.value4  : object.waterfallLoopTimer
private alias object.value5  : object.playingWaterfallLoop
private alias object.value6  : object.clrDivisor_R
private alias object.value7  : object.clrDivisor_G
private alias object.value8  : object.clrDivisor_B
private alias object.value9  : object.waterClrDivisor_R
private alias object.value10 : object.waterClrDivisor_G
private alias object.value11 : object.waterClrDivisor_B

// 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.speed : player.speed
private alias object.gravity : player.gravity
private alias object.animation : player.animation
private alias object.direction : player.direction
private alias object.collisionBottom : player.collisionBottom

// Tile Info ID Aliases
private alias 0 : TILEINFO_INDEX
private alias 1 : TILEINFO_DIRECTION
private alias 8 : TILEINFO_ANGLEB

// Tile Flag Aliases
private alias 1 : TILE_WATERSLIDE

// Tracks
private alias 0 : TRACK_STAGE
private alias 2 : TRACK_INVINCIBLE
private alias 4 : TRACK_BOSS
private alias 6 : TRACK_DROWNING

// Reserved Object Slot Aliases
private alias 10 : SLOT_ZONESETUP
private alias 25 : SLOT_MUSICEVENT_CHANGE

// Music Events
private alias 0 : MUSICEVENT_FADETOBOSS
private alias 1 : MUSICEVENT_FADETOSTAGE
private alias 2 : MUSICEVENT_TRANSITION

private alias 0 : MUSICEVENT_FLAG_NOCHANGE
private alias 1 : MUSICEVENT_FLAG_SPEEDUP
private alias 2 : MUSICEVENT_FLAG_SLOWDOWN

// Music Loops
private alias 84444 : MUSIC_LOOP_LZ
private alias 67538 : MUSIC_LOOP_LZ_F

private alias 1     : MUSIC_LOOP_SBZ
private alias 1     : MUSIC_LOOP_SBZ_F

private alias 39528 : MUSIC_LOOP_INV
private alias 30436 : MUSIC_LOOP_INV_F


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

reserve function LZSetup_SetupRippleDeform1
reserve function LZSetup_SetupRippleDeform2
reserve function LZSetup_getClrDivisor
reserve function LZSetup_InitSuperSonicPal
reserve function LZSetup_InitSuperTailsPal
reserve function LZSetup_InitSuperKnuxPal
reserve function LZSetup_SpeedUpMusicLZ
reserve function LZSetup_SlowDownMusicLZ
reserve function LZSetup_SpeedUpMusicSBZ3
reserve function LZSetup_SlowDownMusicSBZ3


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

public value Water_flashTimer 		= 0  // Uses "Water_" since all water objects use it from the setup so its easier to make new objs this way
public value LZSetup_beltDirection 	= 0


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

private table LZSetup_beltPalDelayTable
	2, 2, 1
end table


private table LZSetup_replay_credits_STK
	0xA000000, 0x62C0000
	0x08, 49
	0x00, 9
	0x08, 102
	0x00, 86
	0x02, 13
	0x00, 11
	0x02, 10
	0x00, 9
	0x02, 13
	0x00, 7
	0x08, 13
	0x38, 1
	0x28, 3
	0x08, 38
	0x00, 27
	0x01, 13
	0x00, 13
	0x02, 13
	0x00, 10
	0x02, 7
	0x08, 9
	0x38, 1
	0x28, 4
	0x08, 27
	0x00, 13
	0x02, 12
	0x00, 12
	0x02, 10
	0x00, 15
	0x02, 7
	0x00, 14
	0x02, 10
	0x00, 35
	0x30, 1
	0x20, 4
	0x00, 8
	0x02, 6
end table


private function LZSetup_SetupRippleDeform1
	stage.deformationData1[arrayPos0] = 1
	arrayPos0++

	stage.deformationData1[arrayPos0] = 1
	arrayPos0++

	stage.deformationData1[arrayPos0] = 2
	arrayPos0++

	stage.deformationData1[arrayPos0] = 2
	arrayPos0++

	stage.deformationData1[arrayPos0] = 3
	arrayPos0++

	stage.deformationData1[arrayPos0] = 3
	arrayPos0++

	stage.deformationData1[arrayPos0] = 3
	arrayPos0++

	stage.deformationData1[arrayPos0] = 3
	arrayPos0++

	stage.deformationData1[arrayPos0] = 2
	arrayPos0++

	stage.deformationData1[arrayPos0] = 2
	arrayPos0++

	stage.deformationData1[arrayPos0] = 1
	arrayPos0++

	stage.deformationData1[arrayPos0] = 1
	arrayPos0++
end function


private function LZSetup_SetupRippleDeform2
	stage.deformationData1[arrayPos0] = -1
	arrayPos0++

	stage.deformationData1[arrayPos0] = -1
	arrayPos0++

	stage.deformationData1[arrayPos0] = -2
	arrayPos0++

	stage.deformationData1[arrayPos0] = -2
	arrayPos0++

	stage.deformationData1[arrayPos0] = -3
	arrayPos0++

	stage.deformationData1[arrayPos0] = -3
	arrayPos0++

	stage.deformationData1[arrayPos0] = -3
	arrayPos0++

	stage.deformationData1[arrayPos0] = -3
	arrayPos0++

	stage.deformationData1[arrayPos0] = -2
	arrayPos0++

	stage.deformationData1[arrayPos0] = -2
	arrayPos0++

	stage.deformationData1[arrayPos0] = -1
	arrayPos0++

	stage.deformationData1[arrayPos0] = -1
	arrayPos0++
end function


// Wacky function to take a normal color and turn it into an underwater color
private function LZSetup_getClrDivisor
	// Regular Colour
	object.clrDivisor_R = temp1
	object.clrDivisor_R >>= 16

	object.clrDivisor_G = temp1
	object.clrDivisor_G >>= 8
	object.clrDivisor_G &= 0xFF

	object.clrDivisor_B = temp1
	object.clrDivisor_B &= 0xFF

	// Underwater Colour
	object.waterClrDivisor_R = temp2
	object.waterClrDivisor_R >>= 16

	object.waterClrDivisor_G = temp2
	object.waterClrDivisor_G >>= 8
	object.waterClrDivisor_G &= 0xFF

	object.waterClrDivisor_B = temp2
	object.waterClrDivisor_B &= 0xFF

	// Minimum of 1 (don't wanna divide by 0!)
	if object.waterClrDivisor_R == 0
		object.waterClrDivisor_R = 1
	end if

	if object.waterClrDivisor_G == 0
		object.waterClrDivisor_G = 1
	end if

	if object.waterClrDivisor_B == 0
		object.waterClrDivisor_B = 1
	end if

	object.clrDivisor_R <<= 8
	object.clrDivisor_G <<= 8
	object.clrDivisor_B <<= 8

	object.clrDivisor_R /= object.waterClrDivisor_R
	object.clrDivisor_G /= object.waterClrDivisor_G
	object.clrDivisor_B /= object.waterClrDivisor_B

	if object.clrDivisor_R == 0
		object.clrDivisor_R = 0x100
	end if

	if object.clrDivisor_G == 0
		object.clrDivisor_G = 0x100
	end if

	if object.clrDivisor_B == 0
		object.clrDivisor_B = 0x100
	end if
end function


private function LZSetup_InitSuperSonicPal
	temp0 = 0

	// First Set of colours is just the regular underwater palette
	GetPaletteEntry(1, 2, temp1)
	SetTableValue(temp1, temp0, Player_SonicSuperAltPal)
	temp0++

	GetPaletteEntry(1, 3, temp1)
	SetTableValue(temp1, temp0, Player_SonicSuperAltPal)
	temp0++

	GetPaletteEntry(1, 4, temp1)
	SetTableValue(temp1, temp0, Player_SonicSuperAltPal)
	temp0++

	GetPaletteEntry(1, 5, temp1)
	SetTableValue(temp1, temp0, Player_SonicSuperAltPal)
	temp0++

	while temp0 < 64
		GetPaletteEntry(0, 2, temp1) // Regular colour
		GetPaletteEntry(1, 2, temp2) // Underwater colour

		CallFunction(LZSetup_getClrDivisor)

		GetTableValue(temp1, temp0, Player_SonicSuperPal)

		// Get the green in the color
		temp2 = temp1
		temp2 >>= 8
		temp2 &= 0xFF
		
		// Get the blue in the color
		temp3 = temp1
		temp3 &= 0xFF

		// Get the red in the color
		temp1 >>= 16

		temp1 *= 0xE0
		temp1 /= object.clrDivisor_R

		temp2 *= 0xE0
		temp2 /= object.clrDivisor_G

		temp3 *= 0xE0
		temp3 /= object.clrDivisor_B

		// Max of 0xE0
		//  -> Note that this game uses the "raw" colors from the original game rather than
		//     "corrected" colors seen in many emulators
		//     With this system, the brighest a color can be is E0E0E0, with all
		//     the reds, greens, and blues having a max of 224, or E0
		temp1 &= 0xF0
		temp2 &= 0xF0
		temp3 &= 0xF0
		if temp1 > 0xE0
			temp1 = 0xE0
		end if
		if temp2 > 0xE0
			temp2 = 0xE0
		end if
		if temp3 > 0xE0
			temp3 = 0xE0
		end if

		temp1 <<= 16
		temp2 <<= 8
		temp1 += temp2
		temp1 += temp3
		SetTableValue(temp1, temp0, Player_SonicSuperAltPal)
		temp0++

		// Colour 2
		GetPaletteEntry(0, 3, temp1) // Regular colour
		GetPaletteEntry(1, 3, temp2) // Underwater colour

		CallFunction(LZSetup_getClrDivisor)

		GetTableValue(temp1, temp0, Player_SonicSuperPal)

		temp2 = temp1
		temp2 >>= 8
		temp2 &= 0xFF

		temp3 = temp1
		temp3 &= 0xFF

		temp1 >>= 16

		temp1 *= 0xE8
		temp1 /= object.clrDivisor_R

		temp2 *= 0xE8
		temp2 /= object.clrDivisor_G
		
		temp3 *= 0xE8
		temp3 /= object.clrDivisor_B
		
		temp1 &= 0xF0
		temp2 &= 0xF0
		temp3 &= 0xF0
		if temp1 > 0xE0
			temp1 = 0xE0
		end if
		if temp2 > 0xE0
			temp2 = 0xE0
		end if
		if temp3 > 0xE0
			temp3 = 0xE0
		end if

		temp1 <<= 16
		temp2 <<= 8
		temp1 += temp2
		temp1 += temp3
		SetTableValue(temp1, temp0, Player_SonicSuperAltPal)
		temp0++

		// Colour 3
		GetPaletteEntry(0, 4, temp1) // Regular colour
		GetPaletteEntry(1, 4, temp2) // Underwater colour

		CallFunction(LZSetup_getClrDivisor)

		GetTableValue(temp1, temp0, Player_SonicSuperPal)

		temp2 = temp1
		temp2 >>= 8
		temp2 &= 0xFF

		temp3 = temp1
		temp3 &= 0xFF

		temp1 >>= 16
		
		temp1 *= 0xF4
		temp1 /= object.clrDivisor_R

		temp2 *= 0xF4
		temp2 /= object.clrDivisor_G

		temp3 *= 0xF4
		temp3 /= object.clrDivisor_B

		temp1 &= 0xF0
		temp2 &= 0xF0
		temp3 &= 0xF0
		if temp1 > 0xE0
			temp1 = 0xE0
		end if
		if temp2 > 0xE0
			temp2 = 0xE0
		end if
		if temp3 > 0xE0
			temp3 = 0xE0
		end if

		temp1 <<= 16
		temp2 <<= 8
		temp1 += temp2
		temp1 += temp3
		SetTableValue(temp1, temp0, Player_SonicSuperAltPal)
		temp0++

		// Colour 4
		GetPaletteEntry(0, 5, temp1) // Regular colour
		GetPaletteEntry(1, 5, temp2) // Underwater colour

		CallFunction(LZSetup_getClrDivisor)

		GetTableValue(temp1, temp0, Player_SonicSuperPal)
		temp2 = temp1
		temp2 >>= 8
		temp2 &= 0xFF

		temp3 = temp1
		temp3 &= 0xFF

		temp1 >>= 16

		temp1 *= 0x100
		temp1 /= object.clrDivisor_R

		temp2 *= 0x100
		temp2 /= object.clrDivisor_G

		temp3 *= 0x100
		temp3 /= object.clrDivisor_B

		temp1 &= 0xF0
		temp2 &= 0xF0
		temp3 &= 0xF0
		if temp1 > 0xE0
			temp1 = 0xE0
		end if
		if temp2 > 0xE0
			temp2 = 0xE0
		end if
		if temp3 > 0xE0
			temp3 = 0xE0
		end if

		temp1 <<= 16
		temp2 <<= 8
		temp1 += temp2
		temp1 += temp3
		SetTableValue(temp1, temp0, Player_SonicSuperAltPal)
		temp0++
	loop
end function


private function LZSetup_InitSuperTailsPal
	temp0 = 0

	GetPaletteEntry(1, 13, temp1)
	SetTableValue(temp1, temp0, Player_TailsSuperAltPal)
	temp0++

	GetPaletteEntry(1, 17, temp1)
	SetTableValue(temp1, temp0, Player_TailsSuperAltPal)
	temp0++

	GetPaletteEntry(1, 18, temp1)
	SetTableValue(temp1, temp0, Player_TailsSuperAltPal)
	temp0++

	GetPaletteEntry(1, 16, temp1)
	SetTableValue(temp1, temp0, Player_TailsSuperAltPal)
	temp0++

	while temp0 < 24
		// Colour 1
		GetPaletteEntry(0, 13, temp1)
		GetPaletteEntry(1, 13, temp2)

		CallFunction(LZSetup_getClrDivisor)

		GetTableValue(temp1, temp0, Player_TailsSuperPal)

		temp2 = temp1
		temp2 >>= 8
		temp2 &= 0xFF

		temp3 = temp1
		temp3 &= 0xFF

		temp1 >>= 16

		temp1 *= 0xF8
		temp1 /= object.clrDivisor_R

		temp2 *= 0xF8
		temp2 /= object.clrDivisor_G

		temp3 *= 0xF8
		temp3 /= object.clrDivisor_B

		temp1 &= 0xF0
		temp2 &= 0xF0
		temp3 &= 0xF0
		if temp1 > 0xE0
			temp1 = 0xE0
		end if
		if temp2 > 0xE0
			temp2 = 0xE0
		end if
		if temp3 > 0xE0
			temp3 = 0xE0
		end if

		temp1 <<= 16
		temp2 <<= 8
		temp1 += temp2
		temp1 += temp3
		SetTableValue(temp1, temp0, Player_TailsSuperAltPal)
		temp0++

		// Colour 2
		GetPaletteEntry(0, 17, temp1)
		GetPaletteEntry(1, 17, temp2)

		CallFunction(LZSetup_getClrDivisor)

		GetTableValue(temp1, temp0, Player_TailsSuperPal)

		temp2 = temp1
		temp2 >>= 8
		temp2 &= 0xFF

		temp3 = temp1
		temp3 &= 0xFF

		temp1 >>= 16

		temp1 *= 0x100
		temp1 /= object.clrDivisor_R

		temp2 *= 0x100
		temp2 /= object.clrDivisor_G

		temp3 *= 0x100
		temp3 /= object.clrDivisor_B

		temp1 &= 0xF0
		temp2 &= 0xF0
		temp3 &= 0xF0
		if temp1 > 0xE0
			temp1 = 0xE0
		end if
		if temp2 > 0xE0
			temp2 = 0xE0
		end if
		if temp3 > 0xE0
			temp3 = 0xE0
		end if

		temp1 <<= 16
		temp2 <<= 8
		temp1 += temp2
		temp1 += temp3
		SetTableValue(temp1, temp0, Player_TailsSuperAltPal)
		temp0++
		
		// Colour 3
		GetPaletteEntry(0, 18, temp1)
		GetPaletteEntry(1, 18, temp2)

		CallFunction(LZSetup_getClrDivisor)

		GetTableValue(temp1, temp0, Player_TailsSuperPal)

		temp2 = temp1
		temp2 >>= 8
		temp2 &= 0xFF

		temp3 = temp1
		temp3 &= 0xFF

		temp1 >>= 16

		temp1 *= 0x100
		temp1 /= object.clrDivisor_R

		temp2 *= 0x100
		temp2 /= object.clrDivisor_G

		temp3 *= 0x100
		temp3 /= object.clrDivisor_B

		temp1 &= 0xF0
		temp2 &= 0xF0
		temp3 &= 0xF0
		if temp1 > 0xE0
			temp1 = 0xE0
		end if
		if temp2 > 0xE0
			temp2 = 0xE0
		end if
		if temp3 > 0xE0
			temp3 = 0xE0
		end if

		temp1 <<= 16
		temp2 <<= 8
		temp1 += temp2
		temp1 += temp3
		SetTableValue(temp1, temp0, Player_TailsSuperAltPal)
		temp0++
		
		// Colour 4
		GetPaletteEntry(0, 16, temp1)
		GetPaletteEntry(1, 16, temp2)

		CallFunction(LZSetup_getClrDivisor)

		GetTableValue(temp1, temp0, Player_TailsSuperPal)

		temp2 = temp1
		temp2 >>= 8
		temp2 &= 0xFF

		temp3 = temp1
		temp3 &= 0xFF

		temp1 >>= 16

		temp1 *= 0x100
		temp1 /= object.clrDivisor_R

		temp2 *= 0x100
		temp2 /= object.clrDivisor_G

		temp3 *= 0x100
		temp3 /= object.clrDivisor_B

		temp1 &= 0xF0
		temp2 &= 0xF0
		temp3 &= 0xF0
		if temp1 > 0xE0
			temp1 = 0xE0
		end if

		if temp2 > 0xE0
			temp2 = 0xE0
		end if
		
		if temp3 > 0xE0
			temp3 = 0xE0
		end if

		temp1 <<= 16
		temp2 <<= 8
		temp1 += temp2
		temp1 += temp3
		SetTableValue(temp1, temp0, Player_TailsSuperAltPal)
		temp0++
	loop
end function


private function LZSetup_InitSuperKnuxPal
	temp0 = 0

	GetPaletteEntry(1, 26, temp1)
	SetTableValue(temp1, temp0, Player_KnuxSuperAltPal)
	temp0++

	GetPaletteEntry(1, 27, temp1)
	SetTableValue(temp1, temp0, Player_KnuxSuperAltPal)
	temp0++

	GetPaletteEntry(1, 28, temp1)
	SetTableValue(temp1, temp0, Player_KnuxSuperAltPal)
	temp0++
end function


private function LZSetup_SpeedUpMusicLZ
	CheckEqual(object[SLOT_MUSICEVENT_CHANGE].type, TypeName[Music Event])
	temp0 = checkResult
	CheckEqual(object[SLOT_MUSICEVENT_CHANGE].propertyValue, MUSICEVENT_TRANSITION)
	temp0 &= checkResult
	CheckEqual(stage.musicFlag, MUSICEVENT_FLAG_NOCHANGE)
	temp0 &= checkResult
	if temp0 == false
		switch music.currentTrack
		case TRACK_STAGE
			SetMusicTrack("Invincibility_F.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV_F)
			SwapMusicTrack("Labyrinth_F.ogg", TRACK_STAGE, MUSIC_LOOP_LZ_F, 8000)
			break

		case TRACK_INVINCIBLE
			SetMusicTrack("Labyrinth_F.ogg", TRACK_STAGE, MUSIC_LOOP_LZ_F)
			SwapMusicTrack("Invincibility_F.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV_F, 8000)
			break

		case TRACK_BOSS
		case TRACK_DROWNING
			SetMusicTrack("Labyrinth_F.ogg", TRACK_STAGE, MUSIC_LOOP_LZ_F)
			SetMusicTrack("Invincibility_F.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV_F)
			break
			
		end switch
	else
		stage.musicFlag = MUSICEVENT_FLAG_SPEEDUP
	end if
end function


private function LZSetup_SlowDownMusicLZ
	CheckEqual(object[SLOT_MUSICEVENT_CHANGE].type, TypeName[Music Event])
	temp0 = checkResult
	CheckEqual(object[SLOT_MUSICEVENT_CHANGE].propertyValue, MUSICEVENT_TRANSITION)
	temp0 &= checkResult
	CheckEqual(stage.musicFlag, MUSICEVENT_FLAG_NOCHANGE)
	temp0 &= checkResult
	if temp0 == false
		switch music.currentTrack
		case TRACK_STAGE
			SetMusicTrack("Invincibility.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV)
			SwapMusicTrack("Labyrinth.ogg", TRACK_STAGE, MUSIC_LOOP_LZ, 12500)
			break

		case TRACK_INVINCIBLE
			SetMusicTrack("Labyrinth.ogg", TRACK_STAGE, MUSIC_LOOP_LZ)
			SwapMusicTrack("Invincibility.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV, 12500)
			break

		case TRACK_BOSS
		case TRACK_DROWNING
			SetMusicTrack("Labyrinth.ogg", TRACK_STAGE, MUSIC_LOOP_LZ)
			SetMusicTrack("Invincibility.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV)
			break
			
		end switch
	else
		stage.musicFlag = MUSICEVENT_FLAG_SLOWDOWN
	end if
end function


private function LZSetup_SpeedUpMusicSBZ3
	CheckEqual(object[SLOT_MUSICEVENT_CHANGE].type, TypeName[Music Event])
	temp0 = checkResult
	CheckEqual(object[SLOT_MUSICEVENT_CHANGE].propertyValue, MUSICEVENT_TRANSITION)
	temp0 &= checkResult
	CheckEqual(stage.musicFlag, MUSICEVENT_FLAG_NOCHANGE)
	temp0 &= checkResult
	if temp0 == false
		switch music.currentTrack
		case TRACK_STAGE
			SetMusicTrack("Invincibility_F.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV_F)
			SwapMusicTrack("ScrapBrain_F.ogg", TRACK_STAGE, MUSIC_LOOP_SBZ_F, 8000)
			break

		case TRACK_INVINCIBLE
			SetMusicTrack("ScrapBrain_F.ogg", TRACK_STAGE, MUSIC_LOOP_SBZ_F)
			SwapMusicTrack("Invincibility_F.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV_F, 8000)
			break

		case TRACK_BOSS
		case TRACK_DROWNING
			SetMusicTrack("ScrapBrain_F.ogg", TRACK_STAGE, MUSIC_LOOP_SBZ_F)
			SetMusicTrack("Invincibility_F.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV_F)
			break
			
		end switch
	else
		stage.musicFlag = MUSICEVENT_FLAG_SPEEDUP
	end if
end function


private function LZSetup_SlowDownMusicSBZ3
	CheckEqual(object[SLOT_MUSICEVENT_CHANGE].type, TypeName[Music Event])
	temp0 = checkResult
	CheckEqual(object[SLOT_MUSICEVENT_CHANGE].propertyValue, MUSICEVENT_TRANSITION)
	temp0 &= checkResult
	CheckEqual(stage.musicFlag, MUSICEVENT_FLAG_NOCHANGE)
	temp0 &= checkResult
	if temp0 == false
		switch music.currentTrack
		case TRACK_STAGE
			SetMusicTrack("Invincibility.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV)
			SwapMusicTrack("ScrapBrain.ogg", TRACK_STAGE, MUSIC_LOOP_SBZ, 12500)
			break

		case TRACK_INVINCIBLE
			SetMusicTrack("ScrapBrain.ogg", TRACK_STAGE, MUSIC_LOOP_SBZ)
			SwapMusicTrack("Invincibility.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV, 12500)
			break

		case TRACK_BOSS
		case TRACK_DROWNING
			SetMusicTrack("ScrapBrain.ogg", TRACK_STAGE, MUSIC_LOOP_SBZ)
			SetMusicTrack("Invincibility.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV)
			break
			
		end switch
	else
		stage.musicFlag = MUSICEVENT_FLAG_SLOWDOWN
	end if
end function


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

event ObjectUpdate
	object.deformTimer++
	if object.deformTimer > 1
		tileLayer[0].deformationOffsetW++
		tileLayer[1].deformationOffsetW++
		object.deformTimer = 0
	end if

	object.paletteTimer1++
	if object.paletteTimer1 == 3
		object.paletteTimer1 = 0
		RotatePalette(0, 171, 174, false)
		RotatePalette(1, 171, 174, false)
	end if

	if object.beltPaletteTimer > 0
		object.beltPaletteTimer--
	else
		object.beltPaletteIndex++
		object.beltPaletteIndex %= 3
		GetTableValue(object.beltPaletteTimer, object.beltPaletteIndex, LZSetup_beltPalDelayTable)

		RotatePalette(0, 187, 189, LZSetup_beltDirection)
		RotatePalette(1, 187, 189, LZSetup_beltDirection)
	end if

	// Handle Player Tile Interactions
	foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
		temp1 = player[currentPlayer].xpos
		temp1 >>= 16

		temp2 = player[currentPlayer].ypos
		temp2 >>= 16
		temp2 += player[currentPlayer].collisionBottom
		temp2--

		Get16x16TileInfo(temp0, temp1, temp2, TILEINFO_INDEX)

		// Check if it's a waterfall tile
		CheckEqual(temp0, 71)
		temp3 = checkResult
		CheckEqual(temp0, 72)
		temp3 |= checkResult
		
		if temp3 == true
			// Force unstick Knuckles, if needed
			
			CheckEqual(player[currentPlayer].state, Player_State_GlideLeft)
			temp3 = checkResult
			CheckEqual(player[currentPlayer].state, Player_State_GlideRight)
			temp3 |= checkResult
			CheckEqual(player[currentPlayer].state, Player_State_Climb)
			temp3 |= checkResult
			CheckEqual(player[currentPlayer].state, Player_State_LedgePullUp)
			temp3 |= checkResult
			if temp3 == true
				if player[currentPlayer].state == Player_State_GlideLeft
					FlipSign(player[currentPlayer].xvel)
					FlipSign(player[currentPlayer].speed)
				end if

				player[currentPlayer].state = Player_State_GlideDrop
				player[currentPlayer].animation = ANI_GLIDING_DROP
			end if
		end if

		if player[currentPlayer].gravity == GRAVITY_GROUND
			Get16x16TileInfo(temp0, temp1, temp2, TILEINFO_ANGLEB)
			if temp0 == TILE_WATERSLIDE
				player[currentPlayer].state = Player_State_WaterSlide

				Get16x16TileInfo(temp0, temp1, temp2, TILEINFO_DIRECTION)
				switch temp0
				case FLIP_NONE
				case FLIP_Y
					player[currentPlayer].direction = FACING_LEFT
					break

				case FLIP_X
				case FLIP_XY
					player[currentPlayer].direction = FACING_RIGHT
					break
					
				end switch
			end if
		end if
	next

	if player[0].state == Player_State_WaterSlide
		if object.waterfallLoopTimer == 0
			if object.playingWaterfallLoop == false
				PlaySfx(SfxName[Waterfall], false)
				StopSfx(SfxName[Waterfall Loop])
				object.playingWaterfallLoop = true
			else
				StopSfx(SfxName[Waterfall])
				PlaySfx(SfxName[Waterfall Loop], false)
			end if
		end if

		object.waterfallLoopTimer++
		object.waterfallLoopTimer &= 0x3F
	else
		if object.waterfallLoopTimer != 0
			object.waterfallLoopTimer++
			object.waterfallLoopTimer &= 0x3F
		else
			object.waterfallLoopTimer = 0
			object.playingWaterfallLoop = false
		end if
	end if

	if Water_flashTimer > 0
		Water_flashTimer--
	end if
end event


event ObjectDraw
	// Change the palette to the underwater one after the water level's Y Pos
	temp0 = stage.waterLevel
	temp0 -= screen.yoffset

	// Enforce a minimum of 0
	if temp0 < 0
		temp0 = 0
	end if

	// Enforce a maximum of the screen's vertical size
	if temp0 > screen.ysize
		temp0 = screen.ysize
	end if

	// Set the above water palette from the upper part of the screen
	SetActivePalette(0, 0, temp0)

	// Set the underwater palette for the bottom part of the screen
	if Water_flashTimer > 0
		// Use the lightning palette if needed
		SetActivePalette(2, temp0, screen.ysize)
	else
		// Otherwise, use the normal water palette
		SetActivePalette(1, temp0, screen.ysize)
	end if
end event


event ObjectStartup
	// If in acts 1-3, set the normal Labyrinth music
	if stage.actNum < 4
		// Set the speed up/slow down functions, too
		SetMusicTrack("Labyrinth.ogg", TRACK_STAGE, MUSIC_LOOP_LZ)
		SpeedUpMusic = LZSetup_SpeedUpMusicLZ
		SlowDownMusic = LZSetup_SlowDownMusicLZ
	else
		// If in "act 4" - AKA SBZ 3 - then use Scrap Brain's music instead
		SetMusicTrack("ScrapBrain.ogg", TRACK_STAGE, MUSIC_LOOP_SBZ)
		SpeedUpMusic = LZSetup_SpeedUpMusicSBZ3
		SlowDownMusic = LZSetup_SlowDownMusicSBZ3
	end if

	// Pecky and Rocky are the inhabitants of this labyrinth
	animalType1 = TypeName[Pecky]
	animalType2 = TypeName[Rocky]

	// Place an LZ Setup Object into the scene
	object[SLOT_ZONESETUP].type 		= TypeName[LZ Setup]
	object[SLOT_ZONESETUP].priority 	= PRIORITY_ACTIVE
	object[SLOT_ZONESETUP].drawOrder 	= 0

	// Start the initial palette cycle stuff
	GetTableValue(object[SLOT_ZONESETUP].beltPaletteTimer, 0, LZSetup_beltPalDelayTable)

	// Set stage deformation data
	// (FG layer properties)

	arrayPos0 = 0
	CallFunction(LZSetup_SetupRippleDeform1)

	arrayPos0 = 128
	CallFunction(LZSetup_SetupRippleDeform1)

	arrayPos0 = 160
	CallFunction(LZSetup_SetupRippleDeform2)

	arrayPos0 = 0x100
	while arrayPos0 < 576
		arrayPos1 = arrayPos0
		arrayPos1 -= 0x100
		stage.deformationData1[arrayPos0] = stage.deformationData1[arrayPos1]
		arrayPos0++
	loop

	SetLayerDeformation(3, 128, 4, 0, 0, 0)

	if stage.actNum < 4
		// If in acts 1-3, then only load the LZ underwater palette
		LoadPalette("LZ_WaterPal.act", 1, 0, 0, 256)
	else
		// SBZ3: Load not only the water palette, but also the main stage palette
		LoadPalette("SBZ3_Pal.act", 0, 128, 128, 192)
		LoadPalette("SBZ3_WaterPal.act", 1, 0, 0, 256)
	end if
	
	// Set up Super colours
	CallFunction(LZSetup_InitSuperSonicPal)
	CallFunction(LZSetup_InitSuperTailsPal)
	CallFunction(LZSetup_InitSuperKnuxPal)

	// Load the eletric flash palette in case the player gets wet with a lightning shield
	LoadPalette("ElectricFlash.act", 2, 0, 0, 256)

	// Reset the flash timer
	Water_flashTimer = 0

	if options.attractMode == true
		if credits.screen > 0
			Player_attractTable 	= LZSetup_replay_credits_STK
			Player_attractTableSize 	= 76
			Player_attractDuration 	= 540
		end if
	
		CallFunction(Player_SetupAttractDemo)
	end if
end event


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

event RSDKDraw
	DrawSprite(0)
end event


event RSDKLoad
	LoadSpriteSheet("Global/Display.gif")
	SpriteFrame(-16, -16, 32, 32, 1, 143)
	
	SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
end event
