/******************************************************************************************
	CRTEST PS   (c) 1999-2001 ISL

	lev_flow.c:			Level-to-level flow for the game
******************************************************************************************/

#include "global.h"

#include "map_play.h"
#include "card.h"
#include "menu.h"
#include "lev_flow.h"
#include "sound.h"
#include "demo.h"
#include "gametext.h"
#include "fma.h"
#include "dogchase.h"
#include "crate.h"
#include "credits.h"
#include "maths.h"

int gameCalledFrom = GAMECALLEDFROM_GAME;




// =============== Level Replays ======================
// Actually, all of these do the same thing:
// (reset the whole damn lot)

// Film reels, etc, are preserved.
// "gamePlayData" should be pointing at "gameReplayData" before calling here
void levflowResetGamePlay(int from_act)
{
	int i;
	int n_sprouts;
	char map_pieces[14];

// Things to preserve if we're not replaying an act
// sprouts
// map pieces

	n_sprouts = gamePlayData->sprouts_carried;
	for(i = 0; i < 14; i++)
	{
		map_pieces[i] = gamePlayData->map_pieces_got[i];
	}

	if(gameCalledFrom == GAMECALLEDFROM_REPLAY)
	{
		gamePlayData->sprouts_carried = 0;
	}

	for(i = 0; i < NUM_CHARACTER_INVS; i++)
	{
		currentInv = &gamePlayData->inventories[i];
		inventoryReset();
	}


// Things that it would be nice to keep from act to act during normal play
	if(gameCalledFrom != GAMECALLEDFROM_REPLAY)
	{
		gamePlayData->sprouts_carried = n_sprouts;
		for(i = 0; i < 14; i++)
		{
			gamePlayData->map_pieces_got[i] = map_pieces[i];
		}
	}
}

void levflowAct1FromOptions()
{
	sound_XA_Stop();
	levflowResetGamePlay(1);
	inventoryEnsureStreamBank(STREAMBANK_INVENTORYACT1);
	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_ACT1_INTRO,1);
	gamePlayData->time_act_started = gameSaveData.time_spent_playing;
	mapplayStart("A1_HUT17",1);
}
void levflowAct2FromOptions()
{
	sound_XA_Stop();
	levflowResetGamePlay(2);
	inventoryEnsureStreamBank(STREAMBANK_INVENTORYACT2);
	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_ACT2_INTRO,1);
	gamePlayData->time_act_started = gameSaveData.time_spent_playing;
	mapplayStart("A2_HUT17",1);
}
void levflowAct3FromOptions()
{
	sound_XA_Stop();
	levflowResetGamePlay(3);
	inventoryEnsureStreamBank(STREAMBANK_INVENTORYACT4);
	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_ACT4_INTRO,1);
	gamePlayData->time_act_started = gameSaveData.time_spent_playing;
	mapplayStart("A4_HUT17",1);
}

void levflowAct2FromDogchase(void)		// This is exactly the same as ...FromOptions()
{
	sound_XA_Stop();
	levflowResetGamePlay(2);
	inventoryEnsureStreamBank(STREAMBANK_INVENTORYACT2);
	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_ACT2_INTRO,1);
	gamePlayData->time_act_started = gameSaveData.time_spent_playing;
	mapplayStart("A2_HUT17",1);
}

// =============== Inter-level Splash ======================

enum
{
	LEVFLOW_SPLASH_ACT1_PREBOSS,
	LEVFLOW_SPLASH_ACT1_DONE,
	LEVFLOW_SPLASH_ACT2_PREBOSS,
	LEVFLOW_SPLASH_ACT2_DONE,
	LEVFLOW_SPLASH_ACT3_PREBOSS,
	LEVFLOW_SPLASH_ACT3_DONE,
};

char *splash_bg_names[] =
{
	"FRONTEND\\SPLASH\\NIGHT.TIM",		// Act1 Preboss
	"FRONTEND\\SPLASH\\ACT1.TIM",		// Act1 Done
	"FRONTEND\\SPLASH\\DAY.TIM",		// Act2 Preboss
	"FRONTEND\\SPLASH\\ACT2.TIM",		// Act2 done
	"FRONTEND\\SPLASH\\PANIC.TIM",		// Act3 preboss
	"FRONTEND\\SPLASH\\ROCKGING.TIM",	// Act3 done
	"FRONTEND\\SPLASH\\INSIDEHUT.TIM",
};


int levflow_splashnumber;
int levflow_menusel = 0;
int levflow_time_taken;

void levflowSplashCycle()
{
	optionsPhaseMenuRGB();

	if (pReadPad->debounce[0] & PAD_UP)
	{
		levflow_menusel--;
	}
	
	else if(pReadPad->debounce[0] & PAD_DOWN)
	{
		levflow_menusel++;
	}
	if(levflow_menusel > 1)
		levflow_menusel = 0;
	if(levflow_menusel < 0)
		levflow_menusel = 1;


	if(pReadPad->debounce[0] & PAD_CROSS)
	{
		switch(levflow_menusel)
		{
		case 0:
			cardSplashSaveStart();
			break;

		case 1:
			switch(levflow_splashnumber)
			{
			case LEVFLOW_SPLASH_ACT1_PREBOSS:
				levflowDogchaseStart();
				break;
			case LEVFLOW_SPLASH_ACT1_DONE:
	// Transfer direct to act 2
	//			optionsStart(OPTIONS_DOOR_START);
				levflowAct2FromDogchase();
				break;

			case LEVFLOW_SPLASH_ACT2_PREBOSS:
				levflowCogchaseStart();
				break;

			case LEVFLOW_SPLASH_ACT2_DONE:
	// Either dump you in Fowlers, or transfer direct to act 3
				optionsStart(OPTIONS_DOOR_START);
				break;

			case LEVFLOW_SPLASH_ACT3_PREBOSS:
				levflowFlymachineStart();
				break;

			case LEVFLOW_SPLASH_ACT3_DONE:
				creditsStart();
				break;
			}

			break;
		}

	}
}

// called during save
int levflowSplashDrawOnly()
{
	gametimerType time;
	drawBGTim();

	optionsAlphaRectangle(-240, -101, 480, 13, 0, 0x202020);
	fontPrintCentred(font, 0,-100, TEXTSTR(TEXTSTR_SPLASH_HEADING_A1BOSS + levflow_splashnumber),128,128,128);


	if(optionsAlphaMainMenuDraw(-80,160,0x003000))
	{
		optionsFramesToTimer(levflow_time_taken, &time);
		fontPrintRightAligned(font,30, -60, TEXTSTR(TEXTSTR_SPLASH_TIME_THIS_ACT), 128,128,64);
		optionsDrawTime(    &time, 50, -60, 128,128,128);



		return 1;
	}
	return 0;
}


#define SPLASH_MENU_Y (50)
void levflowSplashDraw()
{
	if(levflowSplashDrawOnly())
	{
		if(levflow_menusel == 0)
		{
			fontPrintCentred(font, 0,SPLASH_MENU_Y, TEXTSTR(TEXTSTR_OPTIONS_HEADING_SAVE),optionTextRGB,optionTextRGB,optionTextRGB);
			fontPrintCentred(font, 0,SPLASH_MENU_Y+20, TEXTSTR(TEXTSTR_MENU_CONTINUE),64,64,96);
		}
		else
		{
			fontPrintCentred(font, 0,SPLASH_MENU_Y, TEXTSTR(TEXTSTR_OPTIONS_HEADING_SAVE),64,64,96);
			fontPrintCentred(font, 0,SPLASH_MENU_Y+20, TEXTSTR(TEXTSTR_MENU_CONTINUE),optionTextRGB,optionTextRGB,optionTextRGB);
		}

	}


/*
	Well done! You completed Act X

Time Taken		xx:xx              	Best Time		xx:xx

			Chickens Saved		XX/XX

		Number of times captured	XX

			Press X to continue


*/

}

void levflowSplashSaveReturn()
{
	cycle_routine = levflowSplashCycle;
	draw_routine = levflowSplashDraw;
	DB("Return from save\n");

	levflow_menusel = 1;	// default to "continue" after "save"
}


void levflowSplashStart(int which)
{
	ULONG *tim;
	int time_taken;

	optionsAlphaMainMenuInit();
	menuopening=1;
	levflow_menusel = 0;


	levflow_splashnumber = which;

	// What music to play here...? Either the McBrief, or the congrats mission success one.

	sound_XA_Stop();


	tim=(ULONG *)fileLoad(splash_bg_names[which],0);
	if(tim)
	{
		uploadTimToVRAM(tim);
		FREE(tim);
	}

	time_taken = gameSaveData.time_spent_playing - gamePlayData->time_act_started;
	levflow_time_taken = time_taken;

	// See if we've beaten the best time for this particular act
	switch(levflow_splashnumber)
	{
		case 1:		// Act 1 completed
			if(levflow_time_taken<gameSaveData.best_times[TIME_ACT1])
				gameSaveData.best_times[TIME_ACT1] = levflow_time_taken;
			break;

		case 3:		// Act 2 completed
			if(levflow_time_taken<gameSaveData.best_times[TIME_ACT2])
				gameSaveData.best_times[TIME_ACT2] = levflow_time_taken;
			break;

		case 5:		// Act 3 completed
			if(levflow_time_taken<gameSaveData.best_times[TIME_ACT4])		// 4 == 3
				gameSaveData.best_times[TIME_ACT4] = levflow_time_taken;
			break;

		default:
			break;
	}

	cycle_routine = levflowSplashCycle;
	draw_routine = levflowSplashDraw;

}

// =============== Veneer routines for the Mannequin Dog Chase (Act 1 Boss) ======================
// (The parts of the act boss routines which can't be in overlays)
// This can't be in dogchase.c, because it does overlaying

void levflowDogchaseFromGame()
{
	levflowSplashStart(LEVFLOW_SPLASH_ACT1_PREBOSS);
}
void levflowDogchaseStart()
{
	sound_XA_Stop();

	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS1_INTRO,1);
	main_EnsureOverlay(ACT1_SUBGAME_OVERLAY);
	dogchaseStart();
}




// NB - CALLED FROM DOGCHASE. LEAVE ITS OVERLAY THERE WHEN WE EXIT!
void levflowDogchaseRestart()
{
	sound_XA_Stop();

	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS1_FAIL,1);
	main_EnsureOverlay(ACT1_SUBGAME_OVERLAY);
	dogchaseStart();
}

// NB - CALLED FROM DOGCHASE. LEAVE ITS OVERLAY THERE WHEN WE EXIT!
void levflowDogchaseFail()
{
	sound_XA_Stop();

	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS1_FAIL,1);
	main_EnsureOverlay(ACT1_SUBGAME_OVERLAY);	// Wasteful. But needed so it's there for returning to

	switch(gameCalledFrom)
	{
		case GAMECALLEDFROM_GAME:
			optionsStart(OPTIONS_BED_START);
			break;
		case GAMECALLEDFROM_REPLAY:
			optionsStart(OPTIONS_BOMB_START);
			break;
		case GAMECALLEDFROM_DEBUG:
		default:
			menuStart();
			break;
	}
}

// NB - CALLED FROM DOGCHASE. LEAVE ITS OVERLAY THERE WHEN WE EXIT!
void levflowDogchaseSuccess()
{

	sound_XA_Stop();

	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS1_DONE,1);
	main_EnsureOverlay(ACT1_SUBGAME_OVERLAY);	// Wasteful. But needed so it's there for returning to

	if(
		  !gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2]
		&& gameCalledFrom != GAMECALLEDFROM_DEBUG
		)
	{
		// This is THE FIRST TIME you've beaten the dogchase. No replays yet.
		// You've just cracked open act2, either by playing through, or by replaying
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] =  REPLAY_NOTBEATEN;
		levflowSplashStart(LEVFLOW_SPLASH_ACT1_DONE);
		return;
	}

	switch(gameCalledFrom)
	{
		case GAMECALLEDFROM_GAME:	// Played act2
			levflowSplashStart(LEVFLOW_SPLASH_ACT1_DONE);
			break;


		case GAMECALLEDFROM_REPLAY:	// Just replayed the dogchase
			optionsStart(OPTIONS_BOMB_START);
			break;

		case GAMECALLEDFROM_DEBUG:
		default:
			menuStart();
			break;
	}
}


// =============== Veneer routines for the Pie Machine Cog Chase (Act 2 Boss) ======================
void levflowResetInventory()
{
	int i;
	for(i = 1; i <= GNOME; i++)
	{
		if(inventoryCheckForItem(i))
		{
			inventoryRemoveItem(i);
			scenicInventoryNotification(i,SCENIC_INVENTORY_RESPOT);
		}
	}
}

void levflowFreeStreambank()
{
	if(streamed_bank)	// The boss chases are short of vram, so we need to ditch the inventory sprites for the duration...
	{
		textureUnloadBank(streamed_bank);
		streamed_bank = NULL;
	}
}

void levflowCheatAllVids()
{
	int i;
	for(i=0;i<NUM_MOVIES;i++)
	{
		gameSaveData.movies_available[i]=1;			// make none of them available
	}
	optionsStart(OPTIONS_DOOR_START);
}
void levflowCheatAllLevs()
{
	int i;
	for(i = 0; i < N_REPLAY_LEVELS; i++)
	{
		//This makes the door go to a1_coop1_n, but everything is available thru the bomb
		gameSaveData.levels_available[i] = REPLAY_NOTBEATEN;
	}
	optionsStart(OPTIONS_BOMB_START);
}
void levflowCheatEggs()
{
	mapplayStart(sLevelName,level_start_marker);
	gamePlayData->eggs_carried=6;

}

void levflowCheatToManniquin()
{
	gamePlayData->A1fmaStatus[SCENE1004].playedFlag=FMA_PLAYED;	// "You've done hut17, and know what the workhut's for"

	levflowResetInventory();

	inventoryPickUpItem(A1POLES);
	inventoryRemoveItem(A1POLES);

	inventoryPickUpItem(BOOTS);
	inventoryRemoveItem(BOOTS);

	inventoryPickUpItem(GLOVES);
	inventoryPickUpItem(NIGHTDRESS);

	mapplayStart("A1_WORKHUT1",0);
}

void levflowCheatToSeesaw()
{
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;

	if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2])
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] = REPLAY_NOTBEATEN;
	levflowResetInventory();
	inventoryPickUpItem(COOKING_WEIGHTS);
	mapplayStart("A2_WORKHUT3",0);
}

void levflowCheatToFireworks()
{
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;
	if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2])
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] = REPLAY_NOTBEATEN;
	levflowResetInventory();
	inventoryPickUpItem(MATCHES);
	inventoryPickUpItem(FIREWORKS);
	mapplayStart("A2_WORKHUT1",0);
}
void levflowCheatToCatapult()
{
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;
	if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2])
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] = REPLAY_NOTBEATEN;
	levflowResetInventory();

// Make believe we've already done the two big itms
	inventoryPickUpItem(PRAM_CHASSIS);
	inventoryRemoveItem(PRAM_CHASSIS);

	inventoryPickUpItem(BROKEN_LADDER);
	inventoryRemoveItem(BROKEN_LADDER);

// And be carrying the small ones
	inventoryPickUpItem(TENNIS_RACKET);
	inventoryPickUpItem(STRONG_CORD);

	mapplayStart("A2_WORKHUT2",0);
}

void levflowCheatToCogChase()
{
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;
	if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2])
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] = REPLAY_NOTBEATEN;
	gamePlayData->SubGameStates[SUBGAME_CATAPULT]  = REPLAY_BEATEN;
	gamePlayData->SubGameStates[SUBGAME_FIREWORKS] = REPLAY_BEATEN;
	gamePlayData->SubGameStates[SUBGAME_SEESAW]    = REPLAY_BEATEN;
	levflowCogchaseStart();
}



// Name = a2wh1 for fireworks
// Name = a2wh2 for catapult
// Name = a2wh3 for seesaw

// NB - CALLED FROM THE SUBGAMES (ie, this needs to leave the act2 overlay paged in)
void act2SubgameComplete(char *workhutname)
{
	int all_subs_beaten;

	all_subs_beaten =
		   gamePlayData->SubGameStates[SUBGAME_CATAPULT]  == REPLAY_BEATEN
		&& gamePlayData->SubGameStates[SUBGAME_FIREWORKS] == REPLAY_BEATEN
		&& gamePlayData->SubGameStates[SUBGAME_SEESAW]    == REPLAY_BEATEN;
// (ie, all beaten during this play / replay of subgame / replay of act2)

	switch(gameCalledFrom)
	{
		case GAMECALLEDFROM_REPLAY:
/*
			// We've completed a subgame by replaying it at Fowlers.
			// If we'd not opened up act2boss before, then open it, and play i, because we're carrying on with the game
			if(all_subs_beaten && !gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS])
			{
				gameCalledFrom = GAMECALLEDFROM_GAME;
				gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS] = REPLAY_NOTBEATEN;
				levflowSplashStart(LEVFLOW_SPLASH_ACT2_PREBOSS);
			}
			else
*/
			{
				// If the boss was already open, or we hadn't beaten all the subgames
				// then that was just an ordinary replay of a subgame, so go back to Fowler's
				optionsStart(OPTIONS_BOMB_START);
			}
			break;

		case GAMECALLEDFROM_GAME:
			if(all_subs_beaten)
			{
				// We've just finished act2, either by playing, or by replaying act2. Either way, go to the boss,
				// and if it's the first time, flag the boss as being available
				gameCalledFrom = GAMECALLEDFROM_GAME;
				if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS])
					gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS] = REPLAY_NOTBEATEN;
				levflowSplashStart(LEVFLOW_SPLASH_ACT2_PREBOSS);
			}
			else
			{
				// We ain't done all the subgames on this play/replay of act 2. Back to the workhut.
				mapplayStart(workhutname,0);
			}
			break;

		case GAMECALLEDFROM_DEBUG:
		default:
			menuStart();
			break;
	}
}


void levflowCogchaseFromGame()
{
	sound_XA_Stop();

	if(mapplay_next_marker == 0)	// Don't play the vid on respawns
	{
		main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
		video_PlayVid(MOVIENO_BOSS2_INTRO,1);
	}

	mapplayStart("A2_COGCHASE",mapplay_next_marker);	// pick up on the respawn point
}

void levflowCogchaseStart()
{
	sound_XA_Stop();
	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS2_INTRO,1);
	mapplayStart("A2_COGCHASE",0);
}

// called from mapplay
void levflowCogchaseSuccess()
{

	sound_XA_Stop();

	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS2_DONE,1);


	switch(gameCalledFrom)
	{
		case GAMECALLEDFROM_GAME:	// replayed act2
			gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS] = REPLAY_BEATEN;
			if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3])
				gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3] = REPLAY_NOTBEATEN;


			levflowSplashStart(LEVFLOW_SPLASH_ACT2_DONE);
			break;


		case GAMECALLEDFROM_REPLAY:	// Just replayed the cogchase
/*
			if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3])
			{
				// If we'd not completed it before, then continue the game
				gameCalledFrom = GAMECALLEDFROM_GAME;
				gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS] = REPLAY_BEATEN;
				gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3] = REPLAY_NOTBEATEN;

				levflowSplashStart(LEVFLOW_SPLASH_ACT2_DONE);
			}
			else
*/
			{
				// Otherwise, go back to the level select.
				optionsStart(OPTIONS_BOMB_START);
			}
			break;

		case GAMECALLEDFROM_DEBUG:
		default:
			menuStart();
			break;
	}
}


// =============== Veneer routines for the Flying Machine (Act 3 Boss) ======================

void levflowCheatToEngine()
{
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS] = REPLAY_BEATEN;

	if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3])
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3] = REPLAY_NOTBEATEN;
	levflowResetInventory();
	inventoryPickUpItem(OIL_CAN);
	inventoryPickUpItem(CHAIN);
	gamePlayData->inventory_item_status[ENGINE]=INV_STATUS_REMOVED;
	mapplayStart("A4_WORKHUT2",0);
}
void levflowCheatToWings()
{
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS] = REPLAY_BEATEN;

	if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3])
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3] = REPLAY_NOTBEATEN;
	levflowResetInventory();
	inventoryPickUpItem(LAUNDRY);
	inventoryPickUpItem(YARN);
	inventoryPickUpItem(A4POLES);
	mapplayStart("A4_WORKHUT3",0);
}
void levflowCheatToConstruct()
{
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS] = REPLAY_BEATEN;

	if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3])
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3] = REPLAY_NOTBEATEN;
	levflowResetInventory();
	inventoryPickUpItem(COGS);
	inventoryPickUpItem(BINOCULARS);
	inventoryPickUpItem(TOOLS);
	inventoryPickUpItem(WOOD);
	mapplayStart("A4_WORKHUT4",0);
}
void levflowCheatToCrate()
{
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1BOSS] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2] = REPLAY_BEATEN;
	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT2BOSS] = REPLAY_BEATEN;

	if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3])
		gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3] = REPLAY_NOTBEATEN;
	gamePlayData->SubGameStates[SUBGAME_CATAPULT]  = REPLAY_BEATEN;
	gamePlayData->SubGameStates[SUBGAME_FIREWORKS] = REPLAY_BEATEN;
	gamePlayData->SubGameStates[SUBGAME_SEESAW]    = REPLAY_BEATEN;
	gamePlayData->SubGameStates[SUBGAME_CONSTRUCT] = REPLAY_BEATEN;
	gamePlayData->SubGameStates[SUBGAME_ENGINE]    = REPLAY_BEATEN;
	gamePlayData->SubGameStates[SUBGAME_WINGS]     = REPLAY_BEATEN;
	levflowFlymachineStart();
}

// Name = a4wh2 for engine
// Name = a4wh3 for wings
// Name = a4wh4 for construct

void act4SubgameComplete(char *workhutname)
{
	int all_subs_beaten;

	all_subs_beaten =
		   gamePlayData->SubGameStates[SUBGAME_CONSTRUCT] == REPLAY_BEATEN
		&& gamePlayData->SubGameStates[SUBGAME_ENGINE]    == REPLAY_BEATEN
		&& gamePlayData->SubGameStates[SUBGAME_WINGS]     == REPLAY_BEATEN;

	switch(gameCalledFrom)
	{
		case GAMECALLEDFROM_REPLAY:
/*
			if(all_subs_beaten && !gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3BOSS])
			{
			// We've completed a subgame by replaying it at Fowlers.
			// If we'd not opened up act3boss before, then open it, and play it, because we're carrying on with the game
				gameCalledFrom = GAMECALLEDFROM_GAME;
				gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3BOSS] = REPLAY_NOTBEATEN;
				levflowSplashStart(LEVFLOW_SPLASH_ACT3_PREBOSS);
			}
			else
*/
			{
				// If the boss was already open, or we hadn't beaten all the subgames
				// then that was just an ordinary replay of a subgame, so go back to Fowler's
				optionsStart(OPTIONS_BOMB_START);
			}
			break;

		case GAMECALLEDFROM_GAME:
			if(all_subs_beaten)
			{
				// We've just finished act3, either by playing, or by replaying act3. Either way, go to the boss,
				// and if it's the first time, flag the boss as being available
				gameCalledFrom = GAMECALLEDFROM_GAME;
				if(!gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3BOSS])
					gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3BOSS] = REPLAY_NOTBEATEN;
				levflowSplashStart(LEVFLOW_SPLASH_ACT3_PREBOSS);
			}
			else
			{
				mapplayStart(workhutname,0);
			}
			break;

		case GAMECALLEDFROM_DEBUG:
		default:
			menuStart();
			break;

	}
}



void levflowFlymachineFromGame()
{
	sound_XA_Stop();
	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS4_INTRO,1);
	main_EnsureOverlay(ACT4_SUBGAME_OVERLAY);
	levflowFreeStreambank();
	crateStart();
}

void levflowFlymachineStart()
{
	sound_XA_Stop();
	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS4_INTRO,1);
	main_EnsureOverlay(ACT4_SUBGAME_OVERLAY);
	levflowFreeStreambank();
	crateStart();
}

// CALLED FROM WITHIN THE A4 SUBGAME OVERLAY
void levflowCrateSuccess()
{
	sound_XA_Stop();

	main_EnsureOverlay(VIDEO_PLAYING_OVERLAY);
	video_PlayVid(MOVIENO_BOSS4_DONE,1);
	main_EnsureOverlay(ACT4_SUBGAME_OVERLAY);	// coz we've been called from there


	switch(gameCalledFrom)
	{
		case GAMECALLEDFROM_GAME:	// replayed act4
			gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3BOSS] = REPLAY_BEATEN;

			levflowSplashStart(LEVFLOW_SPLASH_ACT3_DONE);
			break;


		case GAMECALLEDFROM_REPLAY:	// Just replayed the crate
/*
			if(gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3BOSS] != REPLAY_BEATEN)
			{
				// If we'd not completed it before, then finish the game
				gameCalledFrom = GAMECALLEDFROM_GAME;
				gameSaveData.levels_available[REPLAY_AVAILABLE_ACT3BOSS] = REPLAY_BEATEN;

				levflowSplashStart(LEVFLOW_SPLASH_ACT3_DONE);
			}
			else
*/
			{
				// Otherwise, go back to the level select.
				optionsStart(OPTIONS_BOMB_START);
			}
			break;

		case GAMECALLEDFROM_DEBUG:
		default:
			menuStart();
			break;
	}
}



