/*
	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
*/



//-------------------------------------------------------//
// Path Swapper                                          //
//-------------------------------------------------------//

// Subtypes:
//  - 0x00..0x03 = Encoded width or height
//  - 0x04		 = Horizontal if set, else vertical
//  - 0x08		 = Layer to set when traversed in positive direction
//  - 0x10		 = Layer to set when traversed in negative direction
//  - 0x20		 = Priority flag to set when traversed in positive direction
//  - 0x40		 = Priority flag to set when traversed in negative direction
//  - 0x80		 = Only affect character on ground

//# address-hook(0x01ccae) end(0x01cdac)
function void PathSwapperInit()
{
	objA0.mapping_offset = 0x01d05a
	objA0.sprite_attributes = (sprite_attribute.PALETTE.LINE1 | 0x06bc)
	objA0.render_flags |= render_flag.WORLD
	objA0.box_size.x = 0x40
	objA0.box_size.y = 0x40
	objA0.sprite_priority = 0x280
	objA0.value32 = u16[0x01cd34 + (objA0.subtype2c & 0x03) * 2]	// Half heights: 0x20, 0x40, 0x80, 0x100

	if (objA0.subtype2c & 0x04)
	{
		objA0.animation.sprite = objA0.subtype2c & 0x07
		D1.u16 = objA0.position.y.u16

		A1 = 0xffffb000
		if (D1.u16 < objA1.position.y.u16)
		{
			u8[A0 + 0x34] = 1
		}
		A1 = 0xffffb04a
		if (D1.u16 < objA1.position.y.u16)
		{
			u8[A0 + 0x35] = 1
		}

		if (competition_mode.active)
		{
			objA0.update_address = addressof(PathSwapperCompetitionMode_UpdateHorizontal)
			objA0.sprite_attributes = (sprite_attribute.PALETTE.LINE3 | 0x03d2)
			PathSwapperCompetitionMode_UpdateHorizontal()
		}
		else
		{
			objA0.update_address = addressof(PathSwapperBaseUpdateHorizontal)
			PathSwapperBaseUpdateHorizontal()
		}
	}
	else
	{
		objA0.animation.sprite = objA0.subtype2c & 0x03
		D1.u16 = objA0.position.x.u16

		A1 = 0xffffb000
		if (D1.u16 < objA1.position.x.u16)
		{
			u8[A0 + 0x34] = 1
		}
		A1 = 0xffffb04a
		if (D1.u16 < objA1.position.x.u16)
		{
			u8[A0 + 0x35] = 1
		}

		if (competition_mode.active)
		{
			objA0.update_address = addressof(PathSwapperCompetitionMode_UpdateVertical)
			objA0.sprite_attributes = (sprite_attribute.PALETTE.LINE3 | 0x03d2)
			PathSwapperCompetitionMode_UpdateVertical()
		}
		else
		{
			objA0.update_address = addressof(PathSwapperBaseUpdateVertical)
			PathSwapperBaseUpdateVertical()
		}
	}
}


//# address-hook(0x01cd8a) end(0x01cdac)
function void PathSwapperBaseUpdateVertical()
{
	if (debug_mode.state == 0)
	{
		D1.u16 = objA0.position.x.u16
		A2 = A0 + 0x34

		// Update for Sonic
		A1 = 0xffffb000
		PathSwapperUpdateVertical()

		// Update for Tails
		A1 = 0xffffb04a
		PathSwapperUpdateVertical()

		CheckForUnloadObject()
	}
	else
	{
		DrawOrUnloadObject()

	#if STANDALONE
		debugDrawRect(objA0.position.x.u16 - 0x08, objA0.position.y.u16 - objA0.value32, 0x10, objA0.value32 * 2, 0xa0ffff80)
	#endif
	}
}



//# address-hook(0x01cdb2) end(0x01cef0)
//# alias(fn01cdb2) deprecated
function void PathSwapperCompetitionMode_UpdateVertical()
{
	// This function is only used in competition mode
	D1.u16 = objA0.position.x.u16
	A2 = A0 + 0x34

	A1 = 0xffffb000
	PathSwapperUpdateVertical()

	A1 = 0xffffb04a
	PathSwapperUpdateVertical()

	A1 = 0xffffcb2c
	PathSwapperUpdateVertical()

#if STANDALONE
	if (debug_mode.state)
#else
	if (debug_mode.enabled)
#endif
	{
		DrawObject()
	}
}


//# address-hook(0x01cdda) end(0x01cef0)
function void PathSwapperUpdateVertical()
{
	u16 px = D1.u16

	// Check position relative to switch
	bool onPositiveSide = (u8[A2] == 0)
	++A2

	// Any change?
	if ((px > objA1.position.x.u16) == onPositiveSide)
		return

	u8[A2-1] = onPositiveSide

	D2.s16 = objA0.position.y.u16 - objA0.value32
	D3.s16 = objA0.position.y.u16 + objA0.value32
	if (s16(objA1.position.y.u16) < D2.s16 || s16(objA1.position.y.u16) >= D3.s16)
		return

	if (objA0.subtype2c & 0x80)
	{
		if (u8[A1 + 0x2a] & char.flag.IN_AIR)
			return
	}

	s16 dx = objA1.position.x.u16 - px
	if (abs(dx) >= 0x40)
		return

	// Switch layers (if not flipped)
	if ((objA0.render_flags & render_flag.FLIP_X) == 0)
	{
		if (objA0.subtype2c & (0x10 >> onPositiveSide))
		{
			u8[A1 + 0x46] = 0x0e
			u8[A1 + 0x47] = 0x0f
		}
		else
		{
			u8[A1 + 0x46] = 0x0c
			u8[A1 + 0x47] = 0x0d
		}
	}

	// Affect priority flag (rendering on foreground)
	if (objA0.subtype2c & (0x40 >> onPositiveSide))
		objA1.sprite_attributes |= sprite_attribute.PRIORITY
	else
		objA1.sprite_attributes &= ~sprite_attribute.PRIORITY
}


//# address-hook(0x01cef2) end(0x01cf14)
function void PathSwapperBaseUpdateHorizontal()
{
	if (debug_mode.state == 0)
	{
		D1.u16 = objA0.position.y.u16
		A2 = A0 + 0x34

		A1 = 0xffffb000
		PathSwapperUpdateHorizontal()

		A1 = 0xffffb04a
		PathSwapperUpdateHorizontal()

		CheckForUnloadObject()
	}
	else
	{
		DrawOrUnloadObject()

	#if STANDALONE
		debugDrawRect(objA0.position.x.u16 - objA0.value32, objA0.position.y.u16 - 0x08, objA0.value32 * 2, 0x10, 0xa0ffff80)
	#endif
	}
}


//# address-hook(0x01cf1a) end(0x01cf3c)
function void PathSwapperCompetitionMode_UpdateHorizontal()
{
	// Only used in competition mode
	D1.u16 = objA0.position.y.u16
	A2 = A0 + 0x34

	A1 = 0xffffb000
	PathSwapperUpdateHorizontal()

	A1 = 0xffffb04a
	PathSwapperUpdateHorizontal()

	A1 = 0xffffcb2c
	PathSwapperUpdateHorizontal()

#if STANDALONE
	if (debug_mode.state)
#else
	if (debug_mode.enabled)
#endif
	{
		DrawObject()
	}
}


//# address-hook(0x01cf42) end(0x01d058)
function void PathSwapperUpdateHorizontal()
{
	// Basically the same as "PathSwapperUpdateVertical()", but for horizontal path swapper

	u16 py = D1.u16

	// Check position relative to switch
	bool onPositiveSide = (u8[A2] == 0)
	++A2

	// Any change?
	if ((py > objA1.position.y.u16) == onPositiveSide)
		return

	u8[A2-1] = onPositiveSide

	D2.s16 = objA0.position.x.u16 - objA0.value32
	D3.s16 = objA0.position.x.u16 + objA0.value32
	if (s16(objA1.position.x.u16) < D2.s16 || s16(objA1.position.x.u16) >= D3.s16)
		return

	if (objA0.subtype2c & 0x80)
	{
		if (u8[A1 + 0x2a] & char.flag.IN_AIR)
			return
	}

	D2.u16 = abs(objA1.position.y.u16 - D1.u16)
	if (D2.u16 >= 0x40)
		return

	// Switch layers (if not flipped)
	if ((objA0.render_flags & render_flag.FLIP_X) == 0)
	{
		if (objA0.subtype2c & (0x10 >> onPositiveSide))
		{
			u8[A1 + 0x46] = 0x0e
			u8[A1 + 0x47] = 0x0f
		}
		else
		{
			u8[A1 + 0x46] = 0x0c
			u8[A1 + 0x47] = 0x0d
		}
	}

	// Affect priority flag (rendering on foreground)
	if (objA0.subtype2c & (0x40 >> onPositiveSide))
		objA1.sprite_attributes |= sprite_attribute.PRIORITY
	else
		objA1.sprite_attributes &= ~sprite_attribute.PRIORITY
}
