mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-25 20:02:33 +01:00
1756 lines
36 KiB
C
1756 lines
36 KiB
C
#include "driver2.h"
|
|
#include "pause.h"
|
|
#include "system.h"
|
|
#include "mission.h"
|
|
#include "overlay.h"
|
|
#include "pres.h"
|
|
#include "pad.h"
|
|
#include "main.h"
|
|
#include "glaunch.h"
|
|
#include "scores.h"
|
|
#include "sound.h"
|
|
#include "cutscene.h"
|
|
#include "overmap.h"
|
|
#include "handling.h"
|
|
#include "platform.h"
|
|
#include "loadsave.h"
|
|
#include "cutrecorder.h"
|
|
|
|
#define REPLAY_NAME_LEN 16
|
|
#define SCORE_NAME_LEN 5
|
|
|
|
#define PAUSE_MENU_LEVELS 3
|
|
|
|
static int gScoreEntered = 0;
|
|
static char EnterNameText[32] = { 0 }; // translated text
|
|
|
|
static int PauseReturnValue;
|
|
|
|
int pauseflag = 0;
|
|
int gShowMap = 0;
|
|
int gDrawPauseMenus = 0;
|
|
int gEnteringScore = 0;
|
|
static int gScorePosition = 0;
|
|
static int allownameentry = 0;
|
|
|
|
int playerwithcontrol[3] = { 0 };
|
|
|
|
// message box
|
|
struct MENU_MESSAGE
|
|
{
|
|
char* header;
|
|
char* text;
|
|
int show;
|
|
} gDisplayedMessage = { NULL, NULL, 0 };
|
|
|
|
typedef void(*pauseFunc)(int dir);
|
|
|
|
struct MENU_ITEM;
|
|
struct MENU_HEADER;
|
|
|
|
struct MENU_ITEM
|
|
{
|
|
char* Text;
|
|
u_char Type;
|
|
u_char Justify;
|
|
pauseFunc func;
|
|
EXIT_VALUE ExitValue;
|
|
MENU_HEADER* SubMenu;
|
|
};
|
|
|
|
struct MENU_HEADER
|
|
{
|
|
char* Title;
|
|
XYWH Bound;
|
|
u_char NumItems;
|
|
MENU_ITEM* MenuItems;
|
|
};
|
|
|
|
static MENU_ITEM* ActiveItem[PAUSE_MENU_LEVELS];
|
|
static MENU_HEADER* VisibleMenus[PAUSE_MENU_LEVELS];
|
|
static MENU_HEADER* ActiveMenu;
|
|
static int ActiveMenuItem;
|
|
static int VisibleMenu;
|
|
|
|
static char SfxVolumeText[8];
|
|
static char MusicVolumeText[8];
|
|
|
|
static char ScoreTime[5][16];
|
|
static char ScoreItems[5][16];
|
|
static char ScoreName[5][7];
|
|
|
|
static char validchars[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+!\xFF\xFE";
|
|
|
|
void PauseMap(int direction);
|
|
void SfxVolume(int direction);
|
|
void MusicVolume(int direction);
|
|
void SaveReplay(int direction);
|
|
void SaveGame(int direction);
|
|
void SkipCutscene(int direction);
|
|
|
|
void EnterScoreName();
|
|
|
|
void CreateScoreNames(SCORE_ENTRY *table, PLAYER_SCORE *score, int position);
|
|
void DrawHighScoreMenu(int selection);
|
|
|
|
char EnterScoreText[32] = { 0 };
|
|
|
|
enum MenuItemType
|
|
{
|
|
//PAUSE_TYPE_ACTIVE = (1 << 0), // suggested - USUSED flag
|
|
PAUSE_TYPE_FUNC = (1 << 1), // simple function calling when pressing Cross
|
|
PAUSE_TYPE_DIRFUNC = (1 << 2), // function calling with direction (left/right)
|
|
PAUSE_TYPE_SFXVOLUME = (1 << 3),
|
|
PAUSE_TYPE_MUSICVOLUME = (1 << 4),
|
|
PAUSE_TYPE_SUBMENU = (1 << 6),
|
|
PAUSE_TYPE_ENDITEMS = (1 << 7),
|
|
};
|
|
|
|
#if defined(_DEBUG) || defined(DEBUG_OPTIONS)
|
|
|
|
void SetRightWayUp(int direction)
|
|
{
|
|
extern char gRightWayUp;
|
|
gRightWayUp = 1;
|
|
PauseReturnValue = MENU_QUIT_CONTINUE;
|
|
}
|
|
|
|
void SetDisplayPosition(int direction)
|
|
{
|
|
extern int gDisplayPosition;
|
|
gDisplayPosition ^= 1;
|
|
}
|
|
|
|
void ToggleInvincibility(int direction)
|
|
{
|
|
extern int gInvincibleCar;
|
|
gInvincibleCar ^= 1;
|
|
}
|
|
|
|
void ToggleImmunity(int direction)
|
|
{
|
|
extern int gPlayerImmune;
|
|
gPlayerImmune ^= 1;
|
|
}
|
|
|
|
void TogglePlayerGhost(int direction)
|
|
{
|
|
extern int playerghost;
|
|
playerghost ^= 1;
|
|
}
|
|
|
|
void ToggleOverlays(int direction)
|
|
{
|
|
gDoOverlays ^= 1;
|
|
}
|
|
|
|
int lastCar = -1;
|
|
|
|
void ToggleSecretCarFun(int direction)
|
|
{
|
|
extern CAR_COSMETICS car_cosmetics[5];
|
|
extern int wantedCar[2];
|
|
|
|
int active = (ActiveCheats.cheat10 ^= 1);
|
|
|
|
if (active)
|
|
{
|
|
if (lastCar == -1)
|
|
lastCar = wantedCar[0];
|
|
|
|
// make our current car the secret car
|
|
wantedCar[0] = 12;
|
|
}
|
|
else
|
|
{
|
|
if (lastCar != -1)
|
|
{
|
|
// restore our initial car
|
|
wantedCar[0] = lastCar;
|
|
lastCar = -1;
|
|
}
|
|
}
|
|
|
|
FixCarCos(&car_cosmetics[4], 12);
|
|
}
|
|
|
|
void ToggleJerichoMode(int direction)
|
|
{
|
|
ActiveCheats.cheat12 ^= 1;
|
|
}
|
|
|
|
void TogglePuppyDogCops(int direction)
|
|
{
|
|
gPuppyDogCop ^= 1;
|
|
}
|
|
|
|
extern void LoadSky(void);
|
|
|
|
void DebugTimeOfDayDay(int direction)
|
|
{
|
|
wantedTimeOfDay = 1;
|
|
gTimeOfDay = 1;
|
|
gWantNight = 0;
|
|
LoadSky();
|
|
}
|
|
|
|
void DebugTimeOfDayNight(int direction)
|
|
{
|
|
wantedTimeOfDay = 3;
|
|
gTimeOfDay = 3;
|
|
gWantNight = 1;
|
|
LoadSky();
|
|
}
|
|
|
|
void DebugTimeOfDayDusk(int direction)
|
|
{
|
|
wantedTimeOfDay = 0;
|
|
gTimeOfDay = 0;
|
|
gWantNight = 0;
|
|
LoadSky();
|
|
}
|
|
|
|
void DebugTimeOfDayDawn(int direction)
|
|
{
|
|
wantedTimeOfDay = 2;
|
|
gTimeOfDay = 2;
|
|
gWantNight = 0;
|
|
LoadSky();
|
|
}
|
|
|
|
void DebugTimeOfDayRain(int direction)
|
|
{
|
|
//extern int weather;
|
|
//weather ^= weather;
|
|
gWeather ^= 1;
|
|
wantedWeather = gWeather;
|
|
|
|
if (gWeather == 1)
|
|
wetness = 7000;
|
|
else
|
|
wetness = 0;
|
|
|
|
LoadSky();
|
|
}
|
|
|
|
MENU_ITEM DebugTimeOfDayItems[] =
|
|
{
|
|
{ "Day", PAUSE_TYPE_FUNC, 2, DebugTimeOfDayDay, MENU_QUIT_NONE, NULL },
|
|
{ "Night", PAUSE_TYPE_FUNC, 2, DebugTimeOfDayNight,MENU_QUIT_NONE, NULL },
|
|
{ "Dusk", PAUSE_TYPE_FUNC, 2, DebugTimeOfDayDusk, MENU_QUIT_NONE, NULL },
|
|
{ "Dawn", PAUSE_TYPE_FUNC, 2, DebugTimeOfDayDawn, MENU_QUIT_NONE, NULL },
|
|
{ "Rain", PAUSE_TYPE_FUNC, 2, DebugTimeOfDayRain, MENU_QUIT_NONE, NULL },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_HEADER DebugTimeOfDayHeader =
|
|
{ "Time Of Day", { 0, 0, 0, 0 }, 0u, DebugTimeOfDayItems };
|
|
|
|
MENU_ITEM DebugJustForFunItems[] =
|
|
{
|
|
{ "Secret Car Fun", PAUSE_TYPE_FUNC, 2, ToggleSecretCarFun, MENU_QUIT_RESTART, NULL },
|
|
{ "Jericho Mode", PAUSE_TYPE_FUNC, 2, ToggleJerichoMode, MENU_QUIT_NONE, NULL },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_HEADER DebugJustForFunHeader =
|
|
{ "Just for fun", { 0, 0, 0, 0 }, 0u, DebugJustForFunItems };
|
|
|
|
MENU_ITEM DebugOptionsItems[] =
|
|
{
|
|
#ifdef CUTSCENE_RECORDER
|
|
//{ gCutsceneRecorderPauseText, 5u, 2u, (pauseFunc)&NextCutsceneRecorderPlayer, MENU_QUIT_NONE, NULL },
|
|
{ gCurrentChasePauseText, 5u, 2u, (pauseFunc)&CutRec_NextChase, MENU_QUIT_NONE, NULL },
|
|
#endif
|
|
{ "Display position", PAUSE_TYPE_FUNC, 2, SetDisplayPosition, MENU_QUIT_NONE, NULL},
|
|
{ "Back on Wheels", PAUSE_TYPE_FUNC, 2, SetRightWayUp, MENU_QUIT_NONE, NULL},
|
|
{ "Time of Day", PAUSE_TYPE_SUBMENU, 2, NULL, MENU_QUIT_NONE, &DebugTimeOfDayHeader },
|
|
{ "Fun Cheats", PAUSE_TYPE_SUBMENU, 2, NULL, MENU_QUIT_NONE, &DebugJustForFunHeader },
|
|
{ "Invincibility", PAUSE_TYPE_FUNC, 2, ToggleInvincibility,MENU_QUIT_NONE, NULL},
|
|
{ "Immunity", PAUSE_TYPE_FUNC, 2, ToggleImmunity, MENU_QUIT_NONE, NULL},
|
|
{ "Puppy Dog Cops", PAUSE_TYPE_FUNC, 2, TogglePuppyDogCops, MENU_QUIT_NONE, NULL },
|
|
{ "Toggle Overlay", PAUSE_TYPE_FUNC, 2, ToggleOverlays, MENU_QUIT_NONE, NULL },
|
|
{ "Player Ghost", PAUSE_TYPE_FUNC, 2, TogglePlayerGhost, MENU_QUIT_NONE, NULL },
|
|
{ "Next Mission", 0, 2, NULL, MENU_QUIT_NEXTMISSION, NULL },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_HEADER DebugOptionsHeader =
|
|
{ "Debug Options", { 0, 0, 0, 0 }, 0u, DebugOptionsItems };
|
|
#endif
|
|
|
|
MENU_ITEM YesNoRestartItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_NO), 1u, 2u, NULL, MENU_QUIT_BACKMENU, NULL },
|
|
{ G_LTXT_ID(GTXT_YES), 1u, 2u, NULL, MENU_QUIT_RESTART, NULL },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM YesNoQuitItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_NO), 1u, 2u, NULL, MENU_QUIT_BACKMENU, NULL },
|
|
{ G_LTXT_ID(GTXT_YES), 1u, 2u, NULL, MENU_QUIT_QUIT, NULL },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_HEADER YesNoRestartHeader =
|
|
{ G_LTXT_ID(GTXT_AreYouSure), { 0, 0, 0, 0 }, 0u, YesNoRestartItems };
|
|
|
|
MENU_HEADER YesNoQuitHeader =
|
|
{ G_LTXT_ID(GTXT_AreYouSure), { 0, 0, 0, 0 }, 0u, YesNoQuitItems };
|
|
|
|
MENU_ITEM MainPauseItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_Continue), 1u, 2u, NULL, MENU_QUIT_CONTINUE, NULL },
|
|
{ G_LTXT_ID(GTXT_ShowMap), PAUSE_TYPE_FUNC, 2u, (pauseFunc)&PauseMap, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_Restart), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
|
|
{ G_LTXT_ID(GTXT_SfxVolume), PAUSE_TYPE_SFXVOLUME | PAUSE_TYPE_DIRFUNC, 2u, (pauseFunc)&SfxVolume, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_MusicVolume), PAUSE_TYPE_MUSICVOLUME | PAUSE_TYPE_DIRFUNC, 2u, (pauseFunc)&MusicVolume, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_FilmDirector), 1u, 2u, NULL, MENU_QUIT_DIRECTOR, NULL},
|
|
{ G_LTXT_ID(GTXT_QuickReplay),1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
|
|
#if defined(_DEBUG) || defined(DEBUG_OPTIONS)
|
|
{ "Debug Options", PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &DebugOptionsHeader },
|
|
#endif
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM MultiplayerPauseItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_Continue), 1u, 2u, NULL, MENU_QUIT_CONTINUE, NULL },
|
|
{ G_LTXT_ID(GTXT_Restart), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
|
|
{ G_LTXT_ID(GTXT_SfxVolume), PAUSE_TYPE_SFXVOLUME | PAUSE_TYPE_DIRFUNC, 2u, (pauseFunc)&SfxVolume, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_MusicVolume), PAUSE_TYPE_MUSICVOLUME | PAUSE_TYPE_DIRFUNC, 2u, (pauseFunc)&MusicVolume, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_QuickReplay),1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM CutscenePauseItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_Continue), 1u, 2u, NULL, MENU_QUIT_CONTINUE, NULL },
|
|
{ G_LTXT_ID(GTXT_SkipCutscene), PAUSE_TYPE_FUNC, 2u, (pauseFunc)&SkipCutscene, MENU_QUIT_CONTINUE, NULL },
|
|
{ G_LTXT_ID(GTXT_Restart), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
|
|
{ G_LTXT_ID(GTXT_SfxVolume), PAUSE_TYPE_SFXVOLUME | PAUSE_TYPE_DIRFUNC, 2u, (pauseFunc)&SfxVolume, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_MusicVolume), PAUSE_TYPE_MUSICVOLUME | PAUSE_TYPE_DIRFUNC, 2u, (pauseFunc)&MusicVolume, MENU_QUIT_NONE, NULL },
|
|
#if defined(_DEBUG) || defined(DEBUG_OPTIONS)
|
|
{ "Debug Options", PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &DebugOptionsHeader },
|
|
#endif
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM MissionCompleteItems[] =
|
|
{
|
|
#ifdef PSX
|
|
{ G_LTXT_ID(GTXT_SaveGame), 3u, 2u, (pauseFunc)&SaveGame, MENU_QUIT_NONE, NULL },
|
|
#endif
|
|
{ G_LTXT_ID(GTXT_Continue), 1u, 2u, NULL, MENU_QUIT_NEXTMISSION, NULL },
|
|
{ G_LTXT_ID(GTXT_FilmDirector),1u,2u,NULL,MENU_QUIT_DIRECTOR,NULL},
|
|
{ G_LTXT_ID(GTXT_QuickReplay),1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
|
|
{ G_LTXT_ID(GTXT_SaveReplay), PAUSE_TYPE_FUNC, 2u, (pauseFunc)&SaveReplay, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_Restart), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM MissionFailedItems[6] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_FilmDirector),1u,2u,NULL,MENU_QUIT_DIRECTOR,NULL},
|
|
{ G_LTXT_ID(GTXT_QuickReplay),1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
|
|
{ G_LTXT_ID(GTXT_Exit), 3u, 2u, (pauseFunc)&SaveReplay, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_RetryMission),PAUSE_TYPE_SUBMENU,2u,NULL,MENU_QUIT_NONE,&YesNoRestartHeader },
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM TakeARideFinishedItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_Restart), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
|
|
{ G_LTXT_ID(GTXT_FilmDirector),1u,2u,NULL,MENU_QUIT_DIRECTOR,NULL},
|
|
{ G_LTXT_ID(GTXT_QuickReplay),1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
|
|
{ G_LTXT_ID(GTXT_SaveReplay), PAUSE_TYPE_FUNC, 2u, (pauseFunc)&SaveReplay, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM DrivingGameFinishedItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_PlayAgain), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
|
|
{ EnterScoreText, 3u, 2u, (pauseFunc)&EnterScoreName, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_FilmDirector),1u,2u,NULL,MENU_QUIT_DIRECTOR,NULL},
|
|
{ G_LTXT_ID(GTXT_QuickReplay),1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
|
|
{ G_LTXT_ID(GTXT_SaveReplay), PAUSE_TYPE_FUNC, 2u, (pauseFunc)&SaveReplay, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM MultiplayerFinishedItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_PlayAgain), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
|
|
{ G_LTXT_ID(GTXT_QuickReplay),1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
|
|
{ G_LTXT_ID(GTXT_SaveReplay), PAUSE_TYPE_FUNC, 2u, (pauseFunc)&SaveReplay, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM ChaseGameFinishedItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_PlayAgain), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
|
|
{ G_LTXT_ID(GTXT_FilmDirector),1u,2u,NULL,MENU_QUIT_DIRECTOR,NULL},
|
|
{ G_LTXT_ID(GTXT_QuickReplay),1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
|
|
{ G_LTXT_ID(GTXT_SaveReplay), PAUSE_TYPE_FUNC, 2u, (pauseFunc)&SaveReplay, MENU_QUIT_NONE, NULL },
|
|
{ G_LTXT_ID(GTXT_Exit), PAUSE_TYPE_SUBMENU, 2u, NULL, MENU_QUIT_NONE, &YesNoQuitHeader },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM NoPadItems[] =
|
|
{
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL}
|
|
};
|
|
|
|
MENU_ITEM NoMultiPadItems[] =
|
|
{
|
|
{ "Exit", 1u, 2u, NULL, MENU_QUIT_QUIT, NULL },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
MENU_ITEM InvalidPadItems[] =
|
|
{
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL}
|
|
};
|
|
|
|
MENU_ITEM InvalidMultiPadItems[] =
|
|
{
|
|
{ G_LTXT_ID(GTXT_Exit), 1u, 2u, NULL, MENU_QUIT_QUIT, NULL },
|
|
{ NULL, PAUSE_TYPE_ENDITEMS, 0u, NULL, MENU_QUIT_NONE, NULL }
|
|
};
|
|
|
|
|
|
MENU_HEADER PauseMenuHeader =
|
|
{ G_LTXT_ID(GTXT_Paused), { 0, 0, 0, 0 }, 0u, MainPauseItems };
|
|
|
|
MENU_HEADER MultiplayerPauseHeader =
|
|
{ G_LTXT_ID(GTXT_Paused), { 0, 0, 0, 0 }, 0u, MultiplayerPauseItems };
|
|
|
|
MENU_HEADER CutscenePauseMenuHeader =
|
|
{ G_LTXT_ID(GTXT_Paused), { 0, 0, 0, 0 }, 0u, CutscenePauseItems };
|
|
|
|
MENU_HEADER MissionCompleteHeader =
|
|
{ G_LTXT_ID(GTXT_MissionSuccessful), { 0, 0, 0, 0 }, 0u, MissionCompleteItems };
|
|
|
|
MENU_HEADER MissionFailedHeader =
|
|
{ G_LTXT_ID(GTXT_MissionFailed), { 0, 0, 0, 0 }, 0u, MissionFailedItems };
|
|
|
|
MENU_HEADER TakeARideFinishedHeader =
|
|
{ G_LTXT_ID(GTXT_GameOver), { 0, 0, 0, 0 }, 0u, TakeARideFinishedItems };
|
|
|
|
MENU_HEADER DrivingGameFinishedHeader =
|
|
{ G_LTXT_ID(GTXT_GameOver), { 0, 0, 0, 0 }, 0u, DrivingGameFinishedItems };
|
|
|
|
MENU_HEADER MultiplayerFinishedHeader =
|
|
{ G_LTXT_ID(GTXT_GameOver), { 0, 0, 0, 0 }, 0u, MultiplayerFinishedItems };
|
|
|
|
MENU_HEADER ChaseGameFinishedHeader =
|
|
{ G_LTXT_ID(GTXT_GameOver), { 0, 0, 0, 0 }, 0u, ChaseGameFinishedItems };
|
|
|
|
MENU_HEADER NoPadHeader =
|
|
{
|
|
G_LTXT_ID(GTXT_InsertController1),
|
|
{ 0, 0, 0, 0 },
|
|
0u,
|
|
NoPadItems
|
|
};
|
|
|
|
MENU_HEADER NoMultiPadHeader =
|
|
{
|
|
G_LTXT_ID(GTXT_InsertController2),
|
|
{ 0, 0, 0, 0 },
|
|
0u,
|
|
NoMultiPadItems
|
|
};
|
|
|
|
MENU_HEADER InvalidPadHeader =
|
|
{
|
|
G_LTXT_ID(GTXT_IncorrectController1),
|
|
{ 0, 0, 0, 0 },
|
|
0u,
|
|
InvalidPadItems
|
|
};
|
|
|
|
MENU_HEADER InvalidMultiPadHeader =
|
|
{
|
|
G_LTXT_ID(GTXT_IncorrectController2),
|
|
{ 0, 0, 0, 0 },
|
|
0u,
|
|
InvalidMultiPadItems
|
|
};
|
|
|
|
|
|
u_char gCurrentTextChar = 0;
|
|
typedef void(*OnEntryComplete)(void* data, char* text);
|
|
|
|
void ScoreNameInputHandler(const char* input)
|
|
{
|
|
if (!input)
|
|
{
|
|
gCurrentTextChar = 255;
|
|
return;
|
|
}
|
|
|
|
gCurrentTextChar = *input;
|
|
}
|
|
|
|
#define USE_PAD_INPUT defined(PSX)
|
|
|
|
// [A] Enter the replay name to save
|
|
char* WaitForTextEntry(char* textBufPtr, int maxLength)
|
|
{
|
|
u_char chr;
|
|
int so, co;
|
|
int delay, toggle;
|
|
char* username;
|
|
unsigned short npad, dpad;
|
|
|
|
username = textBufPtr ? textBufPtr : (char*)_overlay_buffer;
|
|
delay = 0;
|
|
toggle = 0;
|
|
co = 1;
|
|
so = strlen(username);
|
|
|
|
#if !USE_PAD_INPUT
|
|
// PsyX input handler
|
|
g_cfg_gameOnTextInput = ScoreNameInputHandler;
|
|
gCurrentTextChar = 0;
|
|
#endif
|
|
|
|
do {
|
|
|
|
if (!FilterFrameTime())
|
|
continue;
|
|
|
|
ReadControllers();
|
|
|
|
npad = Pads[0].dirnew;
|
|
dpad = Pads[0].direct;
|
|
|
|
// cancel
|
|
if (npad & 0x10)
|
|
return NULL;
|
|
|
|
#if USE_PAD_INPUT
|
|
if (dpad & 0x20)
|
|
{
|
|
// switch to end
|
|
delay = 1;
|
|
toggle = 0;
|
|
co = 67;
|
|
}
|
|
else if (dpad & 0x8000)
|
|
{
|
|
// move left/right to switch chars
|
|
if (delay-- == 0)
|
|
{
|
|
delay = 20;
|
|
toggle = 0;
|
|
co--;
|
|
}
|
|
else if (delay < 1)
|
|
{
|
|
delay = 2;
|
|
toggle = 0;
|
|
co--;
|
|
}
|
|
|
|
if (co < 0)
|
|
co = 67;
|
|
}
|
|
else if (dpad & 0x2000)
|
|
{
|
|
if (delay-- == 0)
|
|
{
|
|
delay = 20;
|
|
toggle = 0;
|
|
co++;
|
|
}
|
|
else if (delay < 1)
|
|
{
|
|
delay = 2;
|
|
toggle = 0;
|
|
co++;
|
|
}
|
|
|
|
if (co > 67)
|
|
co = 0;
|
|
}
|
|
else
|
|
{
|
|
delay = 0;
|
|
}
|
|
|
|
if (so == maxLength)
|
|
chr = 254;
|
|
else
|
|
chr = validchars[co];
|
|
#else
|
|
if (gCurrentTextChar > 0)
|
|
{
|
|
if (gCurrentTextChar == 255)
|
|
{
|
|
// do backspace
|
|
chr = 255;
|
|
}
|
|
else
|
|
{
|
|
// Find a valid character
|
|
for (co = 0; co < 69; co++)
|
|
{
|
|
if (validchars[co] == gCurrentTextChar)
|
|
break;
|
|
}
|
|
|
|
if (so == maxLength)
|
|
{
|
|
chr = 254;
|
|
gCurrentTextChar = 0;
|
|
}
|
|
else
|
|
chr = validchars[co];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (so == maxLength)
|
|
chr = 254;
|
|
else
|
|
chr = 'I';
|
|
}
|
|
|
|
if (npad & 0x40)
|
|
{
|
|
gCurrentTextChar = 254;
|
|
chr = 254;
|
|
}
|
|
#endif
|
|
toggle++;
|
|
|
|
if (toggle & 4)
|
|
username[so] = ' ';
|
|
else if (chr == ' ')
|
|
username[so] = '.';
|
|
else
|
|
username[so] = chr;
|
|
|
|
#if USE_PAD_INPUT
|
|
if (npad & 0x80)
|
|
{
|
|
if (so > 0)
|
|
so--;
|
|
|
|
username[so] = 0;
|
|
username[so + 1] = 0;
|
|
}
|
|
|
|
if (npad & 0x40)
|
|
{
|
|
#else
|
|
if (gCurrentTextChar > 0)
|
|
{
|
|
gCurrentTextChar = 0;
|
|
#endif
|
|
// complete
|
|
if (chr == 254)
|
|
{
|
|
username[so] = 0;
|
|
break;
|
|
}
|
|
|
|
// delete chars
|
|
if (chr == 255)
|
|
{
|
|
if (so > 0)
|
|
so--;
|
|
|
|
username[so] = 0;
|
|
username[so + 1] = 0;
|
|
}
|
|
else if (so < maxLength)
|
|
{
|
|
username[so] = chr;
|
|
username[so + 1] = 0;
|
|
so++;
|
|
}
|
|
}
|
|
|
|
DrawGame();
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
emscripten_sleep(0);
|
|
#endif
|
|
} while (true);
|
|
|
|
#if !USE_PAD_INPUT
|
|
g_cfg_gameOnTextInput = NULL;
|
|
#endif
|
|
|
|
return username;
|
|
}
|
|
|
|
void SkipCutscene(int direction)
|
|
{
|
|
gSkipInGameCutscene = 1;
|
|
}
|
|
|
|
// [D] [T]
|
|
void SaveReplay(int direction)
|
|
{
|
|
char* result;
|
|
char filename[64];
|
|
|
|
#ifdef PSX
|
|
UNIMPLEMENTED();
|
|
// CallMemoryCard(0x10, 1);
|
|
#else
|
|
|
|
#ifdef CUTSCENE_RECORDER
|
|
if(_CutRec_IsOn())
|
|
{
|
|
if (CutRec_SaveChase())
|
|
{
|
|
gDisplayedMessage.header = G_LTXT(GTXT_SaveReplay);
|
|
gDisplayedMessage.text = G_LTXT(GTXT_OK);
|
|
gDisplayedMessage.show = 25;
|
|
}
|
|
else
|
|
{
|
|
gDisplayedMessage.header = G_LTXT(GTXT_SaveReplay);
|
|
gDisplayedMessage.text = G_LTXT(GTXT_SavingError);
|
|
gDisplayedMessage.show = 15;
|
|
}
|
|
}
|
|
else
|
|
#endif // CUTSCENE_RECORDER
|
|
{
|
|
int cnt;
|
|
FILE* temp;
|
|
_mkdir("Replays");
|
|
|
|
ClearMem(EnterNameText, REPLAY_NAME_LEN);
|
|
|
|
// detect the best file name
|
|
// TODO: if replay is loaded - set the loaded replay filename
|
|
if (gLoadedReplay)
|
|
{
|
|
strcpy(EnterNameText, gCurrentReplayFilename);
|
|
}
|
|
else
|
|
{
|
|
cnt = 1;
|
|
while (cnt < 1000)
|
|
{
|
|
sprintf(EnterNameText, "Chase%d", cnt);
|
|
sprintf(filename, "Replays/%s.D2RP", EnterNameText);
|
|
|
|
if ((temp = fopen(filename, "r")) != NULL)
|
|
{
|
|
fclose(temp);
|
|
cnt++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
gDisplayedMessage.header = G_LTXT(GTXT_EnterName);
|
|
gDisplayedMessage.text = EnterNameText;
|
|
gDisplayedMessage.show = -1;
|
|
|
|
// wait for user input the replay name
|
|
result = WaitForTextEntry(EnterNameText, REPLAY_NAME_LEN);
|
|
|
|
gDisplayedMessage.show = 0;
|
|
|
|
if (result)
|
|
{
|
|
sprintf(filename, "Replays/%s.D2RP", result);
|
|
|
|
if (SaveReplayToFile(filename))
|
|
{
|
|
gDisplayedMessage.header = G_LTXT(GTXT_SaveReplay);
|
|
gDisplayedMessage.text = G_LTXT(GTXT_OK);
|
|
gDisplayedMessage.show = 15;
|
|
}
|
|
else
|
|
{
|
|
gDisplayedMessage.header = G_LTXT(GTXT_SaveReplay);
|
|
gDisplayedMessage.text = G_LTXT(GTXT_SavingError);
|
|
gDisplayedMessage.show = 15;
|
|
}
|
|
}
|
|
}
|
|
#endif // PSX
|
|
}
|
|
|
|
// [D] [T]
|
|
void SaveGame(int direction)
|
|
{
|
|
#ifndef PSX
|
|
SaveCurrentGame();
|
|
#endif
|
|
}
|
|
|
|
// [D] [T]
|
|
int MaxMenuStringLength(MENU_HEADER *pMenu)
|
|
{
|
|
int max;
|
|
int temp;
|
|
MENU_ITEM *pItems;
|
|
|
|
pItems = pMenu->MenuItems;
|
|
max = StringWidth(GET_GAME_TXT(pMenu->Title));
|
|
|
|
while ((pItems->Type & PAUSE_TYPE_ENDITEMS) == 0)
|
|
{
|
|
temp = StringWidth(GET_GAME_TXT(pItems->Text));
|
|
|
|
if (pItems->Type & (PAUSE_TYPE_SFXVOLUME | PAUSE_TYPE_MUSICVOLUME))
|
|
temp = temp + StringWidth(" 100");
|
|
|
|
if (temp > max)
|
|
max = temp;
|
|
|
|
pItems++;
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void SetupMenu(MENU_HEADER *menu, int back)
|
|
{
|
|
int len;
|
|
MENU_ITEM *pItem;
|
|
int numItems;
|
|
|
|
numItems = 0;
|
|
|
|
ActiveMenuItem = 0;
|
|
|
|
pItem = menu->MenuItems;
|
|
while (pItem->Type != PAUSE_TYPE_ENDITEMS)
|
|
{
|
|
if (back && pItem == ActiveItem[VisibleMenu])
|
|
ActiveMenuItem = numItems;
|
|
|
|
numItems++;
|
|
pItem++;
|
|
}
|
|
|
|
ActiveMenu = menu;
|
|
ActiveMenu->NumItems = numItems;
|
|
|
|
len = MaxMenuStringLength(ActiveMenu);
|
|
|
|
ActiveMenu->Bound.x = ((304 - len) / 2) - 4;
|
|
ActiveMenu->Bound.w = len + 24;
|
|
ActiveMenu->Bound.y = MAX(48, (SCREEN_H - (numItems + 1) * 15) / 2);
|
|
ActiveMenu->Bound.h = (numItems + 1) * 15 + 10;
|
|
|
|
ActiveItem[VisibleMenu] = &ActiveMenu->MenuItems[ActiveMenuItem];
|
|
}
|
|
|
|
// [D] [T]
|
|
void InitaliseMenu(PAUSEMODE mode)
|
|
{
|
|
MENU_HEADER* pNewMenu;
|
|
int i;
|
|
|
|
for (i = 0; i < PAUSE_MENU_LEVELS; i++)
|
|
{
|
|
ActiveItem[i] = NULL;
|
|
VisibleMenus[i] = NULL;
|
|
}
|
|
|
|
pNewMenu = NULL;
|
|
|
|
allownameentry = 0;
|
|
|
|
switch (mode)
|
|
{
|
|
case PAUSEMODE_PAUSE:
|
|
case PAUSEMODE_PAUSEP1:
|
|
case PAUSEMODE_PAUSEP2:
|
|
if (NumPlayers == 1 && gMultiplayerLevels == 0)
|
|
{
|
|
if (gInGameCutsceneActive == 0)
|
|
pNewMenu = &PauseMenuHeader;
|
|
else
|
|
pNewMenu = &CutscenePauseMenuHeader;
|
|
}
|
|
else
|
|
pNewMenu = &MultiplayerPauseHeader;
|
|
|
|
break;
|
|
case PAUSEMODE_GAMEOVER:
|
|
switch (GameType)
|
|
{
|
|
case GAME_PURSUIT:
|
|
pNewMenu = &ChaseGameFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
break;
|
|
case GAME_GETAWAY:
|
|
case GAME_CHECKPOINT:
|
|
if (NumPlayers == 1)
|
|
{
|
|
pNewMenu = &DrivingGameFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
}
|
|
else
|
|
{
|
|
pNewMenu = &MultiplayerFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
}
|
|
break;
|
|
case GAME_GATERACE:
|
|
case GAME_TRAILBLAZER:
|
|
case GAME_SURVIVAL:
|
|
if (NumPlayers == 1)
|
|
{
|
|
pNewMenu = &DrivingGameFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
allownameentry = 1;
|
|
}
|
|
else
|
|
{
|
|
pNewMenu = &MultiplayerFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
}
|
|
break;
|
|
default:
|
|
if (NumPlayers == 1)
|
|
{
|
|
pNewMenu = &TakeARideFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
}
|
|
else
|
|
{
|
|
pNewMenu = &MultiplayerFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case PAUSEMODE_COMPLETE:
|
|
|
|
switch (GameType)
|
|
{
|
|
case GAME_MISSION:
|
|
pNewMenu = &MissionCompleteHeader;
|
|
gMissionCompletionState = mode;
|
|
break;
|
|
case GAME_GETAWAY:
|
|
case GAME_GATERACE:
|
|
case GAME_CHECKPOINT:
|
|
case GAME_TRAILBLAZER:
|
|
case GAME_SURVIVAL:
|
|
case GAME_COPSANDROBBERS:
|
|
case GAME_CAPTURETHEFLAG:
|
|
if (NumPlayers == 1)
|
|
{
|
|
pNewMenu = &DrivingGameFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
allownameentry = 1;
|
|
}
|
|
else
|
|
{
|
|
pNewMenu = &MultiplayerFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
}
|
|
break;
|
|
case GAME_PURSUIT:
|
|
pNewMenu = &ChaseGameFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
break;
|
|
default:
|
|
if (NumPlayers == 1)
|
|
{
|
|
pNewMenu = &TakeARideFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
}
|
|
else
|
|
{
|
|
pNewMenu = &MultiplayerFinishedHeader;
|
|
gMissionCompletionState = mode;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case PAUSEMODE_PADERROR:
|
|
if (pad_connected < 0)
|
|
{
|
|
if (NumPlayers == 1)
|
|
pNewMenu = &InvalidPadHeader;
|
|
else
|
|
pNewMenu = &InvalidMultiPadHeader;
|
|
|
|
if (Pads[0].type == 1)
|
|
pNewMenu->Title = G_LTXT(GTXT_IncorrectController1);
|
|
else
|
|
pNewMenu->Title = G_LTXT(GTXT_IncorrectController2);
|
|
}
|
|
else
|
|
{
|
|
if (NumPlayers == 1)
|
|
pNewMenu = &NoPadHeader;
|
|
else
|
|
pNewMenu = &NoMultiPadHeader;
|
|
|
|
if (Pads[0].type == 0)
|
|
pNewMenu->Title = G_LTXT(GTXT_InsertController1);
|
|
else
|
|
pNewMenu->Title = G_LTXT(GTXT_InsertController2);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// [A]
|
|
if(pNewMenu)
|
|
{
|
|
VisibleMenu = 0;
|
|
VisibleMenus[VisibleMenu] = pNewMenu;
|
|
|
|
if (NoPlayerControl == 0 && OnScoreTable(NULL) != -1 && allownameentry)
|
|
{
|
|
gScoreEntered = 0;
|
|
|
|
sprintf(EnterScoreText, G_LTXT(GTXT_EnterScore));
|
|
sprintf(EnterNameText, G_LTXT(GTXT_EnterName));
|
|
}
|
|
else
|
|
{
|
|
gScoreEntered = 1;
|
|
|
|
sprintf(EnterScoreText, G_LTXT(GTXT_ViewTable));
|
|
sprintf(EnterNameText, G_LTXT(GTXT_HighScores));
|
|
}
|
|
|
|
SetupMenu(pNewMenu, 0);
|
|
}
|
|
else
|
|
{
|
|
printError("pNewMenu is NULL!\n");
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawVisibleMenus(void)
|
|
{
|
|
int width;
|
|
int itemXpos;
|
|
POLY_FT3 *null;
|
|
POLY_F4 *poly;
|
|
MENU_ITEM *pItem;
|
|
MENU_HEADER *pActive;
|
|
int r, b;
|
|
int i;
|
|
int xpos, ypos;
|
|
int menuWidth;
|
|
|
|
int x1, x2, y1, y2;
|
|
static int maxPercentageWidth = StringWidth(" 100");
|
|
|
|
if (NumPlayers > 1)
|
|
{
|
|
SetFullscreenDrawing();
|
|
}
|
|
|
|
pActive = VisibleMenus[VisibleMenu];
|
|
|
|
xpos = pActive->Bound.x;
|
|
ypos = pActive->Bound.y;
|
|
menuWidth = pActive->Bound.w;
|
|
|
|
if (pActive->Title)
|
|
{
|
|
OutputString(GET_GAME_TXT(pActive->Title), 2, xpos, ypos, menuWidth, 128, 32, 32);
|
|
|
|
ypos += 15;
|
|
}
|
|
|
|
// show all menu items
|
|
for (i = 0; i < pActive->NumItems; i++)
|
|
{
|
|
pItem = &pActive->MenuItems[i];
|
|
|
|
if (!pItem->Text)
|
|
continue;
|
|
|
|
if (pItem == ActiveItem[VisibleMenu])
|
|
{
|
|
r = 0;
|
|
b = 0;
|
|
}
|
|
else
|
|
{
|
|
b = 128;
|
|
r = 128;
|
|
}
|
|
|
|
if(pItem->Type & (PAUSE_TYPE_SFXVOLUME | PAUSE_TYPE_MUSICVOLUME))
|
|
{
|
|
width = StringWidth(GET_GAME_TXT(pItem->Text));
|
|
|
|
itemXpos = xpos + ((menuWidth - width) - maxPercentageWidth) / 2;
|
|
|
|
OutputString(GET_GAME_TXT(pItem->Text), 1, itemXpos, ypos, menuWidth, r, 128, b);
|
|
|
|
if (pItem->Type & PAUSE_TYPE_SFXVOLUME)
|
|
OutputString(SfxVolumeText, 1, itemXpos + width + 10, ypos, menuWidth, r, 128, b);
|
|
else if (pItem->Type & PAUSE_TYPE_MUSICVOLUME)
|
|
OutputString(MusicVolumeText, 1, itemXpos + width + 10, ypos, menuWidth, r, 128, b);
|
|
}
|
|
else
|
|
{
|
|
OutputString(GET_GAME_TXT(pItem->Text), pItem->Justify, xpos, ypos, menuWidth, r, 128, b);
|
|
}
|
|
|
|
ypos += 15;
|
|
}
|
|
|
|
poly = (POLY_F4*)current->primptr;
|
|
|
|
ypos = pActive->Bound.y;
|
|
|
|
setPolyF4(poly);
|
|
x1 = xpos - 5;
|
|
x2 = xpos + menuWidth + 5;
|
|
|
|
y1 = ypos - 5;
|
|
y2 = ypos + pActive->Bound.h;
|
|
|
|
poly->x0 = x1;
|
|
poly->x1 = x2;
|
|
poly->y0 = y1;
|
|
poly->x2 = x1;
|
|
|
|
poly->y1 = y1;
|
|
poly->y2 = y2;
|
|
|
|
poly->x3 = x2;
|
|
poly->y3 = y2;
|
|
|
|
poly->r0 = 16;
|
|
poly->g0 = 16;
|
|
poly->b0 = 16;
|
|
|
|
setSemiTrans(poly, 1);
|
|
|
|
addPrim(current->ot, poly);
|
|
current->primptr += sizeof(POLY_F4);
|
|
|
|
null = (POLY_FT3 *)current->primptr;
|
|
setPolyFT3(null);
|
|
null->x0 = -1;
|
|
null->y0 = -1;
|
|
null->x1 = -1;
|
|
null->y1 = -1;
|
|
null->x2 = -1;
|
|
null->y2 = -1;
|
|
null->tpage = 0;
|
|
|
|
addPrim(current->ot, null);
|
|
|
|
current->primptr += sizeof(POLY_FT3);
|
|
}
|
|
|
|
// [D] [T]
|
|
void ControlMenu(void)
|
|
{
|
|
static int controlmenu_debounce = 0;
|
|
MENU_ITEM* pItem;
|
|
int i;
|
|
ushort paddata;
|
|
MENU_HEADER* menu;
|
|
ushort paddirect;
|
|
int doit;
|
|
|
|
if (playerwithcontrol[2] == 0)
|
|
{
|
|
paddata = Pads[1].dirnew;
|
|
paddirect = Pads[1].direct;
|
|
|
|
if (playerwithcontrol[0])
|
|
{
|
|
paddata = Pads[0].dirnew;
|
|
paddirect = Pads[0].direct;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
paddata = Pads[0].dirnew;
|
|
paddirect = Pads[0].direct;
|
|
|
|
if (NumPlayers == 2)
|
|
{
|
|
paddata = Pads[1].dirnew | Pads[0].dirnew;
|
|
paddirect = Pads[1].direct | Pads[0].direct;
|
|
}
|
|
}
|
|
|
|
// toggle map off
|
|
if (gShowMap)
|
|
{
|
|
if (paddata & (MPAD_CROSS | MPAD_TRIANGLE))
|
|
PauseMap(0);
|
|
|
|
return;
|
|
}
|
|
|
|
pItem = ActiveItem[VisibleMenu];
|
|
|
|
if ((paddirect & 0xA000) && (pItem->Type & PAUSE_TYPE_DIRFUNC))
|
|
{
|
|
doit = 0;
|
|
|
|
if (controlmenu_debounce == 0)
|
|
{
|
|
doit = 1;
|
|
controlmenu_debounce = 10;
|
|
}
|
|
else
|
|
{
|
|
controlmenu_debounce--;
|
|
|
|
if (controlmenu_debounce == 0)
|
|
{
|
|
doit = 1;
|
|
controlmenu_debounce = 2;
|
|
}
|
|
}
|
|
|
|
if (doit)
|
|
{
|
|
// left/right
|
|
(*pItem->func)((paddirect & 0x8000) ? -1 : 1);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
controlmenu_debounce = 0;
|
|
|
|
#ifndef PSX
|
|
// Pause fix for PC mapping
|
|
if ((paddata & MPAD_TRIANGLE) && paddata & (MPAD_D_UP | MPAD_D_DOWN))
|
|
{
|
|
paddata = 0;
|
|
}
|
|
#endif
|
|
|
|
if (paddata & MPAD_D_UP)
|
|
{
|
|
// go up
|
|
ActiveMenuItem--;
|
|
|
|
if (ActiveMenuItem < 0)
|
|
ActiveMenuItem = ActiveMenu->NumItems - 1;
|
|
|
|
ActiveItem[VisibleMenu] = &ActiveMenu->MenuItems[ActiveMenuItem];
|
|
}
|
|
else if (paddata & MPAD_D_DOWN)
|
|
{
|
|
// go down
|
|
ActiveMenuItem++;
|
|
|
|
if (ActiveMenuItem > ActiveMenu->NumItems - 1)
|
|
ActiveMenuItem = 0;
|
|
|
|
ActiveItem[VisibleMenu] = &ActiveMenu->MenuItems[ActiveMenuItem];
|
|
}
|
|
else if (paddata & MPAD_CROSS)
|
|
{
|
|
// Enter submenu
|
|
if (pItem->Type & PAUSE_TYPE_SUBMENU)
|
|
{
|
|
menu = pItem->SubMenu;
|
|
|
|
VisibleMenu++;
|
|
VisibleMenus[VisibleMenu] = menu;
|
|
|
|
SetupMenu(menu, 0);
|
|
return;
|
|
}
|
|
|
|
// function flag
|
|
if (pItem->Type & PAUSE_TYPE_FUNC)
|
|
(*pItem->func)(0);
|
|
|
|
if (pItem->ExitValue == MENU_QUIT_NONE)
|
|
return;
|
|
|
|
if (pItem->ExitValue == MENU_QUIT_BACKMENU)
|
|
{
|
|
VisibleMenu--; // go back in menu stack
|
|
SetupMenu(VisibleMenus[VisibleMenu], 1);
|
|
}
|
|
else
|
|
PauseReturnValue = pItem->ExitValue;
|
|
}
|
|
else if ((paddata & MPAD_TRIANGLE) || (paddata & MPAD_START)) // Triangle or Start
|
|
{
|
|
// continue game if needed
|
|
|
|
if (VisibleMenu == 0)
|
|
{
|
|
#ifndef PSX
|
|
// hack for keyboard swap
|
|
if(!(paddata & MPAD_START))
|
|
return;
|
|
#endif
|
|
for (i = 0; i < ActiveMenu->NumItems; i++)
|
|
{
|
|
pItem = &ActiveMenu->MenuItems[i];
|
|
|
|
if (pItem->ExitValue == MENU_QUIT_CONTINUE)
|
|
{
|
|
PauseReturnValue = pItem->ExitValue;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// only triangle
|
|
if(paddata & 0x10)
|
|
{
|
|
VisibleMenu--;
|
|
SetupMenu(VisibleMenus[VisibleMenu], 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void PauseMap(int direction)
|
|
{
|
|
gShowMap ^= 1;
|
|
|
|
ReadControllers();
|
|
|
|
map_x_shift = 0;
|
|
map_z_shift = 0;
|
|
|
|
if (gShowMap == 0)
|
|
InitOverheadMap();
|
|
}
|
|
|
|
// [D] [T]
|
|
void SfxVolume(int direction)
|
|
{
|
|
if (direction < 0)
|
|
gMasterVolume = gMasterVolume + -100;
|
|
else if (0 < direction)
|
|
gMasterVolume = gMasterVolume + 100;
|
|
|
|
if (gMasterVolume < -10000)
|
|
gMasterVolume = -10000;
|
|
|
|
if (gMasterVolume > 0)
|
|
gMasterVolume = 0;
|
|
|
|
sprintf(SfxVolumeText, "%d", (10000 + gMasterVolume) / 100);
|
|
|
|
SetMasterVolume(gMasterVolume);
|
|
}
|
|
|
|
// [D] [T]
|
|
void MusicVolume(int direction)
|
|
{
|
|
if (direction < 0)
|
|
gMusicVolume = gMusicVolume + -100;
|
|
else if (0 < direction)
|
|
gMusicVolume = gMusicVolume + 100;
|
|
|
|
if (gMusicVolume < -10000)
|
|
gMusicVolume = -10000;
|
|
|
|
if (gMusicVolume > 0)
|
|
gMusicVolume = 0;
|
|
|
|
sprintf(MusicVolumeText, "%d", (10000 + gMusicVolume) / 100);
|
|
|
|
SetXMVolume(gMusicVolume);
|
|
}
|
|
|
|
// [D] [T]
|
|
void EnterScoreName(void)
|
|
{
|
|
u_char chr;
|
|
char* username;
|
|
char* enteredName;
|
|
|
|
SCORE_ENTRY* table;
|
|
unsigned short npad, dpad;
|
|
|
|
username = NULL;
|
|
|
|
if (!gScoreEntered)
|
|
{
|
|
gScorePosition = OnScoreTable(&table);
|
|
|
|
if (gScorePosition != -1)
|
|
username = ScoreName[gScorePosition];
|
|
|
|
CreateScoreNames(table, &gPlayerScore, gScorePosition);
|
|
}
|
|
else
|
|
{
|
|
gScorePosition = -1;
|
|
}
|
|
|
|
gEnteringScore = 1;
|
|
|
|
enteredName = WaitForTextEntry(username, SCORE_NAME_LEN);
|
|
|
|
if (enteredName && username)
|
|
{
|
|
strcpy(gPlayerScore.name, enteredName);
|
|
|
|
AddScoreToTable(table, gScorePosition);
|
|
|
|
sprintf(EnterScoreText, G_LTXT(GTXT_ViewTable));
|
|
sprintf(EnterNameText, G_LTXT(GTXT_HighScores));
|
|
|
|
gScoreEntered = 1;
|
|
}
|
|
|
|
gEnteringScore = 0;
|
|
}
|
|
|
|
void DisplayMenuMessage(char* header, char* text)
|
|
{
|
|
POLY_FT3* null;
|
|
POLY_F4* prim;
|
|
int i;
|
|
int ypos;
|
|
|
|
OutputString(header, 2, 160, 105, 0, 128, 32, 32);
|
|
ypos = 125;
|
|
OutputString(text, 2, 160, ypos, 0, 128, 128, 128);
|
|
|
|
// TODO: Multiline support
|
|
/*
|
|
i = 0;
|
|
do {
|
|
OutputString(text, 2, 160, ypos, 0, 128, 128, 128);
|
|
|
|
ypos += 15;
|
|
|
|
i++;
|
|
} while (i < 5);
|
|
*/
|
|
prim = (POLY_F4*)current->primptr;
|
|
setPolyF4(prim);
|
|
setSemiTrans(prim, 1);
|
|
setShadeTex(prim, 1);
|
|
|
|
prim->y0 = 100;
|
|
prim->y1 = 100;
|
|
prim->y2 = 160;
|
|
prim->y3 = 160;
|
|
prim->x0 = 80;
|
|
prim->x1 = 240;
|
|
prim->x2 = 80;
|
|
prim->x3 = 240;
|
|
|
|
prim->r0 = 16;
|
|
prim->g0 = 16;
|
|
prim->b0 = 16;
|
|
|
|
addPrim(current->ot, prim);
|
|
current->primptr += sizeof(POLY_F4);
|
|
|
|
null = (POLY_FT3*)current->primptr;
|
|
setPolyFT3(null);
|
|
|
|
null->x0 = -1;
|
|
null->y0 = -1;
|
|
null->x1 = -1;
|
|
null->y1 = -1;
|
|
null->x2 = -1;
|
|
null->y2 = -1;
|
|
null->tpage = 0;
|
|
|
|
addPrim(current->ot, null);
|
|
current->primptr += sizeof(POLY_FT3);
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawHighScoreMenu(int selection)
|
|
{
|
|
POLY_FT3* null;
|
|
POLY_F4* prim;
|
|
int i;
|
|
int r,b;
|
|
int ypos;
|
|
char text[8];
|
|
|
|
OutputString(EnterNameText, 2, 160, 70, 0, 128, 32, 32);
|
|
OutputString(G_LTXT(GTXT_Name), 1, 40, 90, 0, 128, 128, 32);
|
|
OutputString(G_LTXT(GTXT_Time), 4, 280, 90, 0, 128, 128, 32);
|
|
|
|
ypos = 110;
|
|
|
|
i = 0;
|
|
do {
|
|
|
|
if (i == selection)
|
|
{
|
|
r = 0;
|
|
b = 0;
|
|
}
|
|
else
|
|
{
|
|
r = 128;
|
|
b = 128;
|
|
}
|
|
|
|
sprintf(text, "%d", i+1);
|
|
|
|
OutputString(text, 1, 40, ypos, 0, r, 128, b);
|
|
|
|
OutputString(ScoreName[i], 1, 60, ypos, 0, r, 128, b);
|
|
OutputString(ScoreItems[i], 4, 220, ypos, 0, r, 128, b);
|
|
OutputString(ScoreTime[i], 4, 280, ypos, 0, r, 128, b);
|
|
|
|
ypos += 15;
|
|
|
|
i++;
|
|
} while (i < 5);
|
|
|
|
prim = (POLY_F4*)current->primptr;
|
|
setPolyF4(prim);
|
|
setSemiTrans(prim, 1);
|
|
setShadeTex(prim, 1);
|
|
|
|
prim->y0 = 65;
|
|
prim->y1 = 65;
|
|
prim->y2 = 197;
|
|
prim->y3 = 197;
|
|
prim->x0 = 26;
|
|
prim->x1 = 294;
|
|
prim->x2 = 26;
|
|
prim->x3 = 294;
|
|
|
|
prim->r0 = 16;
|
|
prim->g0 = 16;
|
|
prim->b0 = 16;
|
|
|
|
addPrim(current->ot, prim);
|
|
current->primptr += sizeof(POLY_F4);
|
|
|
|
null = (POLY_FT3*)current->primptr;
|
|
setPolyFT3(null);
|
|
|
|
null->x0 = -1;
|
|
null->y0 = -1;
|
|
null->x1 = -1;
|
|
null->y1 = -1;
|
|
null->x2 = -1;
|
|
null->y2 = -1;
|
|
null->tpage = 0;
|
|
|
|
addPrim(current->ot, null);
|
|
current->primptr += sizeof(POLY_FT3);
|
|
}
|
|
|
|
int mytolower(int ch)
|
|
{
|
|
if (ch >= 'A' && ch <= 'Z')
|
|
return ('a' + ch - 'A');
|
|
else
|
|
return ch;
|
|
}
|
|
|
|
void strlower(char* str)
|
|
{
|
|
while (*str != '\0')
|
|
{
|
|
*str = mytolower(*str);
|
|
str++;
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void CreateScoreNames(SCORE_ENTRY* table, PLAYER_SCORE* score, int position)
|
|
{
|
|
int time;
|
|
char* text;
|
|
int i;
|
|
|
|
switch (GameType)
|
|
{
|
|
case GAME_PURSUIT:
|
|
case GAME_GETAWAY:
|
|
case GAME_CHECKPOINT:
|
|
case GAME_SURVIVAL:
|
|
text = NULL;
|
|
break;
|
|
case GAME_GATERACE:
|
|
text = G_LTXT(GTXT_Gates);
|
|
break;
|
|
case GAME_TRAILBLAZER:
|
|
text = G_LTXT(GTXT_Cones);
|
|
break;
|
|
default:
|
|
printError("CreateScoreNames: Invalid game type\n");
|
|
return;
|
|
}
|
|
|
|
i = 0;
|
|
do {
|
|
if (i == position)
|
|
{
|
|
time = score->time;
|
|
if (time == -1)
|
|
sprintf(ScoreTime[i], "-:--.--");
|
|
else
|
|
sprintf(ScoreTime[i], "%d:%02d.%02d", time / 180000, time / 3000 + (time / 180000) * -0x3c, (time % 3000) / 0x1e);
|
|
|
|
ScoreItems[i][0] = '\0';
|
|
|
|
if (text != NULL && score->items != -1)
|
|
{
|
|
sprintf(ScoreItems[i], "%d %s", score->items, text);
|
|
strlower(ScoreItems[i]);
|
|
}
|
|
|
|
ClearMem(ScoreName[i], 7);
|
|
}
|
|
else
|
|
{
|
|
time = table->time;
|
|
|
|
if (time == -1)
|
|
sprintf(ScoreTime[i], "-:--.--");
|
|
else
|
|
sprintf(ScoreTime[i], "%d:%02d.%02d", time / 180000, time / 3000 + (time / 180000) * -0x3c, (time % 3000) / 0x1e);
|
|
|
|
ScoreItems[i][0] = '\0';
|
|
|
|
if (text != NULL && table->items != -1)
|
|
{
|
|
sprintf(ScoreItems[i], "%d %s", table->items, text);
|
|
strlower(ScoreItems[i]);
|
|
}
|
|
|
|
sprintf(ScoreName[i], "%s", table->name);
|
|
table++;
|
|
}
|
|
|
|
i++;
|
|
} while (i < 5);
|
|
|
|
}
|
|
|
|
// [A]
|
|
int UpdatePauseMenu(PAUSEMODE mode)
|
|
{
|
|
PAUSEMODE passed_mode;
|
|
passed_mode = mode;
|
|
|
|
if (mode == PAUSEMODE_PADERROR)
|
|
mode = PAUSEMODE_PAUSE;
|
|
|
|
if (passed_mode == PAUSEMODE_PADERROR)
|
|
{
|
|
if (pad_connected == 1)
|
|
InitaliseMenu(mode);
|
|
else
|
|
InitaliseMenu(PAUSEMODE_PADERROR);
|
|
}
|
|
else
|
|
{
|
|
if (pad_connected != 1)
|
|
InitaliseMenu(PAUSEMODE_PADERROR);
|
|
}
|
|
|
|
if (pad_connected < 1)
|
|
playerwithcontrol[2] = 1;
|
|
|
|
ControlMenu();
|
|
|
|
if (PauseReturnValue != 0)
|
|
gDrawPauseMenus = 0;
|
|
|
|
return PauseReturnValue;
|
|
}
|
|
|
|
// [D] [T]
|
|
void ShowPauseMenu(PAUSEMODE mode)
|
|
{
|
|
ReadControllers();
|
|
|
|
if (mode == PAUSEMODE_PAUSEP1)
|
|
{
|
|
playerwithcontrol[0] = 1;
|
|
playerwithcontrol[1] = 0;
|
|
playerwithcontrol[2] = 0;
|
|
}
|
|
else if (mode == PAUSEMODE_PAUSEP2)
|
|
{
|
|
playerwithcontrol[0] = 0;
|
|
playerwithcontrol[1] = 1;
|
|
playerwithcontrol[2] = 0;
|
|
}
|
|
else
|
|
{
|
|
playerwithcontrol[0] = 0;
|
|
playerwithcontrol[1] = 0;
|
|
playerwithcontrol[2] = 1;
|
|
}
|
|
|
|
SetDispMask(1);
|
|
|
|
SfxVolume(0);
|
|
MusicVolume(0);
|
|
|
|
StopPadVibration(0);
|
|
StopPadVibration(1);
|
|
|
|
InitaliseMenu(mode);
|
|
gDrawPauseMenus = 1;
|
|
|
|
PauseReturnValue = 0;
|
|
}
|
|
|
|
// [D] [T]
|
|
void DrawPauseMenus(void)
|
|
{
|
|
int displayMessage;
|
|
|
|
#if !defined(PSX) && defined(DEBUG_OPTIONS)
|
|
extern int g_FreeCameraEnabled;
|
|
|
|
if (g_FreeCameraEnabled)
|
|
return;
|
|
#endif
|
|
|
|
displayMessage = gDisplayedMessage.show == -1 || gDisplayedMessage.show > 0;
|
|
|
|
if ((gDrawPauseMenus || displayMessage) && gShowMap == 0)
|
|
{
|
|
if (displayMessage)
|
|
{
|
|
DisplayMenuMessage(gDisplayedMessage.header, gDisplayedMessage.text);
|
|
|
|
if(gDisplayedMessage.show > 0)
|
|
gDisplayedMessage.show--;
|
|
}
|
|
else if (gEnteringScore)
|
|
DrawHighScoreMenu(gScorePosition);
|
|
else
|
|
DrawVisibleMenus();
|
|
}
|
|
} |