RingRacers/src/menus/options-profiles-edit-1.c
2025-10-12 14:40:52 -05:00

246 lines
6.8 KiB
C

// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by "Lat'".
// Copyright (C) 2025 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file menus/options-profiles-edit-1.c
/// \brief Profile Editor
#include "../i_time.h"
#include "../k_menu.h"
#include "../s_sound.h"
#include "../m_cond.h"
// These are placed in descending order next to the things they modify, for clarity.
// Try to keep the mvar2 in order, if you add new profile info!!
menuitem_t OPTIONS_EditProfile[] = {
{IT_STRING | IT_CVAR | IT_CV_STRING, "Profile ID", "6-character long name to display on menus.",
NULL, {.cvar = &cv_dummyprofilename}, 0, 41},
{IT_STRING | IT_CVAR | IT_CV_STRING, "Player Tag", "Full name, displayed online and in replays.",
NULL, {.cvar = &cv_dummyprofileplayername}, 0, 61},
{IT_STRING | IT_CALL, "Controls", "Change the button mappings.",
NULL, {.routine = M_ProfileDeviceSelect}, 0, 91},
{IT_STRING | IT_SUBMENU, "Accessibility", "Accessibility and quality of life options.",
NULL, {.submenu = &OPTIONS_ProfileAccessibilityDef}, 0, 111},
{IT_STRING | IT_CALL, "Character", NULL, // tooltip set in M_StartEditProfile
NULL, {.routine = M_CharacterSelect}, 0, 131},
{IT_STRING | IT_CALL, "Confirm", "Confirm changes.",
NULL, {.routine = M_ConfirmProfile}, 0, 171},
};
menu_t OPTIONS_EditProfileDef = {
sizeof (OPTIONS_EditProfile) / sizeof (menuitem_t),
&OPTIONS_ProfilesDef,
0,
OPTIONS_EditProfile,
32, 80,
SKINCOLOR_ULTRAMARINE, 0,
MBF_DRAWBGWHILEPLAYING,
"FILE",
2, 5,
M_DrawEditProfile,
M_DrawOptionsCogs,
M_HandleProfileEdit,
NULL,
NULL,
M_ProfileEditInputs,
};
// Returns true if the profile can be saved, false otherwise. Also starts messages if necessary.
static boolean M_ProfileEditEnd(const UINT8 pid)
{
UINT8 i;
// Guest profile, you can't edit that one!
if (optionsmenu.profilen == 0)
{
S_StartSound(NULL, sfx_s3k7b);
M_StartMessage("Profiles", M_GetText("Guest profile cannot be edited.\nCreate a new profile instead."), NULL, MM_NOTHING, NULL, NULL);
M_SetMenuDelay(pid);
return false;
}
// check if some profiles have the same name
for (i = 0; i < PR_GetNumProfiles(); i++)
{
profile_t *check = PR_GetProfile(i);
// For obvious reasons don't check if our name is the same as our name....
if (check != optionsmenu.profile)
{
if (!(strcmp(optionsmenu.profile->profilename, check->profilename)))
{
S_StartSound(NULL, sfx_s3k7b);
M_StartMessage("Profiles", M_GetText("Another profile uses the same name.\nThis must be changed to be able to save."), NULL, MM_NOTHING, NULL, NULL);
M_SetMenuDelay(pid);
return false;
}
}
}
return true;
}
static void M_ProfileEditApply(void)
{
SINT8 belongsto = PR_ProfileUsedBy(optionsmenu.profile);
// Save the profile
optionsmenu.profile->kickstartaccel = cv_dummyprofilekickstart.value;
optionsmenu.profile->autoroulette = cv_dummyprofileautoroulette.value;
optionsmenu.profile->litesteer = cv_dummyprofilelitesteer.value;
optionsmenu.profile->strictfastfall = cv_dummyprofilestrictfastfall.value;
optionsmenu.profile->descriptiveinput = cv_dummyprofiledescriptiveinput.value;
optionsmenu.profile->autoring = cv_dummyprofileautoring.value;
optionsmenu.profile->rumble = cv_dummyprofilerumble.value;
optionsmenu.profile->fov = cv_dummyprofilefov.value;
// If this profile is in-use by anyone, apply the changes immediately upon exiting.
// Don't apply the full profile itself as that would lead to issues mid-game.
if (belongsto > -1 && belongsto < MAXSPLITSCREENPLAYERS)
{
PR_ApplyProfileToggles(optionsmenu.profilen, belongsto);
if (gamestate == GS_MENU)
{
// Safe to apply skin, etc here.
PR_ApplyProfileLight(optionsmenu.profilen, belongsto);
}
}
// Reapply player 1's real profile ID.
if (cv_currprofile.value > -1)
{
PR_ApplyProfilePretend(cv_lastprofile[0].value, 0);
}
}
static void M_ProfileEditExit(void)
{
M_ProfileEditApply();
if (M_GameTrulyStarted() == true)
{
optionsmenu.toptx = 160;
optionsmenu.topty = 35;
optionsmenu.resetprofile = true; // Reset profile after the transition is done.
}
else
{
M_ResetOptions(); // Reset all options variables otherwise things are gonna go reaaal bad lol.
}
PR_SaveProfiles(); // save profiles after we do that.
}
// For profile edit, just make sure going back resets the card to its position, the rest is taken care of automatically.
boolean M_ProfileEditInputs(INT32 ch)
{
(void) ch;
const UINT8 pid = 0;
if (M_MenuBackPressed(pid))
{
if (M_ProfileEditEnd(pid))
{
M_ProfileEditExit();
if (cv_currprofile.value == -1)
M_SetupNextMenu(&MAIN_ProfilesDef, false);
else
M_GoBack(0);
M_SetMenuDelay(pid);
}
return true;
}
else if (M_MenuConfirmPressed(pid))
{
if (currentMenu->menuitems[itemOn].status & IT_TRANSTEXT)
return true; // No.
}
if (menucmd[pid].dpad_ud != 0)
{
optionsmenu.offset.start = I_GetTime();
}
return false;
}
// Handle some actions in profile editing
void M_HandleProfileEdit(void)
{
// Always copy the profile name and player name in the profile.
if (optionsmenu.profile && !menutyping.active)
{
// Copy the first 6 chars for profile name
if (cv_dummyprofilename.string[0])
{
char *s;
// convert dummyprofilename to uppercase
strncpy(optionsmenu.profile->profilename, cv_dummyprofilename.string, PROFILENAMELEN);
s = optionsmenu.profile->profilename;
while (*s)
{
*s = toupper(*s);
s++;
}
}
if (cv_dummyprofileplayername.string[0])
{
strncpy(optionsmenu.profile->playername, cv_dummyprofileplayername.string, MAXPLAYERNAME);
}
}
M_OptionsTick(); // Has to be afterwards because this can unset optionsmenu.profile
}
// Confirm Profile edi via button.
void M_ConfirmProfile(INT32 choice)
{
const UINT8 pid = 0;
(void) choice;
if (M_ProfileEditEnd(pid))
{
if (cv_currprofile.value > -1)
{
M_ProfileEditExit();
M_GoBack(0);
M_SetMenuDelay(pid);
}
else
{
M_StartMessage("Profiles", M_GetText("Are you sure you wish to\nselect this profile?\n"), &M_FirstPickProfile, MM_YESNO, NULL, NULL);
M_SetMenuDelay(pid);
}
}
return;
}
// Prompt a device selection window (just tap any button on the device you want)
void M_ProfileDeviceSelect(INT32 choice)
{
(void)choice;
// While we're here, setup the incoming controls menu to reset the scroll & bind status:
optionsmenu.controlscroll = 0;
optionsmenu.bindtimer = 0;
optionsmenu.lastkey = 0;
optionsmenu.keyheldfor = 0;
optionsmenu.contx = optionsmenu.tcontx = controlleroffsets[gc_a][0];
optionsmenu.conty = optionsmenu.tconty = controlleroffsets[gc_a][1];
M_SetupNextMenu(&OPTIONS_ProfileControlsDef, false); // Don't set device here anymore.
}