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



// Yes, we do ROM writes here indeed!

function void ApplyROMManipulations()
{
	ROMManipulation.RepairSpriteMappings()
	ROMManipulation.RepairAnimations()
	ROMManipulation.CutsceneKnucklesPalette()
	ROMManipulation.AIZ1.KnucklesIntroCritters()
	ROMManipulation.AIZ2.StartPosition()
	ROMManipulation.AIZ2.BlimpSequenceBombs()
	ROMManipulation.HCZ.SetBottomHeight()
	ROMManipulation.CNZ2.KnucklesPreBossCutscene()
	ROMManipulation.HPZ.SecondMuralChunks()
	ROMManipulation.BonusSM.Probabilities()
	ROMManipulation.ALZ.MusicFix()
	ROMManipulation.DPZ.LoopBugFix()
	ROMManipulation.RollingDemoFix()
}


function void ROMManipulation.RepairSpriteMappings()
{
	// Fix for slight offset in Knuckles looking up sprites (0xd5 and 0xd5)
	s16[0x14ba44] = -0x0d
	s16[0x14ba4a] = -0x0d
	s16[0x14ba52] = -0x0d
	s16[0x14ba58] = -0x0d

	// Fix for slight offset in Super Sonic balancing sprites (0xa1 and 0xa2)
	s16[0x14805c] = -0x18	// Originally -0x16
	s16[0x148076] = -0x18	// Originally -0x16

	// Fix for slight offset in Super Sonic standing sprites (0xba to 0xc7)
	s16[0x1480f4] = -0x17	// Originally -0x18
	s16[0x1480fa] = -0x0f	// Originally -0x10
	s16[0x14810e] = -0x17	// Originally -0x18
	s16[0x148114] = -0x0f	// Originally -0x10
	s16[0x148128] = -0x17	// Originally -0x18

	// Fix for slight offset in Super Sonic transformation sprites (0xd5 and 0xd6)
	s16[0x148160] = -0x0e
	s16[0x148174] = -0x0e

	// Fix for incorrect pattern pointers in Super Sonic's third standing sprite
	u8[0x1484f1] = 0x16
	u8[0x1484f7] = 0x16
	u8[0x1484fd] = 0x16
	u8[0x148507] = 0x16

	// Fix for the HCZ blow fish ("Pointdexter")
	s8[0x360e8e] = -0x08
	s8[0x360e9a] = -0x08

	// Remove the cord mapping from the CNZ red balloons; it's directly drawn in standalone to work around unloaded tiles in CNZ1 intro
	u16[0x22306f4] = 0x02
	u16[0x2230708] = 0x02
	u16[0x223071c] = 0x02

	// Fix checkpoint stars loading incorrect tiles
	u16[0x187b8a] = 0xc0
	u16[0x187bec] = 0xc0
	u16[0x187c4e] = 0xc0
}


function void ROMManipulation.RepairAnimations()
{
	// Apply changes to Super Sonic's idle animation to use the third frame
	u8[0x012c45] = 0x5c			// Shift the pointer back a bit to an otherwise empty area
	u32[0x012c96] = 0x07bcbbba	// Add additional frames

	// Fix for Tails' rolling animation playing backwards
	u32[0x015b18] = 0x01989796
	u32[0x015b1d] = 0x00989796
}


function void ROMManipulation.CutsceneKnucklesPalette()
{
	// Fixed Super Sonic underwater palette effect repeat frame
	for (u8 k = 0; k < 6; k += 2)
	{
		u16[0x003a00 + k] = u16[0x0039f4 + k]
		u16[0x003a3c + k] = u16[0x003a30 + k]
	}

	// Changing Cutscene Knuckles' colors a bit to better fit the playable Knuckles
	//  -> Note that this is not used (any more) in S3AIR, as Cutscene Knuckles uses a special palette there
	//  -> See renderhooks.lemon
	u16[0x066912 + 0x04] = 0x064e
	u16[0x066912 + 0x06] = 0x020c
	u16[0x066912 + 0x08] = 0x0206
	//u16[0x066912 + 0x0a] = 0x0080		// TODO: This entry is also used for the rings, should not be changed to green
}


function void ROMManipulation.AIZ1.KnucklesIntroCritters()
{
	// Use AIZ critters and not the MHZ critters in Knuckles' intro, #contributed by iCloudius
	//  -> Also requires some additional initialization code, search for the comment above to find that one
	s16[0x06370f] = 0x5000
	s16[0x063713] = -0x45fb
}


function void ROMManipulation.AIZ2.StartPosition()
{
	if (true)
	{
		// Changed start position for S/T
		u16[0x1e3c1c] = 0x1240
		u16[0x1e3c1e] = 0x0358
	}
	else
	{
		// Original
		u16[0x1e3c1c] = 0x18a0
		u16[0x1e3c1e] = 0x04da
	}
}


function void ROMManipulation.AIZ2.BlimpSequenceBombs()
{
	A0 = 0x23c0a6

	if (Game.getSetting(SETTING_AIZ_BLIMPSEQUENCE))
	{
		// New sequence
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3f5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x4e, 0x3f2c)

		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3f5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x12, 0x3f2c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3edc)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x30, 0x3eac)

		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3f5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x12, 0x3f2c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3edc)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x12, 0x3eac)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3e5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x16, 0x3e2c)

		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3f5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x12, 0x3f2c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3edc)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x12, 0x3eac)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x0c, 0x3e5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x12, 0x3e2c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x40, 0x3dec)

		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x40, 0x3dec)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x04, 0x3dec)
	}
	else
	{
		// Original values
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3f5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3f2c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3f5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3f2c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3f5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x38, 0x3f2c)

		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3edc)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3eac)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3edc)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3eac)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3edc)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x38, 0x3eac)

		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3e5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3e2c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3e5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3e2c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x20, 0x3e5c)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x38, 0x3e2c)

		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x40, 0x3dec)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x40, 0x3dec)
		ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(0x40, 0x3dec)
	}
}

function void ROMManipulation.AIZ2.BlimpSequenceBombs.addBlimpSequenceBomb(u16 delayAfterwards, u16 position)
{
	u16[A0]   = delayAfterwards
	u16[A0+2] = position
	A0 += 4
}

function void ROMManipulation.HCZ.SetBottomHeight()
{
	if (Game.getSetting(SETTING_FIX_GLITCHES) >= 2)
		u16[0x01bce4] = 0x0c00 - getScreenHeight()
	else
		u16[0x01bce4] = 0x1000
}

function void ROMManipulation.CNZ2.KnucklesPreBossCutscene()
{
	// Move the maxX screen position for triggering the cutscene a bit to the right, to avoid issues in 4:3 with extended camera
	u16[0x062526] = 0x46f0		// Originally 0x46e0
}

function void ROMManipulation.HPZ.SecondMuralChunks()
{
	// Replace the two chunks in HPZ originally showing a second copy of the mural
	//  -> This is somewhat irritating in S3AIR because with widescreen, you can see the second mural during the fight against Knuckles
	u8[0x0a7924 + 0x0218] = 0x42
	u8[0x0a7924 + 0x0219] = 0x42
}

function void ROMManipulation.BonusSM.Probabilities()
{
	// Increased chance for Jackpot, reduced chance for Robotnik, and bringing Knuckles on the same level as Sonic & Tails
	A0 = 0x04c8b4
	u8[A0]      = 7		// Chance of 3x Jackpot (enforced triple)	-- original value: 4
	u8[A0 + 3]  = 9		// Chance of 3x Sonic (enforced triple)		-- original value: 9
	u8[A0 + 6]  = 9		// Chance of 3x Knuckles (enforced triple)	-- original value: 4
	u8[A0 + 9]  = 15	// Chance of 3x Robotnik (enforced triple)	-- original value: 18
	u8[A0 + 12] = 9		// Chance of 3x Tails (enforced triple)		-- original value: 9
	u8[A0 + 15] = 15	// Chance of 3x Ring (enforced triple)		-- original value: 15
	u8[A0 + 18] = 15	// Chance of 3x Bar (enforced triple)		-- original value: 15
}

function void ROMManipulation.ALZ.MusicFix()
{
	// Azure Lake emulated music fix, #contributed by Legobouwer
	u8[0x2d9f81] = 0x04
}

function void ROMManipulation.DPZ.LoopBugFix()
{
	// Move y-position of one path swapper from 0x0160 down some pixels to avoid a bug that can send you backwards through the loop
	u16[0x1fc628] = 0x0168
}

function void ROMManipulation.RollingDemoFix()
{
	u8[0x15fd6c] = 0x9d
}
