/*
	This script file is part of the Sonic 3 A.I.R. script software distribution.
	Copyright (C) 2017-2024 by Eukaryot

	Published under the GNU GPLv3 open source software license, see license.txt
	or https://www.gnu.org/licenses/gpl-3.0.en.html
*/



//-------------------------------------------------------//
// Booster Tube (from Launch Base Zone)                  //
//-------------------------------------------------------//

// Note that this logic is used for movement inside LBZ 2 water pipes as well

//# address-hook(0x0295c2) end(0x0295ca)
function void fn0295c2()
{
	--objA0.animation.timer
	if (s8(objA0.animation.timer) >= 0)
		return

	objA0.animation.timer = 0
	fn0295d0()
}


//# address-hook(0x0295d0) end(0x0295e2)
function void fn0295d0()
{
	objA0.render_flags |= render_flag.WORLD
	objA0.box_size.x = 0x10
	objA0.sprite_priority = 0x0280

	objA0.update_address = 0x0295e8
	fn0295e8()
}


//# address-hook(0x0295e8) end(0x029608)
function void fn0295e8()
{
	A1 = 0xffffb000
	A4 = A0 + 0x30
	fn02960e()

	A1 = 0xffffb04a
	A4 = A0 + 0x3a
	fn02960e()

	D0.u8 = u8[A0 + 0x30] + objA0.value3a
	if (D0.u8 == 0)
	{
		CheckForUnloadObject()
	}
}


//# address-hook(0x02960e) end(0x029616)
function void fn02960e()
{
	// Targets:
	//  - 0x029620	-> u8[A4] = 0x00
	//  - 0x0296d4	-> u8[A4] = 0x02
	//  - 0x02978e	-> u8[A4] = 0x04
	call tableLookupAddress(0x02961a, u8[A4])
}


//# address-hook(0x029620) end(0x0296d2)
function void fn029620()
{
	if (debug_mode.state != 0)
		return

	u16 dx = objA1.position.x.u16 - objA0.position.x.u16 + 0x10
	u16 dy = objA1.position.y.u16 - objA0.position.y.u16 + 0x18
	if (dx < 0x20 && dy < 0x28 && u8[A1 + 0x2e] == 0)
	{
		// Character gets caught and moved by this object now
		u8[A4] += 2
		u8[A4 + 0x01] = 0

		objA0.flags2a &= ~object.flag.P1_PUSHING

		objA1.position.x.u16 = objA0.position.x.u16
		objA1.position.y.u16 = objA0.position.y.u16
		objA1.velocity.x = 0
		objA1.velocity.y = 0
		objA1.groundspeed = 0x0800
		objA1.flags2a &= ~char.flag.PUSHING
		objA1.flags2a |= char.flag.IN_AIR
		objA1.state = char.state.ROLLING
		u8[A1 + 0x2e] = (control_flag.DISABLE_INTERACTION | control_flag.DISABLE_UPDATE)
		u8[A1 + 0x40] = 0

		fn0297a2()

		playSound(SFX_ROLL)

		if (objA0.subtype2c & 0x20 && global.act != 0)
		{
		#if STANDALONE
			// Remove priority flag for character
			objA1.sprite_attributes &= ~sprite_attribute.PRIORITY

			// Update achievement
			if (A1 == 0xffffb000)
			{
				Game.setAchievementValue(ACHIEVEMENT_LBZ_STAY_DRY, 0)
			}
		#endif

			// Remove shields like water does
			if (u8[A1 + 0x2b] & char.bonus.SHIELD_FIRE)
			{
				u8[A1 + 0x2b] &= ~(char.bonus.SHIELD_FIRE | char.bonus.ANY_SHIELD)
			}
			if (u8[A1 + 0x2b] & char.bonus.SHIELD_LIGHTNING)
			{
				u8[A1 + 0x2b] &= ~(char.bonus.SHIELD_LIGHTNING | char.bonus.ANY_SHIELD)
			}
		}
	}
}


//# address-hook(0x0296d4) end(0x029766)
function void fn0296d4()
{
	--u8[A4 + 0x02]
	if (s8[A4 + 0x02] <= 0)
	{
		A2 = u32[A4 + 0x06]
		D4.u16 = u16[(A2+=2)-2]
		objA1.position.x.u16 = D4.u16
		D5.u16 = u16[(A2+=2)-2]
		objA1.position.y.u16 = D5.u16
		if (s8[A0 + 0x2c] < 0)
		{
			A2 -= 8
		}
		u32[A4 + 0x06] = A2
		u16[A4 + 0x04] -= 4
		if (u16[A4 + 0x04] != 0)
		{
			D4.u16 = u16[(A2+=2)-2]
			D5.u16 = u16[(A2+=2)-2]
			D2.u16 = 0x1000
			fn029818()
			return
		}

		u8[A4] += 2
		u8[A4 + 0x02] = 0x02
		objA1.position.y.u16 &= 0x0fff
		if ((objA0.subtype2c & 0x40) == 0)
		{
			objA1.velocity.x = 0
			objA1.velocity.y = 0
		}

		playSound(0x81)

		if (objA0.subtype2c & 0x20)
		{
			A2 = A1
			if (allocDynamicObjectAfterA0())
			{
				objA1.update_address = 0x029896
				objA1.position.x.u16 = u16[A2 + 0x10]
				objA1.position.y.u16 = u16[A2 + 0x14]
				objA1.velocity.x = u16[A2 + 0x18]
				objA1.velocity.y = u16[A2 + 0x1a]
			}
			A1 = A2
		}
	}

	fn029768()
}


//# address-hook(0x029768) end(0x02978c)
function void fn029768()
{
	D2 = objA1.position.x + (objA1.velocity.x << 8)
	D3 = objA1.position.y + (objA1.velocity.y << 8)
	objA1.position.x = D2
	objA1.position.y = D3
}


//# address-hook(0x02978e) end(0x0297a0)
function void fn02978e()
{
	--u8[A4 + 0x02]
	if (u8[A4 + 0x02] == 0)
	{
		u8[A1 + 0x2e] = 0
		u8[A4] = 0
	}

	objA1.velocity.y += 0x38
	fn029768()
}


//# address-hook(0x0297a2) end(0x029814)
function void fn0297a2()
{
	D0.u8 = objA0.subtype2c
	if (D0.u8 & 0x80)
	{
		D0.u16 = (D0.u16 & 0x1f) * 4
		A2 = u32[0x1e3f18 + D0.u16]
		D0.u16 = u16[(A2+=2)-2] - 4
		u16[A4 + 0x04] = D0.u16
		A2 += D0.s16
		objA1.position.x.u16 = u16[(A2+=2)-2]
		objA1.position.y.u16 = u16[(A2+=2)-2]
		A2 -= 8
	}
	else
	{
		if (D0.u8 == 0x10 && isMainCharacter(CHARACTER_TAILS))
		{
			D0 = 0
		}

		D0.u16 = (D0.u16 & 0x1f) * 4
		A2 = u32[0x1e3f18 + D0.u16]
		u16[A4 + 0x04] = u16[(A2+=2)-2] - 4
		objA1.position.x.u16 = u16[(A2+=2)-2]
		objA1.position.y.u16 = u16[(A2+=2)-2]
	}

	u32[A4 + 0x06] = A2
	D4.u16 = u16[(A2+=2)-2]
	D5.u16 = u16[(A2+=2)-2]
	D2.u16 = 0x1000
	fn029818()
}


//# address-hook(0x029818) end(0x029894)
function void fn029818()
{
	D3.u16 = D2.u16
	D0 = D4.u16 - objA1.position.x.u16
	if (D0.s16 < 0)
	{
		D0.s16 = -D0.s16
		D2.s16 = -D2.s16
	}

	D1 = D5.u16 - objA1.position.y.u16
	if (D1.s16 < 0)
	{
		D1.s16 = -D1.s16
		D3.s16 = -D3.s16
	}

	if (D1.u16 >= D0.u16)
	{
		D1 = D5.u16
		D1.u16 -= objA1.position.y.u16
		D1 = (D1 << 16) + (D1 >> 16)
		D1.s16 = D1.s32 / D3.s16
		D0 = D4.u16
		D0.u16 -= objA1.position.x.u16
		if (D0.u16 != 0)
		{
			D0 = (D0 << 16) + (D0 >> 16)
			D0.s16 = D0.s32 / D1.s16
		}

		objA1.velocity.x = D0.u16
		objA1.velocity.y = D3.u16
		u16[A4 + 0x02] = abs(D1.s16)
	}
	else
	{
		D0 = D4.u16
		D0.u16 -= objA1.position.x.u16
		D0 = (D0 << 16) + (D0 >> 16)
		D0.s16 = D0.s32 / D2.s16
		D1 = 0
		D1.u16 = D5.u16
		D1.u16 -= objA1.position.y.u16
		if (D1.u16 != 0)
		{
			D1 = (D1 << 16) + (D1 >> 16)
			D1.s16 = D1.s32 / D0.s16
		}

		objA1.velocity.y = D1.u16
		objA1.velocity.x = D2.u16
		u16[A4 + 0x02] = abs(D0.s16)
	}
}



// Effect

//# address-hook(0x029896) end(0x029904)
function void fn029896()
{
	objA0.mapping_offset = 0x029c8a
	objA0.sprite_attributes = (sprite_attribute.PALETTE.LINE2 | 0x02ea)
	objA0.box_size.x = 0x10
	objA0.box_size.y = 0x10
	objA0.render_flags |= render_flag.WORLD
	objA0.sprite_priority = 0x0180

	if (objA0.subtype2c != 0)
	{
		objA0.update_address = 0x029a54
		fn029a54()
		return
	}

	u16[A0 + 0x30] = 0x3c
	if (objA0.velocity.y != 0)
	{
		if (objA0.velocity.y > 0)
		{
			u16[A0 + 0x26] = 6
		}
	}
	else
	{
		u16[A0 + 0x26] = (objA0.velocity.x >= 0) ? 18 : 12
	}

	if (global.act == 0)
	{
		objA0.update_address = 0x029af8
		fn029af8()
	}
	else
	{
		objA0.update_address = 0x02990a
		fn02990a()
	}
}


//# address-hook(0x02990a) end(0x02998c)
function void fn02990a()
{
	--objA0.countdown_value
	if (objA0.countdown_value < 0)
	{
		objA0.countdown_value = 0x03
		if (allocDynamicObjectAfterA0())
		{
			objA1.update_address = (u16[A0 + 0x26] == 6) ? 0x0299f4 : 0x0299c6
			objA1.position.x.u16 = objA0.position.x.u16
			objA1.position.y.u16 = objA0.position.y.u16
			objA1.mapping_offset = 0x029c8a
			objA1.sprite_attributes = (sprite_attribute.PALETTE.LINE2 | 0x02ea)
			objA1.box_size.x = 0x10
			objA1.box_size.y = 0x10
			objA1.sprite_priority = 0x0380

			D0.u16 = u16[A0 + 0x26]
			A2 = 0x029992 + D0.u16
			objA1.velocity.x = u16[(A2+=2)-2]
			objA1.velocity.y = u16[(A2+=2)-2]
			objA1.render_flags = u8[(A2+=1)-1]
			u8[A1 + 0x22] = u8[(A2+=1)-1]
			if (u8[A1 + 0x22] == 0)
			{
				objA1.update_address = 0x029a24
				fn0299aa()
			}
		}
	}

	--u16[A0 + 0x30]
	if (s16[A0 + 0x30] < 0)
	{
		objA0.position.x.u16 = 0x7ff0
	}

	CheckForUnloadObject()
}


//# address-hook(0x0299aa) end(0x0299c4)
function void fn0299aa()
{
	D0 = u16[A0 + 0x30]
	D0.u16 -= 0x3c
	D0.s16 = -D0.s16
	D0.u16 <<= 4
	if (objA1.velocity.x >= 0)
		D0.s16 = -D0.s16
	objA1.velocity.x += D0.u16
}


//# address-hook(0x029a54) end(0x029ab8)
function void fn029a54()
{
	if ((level.framecounter.low & 3) == 0)
	{
		if (allocDynamicObjectAfterA0())
		{
			objA1.update_address = 0x029abe
			objA1.render_flags = (render_flag.WORLD | render_flag.VISIBLE)
			objA1.box_size.y = 0x10
			objA1.box_size.x = 0x10
			objA1.sprite_priority = 0x0380
			objA1.sprite_attributes = (sprite_attribute.PALETTE.LINE2 | 0x02ea)
			objA1.mapping_offset = 0x029c8a
			objA1.position.x.u16 = objA0.position.x.u16
			objA1.position.y.u16 = objA0.position.y.u16
			objA1.velocity.x = 0
			objA1.velocity.y = 0x0400
			u8[A1 + 0x22] = 0x01
			u16[A1 + 0x2e] = 0x0b
		}
	}

	CheckForUnloadObject()
}


//# address-hook(0x029af8) end(0x029b36)
function void fn029af8()
{
	if ((level.framecounter.low & 3) == 0)
	{
		if (allocDynamicObjectAfterA0())
		{
			// Spawn small explosion
			objA1.update_address = 0x01e68e
			objA1.position.x.u16 = objA0.position.x.u16
			objA1.position.y.u16 = objA0.position.y.u16
			objA1.velocity.x = objA0.velocity.x
			objA1.velocity.y = objA0.velocity.y
		}
	}

	--u16[A0 + 0x30]
	if (s16[A0 + 0x30] < 0)
	{
		objA0.position.x.u16 = 0x7ff0
	}

	CheckForUnloadObject()
}
