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

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

private alias object.value0 : object.timer
private alias object.value1 : object.holdTimer
private alias object.value2 : object.moveIndex
private alias object.value3 : object.flip
private alias object.value4 : object.turnIndex
private alias object.value5 : object.startPos.x
private alias object.value6 : object.startPos.y

// States
private alias 0 : FLASHER_PAUSED
private alias 1 : FLASHER_MOVING
private alias 2 : FLASHER_CHARGING
private alias 3 : FLASHER_FLASHING
private alias 4 : FLASHER_DIMMING

// Player Aliases
private alias object.value37 : player.shield
private alias object.value40 : player.hitboxLeft
private alias object.value38 : player.hitboxTop
private alias object.value41 : player.hitboxRight
private alias object.value39 : player.hitboxBottom

private alias 4 : SHIELD_LIGHTNING


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

reserve function Flasher_DebugDraw
reserve function Flasher_DebugSpawn

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

// How long the Flasher should pause between movements
private table Flasher_delayTable
	256, 416, 520, 645, 768, 832, 912, 1088, 61440
end table

// Which way the flasher should turn after each cycle
// First value in an entry is if it should turn around X-wise, second is for Y
private table Flasher_directionTable
	1,	1
	0, 	1
	1,	1
	0, 	1
	0, 	1
	1,	0
	0, 	1
	0, 	1
end table

// The three below are animation tables, with values corresponding to SpriteFrames
// This is parallel to how the object's animation was handled in the original Sonic 2
private table Flasher_aniCharging
	1, 0, 0, 0
	0, 0, 1, 0
	0, 0, 0, 1
	0, 0, 1, 0
	1, 0, 1, 0
	1, 0, 1, 0
	1, 0
end table

private table Flasher_aniFlashing
	2, 3, 4, 3, 2, 0, 2
	0, 3, 0, 4, 0, 3, 0
end table

private table Flasher_aniDimming
	4, 4, 4, 4
	3, 3, 3, 3
	2, 2, 2, 2
	1, 1, 1, 1
	0, 0, 0, 0
end table


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

private function Flasher_DebugDraw
	DrawSpriteFX(0, FX_FLIP, object.xpos, object.ypos)
end function


private function Flasher_DebugSpawn
	CreateTempObject(TypeName[Flasher], 0, object.xpos, object.ypos)
end function


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

event ObjectUpdate
	switch object.state
	case FLASHER_PAUSED
		// State only used upon init, just pause for a moment before starting to attack the player
		object.timer++
		if object.timer == 64
			object.timer = 128
			object.xvel = -0x10000
			object.yvel = 0x4000
			object.speed = 512
			object.state = FLASHER_MOVING
			if object.priority != PRIORITY_XBOUNDS_DESTROY
				object.priority = PRIORITY_ACTIVE
			end if
		end if

		foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
			BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, player[currentPlayer].hitboxLeft, player[currentPlayer].hitboxTop, player[currentPlayer].hitboxRight, player[currentPlayer].hitboxBottom)
			if checkResult == true
				CallFunction(Player_BadnikBreak)
			end if
		next
		break

	case FLASHER_MOVING
		if object.timer > 0
			object.timer--
			if object.xvel < 0
				object.direction = FLIP_NONE
			else
				object.direction = FLIP_X
			end if

			GetTableValue(temp0, object.moveIndex, Flasher_delayTable)
			object.holdTimer++
			if object.holdTimer == temp0
				GetTableValue(object.flip, object.turnIndex, Flasher_directionTable)
				if object.flip == true
					FlipSign(object.speed)
				end if

				object.turnIndex++
				GetTableValue(object.flip, object.turnIndex, Flasher_directionTable)
				if object.flip == true
					FlipSign(object.yvel)
				end if

				object.turnIndex++
				object.turnIndex &= 15

				object.moveIndex++
				if object.moveIndex == 10
					object.moveIndex = 0
					object.holdTimer = 0
				end if
			end if

			object.xvel += object.speed
			object.xpos += object.xvel
			object.ypos += object.yvel
		else
			object.state = FLASHER_CHARGING
		end if

		foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
			BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, player[currentPlayer].hitboxLeft, player[currentPlayer].hitboxTop, player[currentPlayer].hitboxRight, player[currentPlayer].hitboxBottom)
			if checkResult == true
				CallFunction(Player_BadnikBreak)
			end if
		next
		break

	case FLASHER_CHARGING
		GetTableValue(object.frame, object.timer, Flasher_aniCharging)
		object.timer++
		if object.timer == 26
			object.timer = 0
			object.state = FLASHER_FLASHING
		end if

		foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
			BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
			if player[currentPlayer].shield != SHIELD_LIGHTNING
				if checkResult == true
					CallFunction(Player_LightningHit)
				else
					BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, player[currentPlayer].hitboxLeft, player[currentPlayer].hitboxTop, player[currentPlayer].hitboxRight, player[currentPlayer].hitboxBottom)
					if checkResult == true
						CallFunction(Player_BadnikBreak)
					end if
				end if
			else
				if checkResult == true
					CallFunction(Player_BadnikBreak)
				end if
			end if
		next
		break

	case FLASHER_FLASHING
		GetTableValue(object.frame, object.animationTimer, Flasher_aniFlashing)
		object.animationTimer++
		if object.animationTimer == 14
			object.animationTimer = 6
		end if

		object.timer++
		if object.timer == 128
			object.timer = 0
			object.state = FLASHER_DIMMING
		end if

		foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
			if player[currentPlayer].shield != SHIELD_LIGHTNING
				BoxCollisionTest(C_TOUCH, object.entityPos, -12, -12, 12, 12, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
				if checkResult == true
					CallFunction(Player_LightningHit)
				else
					BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, player[currentPlayer].hitboxLeft, player[currentPlayer].hitboxTop, player[currentPlayer].hitboxRight, player[currentPlayer].hitboxBottom)
					if checkResult == true
						CallFunction(Player_BadnikBreak)
					end if
				end if
			else
				BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, player[currentPlayer].hitboxLeft, player[currentPlayer].hitboxTop, player[currentPlayer].hitboxRight, player[currentPlayer].hitboxBottom)
				if checkResult == true
					CallFunction(Player_BadnikBreak)
				end if
			end if
		next
		break

	case FLASHER_DIMMING
		GetTableValue(object.frame, object.timer, Flasher_aniDimming)
		object.timer++
		if object.timer == 20
			object.timer = 128
			object.state = FLASHER_MOVING
		end if

		foreach (GROUP_PLAYERS, currentPlayer, ACTIVE_ENTITIES)
			BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, C_BOX, C_BOX, C_BOX, C_BOX)
			if player[currentPlayer].shield != SHIELD_LIGHTNING
				if checkResult == true
					CallFunction(Player_LightningHit)
				else
					BoxCollisionTest(C_TOUCH, object.entityPos, -8, -8, 8, 8, currentPlayer, player[currentPlayer].hitboxLeft, player[currentPlayer].hitboxTop, player[currentPlayer].hitboxRight, player[currentPlayer].hitboxBottom)
					if checkResult == true
						CallFunction(Player_BadnikBreak)
					end if
				end if
			else
				if checkResult == true
					CallFunction(Player_BadnikBreak)
				end if
			end if
		next
		break

	end switch

	if object.outOfBounds == true
		// Even if out of bounds, only despawn the Flasher if its startPos is OOB too
		temp0 = object.xpos
		temp1 = object.ypos
		object.xpos = object.startPos.x
		object.ypos = object.startPos.y
		if object.outOfBounds == true
			if object.priority != PRIORITY_XBOUNDS_DESTROY
				object.timer = 0
				object.frame = 0
				object.state = FLASHER_PAUSED
				object.priority = PRIORITY_BOUNDS
			end if
		else
			// Object startPos is within bounds, move the Flasher back and continue as normal
			object.xpos = temp0
			object.ypos = temp1
		end if
	end if
end event


event ObjectDraw
	DrawSpriteFX(object.frame, FX_FLIP, object.xpos, object.ypos)
end event


event ObjectStartup
	CheckCurrentStageFolder("Zone06")
	if checkResult == true
		LoadSpriteSheet("MCZ/Objects.gif")
		
		// Normal frame
		SpriteFrame(-16, -8, 23, 15, 1, 1)

		// Lighting Frames
		SpriteFrame(-16, -8, 23, 15, 25, 1)
		SpriteFrame(-16, -8, 24, 16, 1, 17)
		SpriteFrame(-16, -12, 28, 24, 1, 34)
		SpriteFrame(-16, -16, 32, 32, 1, 59)
	else
		// Note - even if these are spriteframes for MBZ, they're broken with values copied directly from MCZ's sheet
		// Using these sheet positions results in some of Eggman's head frames
		LoadSpriteSheet("MBZ/Objects.gif")

		// Normal frame
		SpriteFrame(-16, -8, 23, 15, 1, 1)

		// Lighting Frames
		SpriteFrame(-16, -8, 23, 15, 25, 1)
		SpriteFrame(-16, -8, 24, 16, 1, 17)
		SpriteFrame(-16, -12, 28, 24, 1, 34)
		SpriteFrame(-16, -16, 32, 32, 1, 59)
	end if
	
	foreach (TypeName[Flasher], arrayPos0, ALL_ENTITIES)
		object[arrayPos0].startPos.x = object[arrayPos0].xpos
		object[arrayPos0].startPos.y = object[arrayPos0].ypos
	next
	
	SetTableValue(TypeName[Flasher], DebugMode_ObjCount, DebugMode_TypesTable)
	SetTableValue(Flasher_DebugDraw, DebugMode_ObjCount, DebugMode_DrawTable)
	SetTableValue(Flasher_DebugSpawn, DebugMode_ObjCount, DebugMode_SpawnTable)
	DebugMode_ObjCount++
end event


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

event RSDKDraw
	DrawSpriteFX(0, FX_FLIP, object.xpos, object.ypos)
end event


event RSDKLoad
	CheckCurrentStageFolder("Zone06")
	if checkResult == true
		LoadSpriteSheet("MCZ/Objects.gif")
		SpriteFrame(-16, -8, 23, 15, 1, 1)
	else
		LoadSpriteSheet("MBZ/Objects.gif")
		SpriteFrame(-16, -8, 23, 15, 125, 501) // Decomp note - using fixed frame here
	end if
	
	SetVariableAlias(ALIAS_VAR_PROPVAL, "unused")
end event
