Add core option sublabels

This commit is contained in:
retro-wertz
2019-07-20 00:12:02 +08:00
parent 3a4556dec6
commit 3659603d19
4 changed files with 690 additions and 107 deletions

View File

@@ -944,9 +944,14 @@ static VSUNIGAME dipswitch_topgun = {
}
};
typedef struct {
char value[100];
char label[100];
} VSUNIGAMEOPT_VALUE;
typedef struct {
char key[64];
char val[150];
VSUNIGAMEOPT_VALUE val[10];
} VSUNIGAMEOPT;
static VSUNIGAME *vsgame = NULL;
@@ -967,34 +972,32 @@ static void str_to_corekey_label(char *str)
static void make_core_options(void)
{
unsigned i, dipswitch_size;
char core_prefix[32];
unsigned i, j, num_dipswitch;
char *romname_short = NULL;
dipswitch_size = vsgame->dipswitch_size;
sprintf(core_prefix, "fceumm_dipswitch_%s", vsgame->romname_short);
for (i = 0; i < dipswitch_size; i++)
num_dipswitch = vsgame->dipswitch_size;
romname_short = vsgame->romname_short;
for (i = 0; i < num_dipswitch; i++)
{
unsigned x;
char core_key[64], core_values[150];
DIPSWITCH *coreoptions = &vsgame->dipswitch_core_options[i];
unsigned num_values = vsgame->dipswitch_core_options[i].settings_size;
const char *option_name = vsgame->dipswitch_core_options[i].option_name;
/* make var key string from list */
sprintf(core_key, "%s%c%s", core_prefix, '-', coreoptions->option_name);
memset(core_key, 0 , sizeof(core_key));
memset(core_values, 0 , sizeof(core_values));
/* Create core key string */
sprintf(core_key, "fceumm_dipswitch_%s-%s", romname_short, option_name);
/* sanitize core key string */
str_to_corekey_label(core_key);
/* make var values string from lists of values */
sprintf(core_values, "%s; ", coreoptions->option_name);
for (x = 0; x < coreoptions->settings_size; x++)
{
SETTING *corevalues = &coreoptions->settings[x];
strcat(core_values, corevalues->name);
if ((coreoptions->settings_size - 1) > x)
strcat(core_values, "|");
}
sprintf(vscoreopt[i].key, "%s", core_key);
sprintf(vscoreopt[i].val, "%s", core_values);
/* Create core values */
for (j = 0; j < num_values; j++)
{
const char *var_value = vsgame->dipswitch_core_options[i].settings[j].name;
sprintf(vscoreopt[i].val[j].value, "%s", var_value);
}
}
}
@@ -1067,25 +1070,25 @@ static void update_dipswitch_vsuni(void)
{
struct retro_variable var = {0};
unsigned idx_dips, idx_var;
uint8 vsdip_new = 0x00;
uint8 vsdip_new = FCEUI_VSUniGetDIPs();
if (vsgame == NULL)
return;
vsdip_new = FCEUI_VSUniGetDIPs();
for (idx_dips = 0; idx_dips < vsgame->dipswitch_size; idx_dips++)
{
DIPSWITCH *core_option = &vsgame->dipswitch_core_options[idx_dips];
var.key = vscoreopt[idx_dips].key;
const char *key = vscoreopt[idx_dips].key;
unsigned num_options = vsgame->dipswitch_core_options[idx_dips].settings_size;
var.key = key;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) == 0)
continue;
for (idx_var = 0; idx_var < core_option->settings_size; idx_var++)
for (idx_var = 0; idx_var < num_options; idx_var++)
{
SETTING *vs_settings = &core_option->settings[idx_var];
if (strcmp(var.value, vs_settings->name) != 0)
const char *var_value = vsgame->dipswitch_core_options[idx_dips].settings[idx_var].name;
uint8 value = vsgame->dipswitch_core_options[idx_dips].settings[idx_var].value;
uint8 mask = vsgame->dipswitch_core_options[idx_dips].mask;
if (strcmp(var.value, var_value) != 0)
continue;
vsdip_new &= ~core_option->mask;
vsdip_new |= vs_settings->value;
vsdip_new &= ~mask;
vsdip_new |= value;
}
}
@@ -1101,28 +1104,67 @@ static void update_dipswitch_vsuni(void)
}
/* Nintendo World Championship */
static struct retro_variable dipswitch_nwc[] = {
{ "fceumm_dipswitch_nwc_swa", "Dipswitch SW1 (18.7s); disabled|enabled" },
{ "fceumm_dipswitch_nwc_swb", "Dipswitch SW2 (37.5s); disabled|enabled" },
{ "fceumm_dipswitch_nwc_swc", "Dipswitch SW3 (1m 15s); enabled|disabled" },
{ "fceumm_dipswitch_nwc_swd", "Dipswitch SW4 (2m 30s); disabled|enabled" },
{ NULL, NULL }
static struct retro_core_option_definition dipswitch_nwc[] = {
{
"fceumm_dipswitch_nwc_swa",
"Dipswitch SW1 (+18.7secs)",
"Adds 18.7 seconds to total time. Total time = 5 mins + enabled dipswitches.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"disabled",
},
{
"fceumm_dipswitch_nwc_swb",
"Dipswitch SW1 (+37.5s)",
"Adds 37.5 seconds to total time. Total time = 5 mins + enabled dipswitches.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"disabled",
},
{
"fceumm_dipswitch_nwc_swc",
"Dipswitch SW1 (+1m 15s)",
"Adds 1 minute and 15 seconds to total time. Total time = 5 mins + enabled dipswitches.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"enabled",
},
{
"fceumm_dipswitch_nwc_swd",
"Dipswitch SW1 (+2m 30s)",
"Adds 2 minutes and 30 seconds to total time. Total time = 5 mins + time of enabled dipswitches.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"disabled",
},
};
static void update_dipswitch_nwc(void)
{
struct retro_variable var = {0};
unsigned dips = 0x00;
unsigned index;
unsigned i;
for (index = 0; index < 4; index++)
for (i = 0; i < 4; i++)
{
struct retro_variable *nwc = &dipswitch_nwc[index];
var.key = nwc->key;
const char *key = dipswitch_nwc[i].key;
var.key = key;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
if (strcmp(var.value, "enabled") == 0)
dips |= (1 << index);
dips |= (1 << i);
}
}
@@ -1136,9 +1178,9 @@ static void update_dipswitch_nwc(void)
}
}
void set_dipswitch_variables(unsigned *index, struct retro_variable *vars)
void set_dipswitch_variables(unsigned *index, struct retro_core_option_definition *vars)
{
unsigned i, idx = *index;
unsigned idx = *index;
/* VSUNI Dipswitch */
if (GameInfo->type == GIT_VSUNI)
@@ -1146,10 +1188,25 @@ void set_dipswitch_variables(unsigned *index, struct retro_variable *vars)
vsgame = get_vsuni_dipswitch(GameInfo->gameid);
if (vsgame)
{
unsigned i, j;
unsigned num_options = vsgame->dipswitch_size;
make_core_options();
for (i = 0; i < vsgame->dipswitch_size; i++, idx++) {
vars[idx].key = vscoreopt[i].key;
vars[idx].value = vscoreopt[i].val;
for (i = 0; i < num_options; i++) {
const char *key = vscoreopt[i].key;
const char *desc = vsgame->dipswitch_core_options[i].option_name;
unsigned num_values = vsgame->dipswitch_core_options[i].settings_size;
vars[idx].key = key;
vars[idx].desc = desc;
for (j = 0; j < num_values; j++) {
char *value = vscoreopt[i].val[j].value;
vars[idx].values[j].value = value;
}
idx++;
}
}
}
@@ -1157,7 +1214,8 @@ void set_dipswitch_variables(unsigned *index, struct retro_variable *vars)
/* Nintendo World Championship cart (Mapper 105)*/
if (iNESCart.mapper == 105)
{
i = 0;
unsigned i = 0;
while (dipswitch_nwc[i].key) {
vars[idx] = dipswitch_nwc[i];
idx++;
@@ -1165,7 +1223,7 @@ void set_dipswitch_variables(unsigned *index, struct retro_variable *vars)
}
}
*index = idx;
*index = idx;
}
void update_dipswitch(void)

View File

@@ -3,7 +3,7 @@
#include <libretro.h>
void set_dipswitch_variables(unsigned *index, struct retro_variable *vars);
void set_dipswitch_variables(unsigned *index, struct retro_core_option_definition *vars);
void update_dipswitch(void);
extern retro_environment_t environ_cb;

View File

@@ -30,6 +30,7 @@
#include "libretro-common/include/streams/memory_stream.h"
#include "dipswitch.h"
#include "libretro_core_options.h"
#define MAX_PLAYERS 4 /* max supported players */
#define MAX_PORTS 2 /* max controller ports,
@@ -80,6 +81,7 @@ static unsigned turbo_delay = 0;
static unsigned input_type[MAX_PLAYERS + 1] = {0}; /* 4-players + famicom expansion */
enum RetroZapperInputModes{RetroLightgun, RetroMouse, RetroPointer};
static enum RetroZapperInputModes zappermode = RetroLightgun;
static unsigned show_advance_sound_options;
/* emulator-specific variables */
@@ -744,63 +746,22 @@ void retro_set_controller_port_device(unsigned port, unsigned device)
static void set_variables(void)
{
static const struct retro_variable vars[] = {
{ "fceumm_region", "Region Override; Auto|NTSC|PAL|Dendy" },
{ "fceumm_aspect", "Preferred aspect ratio; 8:7 PAR|4:3" },
{ "fceumm_palette", "Color Palette; default|asqrealc|nintendo-vc|rgb|yuv-v3|unsaturated-final|sony-cxa2025as-us|pal|bmf-final2|bmf-final3|smooth-fbx|composite-direct-fbx|pvm-style-d93-fbx|ntsc-hardware-fbx|nes-classic-fbx-fs|nescap|wavebeam|raw|custom" },
{ "fceumm_up_down_allowed", "Allow Opposing Directions; disabled|enabled" },
#ifdef PSP
{ "fceumm_overscan", "Crop Overscan; enabled|disabled" },
#else
{ "fceumm_overscan_h", "Crop Overscan (Horizontal); disabled|enabled" },
{ "fceumm_overscan_v", "Crop Overscan (Vertical); enabled|disabled" },
#endif
{ "fceumm_nospritelimit", "No Sprite Limit; disabled|enabled" },
{ "fceumm_sndvolume", "Sound Volume; 150|160|170|180|190|200|210|220|230|240|250|0|10|20|30|40|50|60|70|80|90|100|110|120|130|140" },
{ "fceumm_sndquality", "Sound Quality; Low|High|Very High" },
{ "fceumm_swapduty", "Swap Duty Cycles; disabled|enabled" },
#ifdef DEBUG
{ "fceumm_apu_1", "Enable Sound Channel 1 (Square 1); enabled|disabled" },
{ "fceumm_apu_2", "Enable Sound Channel 2 (Square 2); enabled|disabled" },
{ "fceumm_apu_3", "Enable Sound Channel 3 (Triangle); enabled|disabled" },
{ "fceumm_apu_4", "Enable Sound Channel 4 (Noise); enabled|disabled" },
{ "fceumm_apu_5", "Enable Sound Channel 5 (PCM); enabled|disabled" },
#endif
{ "fceumm_turbo_enable", "Turbo Enable; None|Player 1|Player 2|Both" },
{ "fceumm_turbo_delay", "Turbo Delay (in frames); 3|5|10|15|30|60|1|2" },
{ "fceumm_zapper_mode", "Zapper Mode; lightgun|touchscreen|mouse" },
{ "fceumm_show_crosshair", "Show Crosshair; enabled|disabled" },
{ "fceumm_overclocking", "Overclocking; disabled|2x-Postrender|2x-VBlank" },
{ "fceumm_ramstate", "RAM power up state (Restart); fill $ff|fill $00|random" },
{ NULL, NULL }
};
unsigned i = 0, index = 0;
static struct retro_variable vars_empty = { NULL, NULL };
static struct retro_variable retro_vars[32];
unsigned i = 0, index_core = 0;
/* Initialize main core option struct */
for (i = 0; i < MAX_CORE_OPTIONS; i++)
option_defs_us[i] = option_defs_empty;
while (vars[index_core].key != NULL)
{
retro_vars[index_core].key = vars[index_core].key;
retro_vars[index_core].value = vars[index_core].value;
index_core++;
/* Write common core options to main struct */
while (option_defs_common[index].key) {
option_defs_us[index] = option_defs_common[index];
index++;
}
/* append dipswitches to core options if available */
set_dipswitch_variables(&index_core, retro_vars);
/* Append dipswitch settings to core options if available */
set_dipswitch_variables(&index, option_defs_us);
/* NULL terminate */
retro_vars[index_core] = vars_empty;
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)retro_vars);
#ifdef DEBUG
/* list core options */
i = 0;
while (retro_vars[i].key) {
FCEU_printf(" { '%s', '%s' }\n", retro_vars[i].key, retro_vars[i].value);
i++;
}
#endif
libretro_set_core_options(environ_cb);
}
void retro_set_environment(retro_environment_t cb)
@@ -1316,7 +1277,8 @@ static void check_variables(bool startup)
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
sndvolume = atoi(var.value);
int val = (int)(atof(var.value) * 25.6);
sndvolume = val;
FCEUD_SoundToggle();
}

View File

@@ -0,0 +1,563 @@
#ifndef LIBRETRO_CORE_OPTIONS_H__
#define LIBRETRO_CORE_OPTIONS_H__
#include <stdlib.h>
#include <string.h>
#include <libretro.h>
#include <retro_inline.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
********************************
* Core Option Definitions
********************************
*/
/* RETRO_LANGUAGE_ENGLISH */
/* Default language:
* - All other languages must include the same keys and values
* - Will be used as a fallback in the event that frontend language
* is not available
* - Will be used as a fallback for any missing entries in
* frontend language definition */
#define MAX_CORE_OPTIONS 32
struct retro_core_option_definition option_defs_common[] = {
{
"fceumm_region",
"Region Override",
"Force core to use NTSC, PAL or Dendy region timings.",
{
{ "Auto", NULL },
{ "NTSC", NULL },
{ "PAL", NULL },
{ "Dendy", NULL },
{ NULL, NULL},
},
"Auto",
},
{
"fceumm_aspect",
"Preferred aspect ratio",
"Choose prefered aspect ratio.",
{
{ "8:7 PAR", NULL },
{ "4:3", NULL },
{ NULL, NULL},
},
"8:7 PAR",
},
{
"fceumm_palette",
"Color Palette",
"Choose from pre-generted palettes, a custom 64x3 palette from file or raw format (needs to use a nes-decoder shader).",
{
{ "default", NULL },
{ "asqrealc", NULL },
{ "nintendo-vc", NULL },
{ "rgb", NULL },
{ "yuv-v3", NULL },
{ "unsaturated-final", NULL },
{ "sony-cxa2025as-us", NULL },
{ "pal", NULL },
{ "bmf-final2", NULL },
{ "bmf-final3", NULL },
{ "smooth-fbx", NULL },
{ "composite-direct-fbx", NULL },
{ "pvm-style-d93-fbx", NULL },
{ "ntsc-hardware-fbx", NULL },
{ "nes-classic-fbx-fs", NULL },
{ "nescap", NULL },
{ "wavebeam", NULL },
{ "raw", NULL },
{ "custom", NULL },
{ NULL, NULL},
},
"default",
},
{
"fceumm_up_down_allowed",
"Allow Opposing Directions",
"Allows simultaneous UP+DOWN or LEFT+RIGHT button combination which can create different effects in some games.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"disabled",
},
#ifdef PSP
{
"fceumm_overscan",
"Crop Overscan",
"Removes 8 pixel overscan from all sides",
{
{ "enabled", NULL },
{ "disabled", NULL },
{ NULL, NULL},
},
"enabled",
},
#else
{
"fceumm_overscan_h",
"Crop Overscan (Horizontal)",
"Removes 8 pixel from left and right of screen to simulates overscans seen on standard CRT television.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"disabled",
},
{
"fceumm_overscan_v",
"Crop Overscan (Vertical)",
"Removes 8 pixel from top and bottom of screen to simulates overscans seen on standard CRT television.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"enabled",
},
#endif
{
"fceumm_nospritelimit",
"No Sprite Limit",
"Removes the 8-per-scanline hardware limit. This reduces sprite flickering but can cause some games to glitch since some use this for effects.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"disabled",
},
{
"fceumm_sndvolume",
"Sound Volume",
"Change master volume level",
{
{ "0", NULL },
{ "1", NULL },
{ "2", NULL },
{ "3", NULL },
{ "4", NULL },
{ "5", NULL },
{ "6", NULL },
{ "7", NULL },
{ "8", NULL },
{ "9", NULL },
{ "10", NULL },
{ NULL, NULL},
},
"7",
},
{
"fceumm_sndquality",
"Sound Quality",
"Enable higher quality sounds in exchange for more processing power required",
{
{ "Low", NULL },
{ "High", NULL },
{ "Very High", NULL },
{ NULL, NULL},
},
"Low",
},
{
"fceumm_swapduty",
"Swap Duty Cycles",
"Simulates the sound from famiclones has the pulse wave channels duty cycle bits reversed.",
{
{ "disabled", NULL },
{ "enabled", NULL },
{ NULL, NULL},
},
"disabled",
},
{
"fceumm_turbo_enable",
"Turbo Enable",
"Enables or disables turbo buttons.",
{
{ "None", NULL },
{ "Player 1", NULL },
{ "Player 2", NULL },
{ "Both", NULL },
{ NULL, NULL},
},
"None",
},
{
"fceumm_turbo_delay",
"Turbo Delay (in frames)",
"Repeat rate of turbo buttons in frames.",
{
{ "1", NULL },
{ "2", NULL },
{ "3", NULL },
{ "5", NULL },
{ "10", NULL },
{ "15", NULL },
{ "30", NULL },
{ "60", NULL },
{ NULL, NULL},
},
"3",
},
{
"fceumm_zapper_mode",
"Zapper Mode",
"Selects device to use for zapper games.",
{
{ "lightgun", NULL },
{ "touchscreen", NULL },
{ "mouse", NULL },
{ NULL, NULL},
},
"lightgun",
},
{
"fceumm_show_crosshair",
"Show Crosshair",
"Shows or hides on-screen crosshairs when using a zapper.",
{
{ "enabled", NULL },
{ "disabled", NULL },
{ NULL, NULL},
},
"enabled",
},
{
"fceumm_overclocking",
"Overclocking",
"Enables or disables overclocking which can reduce slowdowns in some games. Postrender method is more compatible with every game with Vblank more effective for games like Contra Force.",
{
{ "disabled", NULL },
{ "2x-Postrender", NULL },
{ "2x-VBlank", NULL },
{ NULL, NULL},
},
"disabled",
},
{
"fceumm_ramstate",
"RAM power up state (Restart)",
"Choose RAM startup during power up. Some games rely on initial ram values for random generator as an example.",
{
{ "fill $ff", NULL },
{ "fill $00", NULL },
{ "random", NULL },
{ NULL, NULL},
},
"fill $ff",
},
#ifdef DEBUG
{
"fceumm_apu_1",
"Channel 1 (Square 1)",
"Enables or disables pulse wave generator audio output 1.",
{
{ "enabled", NULL },
{ "disabled", NULL },
{ NULL, NULL},
},
"enabled",
},
{
"fceumm_apu_2",
"Channel 2 (Square 2)",
"Enables or disables pulse wave generator audio output 2.",
{
{ "enabled", NULL },
{ "disabled", NULL },
{ NULL, NULL},
},
"enabled",
},
{
"fceumm_apu_3",
"Channel 3 (Triangle)",
"Enables or disables triangle wave generator audio output.",
{
{ "enabled", NULL },
{ "disabled", NULL },
{ NULL, NULL},
},
"enabled",
},
{
"fceumm_apu_4",
"Channel 4 (Noise)",
"Enables or disables noise generator audio output.",
{
{ "enabled", NULL },
{ "disabled", NULL },
{ NULL, NULL},
},
"enabled",
},
{
"fceumm_apu_5",
"Channel 5 (PCM)",
"Enables or disables delta modulation channel audio output.",
{
{ "enabled", NULL },
{ "disabled", NULL },
{ NULL, NULL},
},
"enabled",
},
#endif
{ NULL, NULL, NULL, { NULL, NULL }, NULL },
};
struct retro_core_option_definition option_defs_empty = {
NULL, NULL, NULL, { NULL, NULL }, NULL
};
struct retro_core_option_definition option_defs_us[MAX_CORE_OPTIONS];
/* RETRO_LANGUAGE_JAPANESE */
/* RETRO_LANGUAGE_FRENCH */
/* RETRO_LANGUAGE_SPANISH */
/* RETRO_LANGUAGE_GERMAN */
/* RETRO_LANGUAGE_ITALIAN */
/* RETRO_LANGUAGE_DUTCH */
/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
/* RETRO_LANGUAGE_RUSSIAN */
/* RETRO_LANGUAGE_KOREAN */
/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
/* RETRO_LANGUAGE_ESPERANTO */
/* RETRO_LANGUAGE_POLISH */
/* RETRO_LANGUAGE_VIETNAMESE */
/* RETRO_LANGUAGE_ARABIC */
/* RETRO_LANGUAGE_GREEK */
/* RETRO_LANGUAGE_TURKISH */
/*
********************************
* Language Mapping
********************************
*/
struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
NULL, /* RETRO_LANGUAGE_JAPANESE */
NULL, /* RETRO_LANGUAGE_FRENCH */
NULL, /* RETRO_LANGUAGE_SPANISH */
NULL, /* RETRO_LANGUAGE_GERMAN */
NULL, /* RETRO_LANGUAGE_ITALIAN */
NULL, /* RETRO_LANGUAGE_DUTCH */
NULL, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
NULL, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
NULL, /* RETRO_LANGUAGE_RUSSIAN */
NULL, /* RETRO_LANGUAGE_KOREAN */
NULL, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
NULL, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
NULL, /* RETRO_LANGUAGE_ESPERANTO */
NULL, /* RETRO_LANGUAGE_POLISH */
NULL, /* RETRO_LANGUAGE_VIETNAMESE */
NULL, /* RETRO_LANGUAGE_ARABIC */
NULL, /* RETRO_LANGUAGE_GREEK */
NULL, /* RETRO_LANGUAGE_TURKISH */
};
/*
********************************
* Functions
********************************
*/
/* Handles configuration/setting of core options.
* Should only be called inside retro_set_environment().
* > We place the function body in the header to avoid the
* necessity of adding more .c files (i.e. want this to
* be as painless as possible for core devs)
*/
static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
{
unsigned version = 0;
if (!environ_cb)
return;
if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version == 1))
{
struct retro_core_options_intl core_options_intl;
unsigned language = 0;
core_options_intl.us = option_defs_us;
core_options_intl.local = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
(language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
core_options_intl.local = option_defs_intl[language];
environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
}
else
{
size_t i;
size_t option_index = 0;
size_t num_options = 0;
struct retro_variable *variables = NULL;
char **values_buf = NULL;
/* Determine number of options
* > Note: We are going to skip a number of irrelevant
* core options when building the retro_variable array,
* but we'll allocate space for all of them. The difference
* in resource usage is negligible, and this allows us to
* keep the code 'cleaner' */
while (true)
{
if (option_defs_us[num_options].key)
num_options++;
else
break;
}
/* Allocate arrays */
variables = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
values_buf = (char **)calloc(num_options, sizeof(char *));
if (!variables || !values_buf)
goto error;
/* Copy parameters from option_defs_us array */
for (i = 0; i < num_options; i++)
{
const char *key = option_defs_us[i].key;
const char *desc = option_defs_us[i].desc;
const char *default_value = option_defs_us[i].default_value;
struct retro_core_option_value *values = option_defs_us[i].values;
size_t buf_len = 3;
size_t default_index = 0;
values_buf[i] = NULL;
/* Skip options that are irrelevant when using the
* old style core options interface */
if ((strcmp(key, "fceumm_advance_sound_options") == 0))
continue;
if (desc)
{
size_t num_values = 0;
/* Determine number of values */
while (true)
{
if (values[num_values].value)
{
/* Check if this is the default value */
if (default_value)
if (strcmp(values[num_values].value, default_value) == 0)
default_index = num_values;
buf_len += strlen(values[num_values].value);
num_values++;
}
else
break;
}
/* Build values string */
if (num_values > 1)
{
size_t j;
buf_len += num_values - 1;
buf_len += strlen(desc);
values_buf[i] = (char *)calloc(buf_len, sizeof(char));
if (!values_buf[i])
goto error;
strcpy(values_buf[i], desc);
strcat(values_buf[i], "; ");
/* Default value goes first */
strcat(values_buf[i], values[default_index].value);
/* Add remaining values */
for (j = 0; j < num_values; j++)
{
if (j != default_index)
{
strcat(values_buf[i], "|");
strcat(values_buf[i], values[j].value);
}
}
}
}
variables[option_index].key = key;
variables[option_index].value = values_buf[i];
option_index++;
}
/* Set variables */
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
error:
/* Clean up */
if (values_buf)
{
for (i = 0; i < num_options; i++)
{
if (values_buf[i])
{
free(values_buf[i]);
values_buf[i] = NULL;
}
}
free(values_buf);
values_buf = NULL;
}
if (variables)
{
free(variables);
variables = NULL;
}
}
}
#ifdef __cplusplus
}
#endif
#endif