/************************************************************ * * * menu_mod.c * * * * * LPGE 1997 * * * * Copyright (C) 1996 Sony Computer Entertainment Inc. * * All Rights Reserved * * * ***********************************************************/ /**************************************************************************** includes ****************************************************************************/ #include "pad.h" #include "sound.h" #include "object.h" #include "tunnel.h" #include "tunnel2.h" #include "flying.h" #include "main.h" #include "menu_mod.h" #include "camera.h" #include "menu.h" /**************************************************************************** imported globals ****************************************************************************/ extern int ShipDrawProcessLabel; extern DrawProcess ShipDrawProcess; /**************************************************************************** local constants ****************************************************************************/ #define MENU_SCREENS_RESOLUTION (HI_RES) #define GENERAL_PICK_NEW_DRAW_PROC_FREQUENCY 6 #define GENERAL_PICK_NEW_SUB_MODE_FREQUENCY 8 #define SHIP_ROTATES_SLOWLY_RESET_FREQUENCY 4 // 200 #define BEHIND_OTHERS_OT_VALUE 50 #define MAX_LOCAL_SPRITES 128 /**************************************************************************** globals ****************************************************************************/ int GlobalPreviousShipDrawProcessLabel = -1; ObjectHandler *GlobalDisplayShip; int GlobalPreviousGlobalShipLightingEffectFlag; int GlobalPreviousShipViewMode; ObjectHandler *GlobalPreviousViewShip; int GlobalViewSubMode; int PreviousShipDrawProcessLabel; ObjectHandler *DisplayShip; int PreviousGlobalShipLightingEffectFlag; int ShipRotationAxis; int ShipRotationSpeed, ShipRotationDirection; ObjectHandler *FirstDisplayShip, *SecondDisplayShip; int FramesWithinFirstEffectSwitcher; int FirstEffectSwitcherPeriod; int FirstEffectSwitcherSubMode; int FramesWithinSecondEffectSwitcher; int SecondEffectSwitcherPeriod; int SecondEffectSwitcherSubMode; int RegularlyUpdateShipDrawProcFlag; int FramesSinceMenuEffectLastSet; int FirstTimeEverForMenuEffectFlag; int DeepBackgroundGraphicsFramePeriod; int DeepBackgroundGraphicsFlipPeriod; int FramesWithinDeepbackgroundGraphics; int DeepBackgroundGraphicsSubMode; int ExplodingLinesRectangleSizeFactor; int NeedleThreadPoints[256]; int NumberOfSpirals; Spiral TheSpirals[MAX_SPIRALS]; int SpiralOutwardDirection, SpiralRadialDirection; int FirstChosenGlobalSpriteIndex; int SecondChosenGlobalSpriteIndex; int ThirdChosenGlobalSpriteIndex; int SpriteMergeDirection; int NumberLocalSprites; GsSPRITE *LocalSpriteList[MAX_LOCAL_SPRITES]; /**************************************************************************** local prototypes ****************************************************************************/ void SetUpMenuEffectSubMode (int mode); void InitShipCameraMode (int mode); void InitShipRotatesSlowlyEffect (void); void InitTwoShipsRotating (void); void CleanUpMenuEffectSubMode (int mode); void CleanUpShipCameraMode (int mode); void CleanUpShipRotatesSlowlyEffect (void); void CleanUpTwoShipsRotating (void); void HandleMenuEffectSubMode (int mode, GsOT *ot); void HandleShipViewing (int mode, GsOT *ot); void DisplayShipRotating (GsOT *ot); void HandleFirstEffectSwitcher (GsOT *ot); void HandleSecondEffectSwitcher (GsOT *ot); void DisplayTwoShipsRotating (GsOT *ot); int GetNewShipDrawProcessLabel (void); void InitAllDeepBackgroundEffects (void); void ResetDeepGraphicEffects (void); void InitSpecificDeepBackgroundEffect (int which); void DrawDeepestBackgroundEffect (GsOT *ot); int GetNewDeepBackgroundEffect (int current); void DrawExplodingLines (GsOT *ot, int cycleRatio); void DrawNeedleThreadLines (GsOT *ot, int cycleRatio); void DrawSpiralEffect (GsOT *ot, int cycleRatio); void DrawSpriteWallFadingInAndOut (GsOT *ot, int cycleRatio); void DrawSpriteWallMergingThroughSprites (GsOT *ot, int cycleRatio); void GetColourDuringCycle (int cycleRatio, CVECTOR *colour); void GetPointOnScreenCentredRect (int sizeFactor, int angle, short *x, short *y); int MovePointIndexAroundRect (int index, int direction, int numPixelsMoved, int width, int height); void GetXAndYOfIndexOntoScreenCentredRectangle (int index, int width, int height, short *x, short *y); void ScaleSpriteTo64by64 (GsSPRITE *sprite); /**************************************************************************** functions ****************************************************************************/ void CreateMenuOption (MenuOption *option, int type, char *string, int lowest, int highest, int actionLabel, int *variable) { int i; assert(option != NULL); assert(type == CHOOSE_INTEGER || type == TAKE_ACTION); assert(strlen(string) <= MAX_MENU_STRING_LENGTH); if (type == CHOOSE_INTEGER) { assert(lowest < highest); assert(variable != NULL); } option->type = type; sprintf(option->string, "%s", string); option->lowest = lowest; option->highest = highest; option->variable = variable; option->stringsFlag = FALSE; for (i = 0; i < MAX_STRINGS_PER_MENU_OPTION; i++) { option->strings[i] = NULL; } option->actionLabel = actionLabel; option->instantResponseFlag = FALSE; option->functionPointer = NULL; } void SetMenuOptionString (MenuOption *option, int whichString, char *string) { assert(option != NULL); assert(whichString >= 1); assert(whichString <= MAX_STRINGS_PER_MENU_OPTION); option->stringsFlag = TRUE; option->strings[whichString-1] = string; } void SetMenuOptionInstantResponse (MenuOption *option, VOID_FROM_INT functionPointer) { assert(option != NULL); assert(functionPointer != NULL); option->instantResponseFlag = TRUE; option->functionPointer = functionPointer; } void SetMenuScreenTimeoutTime (MenuScreen *screen, int time) { assert(screen != NULL); assert(time >= 0); assert(time < 99999); screen->timeoutTime = time; } void SetMenuScreenPauseTimes (MenuScreen *screen, int actionPause, int integerChoicePause) { assert(actionPause > 0); assert(actionPause < 60); assert(integerChoicePause > 0); assert(integerChoicePause < 60); assert(screen != NULL); screen->actionPause = actionPause; screen->integerChoicePause = integerChoicePause; } void SetMenuScreenBackgroundEffect (MenuScreen *screen, int effectID) { assert(screen != NULL); assert(effectID >= 0); assert(effectID < 99999); screen->backgroundDrawEffectFlag = effectID; } void CreateMenuScreen (MenuScreen *screen, int numberOptions, MenuOption *orderedOptionList) { int i; assert(screen != NULL); assert(numberOptions > 0); assert(numberOptions <= MAX_OPTIONS_PER_SCREEN); assert(orderedOptionList != NULL); screen->numberOptions = numberOptions; for (i = 0; i < numberOptions; i++) { screen->options[i] = &orderedOptionList[i]; } screen->selectedOption = 0; screen->framesSinceLastChoice = 0; screen->framesSinceCreation = 0; screen->timeoutTime = -1; screen->active = TRUE; screen->quitCode = -1; screen->backgroundDrawEffectFlag = -1; } // in main loop: call before DisplayTextStrings void DrawMenuScreen (MenuScreen *screen) { int i; int x = 0, y = 0; MenuOption *option; char stringBuffer[64]; int stringLength; int whichString; switch(ScreenResolution) { case LOW_RES: y = -10 * screen->numberOptions; break; case HI_RES: y = -20 * screen->numberOptions; break; default: assert(FALSE); } for (i = 0; i < screen->numberOptions; i++) { option = screen->options[i]; switch (option->type) { case CHOOSE_INTEGER: switch(option->stringsFlag) { case FALSE: sprintf(stringBuffer, "%s %d", option->string, (*(option->variable)) ); break; case TRUE: whichString = (*(option->variable)) - option->lowest; assert(whichString >= 0); assert(whichString < MAX_STRINGS_PER_MENU_OPTION); sprintf(stringBuffer, "%s %s", option->string, option->strings[whichString] ); break; default: assert(FALSE); } break; case TAKE_ACTION: sprintf(stringBuffer, "%s", option->string); break; default: { printf("bad option type %d\n", option->type); printf("menu screen %d ie %08x\n", (int)screen, (int) screen); assert(FALSE); } } stringLength = strlen(stringBuffer); // adjust text for strings to be centred switch(ScreenResolution) { case LOW_RES: x = (-stringLength * 8) / 2; break; case HI_RES: x = (-stringLength * 16) / 2; break; default: assert(FALSE); } if (i == screen->selectedOption) RegisterTextStringForDisplay (stringBuffer, x, y, RED_COLOUR); else RegisterTextStringForDisplay (stringBuffer, x, y, NORMAL_COLOUR); switch(ScreenResolution) { case LOW_RES: y += 20; break; case HI_RES: y += 40; break; default: assert(FALSE); } } } #define TAMPER_WITH_EFFECTS_FLAG 0 void HandleMenuScreenControls (MenuScreen *screen) { MenuOption *option; int id; long pad; int newMode; assert(screen->actionPause > 0); assert(screen->actionPause < 60); assert(screen->integerChoicePause > 0); assert(screen->integerChoicePause < 60); pad = PadRead(0); #if (TAMPER_WITH_EFFECTS_FLAG==1) { // hold-down pause if (pad & PADL2) { while (pad & PADL2) pad = PadRead(0); return; } if (screen->backgroundDrawEffectFlag != -1) { // forcibly change display mode if (pad & PADR2 && screen->framesSinceLastChoice > screen->actionPause) { if (pad & PADRup) { CleanUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); screen->backgroundDrawEffectFlag++; if (screen->backgroundDrawEffectFlag > BASE_MENU_SUB_MODE + NUMBER_BASE_MENU_SUB_MODES - 1) screen->backgroundDrawEffectFlag -= NUMBER_BASE_MENU_SUB_MODES; if (screen->backgroundDrawEffectFlag < BASE_MENU_SUB_MODE) screen->backgroundDrawEffectFlag += NUMBER_BASE_MENU_SUB_MODES; SetUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); printf("newly set menu display mode %d\n", screen->backgroundDrawEffectFlag); screen->framesSinceLastChoice = 0; } if (pad & PADRdown) { CleanUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); screen->backgroundDrawEffectFlag--; if (screen->backgroundDrawEffectFlag < BASE_MENU_SUB_MODE) screen->backgroundDrawEffectFlag += NUMBER_BASE_MENU_SUB_MODES; if (screen->backgroundDrawEffectFlag > BASE_MENU_SUB_MODE + NUMBER_BASE_MENU_SUB_MODES - 1) screen->backgroundDrawEffectFlag -= NUMBER_BASE_MENU_SUB_MODES; SetUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); printf("newly set menu display mode %d\n", screen->backgroundDrawEffectFlag); screen->framesSinceLastChoice = 0; } if (pad & PADRleft) { printf("menu display mode %d\n", screen->backgroundDrawEffectFlag); if (screen->backgroundDrawEffectFlag == FIRST_EFFECT_SWITCHER) { printf("1st submode %d\n", FirstEffectSwitcherSubMode); } else if (screen->backgroundDrawEffectFlag == SECOND_EFFECT_SWITCHER) { printf("2nd submode %d\n", SecondEffectSwitcherSubMode); } } return; } // forcibly change ship draw proc if (pad & PADR1 && screen->framesSinceLastChoice > screen->actionPause) { if (pad & PADRup) { ShipDrawProcessLabel--; if (ShipDrawProcessLabel < 0) ShipDrawProcessLabel += NUMBER_DRAW_PROCESSES; assert(ShipDrawProcessLabel >= 0); assert(ShipDrawProcessLabel < NUMBER_DRAW_PROCESSES); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); printf("newly set ship draw proc %d\n", ShipDrawProcessLabel); screen->framesSinceLastChoice = 0; } if (pad & PADRdown) { ShipDrawProcessLabel++; if (ShipDrawProcessLabel >= NUMBER_DRAW_PROCESSES) ShipDrawProcessLabel -= NUMBER_DRAW_PROCESSES; assert(ShipDrawProcessLabel >= 0); assert(ShipDrawProcessLabel < NUMBER_DRAW_PROCESSES); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); printf("newly set ship draw proc %d\n", ShipDrawProcessLabel); screen->framesSinceLastChoice = 0; } if (pad & PADRleft) { if (RegularlyUpdateShipDrawProcFlag == TRUE) RegularlyUpdateShipDrawProcFlag = FALSE; else RegularlyUpdateShipDrawProcFlag = TRUE; printf("flag now %d\n", RegularlyUpdateShipDrawProcFlag); screen->framesSinceLastChoice = 0; } if (pad & PADLup) { ShipDrawProcessLabel -= 10; if (ShipDrawProcessLabel < 0) ShipDrawProcessLabel += NUMBER_DRAW_PROCESSES; assert(ShipDrawProcessLabel >= 0); assert(ShipDrawProcessLabel < NUMBER_DRAW_PROCESSES); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); printf("newly set ship draw proc %d\n", ShipDrawProcessLabel); screen->framesSinceLastChoice = 0; } if (pad & PADLdown) { ShipDrawProcessLabel += 10; if (ShipDrawProcessLabel >= NUMBER_DRAW_PROCESSES) ShipDrawProcessLabel -= NUMBER_DRAW_PROCESSES; assert(ShipDrawProcessLabel >= 0); assert(ShipDrawProcessLabel < NUMBER_DRAW_PROCESSES); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); printf("newly set ship draw proc %d\n", ShipDrawProcessLabel); screen->framesSinceLastChoice = 0; } return; } // forcibly change deep graphic effect if (pad & PADL1 && screen->framesSinceLastChoice > screen->actionPause) { if (pad & PADLup) { DeepBackgroundGraphicsSubMode++; if (DeepBackgroundGraphicsSubMode > BASE_DEEP_BACKGROUND_SUB_MODE + NUMBER_DEEP_BACKGROUND_SUB_MODES-1) DeepBackgroundGraphicsSubMode -= NUMBER_DEEP_BACKGROUND_SUB_MODES; DrawSync(0); ResetGraph(1); InitSpecificDeepBackgroundEffect(DeepBackgroundGraphicsSubMode); printf("new mode %d\n", DeepBackgroundGraphicsSubMode); screen->framesSinceLastChoice = 0; } if (pad & PADLdown) { DeepBackgroundGraphicsSubMode--; if (DeepBackgroundGraphicsSubMode < BASE_DEEP_BACKGROUND_SUB_MODE) DeepBackgroundGraphicsSubMode += NUMBER_DEEP_BACKGROUND_SUB_MODES; DrawSync(0); ResetGraph(1); InitSpecificDeepBackgroundEffect(DeepBackgroundGraphicsSubMode); printf("new mode %d\n", DeepBackgroundGraphicsSubMode); screen->framesSinceLastChoice = 0; } return; } } } #endif // Rleft: switch up submode of first/second switcher if (pad & PADRleft && screen->framesSinceLastChoice > screen->actionPause) { if (screen->backgroundDrawEffectFlag == FIRST_EFFECT_SWITCHER) { DrawSync(0); ResetGraph(1); CleanUpMenuEffectSubMode(FirstEffectSwitcherSubMode); newMode = FirstEffectSwitcherSubMode+1; if (newMode > BASE_MENU_SUB_MODE + NUMBER_BASE_MENU_SUB_MODES-1) { newMode -= NUMBER_BASE_MENU_SUB_MODES; } SetUpMenuEffectSubMode(newMode); FirstEffectSwitcherSubMode = newMode; screen->framesSinceLastChoice = 0; } else if (screen->backgroundDrawEffectFlag == SECOND_EFFECT_SWITCHER) { DrawSync(0); ResetGraph(1); CleanUpMenuEffectSubMode(SecondEffectSwitcherSubMode); newMode = SecondEffectSwitcherSubMode+1; if (newMode > BASE_MENU_SUB_MODE + NUMBER_BASE_MENU_SUB_MODES-1) { newMode -= NUMBER_BASE_MENU_SUB_MODES; } SetUpMenuEffectSubMode(newMode); SecondEffectSwitcherSubMode = newMode; screen->framesSinceLastChoice = 0; } return; } // Rright: switch down submode of first/second switcher if (pad & PADRright && screen->framesSinceLastChoice > screen->actionPause) { if (screen->backgroundDrawEffectFlag == FIRST_EFFECT_SWITCHER) { DrawSync(0); ResetGraph(1); CleanUpMenuEffectSubMode(FirstEffectSwitcherSubMode); newMode = FirstEffectSwitcherSubMode-1; if (newMode < BASE_MENU_SUB_MODE) { newMode += NUMBER_BASE_MENU_SUB_MODES; } SetUpMenuEffectSubMode(newMode); FirstEffectSwitcherSubMode = newMode; screen->framesSinceLastChoice = 0; } else if (screen->backgroundDrawEffectFlag == SECOND_EFFECT_SWITCHER) { DrawSync(0); ResetGraph(1); CleanUpMenuEffectSubMode(SecondEffectSwitcherSubMode); newMode = SecondEffectSwitcherSubMode-1; if (newMode < BASE_MENU_SUB_MODE) { newMode += NUMBER_BASE_MENU_SUB_MODES; } SetUpMenuEffectSubMode(newMode); SecondEffectSwitcherSubMode = newMode; screen->framesSinceLastChoice = 0; } return; } // Rup: flip first-switcher and second-switcher if (pad & PADRup && screen->framesSinceLastChoice > screen->actionPause) { DrawSync(0); ResetGraph(1); CleanUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); // not allowed to change from this if (screen->backgroundDrawEffectFlag == TWO_SHIPS_ROTATE_SLOWLY) return; if (screen->backgroundDrawEffectFlag == FIRST_EFFECT_SWITCHER) screen->backgroundDrawEffectFlag = SECOND_EFFECT_SWITCHER; else { assert(screen->backgroundDrawEffectFlag == SECOND_EFFECT_SWITCHER); screen->backgroundDrawEffectFlag = FIRST_EFFECT_SWITCHER; } SetUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); screen->framesSinceLastChoice = 0; return; } // compensate for variable frame rate // keep menus as responsive as caller specified screen->framesSinceLastChoice += FrameRateDivider; screen->framesSinceCreation++; // hard-wired: cannot do anything for first 1/3 of second of screen if (screen->framesSinceCreation < MaximumGameFramesPerSecond/3) return; id = screen->selectedOption; option = screen->options[id]; if (screen->timeoutTime != -1) // there is a timeout set { if (screen->framesSinceLastChoice >= screen->timeoutTime) // has timed out { screen->active = FALSE; screen->quitCode = TIMEOUT_QUIT_CODE; screen->framesSinceLastChoice = 0; return; } } // hard-wired exit: start and select if (pad & PADstart && pad & PADselect && screen->framesSinceLastChoice >= screen->actionPause) { screen->active = FALSE; screen->quitCode = QUIT_BACK_TO_LEVEL_ABOVE; screen->framesSinceLastChoice = 0; return; } // move up menu if (pad & PADLup && screen->framesSinceLastChoice >= screen->actionPause) { if (screen->selectedOption == 0) { screen->selectedOption = screen->numberOptions-1; } else screen->selectedOption--; screen->framesSinceLastChoice = 0; return; } // move down menu if (pad & PADLdown && screen->framesSinceLastChoice >= screen->actionPause) { if (screen->selectedOption == screen->numberOptions-1) { screen->selectedOption = 0; } else screen->selectedOption++; screen->framesSinceLastChoice = 0; return; } switch(option->type) { case CHOOSE_INTEGER: if (pad & PADLleft && screen->framesSinceLastChoice >= screen->integerChoicePause) { if ( (*(option->variable)) > option->lowest) { *(option->variable) -= 1; screen->framesSinceLastChoice = 0; if (option->instantResponseFlag == TRUE) { // NEW DrawSync(0); ResetGraph(1); (*option->functionPointer)(*(option->variable)); } return; } else { *(option->variable) = option->highest; screen->framesSinceLastChoice = 0; if (option->instantResponseFlag == TRUE) { (*option->functionPointer)(*(option->variable)); } return; } } else if (pad & PADLright && screen->framesSinceLastChoice >= screen->integerChoicePause) { if ( (*(option->variable)) < option->highest) { *(option->variable) += 1; screen->framesSinceLastChoice = 0; if (option->instantResponseFlag == TRUE) { (*option->functionPointer)(*(option->variable)); } return; } else { *(option->variable) = option->lowest; screen->framesSinceLastChoice = 0; if (option->instantResponseFlag == TRUE) { (*option->functionPointer)(*(option->variable)); } return; } } break; case TAKE_ACTION: // X or start if ( ((pad & PADRdown) || (pad & PADstart)) && screen->framesSinceLastChoice >= screen->actionPause) { screen->active = FALSE; screen->quitCode = option->actionLabel; screen->framesSinceLastChoice = 0; return; } break; default: assert(FALSE); } } void HandleMenuScreen (MenuScreen *screen) { assert(screen != NULL); if (screen->backgroundDrawEffectFlag != -1) SetUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); #if (MENU_SCREENS_RESOLUTION==LOW_RES) { if (ScreenResolution != LOW_RES && screen->backgroundDrawEffectFlag != -1) ResetGraphicResolution(320, 240); } #endif hsync = 0; while (screen->active == TRUE) { HandleSound(); GsSetWorkBase( (PACKET*)packetArea[bufferIndex]); GsClearOt(0, 0, &Wot[bufferIndex]); DrawMenuScreen(screen); HandleMenuScreenControls(screen); DisplayTextStrings (&Wot[bufferIndex]); if (screen->backgroundDrawEffectFlag != -1) { HandleMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag, &Wot[bufferIndex]); } DrawSync(0); hsync = VSync(0); CalculateCurrentFrameRate (hsync); //if (FrameRateDivider > 1) // { // printf("MISSING A FRAME HERE 12345\n"); // } #if 1 // no longer occurs if (hsync > MaximumScanLinesPerFrame * 12) { printf("Timeout problem\n"); DrawSync(0); VSync(0); ResetGraph(1); ResetDeepGraphicEffects(); } #endif GsSwapDispBuff(); GsSortClear(0, 0, 0, &Wot[bufferIndex]); GsDrawOt(&Wot[bufferIndex]); bufferIndex = GsGetActiveBuff(); frameNumber++; } #if (MENU_SCREENS_RESOLUTION==LOW_RES) { if (ScreenResolution != HI_RES) ResetGraphicResolution(640, 480); } #endif DrawSync(0); ResetGraph(1); if (screen->backgroundDrawEffectFlag != -1) CleanUpMenuScreenBackgroundGraphics(screen->backgroundDrawEffectFlag); } void InitialiseMenuScreenBackgroundGraphics (void) { GlobalPreviousShipDrawProcessLabel = -1; GlobalDisplayShip = NULL; GlobalPreviousGlobalShipLightingEffectFlag = -1; GlobalPreviousShipViewMode = -1; GlobalPreviousViewShip = NULL; GlobalViewSubMode = -999; PreviousShipDrawProcessLabel = -1; DisplayShip = NULL; PreviousGlobalShipLightingEffectFlag = -1; ShipRotationAxis = X_Y_PLANE; ShipRotationDirection = CLOCKWISE; ShipRotationSpeed = ONE/256; // two randomly-switch-every-N-frames modes // only difference is period of switch FramesWithinFirstEffectSwitcher = 1; FirstEffectSwitcherPeriod = MaximumGameFramesPerSecond * 8; FirstEffectSwitcherSubMode = BASE_MENU_SUB_MODE + (rand() % NUMBER_BASE_MENU_SUB_MODES); FramesWithinSecondEffectSwitcher = 1; SecondEffectSwitcherPeriod = MaximumGameFramesPerSecond * 6; SecondEffectSwitcherSubMode = BASE_MENU_SUB_MODE + (rand() % NUMBER_BASE_MENU_SUB_MODES); RegularlyUpdateShipDrawProcFlag = TRUE; FirstTimeEverForMenuEffectFlag = TRUE; InitAllDeepBackgroundEffects(); } void SetUpMenuScreenBackgroundGraphics (int effectID) { switch(effectID) { case SHIP_CIRCLING_VIEW: case SHIP_CUBOID_VIEW: case SHIP_SPHERICAL_VIEW: case SHIP_HELICAL_VIEW: case SHIP_LAZY_ROTATION_VIEW: case SHIP_ROTATES_SLOWLY: case TWO_SHIPS_ROTATE_SLOWLY: SetUpMenuEffectSubMode(effectID); break; case FIRST_EFFECT_SWITCHER: FramesWithinFirstEffectSwitcher = 1; FirstEffectSwitcherSubMode = BASE_MENU_SUB_MODE + (rand() % NUMBER_BASE_MENU_SUB_MODES); SetUpMenuEffectSubMode(FirstEffectSwitcherSubMode); break; case SECOND_EFFECT_SWITCHER: FramesWithinSecondEffectSwitcher = 1; SecondEffectSwitcherSubMode = BASE_MENU_SUB_MODE + (rand() % NUMBER_BASE_MENU_SUB_MODES); SetUpMenuEffectSubMode(SecondEffectSwitcherSubMode); break; default: printf("HERE at line %d; bad value %d\n", __LINE__, effectID); assert(FALSE); } ResetDeepGraphicEffects(); } void SetUpMenuEffectSubMode (int mode) { switch(mode) { case SHIP_CIRCLING_VIEW: case SHIP_CUBOID_VIEW: case SHIP_SPHERICAL_VIEW: case SHIP_HELICAL_VIEW: case SHIP_LAZY_ROTATION_VIEW: InitShipCameraMode(mode); break; case SHIP_ROTATES_SLOWLY: InitShipRotatesSlowlyEffect(); break; case FIRST_EFFECT_SWITCHER: assert(FALSE); // should never get here break; case SECOND_EFFECT_SWITCHER: assert(FALSE); // should never get here break; case TWO_SHIPS_ROTATE_SLOWLY: InitTwoShipsRotating(); break; default: assert(FALSE); } FramesSinceMenuEffectLastSet = 0; SetViewInSystem(); } void InitShipCameraMode (int mode) { int choice; ObjectHandler *ship; GsSetLightMode(0); GsSetAmbient(ONE/2, ONE/2, ONE/2); GlobalPreviousShipDrawProcessLabel = ShipDrawProcessLabel; ShipDrawProcessLabel = GetNewShipDrawProcessLabel(); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); GlobalPreviousGlobalShipLightingEffectFlag = GlobalShipLightingEffectFlag; switch(OverallGameState) { case SETTING_UP_FREE_PRACTICE: case SETTING_UP_STRAIGHT_RACE: case SETTING_UP_TWO_PLAYER_RACE: case SETTING_UP_TRACK_VIEWING: case SETTING_UP_MUSIC_OPTIONS: ship = &PlayerOnesShip; break; case SETTING_UP_ROLLING_DEMO: case MAIN_MENU: ship = &OtherShips[0]; break; default: assert(FALSE); } GlobalDisplayShip = ship; GlobalPreviousViewShip = TheViewShip; GlobalPreviousShipViewMode = ship->viewMode; InitMatrix( &GlobalDisplayShip->matrix); GlobalDisplayShip->coord.coord = GlobalDisplayShip->matrix; GlobalDisplayShip->coord.flg = 0; GlobalDisplayShip->tunnelSection = 0; switch(mode) { case SHIP_CIRCLING_VIEW: choice = rand() % 4; switch(choice) { case 0: GlobalViewSubMode = VIEW_CIRCLES_OBJECT_CLOSE_IN; break; case 1: GlobalViewSubMode = VIEW_CIRCLES_OBJECT; break; case 2: GlobalViewSubMode = VIEW_CIRCLES_OBJECT_TWISTING; break; case 3: GlobalViewSubMode = VIEW_CIRCLES_OBJECT_CHANGING_ORBITAL_PLANE; break; default: assert(FALSE); } break; case SHIP_CUBOID_VIEW: choice = rand() % 2; switch(choice) { case 0: GlobalViewSubMode = VIEW_BY_SECOND_CUBOID_VIEWER; break; case 1: GlobalViewSubMode = VIEW_BY_THIRD_CUBOID_VIEWER; break; default: assert(FALSE); } break; case SHIP_SPHERICAL_VIEW: choice = rand() % 2; switch(choice) { case 0: GlobalViewSubMode = VIEW_BY_SECOND_SPHERICAL_VIEWER; break; case 1: GlobalViewSubMode = VIEW_BY_FOURTH_SPHERICAL_VIEWER; break; default: assert(FALSE); } break; case SHIP_HELICAL_VIEW: choice = rand() % 2; switch(choice) { case 0: GlobalViewSubMode = VIEW_BY_THIRD_HELICAL_VIEWER; break; case 1: GlobalViewSubMode = VIEW_BY_FOURTH_HELICAL_VIEWER; break; default: assert(FALSE); } break; case SHIP_LAZY_ROTATION_VIEW: GlobalViewSubMode = VIEW_BY_FIRST_LAZY_ROTATION_VIEW + (rand() % NUMBER_LAZY_ROTATION_MODES); break; default: assert(FALSE); } GlobalDisplayShip->viewMode = GlobalViewSubMode; SetNewViewShip(GlobalDisplayShip); } void InitShipRotatesSlowlyEffect (void) { ObjectHandler *ship; GsSetLightMode(0); GsSetAmbient(ONE/2, ONE/2, ONE/2); PreviousShipDrawProcessLabel = ShipDrawProcessLabel; ShipDrawProcessLabel = GetNewShipDrawProcessLabel(); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); PreviousGlobalShipLightingEffectFlag = GlobalShipLightingEffectFlag; switch(OverallGameState) { case SETTING_UP_FREE_PRACTICE: case SETTING_UP_STRAIGHT_RACE: case SETTING_UP_TWO_PLAYER_RACE: case SETTING_UP_TRACK_VIEWING: case SETTING_UP_MUSIC_OPTIONS: ship = &PlayerOnesShip; break; case SETTING_UP_ROLLING_DEMO: case MAIN_MENU: ship = &OtherShips[0]; break; default: assert(FALSE); } DisplayShip = ship; InitMatrix( &DisplayShip->matrix); DisplayShip->coord.coord = DisplayShip->matrix; DisplayShip->coord.flg = 0; DisplayShip->tunnelSection = 0; ViewTypeFlag = REFERENCE_VIEW; TheView.rz = 0; TheView.super = WORLD; TheView.vrx = 0; TheView.vry = 0; TheView.vrz = 0; TheView.vpx = 0; TheView.vpy = 0; TheView.vpz = -250; ViewTypeFlag = REFERENCE_VIEW; GsSetProjection(FIXED_PROJECTION_DISTANCE); ShipRotationAxis = X_Y_PLANE + (rand() % 3); ShipRotationDirection = CLOCKWISE + (rand() % 2); } void InitTwoShipsRotating (void) { GsSetLightMode(0); GsSetAmbient(ONE/2, ONE/2, ONE/2); PreviousShipDrawProcessLabel = ShipDrawProcessLabel; ShipDrawProcessLabel = GetNewShipDrawProcessLabel(); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); PreviousGlobalShipLightingEffectFlag = GlobalShipLightingEffectFlag; FirstDisplayShip = &PlayerOnesShip; SecondDisplayShip = &PlayerTwosShip; InitMatrix( &FirstDisplayShip->matrix); FirstDisplayShip->matrix.t[1] = -75; FirstDisplayShip->coord.coord = FirstDisplayShip->matrix; FirstDisplayShip->coord.flg = 0; FirstDisplayShip->tunnelSection = 0; InitMatrix( &SecondDisplayShip->matrix); SecondDisplayShip->matrix.t[1] = 75; SecondDisplayShip->coord.coord = SecondDisplayShip->matrix; SecondDisplayShip->coord.flg = 0; SecondDisplayShip->tunnelSection = 0; ViewTypeFlag = REFERENCE_VIEW; TheView.rz = 0; TheView.super = WORLD; TheView.vrx = 0; TheView.vry = 0; TheView.vrz = 0; TheView.vpx = 0; TheView.vpy = 0; TheView.vpz = -250; ViewTypeFlag = REFERENCE_VIEW; GsSetProjection(FIXED_PROJECTION_DISTANCE); ShipRotationAxis = X_Y_PLANE + (rand() % 3); ShipRotationDirection = CLOCKWISE + (rand() % 2); } void CleanUpMenuScreenBackgroundGraphics (int effectID) { switch(effectID) { case SHIP_CIRCLING_VIEW: case SHIP_CUBOID_VIEW: case SHIP_SPHERICAL_VIEW: case SHIP_HELICAL_VIEW: case SHIP_LAZY_ROTATION_VIEW: case SHIP_ROTATES_SLOWLY: case TWO_SHIPS_ROTATE_SLOWLY: CleanUpMenuEffectSubMode(effectID); break; case FIRST_EFFECT_SWITCHER: CleanUpMenuEffectSubMode(FirstEffectSwitcherSubMode); break; case SECOND_EFFECT_SWITCHER: CleanUpMenuEffectSubMode(SecondEffectSwitcherSubMode); break; default: assert(FALSE); } } void CleanUpMenuEffectSubMode (int mode) { switch(mode) { case SHIP_CIRCLING_VIEW: case SHIP_CUBOID_VIEW: case SHIP_SPHERICAL_VIEW: case SHIP_HELICAL_VIEW: case SHIP_LAZY_ROTATION_VIEW: CleanUpShipCameraMode(mode); break; case SHIP_ROTATES_SLOWLY: CleanUpShipRotatesSlowlyEffect(); break; case FIRST_EFFECT_SWITCHER: assert(FALSE); // should never get here break; case SECOND_EFFECT_SWITCHER: assert(FALSE); // should never get here break; case TWO_SHIPS_ROTATE_SLOWLY: CleanUpTwoShipsRotating(); break; default: assert(FALSE); } } void CleanUpShipCameraMode (int mode) { ObjectHandler *ship; ShipDrawProcessLabel = GlobalPreviousShipDrawProcessLabel; SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); GlobalShipLightingEffectFlag = GlobalPreviousGlobalShipLightingEffectFlag; TheViewShip = GlobalPreviousViewShip; switch(OverallGameState) { case SETTING_UP_FREE_PRACTICE: case SETTING_UP_STRAIGHT_RACE: case SETTING_UP_TWO_PLAYER_RACE: case SETTING_UP_TRACK_VIEWING: case SETTING_UP_MUSIC_OPTIONS: ship = &PlayerOnesShip; break; case SETTING_UP_ROLLING_DEMO: case MAIN_MENU: ship = &OtherShips[0]; break; default: assert(FALSE); } ship->viewMode = GlobalPreviousShipViewMode; } void CleanUpShipRotatesSlowlyEffect (void) { ShipDrawProcessLabel = PreviousShipDrawProcessLabel; SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); GlobalShipLightingEffectFlag = PreviousGlobalShipLightingEffectFlag; } void CleanUpTwoShipsRotating (void) { ShipDrawProcessLabel = PreviousShipDrawProcessLabel; SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); GlobalShipLightingEffectFlag = PreviousGlobalShipLightingEffectFlag; } void HandleMenuScreenBackgroundGraphics (int backgroundGraphicsEffectID, GsOT *ot) { DrawDeepestBackgroundEffect(ot); switch(backgroundGraphicsEffectID) { case SHIP_CIRCLING_VIEW: case SHIP_CUBOID_VIEW: case SHIP_SPHERICAL_VIEW: case SHIP_HELICAL_VIEW: case SHIP_LAZY_ROTATION_VIEW: case SHIP_ROTATES_SLOWLY: case TWO_SHIPS_ROTATE_SLOWLY: HandleMenuEffectSubMode(backgroundGraphicsEffectID, ot); break; case FIRST_EFFECT_SWITCHER: HandleFirstEffectSwitcher(ot); break; case SECOND_EFFECT_SWITCHER: HandleSecondEffectSwitcher(ot); break; default: assert(FALSE); } //DrawDeepestBackgroundEffect(ot); } void HandleMenuEffectSubMode (int mode, GsOT *ot) { switch(mode) { case SHIP_CIRCLING_VIEW: case SHIP_CUBOID_VIEW: case SHIP_SPHERICAL_VIEW: case SHIP_HELICAL_VIEW: case SHIP_LAZY_ROTATION_VIEW: HandleShipViewing(mode, ot); HandleTheView(); break; case SHIP_ROTATES_SLOWLY: DisplayShipRotating(ot); SetViewInSystem(); break; case FIRST_EFFECT_SWITCHER: assert(FALSE); // should never get here break; case SECOND_EFFECT_SWITCHER: assert(FALSE); // should never get here break; case TWO_SHIPS_ROTATE_SLOWLY: DisplayTwoShipsRotating(ot); break; default: assert(FALSE); } FramesSinceMenuEffectLastSet++; } void HandleShipViewing (int mode, GsOT *ot) { MATRIX matrix; int cyclePoint, theta; int resetFrequency, modeResetFrequency; cyclePoint = FramesSinceMenuEffectLastSet % 180; theta = (ONE * cyclePoint) / 180; // cycle three coloured lights TheLights[0].vx = rcos(theta); TheLights[0].vy = rsin(theta); TheLights[0].vz = 0; TheLights[0].r = 128; TheLights[0].g = 0; TheLights[0].b = 0; GsSetFlatLight(0, &TheLights[0]); TheLights[1].vz = rcos(theta); TheLights[1].vx = rsin(theta); TheLights[1].vy = 0; TheLights[1].g = 128; TheLights[1].r = 0; TheLights[1].b = 0; GsSetFlatLight(1, &TheLights[1]); TheLights[2].vy = rcos(theta); TheLights[2].vz = rsin(theta); TheLights[2].vx = 0; TheLights[2].b = 128; TheLights[2].r = 0; TheLights[2].g = 0; GsSetFlatLight(2, &TheLights[2]); ExecuteSingleDrawProcess( &ShipDrawProcess); GlobalDisplayShip->coord.flg = 0; if (GlobalDisplayShip != NULL) { GsGetLs(&(GlobalDisplayShip->coord), &matrix); GsSetLightMatrix(&matrix); GsSetLsMatrix(&matrix); HandleGlobalShipLightingEffect( &matrix); GsSortObject4( &(GlobalDisplayShip->handler), ot, OT_SHIFT, getScratchAddr(0)); } assert(FrameRateDivider > 0); resetFrequency = (MaximumGameFramesPerSecond * GENERAL_PICK_NEW_DRAW_PROC_FREQUENCY) / FrameRateDivider; if ((FramesSinceMenuEffectLastSet % resetFrequency) == 0 && RegularlyUpdateShipDrawProcFlag == TRUE) { ShipDrawProcessLabel = GetNewShipDrawProcessLabel(); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); } assert(FrameRateDivider > 0); modeResetFrequency = (MaximumGameFramesPerSecond * GENERAL_PICK_NEW_SUB_MODE_FREQUENCY) / FrameRateDivider; if ((FramesSinceMenuEffectLastSet % modeResetFrequency) == 0) { int choice, newMode; switch(mode) { case SHIP_CIRCLING_VIEW: for (;;) { choice = rand() % 4; switch(choice) { case 0: newMode = VIEW_CIRCLES_OBJECT_CLOSE_IN; break; case 1: newMode = VIEW_CIRCLES_OBJECT; break; case 2: newMode = VIEW_CIRCLES_OBJECT_TWISTING; break; case 3: newMode = VIEW_CIRCLES_OBJECT_CHANGING_ORBITAL_PLANE; break; default: assert(FALSE); } if (newMode != GlobalViewSubMode) break; } GlobalViewSubMode = newMode; break; case SHIP_CUBOID_VIEW: for (;;) { choice = rand() % 2; switch(choice) { case 0: newMode = VIEW_BY_SECOND_CUBOID_VIEWER; break; case 1: newMode = VIEW_BY_THIRD_CUBOID_VIEWER; break; default: assert(FALSE); } if (newMode != GlobalViewSubMode) break; } GlobalViewSubMode = newMode; break; case SHIP_SPHERICAL_VIEW: for (;;) { choice = rand() % 2; switch(choice) { case 0: newMode = VIEW_BY_SECOND_SPHERICAL_VIEWER; break; case 1: newMode = VIEW_BY_FOURTH_SPHERICAL_VIEWER; break; default: assert(FALSE); } if (newMode != GlobalViewSubMode) break; } GlobalViewSubMode = newMode; break; case SHIP_HELICAL_VIEW: for (;;) { choice = rand() % 2; switch(choice) { case 0: newMode = VIEW_BY_THIRD_HELICAL_VIEWER; break; case 1: newMode = VIEW_BY_FOURTH_HELICAL_VIEWER; break; default: assert(FALSE); } if (newMode != GlobalViewSubMode) break; } GlobalViewSubMode = newMode; break; case SHIP_LAZY_ROTATION_VIEW: for (;;) { newMode = VIEW_BY_FIRST_LAZY_ROTATION_VIEW + (rand() % NUMBER_LAZY_ROTATION_MODES); if (newMode != GlobalViewSubMode) break; } GlobalViewSubMode = newMode; break; default: assert(FALSE); } GlobalDisplayShip->viewMode = GlobalViewSubMode; SetNewViewShip(GlobalDisplayShip); } } void DisplayShipRotating (GsOT *ot) { MATRIX matrix, twistMatrix; SVECTOR twistVector; int angle; int cyclePoint, theta; int rotationResetFrequency, resetFrequency; int newChoice; cyclePoint = FramesSinceMenuEffectLastSet % 180; theta = (ONE * cyclePoint) / 180; // cycle three coloured lights TheLights[0].vx = rcos(theta); TheLights[0].vy = rsin(theta); TheLights[0].vz = 0; TheLights[0].r = 128; TheLights[0].g = 0; TheLights[0].b = 0; GsSetFlatLight(0, &TheLights[0]); TheLights[1].vz = rcos(theta); TheLights[1].vx = rsin(theta); TheLights[1].vy = 0; TheLights[1].g = 128; TheLights[1].r = 0; TheLights[1].b = 0; GsSetFlatLight(1, &TheLights[1]); TheLights[2].vy = rcos(theta); TheLights[2].vz = rsin(theta); TheLights[2].vx = 0; TheLights[2].b = 128; TheLights[2].r = 0; TheLights[2].g = 0; GsSetFlatLight(2, &TheLights[2]); ExecuteSingleDrawProcess( &ShipDrawProcess); if (DisplayShip != NULL) { GsGetLs(&(DisplayShip->coord), &matrix); GsSetLightMatrix(&matrix); GsSetLsMatrix(&matrix); HandleGlobalShipLightingEffect( &matrix); GsSortObject4( &(DisplayShip->handler), ot, OT_SHIFT, getScratchAddr(0)); } assert(CurrentFrameRate > 0); switch(ShipRotationDirection) { case CLOCKWISE: angle = ShipRotationSpeed; TheView.rz -= ((90 * ONE) / CurrentFrameRate); break; case ANTICLOCKWISE: angle = -ShipRotationSpeed; TheView.rz += ((90 * ONE) / CurrentFrameRate); break; default: assert(FALSE); } ViewTypeFlag = REFERENCE_VIEW; switch(ShipRotationAxis) { case X_Y_PLANE: setVECTOR( &twistVector, 0, 0, angle); break; case X_Z_PLANE: setVECTOR( &twistVector, 0, angle, 0); break; case Y_Z_PLANE: setVECTOR( &twistVector, angle, 0, 0); break; default: assert(FALSE); } RotMatrix( &twistVector, &twistMatrix); MulMatrix0( &DisplayShip->coord.coord, &twistMatrix, &DisplayShip->coord.coord); DisplayShip->coord.flg = 0; assert(FrameRateDivider > 0); rotationResetFrequency = (MaximumGameFramesPerSecond * SHIP_ROTATES_SLOWLY_RESET_FREQUENCY) / FrameRateDivider; if ((FramesSinceMenuEffectLastSet % rotationResetFrequency) == 0) { for (;;) { newChoice = X_Y_PLANE + (rand() % 3); if (newChoice != ShipRotationAxis) break; } ShipRotationAxis = newChoice; for (;;) { newChoice = CLOCKWISE + (rand() % 2); if (newChoice != ShipRotationDirection) break; } ShipRotationDirection = newChoice; } assert(FrameRateDivider > 0); resetFrequency = (MaximumGameFramesPerSecond * GENERAL_PICK_NEW_DRAW_PROC_FREQUENCY) / FrameRateDivider; if ((FramesSinceMenuEffectLastSet % resetFrequency) == 0) { ShipDrawProcessLabel = GetNewShipDrawProcessLabel(); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); } } void HandleFirstEffectSwitcher (GsOT *ot) { assert(FirstEffectSwitcherPeriod > 0); if (FramesWithinFirstEffectSwitcher >= FirstEffectSwitcherPeriod || FirstTimeEverForMenuEffectFlag == TRUE) { int newSubMode; CleanUpMenuEffectSubMode(FirstEffectSwitcherSubMode); // set new mode for (;;) { newSubMode = BASE_MENU_SUB_MODE + (rand() % NUMBER_BASE_MENU_SUB_MODES); if (newSubMode != FirstEffectSwitcherSubMode) break; } SetUpMenuEffectSubMode(newSubMode); FirstEffectSwitcherSubMode = newSubMode; FramesWithinFirstEffectSwitcher = 0; HandleMenuEffectSubMode(FirstEffectSwitcherSubMode, ot); if (FirstTimeEverForMenuEffectFlag == TRUE) FirstTimeEverForMenuEffectFlag = FALSE; } else { FramesWithinFirstEffectSwitcher += FrameRateDivider; HandleMenuEffectSubMode(FirstEffectSwitcherSubMode, ot); } } void HandleSecondEffectSwitcher (GsOT *ot) { assert(SecondEffectSwitcherPeriod > 0); if (FramesWithinSecondEffectSwitcher >= SecondEffectSwitcherPeriod || FirstTimeEverForMenuEffectFlag == TRUE) { int newSubMode; CleanUpMenuEffectSubMode(SecondEffectSwitcherSubMode); // set new mode for (;;) { newSubMode = BASE_MENU_SUB_MODE + (rand() % NUMBER_BASE_MENU_SUB_MODES); if (newSubMode != SecondEffectSwitcherSubMode) break; } SetUpMenuEffectSubMode(newSubMode); SecondEffectSwitcherSubMode = newSubMode; FramesWithinSecondEffectSwitcher = 0; HandleMenuEffectSubMode(SecondEffectSwitcherSubMode, ot); if (FirstTimeEverForMenuEffectFlag == TRUE) FirstTimeEverForMenuEffectFlag = FALSE; } else { FramesWithinSecondEffectSwitcher += FrameRateDivider; HandleMenuEffectSubMode(SecondEffectSwitcherSubMode, ot); } } void DisplayTwoShipsRotating (GsOT *ot) { MATRIX matrix, twistMatrix; SVECTOR twistVector; int angle; int cyclePoint, theta; int rotationResetFrequency, resetFrequency; int newChoice; cyclePoint = FramesSinceMenuEffectLastSet % 180; theta = (ONE * cyclePoint) / 180; // cycle three coloured lights TheLights[0].vx = rcos(theta); TheLights[0].vy = rsin(theta); TheLights[0].vz = 0; TheLights[0].r = 128; TheLights[0].g = 0; TheLights[0].b = 0; GsSetFlatLight(0, &TheLights[0]); TheLights[1].vz = rcos(theta); TheLights[1].vx = rsin(theta); TheLights[1].vy = 0; TheLights[1].g = 128; TheLights[1].r = 0; TheLights[1].b = 0; GsSetFlatLight(1, &TheLights[1]); TheLights[2].vy = rcos(theta); TheLights[2].vz = rsin(theta); TheLights[2].vx = 0; TheLights[2].b = 128; TheLights[2].r = 0; TheLights[2].g = 0; GsSetFlatLight(2, &TheLights[2]); ExecuteSingleDrawProcess( &ShipDrawProcess); if (FirstDisplayShip != NULL) { GsGetLs(&(FirstDisplayShip->coord), &matrix); GsSetLightMatrix(&matrix); GsSetLsMatrix(&matrix); HandleGlobalShipLightingEffect( &matrix); GsSortObject4( &(FirstDisplayShip->handler), ot, OT_SHIFT, getScratchAddr(0)); } if (SecondDisplayShip != NULL) { GsGetLs(&(SecondDisplayShip->coord), &matrix); GsSetLightMatrix(&matrix); GsSetLsMatrix(&matrix); HandleGlobalShipLightingEffect( &matrix); GsSortObject4( &(SecondDisplayShip->handler), ot, OT_SHIFT, getScratchAddr(0)); } assert(CurrentFrameRate > 0); switch(ShipRotationDirection) { case CLOCKWISE: angle = ShipRotationSpeed; TheView.rz -= ((90 * ONE) / CurrentFrameRate); break; case ANTICLOCKWISE: angle = -ShipRotationSpeed; TheView.rz += ((90 * ONE) / CurrentFrameRate); break; default: assert(FALSE); } ViewTypeFlag = REFERENCE_VIEW; switch(ShipRotationAxis) { case X_Y_PLANE: setVECTOR( &twistVector, 0, 0, angle); break; case X_Z_PLANE: setVECTOR( &twistVector, 0, angle, 0); break; case Y_Z_PLANE: setVECTOR( &twistVector, angle, 0, 0); break; default: assert(FALSE); } RotMatrix( &twistVector, &twistMatrix); MulMatrix0( &FirstDisplayShip->coord.coord, &twistMatrix, &FirstDisplayShip->coord.coord); FirstDisplayShip->coord.flg = 0; setVECTOR( &twistVector, -twistVector.vx, -twistVector.vy, -twistVector.vz); RotMatrix( &twistVector, &twistMatrix); MulMatrix0( &SecondDisplayShip->coord.coord, &twistMatrix, &SecondDisplayShip->coord.coord); SecondDisplayShip->coord.flg = 0; assert(FrameRateDivider > 0); rotationResetFrequency = (MaximumGameFramesPerSecond * SHIP_ROTATES_SLOWLY_RESET_FREQUENCY) / FrameRateDivider; if ((FramesSinceMenuEffectLastSet % rotationResetFrequency) == 0) { for (;;) { newChoice = X_Y_PLANE + (rand() % 3); if (newChoice != ShipRotationAxis) break; } ShipRotationAxis = newChoice; for (;;) { newChoice = CLOCKWISE + (rand() % 2); if (newChoice != ShipRotationDirection) break; } ShipRotationDirection = newChoice; } assert(FrameRateDivider > 0); resetFrequency = (MaximumGameFramesPerSecond * GENERAL_PICK_NEW_DRAW_PROC_FREQUENCY) / FrameRateDivider; if ((FramesSinceMenuEffectLastSet % resetFrequency) == 0) { ShipDrawProcessLabel = GetNewShipDrawProcessLabel(); SetDrawProcess2( &ShipDrawProcess, &Wave15ImageInfo, ShipDrawProcessLabel, FIFTH, FIFTH); } } #define NUMBER_GOOD_SHIP_DRAW_PROCS 17 int ListOfGoodShipDrawProcs[NUMBER_GOOD_SHIP_DRAW_PROCS] = {14, 15, 18, 20, 21, 24, 33, 34, 38, 40, 43, 59, 62, 67, 77, 104, 121}; int GetNewShipDrawProcessLabel (void) { int label, index; index = rand() % NUMBER_GOOD_SHIP_DRAW_PROCS; label = ListOfGoodShipDrawProcs[index]; return label; } // deep background: just means sprite/line effects occurring behind // the moving ships void InitAllDeepBackgroundEffects (void) { int i; ExplodingLinesRectangleSizeFactor = 2048; for (i = 0; i < 128; i++) { NeedleThreadPoints[i] = i; NeedleThreadPoints[i+128] = 512 + i; // 287 + i; } NumberOfSpirals = 0; for (i = 0; i < MAX_SPIRALS; i++) { InitSpiralToVoid( &TheSpirals[i]); } NumberLocalSprites = 0; LocalSpriteList[NumberLocalSprites] = &SimpleBlueSprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &SmoothSpectrumSprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &SmoothRedSprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &CircleSprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &TileFiveSprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number1Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number2Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number5Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number7Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number8Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number9Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number10Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number11Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number12Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number13Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number15Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number17Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number21Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number22Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number24Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number25Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number26Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number28Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number29Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number33Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number34Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number38Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number39Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number41Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number42Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number43Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number45Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number46Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number47Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Number52Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Spiral1Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Spiral2Sprite; NumberLocalSprites++; LocalSpriteList[NumberLocalSprites] = &Spiral3Sprite; NumberLocalSprites++; assert(NumberLocalSprites <= MAX_LOCAL_SPRITES); DeepBackgroundGraphicsFramePeriod = MaximumGameFramesPerSecond * 4; DeepBackgroundGraphicsFlipPeriod = MaximumGameFramesPerSecond * 8; FramesWithinDeepbackgroundGraphics = 0; DeepBackgroundGraphicsSubMode = BASE_DEEP_BACKGROUND_SUB_MODE + (rand() % NUMBER_DEEP_BACKGROUND_SUB_MODES); InitSpecificDeepBackgroundEffect(DeepBackgroundGraphicsSubMode); } void ResetDeepGraphicEffects (void) { FramesWithinDeepbackgroundGraphics = 0; DeepBackgroundGraphicsSubMode = BASE_DEEP_BACKGROUND_SUB_MODE + (rand() % NUMBER_DEEP_BACKGROUND_SUB_MODES); InitSpecificDeepBackgroundEffect(DeepBackgroundGraphicsSubMode); } void InitSpecificDeepBackgroundEffect (int which) { switch(DeepBackgroundGraphicsSubMode) { case EXPLODING_LINES: case NEEDLETHREAD_LINES: // do nowt break; case SPIRAL_EFFECT: SpiralOutwardDirection = CLOCKWISE_OUT + (rand() % 2); SpiralRadialDirection = FORWARD + (rand() % 2); break; case SPRITE_WALL_FADE_IN_AND_OUT: FirstChosenGlobalSpriteIndex = rand() % NumberLocalSprites; break; case SPRITE_WALL_MERGE_THROUGH_SPRITES: SecondChosenGlobalSpriteIndex = rand() % NumberLocalSprites; ThirdChosenGlobalSpriteIndex = rand() % NumberLocalSprites; SpriteMergeDirection = rand() % 4; break; default: assert(FALSE); } FramesWithinDeepbackgroundGraphics = 0; } void DrawDeepestBackgroundEffect (GsOT *ot) { int time, cycleRatio, newEffect; FramesWithinDeepbackgroundGraphics++; #if 0 if (FramesWithinDeepbackgroundGraphics >= DeepBackgroundGraphicsFramePeriod) { FramesWithinDeepbackgroundGraphics = 0; #if 0 newEffect = GetNewDeepBackgroundEffect(DeepBackgroundGraphicsSubMode); DrawSync(0); ResetGraph(1); InitSpecificDeepBackgroundEffect(newEffect); DeepBackgroundGraphicsSubMode = newEffect; #endif } #endif if (FramesWithinDeepbackgroundGraphics >= DeepBackgroundGraphicsFlipPeriod) { FramesWithinDeepbackgroundGraphics = 0; #if 1 newEffect = GetNewDeepBackgroundEffect(DeepBackgroundGraphicsSubMode); DrawSync(0); ResetGraph(1); InitSpecificDeepBackgroundEffect(newEffect); DeepBackgroundGraphicsSubMode = newEffect; #endif } assert(DeepBackgroundGraphicsFramePeriod > 0); time = FramesWithinDeepbackgroundGraphics % DeepBackgroundGraphicsFramePeriod; cycleRatio = (time * ONE) / DeepBackgroundGraphicsFramePeriod; assert(cycleRatio >= 0); assert(cycleRatio < ONE); switch(DeepBackgroundGraphicsSubMode) { case EXPLODING_LINES: DrawExplodingLines(ot, cycleRatio); break; case NEEDLETHREAD_LINES: DrawNeedleThreadLines(ot, cycleRatio); break; case SPIRAL_EFFECT: assert(FALSE); // no more //DrawSpiralEffect(ot, cycleRatio); break; case SPRITE_WALL_FADE_IN_AND_OUT: DrawSpriteWallFadingInAndOut(ot, cycleRatio); break; case SPRITE_WALL_MERGE_THROUGH_SPRITES: assert(FALSE); //DrawSpriteWallMergingThroughSprites(ot, cycleRatio); break; default: assert(FALSE); } } // note: needs changing if number / order of #define modes changes int GetNewDeepBackgroundEffect (int current) { int newEffect; int choice; switch(DeepBackgroundGraphicsSubMode) { case EXPLODING_LINES: choice = rand() % 2; switch(choice) { case 0: newEffect = NEEDLETHREAD_LINES; break; case 1: newEffect = SPRITE_WALL_FADE_IN_AND_OUT; break; default: assert(FALSE); } break; case NEEDLETHREAD_LINES: choice = rand() % 2; switch(choice) { case 0: newEffect = EXPLODING_LINES; break; case 1: newEffect = SPRITE_WALL_FADE_IN_AND_OUT; break; default: assert(FALSE); } break; case SPIRAL_EFFECT: assert(FALSE); #if 0 // no more choice = rand() % 4; switch(choice) { case 0: newEffect = EXPLODING_LINES; break; case 1: newEffect = NEEDLETHREAD_LINES; break; //case 2: newEffect = SPRITE_WALL_FADE_IN_AND_OUT; break; case 2: case 3: newEffect = SPRITE_WALL_MERGE_THROUGH_SPRITES; break; default: assert(FALSE); } #endif break; case SPRITE_WALL_FADE_IN_AND_OUT: choice = rand() % 2; switch(choice) { case 0: newEffect = EXPLODING_LINES; break; case 1: newEffect = NEEDLETHREAD_LINES; break; default: assert(FALSE); } break; case SPRITE_WALL_MERGE_THROUGH_SPRITES: assert(FALSE); #if 0 // no more choice = rand() % 3; switch(choice) { case 0: newEffect = EXPLODING_LINES; break; case 1: newEffect = NEEDLETHREAD_LINES; break; case 2: newEffect = SPIRAL_EFFECT; break; default: assert(FALSE); } #endif break; default: assert(FALSE); } return newEffect; } // number lines drawn = ONE/step void DrawExplodingLines (GsOT *ot, int cycleRatio) { int firstRectSizeFactor, secondRectSizeFactor; register int theta; int phase; GsGLINE gline; CVECTOR colour; int fasterChangeRatio; int step; fasterChangeRatio = cycleRatio * 4; while (fasterChangeRatio >= ONE) fasterChangeRatio -= ONE; if (cycleRatio < (ONE-ExplodingLinesRectangleSizeFactor)) { firstRectSizeFactor = (cycleRatio * ONE) / (ONE-ExplodingLinesRectangleSizeFactor); secondRectSizeFactor = ((cycleRatio-ExplodingLinesRectangleSizeFactor) * ONE) / (ONE-ExplodingLinesRectangleSizeFactor); if (secondRectSizeFactor <= 0) { phase = 0; secondRectSizeFactor = 0; } else { phase = 1; } } else { phase = 2; firstRectSizeFactor = ONE; secondRectSizeFactor = ((cycleRatio-ExplodingLinesRectangleSizeFactor) * ONE) / (ONE-ExplodingLinesRectangleSizeFactor); } GetColourDuringCycle (fasterChangeRatio, &colour); gline.r0 = colour.r; gline.g0 = colour.g; gline.b0 = colour.b; gline.r1 = colour.g; gline.g1 = colour.b; gline.b1 = colour.r; // make semi-trans gline.attribute = 0; gline.attribute |= GsALON; gline.attribute |= (1<<28); gline.attribute |= (1<<29); step = 24; // 16 for (theta = 0; theta < ONE; theta += step) { switch(phase) { case 0: gline.x0 = 0; gline.y0 = 0; GetPointOnScreenCentredRect( firstRectSizeFactor, theta, &gline.x1, &gline.y1); break; case 1: GetPointOnScreenCentredRect( firstRectSizeFactor, theta, &gline.x1, &gline.y1); GetPointOnScreenCentredRect( secondRectSizeFactor, theta, &gline.x0, &gline.y0); break; case 2: GetPointOnScreenCentredRect( secondRectSizeFactor, theta, &gline.x0, &gline.y0); GetPointOnScreenCentredRect( ONE, theta, &gline.x1, &gline.y1); break; default: assert(FALSE); } GsSortGLine( &gline, ot, BEHIND_OTHERS_OT_VALUE + (theta/step)); } } // number lines drawn = step void DrawNeedleThreadLines (GsOT *ot, int cycleRatio) { register int i; GsGLINE gline; CVECTOR colour; int step; for (i = 0; i < 256; i++) { NeedleThreadPoints[i] = MovePointIndexAroundRect(NeedleThreadPoints[i], CLOCKWISE, 4, ScreenWidth, ScreenHeight); // speed used to be 1 } // make semi-trans gline.attribute = 0; gline.attribute |= GsALON; gline.attribute |= (1<<28); gline.attribute |= (1<<29); GetColourDuringCycle (cycleRatio, &colour); gline.r0 = colour.r; gline.g0 = colour.g; gline.b0 = colour.b; gline.r1 = colour.g; gline.g1 = colour.b; gline.b1 = colour.r; step = 128; // 64 for (i = 0; i < step; i++) { GetXAndYOfIndexOntoScreenCentredRectangle(NeedleThreadPoints[i], ScreenWidth, ScreenHeight, &gline.x0, &gline.y0); GetXAndYOfIndexOntoScreenCentredRectangle(NeedleThreadPoints[i+128], ScreenWidth, ScreenHeight, &gline.x1, &gline.y1); if (gline.y0 == -ScreenHeight/2) gline.y0 -= 6; if (gline.y1 == -ScreenHeight/2) gline.y1 -= 6; GsSortGLine( &gline, ot, BEHIND_OTHERS_OT_VALUE + i); } } // number lines drawn: up to [spiral.numberOfArms * ((ONE-step)/step)] // 16 * (4096-128)) / 128 = 511 void DrawSpiralEffect (GsOT *ot, int cycleRatio) { Spiral *spiral; int factor1, factor2; int phase; register int i, j; GsGLINE gline; int step; CVECTOR colour; int fasterChangeRatio; assert(cycleRatio >= 0); assert(cycleRatio < ONE); step = 512; // 256, 128, 64 fasterChangeRatio = cycleRatio * 4; while (fasterChangeRatio >= ONE) fasterChangeRatio -= ONE; if (fasterChangeRatio == 0) // cycleRatio { switch(SpiralOutwardDirection) { case CLOCKWISE_OUT: SpiralOutwardDirection = ANTICLOCKWISE_OUT; break; case ANTICLOCKWISE_OUT: SpiralOutwardDirection = CLOCKWISE_OUT; break; default: printf("bad val %d\n", SpiralOutwardDirection); assert(FALSE); } if ((rand() % 4) == 0) { switch(SpiralRadialDirection) { case FORWARD: SpiralRadialDirection = BACKWARD; break; case BACKWARD: SpiralRadialDirection = FORWARD; break; default: assert(FALSE); } } } spiral = &TheSpirals[0]; CreateSpiral (spiral, 16, SpiralOutwardDirection, ONE, 0); SetSpiralLimits (spiral, 0, 320); // 160 radius before PositionSpiral (spiral, 0, 0); switch(SpiralRadialDirection) { case FORWARD: factor1 = fasterChangeRatio; //cycleRatio; factor2 = factor1 - 1024; if (factor2 <= 0) { phase = 0; } else { phase = 1; } if (factor1 < step) factor1 = step; break; case BACKWARD: factor1 = fasterChangeRatio; //cycleRatio; factor2 = factor1 - 1024; if (factor2 <= 0) { phase = 0; } else { phase = 1; } if (factor1 < step) factor1 = step; break; default: assert(FALSE); } // make semi-trans gline.attribute = 0; //gline.attribute |= GsALON; //gline.attribute |= (1<<28); //gline.attribute |= (1<<29); GetColourDuringCycle (fasterChangeRatio, &colour); gline.r0 = (colour.r * 3) / 2; gline.g0 = (colour.b * 3) / 2; gline.b0 = (colour.g * 3) / 2; gline.r1 = (colour.g * 3) / 2; gline.g1 = (colour.b * 3) / 2; gline.b1 = (colour.r * 3) / 2; switch(phase) { #if 0 case 0: assert(factor1 >= step); assert(factor1 <= ONE); for (i = 0; i < spiral->numberArms; i++) { for (j = 0; j < factor1-step; j += step) { GetPointOnSpiralArm(spiral, i, &gline.x0, &gline.y0, j); GetPointOnSpiralArm(spiral, i, &gline.x1, &gline.y1, j+step); GsSortGLine( &gline, ot, BEHIND_OTHERS_OT_VALUE + i); } } break; case 1: assert(factor1 >= factor2+step); assert(factor1 <= ONE); for (i = 0; i < spiral->numberArms; i++) { for (j = factor2; j < factor1-step; j += step) { GetPointOnSpiralArm(spiral, i, &gline.x0, &gline.y0, j); GetPointOnSpiralArm(spiral, i, &gline.x1, &gline.y1, j+step); GsSortGLine( &gline, ot, BEHIND_OTHERS_OT_VALUE + i); } } break; #endif #if 1 case 0: case 1: assert(factor1 >= step); assert(factor1 <= ONE); for (i = 0; i < spiral->numberArms; i++) { for (j = 0; j < factor1-step; j += step) { GetPointOnSpiralArm(spiral, i, &gline.x0, &gline.y0, j); GetPointOnSpiralArm(spiral, i, &gline.x1, &gline.y1, j+step); GsSortGLine( &gline, ot, BEHIND_OTHERS_OT_VALUE + i); } } break; #endif default: assert(FALSE); } } // number sprites drawn = (ScreenWidth / step) * (ScreenHeight / step) void DrawSpriteWallFadingInAndOut (GsOT *ot, int cycleRatio) { register int x, y; int newSpriteIndex; GsSPRITE sprite, *localSprite; register int i, j; int numX, numY; int phase, subRatio; CVECTOR maxColour = {64, 64, 64}; int step, stepX, stepY; int drawFlag; assert(FirstChosenGlobalSpriteIndex >= 0); assert(FirstChosenGlobalSpriteIndex < NumberLocalSprites); if (cycleRatio == 0) { for (;;) { newSpriteIndex = rand() % NumberLocalSprites; if (newSpriteIndex != FirstChosenGlobalSpriteIndex && (LocalSpriteList[newSpriteIndex]->w == 32 || LocalSpriteList[newSpriteIndex]->w == 64) && (LocalSpriteList[newSpriteIndex]->h == 32 || LocalSpriteList[newSpriteIndex]->h == 64)) break; } FirstChosenGlobalSpriteIndex = newSpriteIndex; } localSprite = LocalSpriteList[FirstChosenGlobalSpriteIndex]; sprite.attribute = localSprite->attribute; sprite.x = localSprite->x; sprite.y = localSprite->y; sprite.w = localSprite->w; sprite.h = localSprite->h; sprite.tpage = localSprite->tpage; sprite.u = localSprite->u; sprite.v = localSprite->v; sprite.cx = localSprite->cx; sprite.cy = localSprite->cy; sprite.r = localSprite->r; sprite.g = localSprite->g; sprite.b = localSprite->b; sprite.mx = localSprite->mx; sprite.my = localSprite->my; sprite.scalex = localSprite->scalex; sprite.scaley = localSprite->scaley; sprite.rotate = localSprite->rotate; #if 0 phase = (cycleRatio * 4) / ONE; switch(phase) { case 0: // fade-in subRatio = cycleRatio * 4; sprite.r = (maxColour.r * subRatio) >> 12; sprite.g = (maxColour.g * subRatio) >> 12; sprite.b = (maxColour.b * subRatio) >> 12; drawFlag = TRUE; break; case 1: // hold sprite.r = maxColour.r; sprite.g = maxColour.g; sprite.b = maxColour.b; drawFlag = TRUE; break; case 2: // fade-out subRatio = (cycleRatio-2048) * 4; sprite.r = (maxColour.r * (ONE-subRatio)) >> 12; sprite.g = (maxColour.g * (ONE-subRatio)) >> 12; sprite.b = (maxColour.b * (ONE-subRatio)) >> 12; drawFlag = TRUE; break; case 3: drawFlag = FALSE; break; default: assert(FALSE); } #endif #if 1 phase = (cycleRatio * 8) / ONE; switch(phase) { case 0: case 1: case 2: // fade-in subRatio = (cycleRatio * 8) / 3; sprite.r = (maxColour.r * subRatio) >> 12; sprite.g = (maxColour.g * subRatio) >> 12; sprite.b = (maxColour.b * subRatio) >> 12; drawFlag = TRUE; break; case 3: // hold sprite.r = maxColour.r; sprite.g = maxColour.g; sprite.b = maxColour.b; drawFlag = TRUE; break; case 4: case 5: case 6: // fade-out subRatio = ((cycleRatio-2048) * 8) / 3; sprite.r = (maxColour.r * (ONE-subRatio)) >> 12; sprite.g = (maxColour.g * (ONE-subRatio)) >> 12; sprite.b = (maxColour.b * (ONE-subRatio)) >> 12; drawFlag = TRUE; break; case 7: drawFlag = FALSE; break; default: assert(FALSE); } #endif step = 64; // 128 if (drawFlag == TRUE) { #if 0 numX = ScreenWidth / step; numY = ScreenHeight / step; ScaleSpriteTo64by64( &sprite); #endif #if 1 stepX = sprite.w; stepY = sprite.h; numX = ScreenWidth / stepX; numY = ScreenHeight / stepY; #endif for (i = 0; i < numX; i++) { x = (-ScreenWidth/2) + (i*stepX); for (j = 0; j < numY; j++) { y = (-ScreenHeight/2) + (j*stepY); sprite.x = x; sprite.y = y; GsSortFastSprite( &sprite, ot, BEHIND_OTHERS_OT_VALUE + (numY * i) + j); } } } } // number sprites drawn = 2 * (ScreenWidth / step) * (ScreenHeight / step) void DrawSpriteWallMergingThroughSprites (GsOT *ot, int cycleRatio) { register int x, y; register int i, j; int numX, numY; int secondX = 0, secondY = 0, thirdX = 0, thirdY = 0; int drawSecondFlag, drawThirdFlag; int step, stepX, stepY; GsSPRITE *secondSprite, *thirdSprite; if (cycleRatio == 0) { SecondChosenGlobalSpriteIndex = ThirdChosenGlobalSpriteIndex; for (;;) { ThirdChosenGlobalSpriteIndex = rand() % NumberLocalSprites; if (ThirdChosenGlobalSpriteIndex != SecondChosenGlobalSpriteIndex && (LocalSpriteList[ThirdChosenGlobalSpriteIndex]->w == 32 || LocalSpriteList[ThirdChosenGlobalSpriteIndex]->w == 64) && (LocalSpriteList[ThirdChosenGlobalSpriteIndex]->h == 32 || LocalSpriteList[ThirdChosenGlobalSpriteIndex]->h == 64)) break; } SpriteMergeDirection = rand() % 4; secondSprite = LocalSpriteList[SecondChosenGlobalSpriteIndex]; thirdSprite = LocalSpriteList[ThirdChosenGlobalSpriteIndex]; secondX = 0; secondY = 0; secondSprite->scalex = ONE; secondSprite->scaley = ONE; secondSprite->r = 64; secondSprite->g = 64; secondSprite->b = 64; drawSecondFlag = TRUE; drawThirdFlag = FALSE; } else { secondSprite = LocalSpriteList[SecondChosenGlobalSpriteIndex]; thirdSprite = LocalSpriteList[ThirdChosenGlobalSpriteIndex]; if (cycleRatio < 2048) { secondX = 0; secondY = 0; secondSprite->scalex = ONE; secondSprite->scaley = ONE; secondSprite->r = 64; secondSprite->g = 64; secondSprite->b = 64; if (SpriteMergeDirection < 0 || SpriteMergeDirection > 3) SpriteMergeDirection = 0; switch(SpriteMergeDirection) { case 0: thirdX = 60 - ((cycleRatio * 60) >> 11); thirdY = 0; break; case 1: thirdX = -60 + ((cycleRatio * 60) >> 11); thirdY = 0; break; case 2: thirdY = 60 - ((cycleRatio * 60) >> 11); thirdX = 0; break; case 3: thirdY = -60 + ((cycleRatio * 60) >> 11); thirdX = 0; break; default: assert(FALSE); } thirdSprite->scalex = ONE; thirdSprite->scaley = ONE; thirdSprite->r = 64; thirdSprite->g = 64; thirdSprite->b = 64; drawSecondFlag = TRUE; drawThirdFlag = TRUE; } else { thirdX = 0; thirdY = 0; thirdSprite->scalex = ONE; thirdSprite->scaley = ONE; thirdSprite->r = 64; thirdSprite->g = 64; thirdSprite->b = 64; drawSecondFlag = FALSE; drawThirdFlag = TRUE; } } step = 64; // 128 #if 0 numX = ScreenWidth / step; numY = ScreenHeight / step; if (drawSecondFlag == TRUE) ScaleSpriteTo64by64(secondSprite); if (drawThirdFlag == TRUE) ScaleSpriteTo64by64(thirdSprite); #endif #if 1 stepX = secondSprite->w; stepY = secondSprite->h; numX = ScreenWidth / stepX; numY = ScreenHeight / stepY; #endif for (i = 0; i < numX; i++) { x = (-ScreenWidth/2) + (i*stepX); for (j = 0; j < numY; j++) { y = (-ScreenHeight/2) + (j*stepY); if (drawSecondFlag == TRUE) { secondSprite->x = x + secondX; secondSprite->y = y + secondY; GsSortFastSprite(secondSprite, ot, BEHIND_OTHERS_OT_VALUE + (numY * i) + j); } if (drawThirdFlag == TRUE) { thirdSprite->x = x + thirdX; thirdSprite->y = y + thirdY; GsSortFastSprite(thirdSprite, ot, BEHIND_OTHERS_OT_VALUE-1 + (numY * i) + j); } } } } // whenever (frameNumber % period == 0), colour is (r128,g0,b0) void GetColourDuringCycle (int cycleRatio, CVECTOR *colour) { int phase, subRatio; assert(cycleRatio >= 0); assert(cycleRatio < ONE); phase = (cycleRatio * 3) / ONE; switch(phase) { case 0: subRatio = cycleRatio * 3; colour->r = 128 - ((subRatio * 128) / ONE); colour->g = (subRatio * 128) / ONE; colour->b = 0; break; case 1: subRatio = ((cycleRatio - (ONE / 3)) * 3); colour->r = 0; colour->g = 128 - ((subRatio * 128) / ONE); colour->b = (subRatio * 128) / ONE; break; case 2: subRatio = ((cycleRatio - ((2 * ONE) / 3)) * 3); colour->r = (subRatio * 128) / ONE; colour->g = 0; colour->b = 128 - ((subRatio * 128) / ONE); break; default: assert(FALSE); } } void GetPointOnScreenCentredRect (int sizeFactor, int angle, short *x, short *y) { int halfWidth, halfHeight; assert(sizeFactor >= 0); assert(sizeFactor <= ONE); assert(angle >= 0); assert(angle < ONE); // assert 4:3 aspect ratio assert(((ScreenWidth * 3) == (ScreenHeight * 4))); halfWidth = ScreenWidth/2; halfHeight = ScreenHeight/2; if (angle < 512) { *x = (ScreenWidth * angle) / 1024; *y = -halfHeight; } else if (angle >= 512 && angle < 1536) { *x = halfWidth; *y = -halfHeight + ((ScreenHeight * (angle-512)) / 1024); } else if (angle >= 1536 && angle < 2560) { *x = halfWidth - ((ScreenWidth * (angle-1536)) / 1024); *y = halfHeight; } else if (angle >= 2560 && angle < 3584) { *x = -halfWidth; *y = halfHeight - ((ScreenHeight * (angle-2560)) / 1024); } else { *x = -halfWidth + ((ScreenWidth * (angle-3584)) / 1024); *y = -halfHeight; } *x = ((*x) * sizeFactor) >> 12; *y = ((*y) * sizeFactor) >> 12; } int MovePointIndexAroundRect (int index, int direction, int numPixelsMoved, int width, int height) { int final, totalNumberPixels; assert(width > 1); assert(height > 1); totalNumberPixels = ((width + height) * 2) - 4; assert(index >= 0); assert(index < totalNumberPixels); assert(numPixelsMoved >= 0); assert(numPixelsMoved < totalNumberPixels); switch(direction) { case CLOCKWISE: final = index + numPixelsMoved; break; case ANTICLOCKWISE: final = index - numPixelsMoved; break; default: assert(FALSE); } if (final < 0) final += totalNumberPixels; if (final >= totalNumberPixels) final -= totalNumberPixels; assert(final >= 0); assert(final < totalNumberPixels); return final; } // bottom left is index 0 void GetXAndYOfIndexOntoScreenCentredRectangle (int index, int width, int height, short *x, short *y) { int totalNumberPixels; assert(width > 1); assert(height > 1); totalNumberPixels = ((width + height) * 2) - 4; assert(index >= 0); assert(index < totalNumberPixels); if (index < (totalNumberPixels/4)) { *x = -width/2; *y = (height/2) - ((height * index) / (totalNumberPixels/4)); } else if (index >= (totalNumberPixels/4) && index < (totalNumberPixels/2)) { *x = -width/2 + ((width * (index-(totalNumberPixels/4))) / (totalNumberPixels/4)); *y = -height/2; } else if (index >= (totalNumberPixels/2) && index < ((3*totalNumberPixels)/4)) { *x = width/2; *y = -height/2 + ((height * (index-(totalNumberPixels/2))) / (totalNumberPixels/4)); } else { *x = width/2 - ((width * (index-((3*totalNumberPixels)/4))) / (totalNumberPixels/4)); *y = height/2; } } void ScaleSpriteTo64by64 (GsSPRITE *sprite) { assert(sprite != NULL); switch(sprite->w) { case 64: sprite->scalex = ONE; break; case 32: sprite->scalex = 8192; break; default: assert(FALSE); } switch(sprite->h) { case 64: sprite->scaley = ONE; break; case 32: sprite->scaley = 8192; break; default: assert(FALSE); } }