Scriptname RenTime:RenTimeTeleportScript extends Quest

; Temporal Implosion Management Engine - T.I.M.E.

struct PlayerMovement
	float x = 0.0
	float y = 0.0
	float z = 0.0
	float anglex
	float angley
	float anglez
	float health
	float actionpoints
	Cell currentcell = none
	ObjectReference MyMarker = none
endStruct	

PlayerMovement[] Property movearray Auto

int internaltimer = 0

ObjectReference Property PlayerRef Auto

ImageSpaceModifier Property SlowTimeImod Auto

Potion Property RenTimeJetPill Auto
MagicEffect Property SlowTimeJet Auto
Keyword Property SlowTimeKeyword Auto

bool playerinjump = false

bool Property playerteleporting = false Auto

float cooldown = 0.0

Keyword Property ActorTypeNPC Auto

Spell Property RenTimeNPCAbility Auto

ObjectReference Property MyCurrentFurniture Auto

Float Property TimeJumpSpeed = 0.5 Auto

ActorValue Property Health Auto
ActorValue Property ActionPoints Auto

Formlist Property RenTimeProjectileFormlist Auto

InputEnableLayer Property PlayerInputLayer Auto

Static Property XMarker Auto

ObjectReference Property PlayerFollower Auto
bool MovePlayerFollower = true

Int Property TimeMode = 0 Auto

; TimeMode 0 = player-only
; TimeMode 1 = Player + NPCs (projectiles get disabled / removed, but not mines)
; for every mode, we will disable player controls

Event OnInit()

	if (PlayerRef != Game.GetPlayer())
		PlayerRef = Game.GetPlayer()
	endif

	if (PlayerRef.GetItemCount(RenTimeJetPill) == 0)
		PlayerRef.AddItem(RenTimeJetPill, 100)
	endif
	
	Self.RegisterForAnimationEvent(PlayerRef, "JumpUp")	
	Self.RegisterForAnimationEvent(PlayerRef, "JumpDown")	
	Self.RegisterForAnimationEvent(PlayerRef, "jetpackStart")
	
	Self.RegisterForPlayerTeleport()
	Self.RegisterForRemoteEvent(PlayerRef, "OnTranslationComplete")	
	Self.RegisterForRemoteEvent(PlayerRef, "OnTranslationAlmostComplete")
	Self.RegisterForRemoteEvent(PlayerRef, "OnTranslationFailed")
	Self.RegisterForRemoteEvent((PlayerRef As Actor), "OnSit")
	Self.RegisterForRemoteEvent((PlayerRef As Actor), "OnGetUp")
	
	PlayerFollower = PlayerRef.PlaceAtMe(XMarker, 1, true, false, false)
	
	movearray = new PlayerMovement[128]
	int i = 0
	while (i < movearray.length)
		movearray[i] = new PlayerMovement
		i += 1
	endWhile	
	
	Self.StartTimer(1.0, 2)
	Self.StartTimer(TimeJumpSpeed, 0)
endEvent

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
	if (asEventName == "JumpUp" || asEventName == "jetpackStart")
		playerinjump = true
	endIf
	if (asEventName == "JumpDown")
		playerinjump = false	
	endif
endEvent

Function ClearArray()

	int i = 0
	while (i < movearray.length)
		movearray[i] = new PlayerMovement
		i += 1
	endWhile
	
endFunction

Event OnPlayerTeleport()
	MovePlayerFollower = false
	int itr = internaltimer
	
	while (movearray[itr].currentcell == PlayerRef.GetParentCell() && itr >= 0)
		itr -= 1
	endWhile
	
	if (itr < 0)
		itr = 0
	endif
	
	if (movearray[itr].currentcell != PlayerRef.GetParentCell())
		movearray[itr].MyMarker = PlayerFollower.PlaceAtMe(XMarker, 1, true, false, false)
		MovePlayerFollower = true
	endif
endEvent

Function NextJump()
	if (internaltimer >= 0 && movearray[internaltimer].x != 0.0 && movearray[internaltimer].y != 0.0)
	
		if (movearray[internaltimer].currentcell != PlayerRef.GetParentCell())
			if (movearray[internaltimer].MyMarker != none && movearray[internaltimer].MyMarker.GetParentCell() != PlayerRef.GetParentCell())
				PlayerRef.MoveTo(movearray[internaltimer].MyMarker)
			endif
		endif
	
		PlayerRef.TranslateTo(movearray[internaltimer].x, movearray[internaltimer].y, movearray[internaltimer].z, movearray[internaltimer].anglex, movearray[internaltimer].angley, movearray[internaltimer].anglez, 16000.0, 0.0)
		
		movearray[internaltimer].x = 0.0
		movearray[internaltimer].y = 0.0
		movearray[internaltimer].z = 0.0
		
		movearray[internaltimer].anglex = 0.0
		movearray[internaltimer].angley = 0.0
		movearray[internaltimer].anglez = 0.0
		
		PlayerRef.SetValue(Health, (movearray[internaltimer].health As Float))		
		PlayerRef.SetValue(ActionPoints, (movearray[internaltimer].actionpoints As Float))				
		
		if ((internaltimer-1) >= 0 && movearray[internaltimer-1].x == 0.0 && movearray[internaltimer-1].y == 0.0)		
			CheckIfComplete()			
		endif
	else
		if (movearray[127].x != 0.0 && movearray[127].y != 0.0)
			internaltimer = 127
			NextJump()
		endif
	
		CheckIfComplete()	
	endif
endFunction

Event ObjectReference.OnTranslationAlmostComplete(ObjectReference akSender)
	internaltimer -= 1
	NextJump()
endEvent

Event ObjectReference.OnTranslationFailed(ObjectReference akSender)
	internaltimer -= 1
	NextJump()
endEvent

Event Actor.OnGetUp(Actor akSender, ObjectReference akFurniture)
	MyCurrentFurniture = none
endEvent

Event Actor.OnSit(Actor akSender, ObjectReference akFurniture)
	MyCurrentFurniture = akFurniture
endEvent

Function CheckIfComplete()
	internaltimer = 0
	if (SlowTimeImod != none)	
		SlowTimeImod.Remove()	
	endif
	
	PlayerRef.StopTranslation()
	
	ClearArray()	
	
	(PlayerRef As Actor).SetGhost(false)	
	
	PlayerInputLayer.EnablePlayerControls()
	
	PlayerInputLayer.Delete()
	
	playerteleporting = false
	cooldown = 5.0
endFunction

Function TeleportBack()

	PlayerInputLayer.DisablePlayerControls(abLooking = true)

	if (SlowTimeImod != none)
		SlowTimeImod.Apply()
	endif

	float change_x = 0
	float change_y = 0
	float change_z = 0
	float change_anglex = 0
	float change_angley = 0		
	float change_anglez = 0		
	
	int i = 0	
	
	bool continueloop = true
	
	while (i < movearray.length && continueloop == true)
		if (movearray[i].x == 0.0 && movearray[i].y == 0.0)
			continueloop = false
			i -= 1
		else
			i += 1
		endif
	endWhile	
	
	if (i <= 0)
		return
	endif
	
	internaltimer = i
	
	(PlayerRef As Actor).SetGhost(true)
	
	if ((PlayerRef As Actor).GetSitState() >= 1 && MyCurrentFurniture != none && MyCurrentFurniture Is Actor == false)
		(PlayerRef As Actor).Dismount()
	endif	
	
	PlayerRef.TranslateTo(movearray[internaltimer].x, movearray[internaltimer].y, movearray[internaltimer].z, movearray[internaltimer].anglex, movearray[internaltimer].angley, movearray[internaltimer].anglez, 8000.0)
	
endFunction

Event OnTimer(int timerid)
	
	if (cooldown >= 0 && timerid == 0)
		cooldown -= TimeJumpSpeed
	endif
	
	if (PlayerRef.HasEffectKeyword(SlowTimeKeyword) == true && cooldown <= 0 && timerid == 0)
		if (playerteleporting == false)
			playerteleporting = true
			
			PlayerInputLayer = InputEnableLayer.Create()
			
			ObjectReference[] FoundProjs = PlayerRef.FindAllReferencesOfType(RenTimeProjectileFormlist, 12000)	
			
			int itr = 0
			while (itr < FoundProjs.length)
				FoundProjs[itr].Disable()
				FoundProjs[itr].DeleteWhenAble()
				itr += 1
			endWhile
			
			TeleportBack()
		endif
		Self.StartTimer(TimeJumpSpeed, 0)
		return		
	endif
	
	if (playerinjump == true && timerid == 0)
		Self.StartTimer(TimeJumpSpeed, 0)
		return
	endif
	
	if (timerid == 2)
	
		ObjectReference[] FoundActors = PlayerRef.FindAllReferencesWithKeyword(ActorTypeNPC, 12000)
	
		int itr = 0
		
		while (FoundActors != none && itr < FoundActors.length)
			if (FoundActors[itr] != none && (FoundActors[itr] As Actor).HasSpell(RenTimeNPCAbility) == false)
				(FoundActors[itr] As Actor).AddSpell(RenTimeNPCAbility)
			endif
			itr += 1
		endWhile
	
		Self.StartTimer(2.0, 2)
	elseif (timerid == 0)	
		PlayerFollower.MoveTo(PlayerRef)
	
		movearray[internaltimer].x = PlayerRef.GetPositionX()
		movearray[internaltimer].y = PlayerRef.GetPositionY()	
		movearray[internaltimer].z = PlayerRef.GetPositionZ()
		
		movearray[internaltimer].anglex = PlayerRef.GetAngleX()
		movearray[internaltimer].angley = PlayerRef.GetAngleY()
		movearray[internaltimer].anglez = PlayerRef.GetAngleZ()	
		
		movearray[internaltimer].health = PlayerRef.GetValue(Health) As Int		
		movearray[internaltimer].actionpoints = PlayerRef.GetValue(ActionPoints) As Int				
		
		movearray[internaltimer].currentcell = PlayerRef.GetParentCell()
		
		if (movearray[internaltimer].MyMarker != none)
			movearray[internaltimer].MyMarker.Disable()
			movearray[internaltimer].MyMarker.DeleteWhenAble()
			movearray[internaltimer].MyMarker = none
		endif
		
		internaltimer += 1
		
		if (internaltimer >= 128)
			ClearArray()
			internaltimer = 0
		endif
	
		Self.StartTimer(TimeJumpSpeed, 0)
	endif
	
endEvent