/************************************************************ * * * menu.c * * * * * LPGE 1997 * * * * Copyright (C) 1996 Sony Computer Entertainment Inc. * * All Rights Reserved * * * ***********************************************************/ #include "menu.h" #include "cd_data.h" #include "camera.h" /**************************************************************************** globals ****************************************************************************/ int FramesSinceLastUserSelection; int OpeningSequenceQuitFlag; int MainMenuQuitFlag; int DuringTheRaceQuitFlag; int AfterTheRaceQuitFlag; int ViewingTheTracksQuitFlag; int RollingDemoQuitFlag; int DuringTwoPlayerRaceQuitFlag; // these are what the user directly chooses in the menus int ChosenTrackNumber; int ChosenNumberOfDrivers; int ChosenNumberOfLaps; int NumberOfLapsCompletedInFreePractice; extern int ShipDrawProcessLabel; extern DrawProcess ShipDrawProcess; /**************************************************************************** macros ****************************************************************************/ #define PrintGameState(state) \ { \ switch((state)) \ { \ case OPENING_SEQUENCE: printf("OPENING_SEQUENCE\n"); break; \ case MAIN_MENU: printf("MAIN_MENU\n"); break; \ case DURING_THE_RACE: printf("DURING_THE_RACE\n"); break; \ case VIEWING_THE_TRACKS: printf("VIEWING_THE_TRACKS\n"); break; \ case SETTING_UP_FREE_PRACTICE: printf("SETTING_UP_FREE_PRACTICE\n"); break; \ case SETTING_UP_STRAIGHT_RACE: printf("SETTING_UP_STRAIGHT_RACE\n"); break; \ case SETTING_UP_TRACK_VIEWING: printf("SETTING_UP_TRACK_VIEWING\n"); break; \ case SETTING_UP_ROLLING_DEMO: printf("SETTING_UP_ROLLING_DEMO\n"); break; \ case SETTING_UP_TWO_PLAYER_RACE: printf("SETTING_UP_TWO_PLAYER_RACE\n"); break; \ case TWO_PLAYER_RACE: printf("TWO_PLAYER_RACE\n"); break; \ default: printf("BAD VALUE %d\n", (state)); assert(FALSE); \ } \ } #define ALL_ONES 0xffffffff u_long onlyNthBitOn, onlyNthBitOffMask; #define TURN_NTH_BIT_OFF(argument, sizeInBits, N) \ { \ onlyNthBitOn = 1 << (N); \ onlyNthBitOffMask = ALL_ONES ^ onlyNthBitOn; \ argument &= onlyNthBitOffMask; \ } #define ValidID(id) ( (id >= 0) && (id < NumberTunnelSections) ) #define ANTI_DIRECTION(direction) (direction) == BACKWARDS ? FORWARDS : BACKWARDS /**************************************************************************** local prototypes ****************************************************************************/ int GetNewRollingDemoMode (void); void HandleDeliberateRollingDemoControls (long pad); /**************************************************************************** functions ****************************************************************************/ void InitialiseTheGameState (void) { FramesSinceLastUserSelection = 0; OverallGameState = OPENING_SEQUENCE; StateChangeWaitingFlag = FALSE; ResetAllGuiLoopQuitFlags(); ResetBasicTunnelSelectionData(); RollingDemoActiveFlag = FALSE; RollingDemoDeliberateFlag = FALSE; RollingDemoStartFrame = -1; RollingDemoFirstTimeEverFlag = TRUE; InitialiseRace(); ChosenTrackNumber = 1; ChosenNumberOfDrivers = 1; ChosenNumberOfLaps = 3; TrackViewerShipViewMode = VIEW_BY_FIRST_DIRECTORS_CUT; RollingDemoMainMode = ROLLING_DEMO_SOLO_AI_FLIER; } void ResetAllGuiLoopQuitFlags (void) { OpeningSequenceQuitFlag = FALSE; MainMenuQuitFlag = FALSE; DuringTheRaceQuitFlag = FALSE; AfterTheRaceQuitFlag = FALSE; ViewingTheTracksQuitFlag = FALSE; RollingDemoQuitFlag = FALSE; DuringTwoPlayerRaceQuitFlag = FALSE; EndRaceNowFlag = FALSE; } void ResetBasicTunnelSelectionData (void) { MainMenuChoice = STRAIGHT_RACE; } void SetANewGameState (int newState) { int oldState; // could make a noise here .... oldState = OverallGameState; assert(newState != oldState); assert(newState >= 0 && newState < MAX_GAME_MODES); OverallGameState = newState; ResetAllGuiLoopQuitFlags(); switch(oldState) { case OPENING_SEQUENCE: OpeningSequenceQuitFlag = TRUE; break; case MAIN_MENU: MainMenuQuitFlag = TRUE; break; case DURING_THE_RACE: DuringTheRaceQuitFlag = TRUE; break; case VIEWING_THE_TRACKS: ViewingTheTracksQuitFlag = TRUE; break; case TWO_PLAYER_RACE: DuringTwoPlayerRaceQuitFlag = TRUE; break; case SETTING_UP_FREE_PRACTICE: // do nowt case SETTING_UP_STRAIGHT_RACE: // do nowt case SETTING_UP_TRACK_VIEWING: // do nowt case SETTING_UP_ROLLING_DEMO: // do nowt case SETTING_UP_TWO_PLAYER_RACE: // do nowt case SETTING_UP_MUSIC_OPTIONS: // do nowt break; default: assert(FALSE); } HandleGameStateTransition(oldState, newState); StateChangeWaitingFlag = TRUE; } // here: must do things // eg after race, set flag to clear things, // after set up race, should create tunnel, etc void HandleGameStateTransition (int oldState, int newState) { assert(newState != oldState); // never go back to opening sequence assert(newState != OPENING_SEQUENCE); FramesSinceLastUserSelection = 0; InitialiseRandomNumbers(); // try to preserve some element of randomness InitProfiler2(); ChosenNumberOfLaps = 3; // always turn off pause if (GlobalPauseFlag == TRUE) { GlobalPauseFlag = FALSE; SetObjectsInteractivity(TRUE); } if (oldState == VIEWING_THE_TRACKS && newState == SETTING_UP_TRACK_VIEWING) { ResetTrackViewingData(); if (TrackViewerMainMode == VIEW_TRACK_FROM_OUTSIDE) // uses low-res { ResetGraphicResolution (640, 480); } } if (newState == MAIN_MENU) // returning to main menu { ResetBasicTunnelSelectionData(); } // reset ship draw process whenever returning to interactive state if (newState == DURING_THE_RACE || newState == VIEWING_THE_TRACKS || newState == TWO_PLAYER_RACE || newState == FREE_PRACTICE) { ShipDrawProcessLabel = FORTY_SIXTH; SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); if (newState == VIEWING_THE_TRACKS && TrackViewerMainMode == VIEW_TRACK_FROM_OUTSIDE) { DrawProcessesClippingFlag = FALSE; } else { DrawProcessesClippingFlag = TRUE; } } // exit race completely, reset all race data if (oldState == DURING_THE_RACE || oldState == VIEWING_THE_TRACKS || oldState == TWO_PLAYER_RACE || oldState == FREE_PRACTICE) { //PRINT("Resetting Everything\n"); ResetCluts(); InitTunnelToVoid(); SetBasicTunnelParameters(); // NEW DrawSync(0); ResetGraph(1); // VERY NEW GsClearOt(0, 0, &Wot[0]); GsClearOt(0, 0, &Wot[1]); GsClearOt(0, 0, &Wot6[0]); GsClearOt(0, 0, &Wot6[1]); InitialiseObjects(); ResetTrackViewingData(); StartDrawingSectionId = 0; EndDrawingSectionId = 1; InitialiseRace(); TunnelSideAppearanceFlag = VISIBLE_FROM_INSIDE; TunnelSectionClippingFlag = TRUE; } } // each gui loop gets control for as long as it needs; // when it quits, control returns here, to select the next function void HandleTheGameStateMachine (void) { for (;;) { StateChangeWaitingFlag = FALSE; switch (OverallGameState) { case OPENING_SEQUENCE: OpeningSequenceLoop(); break; case MAIN_MENU: GuiLoopForTheMainMenu(); break; case DURING_THE_RACE: GuiLoopDuringTheRace(); break; case VIEWING_THE_TRACKS: GuiLoopForViewingTheTracks(); break; case SETTING_UP_FREE_PRACTICE: GuiLoopForSettingUpFreePractice(); break; case SETTING_UP_STRAIGHT_RACE: GuiLoopForSettingUpStraightRace(); break; case SETTING_UP_TRACK_VIEWING: GuiLoopForSettingUpTrackViewing(); break; case SETTING_UP_ROLLING_DEMO: GuiLoopForSettingUpRollingDemo(); break; case SETTING_UP_TWO_PLAYER_RACE: GuiLoopForSettingUpTwoPlayerRace(); break; case TWO_PLAYER_RACE: GuiLoopForTwoPlayerRace(); break; case SETTING_UP_MUSIC_OPTIONS: GuiLoopForSettingMusicOptions(); break; case QUIT_PROGRAM_COMPLETELY: // fall back to main return; default: assert(FALSE); } } } #define OPENING_SEQUENCE_FLAG 1 // NOTE that the opening sequence works differently under // Yaroze and dev kit; the dev-kit version has taken priority // for the demo disc. At present, the Yaroze version is uncertain; // should run, but will probably look/sound silly. short vabYaroze; int yarozeVoiceID; void OpeningSequenceLoop (void) { #if (OPENING_SEQUENCE_FLAG==1) int bufferIndex = 0; int openingSequenceStartFrame = 0; int openingSequenceFirstPhaseDuration = (MaximumGameFramesPerSecond * 3) / 2; // 3, 1, 1 int fadeUpDuration = (MaximumGameFramesPerSecond * 3) / 5; int fadeOutDuration = (MaximumGameFramesPerSecond * 3) / 5; int backColour; GsSPRITE introSprite; GsIMAGE introImageInfo; ProperInitialiseTexture(INTRO_TEXTURE_ADDRESS, &introImageInfo); LinkSpriteToImageInfo( &introSprite, &introImageInfo); // transfer VAB data vabYaroze = SsVabTransfer( (u_char *)YAROZE_VH_ADDRESS, (u_char *)YAROZE_VB_ADDRESS, -1, 1); if (vabYaroze < 0) { printf("Yaroze VAB open failed\n"); HERE; exit(1); } SsSetMVol(127, 127); ResetGraphicResolution(256, 240); introSprite.x = -3; introSprite.y = 12; assert(introSprite.w != 0); assert(introSprite.h != 0); introSprite.mx = introSprite.w/2; introSprite.my = introSprite.h/2; introSprite.rotate = ONE * 90; // 90 degrees openingSequenceStartFrame = frameNumber; bufferIndex = GsGetActiveBuff(); while (OpeningSequenceQuitFlag == FALSE) { HandleSound(); GsSetRefView2( &TheView); GsSetWorkBase( (PACKET*)packetArea[bufferIndex]); GsClearOt(0, 0, &Wot[bufferIndex]); if ((frameNumber - openingSequenceStartFrame) <= openingSequenceFirstPhaseDuration) { introSprite.r = (255 * (frameNumber - openingSequenceFirstPhaseDuration)) / openingSequenceFirstPhaseDuration; introSprite.g = (255 * (frameNumber - openingSequenceFirstPhaseDuration)) / openingSequenceFirstPhaseDuration; introSprite.b = (255 * (frameNumber - openingSequenceFirstPhaseDuration)) / openingSequenceFirstPhaseDuration; backColour = 0; if (frameNumber - openingSequenceStartFrame > 2) { GsSortSprite( &introSprite, &Wot[bufferIndex], 50); } } else { introSprite.r = 255; introSprite.g = 255; introSprite.b = 255; introSprite.attribute |= GsALON; // semi-trans introSprite.attribute |= 1<<28; introSprite.attribute |= 1<<29; if (frameNumber - openingSequenceStartFrame < (openingSequenceFirstPhaseDuration + fadeUpDuration)) { backColour = (255 * (frameNumber - openingSequenceStartFrame - openingSequenceFirstPhaseDuration)) / fadeUpDuration; GsSortSprite( &introSprite, &Wot[bufferIndex], 50); } else { backColour = (255 * (fadeUpDuration+fadeOutDuration -(frameNumber - openingSequenceStartFrame - openingSequenceFirstPhaseDuration))) / fadeOutDuration; } } hsync = VSync(0); DrawSync(0); GsSwapDispBuff(); GsSortClear(backColour, backColour, backColour, &Wot[bufferIndex]); GsDrawOt(&Wot[bufferIndex]); bufferIndex = GsGetActiveBuff(); frameNumber++; if (frameNumber - openingSequenceStartFrame > (openingSequenceFirstPhaseDuration + fadeUpDuration + fadeOutDuration)) { ResetGraphicResolution(640, 480); OpeningSequenceQuitFlag = TRUE; } } #else { OpeningSequenceQuitFlag = TRUE; //PRINT("Not doing opening sequence\n"); } #endif // always do this MainMenuChoice = ROLLING_DEMO; PrepareRollingDemo(FALSE); // play looping background tune PlayJasonsTune(); } MenuOption MainMenuScreenOptions[6]; MenuScreen MainMenuScreen; void GuiLoopForTheMainMenu (void) { CreateMenuOption( &MainMenuScreenOptions[0], TAKE_ACTION, "One player race", 0, 0, STRAIGHT_RACE, NULL); CreateMenuOption( &MainMenuScreenOptions[1], TAKE_ACTION, "Two player race", 0, 0, TWO_PLAYERS_RACING, NULL); CreateMenuOption( &MainMenuScreenOptions[2], TAKE_ACTION, "Rolling Demo", 0, 0, ROLLING_DEMO, NULL); CreateMenuOption( &MainMenuScreenOptions[3], TAKE_ACTION, "Free Practice", 0, 0, FREE_PRACTICE, NULL); CreateMenuOption( &MainMenuScreenOptions[4], TAKE_ACTION, "View the tracks", 0, 0, VIEW_THE_TRACKS, NULL); #if (DEVELOPMENT_ENVIRONMENT==YAROZE) // CD player options only for Yaroze CreateMenuOption( &MainMenuScreenOptions[5], TAKE_ACTION, "Music options", 0, 0, SET_MUSIC_OPTIONS, NULL); CreateMenuScreen( &MainMenuScreen, 6, MainMenuScreenOptions); #else CreateMenuScreen( &MainMenuScreen, 5, MainMenuScreenOptions); #endif SetMenuScreenPauseTimes( &MainMenuScreen, 8, 7); // start rolling demo after five seconds of inactivity SetMenuScreenTimeoutTime( &MainMenuScreen, MaximumGameFramesPerSecond * 5); SetMenuScreenBackgroundEffect( &MainMenuScreen, SECOND_EFFECT_SWITCHER); bufferIndex = GsGetActiveBuff(); HandleMenuScreen( &MainMenuScreen); if (MainMenuScreen.quitCode == QUIT_BACK_TO_LEVEL_ABOVE) { //printf("Exiting Program Now\n"); MakeClunk(); SetANewGameState(QUIT_PROGRAM_COMPLETELY); return; } // what was the choice? MainMenuChoice = MainMenuScreen.quitCode; // now handle the choice switch(MainMenuChoice) { case TIMEOUT_QUIT_CODE: // when left unattended PrepareRollingDemo(FALSE); break; case FREE_PRACTICE: MakeClunk(); RollingDemoActiveFlag = FALSE; RollingDemoDeliberateFlag = FALSE; SetANewGameState(SETTING_UP_FREE_PRACTICE); break; case ROLLING_DEMO: MakeClunk(); RollingDemoActiveFlag = TRUE; RollingDemoDeliberateFlag = TRUE; SetANewGameState(SETTING_UP_ROLLING_DEMO); break; case STRAIGHT_RACE: MakeClunk(); RollingDemoActiveFlag = FALSE; RollingDemoDeliberateFlag = FALSE; SetANewGameState(SETTING_UP_STRAIGHT_RACE); break; case TWO_PLAYERS_RACING: MakeClunk(); RollingDemoActiveFlag = FALSE; RollingDemoDeliberateFlag = FALSE; SetANewGameState(SETTING_UP_TWO_PLAYER_RACE); break; case VIEW_THE_TRACKS: MakeClunk(); RollingDemoActiveFlag = FALSE; RollingDemoDeliberateFlag = FALSE; SetANewGameState(SETTING_UP_TRACK_VIEWING); break; #if (DEVELOPMENT_ENVIRONMENT==YAROZE) // DISABLED FOR DEMO ON DEMO DISC case SET_MUSIC_OPTIONS: MakeClunk(); RollingDemoActiveFlag = FALSE; RollingDemoDeliberateFlag = FALSE; SetANewGameState(SETTING_UP_MUSIC_OPTIONS); break; #endif default: assert(FALSE); } } int GetNewRollingDemoMode (void) { int mode; mode = ROLLING_DEMO_SOLO_AI_FLIER + (rand() % 2); // BEST //mode = ROLLING_DEMO_TRACK_VIEWING + (rand() % 3); return mode; } #define NUMBER_BEST_TRACKS 23 int BestTrackList[NUMBER_BEST_TRACKS] = {1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, 18, 21, 23, 24, 26, 30, 32, 34, 36, 37, 38, 41}; void PrepareRollingDemo (int deliberateFlag) { int choice; RollingDemoActiveFlag = TRUE; RollingDemoStartFrame = frameNumber; RollingDemoDeliberateFlag = deliberateFlag; switch(deliberateFlag) { case FALSE: if (RollingDemoFirstTimeEverFlag == FALSE) // self-start demo { // pick random mode RollingDemoMainMode = GetNewRollingDemoMode(); // pick random track ChosenTrackNumber = 1 + (rand() % NUMBER_SET_TRACKS); } else // first time: set mode and track { int index; assert(RollingDemoFirstTimeEverFlag == TRUE); RollingDemoMainMode = ROLLING_DEMO_SOLO_AI_FLIER; index = rand() % NUMBER_BEST_TRACKS; ChosenTrackNumber = BestTrackList[index]; assert(ChosenTrackNumber >= 1); assert(ChosenTrackNumber <= NUMBER_SET_TRACKS); RollingDemoFirstTimeEverFlag = FALSE; } break; case TRUE: // use user's choices break; default: assert(FALSE); } switch(RollingDemoMainMode) { case ROLLING_DEMO_TRACK_VIEWING: TrackViewerCameraControlMode = TRACK_VIEWER_AUTO_CAMERA; if (RollingDemoDeliberateFlag == FALSE) { TrackViewerMainMode = VIEW_TRACK_FROM_INSIDE + (rand() % 2); } switch(TrackViewerMainMode) { case VIEW_TRACK_FROM_INSIDE: if (deliberateFlag == FALSE) { TrackViewerDirection = FORWARDS + (rand() % 2); choice = rand() % 4; switch(choice) { case 0: TrackViewerAutoCameraMode = TRACK_VIEWER_AUTO_CAMERA_SLOW_MODE; break; case 1: TrackViewerAutoCameraMode = TRACK_VIEWER_AUTO_CAMERA_TWISTER_MODE; break; case 2: TrackViewerAutoCameraMode = TRACK_VIEWER_AUTO_CAMERA_TWISTING_ROLLERCOASTER_MODE; break; case 3: TrackViewerAutoCameraMode = TRACK_VIEWER_AUTO_CAMERA_ZOOM_ROLLERCOASTER_MODE; break; default: assert(FALSE); } } break; case VIEW_TRACK_FROM_OUTSIDE: // at present only one autocamera mode for external viewing // hence no choice to make here break; default: assert(FALSE); } PrepareTheTrackForViewing(); SetANewGameState(VIEWING_THE_TRACKS); break; case ROLLING_DEMO_SOLO_AI_FLIER: SetUpARollingDemoSoloAiFlier(deliberateFlag); SetANewGameState(DURING_THE_RACE); break; case ROLLING_DEMO_AI_FLIERS_RACE: SetUpARollingDemoAiFliersRace(deliberateFlag); SetANewGameState(DURING_THE_RACE); break; default: assert(FALSE); } } // set up the ships for racing // should be assigning ship types for movement data // Expects: that NumberOfShipsInRace and ShipsInTunnel // are all set up, that the tunnel is already completely built // that FrameWhenRaceStarts is set // first ship put in at centre of section zero // each further is one section along void PrepareShipsForRace2 (void) { ObjectHandler *ship; VECTOR offsetVector; MATRIX offsetMatrix; int i, j; setVECTOR( &offsetVector, 0, 0, TunnelSectionLength/2); InitMatrix( &offsetMatrix); for (i = 0; i < NumberOfShipsInRace; i++) { ship = ShipsInTunnel[i]; ship->alive = TRUE; ship->racingFlag = TRUE; PutObjectInTunnel(ship, i, &offsetVector, &offsetMatrix); // data for 3rd blagger fliers // GENERALISE for other flier types: init properly ship->startFrame = frameNumber; ship->currentPositionIndex = (i * ship->speedFactor) + (ship->speedFactor/2); ship->playbackFrameIndex = 0; ship->placeInRace = NumberOfShipsInRace - i; // place: 1 to N InitialPositions[i] = ship->placeInRace; ship->furthestSection = ship->tunnelSection; ship->furthestLap = 0; ship->advancedFlag = FALSE; ship->framesWhenLapsEnd[0] = 0; // relative to RaceFrameCounter for (j = 1; j < MAX_LAPS_PER_OBJECT; j++) { ship->framesWhenLapsEnd[j] = 0; } ship->bestLapTime = 0; } } void PrepareTheTrackForViewing (void) { assert(ChosenTrackNumber >= 1); assert(ChosenTrackNumber <= NUMBER_SET_TRACKS); ChosenSetTrack = ChosenTrackNumber-1; // HERE: tell the user we are building the tunnel // bring up nice TIM, print message near bottom of screen //PRINT("\n\nCreating the chosen track now\n\n"); switch(TrackViewerMainMode) { case VIEW_TRACK_FROM_INSIDE: TunnelSectionClippingFlag = TRUE; TunnelSideAppearanceFlag = VISIBLE_FROM_INSIDE; break; case VIEW_TRACK_FROM_OUTSIDE: TunnelSectionClippingFlag = FALSE; TunnelSideAppearanceFlag = VISIBLE_FROM_OUTSIDE; break; default: assert(FALSE); } // build the specified tunnel SortTunnelToSetTrack(ChosenSetTrack); // sort the viewer ResetTrackViewingData(); SetUpTheViewer(); FrameWhenTrackViewingStarts = frameNumber; if (TrackViewerMainMode == VIEW_TRACK_FROM_OUTSIDE) { OverallLightMode = 0; // no fogging with external track viewing GsSetLightMode(OverallLightMode); GsSetAmbient(ONE, ONE, ONE); // need alot of light } } int TopLeftX, TopLeftY; int BottomLeftX, BottomLeftY; int BottomRightX, BottomRightY; void GuiLoopDuringTheRace (void) { int i; int yPrint, yIncrement; int speed; int lap, frames; char thisLapTimeString[16]; long pad; VECTOR shipZaxis; int viewShipDirection; int firstFrame, startUpPhase = -1, oneSecondsWorth; int viewAlreadySetFlag = FALSE; firstFrame = frameNumber; assert(MaximumGameFramesPerSecond > 0); oneSecondsWorth = MaximumGameFramesPerSecond; switch(ScreenResolution) { case LOW_RES: TopLeftX = -150; TopLeftY = -110; BottomLeftX = -150; BottomLeftY = 110; BottomRightX = 150-96; BottomRightY = 110; break; case HI_RES: TopLeftX = -288; TopLeftY = -190; BottomLeftX = -288; BottomLeftY = 190; BottomRightX = 118; BottomRightY = 190; break; default: assert(FALSE); } bufferIndex = GsGetActiveBuff(); while (DuringTheRaceQuitFlag == FALSE) { if (RollingDemoActiveFlag != TRUE) { // use intro view if (frameNumber - firstFrame < (oneSecondsWorth*IntroViewDurationInSeconds)) { HandleIntroView(frameNumber - firstFrame); viewAlreadySetFlag = TRUE; startUpPhase = -999; SetObjectsInteractivity(FALSE); GlobalPauseFlag = TRUE; } else if (frameNumber - firstFrame < (oneSecondsWorth*(IntroViewDurationInSeconds+1))) { SetObjectsInteractivity(FALSE); GlobalPauseFlag = TRUE; startUpPhase = ((frameNumber - firstFrame - (oneSecondsWorth*IntroViewDurationInSeconds)) * 3) / oneSecondsWorth; viewAlreadySetFlag = FALSE; } else if (frameNumber - firstFrame == (oneSecondsWorth*(IntroViewDurationInSeconds+1))) { startUpPhase = -1; GlobalPauseFlag = FALSE; SetObjectsInteractivity(TRUE); viewAlreadySetFlag = FALSE; } else { startUpPhase = -1; viewAlreadySetFlag = FALSE; } SortFntPrint(); } #if (DEVELOPMENT_ENVIRONMENT==YAROZE) { if (SoundToGraphicInUseFlag == TRUE) { #if 0 // OLD { CdDataPointer = ReadCDDA(); #if 0 // testing ConvertMusicDataTo32UnsignedPieces(); if (frameNumber % 120 == 0) { int i; printf("32fold data :-\n\n"); for (i = 0; i < 32; i++) { printf("%d\t", Cd32foldBuffer[i]); if (((i+1) % 8) == 0) printf("\n"); } printf("\n\n"); } #endif #if 0 // testing GenerateTestCdData(); #endif CalculateSalientCdDataFacts(); #if 0 // testing; this causes frame drop // fft Very expensive if (frameNumber % 30 == 0) fft(); #endif } #endif // OLD #if 1 // NEW if (CompactDiscMusicPlayFlag == TRUE) { CdDataPointer = ReadCDDA(); } else { //GenerateSpuriousCdData(); GenerateTestCdData(); } CalculateSalientCdDataFacts(); #endif // NEW } } #else { if (SoundToGraphicInUseFlag == TRUE) { //CdDataPointer = ReadCDDA(); GenerateSpuriousCdData(); CalculateSalientCdDataFacts(); } } #endif DealWithControllerPad(); if (StateChangeWaitingFlag == TRUE) return; HandleSound(); //PutStackOntoDataCache(); HandleAllObjects(); //RestoreStackFromDataCache(); if (DebugDynTexMarker != TRUE) UpdateTheTunnel(); // at present, only one global ship draw process // later on, one per ship if (ShipDrawProcessLabel != -1 && DebugDynTexMarker != TRUE) ExecuteSingleDrawProcess( &ShipDrawProcess); switch(ScreenResolution) { case LOW_RES: yPrint = -60; yIncrement = 20; break; case HI_RES: yPrint = -120; yIncrement = 40; break; default: assert(FALSE); } if (RaceOnFlag) { HandleRacePositions(); } if (viewAlreadySetFlag == FALSE) HandleTheView(); GsSetWorkBase( (PACKET*)packetArea[bufferIndex]); GsClearOt(0, 0, &Wot[bufferIndex]); if (RollingDemoActiveFlag == FALSE) // this chunk used to above large #if 0 section above { RegisterTextStringForDisplay ("Speed ", TopLeftX, TopLeftY, BLUE_COLOUR); speed = GetSpeedFractionOfViewShip(); DrawSpeedBar( &Wot[bufferIndex], -184, -190, speed, 4096, 480); sprintf(SimplePrintString2, "lap %d", PlayerOnesShip.furthestLap+1); RegisterTextStringForDisplay (SimplePrintString2, BottomLeftX, BottomLeftY, GREEN_COLOUR); switch(MainMenuChoice) { case FREE_PRACTICE: lap = PlayerOnesShip.furthestLap; assert(lap >= 0); assert(lap < MAX_LAPS_PER_OBJECT); frames = RaceFrameCounter - PlayerOnesShip.framesWhenLapsEnd[lap]; if (frames < 0) { PRINT("BAD values\n"); PRINT("RaceFrameCounter %d\n", RaceFrameCounter); PRINT("lap %d\n", lap); PRINT("PlayerOnesShip.framesWhenLapsEnd[lap] %d\n", PlayerOnesShip.framesWhenLapsEnd[lap]); frames = 0; } GetStringOfTimeInFrames(frames, thisLapTimeString); sprintf(SimplePrintString3, "time %s", thisLapTimeString); RegisterTextStringForDisplay (SimplePrintString3, BottomRightX, BottomRightY, RED_COLOUR); break; case STRAIGHT_RACE: sprintf(SimplePrintString3, "Position %d", PlayerOnesShip.placeInRace); RegisterTextStringForDisplay (SimplePrintString3, BottomRightX, BottomRightY, RED_COLOUR); break; default: assert(FALSE); } } else // rolling demo on { pad = PadRead(0); if (RollingDemoDeliberateFlag == TRUE) // select to quit deliberate demo { HandleDeliberateRollingDemoControls(pad); // NEW } else // any key quits auto-demo { if (pad != 0) SetANewGameState(MAIN_MENU); } if (StateChangeWaitingFlag == TRUE) return; } // if going the wrong way, print message saying so setVECTOR( &shipZaxis, TheViewShip->matrix.m[0][2], TheViewShip->matrix.m[1][2], TheViewShip->matrix.m[2][2]); assert(ValidID(TheViewShip->tunnelSection)); viewShipDirection = FindWhichWayVectorGoesInSection( &shipZaxis, TheViewShip->tunnelSection); if (viewShipDirection != FORWARDS) { RegisterTextStringForDisplay("WRONG WAY", -63, -90, RED_COLOUR); } if (GlobalPauseFlag == TRUE && startUpPhase == -1) { RegisterTextStringForDisplay ("PAUSED", -31, -65, RED_COLOUR); } // TEST box for fading .... //GsSortBoxFill( &FadeBox, &Wot[bufferIndex], 0); if (RollingDemoActiveFlag == FALSE) { switch(startUpPhase) { case -1: // do nowt, not in startup break; case 0: RegisterTextStringForDisplay ("Ready ", -40, -40, RED_COLOUR); break; case 1: RegisterTextStringForDisplay ("Steady ", -48, -20, YELLOW_COLOUR); break; case 2: RegisterTextStringForDisplay ("Go ", -16, 0, DARK_GREEN_COLOUR); break; case -999: // in startup, but no string printing here break; default: assert(FALSE); } } //PutStackOntoDataCache(); DisplayTextStrings (&Wot[bufferIndex]); //RestoreStackFromDataCache(); if (DebugDynTexMarker == TRUE) { UpdateTheTunnel(); if (ShipDrawProcessLabel != -1) ExecuteSingleDrawProcess( &ShipDrawProcess); } //PutStackOntoDataCache(); DrawTheTunnelPolygons( &Wot[bufferIndex], OT_SHIFT); //RestoreStackFromDataCache(); DrawTheRacingShips( &Wot[bufferIndex], OT_SHIFT); #if 1 // old sprite tester if (ShowGlobalSpriteFlag == TRUE) { assert(SelectedGlobalSprite >= 0); assert(SelectedGlobalSprite < MAX_GLOBAL_SPRITES); assert(SelectedGlobalSprite < NumberGlobalSprites); GlobalSpriteList[SelectedGlobalSprite]->x = -GlobalSpriteList[SelectedGlobalSprite]->w/2; GlobalSpriteList[SelectedGlobalSprite]->y = -GlobalSpriteList[SelectedGlobalSprite]->h/2; GlobalSpriteList[SelectedGlobalSprite]->scalex = ONE; GlobalSpriteList[SelectedGlobalSprite]->scaley = ONE; GlobalSpriteList[SelectedGlobalSprite]->mx = 0; GlobalSpriteList[SelectedGlobalSprite]->my = 0; GlobalSpriteList[SelectedGlobalSprite]->rotate = 0; GlobalSpriteList[SelectedGlobalSprite]->r = 128; GlobalSpriteList[SelectedGlobalSprite]->g = 128; GlobalSpriteList[SelectedGlobalSprite]->b = 128; FntPrint(currentFontStream, "global sprite %d\n", SelectedGlobalSprite); GsSortSprite( GlobalSpriteList[SelectedGlobalSprite], &Wot[bufferIndex], 0); // now draw four in tiling block GlobalSpriteList[SelectedGlobalSprite]->scalex = ONE/2; GlobalSpriteList[SelectedGlobalSprite]->scaley = ONE/2; GlobalSpriteList[SelectedGlobalSprite]->x = -ScreenWidth/2 + 10; GlobalSpriteList[SelectedGlobalSprite]->y = -ScreenHeight/2 + 40; GsSortSprite( GlobalSpriteList[SelectedGlobalSprite], &Wot[bufferIndex], 0); GlobalSpriteList[SelectedGlobalSprite]->x = -ScreenWidth/2 + 10; GlobalSpriteList[SelectedGlobalSprite]->y = -ScreenHeight/2 + 40 + GlobalSpriteList[SelectedGlobalSprite]->h/2; GsSortSprite( GlobalSpriteList[SelectedGlobalSprite], &Wot[bufferIndex], 0); GlobalSpriteList[SelectedGlobalSprite]->x = -ScreenWidth/2 + 10 + GlobalSpriteList[SelectedGlobalSprite]->w/2; GlobalSpriteList[SelectedGlobalSprite]->y = -ScreenHeight/2 + 40; GsSortSprite( GlobalSpriteList[SelectedGlobalSprite], &Wot[bufferIndex], 0); GlobalSpriteList[SelectedGlobalSprite]->x = -ScreenWidth/2 + 10 + GlobalSpriteList[SelectedGlobalSprite]->w/2; GlobalSpriteList[SelectedGlobalSprite]->y = -ScreenHeight/2 + 40 + GlobalSpriteList[SelectedGlobalSprite]->h/2; GsSortSprite( GlobalSpriteList[SelectedGlobalSprite], &Wot[bufferIndex], 0); } #endif cpuLoad = VSync(1); //DrawSync(0); // PROVES UNNECESSARY: game faster without it gpuLoad = VSync(1); hsync = VSync(0); if (hsync > maxHsync) maxHsync = hsync; if (StoreScreenFlag == TRUE) { StoreScreen(); CleanUpProgram(); exit(1); } CalculateCurrentFrameRate(hsync); SortAllShipsParametersByFrameRate(); if (frameLimiter > 1) // slow game down { for (i = 0; i < frameLimiter-1; i++) VSync(0); } GsSwapDispBuff(); // little use to this .... //GsSortClear(BackgroundColourRed, BackgroundColourGreen, // BackgroundColourBlue, &Wot[bufferIndex]); GsSortClear(0, 0, 0, &Wot[bufferIndex]); GsDrawOt(&Wot[bufferIndex]); if (TheTunnelDescription.tunnelHighlightFlag == TRUE) { ResetDataDueToHighlighting(); } bufferIndex = GsGetActiveBuff(); if (RollingDemoActiveFlag != TRUE) { //FntPrint(currentFontStream, "frame: %d\n", frameNumber); //FntPrint(currentFontStream, "hsync: %d\n", hsync); //FntPrint(currentFontStream, "maxHsync: %d\n", maxHsync); //FntPrint(currentFontStream, "frame lim: %d\n", frameLimiter); } if (frameNumber == 60) maxHsync = hsync; else if (maxHsync > 1500) { if (frameNumber % 20 == 0) { //PRINT("massive hsync: %d\n", maxHsync); } maxHsync = 0; } if (FrameRateDivider > 1) { if (frameNumber % 20 == 0) { PRINT("MISSING A FRAME\n"); } } FntFlush(currentFontStream); frameNumber++; if (GlobalPauseFlag == FALSE) RaceFrameCounter++; if (EndRaceNowFlag == TRUE) { switch(MainMenuChoice) { case FREE_PRACTICE: NumberOfLapsCompletedInFreePractice = PlayerOnesShip.furthestLap; ShowFreePracticeResults(); SetANewGameState(SETTING_UP_FREE_PRACTICE); break; case ROLLING_DEMO: SetANewGameState(SETTING_UP_ROLLING_DEMO); break; case STRAIGHT_RACE: ShowFullRaceResults(); SetANewGameState(SETTING_UP_STRAIGHT_RACE); break; default: PRINT("BAD main menu choice %d\n", MainMenuChoice); assert(FALSE); } } if (RollingDemoActiveFlag == TRUE) { if (RollingDemoMainMode == ROLLING_DEMO_AI_FLIERS_RACE) { // every so often, view from new ship if (frameNumber % (MaximumGameFramesPerSecond * 6) == 0) { int choice; for (;;) { choice = rand() % NumberOfShipsInRace; if (ShipsInTunnel[choice] != TheViewShip) break; } SetNewViewShip(ShipsInTunnel[choice]); } } // once in a while, sort a new rolling demo if ( ((frameNumber - RollingDemoStartFrame) % (MaximumGameFramesPerSecond * 24)) == 0) { SortOutANewRollingDemo(); } if (RollingDemoDeliberateFlag == FALSE) { if (frameNumber - RollingDemoStartFrame >= ROLLING_DEMO_NATURAL_DURATION) { SetANewGameState(MAIN_MENU); } } } } } // during deliberate rolling demo, allow user to change view mode // should really print string saying what it is ... // register string for brief display (delay from now, duration, string) void HandleDeliberateRollingDemoControls (long pad) { if (pad & PADselect) SetANewGameState(SETTING_UP_ROLLING_DEMO); else { static int framesSinceLastChoice = 0; framesSinceLastChoice++; if (framesSinceLastChoice >= MaximumGameFramesPerSecond/4) { if (pad & PADLup) { if (TheViewShip->viewMode == BASE_VIEW_MODE + NUMBER_OF_DECENT_VIEW_MODES - 1) { TheViewShip->viewMode = BASE_VIEW_MODE; } else { TheViewShip->viewMode++; } SetNewViewShip(TheViewShip); framesSinceLastChoice = 0; return; } if (pad & PADLdown) { if (TheViewShip->viewMode == BASE_VIEW_MODE) { TheViewShip->viewMode = BASE_VIEW_MODE + NUMBER_OF_DECENT_VIEW_MODES - 1; } else { TheViewShip->viewMode--; } SetNewViewShip(TheViewShip); framesSinceLastChoice = 0; return; } } } } extern SVECTOR ScreenScaler; void GuiLoopForTwoPlayerRace (void) { int i; SVECTOR screenScaler; RECT clippingRectangle; int playerOneDirection, playerTwoDirection; VECTOR shipZaxis; int speed; int firstFrame, startUpPhase; #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) ResetGraphicResolution(320, 240); // low res because // this mode will drop frames #endif setVECTOR( &screenScaler, ONE, ((3 * ONE) / 4), ONE); bufferIndex = GsGetActiveBuff(); #if (DRAW_DISTANCE_REDUCED_FOR_TWO_PLAYER_MODE==1) // set heavy nighttime-fogging, since draw distance is low OverallLightMode = 1; GsSetLightMode(OverallLightMode); TheFogging.dqa = -5000; TheFogging.dqb = 33099400; TheFogging.rfc = 0; TheFogging.gfc = 0; TheFogging.bfc = 0; GsSetFogParam( &TheFogging); #endif firstFrame = frameNumber; while(DuringTwoPlayerRaceQuitFlag == FALSE) { assert(RollingDemoActiveFlag == FALSE); // business for 'ready, steady, go' start if (frameNumber - firstFrame < 60) { GlobalPauseFlag = TRUE; SetObjectsInteractivity(FALSE); startUpPhase = ((frameNumber - firstFrame) * 3) / 60; } else if (frameNumber - firstFrame == 60) { startUpPhase = -1; GlobalPauseFlag = FALSE; SetObjectsInteractivity(TRUE); } else startUpPhase = -1; // business done before any drawing DealWithControllerPad(); if (StateChangeWaitingFlag == TRUE) { #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) ResetGraphicResolution(640, 480); #endif return; } HandleSound(); //PutStackOntoDataCache(); HandleAllObjects(); //RestoreStackFromDataCache(); if (RaceOnFlag) { HandleRacePositions(); } UpdateTheTunnel(); if (ShipDrawProcessLabel != -1) ExecuteSingleDrawProcess( &ShipDrawProcess); /////// Start of business for drawing top screen //////////// #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) { GsSetOrign(160, 60); GsScaleScreen( &screenScaler); } #else { GsSetOrign(320, 120); } #endif bufferIndex = GsGetActiveBuff(); SetNewViewShip( &PlayerOnesShip); HandleTheView(); GsSetWorkBase( (PACKET*)packetArea[bufferIndex]); GsClearOt(0, 0, &Wot[bufferIndex]); // if going the wrong way, print message saying so setVECTOR( &shipZaxis, PlayerOnesShip.matrix.m[0][2], PlayerOnesShip.matrix.m[1][2], PlayerOnesShip.matrix.m[2][2]); assert(ValidID(PlayerOnesShip.tunnelSection)); playerOneDirection = FindWhichWayVectorGoesInSection( &shipZaxis, PlayerOnesShip.tunnelSection); if (playerOneDirection != FORWARDS) { RegisterTextStringForDisplay("WRONG WAY", -40, -10, RED_COLOUR); } switch(startUpPhase) { case -1: // do nowt, not in startup break; case 0: RegisterTextStringForDisplay ("Ready ", -40, -40, RED_COLOUR); break; case 1: RegisterTextStringForDisplay ("Steady ", -48, -20, YELLOW_COLOUR); break; case 2: RegisterTextStringForDisplay ("Go ", -16, 0, DARK_GREEN_COLOUR); break; default: assert(FALSE); } #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) { RegisterTextStringForDisplay ("Speed ", -136, -35, BLUE_COLOUR); speed = GetSpeedFractionOfViewShip(); DrawSpeedBar( &Wot[bufferIndex], -88, -35, speed, 2048, 180); sprintf(SimplePrintString2, "lap %d", PlayerOnesShip.furthestLap+1); RegisterTextStringForDisplay (SimplePrintString2, -144, 48, GREEN_COLOUR); sprintf(SimplePrintString3, "Position %d", PlayerOnesShip.placeInRace); RegisterTextStringForDisplay (SimplePrintString3, 64, 44, RED_COLOUR); if (GlobalPauseFlag == TRUE && startUpPhase == -1) { RegisterTextStringForDisplay ("PAUSED", -15, -40, RED_COLOUR); } } #else { RegisterTextStringForDisplay ("Speed ", -272, -70, BLUE_COLOUR); speed = GetSpeedFractionOfViewShip(); DrawSpeedBar( &Wot[bufferIndex], -176, -70, speed, 4096, 360); sprintf(SimplePrintString2, "lap %d", PlayerOnesShip.furthestLap+1); RegisterTextStringForDisplay (SimplePrintString2, -288, 96, GREEN_COLOUR); sprintf(SimplePrintString3, "Position %d", PlayerOnesShip.placeInRace); RegisterTextStringForDisplay (SimplePrintString3, 128, 88, RED_COLOUR); if (GlobalPauseFlag == TRUE && startUpPhase == -1) { RegisterTextStringForDisplay ("PAUSED", -31, -80, RED_COLOUR); } } #endif DisplayTextStrings (&Wot[bufferIndex]); //PutStackOntoDataCache(); DrawTheTunnelPolygons( &Wot[bufferIndex], OT_SHIFT); //RestoreStackFromDataCache(); DrawTheRacingShips( &Wot[bufferIndex], OT_SHIFT); hsync = VSync(0); if (StoreScreenFlag == TRUE) { StoreScreen(); CleanUpProgram(); exit(1); } if (frameLimiter > 1) // slow game down { for (i = 0; i < frameLimiter-1; i++) VSync(0); } GsSwapDispBuff(); GsSortClear(0, 0, 0, &Wot[bufferIndex]); #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) { setRECT( &clippingRectangle, 0, 0, 320, 120); GsSetClip( &clippingRectangle); GsScaleScreen( &ScreenScaler); } #else { setRECT( &clippingRectangle, 0, 0, 640, 240); GsSetClip( &clippingRectangle); } #endif GsDrawOt(&Wot[bufferIndex]); ///////////// End of business for drawing top screen ///////////////////// ///////////// Start of business for drawing bottom screen ///////////////////// #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) { GsSetOrign(160, 180); GsScaleScreen( &screenScaler); } #else { GsSetOrign(320, 360); } #endif GsSwapDispBuff(); // hmmmmmm...... GsSwapDispBuff(); GsSetWorkBase( (PACKET*) packetArea6[bufferIndex]); GsClearOt(0, 0, &Wot6[bufferIndex]); SetNewViewShip( &PlayerTwosShip); HandleTheView(); // if going the wrong way, print message saying so setVECTOR( &shipZaxis, PlayerTwosShip.matrix.m[0][2], PlayerTwosShip.matrix.m[1][2], PlayerTwosShip.matrix.m[2][2]); assert(ValidID(PlayerTwosShip.tunnelSection)); playerTwoDirection = FindWhichWayVectorGoesInSection( &shipZaxis, PlayerTwosShip.tunnelSection); if (playerTwoDirection != FORWARDS) { RegisterTextStringForDisplay("WRONG WAY", -80, -10, RED_COLOUR); } switch(startUpPhase) { case -1: // do nowt, not in startup break; case 0: RegisterTextStringForDisplay ("Ready ", -40, -40, RED_COLOUR); break; case 1: RegisterTextStringForDisplay ("Steady ", -48, -20, YELLOW_COLOUR); break; case 2: RegisterTextStringForDisplay ("Go ", -16, 0, DARK_GREEN_COLOUR); break; default: assert(FALSE); } #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) { RegisterTextStringForDisplay ("Speed ", -136, -56, BLUE_COLOUR); speed = GetSpeedFractionOfViewShip(); DrawSpeedBar( &Wot6[bufferIndex], -88, -56, speed, 2048, 180); sprintf(SimplePrintString2, "lap %d", PlayerTwosShip.furthestLap+1); RegisterTextStringForDisplay (SimplePrintString2, -144, 36, GREEN_COLOUR); sprintf(SimplePrintString3, "Position %d", PlayerTwosShip.placeInRace); RegisterTextStringForDisplay (SimplePrintString3, 64, 44, RED_COLOUR); } #else { RegisterTextStringForDisplay ("Speed ", -272, -112, BLUE_COLOUR); speed = GetSpeedFractionOfViewShip(); DrawSpeedBar( &Wot6[bufferIndex], -176, -112, speed, 4096, 360); sprintf(SimplePrintString2, "lap %d", PlayerTwosShip.furthestLap+1); RegisterTextStringForDisplay (SimplePrintString2, -288, 72, GREEN_COLOUR); sprintf(SimplePrintString3, "Position %d", PlayerTwosShip.placeInRace); RegisterTextStringForDisplay (SimplePrintString3, 128, 88, RED_COLOUR); } #endif DisplayTextStrings (&Wot6[bufferIndex]); //PutStackOntoDataCache(); DrawTheTunnelPolygons( &Wot6[bufferIndex], OT_SHIFT); //RestoreStackFromDataCache(); DrawTheRacingShips( &Wot6[bufferIndex], OT_SHIFT); #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) { setRECT( &clippingRectangle, 0, 120, 320, 120); GsSetClip( &clippingRectangle); GsScaleScreen( &ScreenScaler); } #else { setRECT( &clippingRectangle, 0, 240, 640, 240); GsSetClip( &clippingRectangle); } #endif GsDrawOt(&Wot6[bufferIndex]); ///////////// End of business for drawing bottom screen ///////////////////// // more common frame-handle business SortFntPrint(); //FntPrint(currentFontStream, "\t\thsync: %d\n", hsync); //FntPrint(currentFontStream, "\t\tmaxHsync: %d\n", maxHsync); CalculateCurrentFrameRate(hsync); SortAllShipsParametersByFrameRate(); if (TheTunnelDescription.tunnelHighlightFlag == TRUE) { ResetDataDueToHighlighting(); } if (frameNumber == 60) maxHsync = hsync; else if (maxHsync > 1500) { //PRINT("massive hsync: %d\n", maxHsync); maxHsync = 0; } if (FrameRateDivider > 1) { if (frameNumber % 30 == 0) { PRINT("MISSING A FRAME\n"); } } FntFlush(currentFontStream); frameNumber++; if (GlobalPauseFlag == FALSE) RaceFrameCounter++; if (EndRaceNowFlag == TRUE) { #if (REDUCE_RESOLUTION_FOR_TWO_PLAYER_MODE==1) ResetGraphicResolution(640, 480); #endif ShowTwoPlayerRaceResults(); SetANewGameState(SETTING_UP_TWO_PLAYER_RACE); } assert(RollingDemoActiveFlag == FALSE); } } void DrawTheRacingShips (GsOT *ot, int otShift) { int i; ObjectHandler *object; int sectionID; MATRIX matrix; assert(NumberOfShipsInRace > 0); assert(NumberOfShipsInRace <= MAX_SHIPS_PER_RACE); for (i = 0; i < NumberOfShipsInRace; i++) { if (ShipsInTunnel[i] != NULL) { object = ShipsInTunnel[i]; if (object->displayFlag != TMD) continue; if (object == TheViewShip) // don't draw { if (ViewModeProhibitsDrawing(object)) continue; } sectionID = object->tunnelSection; assert(ValidID(sectionID)); // Ship clipping on basis of tunnel start&end // drawing sections // ALSO RELIES ON assignment to these two // currently done in DrawTheTunnelPolygons // should be done elsewhere (before) if (SectionBetweenLimits(sectionID, StartDrawingSectionId, EndDrawingSectionId) == FALSE) continue; GsGetLs(&(object->coord), &matrix); // local to screen matrix GsSetLightMatrix(&matrix); GsSetLsMatrix(&matrix); HandleGlobalShipLightingEffect( &matrix); GsSortObject4( &(object->handler), ot, otShift, getScratchAddr(0)); } } } // NOTE that the increase-brightness effect seriously // accentuates the Colours of flat lights: // ship turns noticably green/blue/red // and this Interferes with the effect of environment mapping // - could use much weaker flat lights, or less coloured ones void HandleGlobalShipLightingEffect (MATRIX *matrix) { int i, j; int period, time, cycleRatio, factor, temp; int periodFlag, firstFactor, secondFactor, withinCycleRatio; switch(GlobalShipLightingEffectFlag) { case NONE: // do nowt break; case FIRST: for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { matrix->m[i][j] <<= 1; } break; case SECOND: for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { matrix->m[i][j] <<= 2; } break; case THIRD: for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { matrix->m[i][j] <<= 3; } break; case FOURTH: for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { matrix->m[i][j] *= 3; } break; case FIFTH: // x matrix->m[0][0] <<= 2; matrix->m[1][0] <<= 2; matrix->m[2][0] <<= 2; break; case SIXTH: // y matrix->m[0][1] <<= 2; matrix->m[1][1] <<= 2; matrix->m[2][1] <<= 2; break; case SEVENTH: // z matrix->m[0][2] <<= 2; matrix->m[1][2] <<= 2; matrix->m[2][2] <<= 2; break; case EIGHTH: // x matrix->m[0][0] <<= 2; matrix->m[0][1] <<= 2; matrix->m[0][2] <<= 2; break; case NINTH: // y matrix->m[1][0] <<= 2; matrix->m[1][1] <<= 2; matrix->m[1][2] <<= 2; break; case TENTH: // z matrix->m[2][0] <<= 2; matrix->m[2][1] <<= 2; matrix->m[2][2] <<= 2; break; case ELEVENTH: // oscillate brightness accentuation assert(MaximumGameFramesPerSecond > 0); period = MaximumGameFramesPerSecond * 2; time = frameNumber % period; cycleRatio = (time << 12) / period; if (cycleRatio < 2048) { factor = (2 * ONE) + (cycleRatio * 4); } else { factor = (4 * ONE) - ((cycleRatio-2048) * 4); } assert(factor >= (2*ONE)); assert(factor <= (4*ONE)); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { temp = (matrix->m[i][j] * factor) >> 12; assert(temp < 32768 && temp > -32768); matrix->m[i][j] = temp; } break; case TWELFTH: // oscillate which axis to highlight assert(MaximumGameFramesPerSecond > 0); period = MaximumGameFramesPerSecond * 2; time = frameNumber % period; cycleRatio = (time << 12) / period; periodFlag = (cycleRatio * 3) >> 12; switch(periodFlag) { case 0: withinCycleRatio = cycleRatio; firstFactor = withinCycleRatio * 12 * ONE; secondFactor = (4*ONE) - firstFactor; for (i = 0; i < 3; i++) { temp = (matrix->m[i][0] * firstFactor) >> 12; assert(temp < 32768 && temp > -32768); matrix->m[i][0] = temp; temp = (matrix->m[i][1] * secondFactor) >> 12; assert(temp < 32768 && temp > -32768); matrix->m[i][1] = temp; } break; case 1: withinCycleRatio = cycleRatio - (ONE/3); firstFactor = withinCycleRatio * 12 * ONE; secondFactor = (4*ONE) - firstFactor; for (i = 0; i < 3; i++) { temp = (matrix->m[i][1] * firstFactor) >> 12; assert(temp < 32768 && temp > -32768); matrix->m[i][1] = temp; temp = (matrix->m[i][2] * secondFactor) >> 12; assert(temp < 32768 && temp > -32768); matrix->m[i][2] = temp; } break; case 2: withinCycleRatio = cycleRatio - ((2*ONE)/3); firstFactor = withinCycleRatio * 12 * ONE; secondFactor = (4*ONE) - firstFactor; for (i = 0; i < 3; i++) { temp = (matrix->m[i][2] * firstFactor) >> 12; assert(temp < 32768 && temp > -32768); matrix->m[i][2] = temp; temp = (matrix->m[i][0] * secondFactor) >> 12; assert(temp < 32768 && temp > -32768); matrix->m[i][0] = temp; } break; default: assert(FALSE); } break; default: assert(FALSE); } GsSetLightMatrix(matrix); } #define CLOSING_SEQUENCE_FLAG 1 // 8 #define NUM_STRS_HERE 12 // 2 #define NUM_SCREENS_HERE 1 void ClosingSequenceLoop (void) { #if CLOSING_SEQUENCE_FLAG char AllCreditStrings[3][NUM_STRS_HERE][50]; int bufferIndex; int closingSequenceStartFrame; int closingSequenceEachScreenDuration = MaximumGameFramesPerSecond * 6; // 4 int whichScreen; int numberStringsThisScreen; int stringLength; int highlightedString; int x, y; int index, i; int frameWithinClosingSequence, frameWithinThisScreen; strcpy(AllCreditStrings[0][0], "With thanks to"); strcpy(AllCreditStrings[0][1], "--------------"); strcpy(AllCreditStrings[0][2], "Vince Diesi"); strcpy(AllCreditStrings[0][3], "Stuart Ashley"); strcpy(AllCreditStrings[0][4], "Colin Hughes"); strcpy(AllCreditStrings[0][5], "Jason Page"); strcpy(AllCreditStrings[0][6], "Malachy Duffin"); strcpy(AllCreditStrings[0][7], "Richard Evans"); strcpy(AllCreditStrings[0][8], "Sarah Bennett"); strcpy(AllCreditStrings[0][9], "Paul Holman"); strcpy(AllCreditStrings[0][10], ""); strcpy(AllCreditStrings[0][11], ""); closingSequenceStartFrame = frameNumber; whichScreen = 0; assert(closingSequenceEachScreenDuration != 0); bufferIndex = GsGetActiveBuff(); for (;;) { HandleSound(); frameWithinClosingSequence = frameNumber - closingSequenceStartFrame; whichScreen = frameWithinClosingSequence / closingSequenceEachScreenDuration; if (whichScreen > (NUM_SCREENS_HERE-1)) { break; } frameWithinThisScreen = frameWithinClosingSequence - (whichScreen * closingSequenceEachScreenDuration); numberStringsThisScreen = 0; for (i = 0; i < NUM_STRS_HERE; i++) { if (strlen(AllCreditStrings[whichScreen][i]) > 0) numberStringsThisScreen++; } highlightedString = ((frameWithinThisScreen * (numberStringsThisScreen-2)) / closingSequenceEachScreenDuration) + 2; switch(ScreenResolution) { case LOW_RES: y = -10 * numberStringsThisScreen; break; case HI_RES: y = -20 * numberStringsThisScreen; break; default: assert(FALSE); } for (index = 0; index < numberStringsThisScreen; index++) { stringLength = strlen(AllCreditStrings[whichScreen][index]); switch(ScreenResolution) { case LOW_RES: x = (-stringLength * 8) / 2; break; case HI_RES: x = (-stringLength * 16) / 2; break; default: assert(FALSE); } if (index == 0 || index == 1) RegisterTextStringForDisplay(AllCreditStrings[whichScreen][index], x, y, CYAN_COLOUR); else if (index == highlightedString) RegisterTextStringForDisplay(AllCreditStrings[whichScreen][index], x, y, RED_COLOUR); else RegisterTextStringForDisplay(AllCreditStrings[whichScreen][index], x, y, NORMAL_COLOUR); switch(ScreenResolution) { case LOW_RES: if (index == 1) y += 30; else y += 20; break; case HI_RES: if (index == 1) y += 60; else y += 40; break; default: assert(FALSE); } } GsSetRefView2( &TheView); GsSetWorkBase( (PACKET*)packetArea[bufferIndex]); GsClearOt(0, 0, &Wot[bufferIndex]); DisplayTextStrings (&Wot[bufferIndex]); DrawSync(0); VSync(0); GsSwapDispBuff(); GsSortClear(0, 0, 0, &Wot[bufferIndex]); GsDrawOt(&Wot[bufferIndex]); bufferIndex = GsGetActiveBuff(); FntFlush(currentFontStream); frameNumber++; } #else { //PRINT("Closing Sequence: nothing happening here yet\n"); } #endif } void GuiLoopForViewingTheTracks (void) { int i; bufferIndex = GsGetActiveBuff(); while (ViewingTheTracksQuitFlag == FALSE) { HandleSound(); DealWithControllerPad(); if (StateChangeWaitingFlag == TRUE) return; HandleTrackViewer(); if (StateChangeWaitingFlag == TRUE) return; HandleTheView(); UpdateTheTunnel(); switch(TrackViewerMainMode) { case VIEW_TRACK_FROM_INSIDE: GsSetWorkBase( (PACKET*)packetArea[bufferIndex]); break; case VIEW_TRACK_FROM_OUTSIDE: SetPacketAreaInSystem (USE_BOTH_PACKET_AREAS, bufferIndex); break; default: assert(FALSE); } GsClearOt(0, 0, &Wot[bufferIndex]); //PutStackOntoDataCache(); DrawTheTunnelPolygons( &Wot[bufferIndex], OT_SHIFT); //RestoreStackFromDataCache(); cpuLoad = VSync(1); //DrawSync(0); // PROVES UNNECESSARY: game faster without it gpuLoad = VSync(1); hsync = VSync(0); GsSwapDispBuff(); GsSortClear(0, 0, 0, &Wot[bufferIndex]); GsDrawOt(&Wot[bufferIndex]); if (TheTunnelDescription.tunnelHighlightFlag == TRUE) { ResetDataDueToHighlighting(); } bufferIndex = GsGetActiveBuff(); CalculateCurrentFrameRate(hsync); SortAllShipsParametersByFrameRate(); if (frameNumber == 60) maxHsync = hsync; else if (maxHsync > 1500) { //PRINT("massive hsync: %d\n", maxHsync); maxHsync = 0; } if (FrameRateDivider > 1) // dropping frames { if (frameNumber % 120 == 0) { PRINT("MISSING A FRAME\n"); } } FntFlush(currentFontStream); frameNumber++; DealWithControlsForTrackViewer(); if (frameLimiter > 1) // slow game down { for (i = 0; i < frameLimiter-1; i++) VSync(0); } if (RollingDemoActiveFlag == TRUE) { // every once in a while, set new demo if ( ((frameNumber - RollingDemoStartFrame) % (MaximumGameFramesPerSecond * 24)) == 0) { SortOutANewRollingDemo(); } if (RollingDemoDeliberateFlag == FALSE) { if (frameNumber - RollingDemoStartFrame >= ROLLING_DEMO_NATURAL_DURATION) { SetANewGameState(MAIN_MENU); } } } } } void DealWithControlsForTrackViewer (void) { long pad; int trackViewerFramePause = 15; static int framesSinceLastSpeedChange = 0; assert(FrameRateDivider >= 1); pad = PadRead(0); FramesSinceLastUserSelection++; framesSinceLastSpeedChange++; switch(TrackViewerMainMode) { case VIEW_TRACK_FROM_INSIDE: if (RollingDemoActiveFlag == TRUE && RollingDemoDeliberateFlag == FALSE) { if ( ((frameNumber - FrameWhenTrackViewingStarts) > ROLLING_DEMO_NATURAL_DURATION) || pad != 0) { RollingDemoActiveFlag = FALSE; RollingDemoStartFrame = -1; SetANewGameState(MAIN_MENU); } } if (FramesSinceLastUserSelection > trackViewerFramePause) { if (pad & PADselect) // end track viewing { if (RollingDemoActiveFlag == TRUE) { RollingDemoActiveFlag = FALSE; RollingDemoStartFrame = -1; if (RollingDemoDeliberateFlag == TRUE) SetANewGameState(SETTING_UP_ROLLING_DEMO); else SetANewGameState(MAIN_MENU); } else SetANewGameState(SETTING_UP_TRACK_VIEWING); } // triangle: reverse direction of camera movement if (pad & PADRup) { TrackViewerDirection = ANTI_DIRECTION(TrackViewerDirection); ViewerObject.discreteSpeed = -ViewerObject.discreteSpeed; FramesSinceLastUserSelection = 0; } } switch(TrackViewerCameraControlMode) { case TRACK_VIEWER_USER_CONTROLLED_CAMERA: // ok, have control break; case TRACK_VIEWER_AUTO_CAMERA: // no controls return; break; default: assert(FALSE); } // L1 and R1: change Z angle of view if (pad & PADLleft) TrackViewerZAngle -= 3 * FrameRateDivider; if (pad & PADLright) TrackViewerZAngle += 3 * FrameRateDivider; while (TrackViewerZAngle >= 360) TrackViewerZAngle -= 360; while (TrackViewerZAngle < 0) TrackViewerZAngle += 360; if (pad & PADRdown && framesSinceLastSpeedChange > 5) { switch(TrackViewerDirection) { case FORWARDS: if (ViewerObject.discreteSpeed < MAXIMUM_SPEED_32) { ViewerObject.discreteSpeed += FrameRateDivider; framesSinceLastSpeedChange = 0; return; } break; case BACKWARDS: if (ViewerObject.discreteSpeed > -MAXIMUM_SPEED_32) { ViewerObject.discreteSpeed -= FrameRateDivider; framesSinceLastSpeedChange = 0; return; } break; default: assert(FALSE); } } if (pad & PADRleft && framesSinceLastSpeedChange > 5) { switch(TrackViewerDirection) { case FORWARDS: if (ViewerObject.discreteSpeed > NORMAL_SPEED_32) { ViewerObject.discreteSpeed -= FrameRateDivider; framesSinceLastSpeedChange = 0; return; } break; case BACKWARDS: if (ViewerObject.discreteSpeed < -NORMAL_SPEED_32) { ViewerObject.discreteSpeed += FrameRateDivider; framesSinceLastSpeedChange = 0; return; } break; default: assert(FALSE); } } break; case VIEW_TRACK_FROM_OUTSIDE: // six rotations, zoom in and out if (FramesSinceLastUserSelection > trackViewerFramePause) { if (pad & PADselect) // end track viewing { if (RollingDemoActiveFlag == TRUE) { RollingDemoActiveFlag = FALSE; RollingDemoStartFrame = -1; if (RollingDemoDeliberateFlag == TRUE) SetANewGameState(SETTING_UP_ROLLING_DEMO); else SetANewGameState(MAIN_MENU); } else { SetANewGameState(SETTING_UP_TRACK_VIEWING); } } } switch(TrackViewerCameraControlMode) { case TRACK_VIEWER_USER_CONTROLLED_CAMERA: // ok, have control break; case TRACK_VIEWER_AUTO_CAMERA: // no controls return; break; default: assert(FALSE); } if (pad & PADLup) { TrackViewerWholeTrackCoordTwist.vx += 32 * FrameRateDivider; return; } if (pad & PADLdown) { TrackViewerWholeTrackCoordTwist.vx -= 32 * FrameRateDivider; return; } if (pad & PADLleft) { TrackViewerWholeTrackCoordTwist.vy += 32 * FrameRateDivider; return; } if (pad & PADLright) { TrackViewerWholeTrackCoordTwist.vy -= 32 * FrameRateDivider; return; } if (pad & PADL1) { TrackViewerWholeTrackCoordTwist.vz += 32 * FrameRateDivider; return; } if (pad & PADL2) { TrackViewerWholeTrackCoordTwist.vz -= 32 * FrameRateDivider; return; } // zoom in and out if (pad & PADRup) { TrackViewerWholeTrackCentreDistance -= 512 * FrameRateDivider; if (TrackViewerWholeTrackCentreDistance < MINIMUM_WHOLE_TRACK_CENTRE_DISTANCE) TrackViewerWholeTrackCentreDistance = MINIMUM_WHOLE_TRACK_CENTRE_DISTANCE; TheView.vpz = -TrackViewerWholeTrackCentreDistance; return; } if (pad & PADRdown) { TrackViewerWholeTrackCentreDistance += 512 * FrameRateDivider; if (TrackViewerWholeTrackCentreDistance > MAXIMUM_WHOLE_TRACK_CENTRE_DISTANCE) TrackViewerWholeTrackCentreDistance = MAXIMUM_WHOLE_TRACK_CENTRE_DISTANCE; TheView.vpz = -TrackViewerWholeTrackCentreDistance; return; } if (FramesSinceLastUserSelection > trackViewerFramePause) { if (pad & PADselect) { SetANewGameState(SETTING_UP_TRACK_VIEWING); } } break; default: assert(FALSE); } } char FreePracticeString1[] = "Tie Fighter"; char FreePracticeString2[] = "Sea Shell"; char FreePracticeString3[] = "light cruiser"; char FreePracticeString4[] = "heavy bomber"; char FreePracticeString5[] = "Pincer crab"; char FreePracticeString6[] = "Spy Plane"; char FreePracticeString7[] = "Metal Dart"; MenuOption SettingUpFreePracticeScreenOptions[4]; MenuScreen SettingUpFreePracticeScreen; void GuiLoopForSettingUpFreePractice (void) { CreateMenuOption( &SettingUpFreePracticeScreenOptions[0], TAKE_ACTION, "Start free practice", 0, 0, START_FREE_PRACTICE, NULL); CreateMenuOption( &SettingUpFreePracticeScreenOptions[1], CHOOSE_INTEGER, "Track ", 1, NUMBER_SET_TRACKS, -1, &ChosenTrackNumber); CreateMenuOption( &SettingUpFreePracticeScreenOptions[2], CHOOSE_INTEGER, "Ship Model ", 0, NUMBER_SHIP_MODELS-1, -1, &PlayerOneModelNumber); SetMenuOptionInstantResponse( &SettingUpFreePracticeScreenOptions[2], &SetPlayerOnesShipModel); SetMenuOptionString( &SettingUpFreePracticeScreenOptions[2], 1, FreePracticeString1); SetMenuOptionString( &SettingUpFreePracticeScreenOptions[2], 2, FreePracticeString2); SetMenuOptionString( &SettingUpFreePracticeScreenOptions[2], 3, FreePracticeString3); SetMenuOptionString( &SettingUpFreePracticeScreenOptions[2], 4, FreePracticeString4); SetMenuOptionString( &SettingUpFreePracticeScreenOptions[2], 5, FreePracticeString5); SetMenuOptionString( &SettingUpFreePracticeScreenOptions[2], 6, FreePracticeString6); SetMenuOptionString( &SettingUpFreePracticeScreenOptions[2], 7, FreePracticeString7); CreateMenuOption( &SettingUpFreePracticeScreenOptions[3], TAKE_ACTION, "Return to main menu", 0, 0, QUIT_BACK_TO_LEVEL_ABOVE, NULL); CreateMenuScreen( &SettingUpFreePracticeScreen, 4, SettingUpFreePracticeScreenOptions); SetMenuScreenPauseTimes( &SettingUpFreePracticeScreen, 8, 5); // 10, 7 SetMenuScreenBackgroundEffect( &SettingUpFreePracticeScreen, SECOND_EFFECT_SWITCHER); // start rolling demo after twelve seconds of inactivity SetMenuScreenTimeoutTime( &SettingUpFreePracticeScreen, MaximumGameFramesPerSecond * 12); bufferIndex = GsGetActiveBuff(); HandleMenuScreen(&SettingUpFreePracticeScreen); // handle action taken switch (SettingUpFreePracticeScreen.quitCode) { case TIMEOUT_QUIT_CODE: // when left unattended PrepareRollingDemo(FALSE); break; case QUIT_BACK_TO_LEVEL_ABOVE: MakeClunk(); SetANewGameState(MAIN_MENU); break; case START_FREE_PRACTICE: MakeClunk(); SetUpAFreePracticeSession(); SetANewGameState(DURING_THE_RACE); break; default: assert(FALSE); } } MenuOption SettingUpStraightRaceScreenOptions[6]; MenuScreen SettingUpStraightRaceScreen; void GuiLoopForSettingUpStraightRace (void) { CreateMenuOption( &SettingUpStraightRaceScreenOptions[0], TAKE_ACTION, "Go ahead and race", 0, 0, START_STRAIGHT_RACE, NULL); CreateMenuOption( &SettingUpStraightRaceScreenOptions[1], CHOOSE_INTEGER, "Track ", 1, NUMBER_SET_TRACKS, -1, &ChosenTrackNumber); CreateMenuOption( &SettingUpStraightRaceScreenOptions[2], CHOOSE_INTEGER, "Ship Model ", 0, NUMBER_SHIP_MODELS-1, -1, &PlayerOneModelNumber); SetMenuOptionInstantResponse( &SettingUpStraightRaceScreenOptions[2], &SetPlayerOnesShipModel); SetMenuOptionString( &SettingUpStraightRaceScreenOptions[2], 1, FreePracticeString1); SetMenuOptionString( &SettingUpStraightRaceScreenOptions[2], 2, FreePracticeString2); SetMenuOptionString( &SettingUpStraightRaceScreenOptions[2], 3, FreePracticeString3); SetMenuOptionString( &SettingUpStraightRaceScreenOptions[2], 4, FreePracticeString4); SetMenuOptionString( &SettingUpStraightRaceScreenOptions[2], 5, FreePracticeString5); SetMenuOptionString( &SettingUpStraightRaceScreenOptions[2], 6, FreePracticeString6); SetMenuOptionString( &SettingUpStraightRaceScreenOptions[2], 7, FreePracticeString7); CreateMenuOption( &SettingUpStraightRaceScreenOptions[3], CHOOSE_INTEGER, "Number of other drivers ", 1, MAX_SHIPS_PER_RACE-1, -1, &ChosenNumberOfDrivers); CreateMenuOption( &SettingUpStraightRaceScreenOptions[4], CHOOSE_INTEGER, "Number of laps ", 1, MAX_LAPS_IN_RACE, -1, &ChosenNumberOfLaps); CreateMenuOption( &SettingUpStraightRaceScreenOptions[5], TAKE_ACTION, "Return to main menu", 0, 0, QUIT_BACK_TO_LEVEL_ABOVE, NULL); CreateMenuScreen( &SettingUpStraightRaceScreen, 6, SettingUpStraightRaceScreenOptions); SetMenuScreenPauseTimes( &SettingUpStraightRaceScreen, 8, 5); // 10, 7 SetMenuScreenBackgroundEffect( &SettingUpStraightRaceScreen, SECOND_EFFECT_SWITCHER); // start rolling demo after twelve seconds of inactivity SetMenuScreenTimeoutTime( &SettingUpStraightRaceScreen, MaximumGameFramesPerSecond * 12); bufferIndex = GsGetActiveBuff(); HandleMenuScreen(&SettingUpStraightRaceScreen); // handle action taken switch (SettingUpStraightRaceScreen.quitCode) { case TIMEOUT_QUIT_CODE: // when left unattended PrepareRollingDemo(FALSE); break; case QUIT_BACK_TO_LEVEL_ABOVE: MakeClunk(); SetANewGameState(MAIN_MENU); break; case START_STRAIGHT_RACE: MakeClunk(); SetUpAFullRace(); SetANewGameState(DURING_THE_RACE); break; default: assert(FALSE); } } MenuOption SettingUpTwoPlayerRaceScreenOptions[6]; MenuScreen SettingUpTwoPlayerRaceScreen; void GuiLoopForSettingUpTwoPlayerRace (void) { CreateMenuOption( &SettingUpTwoPlayerRaceScreenOptions[0], TAKE_ACTION, "Start race", 0, 0, START_TWO_PLAYER_RACE, NULL); CreateMenuOption( &SettingUpTwoPlayerRaceScreenOptions[1], CHOOSE_INTEGER, "Player 1 Ship ", 0, NUMBER_SHIP_MODELS-1, -1, &PlayerOneModelNumber); SetMenuOptionInstantResponse( &SettingUpTwoPlayerRaceScreenOptions[1], &SetPlayerOnesShipModel); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[1], 1, FreePracticeString1); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[1], 2, FreePracticeString2); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[1], 3, FreePracticeString3); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[1], 4, FreePracticeString4); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[1], 5, FreePracticeString5); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[1], 6, FreePracticeString6); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[1], 7, FreePracticeString7); CreateMenuOption( &SettingUpTwoPlayerRaceScreenOptions[2], CHOOSE_INTEGER, "Player 2 Ship ", 0, NUMBER_SHIP_MODELS-1, -1, &PlayerTwoModelNumber); SetMenuOptionInstantResponse( &SettingUpTwoPlayerRaceScreenOptions[2], &SetPlayerTwosShipModel); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[2], 1, FreePracticeString1); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[2], 2, FreePracticeString2); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[2], 3, FreePracticeString3); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[2], 4, FreePracticeString4); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[2], 5, FreePracticeString5); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[2], 6, FreePracticeString6); SetMenuOptionString( &SettingUpTwoPlayerRaceScreenOptions[2], 7, FreePracticeString7); CreateMenuOption( &SettingUpTwoPlayerRaceScreenOptions[3], CHOOSE_INTEGER, "Track ", 1, NUMBER_SET_TRACKS, -1, &ChosenTrackNumber); CreateMenuOption( &SettingUpTwoPlayerRaceScreenOptions[4], CHOOSE_INTEGER, "Number of laps ", 1, MAX_LAPS_IN_RACE, -1, &ChosenNumberOfLaps); CreateMenuOption( &SettingUpTwoPlayerRaceScreenOptions[5], TAKE_ACTION, "Return to main menu", 0, 0, QUIT_BACK_TO_LEVEL_ABOVE, NULL); CreateMenuScreen( &SettingUpTwoPlayerRaceScreen, 6, SettingUpTwoPlayerRaceScreenOptions); SetMenuScreenPauseTimes( &SettingUpTwoPlayerRaceScreen, 8, 5); // 10, 7 SetMenuScreenBackgroundEffect( &SettingUpTwoPlayerRaceScreen, TWO_SHIPS_ROTATE_SLOWLY); // start rolling demo after twelve seconds of inactivity SetMenuScreenTimeoutTime( &SettingUpTwoPlayerRaceScreen, MaximumGameFramesPerSecond * 12); bufferIndex = GsGetActiveBuff(); HandleMenuScreen(&SettingUpTwoPlayerRaceScreen); // handle action taken switch (SettingUpTwoPlayerRaceScreen.quitCode) { case TIMEOUT_QUIT_CODE: // when left unattended PrepareRollingDemo(FALSE); break; case QUIT_BACK_TO_LEVEL_ABOVE: MakeClunk(); SetANewGameState(MAIN_MENU); break; case START_TWO_PLAYER_RACE: MakeClunk(); SetUpTwoPlayerRace(); SetANewGameState(TWO_PLAYER_RACE); break; default: assert(FALSE); } } MenuOption SettingUpTrackViewingScreenOptions[7]; MenuScreen SettingUpTrackViewingScreen; char TrackViewingString1[] = "Inside"; char TrackViewingString2[] = "Outside"; char TrackViewingString3[] = "User"; char TrackViewingString4[] = "Auto"; char TrackViewingString13[] = "forwards"; char TrackViewingString14[] = "backwards"; char TrackViewingString5[] = "slow"; char TrackViewingString6[] = "faster"; char TrackViewingString7[] = "super fast"; char TrackViewingString8[] = "twister"; char TrackViewingString9[] = "rollercoaster 1"; char TrackViewingString10[] = "rollercoaster 2"; char TrackViewingString11[] = "rollercoaster 3"; char TrackViewingString12[] = "swivel camera"; void GuiLoopForSettingUpTrackViewing (void) { ResetTrackViewingData(); CreateMenuOption( &SettingUpTrackViewingScreenOptions[0], TAKE_ACTION, "Start track viewing", 0, 0, START_TRACK_VIEWING, NULL); CreateMenuOption( &SettingUpTrackViewingScreenOptions[1], CHOOSE_INTEGER, "Track ", 1, NUMBER_SET_TRACKS, -1, &ChosenTrackNumber); CreateMenuOption( &SettingUpTrackViewingScreenOptions[2], CHOOSE_INTEGER, "View track from", VIEW_TRACK_FROM_INSIDE, VIEW_TRACK_FROM_OUTSIDE, -1, &TrackViewerMainMode); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[2], 1, TrackViewingString1); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[2], 2, TrackViewingString2); CreateMenuOption( &SettingUpTrackViewingScreenOptions[3], CHOOSE_INTEGER, "Camera Control", TRACK_VIEWER_USER_CONTROLLED_CAMERA, TRACK_VIEWER_AUTO_CAMERA, -1, &TrackViewerCameraControlMode); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[3], 1, TrackViewingString3); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[3], 2, TrackViewingString4); CreateMenuOption( &SettingUpTrackViewingScreenOptions[4], CHOOSE_INTEGER, "Track viewer direction", FORWARDS, BACKWARDS, -1, &TrackViewerDirection); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[4], 1, TrackViewingString13); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[4], 2, TrackViewingString14); CreateMenuOption( &SettingUpTrackViewingScreenOptions[5], CHOOSE_INTEGER, "Auto camera mode", TRACK_VIEWER_AUTO_CAMERA_SLOW_MODE, TRACK_VIEWER_AUTO_CAMERA_ZOOM_ROLLERCOASTER_MODE, -1, &TrackViewerAutoCameraMode); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[5], 1, TrackViewingString5); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[5], 2, TrackViewingString6); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[5], 3, TrackViewingString7); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[5], 4, TrackViewingString8); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[5], 5, TrackViewingString9); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[5], 6, TrackViewingString10); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[5], 7, TrackViewingString11); SetMenuOptionString( &SettingUpTrackViewingScreenOptions[5], 8, TrackViewingString12); CreateMenuOption( &SettingUpTrackViewingScreenOptions[6], TAKE_ACTION, "Return to main menu", 0, 0, QUIT_BACK_TO_LEVEL_ABOVE, NULL); CreateMenuScreen( &SettingUpTrackViewingScreen, 7, SettingUpTrackViewingScreenOptions); SetMenuScreenPauseTimes( &SettingUpTrackViewingScreen, 8, 5); // 10, 7 SetMenuScreenBackgroundEffect( &SettingUpTrackViewingScreen, SECOND_EFFECT_SWITCHER); // start rolling demo after twelve seconds of inactivity SetMenuScreenTimeoutTime( &SettingUpTrackViewingScreen, MaximumGameFramesPerSecond * 12); bufferIndex = GsGetActiveBuff(); HandleMenuScreen(&SettingUpTrackViewingScreen); // handle action taken switch (SettingUpTrackViewingScreen.quitCode) { case TIMEOUT_QUIT_CODE: // when left unattended PrepareRollingDemo(FALSE); break; case QUIT_BACK_TO_LEVEL_ABOVE: MakeClunk(); SetANewGameState(MAIN_MENU); break; case START_TRACK_VIEWING: MakeClunk(); PrepareTheTrackForViewing(); SetANewGameState(VIEWING_THE_TRACKS); break; default: assert(FALSE); } } MenuOption SettingUpRollingDemoScreenOptions[8]; MenuScreen SettingUpRollingDemoScreen; char RollingDemoString1[] = "track viewing"; char RollingDemoString2[] = "solo flier"; char RollingDemoString3[] = "race"; char RollingDemoString4[] = "slow"; char RollingDemoString5[] = "faster"; char RollingDemoString6[] = "super fast"; char RollingDemoString7[] = "twister"; char RollingDemoString8[] = "rollercoaster 1"; char RollingDemoString9[] = "rollercoaster 2"; char RollingDemoString10[] = "rollercoaster 3"; char RollingDemoString11[] = "inside"; char RollingDemoString12[] = "outside"; char RollingDemoString13[] = "behind and above"; char RollingDemoString14[] = "behind and below"; char RollingDemoString15[] = "local"; char RollingDemoString16[] = "circling close in"; char RollingDemoString17[] = "circling"; char RollingDemoString18[] = "circling twisting"; char RollingDemoString19[] = "circling wide"; char RollingDemoString20[] = "circling wide twisting"; char RollingDemoString21[] = "circling on sphere"; char RollingDemoString22[] = "first elliptical"; char RollingDemoString23[] = "second elliptical"; char RollingDemoString24[] = "third elliptical"; char RollingDemoString25[] = "fourth elliptical"; char RollingDemoString26[] = "cardinal flyby"; char RollingDemoString27[] = "static flyby"; char RollingDemoString28[] = "head on flyby"; char RollingDemoString29[] = "first moving flyby"; char RollingDemoString30[] = "second moving flyby"; char RollingDemoString31[] = "third moving flyby"; char RollingDemoString32[] = "fourth moving flyby"; char RollingDemoString33[] = "first cuboid"; char RollingDemoString34[] = "second cuboid"; char RollingDemoString35[] = "third cuboid"; char RollingDemoString36[] = "first spherical"; char RollingDemoString37[] = "second spherical"; char RollingDemoString38[] = "third spherical"; char RollingDemoString39[] = "fourth spherical"; char RollingDemoString40[] = "first helical"; char RollingDemoString41[] = "second helical"; char RollingDemoString42[] = "third helical"; char RollingDemoString43[] = "fourth helical"; char RollingDemoString44[] = "first cube-circling"; char RollingDemoString45[] = "second cube-circling"; char RollingDemoString46[] = "head on static"; char RollingDemoString47[] = "off centre static"; char RollingDemoString48[] = "local backwards"; char RollingDemoString49[] = "external ahead"; char RollingDemoString50[] = "external behind"; char RollingDemoString51[] = "external left"; char RollingDemoString52[] = "external right"; char RollingDemoString53[] = "external above"; char RollingDemoString54[] = "external below"; char RollingDemoString55[] = "first lazy rotation"; char RollingDemoString56[] = "second lazy rotation"; char RollingDemoString57[] = "third lazy rotation"; char RollingDemoString58[] = "circles behind"; char RollingDemoString59[] = "swivels behind"; char RollingDemoString60[] = "first director's cut"; char RollingDemoString61[] = "second director's cut"; char RollingDemoString62[] = "third director's cut"; char RollingDemoString63[] = "fourth director's cut"; void GuiLoopForSettingUpRollingDemo (void) { CreateMenuOption( &SettingUpRollingDemoScreenOptions[0], TAKE_ACTION, "Start rolling demo", 0, 0, START_ROLLING_DEMO, NULL); CreateMenuOption( &SettingUpRollingDemoScreenOptions[1], CHOOSE_INTEGER, "Demo mode ", ROLLING_DEMO_TRACK_VIEWING, ROLLING_DEMO_AI_FLIERS_RACE, -1, &RollingDemoMainMode); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[1], 1, RollingDemoString1); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[1], 2, RollingDemoString2); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[1], 3, RollingDemoString3); CreateMenuOption( &SettingUpRollingDemoScreenOptions[2], CHOOSE_INTEGER, "Track viewer mode ", TRACK_VIEWER_AUTO_CAMERA_SLOW_MODE, TRACK_VIEWER_AUTO_CAMERA_ZOOM_ROLLERCOASTER_MODE, -1, &TrackViewerAutoCameraMode); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[2], 1, RollingDemoString4); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[2], 2, RollingDemoString5); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[2], 3, RollingDemoString6); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[2], 4, RollingDemoString7); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[2], 5, RollingDemoString8); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[2], 6, RollingDemoString9); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[2], 7, RollingDemoString10); CreateMenuOption( &SettingUpRollingDemoScreenOptions[3], CHOOSE_INTEGER, "View track from ", VIEW_TRACK_FROM_INSIDE, VIEW_TRACK_FROM_OUTSIDE, -1, &TrackViewerMainMode); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[3], 1, RollingDemoString11); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[3], 2, RollingDemoString12); CreateMenuOption( &SettingUpRollingDemoScreenOptions[4], CHOOSE_INTEGER, "Ship model ", 0, NUMBER_SHIP_MODELS-1, -1, &RollingDemoAiFlierModelNumber); SetMenuOptionInstantResponse( &SettingUpRollingDemoScreenOptions[4], &SetFirstOtherShipModel); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[4], 1, FreePracticeString1); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[4], 2, FreePracticeString2); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[4], 3, FreePracticeString3); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[4], 4, FreePracticeString4); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[4], 5, FreePracticeString5); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[4], 6, FreePracticeString6); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[4], 7, FreePracticeString7); CreateMenuOption( &SettingUpRollingDemoScreenOptions[5], CHOOSE_INTEGER, "Ship view mode ", BASE_VIEW_MODE, BASE_VIEW_MODE + NUMBER_OF_SHIP_VIEW_MODES - 1, -1, &TrackViewerShipViewMode); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 1, RollingDemoString13); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 2, RollingDemoString14); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 3, RollingDemoString15); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 4, RollingDemoString16); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 5, RollingDemoString17); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 6, RollingDemoString18); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 7, RollingDemoString19); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 8, RollingDemoString20); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 9, RollingDemoString21); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 10, RollingDemoString22); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 11, RollingDemoString23); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 12, RollingDemoString24); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 13, RollingDemoString25); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 14, RollingDemoString26); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 15, RollingDemoString27); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 16, RollingDemoString28); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 17, RollingDemoString29); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 18, RollingDemoString30); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 19, RollingDemoString31); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 20, RollingDemoString32); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 21, RollingDemoString33); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 22, RollingDemoString34); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 23, RollingDemoString35); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 24, RollingDemoString36); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 25, RollingDemoString37); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 26, RollingDemoString38); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 27, RollingDemoString39); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 28, RollingDemoString40); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 29, RollingDemoString41); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 30, RollingDemoString42); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 31, RollingDemoString43); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 32, RollingDemoString44); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 33, RollingDemoString45); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 34, RollingDemoString46); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 35, RollingDemoString47); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 36, RollingDemoString48); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 37, RollingDemoString49); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 38, RollingDemoString50); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 39, RollingDemoString51); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 40, RollingDemoString52); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 41, RollingDemoString53); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 42, RollingDemoString54); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 43, RollingDemoString55); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 44, RollingDemoString56); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 45, RollingDemoString57); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 46, RollingDemoString58); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 47, RollingDemoString59); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 48, RollingDemoString60); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 49, RollingDemoString61); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 50, RollingDemoString62); SetMenuOptionString( &SettingUpRollingDemoScreenOptions[5], 51, RollingDemoString63); CreateMenuOption( &SettingUpRollingDemoScreenOptions[6], CHOOSE_INTEGER, "Track ", 1, NUMBER_SET_TRACKS, -1, &ChosenTrackNumber); CreateMenuOption( &SettingUpRollingDemoScreenOptions[7], TAKE_ACTION, "Return to main menu", 0, 0, QUIT_BACK_TO_LEVEL_ABOVE, NULL); CreateMenuScreen( &SettingUpRollingDemoScreen, 8, SettingUpRollingDemoScreenOptions); SetMenuScreenPauseTimes( &SettingUpRollingDemoScreen, 8, 5); // 10, 7 SetMenuScreenBackgroundEffect( &SettingUpRollingDemoScreen, SECOND_EFFECT_SWITCHER); // start rolling demo after twelve seconds of inactivity SetMenuScreenTimeoutTime( &SettingUpRollingDemoScreen, MaximumGameFramesPerSecond * 12); bufferIndex = GsGetActiveBuff(); HandleMenuScreen(&SettingUpRollingDemoScreen); // handle action taken switch(SettingUpRollingDemoScreen.quitCode) { case TIMEOUT_QUIT_CODE: // when left unattended PrepareRollingDemo(FALSE); break; case QUIT_BACK_TO_LEVEL_ABOVE: MakeClunk(); SetANewGameState(MAIN_MENU); break; case START_ROLLING_DEMO: MakeClunk(); PrepareRollingDemo(TRUE); break; default: assert(FALSE); } } MenuOption SettingUpMusicOptionsScreenOptions[4]; MenuScreen SettingUpMusicOptionsScreen; char MusicOptionString1[] = "off"; char MusicOptionString2[] = "on"; char MusicMenuScreenTopMessageString[] = "Insert a CD for music"; void GuiLoopForSettingMusicOptions (void) { #if (DEVELOPMENT_ENVIRONMENT==YAROZE) MenuScreen *screen; int volumeOverEight; int previousFlag, previousTrack, previousVolume; int previousJasonTuneOnFlag; int jasonTuneBooleanFlag; int x, y, stringLength; int actualTrackIndex; volumeOverEight = CompactDiscVolumeSetting / 8; previousFlag = CompactDiscMusicPlayFlag; previousTrack = CompactDiscTrackNumber; previousVolume = CompactDiscVolumeSetting; previousJasonTuneOnFlag = JasonTuneOnFlag; jasonTuneBooleanFlag = JasonTuneOnFlag; CreateMenuOption( &SettingUpMusicOptionsScreenOptions[0], CHOOSE_INTEGER, "Background tune ", FALSE, TRUE, -1, &jasonTuneBooleanFlag); SetMenuOptionString( &SettingUpMusicOptionsScreenOptions[0], 1, MusicOptionString1); SetMenuOptionString( &SettingUpMusicOptionsScreenOptions[0], 2, MusicOptionString2); CreateMenuOption( &SettingUpMusicOptionsScreenOptions[1], CHOOSE_INTEGER, "CD Music player ", FALSE, TRUE, -1, &CompactDiscMusicPlayFlag); SetMenuOptionString( &SettingUpMusicOptionsScreenOptions[1], 1, MusicOptionString1); SetMenuOptionString( &SettingUpMusicOptionsScreenOptions[1], 2, MusicOptionString2); CreateMenuOption( &SettingUpMusicOptionsScreenOptions[2], CHOOSE_INTEGER, "CD Track ", 1, NUMBER_CD_TRACKS, -1, &CompactDiscTrackNumber); CreateMenuOption( &SettingUpMusicOptionsScreenOptions[3], CHOOSE_INTEGER, "Volume ", 0, 15, -1, &volumeOverEight); CreateMenuOption( &SettingUpMusicOptionsScreenOptions[4], TAKE_ACTION, "Return to main menu", 0, 0, QUIT_BACK_TO_LEVEL_ABOVE, NULL); CreateMenuScreen( &SettingUpMusicOptionsScreen, 5, SettingUpMusicOptionsScreenOptions); SetMenuScreenPauseTimes( &SettingUpMusicOptionsScreen, 12, 7); // 15, 12 SetMenuScreenBackgroundEffect( &SettingUpMusicOptionsScreen, SECOND_EFFECT_SWITCHER); #if 0 // not for music screen // start rolling demo after twelve seconds of inactivity SetMenuScreenTimeoutTime( &SettingUpMusicOptionsScreen, MaximumGameFramesPerSecond * 12); #endif bufferIndex = GsGetActiveBuff(); screen = &SettingUpMusicOptionsScreen; SetUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); while (screen->active == TRUE) { HandleSound(); GsSetWorkBase( (PACKET*)packetArea[bufferIndex]); GsClearOt(0, 0, &Wot[bufferIndex]); DrawMenuScreen(screen); switch(ScreenResolution) { case LOW_RES: y = -10 * screen->numberOptions - 40; break; case HI_RES: y = -20 * screen->numberOptions - 80; break; default: assert(FALSE); } stringLength = strlen(MusicMenuScreenTopMessageString); switch(ScreenResolution) { case LOW_RES: x = (-stringLength * 8) / 2; break; case HI_RES: x = (-stringLength * 16) / 2; break; default: assert(FALSE); } RegisterTextStringForDisplay(MusicMenuScreenTopMessageString, x, y, GREEN_COLOUR); HandleMenuScreenControls(screen); #if (DEVELOPMENT_ENVIRONMENT==DEV_KIT) { // not functional under dev kit CompactDiscMusicPlayFlag = FALSE; } #endif DisplayTextStrings (&Wot[bufferIndex]); HandleMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag, &Wot[bufferIndex]); DrawSync(0); hsync = VSync(0); CalculateCurrentFrameRate (hsync); GsSwapDispBuff(); GsSortClear(0, 0, 0, &Wot[bufferIndex]); GsDrawOt(&Wot[bufferIndex]); bufferIndex = GsGetActiveBuff(); frameNumber += FrameRateDivider; // make music changes immediately if (previousJasonTuneOnFlag != jasonTuneBooleanFlag) { switch(jasonTuneBooleanFlag) { case TRUE: assert(previousJasonTuneOnFlag == FALSE); previousJasonTuneOnFlag = jasonTuneBooleanFlag; PlayJasonsTune(); break; case FALSE: assert(previousJasonTuneOnFlag == TRUE); previousJasonTuneOnFlag = jasonTuneBooleanFlag; TurnOffJasonsTune(); break; default: assert(FALSE); } } if (previousVolume != volumeOverEight) { previousVolume = volumeOverEight; CompactDiscVolumeSetting = volumeOverEight * 8; SsSetSerialVol(SS_CD, CompactDiscVolumeSetting, CompactDiscVolumeSetting); } if (previousTrack != CompactDiscTrackNumber) { previousTrack = CompactDiscTrackNumber; if (CompactDiscMusicPlayFlag == TRUE) { CdPlay(2, CompactDiscTrackList, CompactDiscTrackNumber-1); } } if (previousFlag != CompactDiscMusicPlayFlag) { previousFlag = CompactDiscMusicPlayFlag; if (CompactDiscMusicPlayFlag == TRUE) { SsSetSerialVol(SS_CD, CompactDiscVolumeSetting, CompactDiscVolumeSetting); actualTrackIndex = CdPlay(3, CompactDiscTrackList, CompactDiscTrackNumber-1); //printf("actualTrackIndex %d\n", actualTrackIndex); //printf("using CompactDiscTrackNumber %d\n\n", CompactDiscTrackNumber); CdPlay(2, CompactDiscTrackList, CompactDiscTrackNumber-1); // if background music was on, turn it off if (jasonTuneBooleanFlag == TRUE) jasonTuneBooleanFlag = FALSE; } else { // stop play CdPlay(0, CompactDiscTrackList, CompactDiscTrackNumber-1); } } } CleanUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); // from here, we can only return to main menu switch (SettingUpMusicOptionsScreen.quitCode) { case TIMEOUT_QUIT_CODE: // when left unattended PrepareRollingDemo(FALSE); break; case QUIT_BACK_TO_LEVEL_ABOVE: MakeClunk(); SetANewGameState(MAIN_MENU); break; default: assert(FALSE); } #endif // REMOVED for non-Yaroze version } // one is in progress // stop it, start a new one void SortOutANewRollingDemo (void) { int newTrack; int previousRollingDemoMode; int choice; previousRollingDemoMode = RollingDemoMainMode; // end everything ResetCluts(); InitTunnelToVoid(); SetBasicTunnelParameters(); InitialiseObjects(); ResetTrackViewingData(); InitialiseRace(); TunnelSideAppearanceFlag = VISIBLE_FROM_INSIDE; TunnelSectionClippingFlag = TRUE; // pick a new demo with a new track RollingDemoMainMode = GetNewRollingDemoMode(); // grab new track randomly for (;;) { newTrack = 1 + (rand() % NUMBER_SET_TRACKS); if (newTrack != ChosenTrackNumber) break; } ChosenTrackNumber = newTrack; RollingDemoActiveFlag = TRUE; RollingDemoStartFrame = frameNumber; switch(RollingDemoMainMode) { case ROLLING_DEMO_TRACK_VIEWING: TrackViewerCameraControlMode = TRACK_VIEWER_AUTO_CAMERA; if (RollingDemoDeliberateFlag == FALSE) { TrackViewerMainMode = VIEW_TRACK_FROM_INSIDE + (rand() % 2); } switch(TrackViewerMainMode) { case VIEW_TRACK_FROM_INSIDE: if (RollingDemoDeliberateFlag == FALSE) { TrackViewerDirection = FORWARDS + (rand() % 2); choice = rand() % 4; switch(choice) { case 0: TrackViewerAutoCameraMode = TRACK_VIEWER_AUTO_CAMERA_SLOW_MODE; break; case 1: TrackViewerAutoCameraMode = TRACK_VIEWER_AUTO_CAMERA_TWISTER_MODE; break; case 2: TrackViewerAutoCameraMode = TRACK_VIEWER_AUTO_CAMERA_TWISTING_ROLLERCOASTER_MODE; break; case 3: TrackViewerAutoCameraMode = TRACK_VIEWER_AUTO_CAMERA_ZOOM_ROLLERCOASTER_MODE; break; default: assert(FALSE); } } break; case VIEW_TRACK_FROM_OUTSIDE: // at present only one autocamera mode for external viewing // hence no choice to make here break; default: assert(FALSE); } PrepareTheTrackForViewing(); if (previousRollingDemoMode != ROLLING_DEMO_TRACK_VIEWING) SetANewGameState(VIEWING_THE_TRACKS); break; case ROLLING_DEMO_SOLO_AI_FLIER: SetUpARollingDemoSoloAiFlier(RollingDemoDeliberateFlag); if (previousRollingDemoMode == ROLLING_DEMO_TRACK_VIEWING) SetANewGameState(DURING_THE_RACE); break; case ROLLING_DEMO_AI_FLIERS_RACE: SetUpARollingDemoAiFliersRace(RollingDemoDeliberateFlag); if (previousRollingDemoMode == ROLLING_DEMO_TRACK_VIEWING) SetANewGameState(DURING_THE_RACE); break; default: assert(FALSE); } } void SetUpAFreePracticeSession (void) { ChosenNumberOfLaps = 5; // now copy user selection data into real race data FrameWhenRaceStarts = frameNumber; RaceFrameCounter = 0; assert(ChosenTrackNumber >= 1); assert(ChosenTrackNumber <= NUMBER_SET_TRACKS); ChosenSetTrack = ChosenTrackNumber-1; NumberOfShipsInRace = 1; // just the player ShipsInTunnel[0] = &PlayerOnesShip; PlayerOnesShip.specialMovementFlag = HUMAN_PLAYER; RaceOnFlag = FALSE; NumberOfLapsInRace = MAX_LAPS_IN_RACE; // build the specified tunnel SortTunnelToSetTrack(ChosenSetTrack); PrepareShipsForRace2(); PlayerOnesShip.viewMode = VIEW_FIXED_BEHIND_ABOVE_OBJECT; SetNewViewShip( &PlayerOnesShip); } void SetUpAFullRace (void) { int i; assert(ChosenNumberOfDrivers >= 1); assert(ChosenNumberOfDrivers < MAX_SHIPS_PER_RACE); assert(ChosenNumberOfLaps >= 0); assert(ChosenNumberOfLaps <= MAX_LAPS_IN_RACE); assert(ChosenNumberOfLaps < MAX_LAPS_PER_OBJECT+1); FrameWhenRaceStarts = frameNumber; RaceFrameCounter = 0; assert(ChosenTrackNumber >= 1); assert(ChosenTrackNumber <= NUMBER_SET_TRACKS); ChosenSetTrack = ChosenTrackNumber-1; NumberOfShipsInRace = ChosenNumberOfDrivers+1; // player also assert(NumberOfShipsInRace <= MAX_SHIPS_PER_RACE); ShipsInTunnel[0] = &PlayerOnesShip; for (i = 0; i < NumberOfShipsInRace-1; i++) { ShipsInTunnel[i+1] = &OtherShips[i]; OtherShips[i].specialMovementFlag = AI_FLIER_1; OtherShips[i].properMovementFlag = FALSE; SetRandomModelForShip( &OtherShips[i]); // dynamic flier #if 0 // NOT YET OtherShips[i].specialMovementFlag = AI_FLIER_2; OtherShips[i].properMovementFlag = TRUE; #endif // dynamic flier #if 0 // NOT YET OtherShips[i].specialMovementFlag = AI_FLIER_3; OtherShips[i].properMovementFlag = TRUE; #endif OtherShips[i].speedFactor = 64; OtherShips[i].discreteSpeed = 10; } RaceOnFlag = TRUE; NumberOfLapsInRace = ChosenNumberOfLaps; // build the specified tunnel SortTunnelToSetTrack(ChosenSetTrack); PrepareShipsForRace2(); SetNewViewShip( &PlayerOnesShip); } void SetUpTwoPlayerRace (void) { int originalNumberOfShapesPerSection; #if (DRAW_DISTANCE_REDUCED_FOR_TWO_PLAYER_MODE==1) int originalNumberOfSectionsDrawn; #endif assert(ChosenNumberOfLaps >= 0); assert(ChosenNumberOfLaps <= MAX_LAPS_IN_RACE); assert(ChosenNumberOfLaps < MAX_LAPS_PER_OBJECT+1); FrameWhenRaceStarts = frameNumber; RaceFrameCounter = 0; assert(ChosenTrackNumber >= 1); assert(ChosenTrackNumber <= NUMBER_SET_TRACKS); ChosenSetTrack = ChosenTrackNumber-1; // reduce the number of shapes per section and #sections drawn // to keep frame rate up originalNumberOfShapesPerSection = SetTracks[ChosenSetTrack].shapesPerSection; #if (DRAW_DISTANCE_REDUCED_FOR_TWO_PLAYER_MODE==1) originalNumberOfSectionsDrawn = SetTracks[ChosenSetTrack].numberSectionsDrawn; #endif SetTracks[ChosenSetTrack].shapesPerSection = (SetTracks[ChosenSetTrack].shapesPerSection * 2) / 3; #if (DRAW_DISTANCE_REDUCED_FOR_TWO_PLAYER_MODE==1) SetTracks[ChosenSetTrack].numberSectionsDrawn -= 6; #endif NumberOfShipsInRace = 2; ShipsInTunnel[0] = &PlayerOnesShip; ShipsInTunnel[1] = &PlayerTwosShip; // now default to local view PlayerOnesShip.viewMode = VIEW_LOCAL_TO_OBJECT; PlayerTwosShip.viewMode = VIEW_LOCAL_TO_OBJECT; RaceOnFlag = TRUE; NumberOfLapsInRace = ChosenNumberOfLaps; // build the specified tunnel SortTunnelToSetTrack(ChosenSetTrack); PrepareShipsForRace2(); SetNewViewShip( ShipsInTunnel[0]); SetTracks[ChosenSetTrack].shapesPerSection = originalNumberOfShapesPerSection; #if (DRAW_DISTANCE_REDUCED_FOR_TWO_PLAYER_MODE==1) SetTracks[ChosenSetTrack].numberSectionsDrawn = originalNumberOfSectionsDrawn; #endif } void SetUpARollingDemoSoloAiFlier (int deliberateFlag) { ChosenNumberOfLaps = 1; // now copy user selection data into real race data FrameWhenRaceStarts = frameNumber; RaceFrameCounter = 0; assert(ChosenTrackNumber >= 1); assert(ChosenTrackNumber <= NUMBER_SET_TRACKS); ChosenSetTrack = ChosenTrackNumber-1; NumberOfShipsInRace = 1; // just the ai ship ShipsInTunnel[0] = &OtherShips[0]; OtherShips[0].specialMovementFlag = AI_FLIER_1; OtherShips[0].speedFactor = 64; // set speed of travel of solo AI flier OtherShips[0].speedControlFlag = FASTISH_FLIER; switch(OtherShips[0].speedControlFlag) { case SLOW_FLIER: OtherShips[0].discreteSpeed = 8; break; case SLOWISH_FLIER: OtherShips[0].discreteSpeed = 12; break; case FASTISH_FLIER: OtherShips[0].discreteSpeed = 16; break; default: assert(FALSE); } RaceOnFlag = FALSE; NumberOfLapsInRace = MAX_LAPS_IN_RACE; if (deliberateFlag == FALSE) { OtherShips[0].viewMode = VIEW_BY_FIRST_DIRECTORS_CUT; } else { OtherShips[0].viewMode = TrackViewerShipViewMode; } // build the specified tunnel SortTunnelToSetTrack(ChosenSetTrack); PrepareShipsForRace2(); SetNewViewShip( ShipsInTunnel[0]); } void SetUpARollingDemoAiFliersRace (int deliberateFlag) { int i; int choice; // always pick #drivers randomly choice = rand() % 2; if (choice == 0) ChosenNumberOfDrivers = 2; else ChosenNumberOfDrivers = 4; ChosenNumberOfLaps = MAX_LAPS_IN_RACE; assert(ChosenNumberOfLaps <= MAX_LAPS_IN_RACE); assert(ChosenNumberOfLaps < MAX_LAPS_PER_OBJECT+1); FrameWhenRaceStarts = frameNumber; RaceFrameCounter = 0; assert(ChosenTrackNumber >= 1); assert(ChosenTrackNumber <= NUMBER_SET_TRACKS); ChosenSetTrack = ChosenTrackNumber-1; NumberOfShipsInRace = ChosenNumberOfDrivers; assert(NumberOfShipsInRace < MAX_SHIPS_PER_RACE); // pick speed of racing ships choice = SLOWISH_FLIER; for (i = 0; i < NumberOfShipsInRace; i++) { ShipsInTunnel[i] = &OtherShips[i]; OtherShips[i].specialMovementFlag = AI_FLIER_1; OtherShips[i].speedFactor = 64; SetRandomModelForShip( &OtherShips[i]); // only allow first two speeds in race mode OtherShips[i].speedControlFlag = choice; switch(OtherShips[i].speedControlFlag) { case SLOW_FLIER: OtherShips[i].discreteSpeed = 8; break; case SLOWISH_FLIER: OtherShips[i].discreteSpeed = 12; break; case FASTISH_FLIER: assert(FALSE); // not allowed in race mode break; default: printf("bad value %d\n", OtherShips[i].speedControlFlag); assert(FALSE); } if (deliberateFlag == TRUE) OtherShips[i].viewMode = TrackViewerShipViewMode; else { assert(deliberateFlag == FALSE); OtherShips[i].viewMode = VIEW_BY_FIRST_DIRECTORS_CUT; } } RaceOnFlag = TRUE; NumberOfLapsInRace = ChosenNumberOfLaps; // attach camera to a randomly chosen ship choice = rand() % ChosenNumberOfDrivers; // build the specified tunnel SortTunnelToSetTrack(ChosenSetTrack); PrepareShipsForRace2(); SetNewViewShip(ShipsInTunnel[choice]); } // show best lap time, tell if a new lap record has been set void ShowFreePracticeResults (void) { int fastestTime, candidateTime; int i; int newLapRecordSpeed; char timeString[64]; DrawSync(0); VSync(0); if (NumberOfLapsCompletedInFreePractice < 1) // no results return; // work out the fastest lap fastestTime = PlayerOnesShip.framesWhenLapsEnd[1] - PlayerOnesShip.framesWhenLapsEnd[0]; // first lap assert(NumberOfLapsInRace >= 0); assert(NumberOfLapsInRace <= MAX_LAPS_IN_RACE); assert(NumberOfLapsInRace < MAX_LAPS_PER_OBJECT); for (i = 2; i <= NumberOfLapsCompletedInFreePractice; i++) { candidateTime = PlayerOnesShip.framesWhenLapsEnd[i] - PlayerOnesShip.framesWhenLapsEnd[i-1]; if (candidateTime < fastestTime) { if (candidateTime > 0) { fastestTime = candidateTime; } } } if (fastestTime < 0) { PRINT("BAD time\n"); HERE; return; } GetStringOfTimeInFrames(fastestTime, timeString); sprintf(TextStringList[0], "your best lap time was %s", timeString); if (fastestTime < TheTunnelDescription.bestLapTimeInFrames) { // new lap record sprintf(TextStringList[1], "a new lap record"); assert(ChosenSetTrack >= 0); assert(ChosenSetTrack < NUMBER_SET_TRACKS); SetTracks[ChosenSetTrack].bestLapTimeInFrames = fastestTime; newLapRecordSpeed = TheTunnelDescription.totalDistance / fastestTime; sprintf(TextStringList[2], "average speed %d", newLapRecordSpeed); sprintf(TextStringList[3], "press any key to continue"); GuiLoopForDisplayingStrings(4, MaximumGameFramesPerSecond); } else { sprintf(TextStringList[1], "press any key to continue"); GuiLoopForDisplayingStrings(2, MaximumGameFramesPerSecond); } } void ShowTwoPlayerRaceResults (void) { int winnerID; char timeString[64]; int fastestTime, fastestPlayer, candidateTime; int i; if (PlayerOnesShip.furthestLap < NumberOfLapsInRace && PlayerTwosShip.furthestLap < NumberOfLapsInRace) { return; } // sort value of winnerID: 1 or 2 if (PlayerOnesShip.placeInRace == 1) { assert(PlayerTwosShip.placeInRace == 2); winnerID = 1; } else { assert(PlayerOnesShip.placeInRace == 2); assert(PlayerTwosShip.placeInRace == 1); winnerID = 2; } sprintf(TextStringList[0], "Player %d won", winnerID); assert(NumberOfLapsInRace >= 0); assert(NumberOfLapsInRace <= MAX_LAPS_IN_RACE); assert(NumberOfLapsInRace <= MAX_LAPS_PER_OBJECT); // now work out the fastest lap and who got it fastestPlayer = 1; fastestTime = PlayerOnesShip.framesWhenLapsEnd[1] - PlayerOnesShip.framesWhenLapsEnd[0]; for (i = 2; i <= PlayerOnesShip.furthestLap; i++) { candidateTime = PlayerOnesShip.framesWhenLapsEnd[i] - PlayerOnesShip.framesWhenLapsEnd[i-1]; if (candidateTime < fastestTime) { if (candidateTime > 0) { fastestTime = candidateTime; } } } for (i = 1; i <= PlayerTwosShip.furthestLap; i++) { candidateTime = PlayerTwosShip.framesWhenLapsEnd[i] - PlayerTwosShip.framesWhenLapsEnd[i-1]; if (candidateTime < fastestTime) { if (candidateTime > 0) { fastestTime = candidateTime; fastestPlayer = 2; } } } if (fastestTime < 0) { PRINT("BAD time\n"); HERE; return; } GetStringOfTimeInFrames(fastestTime, timeString); sprintf(TextStringList[1], "player %d has the fastest lap", fastestPlayer); sprintf(TextStringList[2], "which was %s", timeString); sprintf(TextStringList[3], "press any key to continue"); GuiLoopForDisplayingStrings (4, MaximumGameFramesPerSecond); } void ShowFullRaceResults (void) { int i, j; int fastestPlayer, fastestTime, candidateTime; char timeString[64]; int raceEndedEarlyFlag; int newLapRecordSpeed; raceEndedEarlyFlag = TRUE; for (i = 0; i < NumberOfShipsInRace; i++) { if (ShipsInTunnel[i]->furthestLap == NumberOfLapsInRace) { raceEndedEarlyFlag = FALSE; break; } } if (raceEndedEarlyFlag == TRUE) { return; } if (PlayerOnesShip.placeInRace == 1) sprintf(TextStringList[0], "you won the race outright"); else sprintf(TextStringList[0], "you finished in place %d", PlayerOnesShip.placeInRace); fastestPlayer = 1; fastestTime = PlayerOnesShip.framesWhenLapsEnd[1] - PlayerOnesShip.framesWhenLapsEnd[0]; for (i = 0; i < NumberOfShipsInRace; i++) { for (j = 1; j <= NumberOfLapsInRace; j++) { candidateTime = ShipsInTunnel[i]->framesWhenLapsEnd[j] - ShipsInTunnel[i]->framesWhenLapsEnd[j-1]; if (candidateTime < fastestTime) { if (candidateTime > 0) { fastestTime = candidateTime; fastestPlayer = i+1; } } } } if (fastestTime <= 0) { PRINT("BAD time\n"); HERE; return; } GetStringOfTimeInFrames(fastestTime, timeString); sprintf(TextStringList[1], "racer %d made the fastest lap", fastestPlayer); sprintf(TextStringList[2], "which was %s", timeString); if (fastestTime < TheTunnelDescription.bestLapTimeInFrames) { // new lap record sprintf(TextStringList[3], "a new lap record"); assert(ChosenSetTrack >= 0); assert(ChosenSetTrack < NUMBER_SET_TRACKS); SetTracks[ChosenSetTrack].bestLapTimeInFrames = fastestTime; assert(fastestTime != 0); newLapRecordSpeed = TheTunnelDescription.totalDistance / fastestTime; sprintf(TextStringList[4], "average speed %d", newLapRecordSpeed); sprintf(TextStringList[5], "press any key to continue"); GuiLoopForDisplayingStrings(6, MaximumGameFramesPerSecond); } else { sprintf(TextStringList[3], "press any key to continue"); GuiLoopForDisplayingStrings(4, MaximumGameFramesPerSecond); } } // write time data into string as properly formatted numbers void GetStringOfTimeInFrames (int frames, char *output) { int secondsBundle, fraction; int minutes, seconds, hundredths; assert(output != NULL); assert(frames >= 0); secondsBundle = FramesToSeconds(frames); seconds = secondsBundle >> 16; minutes = 0; while (seconds >= 60) { minutes++; seconds -= 60; } fraction = secondsBundle & 0xffff; hundredths = (100 * fraction) >> 12; if (hundredths >= 10) { if (seconds >= 10) sprintf(output, "%d:%d.%d", minutes, seconds, hundredths); else sprintf(output, "%d:0%d.%d", minutes, seconds, hundredths); } else { if (seconds >= 10) sprintf(output, "%d:%d.0%d", minutes, seconds, hundredths); else sprintf(output, "%d:0%d.0%d", minutes, seconds, hundredths); } } // sizeFraction: drawing 8 or 16 lines for speed bar #define DOUBLE_SPEED_BAR_LENGTH_FLAG 1 void DrawSpeedBar (GsOT *ot, int xBase, int yBase, int speedFraction, int sizeFraction, int maximumWidth) { int i; GsGLINE *line; int width; int value; assert(speedFraction >= 0); assert(speedFraction <= ONE); assert(sizeFraction >= 0); assert(sizeFraction <= ONE); width = (maximumWidth * speedFraction) >> 12; #if DOUBLE_SPEED_BAR_LENGTH_FLAG width <<= 1; #endif for (i = 0; i < 16; i++) { line = &SpeedLines[i]; line->x0 = xBase; line->y0 = yBase + i; line->x1 = line->x0 + width - ((16 - i) * 2); line->y1 = line->y0; // blue to red line->r0 = 0; line->g0 = 0; line->b0 = 128; line->r1 = ((256 * speedFraction) >> 12); line->g1 = 0; value = 128 - ((256 * speedFraction) >> 12); if (value < 0) line->b1 = 0; else line->b1 = value; if (line->x1 > line->x0) { GsSortGLine(line, ot, 0); } // draw speed bar of half size if (sizeFraction == 2048 && i >= 8) return; } }