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

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

private alias object.value0  : object.paletteTimer
private alias object.value2  : object.cylinder1TileFrame
private alias object.value3  : object.cylinder2TileFrame
private alias object.value4  : object.bgPiston1TileFrame
private alias object.value5  : object.bgPiston2TileFrame
private alias object.value6  : object.lavaTileFrame
private alias object.value7  : object.bgPistonTileDuration
private alias object.value8  : object.bgPistonTileAnimID
private alias object.value9  : object.lavaTileDuration
private alias object.value10 : object.palCycle1Timer
private alias object.value11 : object.palCycle1Index
private alias object.value12 : object.palCycle2Timer
private alias object.value13 : object.palCycle2Index

// Universal MPZ Object Aliases
// (As in, all objects in MPZ use their value31 like this)
private alias object.value31 : object.wrapOffset.y

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

// Tracks
private alias 0 : TRACK_STAGE
private alias 1 : TRACK_ACTFINISH
private alias 2 : TRACK_INVINCIBLE
private alias 3 : TRACK_CONTINUE
private alias 4 : TRACK_BOSS
private alias 5 : TRACK_GAMEOVER
private alias 6 : TRACK_DROWNING
private alias 7 : TRACK_SUPER

// Reserved Object Slots Aliases
private alias 10 : SLOT_ZONESETUP
private alias 25 : SLOT_MUSICEVENT_CHANGE
private alias 26 : SLOT_MUSICEVENT_BOSS

// Tile Flag Aliases
private alias 1 : TILE_LAVA

// Tile Info ID Aliases
private alias 8 : TILEINFO_ANGLEB

// Music Events
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 309378 : MUSIC_LOOP_MPZ
private alias 247394 : MUSIC_LOOP_MPZ_F

private alias 38679  : MUSIC_LOOP_INV
private alias 30897  : MUSIC_LOOP_INV_F

// Achievement Aliases
private alias 9 : ACHIEVEMENT_MPZMASTER


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

reserve function MPZSetup_SpeedUpMusic
reserve function MPZSetup_SlowDownMusic


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

private value MPZSetup_prevStageWrap 		= 0
public value MPZSetup_cogFrame 				= 0
public value MPZSetup_cogTimer 				= 0
private value MPZSetup_checkedAchievement 	= 0
private value MPZSetup_playerWasHit 		= 0
private value MPZSetup_unused1 				= 0 // As the name suggests, it is not used
private value MPZSetup_unused2 				= 0 // As the name suggests, it is not used


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

private table MPZSetup_palCycle1
	0x00A000, 0x000000, 0xE0E000, 0x000000, 0xE02000
	0x000000, 0xE020E0, 0x000000, 0x0080E0, 0x000000
end table

private table MPZSetup_palCycle2
	0x600000, 0x800000, 0xA00000
	0xC00000, 0xA00000, 0x800000
end table


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

private function MPZSetup_SpeedUpMusic
	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("Metropolis_F.ogg", TRACK_STAGE, MUSIC_LOOP_MPZ_F, 8000)
			break

		case TRACK_INVINCIBLE
			SetMusicTrack("Metropolis_F.ogg", TRACK_STAGE, MUSIC_LOOP_MPZ_F)
			SwapMusicTrack("Invincibility_F.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV_F, 8000)
			break

		case TRACK_BOSS
		case TRACK_GAMEOVER
		case TRACK_SUPER
			SetMusicTrack("Metropolis_F.ogg", TRACK_STAGE, MUSIC_LOOP_MPZ_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 MPZSetup_SlowDownMusic
	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("Metropolis.ogg", TRACK_STAGE, MUSIC_LOOP_MPZ, 12500)
			break

		case TRACK_INVINCIBLE
			SetMusicTrack("Metropolis.ogg", TRACK_STAGE, MUSIC_LOOP_MPZ)
			SwapMusicTrack("Invincibility.ogg", TRACK_INVINCIBLE, MUSIC_LOOP_INV, 12500)
			break

		case TRACK_BOSS
		case TRACK_GAMEOVER
		case TRACK_SUPER
			SetMusicTrack("Metropolis.ogg", TRACK_STAGE, MUSIC_LOOP_MPZ)
			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.paletteTimer++
	if object.paletteTimer > 2
		object.paletteTimer = 0
		RotatePalette(0, 161, 163, false)
	end if

	object.palCycle1Timer++
	if object.palCycle1Timer >= 10
		object.palCycle1Timer = 0
		object.palCycle1Index++
		if object.palCycle1Index >= 10
			object.palCycle1Index = 0
		end if
		GetTableValue(temp0, object.palCycle1Index, MPZSetup_palCycle1)
		SetPaletteEntry(0, 175, temp0)
	end if


	object.palCycle2Timer++
	if object.palCycle2Timer >= 18
		object.palCycle2Timer = 0
		object.palCycle2Index++
		if object.palCycle2Index >= 6
			object.palCycle2Index = 0
		end if
		GetTableValue(temp0, object.palCycle2Index, MPZSetup_palCycle2)
		SetPaletteEntry(0, 168, temp0)
	end if


	// Cylinder Animations (Interactable)
	Copy16x16Tile(760, object.cylinder1TileFrame)
	object.cylinder1TileFrame++

	Copy16x16Tile(761, object.cylinder1TileFrame)
	object.cylinder1TileFrame++

	Copy16x16Tile(762, object.cylinder1TileFrame)
	object.cylinder1TileFrame++

	Copy16x16Tile(763, object.cylinder1TileFrame)
	object.cylinder1TileFrame++

	Copy16x16Tile(764, object.cylinder1TileFrame)
	object.cylinder1TileFrame++

	Copy16x16Tile(765, object.cylinder1TileFrame)
	object.cylinder1TileFrame++

	Copy16x16Tile(766, object.cylinder1TileFrame)
	object.cylinder1TileFrame++

	Copy16x16Tile(767, object.cylinder1TileFrame)
	object.cylinder1TileFrame++

	if object.cylinder1TileFrame == 832
		object.cylinder1TileFrame = 768
	end if

	// Cylinder Animations (BG)
	Copy16x16Tile(744, object.cylinder2TileFrame)
	object.cylinder2TileFrame++

	Copy16x16Tile(745, object.cylinder2TileFrame)
	object.cylinder2TileFrame++

	Copy16x16Tile(746, object.cylinder2TileFrame)
	object.cylinder2TileFrame++

	Copy16x16Tile(747, object.cylinder2TileFrame)
	object.cylinder2TileFrame++

	Copy16x16Tile(748, object.cylinder2TileFrame)
	object.cylinder2TileFrame++

	Copy16x16Tile(749, object.cylinder2TileFrame)
	object.cylinder2TileFrame++

	Copy16x16Tile(750, object.cylinder2TileFrame)
	object.cylinder2TileFrame++

	Copy16x16Tile(751, object.cylinder2TileFrame)
	object.cylinder2TileFrame++

	if object.cylinder2TileFrame == 896
		object.cylinder2TileFrame = 832
	end if

	if object.bgPistonTileDuration < 2
		Copy16x16Tile(753, object.bgPiston1TileFrame)
		object.bgPiston1TileFrame++

		Copy16x16Tile(754, object.bgPiston1TileFrame)
		object.bgPiston1TileFrame++

		Copy16x16Tile(755, object.bgPiston1TileFrame)
		object.bgPiston1TileFrame++

		if object.bgPiston1TileFrame == 908
			object.bgPiston1TileFrame = 896
		end if

		Copy16x16Tile(742, object.bgPiston2TileFrame)
		object.bgPiston2TileFrame++

		Copy16x16Tile(743, object.bgPiston2TileFrame)
		object.bgPiston2TileFrame++

		Copy16x16Tile(752, object.bgPiston2TileFrame)
		object.bgPiston2TileFrame++

		if object.bgPiston2TileFrame == 908
			object.bgPiston2TileFrame = 896
		end if

		if object.bgPistonTileAnimID == 0
			object.bgPistonTileDuration = 20
		else
			object.bgPistonTileDuration = 8
		end if
		object.bgPistonTileAnimID ^= 1
	else
		object.bgPistonTileDuration--
	end if

	if object.lavaTileDuration < 2
		Copy16x16Tile(756, object.lavaTileFrame)
		object.lavaTileFrame++

		Copy16x16Tile(757, object.lavaTileFrame)
		object.lavaTileFrame++

		Copy16x16Tile(758, object.lavaTileFrame)
		object.lavaTileFrame++

		Copy16x16Tile(759, object.lavaTileFrame)
		object.lavaTileFrame++

		if object.lavaTileFrame == 932
			object.lavaTileFrame = 908
		end if
		object.lavaTileDuration = 14
	else
		object.lavaTileDuration--
	end if

	// Cycle through all players
	foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
		// Check if the player is on lava
		temp1 = player[currentPlayer].xpos
		temp1 >>= 16

		temp2 = player[currentPlayer].ypos
		temp2 >>= 16

		temp2 += 4

		// First bit is set for lava tiles
		Get16x16TileInfo(temp0, temp1, temp2, TILEINFO_ANGLEB)
		temp0 &= TILE_LAVA

		if temp0 == TILE_LAVA
			CallFunction(Player_FireHit)
		end if
	next

	MPZSetup_cogFrame += MPZSetup_cogTimer
	MPZSetup_cogFrame &= 3
	
	if player[0].ypos >= 0x8F00000
		temp1 = player[0].ypos
		currentPlayer = 0
		while currentPlayer < playerCount
			temp0 = player[currentPlayer].ypos
			temp0 -= temp1
			Abs(temp0)
			if temp0 < 0x8C0000
				player[currentPlayer].ypos -= 0x8000000
			end if
			currentPlayer++
		loop

		if camera[0].ypos >= 0x800
			camera[0].ypos -= 0x800
			screen.yoffset -= 0x800
		end if
	end if

	if player[0].ypos <= 0x900000
		temp1 = player[0].ypos
		currentPlayer = 0
		while currentPlayer < playerCount
			temp0 = player[currentPlayer].ypos
			temp0 -= temp1
			Abs(temp0)
			if temp0 < 0x8C0000
				player[currentPlayer].ypos += 0x8000000
			end if
			currentPlayer++
		loop
		
		if camera[0].ypos <= 384
			camera[0].ypos += 0x800
			screen.yoffset += 0x800
		end if
	end if

	// Stage Wrap (Bottom)
	if camera[0].ypos >= 1552
		if MPZSetup_prevStageWrap == 0
			MPZSetup_prevStageWrap = 1
			arrayPos0 = 0x20
			while arrayPos0 < 0x4A0
				if object[arrayPos0].ypos <= 0x2800000
					object[arrayPos0].ypos += 0x8000000
					object[arrayPos0].wrapOffset.y += 0x8000000
				end if
				arrayPos0++
			loop
		end if
	end if

	// Stage Wrap (Top)
	if camera[0].ypos <= 640
		if MPZSetup_prevStageWrap == 1
			MPZSetup_prevStageWrap = 0
			arrayPos0 = 32
			while arrayPos0 < 0x4A0
				if object[arrayPos0].ypos >= 0x6800000
					object[arrayPos0].ypos -= 0x8000000
					object[arrayPos0].wrapOffset.y -= 0x8000000
				end if
				arrayPos0++
			loop
		end if
	end if

	if player[0].state == Player_State_Hurt
		// The player has been hurt, the achievment is unobtainable now
		MPZSetup_playerWasHit = true
	end if

	if MPZSetup_checkedAchievement == false
		if stage.debugMode == false
			if object[30].type == TypeName[Act Finish]
				MPZSetup_checkedAchievement = true

				if MPZSetup_playerWasHit == false
					// Grant the "Metropolis Master" Achieve, since the player made it though without getting hit even once
					CallNativeFunction2(SetAchievement, ACHIEVEMENT_MPZMASTER, 100)
				end if
			end if
		end if
	end if
end event


event ObjectStartup
	SetMusicTrack("Metropolis.ogg", TRACK_STAGE, 309378)
	SpeedUpMusic 	= MPZSetup_SpeedUpMusic
	SlowDownMusic 	= MPZSetup_SlowDownMusic

	animalType1 = TypeName[Locky]
	animalType2 = TypeName[Wocky]
	
	// Reset the colour used for the boss flash
	SetPaletteEntry(0, 192, 0x000000)

	object[SLOT_ZONESETUP].type 				= TypeName[MPZ Setup]
	object[SLOT_ZONESETUP].priority 			= 1
	object[SLOT_ZONESETUP].cylinder1TileFrame 	= 768
	object[SLOT_ZONESETUP].cylinder2TileFrame 	= 832
	object[SLOT_ZONESETUP].bgPiston1TileFrame 	= 896
	object[SLOT_ZONESETUP].bgPiston2TileFrame 	= 902
	object[SLOT_ZONESETUP].lavaTileFrame 		= 908

	MPZSetup_prevStageWrap 		= 0
	MPZSetup_cogFrame 			= 0
	MPZSetup_cogTimer 			= 0
	MPZSetup_checkedAchievement = false
	if starPostID == 0
		MPZSetup_playerWasHit 	= false
	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
