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

// Any water objects in the scene should be followed by THREE blank objects, these manage player stuff

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

private alias object.value1 : object.constBubbleTimer
private alias object.value2 : object.randBubbleTimer
private alias object.value3 : object.proccessActEffects
private alias object.value8 : object.nextTrackID // Stores the track that should play after the drowning one stops

// Player Aliases
private alias object.type : player.type
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.direction : player.direction
private alias object.tileCollisions : player.tileCollisions
private alias object.interaction : player.interaction

private alias object.value1  : player.timer
private alias object.value3  : player.drownTimer
private alias object.value4  : player.drownLevel
private alias object.value18 : player.sortedDrawOrder
private alias object.value20 : player.topSpeed
private alias object.value21 : player.acceleration
private alias object.value22 : player.deceleration
private alias object.value23 : player.airAcceleration
private alias object.value24 : player.airDeceleration
private alias object.value25 : player.gravityStrength
private alias object.value27 : player.jumpStrength
private alias object.value28 : player.jumpCap
private alias object.value37 : player.shield

// AirBubble Aliases
private alias object.value1 : airBubble.originPos.x
private alias object.value2 : airBubble.targetPlayer

// CountdownBubble Aliases
private alias object.value1 : countdownBubble.drawPos.x
private alias object.value2 : countdownBubble.drawPos.y

// Death Event Aliases
private alias object.value4 : object.timeOver

// Shields
private alias 0 : SHIELD_NONE
private alias 1 : SHIELD_NORMAL
private alias 2 : SHIELD_BUBBLE
private alias 3 : SHIELD_FIRE
private alias 4 : SHIELD_LIGHTNING
private alias 5 : SHIELD_GOGGLES 	// LZ goggles, debug mode only

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

// Super States
private alias 1 : SUPERSTATE_SUPER


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

reserve function MissionWater_SmallAirBubble
reserve function MissionWater_SpawnCountDownBubble
reserve function MissionWater_ResetDrownMusic


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

public value MissionWater_waterSlotID = 0
public value MissionWater_activateFlag = 0


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

private function MissionWater_SmallAirBubble
	if object[+0].constBubbleTimer > 0
		object[+0].constBubbleTimer--

		if object[+0].randBubbleTimer > 0
			object[+0].randBubbleTimer--
		else
			CreateTempObject(TypeName[Air Bubble], 2, player[0].xpos, player[0].ypos)
			object[tempObjectPos].drawOrder = 4
			object[tempObjectPos].yvel = -0x8800
			airBubble[tempObjectPos].targetPlayer = 0
			if player[0].direction == FLIP_NONE
				object[tempObjectPos].xpos += 0x60000
			else
				object[tempObjectPos].xpos -= 0x60000
				object[tempObjectPos].angle = 256
			end if
			airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos
			object[+0].randBubbleTimer = 512
		end if
	else
		Rand(temp0, 3)
		if temp0 == 1
			Rand(object[+0].randBubbleTimer, 16)
			object[+0].randBubbleTimer += 8
		else
			object[+0].randBubbleTimer = 512
		end if

		object[+0].constBubbleTimer = 60
		CreateTempObject(TypeName[Air Bubble], 2, player[0].xpos, player[0].ypos)
		object[tempObjectPos].drawOrder = 4
		object[tempObjectPos].yvel = -0x8800
		airBubble[tempObjectPos].targetPlayer = 0
		if player[0].direction == FLIP_NONE
			object[tempObjectPos].xpos += 0x60000
		else
			object[tempObjectPos].xpos -= 0x60000
			object[tempObjectPos].angle = 256
		end if

		airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos
	end if
end function


private function MissionWater_SpawnCountDownBubble
	CreateTempObject(TypeName[Countdown Bubble], temp0, player[0].xpos, player[0].ypos)
	object[tempObjectPos].drawOrder = 5
	object[tempObjectPos].yvel = -0x8800
	countdownBubble[tempObjectPos].drawPos.y = 0 // this is odd... this is drawPos.y, not "targetPlayer", likely a leftover from AirBubble spawning
	
	if player[0].direction == FLIP_NONE
		object[tempObjectPos].xpos += 0x60000
	else
		object[tempObjectPos].xpos -= 0x60000
		object[tempObjectPos].angle = 0x100
	end if

	countdownBubble[tempObjectPos].drawPos.x = object[tempObjectPos].xpos
end function


private function MissionWater_ResetDrownMusic
	arrayPos0 = MissionWater_waterSlotID
	arrayPos0 += 0
	if player[0].type != TypeName[Death Event]
		if music.currentTrack == TRACK_DROWNING
			if object[arrayPos0].nextTrackID == TRACK_INVINCIBLE
				arrayPos1 = 0
				arrayPos1 += playerCount
				if object[arrayPos1].type != TypeName[Invincibility]
					if Player_superState != SUPERSTATE_SUPER
						object[arrayPos0].nextTrackID = TRACK_STAGE
					end if
				end if
			end if

			PlayMusic(object[arrayPos0].nextTrackID)
		end if
	end if
end function


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

// It seems for whatever reason, Sonic Team replaced all instances of currentPlayer with 0
// They just found and replaced every instance with no further adjustments, so if you see "if 0 == 0" or "object[+0]" anywhere, that's why

event ObjectUpdate
	if object.ypos < stage.newWaterLevel
		object.ypos += 0x10000
	end if
	if object.ypos > stage.newWaterLevel
		object.ypos -= 0x10000
	end if

	temp0 = oscillation
	temp0 <<= 1
	Sin(stage.waterLevel, temp0)
	stage.waterLevel <<= 10
	stage.waterLevel += object.ypos
	temp7 = stage.waterLevel
	stage.waterLevel >>= 16
	
	if stage.timeEnabled == false
		if object[0].type == TypeName[Player Object]
			player[0].drownTimer = 0
		end if
		
		if object[0].type == TypeName[Death Event]
			object[0].timeOver = 11
		end if
	end if

	if player[0].gravityStrength == 0x3800
		CheckNotEqual(player[0].type, TypeName[Debug Mode])
		temp0 = checkResult
		CheckNotEqual(player[0].state, Player_State_Death)
		temp0 &= checkResult
		CheckGreater(player[0].ypos, temp7)
		temp0 &= checkResult
		if temp0 == true
			if player[0].yvel > 0
				player[0].yvel >>= 2
			end if

			if object.ypos < stage.newWaterLevel
				player[0].yvel += 0x10000
			end if

			if player[0].state == Player_State_Fly
				StopSfx(SfxName[Flying])
				StopSfx(SfxName[Jump])
			end if

			player[0].xvel >>= 1
			player[0].speed >>= 1

			CallFunction(Player_UpdatePhysicsState)
			if player[0].yvel != 0
				CreateTempObject(TypeName[Water Splash], 0, player[0].xpos, temp7)
				object[tempObjectPos].drawOrder = 4
				PlaySfx(SfxName[Water Splash], false)
			end if

			object[+0].constBubbleTimer = 52
			player[0].drownTimer = 0
		end if
	else
		if player[0].shield == SHIELD_FIRE
			temp2 = 0
			while temp2 < 8
				Rand(temp0, 32)
				Rand(temp1, 32)
				temp0 -= 16
				temp0 <<= 16
				temp0 += player[0].xpos
				temp1 -= 16
				temp1 <<= 16
				temp1 += player[0].ypos
				CreateTempObject(TypeName[Dust Puff], 0, temp0, temp1)
				object[tempObjectPos].drawOrder = player[0].sortedDrawOrder
				object[tempObjectPos].drawOrder++
				object[tempObjectPos].xvel = player[0].xvel
				object[tempObjectPos].yvel = player[0].yvel
				temp2++
			loop

			player[0].shield = SHIELD_NONE
			arrayPos0 = 0
			arrayPos0 += playerCount
			CallFunction(Player_ApplyShield)
		end if

		if player[0].shield == SHIELD_LIGHTNING
			player[0].shield = SHIELD_NONE
			arrayPos0 = 0
			arrayPos0 += playerCount
			CallFunction(Player_ApplyShield)
			Water_flashTimer = 4
		end if

		if player[0].shield != SHIELD_BUBBLE
			if player[0].drownTimer == 0
				player[0].drownLevel = 0
				CallFunction(MissionWater_ResetDrownMusic)
			end if

			switch player[0].drownLevel
			case 0
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 360
					if 0 == 0
						PlaySfx(SfxName[Drown Alert], false)
					end if
					player[0].drownLevel++
				end if
				break

			case 1
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 660
					if 0 == 0
						PlaySfx(SfxName[Drown Alert], false)
					end if
					player[0].drownLevel++
				end if
				break

			case 2
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 960
					if 0 == 0
						PlaySfx(SfxName[Drown Alert], false)
					end if
					player[0].drownLevel++
				end if
				break

			case 3
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 1080
					if 0 == 0
						object.nextTrackID = music.currentTrack
						PlayMusic(TRACK_DROWNING)
					end if

					temp0 = 0
					CallFunction(MissionWater_SpawnCountDownBubble)
					player[0].drownLevel++
				end if
				break

			case 4
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 1200
					temp0 = 1
					CallFunction(MissionWater_SpawnCountDownBubble)
					player[0].drownLevel++
				end if
				break

			case 5
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 1320
					temp0 = 2
					CallFunction(MissionWater_SpawnCountDownBubble)
					player[0].drownLevel++
				end if
				break

			case 6
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 1440
					temp0 = 3
					CallFunction(MissionWater_SpawnCountDownBubble)
					player[0].drownLevel++
				end if
				break

			case 7
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 1560
					temp0 = 4
					CallFunction(MissionWater_SpawnCountDownBubble)
					player[0].drownLevel++
				end if
				break

			case 8
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 1680
					temp0 = 5
					CallFunction(MissionWater_SpawnCountDownBubble)
					player[0].drownLevel++
				end if
				break

			case 9
				CallFunction(MissionWater_SmallAirBubble)
				player[0].drownTimer++
				if player[0].drownTimer == 1800
					if player[0].state != Player_State_Death
						if 0 == 0
							stage.timeEnabled = false
							camera[0].enabled = false
						end if
						player[0].state = Player_State_Drown
						player[0].animation = ANI_DROWNING
						player[0].speed = 0
						player[0].xvel = 0
						player[0].yvel = 0
						player[0].tileCollisions = false
						player[0].interaction = false
						player[0].sortedDrawOrder = 5
						object[+0].constBubbleTimer = 2
						PlaySfx(SfxName[Drowning], false)
						player[0].drownLevel++
					end if
				end if
				break

			case 10
				player[0].drownTimer++
				if player[0].drownTimer == 1860
					player[0].drownLevel++
				end if

				if object[+0].constBubbleTimer > 0
					object[+0].constBubbleTimer--
					if object[+0].randBubbleTimer > 0
						object[+0].randBubbleTimer--
					else
						Rand(temp1, 2)
						temp1 += 2
						CreateTempObject(TypeName[Air Bubble], temp1, player[0].xpos, player[0].ypos)
						object[tempObjectPos].drawOrder = 5
						object[tempObjectPos].yvel = -0x8800
						object[tempObjectPos].ypos -= 0x60000
						airBubble[tempObjectPos].targetPlayer = 0
						Rand(object[tempObjectPos].angle, 256)
						airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos
						object[+0].randBubbleTimer = 512
					end if
				else
					Rand(temp0, 5)
					if temp0 == 1
						object[+0].randBubbleTimer = 2
					else
						object[+0].randBubbleTimer = 512
					end if
					object[+0].constBubbleTimer = 6

					Rand(temp1, 2)
					temp1 += 2
					CreateTempObject(TypeName[Air Bubble], temp1, player[0].xpos, player[0].ypos)
					object[tempObjectPos].drawOrder = 5
					object[tempObjectPos].yvel = -0x8800
					object[tempObjectPos].ypos -= 0x60000
					airBubble[tempObjectPos].targetPlayer = 0
					Rand(object[tempObjectPos].angle, 0x100)
					airBubble[tempObjectPos].originPos.x = object[tempObjectPos].xpos
				end if
				break
			end switch
		end if

		CheckEqual(player[0].type, TypeName[Debug Mode])
		temp0 = checkResult
		CheckLower(player[0].ypos, temp7)
		temp0 |= checkResult
		if temp0 == true
			if player[0].state != Player_State_Death
				player[0].yvel <<= 1
				if player[0].yvel < -0x100000
					player[0].yvel = -0x100000
				end if

				// plucked this from the forever version, *this* is the water jump bug fix
				if player[0].animation == ANI_JUMPING
					if player[0].timer > 0
						if player[0].yvel < -0x68000
							player[0].yvel = -0x68000
						end if
					end if
				end if

				if player[0].state == Player_State_Fly
					if player[0].timer < 480
						PlaySfx(SfxName[Flying], true)
					else
						PlaySfx(SfxName[Jump], true)
					end if
				end if
				

				CallFunction(Player_UpdatePhysicsState)
				if player[0].yvel != 0
					temp0 = object.ypos
					temp0 -= player[0].ypos
					if temp0 < 0xF00000
						CreateTempObject(TypeName[Water Splash], 0, player[0].xpos, temp7)
						object[tempObjectPos].drawOrder = 4
						PlaySfx(SfxName[Water Splash], false)
					end if
				end if

				player[0].drownTimer = 0
				CallFunction(MissionWater_ResetDrownMusic)
			end if
		end if
	end if

	object.animationTimer++
	object.animationTimer %= 24
	object.frame = object.animationTimer
	object.frame >>= 3
end event


event ObjectDraw
	temp0 = screen.xoffset
	Sin(temp1, oscillation)
	temp1 >>= 5
	temp0 += temp1
	temp0 &= 63
	FlipSign(temp0)

	temp1 = stage.waterLevel
	temp1 -= screen.yoffset
	DrawSpriteScreenFX(object.frame, FX_INK, temp0, temp1)
	
	temp0 += 256
	DrawSpriteScreenFX(object.frame, FX_INK, temp0, temp1)
end event


event ObjectStartup
	LoadSpriteSheet("LZ/Objects2.gif")

	foreach (TypeName[MissionWater], arrayPos0, ALL_ENTITIES)
		object[arrayPos0].priority = PRIORITY_ACTIVE
		object[arrayPos0].drawOrder = 5
		object[arrayPos0].inkEffect = INK_ALPHA
		object[arrayPos0].alpha = 0xA0
		stage.newWaterLevel = object[arrayPos0].ypos
		MissionWater_waterSlotID = arrayPos0
		stage.waterLevel = stage.newWaterLevel
		stage.waterLevel >>= 16
		object[arrayPos0].ypos = stage.newWaterLevel
	next

	if lampPostID > 31
		stage.waterState = recWaterState
		stage.waterLevel = recWaterLevel
		stage.newWaterLevel = recWaterLevel
		stage.newWaterLevel <<= 16
		arrayPos0 = MissionWater_waterSlotID
		object[arrayPos0].ypos = stage.newWaterLevel
	else
		stage.waterState = 0
	end if

	MissionWater_activateFlag = false

	player[0].drownTimer = 0
	if player[0].ypos > stage.newWaterLevel
		player[0].yvel >>= 2
		player[0].xvel >>= 1
		player[0].speed >>= 1
		player[0].topSpeed >>= 1
		player[0].acceleration >>= 1
		player[0].deceleration >>= 1
		player[0].airAcceleration >>= 1
		player[0].airDeceleration >>= 1
		player[0].gravityStrength = 0x1000
		if stage.playerListPos == PLAYER_KNUX_ALONE
			player[0].jumpStrength = 0x30000
		else
			player[0].jumpStrength = 0x38000
		end if
		player[0].jumpCap = -0x20000
		arrayPos0 = MissionWater_waterSlotID
		arrayPos0 += 0 // Good job, Sonic Team
		object[arrayPos0].constBubbleTimer = 52
	end if
	
	SpriteFrame(0, -8, 256, 16, 0, 129)
	SpriteFrame(0, -8, 256, 16, 0, 146)
	SpriteFrame(0, -8, 256, 16, 0, 163)

	BrokenMonitor_ResetDrownMusic = MissionWater_ResetDrownMusic
end event


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

event RSDKDraw
	DrawSprite(0)
end event


event RSDKLoad
	LoadSpriteSheet("LZ/Objects2.gif")
	SpriteFrame(0, -8, 256, 16, 0, 129)
	
	SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
end event
