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

 Having blank functions (or copies of functions) for everything that "never happens" on the OPSM demo version
 saves a hell of a lot of "#ifdefs" littering the game code, and thus
 makes it less likely that I'll mess the game up in producing the demo. Hurrah!

******************************************************************************************/


//#define GAME_SHOW_DEMO
#include "global.h"
#include "main.h"
#include "menu.h"
#include "map_draw.h"
#include "bff_load.h"
#include "debris.h"
#include "lights.h"
#include "timer.h"
#include "maths.h"
#include "overlays.h"
#include "map_view.h"
#include "global.h"
#include <psitypes.h>
#include "options.h"
#include "gallery.h"
#include "scenics.h"
#include "overlays.h"
#include "pad.h"
#include "gametext.h"
#include "card.h"
#include "demo.h"
#include "loadsnd.h"
#include "inventory.h"
#include "puzzles.h"
#include "wings.h"
#include "sound.h"
#include "charactr.h"
#include "credits.h"
#include "map_play.h"
#include "seesaw.h"
#include "catapult.h"
#include "fireworks.h"
#include "engine.h"
#include "construct.h"
#include "egglaying.h"
#include <isltex.h>
#include "fma.h"
#include "lev_flow.h"
#include "card.h"
#include "startup.h"
void levflowResetGamePlay(int from_act);

extern UBYTE	quitMainLoop;	// it's in main.c

int demoshell_leaving = 0;


// ============================ BRAND SPANKING NEW FUNCTIONS ===================================





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

#define N_ENDING_SPLASHES 3

// Run through some splash screens, then quit
#ifdef _WINDOWS
char *demo_ending_names[] = 
{
	"FRONTEND\\SPLASH\\1.BMP",
	"FRONTEND\\SPLASH\\2.BMP",
	"FRONTEND\\SPLASH\\3.BMP",
	"FRONTEND\\SPLASH\\4.BMP",
	"FRONTEND\\SPLASH\\5.BMP",
	"FRONTEND\\SPLASH\\6.BMP",
	"FRONTEND\\SPLASH\\7.BMP"
};
#else
char *demo_ending_names[] = 
{
	"FRONTEND\\SPLASH\\1.TIM",
	"FRONTEND\\SPLASH\\2.TIM",
	"FRONTEND\\SPLASH\\3.TIM",
	"FRONTEND\\SPLASH\\4.TIM",
	"FRONTEND\\SPLASH\\5.TIM",
	"FRONTEND\\SPLASH\\6.TIM",
	"FRONTEND\\SPLASH\\7.TIM"
};
#endif

enum
{
	DEMO_QUIT_SPLASH1,
	DEMO_QUIT_SPLASH2,
	DEMO_QUIT_SPLASH3,
	DEMO_QUIT_SPLASH4,

	DEMO_INTRO_SPLASH,
	DEMO_COMPLETE_SPLASH
};

int demo_ending_countdown;
int demo_ending_piccy;


void demoEndingSplashload()
{
#ifdef DREAMCAST
		dcTim_Load(&testTim,demo_ending_names[demo_ending_piccy]);
#endif
#ifdef _WINDOWS
	LoadBackdrop1 ( demo_ending_names[demo_ending_piccy]);
#else
  #ifndef DREAMCAST
		ULONG *tim;
		tim=(ULONG *)fileLoad(demo_ending_names[demo_ending_piccy],0);
		uploadTimToVRAM(tim);
		FREE(tim);
  #endif
#endif

	demo_ending_countdown = FRAMESEC * 3;
	demo_ending_piccy++;
}



void demoEndingDraw()
{
#ifdef _WINDOWS
	DrawBackdrop();
#else
	drawBGTim();
#endif

}
void demoEndingCycle()
{
	demo_ending_countdown--;
	if(demo_ending_countdown < 0 || (padData.debounce[0] & PAD_CROSS))
	{
		if(demo_ending_piccy >= DEMO_QUIT_SPLASH4)
		{
			quitMainLoop = 1;	// Back out to the shell. Phew. We should do some tidying, remember.
		}
		else
		{
			demoEndingSplashload();
		}
	}
}

void demostubFinished()
{
	demoshell_leaving = 1;
	sound_XA_Stop();
	draw_routine = demoEndingDraw;
	cycle_routine = demoEndingCycle;
	demo_ending_piccy = DEMO_QUIT_SPLASH1;
	demoEndingSplashload();

}


// The pause menu calls "startupstart" when you ask to quit. So let's quit
void startupStart()
{
	demostubFinished();
}

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

void demostubToGame()
{
// Copied from optionsEndToGame()

	gameCalledFrom = GAMECALLEDFROM_GAME;
	subgameCalledFrom = GAMECALLEDFROM_GAME;

// Copied from 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;
	subgameCalledFrom = GAMECALLEDFROM_GAME;
	mapplayStart("A1_HUT17",1);

}

void demoIntroCycle()
{
	demo_ending_countdown--;
	if(demo_ending_countdown < 0 || (padData.debounce[0] & PAD_CROSS))
	{
		demostubToGame();
	}
}

void demostubIntroStart()
{
	sound_XA_Stop();
	draw_routine = demoEndingDraw;
	cycle_routine = demoIntroCycle;

	demo_ending_piccy = DEMO_INTRO_SPLASH;
	demoEndingSplashload();

}

// This is where the startup menu goes to
void demostubStart()
{
	//demostubToGame();
	demostubIntroStart();
}




void demoCompleteCycle()
{
	demo_ending_countdown--;
	if(demo_ending_countdown < 0 || (padData.debounce[0] & PAD_CROSS))
	{
		demostubFinished();
	}
}

void demostubCompleteStart()
{
	demoshell_leaving = 1;
	sound_XA_Stop();
	draw_routine = demoEndingDraw;
	cycle_routine = demoCompleteCycle;

	demo_ending_piccy = DEMO_COMPLETE_SPLASH;
	demoEndingSplashload();

}



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

// Having blank functions for everything that "never happens" on the OPSM demo version
// saves a hell of a lot of "#ifdefs" littering the game code, and thus
// makes it less likely that I'll mess the game up in producing the demo

void catapultExit() {}
void seesawExit()	{}
void egglayingExit()	{}
void crateExit()	{}
void dogchaseExit()	{}
void engineExit()	{}
void wingExit()	{}
void constructExit()	{}

void catapultRestart() {}
void seesawRestart()	{}
void egglayingRestart()	{}
void crateRestart()	{}
void dogchaseRestart()	{}
void engineRestart()	{}
void wingRestart()	{}
void constructRestart()	{}

void catapultFree() {}
void seesawFree()	{}
void egglayingFree()	{}
void crateFree()	{}
void dogchaseFree()	{}
void engineFree()	{}
void wingFree()	{}
void constructFree()	{}

void dogchaseStart()	{}
void crateStart()	{}
void engineStart()	{}
void seesawStart()	{}
void wingStart()	{}
void catapultStart()	{}
void constructStart()	{}
void elStart()	{}
void levflowSplashStart()	{}

void psiFixupPrims(PSIMODEL *psiModel) {}
void oldPsiRenderer(PSIDATA *psiData) {}
long psiCRCName(char *psiName)	{ return 0; }
void menuDraw()	{}

void video_PlayVid(int n, int make_avail)	{}


void levflowDogchaseFromGame()	{}
//seesawStart
//catapultStart
//fireworksStart
void levflowCogchaseFromGame()	{}
void levflowCogchaseSuccess()	{}

//engineStart
//constructStart
//wingStart
void elStart4()	{}
void elStart2()	{}
void elStart1()	{}

void levflowCheatToManniquin()	{}
void levflowCheatToCatapult()	{}
void levflowCheatToFireworks()	{}
void levflowCheatToSeesaw()	{}
void levflowCheatToCogChase()	{}
void levflowCheatToConstruct()	{}
void levflowCheatToEngine()	{}
void levflowCheatToWings()	{}
void levflowCheatToCrate()	{}
void levflowCheatAllVids()	{}
void levflowCheatAllLevs()	{}
void levflowCheatEggs()	{}

void optionsDrawTimeSmall(gametimerType *timetoprint, int x, int y, int r, int g, int b) {}
void optionsFramesToTimer (int timeinframes, gametimerType *timer) {}


void curtainsInitialise(void)	{}
void curtainsRemoveRatFromRopes(CHARACTER *pC)	{}
void curtainsRatOnRope(CHARACTER *pC, SCENIC *pRope)	{}
int curtainsMain(void)	{return 0;}


// =========== Copies of individual functions that we still need from the main source ============



// ============================ OPTIONS.C ===================================
OPTIONDATASTR optionData;

void optionsHitOptions(int which)
{
	if(which & OPTIONS_HIT_SCREEN_POS)
	{
		displayPage[0].dispenv.screen.x = displayPage[1].dispenv.screen.x = optionData.screen.offset_x;
		displayPage[0].dispenv.screen.y = displayPage[1].dispenv.screen.y = optionData.screen.offset_y;
	}
	if(which & OPTIONS_HIT_SHOCKENABLE)
	{
		pReadPad->shockEnable = optionData.control.vibration;
	}

	if(which & OPTIONS_HIT_SFX_VOL)
	{
		sfxSetGlobalVolume(optionData.sound.sfxvol);	// the sfxglobalvolume is 0...0xffff
	}

	if(which & OPTIONS_HIT_MUSIC_VOL)
	{
//		SpuSetCommonCDVolume(optionData.sound.musicvol);
		sound_XA_VolRefresh();
	}

	if(which & OPTIONS_HIT_CONTROL_METHOD)
	{
		controlMap = optionData.control.method;
	}
}


void optionsResetAllToDefaults(void)
{
	optionData.control.vibration=0;	// disable vibration by default
#ifdef DREAMCAST	
	if(soundMode == SYD_CFG_STEREO)
		optionData.sound.stereo = TRUE;
	else
		optionData.sound.stereo = FALSE;
#else
	optionData.sound.stereo = 1;			// enable stereo by default
#endif
	optionData.sound.sfxvol = 128;			// the SFX volume
	optionData.sound.speechvol = 128;		// the speech volume
	optionData.sound.musicvol = 128;		// the music volume

#if PALMODE==1
	optionData.screen.offset_x = 2;
	optionData.screen.offset_y = 18;
#else
	optionData.screen.offset_x = 0;
	optionData.screen.offset_y = 3;
#endif

	optionsHitOptions(OPTIONS_HIT_ALL);
}

void optionsDrawBoxOutline(int x, int y, int w, int h, unsigned int colour)
{
	overlayLine(x,y,x+w,y,colour);			// top
	overlayLine(x+w,y,x+w,y+h,colour);		// right
	overlayLine(x,y+h,x+w,y+h,colour);		// bottom
	overlayLine(x,y,x,y+h,colour);			// left
}




unsigned char optionstate;

// (Acutally, I've locked "startup" only to have the one entry now)
void optionsStart(int mode)
{
	demostubStart();
}

void cardFowlerLoadStart()
{
	demostubStart();
}

void menuStart2()
{
	demostubStart();
}


// ============================ CARD.C ===================================

GameSaveDataType gameSaveData;
// For use during replays of acts. Not saved to card.
GamePlayDataType gamePlayDataMain;
// Points to either the replay one, or to the current one inside the savedata.
GamePlayDataType *gamePlayData = &gamePlayDataMain;


#if(PALMODE==YES)
	int INIT_DOGCHASE_BEST = 7500;
	int INIT_COGCHASE_BEST = 7500;
	int INIT_ACT1_BEST = (30*60*25);
	int INIT_ACT2_BEST = (90*60*25);
	int INIT_ACT3_BEST = (120*60*25);
#else
	int INIT_DOGCHASE_BEST = 9000;
	int INIT_COGCHASE_BEST = 9000;
	int INIT_ACT1_BEST = (30*60*30);
	int INIT_ACT2_BEST = (90*60*30);
	int INIT_ACT3_BEST = (120*60*30);
#endif

void cardInitialPrefs(OPTIONDATASTR *data)
{
	FMEMZERO(data,sizeof(OPTIONDATASTR));
	optionsResetAllToDefaults();

	optionsHitOptions(OPTIONS_HIT_ALL);	// actually called by "resetalltodefaults", but better safe than sorry

}

// initialise anything that's non-zero
void cardInitialGameState()	//GameSaveDataType *data)
{
	int i;
	GameSaveDataType *data = &gameSaveData;

#ifdef DEBUG
	if(sizeof(CARD_SAVE_STR) > MAX_SAVE_SIZE)
	{
		DB("card save str is %d. Too big - should be <= %d\n",sizeof(CARD_SAVE_STR),MAX_SAVE_SIZE);
	}
	ASSERT(sizeof(CARD_SAVE_STR) <= MAX_SAVE_SIZE);
#endif

	FMEMZERO(data,sizeof(GameSaveDataType));
	FMEMZERO(gamePlayData,sizeof(GamePlayDataType));

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

	gamePlayData->map_pieces_got[8] = 1;	// Always got the first map piece
	gameSaveData.movies_available[0]=1;	// RFW - Make the game intro available

	gameSaveData.levels_available[REPLAY_AVAILABLE_ACT1] = REPLAY_NOTBEATEN;

	gameSaveData.best_times[TIME_DOGCHASE] = INIT_DOGCHASE_BEST;		// Lets make it 5 minutes...
	gameSaveData.best_times[TIME_COGCHASE] = INIT_COGCHASE_BEST;		// Lets make it 5 minutes...
	gameSaveData.best_times[TIME_ACT1] = INIT_ACT1_BEST;		// Lets make it 30 minutes...
	gameSaveData.best_times[TIME_ACT2] = INIT_ACT2_BEST;		// Lets make it 90 minutes...
	gameSaveData.best_times[TIME_ACT4] = INIT_ACT3_BEST;		// Lets make it 120 minutes...


	gameSaveData.current_lev = options_returnlevel = LEVNUMBER_A1_HUT17;

	currentInv = &gamePlayData->inventories[INVNO_GINGER];

#ifdef GAME_SHOW_DEMO
	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_BEATEN;	//REPLAY_NOTBEATEN;
	}
	for(i=0;i<NUM_MOVIES;i++)
	{
		gameSaveData.movies_available[i]=1;
	}
	for(i=0;i<10; i++)	// NUM_STILLS
	{
		gameSaveData.stills_available[i]=1;
	}
	gameSaveData.blitz_games_internal = 1;
#endif

#if (EIDOS_DEBUG_STUFF==1) || (defined DEBUG )
	gameSaveData.blitz_games_internal = 1;	// allow use of the debug menu on Eidos test burns, and on devkits (Turn back off during saves).
#endif

}


SfxSampleType *cardmenusfx1;
SfxSampleType *cardmenusfx2;
SfxSampleType *cardmenusfx3;
char cardmenusfxset;
int cardmenusfx_pitch1;
int cardmenusfx_pitch2;
int cardmenusfx_pitch3;
int cardmenusfx_vol1;
int cardmenusfx_vol2;
int cardmenusfx_vol3;

void cardFindMenuSfx(int set)
{
	cardmenusfxset = set;
	if(!set)
	{
		// Generic (inventory) samples
		cardmenusfx1 = sfxFindSampleInAllBanks("bleep4");
		cardmenusfx2 = sfxFindSampleInAllBanks("clik4");
		cardmenusfx3 = sfxFindSampleInAllBanks("clik3");

		cardmenusfx_pitch1 = 800;
		cardmenusfx_pitch2 = 800;
		cardmenusfx_pitch3 = 800;
		cardmenusfx_vol1 = 0x8888;
		cardmenusfx_vol2 = 0x8888;
		cardmenusfx_vol3 = 0xffff;
		DB("SFX (Generic Set) FOUND\n");
	}
	else
	{
		// MainMenu samples
		cardmenusfx1 = sfxFindSampleInAllBanks("clik1");	// go
		cardmenusfx2 = sfxFindSampleInAllBanks("clik1");	// cancl
		cardmenusfx3 = sfxFindSampleInAllBanks("clik2");	// sel
		cardmenusfx_pitch1 = 1000;
		cardmenusfx_pitch2 = 1000;
		cardmenusfx_pitch3 = 1000;
		cardmenusfx_vol1 = 0xffff;
		cardmenusfx_vol2 = 0xffff;
		cardmenusfx_vol3 = 0xffff;
		DB("SFX (Menu Set) FOUND\n");
	}
	ASSERT (cardmenusfx1 && cardmenusfx2 && cardmenusfx3);
}

void cardPostLangStart()
{
// Initial prefs/state are done in "main"
	startupContinue();
}


// ============================ LEV_FLOW.C ===================================

int cogchase_start_time;
int gameCalledFrom = GAMECALLEDFROM_GAME;
int subgameCalledFrom = GAMECALLEDFROM_GAME;

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];
	}

	// zero out the gameplay variables so you can replay stuff
	memset(gamePlayData,0,sizeof(GamePlayDataType));



	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
// Now restore anything that needs restoring



#ifdef ZERO_SPROUTS_ON_REPLAY
	if(gameCalledFrom != GAMECALLEDFROM_REPLAY)
#endif
	{
		gamePlayData->sprouts_carried = n_sprouts;
		for(i = 0; i < 14; i++)
		{
			gamePlayData->map_pieces_got[i] = map_pieces[i];
		}
	}
}


void act2SubgameComplete(char *workhutname)
{
//	act2SubgameComplete("A2_WORKHUT1");

// The 4-minute timeout makes a replay impossible anyway. Shame

	if(gamePlayData->SubGameStates[SUBGAME_FIREWORKS] == REPLAY_BEATEN)
	{
		demostubCompleteStart();
	}
	else
	{
		demostubFinished();
	}
}


// ============================ SOUND.C (called from main, so alternative f'ns dead easy) ===================================

#define NUMBEROF8TRACKXA 3
#define NUMBER_OF_FMA_TRACKS (24)
#define N_XA_TRACKS (NUMBEROF8TRACKXA + NUMBER_OF_FMA_TRACKS)
extern XAFileType ref_music[N_XA_TRACKS];

void sound_DemoXAInit()
{
	int i;
	XAFileType *music;

	FMEMZERO(&ref_music,N_XA_TRACKS * sizeof(XAFileType));

//	for(i = 0; i < N_XA_TRACKS; i++)
	for(i = 0; i < NUMBEROF8TRACKXA; i++)
	{
		if(XAgetStatus())
		{
//			music = XAgetFileInfo(xa_file_names[i]);	// the ";1" is added internally
			music = NULL;
			if(music)
			{
				ref_music[i] = *music;
				FREE(music);
			}
		}
	}
}

void sound_XA_FindDemoLangFiles(int lang)
{
	char fname[40];
	int i;
	XAFileType *music;

	for(i = 0; i < NUMBER_OF_FMA_TRACKS; i++)
	{
		// (1,2,3,4,5, 23,24) Don't forget the -1
		if(i == 5)
			i = 22;

		sprintf(fname,"\\CRDEMO\\%02i.XA",i+1);

		if(XAgetStatus())
		{
			music = XAgetFileInfo(fname);	// the ";1" is added internally
			if(music)
			{
				ref_music[NUMBEROF8TRACKXA+i] = *music;
				FREE(music);
			}
		}
	}
}

