@@ -70,6 +70,9 @@ typedef struct
7070 float contrast ;
7171 float brightness ;
7272
73+ // [game]
74+ u8 saveSlot ;
75+
7376 // [advanced]
7477 bool saveOverride ;
7578 u16 defaultSave ;
@@ -98,6 +101,9 @@ static OafConfig g_oafConfig =
98101 1.f , // contrast
99102 0.f , // brightness
100103
104+ // [game]
105+ 0 , // saveSlot
106+
101107 // [advanced]
102108 false, // saveOverride
103109 14 // defaultSave
@@ -492,7 +498,7 @@ static void gbaGfxHandler(void *args)
492498 taskExit ();
493499}
494500
495- static int confIniHandler (void * user , const char * section , const char * name , const char * value )
501+ static int cfgIniCallback (void * user , const char * section , const char * name , const char * value )
496502{
497503 OafConfig * const config = (OafConfig * )user ;
498504
@@ -516,6 +522,11 @@ static int confIniHandler(void* user, const char* section, const char* name, con
516522 else if (strcmp (name , "brightness" ) == 0 )
517523 config -> brightness = str2float (value );
518524 }
525+ else if (strcmp (section , "game" ) == 0 )
526+ {
527+ if (strcmp (name , "saveSlot" ) == 0 )
528+ config -> saveSlot = (u8 )strtoul (value , NULL , 10 );
529+ }
519530 else if (strcmp (section , "advanced" ) == 0 )
520531 {
521532 if (strcmp (name , "saveOverride" ) == 0 )
@@ -528,14 +539,14 @@ static int confIniHandler(void* user, const char* section, const char* name, con
528539 return 1 ; // 1 is no error? Really?
529540}
530541
531- static Result parseConfig (const char * const path , void * config )
542+ static Result parseOafConfig (const char * const path , const bool writeDefaultCfg )
532543{
533544 char * iniBuf = (char * )calloc (INI_BUF_SIZE , 1 );
534545 if (iniBuf == NULL ) return RES_OUT_OF_MEM ;
535546
536547 Result res = fsQuickRead (path , iniBuf , INI_BUF_SIZE - 1 );
537- if (res == RES_OK ) ini_parse_string (iniBuf , confIniHandler , config );
538- else
548+ if (res == RES_OK ) ini_parse_string (iniBuf , cfgIniCallback , & g_oafConfig );
549+ else if ( writeDefaultCfg )
539550 {
540551 const char * const defaultConfig = DEFAULT_CONFIG ;
541552 res = fsQuickWrite (path , defaultConfig , strlen (defaultConfig ));
@@ -591,27 +602,33 @@ static Result showFileBrowser(char romAndSavePath[512])
591602 return res ;
592603}
593604
594- static void rom2SavePath (char romPath [512 ], const u8 saveSlot )
605+ static void rom2GameCfgPath (char romPath [512 ])
606+ {
607+ // Extract the file name and change the extension.
608+ // For cfg2SavePath() we need to reserve 2 extra bytes/chars.
609+ char tmpSaveFileName [256 ];
610+ safeStrcpy (tmpSaveFileName , strrchr (romPath , '/' ) + 1 , 256 - 2 );
611+ strcpy (tmpSaveFileName + strlen (tmpSaveFileName ) - 4 , ".ini" );
612+
613+ // Construct the new path.
614+ strcpy (romPath , OAF_SAVE_DIR "/" );
615+ strcat (romPath , tmpSaveFileName );
616+ }
617+
618+ static void gameCfg2SavePath (char cfgPath [512 ], const u8 saveSlot )
595619{
596620 if (saveSlot > 9 )
597621 {
598- * romPath = '\0' ; // Prevent using the ROM as save file.
622+ * cfgPath = '\0' ; // Prevent using the ROM as save file.
599623 return ;
600624 }
601625
602- char tmpSaveFileName [256 ];
603626 static char numberedExt [7 ] = {'.' , 'X' , '.' , 's' , 'a' , 'v' , '\0' };
604627
628+ // Change the extension.
629+ // This relies on rom2GameCfgPath() to reserve 2 extra bytes/chars.
605630 numberedExt [1 ] = '0' + saveSlot ;
606-
607- // Extract the file name and change the extension.
608- // The numbered extension is 2 chars longer than unnumbered.
609- safeStrcpy (tmpSaveFileName , strrchr (romPath , '/' ) + 1 , 256 - 2 );
610- strcpy (tmpSaveFileName + strlen (tmpSaveFileName ) - 4 , (saveSlot == 0 ? ".sav" : numberedExt ));
611-
612- // Construct the new path.
613- strcpy (romPath , OAF_SAVE_DIR "/" );
614- strcat (romPath , tmpSaveFileName );
631+ strcpy (cfgPath + strlen (cfgPath ) - 4 , (saveSlot == 0 ? ".sav" : numberedExt ));
615632}
616633
617634Result oafParseConfigEarly (void )
@@ -627,7 +644,7 @@ Result oafParseConfigEarly(void)
627644 if ((res = fMkdir (OAF_SAVE_DIR )) != RES_OK && res != RES_FR_EXIST ) break ;
628645
629646 // Parse the config.
630- res = parseConfig ("config.ini" , & g_oafConfig );
647+ res = parseOafConfig ("config.ini" , true );
631648 } while (0 );
632649
633650 return res ;
@@ -641,38 +658,47 @@ u8 oafGetBacklightConfig(void)
641658Result oafInitAndRun (void )
642659{
643660 Result res ;
644- char * const romAndSavePath = (char * )calloc (512 , 1 );
645- if (romAndSavePath != NULL )
661+ char * const filePath = (char * )calloc (512 , 1 );
662+ if (filePath != NULL )
646663 {
647664 do
648665 {
649- if ((res = fsLoadPathFromFile ("autoboot.txt" , romAndSavePath )) == RES_FR_NO_FILE )
666+ // Try to load the ROM path from autoboot.txt.
667+ // If this file doesn't exist show the file browser.
668+ if ((res = fsLoadPathFromFile ("autoboot.txt" , filePath )) == RES_FR_NO_FILE )
650669 {
651- if ((res = showFileBrowser (romAndSavePath )) != RES_OK || * romAndSavePath == '\0' ) break ;
670+ if ((res = showFileBrowser (filePath )) != RES_OK || * filePath == '\0' ) break ;
652671 ee_puts ("Loading..." );
653672 }
654673 else if (res != RES_OK ) break ;
655674
675+ // Load the ROM file.
656676 u32 romSize ;
657- if ((res = loadGbaRom (romAndSavePath , & romSize )) != RES_OK ) break ;
677+ if ((res = loadGbaRom (filePath , & romSize )) != RES_OK ) break ;
678+
679+ // Load the per-game config.
680+ rom2GameCfgPath (filePath );
681+ if ((res = parseOafConfig (filePath , false)) != RES_OK && res != RES_FR_NO_FILE ) break ;
658682
659- // Adjust path for the save file and get save type.
660- rom2SavePath ( romAndSavePath , 0 ); // TODO: Save slot config.
683+ // Adjust the path for the save file and get save type.
684+ gameCfg2SavePath ( filePath , g_oafConfig . saveSlot );
661685 u16 saveType ;
662686 if (g_oafConfig .useGbaDb || g_oafConfig .saveOverride )
663- saveType = getSaveType (romSize , romAndSavePath );
687+ saveType = getSaveType (romSize , filePath );
664688 else
665689 saveType = detectSaveType (romSize );
666690
667- // Prepare ARM9 for GBA mode + settings and save loading.
668- if ((res = LGY_prepareGbaMode (g_oafConfig .directBoot , saveType , romAndSavePath )) == RES_OK )
691+ // Prepare ARM9 for GBA mode + save loading.
692+ if ((res = LGY_prepareGbaMode (g_oafConfig .directBoot , saveType , filePath )) == RES_OK )
669693 {
670694#ifdef NDEBUG
695+ // Force black and turn the backlight off on the bottom screen.
696+ // Don't turn the backlight off on 2DS (1 panel).
671697 GFX_setForceBlack (false, true);
672- // Don't turn the backlight off on 2DS.
673698 if (MCU_getSystemModel () != 3 ) GFX_powerOffBacklights (GFX_BLIGHT_BOT );
674699#endif
675700
701+ // Initialize the legacy frame buffer and frame handler.
676702 const KHandle frameReadyEvent = createEvent (false);
677703 LGYFB_init (frameReadyEvent ); // Setup Legacy Framebuffer.
678704 createTask (0x800 , 3 , gbaGfxHandler , (void * )frameReadyEvent );
@@ -687,7 +713,7 @@ Result oafInitAndRun(void)
687713 }
688714 else res = RES_OUT_OF_MEM ;
689715
690- free (romAndSavePath );
716+ free (filePath );
691717
692718 return res ;
693719}
0 commit comments