#TouhouDanmakufu[Stage]
#Title["Touhou Hou Enbu"]
#Text["Stage Script"]
#ScriptVersion[3]
#System["script/thdcs/functions/function_system.txt"]

// Camera debug
let debugCameraShift = 0;							// debug camera for X position
let debugCameraLift = 0;							// debug camera for Y position
let debugCameraZoom = 0;							// debug camera for Z position
let debugCameraTilt = 0;							// debug camera for elevation
let debugCameraTurn = 0;							// debug camera for azimuth

// 3D camera variables
let cameraTilt = 0;								// Elevation angle
let cameraTurn = 0;								// Azimuth angle
let camRadius = 0;								// Radius
let cameraShift = 0;							// X-pos
let cameraLift = 0;								// Y-pos
let cameraZoom = 0;								// Z-pos
let cameraRoll = 0;								// Roll angle
let cameraSwitch = 0;							// Switcher
let isQuake = false;

// Global stage essentials, used for all stages...
let idScript;
let fogStart = 0;								// global var for setting the start of the fog. Begin fogging.
let fogEnd = 0;									// global var for setting the end of the fog. Highest density. 
let fogRed = 0;									// global var for setting RGB red.
let fogGreen = 0;								// global var for setting RGB green.
let fogBlue = 0;								// global var for setting RGB blue.
let f = 0;										// global var for scrolling the z-pos of the stage. f = frame.
let s = 0;										// global var for scrolling textures UV. s = scroll.
let s2 = 0;										// global var for scrolling textures UV. s2 = scroll 2.

// world mutation enum for morphing the stages
let isMutatingStage = false;					// Trigger to track if transition or mutation taking place
let holdStage = false;							// Trigger to hold changes. 
let stagelook = 0;								// main var for the stagelook.
let worldBalInside = 1;							// Enums for the various stage looks + camera behaviour
let worldBallBoss = 2;
let worldAfroInside = 3;
let worldAfroOutside = 4;
let worldAfroBoss = 5;
let worldDjSky = 6;
let worldDjCity = 7;
let worldDjCity2 = 8;
let worldDjCity3 = 9;
let worldDjBoss = 10;

// stage 1 essentials
let startFade = 555; 							// starts fading at this distance from the camera.
let endFade = 55; 								// below this distance, the object is completely invisible.
let butterflySpotlightSpinValue = 0;							// var to spin the spotlights.

// stage 2 essentials
let lightBundleCoordinates = [ 
	[[0,0],[128,640],[256,128],[384,512],[512,896],[640,256],[768,768],[896,512]],
	[[0,256],[128,896],[256,640],[384,384],[512,384],[640,128],[768,512],[896,768]],
	[[0,512],[128,256],[256,896],[384,768],[512,512],[640,384],[768,128],[896,896]],
	[[0,768],[128,512],[256,256],[384,768],[512,384],[640,512],[768,896],[896,256]]
];
let lightBundleID = [];
let lightBundleID2 = [];
let lightBundle1 = [];
let lightBundle2 = [];
let lightBundle3 = [];
let lightBundleChange = false;
let lightBundleAlpha = 0;
let lightBundleRed = 0;
let lightBundleGreen = 0;
let lightBundleBlue = 0;
let lightBundleAlpha1 = 0;
let lightBundleAlpha2 = 0;
let lightBundleAlpha3 = 0;
let lightBundleFogRed = 0;
let lightBundleFogGreen = 0;
let lightBundleFogBlue = 0;
let cloudFadeValue = 0;
let cloudAlpha = 205; 

// stage 3 essentials
let updateFog = true;
let wallSwitchValue = 0;

// arrays for stage objects en zpos tracking for scrolling / handling / etc.
let stageNonMoveObj = [];
let stageSpriteObj = [];		
let stageSpriteZpos = [];
let stageSpriteYObj = [];		
let stageSpriteYpos = [];
let stageSpriteYObj2 = [];		
let stageSpriteYpos2 = [];

// include libraries
#include "script/thdcs/functions/function_loaddata.txt"				// All textures
#include "script/thdcs/functions/function_common.txt"				// Commons
#include "script/thdcs/functions/function_global.txt"				// Global useful

#include "script/thdcs/stage/constructFairy.txt"					// Core script for stg enemies

#include "script/thdcs/stage/movementFairyStage01.txt"				// Identify and handle movement
#include "script/thdcs/stage/movementFairyStage02.txt"
#include "script/thdcs/stage/movementFairyStage03.txt"

#include "script/thdcs/stage/danmakuFairyStage01.txt"				// Shot patterns for fairies
#include "script/thdcs/stage/danmakuFairyStage02.txt"
#include "script/thdcs/stage/danmakuFairyStage03.txt"

#include "script/thdcs/stage/patternStage01.txt"					// Wave pattern / timings / etc
#include "script/thdcs/stage/patternStage02.txt"
#include "script/thdcs/stage/patternStage03.txt"

#include "script/thdcs/stage/constructMain.txt"						// Core stage look construct
#include "script/thdcs/stage/archiStage01.txt"						// Defines how everything is placed in stage
#include "script/thdcs/stage/constructStage01.txt"					// Functions and tasks for stage looks
#include "script/thdcs/stage/archiStage02.txt"
#include "script/thdcs/stage/constructStage02.txt"
#include "script/thdcs/stage/archiStage03.txt"
#include "script/thdcs/stage/constructStage03.txt"

#include "script/thdcs/system/shotlibrary.txt"						// Used for enemies in stages

//=======================================================================================================

SetCommonData("DanceContestStageID", GetOwnScriptID);			// used for EVENT_USER method

// initialize stuff
@Initialize {
	preStage;
}

@Event {
	if(GetEventType() == EV_USER+3000) {
        CloseStgScene;
	}
}

@MainLoop { yield; }
@Finalize { }

task preStage {
    StartItemScript("script/thdcs/functions/function_item.txt");

	SetAreaCommonData("game","PIV",10000);

	SetShotAutoDeleteClip(32,32,32,32);
	
	// Check whether this is a SPELL practise mode. If it is, load stage 0 (practise). Stage 1+ = regular
	// Stage 0 basically instantly loads required BG and the general PLURAL (spellpractise.txt)
	if(GetAreaCommonData("game", "menuFlow", 0) == 4) {
		SetPlayerLife(0);
		SetPlayerSpell(0);
		renderStage(0);	
	}
	// Replay mode 
	else if(GetAreaCommonData("game", "menuFlow", 0) == 5) {
		SetAreaCommonData("game", "difficulty", GetCommonData("replayDifficulty", 0));
		if(GetCommonData("replayMode","NULL") == "Spl Prac") { 
			SetAreaCommonData("game", "fightHina", true);
			SetAreaCommonData("game", "fightIku", true);
			SetAreaCommonData("game", "fightTewi", true);
		}

		renderStage(GetCommonData("replayStgIndex", 0));
	}	
	// Story mode, practise stage mode.
	else {  
		SetAreaCommonData("game", "cannotUnlock", 0);
		SetAreaCommonData("game", "fightHina", false);
		SetAreaCommonData("game", "fightIku", false);
		SetAreaCommonData("game", "fightTewi", false);

		if(GetAreaCommonData("game", "menuFlow", 0) == 3) {
		    SetPlayerLife(9);
		    SetPlayerSpell(3);
            SetCommonData("remainingContinues", 0);
        }
		else {
		    SetPlayerLife(3);
		    SetPlayerSpell(2);
		    SetCommonData("remainingContinues", 2);
        }

		renderStage(GetAreaCommonData("game", "stageNum", 1));    // Render stage based on commondata (in case practise was used)
	}

	renderCamera();	            // Camera and world cam behaviour
	stageHeartBeat();	        // 193 Heartbeat for player dying or stages being cleared/ended
    stageFinalizeHeartBeat();
}

//TODO: Contains debug text. Remove before release.
// 193 heartbeat for the stage to track player state.
task stageHeartBeat {
	loop {
		if(GetCommonData("stgReplayAbort", false)) { break; }

        // If the player goes pichuun, prevent STATE_END from kicking in by intercepting at '0' lives. Which is technically the last.
        // Note: this is in sync with the number of hearts drawn on the HUD.
        //       The HUD will make it look as if the player is on his/her last life.
		if(GetPlayerState == STATE_DOWN && GetPlayerLife == 0 && GetCommonData("remainingContinues", 0) > 0) {
		    let mainPackID = GetCommonData("mainPackID", 0);
            NotifyEventAll(EV_USER+2000, 0);

            SetCommonData("holdStageHeartBeat", true);

            while(GetCommonData("holdStageHeartBeat", false)) { yield; }

            SetPlayerLife(3);
		}

		// If the player is out of continues and is hit: deduct -1 life to sync number of hearts and making sure STATE_END kicks in
		if(GetPlayerState == STATE_DOWN && GetPlayerLife == 1 && GetCommonData("remainingContinues", 0) == 0) {
		    SetPlayerLife(GetPlayerLife - 1);
		}

		// Player is cut of lives and no more continues.
        if(GetPlayerState == STATE_END) {
            if(GetAreaCommonData("game","menuFlow",0) == 4) {
                SetCommonData("hasLostInSpellPractise", true);
            }
            CloseStgScene;
            break;
		}
		yield;
	}
}

task stageFinalizeHeartBeat {
    SetCommonData("stopStageHeartBeat", false);
    loop {
        if(GetCommonData("stopStageHeartBeat", false)) {
            break;
        }
        yield;
    }
    CloseStgScene;
}
	
// Task to scroll stage. Reads values from the two arrays.
task scrollStage {
	loop { 
		ascent(i in 0..length(stageSpriteObj)) {
			ObjRender_SetZ(stageSpriteObj[i], stageSpriteZpos[i]+f);
		}
		yield;	
	}
}

// Task to scroll stage. Reads values from the two arrays.
task scrollStageY {
	loop { 
		ascent(i in 0..length(stageSpriteYObj)) {
			ObjRender_SetY(stageSpriteYObj[i],stageSpriteYpos[i]-f);
		}
		ascent(i in 0..length(stageSpriteYObj2)) {
			ObjRender_SetY(stageSpriteYObj2[i],stageSpriteYpos2[i]-s/256);
		}		
		yield;	
	}
}

// Main render task
task renderStage(stage) {
	Reset2DCamera;		// Reset any possible 2D camera settings.
	scrollStage;		// Grand stage scrolling handler.
	
	// Enable fog for the game. Fog minimum, maximum and colours are handled in threads. 
	SetFogEnable(true);
	
	//------------------------------------------------------------------------------------------------------------------------------------------
	// Stage 0 - the SPELL practise global stage.
	if(stage == 0) {
		SetAreaCommonData("game","stageNum",0);
		SetAreaCommonData("game","feverpoint",0);
		
		if(GetCommonData("tryStage",0) == 0) {
			SetCameraPerspectiveClip(10,4096);

			if(GetCommonData("tryCard",0) < 1) { 
				PlayMusic(BGM_STG01);
				fogStart = 1600; fogEnd = 3000; 
				fogRed = 155; fogGreen = 25; fogBlue = 105;
				cameraShift = -128; cameraLift = 128; cameraZoom = -370; cameraTurn = 115; cameraTilt = 20; camRadius = 5;	
				buildBal01; stagelook = 1;	
				cameraSwitch = 2;					
			} else {
				PlayMusic(BGM_BOSS01);
				fogStart = 1600; fogEnd = 3000; 
				fogRed = 155; fogGreen = 25; fogBlue = 105;
				cameraShift = -128; cameraLift = 128; cameraZoom = -370; cameraTurn = 115; cameraTilt = 20; camRadius = 5;	
				buildBal01; stagelook = 1;	
				cameraSwitch = 2;				
			}
		}
		if(GetCommonData("tryStage",0) == 1) {
			SetCameraPerspectiveClip(10,8192);

			if(GetCommonData("tryCard",0) < 1) { 
				PlayMusic(BGM_STG02); 		
				fogStart = 400; fogEnd = 600;
				fogRed = 128; fogGreen = 96; fogBlue = 64;
				cameraShift = 0; cameraLift = 256; cameraZoom = 0; cameraTurn = 90; cameraTilt = 0; camRadius = 768;	
				buildAfro02; stagelook = 4;				
			} else {
				PlayMusic(BGM_BOSS02);
				fogStart = 4000; fogEnd = 6000;
				fogRed = 128; fogGreen = 96; fogBlue = 64;
				cameraShift = -256; cameraLift = 256; cameraZoom = 0; cameraTurn = -90; cameraTilt = 10; camRadius = 5;	
				buildAfro03; stagelook = 5;	
				cameraSwitch = 2;					
			}
		}
		if(GetCommonData("tryStage",0) == 2) {
			SetCameraPerspectiveClip(10,20000);

			if(GetCommonData("tryCard",0) < 2) {
				PlayMusic(BGM_STG03); 
				fogStart = 1; fogEnd = 2;
				fogRed = 30; fogGreen = 10; fogBlue = 10;	
				cameraShift = 0; cameraLift = 256; cameraZoom = -2560; cameraTurn = 90; cameraTilt = 15; camRadius = 5;
				f = 0; s = 0;
				buildDj03; stagelook = 9; cameraSwitch = 0;
			} else {
				PlayMusic(BGM_BOSS03); 
				fogStart = 1600; fogEnd = 4096;
				fogRed = 255; fogGreen = 64; fogBlue = 64;	
				f = 0; s = 0; 
				cameraShift = 0; cameraLift = 128; cameraZoom = 256; cameraTurn = 90; cameraTilt = 6; camRadius = 5; cameraRoll = 0;
				buildDj04; stagelook = 10;	
				updateDjStageFog; 	
				cameraSwitch = 3;					
			} 		
		}
		
		idScript = LoadScriptInThread("script/thdcs/stage/stage00/spellpractise.txt"); 
		StartScript(idScript);
		wait(60);
		
		while(!IsCloseScript(idScript) && GetPlayerState() != STATE_END) { yield; }	
		
		cleanupWorld;
		CloseStgScene;
	}
	
	//------------------------------------------------------------------------------------------------------------------------------------------
	// Stage 1 render
	if(stage == 1) { 
		SetCommonData("mainPlural", false);
		SetAreaCommonData("game", "stageNum", 1);
		SetAreaCommonData("game", "feverpoint", 0);
		if(!GetAreaCommonData("core", "practiseStg1", false)) { SetAreaCommonData("core", "practiseStg1", true); SaveCommonDataAreaA1("core"); }
		showCollectLine;
		
		SetCameraPerspectiveClip(10, 4096);

		// Indoor flight
		fogStart = 100; fogEnd = 300;
		cameraSwitch = 0;	
		fogRed = 155; fogGreen = 25; fogBlue = 105;
		cameraShift = -128; cameraLift = 128; cameraZoom = -370; cameraTurn = 180; cameraTilt = 20; camRadius = 5;	
		buildBal01; stagelook = 1;
		
		// music for stage 1
		adjustBGMVol(GetAreaCommonData("sound", "song", 0), GetAreaCommonData("system", "bgmvol", 100));
		PlayMusic(BGM_STG01);
		
		// Begin stage 1 execution
		wait(60);
		worldPlay01_0;
		worldPlay01_mid;
		worldPlay01_1;
	    worldPlay01_boss;

		StopMusic(GetAreaCommonData("sound", "song", 0));
        AddScore(calculateAndGetStageClearBonus());
        wait(120);
		stageSwitchFadeInOutEffect();
        wait(60);

		SaveCommonDataAreaA1("core");
		fogStart = 1; fogEnd = 2;		
		cleanupWorld;

		if(!IsReplay) { 
			if(GetAreaCommonData("game","menuFlow",0) == 3) { CloseStgScene; } 
			else { renderStage(2); } 	
		} else {
			if(GetCommonData("replayMode","NULL") == "Story") { 
				renderStage(2);
			}
			if(GetCommonData("replayMode","NULL") == "Stg Prac") { 
				CloseStgScene;
			}
		}
	}

	//------------------------------------------------------------------------------------------------------------------------------------------
	// Stage 2 render 
	if(stage == 2) { 
		SetCommonData("mainPlural", false);
		SetAreaCommonData("game", "stageNum", 2);
		SetAreaCommonData("game", "feverpoint", 0);
		if(!GetAreaCommonData("core","practiseStg2",false)) { SetAreaCommonData("core","practiseStg2",true); SaveCommonDataAreaA1("core"); } 
		
		SetCameraPerspectiveClip(10, 8192);
		
		// Lobby indoor
		fogStart = 1600; fogEnd = 4800;
		cameraShift = 768; cameraLift = 256; cameraZoom = 256; cameraTurn = 65; cameraTilt = 15; camRadius = 256;
		buildAfro01; stagelook = 3;
		
		// music for stage 2 
		PlayMusic(BGM_STG02);
		
		// Begin stage 2 execution
		wait(60);
		worldPlay02_0;
	    worldPlay02_mid;
		worldPlay02_1;
		worldPlay02_boss;
		
		StopMusic(GetAreaCommonData("sound", "song", 0));
		AddScore(calculateAndGetStageClearBonus());
        wait(120);
		stageSwitchFadeInOutEffect();
        wait(60);

		SaveCommonDataAreaA1("core");
		fogStart = 1; fogEnd = 2;	
		cleanupWorld;
		
		if(!IsReplay) { 
			if(GetAreaCommonData("game","menuFlow",0) == 3) { CloseStgScene; } 
			else { renderStage(3); } 	
		}
		else {
			if(GetCommonData("replayMode","NULL") == "Story") { 
				renderStage(3);
			}
			if(GetCommonData("replayMode","NULL") == "Stg Prac") { 
				CloseStgScene;
			}
		}
	}
	//------------------------------------------------------------------------------------------------------------------------------------------
	// Stage 3 render
	if(stage == 3) { 
		SetCommonData("mainPlural", false);
		SetAreaCommonData("game", "stageNum", 3);
		SetAreaCommonData("game", "feverpoint", 0);
		if(!GetAreaCommonData("core", "practiseStg3", false)) { SetAreaCommonData("core","practiseStg3",true); SaveCommonDataAreaA1("core"); }
		
		SetCameraPerspectiveClip(10, 20000);

		// Sky flight
		fogStart = 1000; fogEnd = 2000;
		fogRed = 10; fogGreen = 5; fogBlue = 5;	
		cameraShift = 0; cameraLift = 0; cameraZoom = -640; cameraTurn = 91; cameraTilt = 180; camRadius = 5;	// top view
		buildDj01; stagelook = 6;
		
		// music for stage 3
		PlayMusic(BGM_STG03);
		
		// Begin stage 3 execution
		wait(60);
		worldPlay03_0;
		worldPlay03_1;
		worldPlay03_mid1;
		worldPlay03_mid2;
		worldPlay03_boss;
		wait(90);

		if(GetPlayerState != STATE_END && GetAreaCommonData("game","menuFlow",0) == 0) { fadeEndScreen; fadeEndScreen; }
		StopMusic(GetAreaCommonData("sound","song",0));
		AddScore(calculateAndGetStageClearBonus());
		AddScore(calculateAndGetGameClearBonus());
		SaveCommonDataAreaA1("core");
		cleanupWorld;
        wait(60);
		
		if(!IsReplay) { 
			if(GetAreaCommonData("game","menuFlow",0) == 3) { CloseStgScene; } 
			else { CloseStgScene; } 	
		}
		else {
			if(GetCommonData("replayMode","NULL") == "Story") { 
				CloseStgScene;
			}
			if(GetCommonData("replayMode","NULL") == "Stg Prac") { 
				CloseStgScene;
			}
		}
	}
}

//------------------------------------------------------------------------------------------------------------------------------------------
// Global handlers

// TODO: Move to another location + also research the brief choking/stagger when swapping stages
task stageSwitchFadeInOutEffect() {
    let obj = ObjPrim_Create(OBJ_SPRITE_2D);
    let effectSwitch = 0;
    let alpha = 0;

    Obj_SetRenderPriorityI(obj, 30);
    ObjPrim_SetTexture(obj, minitex);
    ObjRender_SetBlendType(obj, BLEND_ALPHA);
    ObjRender_SetAlpha(obj, alpha);
    ObjSprite2D_SetSourceRect(obj, 0, 0, 1024, 1024);
    ObjRender_SetScaleXYZ(obj, 1.0, 1.0, 0);
    ObjSprite2D_SetDestCenter(obj);
    ObjRender_SetColor(obj, 0, 0, 0);
    ObjRender_SetPosition(obj, GetCenterX, GetCenterY,0);

    loop(30) {
        alpha += 255/30;
        ObjRender_SetAlpha(obj,alpha);
        yield;
    }
    wait(60);
    loop(30) {
        alpha -= 255/30;
        ObjRender_SetAlpha(obj,alpha);
        yield;
    }
    Obj_Delete(obj);
}

//------------------------------------------------------------------------------------------------------------------------------------------
// Stage 1 handlers
// There are none. 

//------------------------------------------------------------------------------------------------------------------------------------------
// Stage 2 handlers

// task to update the colour of the wall 
task updateDownTownfog(obj,type) { 
	while(!Obj_IsDeleted(obj)) {
		if(type) { ObjSprite3D_SetSourceDestRect(obj,0+s*4,0+s*4,1024+s*4,1024+s*4); }
		if(!type) { ObjSprite3D_SetSourceDestRect(obj,0-s*2,0+s*2,1024-s*2,1024+s*2); }
		yield;
	}
} 

//------------------------------------------------------------------------------------------------------------------------------------------
// Stage 3 handlers

// task to update the colour of the wall. 
task updateDownTown(obj) { 
	let glow = 0;
	let glowFrame = 0;
	let baseAlpha = 0;
	wait(420);
	while(!Obj_IsDeleted(obj)) {
		// was 192 192 192 (toned down to avoid bullets blending with bg (too much glow))
		ObjRender_SetColor(obj, 168+glow, 168+glow, 168+glow);
		ObjRender_SetAlpha(obj, baseAlpha);
		
		// was 255
		if(baseAlpha < 205) { baseAlpha += 0.5; }
		ObjSprite3D_SetSourceDestRect(obj, 0, 0+s, 1024, 2048+s);
		glow = 200 * sin(glowFrame) / 4;
		glowFrame += 2;
		yield;
	}
} 

// task to scroll the overlay of the dome hall entry
task domeWallOverlayListener(obj) { 
	let alphaValue = 254;
	
	while(!Obj_IsDeleted(obj)) {
	
		ObjRender_SetAlpha(obj,alphaValue);
		alphaValue = 254*sin(s*8);
		yield;
	}
}

// task to update the spots of DJ room
task updateDjSpot(obj2,obj3,type) {
	if(type) { wait(45); }

	while(!Obj_IsDeleted(obj2)) {
		ObjRender_SetAlpha(obj2, 255);
		ObjRender_SetAlpha(obj3, 65);
		wait(45);
		
		ObjRender_SetAlpha(obj2, 0);
		ObjRender_SetAlpha(obj3, 0);
		wait(45);
		
		yield;
	}
}

// task to update the colour of the wall. 
task updateDjCrowd(obj,type) { 
	let crowdAnimationValue = 0;
	let crowdFrameCount = 0;
	
	if(type) { wait(60); }

	while(!Obj_IsDeleted(obj)) {
		crowdAnimationValue = 4 * sin(crowdFrameCount) / 3;
		crowdFrameCount += 8;
		ObjRender_SetY(obj,ObjRender_GetY(obj) + crowdAnimationValue);		
		yield;
	}
} 

// task to update the colour of the wall. 
task updateDjWallColour(obj) { 
	while(!Obj_IsDeleted(obj)) {
		ObjRender_SetColor(obj,fogRed, fogGreen, fogBlue);
		ObjSprite3D_SetSourceDestRect(obj,0+s,0,4096+s,512);
		yield;
	}
} 

// task to update the colour of the wall. 
task updateDjStageFog() {
	while(updateFog) {
		if(wallSwitchValue==0) { fogBlue++; if(fogBlue == 255) { wallSwitchValue = 1; } } 	//paars
		if(wallSwitchValue==1) { fogRed--; if(fogRed == 64) { wallSwitchValue = 2; } } 		//blauw
		if(wallSwitchValue==2) { fogGreen++; if(fogGreen == 255) { wallSwitchValue = 3; } } 	//mint
		if(wallSwitchValue==3) { fogBlue--; if(fogBlue == 64) { wallSwitchValue = 4; } } 	//groen
		if(wallSwitchValue==4) { fogRed++; if(fogRed == 255) { wallSwitchValue = 5; } } 		//oranje
		if(wallSwitchValue==5) { fogGreen--; if(fogGreen == 64) { wallSwitchValue = 0; } } 	//rood		
		yield;
	}
} 

//------------------------------------------------------------------------------------------------------------------------------------------
// Global handlers

// Global camera control for stages and stage flow. Holds debugging.	
task renderCamera { 
	loop {
		SetFogParam(fogStart,fogEnd,fogRed,fogGreen,fogBlue);
		
		// debug cam: debugCameraTilt, debugCameraTurn, debugCameraZoom, debugCameraShift, debugCameraLift. Hold C, release == reset
		/*
		if(GetVirtualKeyState(VK_USER1) == KEY_HOLD) { 
			if (GetVirtualKeyState(VK_LEFT) == KEY_HOLD) { debugCameraTurn--; }
			else if(GetVirtualKeyState(VK_RIGHT) == KEY_HOLD) { debugCameraTurn++; }
			else if(GetVirtualKeyState(VK_UP) == KEY_HOLD) { debugCameraTilt++;; }
			else if(GetVirtualKeyState(VK_DOWN) == KEY_HOLD) { debugCameraTilt--; }
			else if(GetVirtualKeyState(VK_SHOT) == KEY_HOLD) { f+=48; }
		}
		if(GetVirtualKeyState(VK_USER2) == KEY_HOLD) { 
			if (GetVirtualKeyState(VK_LEFT) == KEY_HOLD) { debugCameraShift+=8; }
			else if(GetVirtualKeyState(VK_RIGHT) == KEY_HOLD) { debugCameraShift-=8; }
			else if(GetVirtualKeyState(VK_UP) == KEY_HOLD) { debugCameraLift+=8; }
			else if(GetVirtualKeyState(VK_DOWN) == KEY_HOLD) { debugCameraLift-=8; }
		}		
		if(GetVirtualKeyState(VK_USER1) == KEY_PULL || GetVirtualKeyState(VK_USER2) == KEY_PULL) { 
			debugCameraTilt = 0; debugCameraTurn = 0; debugCameraZoom = 0; debugCameraShift = 0; debugCameraLift = 0;
		}
		*/
		// move the stage by mutating f
		//if(GetKeyState(KEY_T) == KEY_HOLD) { f+=40; }
		//if(GetKeyState(KEY_R) == KEY_PUSH) { f = 2048; }
		
		// Global camera control
		SetCameraFocusX(cameraShift + debugCameraShift);
		SetCameraFocusY(cameraLift + debugCameraLift);
		SetCameraFocusZ(cameraZoom);

		// Camera sways when the player moves around the field. Only able to be applied in certain sections
		if(stagelook == worldBalInside || stagelook == worldAfroInside || stagelook == worldAfroOutside || stagelook == worldDjCity) {
			SetCameraAzimuthAngle(cameraTurn - 8*sin((224-GetPlayerX)/3) + debugCameraTurn);
			SetCameraElevationAngle(cameraTilt + 10*sin((240-GetPlayerY)/3) + debugCameraTilt);
			SetCameraRoll(cameraRoll - 8*sin((224-GetPlayerX)/3)); 
		} 
		else { 
			SetCameraAzimuthAngle(cameraTurn + debugCameraTurn);
			SetCameraElevationAngle(cameraTilt + debugCameraTilt);
			SetCameraRoll(cameraRoll);
		}
		SetCameraRadius(camRadius + debugCameraZoom);	

		// Stage control and mutation of camera or behaviour
		alternative(stagelook) 
		case(worldBalInside) { 
			if(cameraSwitch == 1) {
				if(cameraTurn > 112) { cameraTurn-=0.2; } 
				if(cameraZoom < 256) { cameraZoom+=2; f+=2; } 
				if(cameraZoom == 256) { cameraSwitch = 2; } 
				f+=4;
			}
			if(cameraSwitch == 2) { 
				butterflySpotlightSpinValue += 1;
				f+=10;
				if(f > 2048) { f = 0; } 		
			} 
			butterflySpotlightSpinValue += 1;
		}
		case(worldAfroInside) { 
			cameraSwitch = 0;
			f+=24;
			if(f > 4096) { f = 0; }
		}
		case(worldAfroOutside) {
			f+=8;
			s+=6;
			cameraTurn+=0.3;
			if(cameraTilt > -15) { cameraTilt-=0.05; }
			if(f > 2048) { f = 0; } 
		}
		case(worldAfroBoss) {		
			if(cameraSwitch == 0) { cameraTilt+=0.5; cameraTurn-=0.5; cameraLift+=4; cameraZoom-=4; if(cameraTilt > 32 && cameraLift > 128) { cameraSwitch = 1; } }
			if(cameraSwitch == 1) { cameraLift--; cameraZoom-=4; cameraTurn--; cameraTilt-=0.1; if(cameraZoom == 0) { cameraSwitch = 2; } } 
			if(cameraSwitch == 2) { cameraTilt-=0.1; cameraTurn--; if(cameraTilt < 11) { cameraSwitch = 3; } } 
			if(cameraSwitch == 3) { cameraTurn-=0.1; }
			if(cameraSwitch == 4) { } 
		}		
		case(worldDjSky) {
			cameraSwitch = 0;
			s+=0.5;
		}
		case(worldDjCity) { 
			if(cameraSwitch == 0) { f+=48; }			// pre midboss speed
			if(cameraSwitch == 1) { f+=144; } 			// after first midboss speed
			if(f > 12288) { f = 0; } 
		}
		case(worldDjCity2) { 
			if(cameraSwitch == 0) { f+=48; }			// pre midboss speed
			if(cameraSwitch == 1) { f+=144; } 			// after first midboss speed
			if(f > 12288) { f = 0; } 
		}	
		case(worldDjCity3) { 	
			if(cameraSwitch == 0) { 
				cameraRoll = 0 + 8*sin(s/2)/1;
				cameraShift = 0 - 512*sin(s/3);
				cameraLift = 256 + 128*cos(s/4);
				cameraZoom = -2560 + 256*cos(s/3); 
				cameraTilt = 15 - 6*cos(s/4);
			}
			if(cameraSwitch == 1) { 
				if(cameraRoll > 0) { cameraRoll--; } 
				if(cameraShift > 0) { cameraShift-=4; } 
				if(cameraShift < 0) { cameraShift+=4; } 
				if(cameraLift > 256) { cameraLift--; } 
				if(cameraLift < 256) { cameraLift++; } 
			}
			s++;
		}
		case(worldDjBoss) {
			if(cameraSwitch == 0) { 
				cameraTurn = 90 + 16*cos(s/1); 
				if(f > 300) { 
					if(cameraTurn > 90) { cameraTurn-=2; } 
					if(cameraTurn < 90) { cameraTurn+=2; }
					if(cameraTurn == 90) { 
						cameraSwitch = 1; 
						f = 0;
					}
				} 
			} 
			if(cameraSwitch == 1) { if(cameraZoom > 512) { cameraZoom-=24; } if(f > 120) { cameraSwitch = 2; f = 0; } }
			if(cameraSwitch == 2) { if(cameraZoom < 620) { cameraZoom+=8; cameraLift+=4; } if(f > 120 && !GetCommonData("isDialogue",false)) { cameraSwitch = 3; f = 0; s = 0; } }
			if(cameraSwitch == 3) { cameraTurn = 90 + 128*sin(s/4)/1; cameraLift = 256 - 128*sin(s)/1; } 
		
			f++;
			s++;
		}
		yield;	
	}	
}

// Global cleanup for all sprites in arrays before moving to next stage or part. 
function cleanupWorld() {
	ascent(i in 0..length(stageSpriteObj)) {
		Obj_Delete(stageSpriteObj[i]);
	}
	ascent(i in 0..length(stageSpriteYObj)) {
		Obj_Delete(stageSpriteYObj[i]);
	}	
	ascent(i in 0..length(stageSpriteYObj2)) {
		Obj_Delete(stageSpriteYObj2[i]);
	}		
	ascent(i in 0..length(stageNonMoveObj)) {
		Obj_Delete(stageNonMoveObj[i]);
	}		
}

