CSE2-tweaks/src/Pause.cpp

2404 lines
69 KiB
C++

#include "Pause.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "WindowsWrapper.h"
#include "Back.h"
#include "Backends/Controller.h"
#include "Backends/Misc.h"
#include "CommonDefines.h"
#include "Config.h"
#include "Bitmap.h"
#include "Boss.h"
#include "Draw.h"
#include "Escape.h"
#include "Flash.h"
#include "Game.h"
#include "Generic.h"
#include "KeyControl.h"
#include "Main.h"
#include "Organya.h"
#include "Sound.h"
#include "Stage.h"
#include "NpcHit.h"
#include "MyChar.h"
#include "MycHit.h"
#include "Shoot.h"
#include "ArmsItem.h"
#include "Frame.h"
#include "GenericLoad.h"
#define MAX_OPTIONS ((WINDOW_HEIGHT / 20) - 4) // The maximum number of options we can fit on-screen at once
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
enum
{
CALLBACK_CONTINUE = -1,
CALLBACK_PREVIOUS_MENU = -2,
CALLBACK_RESET = -3,
CALLBACK_EXIT = -4,
};
typedef enum CallbackAction
{
ACTION_INIT,
ACTION_DEINIT,
ACTION_UPDATE,
ACTION_OK,
ACTION_LEFT,
ACTION_RIGHT
} CallbackAction;
typedef struct Option
{
const char *name;
int (*callback)(struct OptionsMenu *parent_menu, size_t this_option, CallbackAction action);
void *user_data;
const char *value_string;
long value;
BOOL disabled;
long attribute_size;
long attribute_index;
} Option;
typedef struct OptionsMenu
{
const char *title;
const char *subtitle;
struct Option *options;
size_t total_options;
int x_offset;
BOOL submenu;
} OptionsMenu;
static BOOL restart_required;
static BOOL tweaks_restart_required;
static const RECT rcMyChar[4] = {
{0, 16, 16, 32},
{16, 16, 32, 32},
{0, 16, 16, 32},
{32, 16, 48, 32},
};
unsigned int bMode;
static const char* GetKeyName(int key)
{
switch (key)
{
case BACKEND_KEYBOARD_A:
return "A";
case BACKEND_KEYBOARD_B:
return "B";
case BACKEND_KEYBOARD_C:
return "C";
case BACKEND_KEYBOARD_D:
return "D";
case BACKEND_KEYBOARD_E:
return "E";
case BACKEND_KEYBOARD_F:
return "F";
case BACKEND_KEYBOARD_G:
return "G";
case BACKEND_KEYBOARD_H:
return "H";
case BACKEND_KEYBOARD_I:
return "I";
case BACKEND_KEYBOARD_J:
return "J";
case BACKEND_KEYBOARD_K:
return "K";
case BACKEND_KEYBOARD_L:
return "L";
case BACKEND_KEYBOARD_M:
return "M";
case BACKEND_KEYBOARD_N:
return "N";
case BACKEND_KEYBOARD_O:
return "O";
case BACKEND_KEYBOARD_P:
return "P";
case BACKEND_KEYBOARD_Q:
return "Q";
case BACKEND_KEYBOARD_R:
return "R";
case BACKEND_KEYBOARD_S:
return "S";
case BACKEND_KEYBOARD_T:
return "T";
case BACKEND_KEYBOARD_U:
return "U";
case BACKEND_KEYBOARD_V:
return "V";
case BACKEND_KEYBOARD_W:
return "W";
case BACKEND_KEYBOARD_X:
return "X";
case BACKEND_KEYBOARD_Y:
return "Y";
case BACKEND_KEYBOARD_Z:
return "Z";
case BACKEND_KEYBOARD_0:
return "0";
case BACKEND_KEYBOARD_1:
return "1";
case BACKEND_KEYBOARD_2:
return "2";
case BACKEND_KEYBOARD_3:
return "3";
case BACKEND_KEYBOARD_4:
return "4";
case BACKEND_KEYBOARD_5:
return "5";
case BACKEND_KEYBOARD_6:
return "6";
case BACKEND_KEYBOARD_7:
return "7";
case BACKEND_KEYBOARD_8:
return "8";
case BACKEND_KEYBOARD_9:
return "9";
case BACKEND_KEYBOARD_F1:
return "F1";
case BACKEND_KEYBOARD_F2:
return "F2";
case BACKEND_KEYBOARD_F3:
return "F3";
case BACKEND_KEYBOARD_F4:
return "F4";
case BACKEND_KEYBOARD_F5:
return "F5";
case BACKEND_KEYBOARD_F6:
return "F6";
case BACKEND_KEYBOARD_F7:
return "F7";
case BACKEND_KEYBOARD_F8:
return "F8";
case BACKEND_KEYBOARD_F9:
return "F9";
case BACKEND_KEYBOARD_F10:
return "F10";
case BACKEND_KEYBOARD_F11:
return "F11";
case BACKEND_KEYBOARD_F12:
return "F12";
case BACKEND_KEYBOARD_UP:
return "Up";
case BACKEND_KEYBOARD_DOWN:
return "Down";
case BACKEND_KEYBOARD_LEFT:
return "Left";
case BACKEND_KEYBOARD_RIGHT:
return "Right";
case BACKEND_KEYBOARD_ESCAPE:
return "Escape";
case BACKEND_KEYBOARD_BACK_QUOTE:
return "`";
case BACKEND_KEYBOARD_TAB:
return "Tab";
case BACKEND_KEYBOARD_CAPS_LOCK:
return "Caps Lock";
case BACKEND_KEYBOARD_LEFT_SHIFT:
return "Left Shift";
case BACKEND_KEYBOARD_LEFT_CTRL:
return "Left Ctrl";
case BACKEND_KEYBOARD_LEFT_ALT:
return "Left Alt";
case BACKEND_KEYBOARD_SPACE:
return "Space";
case BACKEND_KEYBOARD_RIGHT_ALT:
return "Right Alt";
case BACKEND_KEYBOARD_RIGHT_CTRL:
return "Right Ctrl";
case BACKEND_KEYBOARD_RIGHT_SHIFT:
return "Right Shift";
case BACKEND_KEYBOARD_ENTER:
return "Enter";
case BACKEND_KEYBOARD_BACKSPACE:
return "Backspace";
case BACKEND_KEYBOARD_MINUS:
return "-";
case BACKEND_KEYBOARD_EQUALS:
return "=";
case BACKEND_KEYBOARD_LEFT_BRACKET:
return "[";
case BACKEND_KEYBOARD_RIGHT_BRACKET:
return "]";
case BACKEND_KEYBOARD_BACK_SLASH:
return "\\";
case BACKEND_KEYBOARD_SEMICOLON:
return ";";
case BACKEND_KEYBOARD_APOSTROPHE:
return "'";
case BACKEND_KEYBOARD_COMMA:
return ",";
case BACKEND_KEYBOARD_PERIOD:
return ".";
case BACKEND_KEYBOARD_FORWARD_SLASH:
return "/";
}
return "Unknown";
}
static void PutTextCentred(int x, int y, const char *text, unsigned long color)
{
size_t string_width = 0;
size_t string_height = font_height;
for (const char *text_pointer = text; *text_pointer != '\0';)
{
if (IsShiftJIS(*text_pointer))
{
text_pointer += 2;
string_width += font_width * 2;
}
else
{
text_pointer += 1;
string_width += font_width/2;
}
}
PutText(x - string_width / 2, y - string_height / 2, text, color);
}
static void PutTitleTextCentered(int x, int y, const char *text, unsigned long color)
{
size_t string_width = 0;
size_t string_height = title_height;
for (const char *text_pointer = text; *text_pointer != '\0';)
{
if (IsShiftJIS(*text_pointer))
{
text_pointer += 2;
string_width += font_width * 2;
}
else
{
text_pointer += 1;
string_width += font_width;
}
}
PutTitleText(x - string_width / 2, y - string_height / 2, text, color);
}
static int EnterOptionsMenu(OptionsMenu *options_menu, size_t selected_option)
{
int scroll = 0;
int frame_x;
int frame_y;
unsigned int anime = 0;
int return_value;
// Initialise options
for (size_t i = 0; i < options_menu->total_options; ++i)
options_menu->options[i].callback(options_menu, i, ACTION_INIT);
RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
for (;;)
{
// Get pressed keys
GetTrg();
// Allow unpausing by pressing the pause button only when in the main pause menu (not submenus)
if (!options_menu->submenu && gKeyTrg & KEY_PAUSE)
{
return_value = CALLBACK_CONTINUE;
break;
}
// Go back one submenu when the 'cancel' button is pressed
if (gKeyTrg & gKeyCancel)
{
return_value = CALLBACK_CONTINUE;
break;
}
// Handling up/down input
if (gKeyTrg & (gKeyUp | gKeyDown))
{
const size_t old_selection = selected_option;
if (gKeyTrg & gKeyDown)
if (selected_option++ == options_menu->total_options - 1)
selected_option = 0;
if (gKeyTrg & gKeyUp)
if (selected_option-- == 0)
selected_option = options_menu->total_options - 1;
// Update the menu-scrolling, if there are more options than can be fit on the screen
if (selected_option < old_selection)
scroll = MAX(0, MIN(scroll, (int)selected_option - 1));
if (selected_option > old_selection)
scroll = MIN(MAX(0, (int)options_menu->total_options - MAX_OPTIONS), MAX(scroll, (int)selected_option - (MAX_OPTIONS - 2)));
PlaySoundObject(SND_SWITCH_WEAPON, SOUND_MODE_PLAY);
}
// Run option callbacks
for (size_t i = 0; i < options_menu->total_options; ++i)
{
if (!options_menu->options[i].disabled)
{
CallbackAction action = ACTION_UPDATE;
if (i == selected_option)
{
if (gKeyTrg & gKeyOk)
action = ACTION_OK;
else if (gKeyTrg & gKeyLeft)
action = ACTION_LEFT;
else if (gKeyTrg & gKeyRight)
action = ACTION_RIGHT;
}
return_value = options_menu->options[i].callback(options_menu, i, action);
// If the callback returned something other than CALLBACK_CONTINUE, it's time to exit this submenu
if (return_value != CALLBACK_CONTINUE)
break;
}
}
if (return_value != CALLBACK_CONTINUE)
break;
// Update Quote animation counter
if (++anime >= 80)
anime = 0;
// Draw screen
if (bMode == 1) { // Action Mode
PutBitmap3(&rcView, 0, 0, &pauseView, SURFACE_ID_SCREEN_GRAB);
PutBitmap3(&rcView, 0, 0, &pauseView, SURFACE_ID_MENU_OVERLAY);
}
else if (bMode == 2){
CortBox(&rcView,0x202020);
}
else{
if(anime % 2 == 0)
ActBack();
GetFramePosition(&frame_x, &frame_y);
PutBack(frame_x, frame_y);
PutBitmap3(&rcView, 0, 0, &pauseView, SURFACE_ID_MENU_OVERLAY);
}
const size_t visible_options = MIN(MAX_OPTIONS, options_menu->total_options);
int y = (WINDOW_HEIGHT / 2) - ((visible_options * 20) / 2) - (40 / 2);
// Draw title
PutTitleTextCentered(WINDOW_WIDTH / 2, y, options_menu->title, RGB(0x73, 0x73, 0x73));
// Draw subtitle
if (options_menu->subtitle != NULL)
PutTextCentred(WINDOW_WIDTH / 2, y + 14, options_menu->subtitle, RGB(0xFF, 0xFF, 0xFF));
y += 40;
RECT top_arrow_view = {181,124,195,138};
RECT bottom_arrow_view = {196,124,210,138};
if(scroll != 0){
PutBitmap3(&rcView, PixelToScreenCoord((WINDOW_WIDTH / 2) + options_menu->x_offset - 19), PixelToScreenCoord( (WINDOW_HEIGHT / 2) + (10 * 1) - (((visible_options - 1) * 20) / 2) - 22 - abs(static_cast<int>(anime / 20 % 4 - 1))), &top_arrow_view, SURFACE_ID_CARET);
}
if(scroll + visible_options < options_menu->total_options && options_menu->total_options > MAX_OPTIONS){
PutBitmap3(&rcView, PixelToScreenCoord((WINDOW_WIDTH / 2) + options_menu->x_offset - 19), PixelToScreenCoord((WINDOW_HEIGHT / 2) + (10 * 1) - (((visible_options - 1) * 20) / 2) + 133 + abs(static_cast<int>(anime / 20 % 4 - 1))), &bottom_arrow_view, SURFACE_ID_CARET);
}
for (size_t i = scroll; i < scroll + visible_options; ++i)
{
const int x = (WINDOW_WIDTH / 2) + options_menu->x_offset;
const int y = (WINDOW_HEIGHT / 2) + (10 * 1) - (((visible_options - 1) * 20) / 2) + ((i - scroll) * 20) - 10;
// Draw Quote next to the selected option
if (i == selected_option)
PutBitmap3(&rcView, PixelToScreenCoord(x - 20), PixelToScreenCoord(y - 6), &rcMyChar[anime / 10 % 4], SURFACE_ID_MY_CHAR);
unsigned long option_colour = options_menu->options[i].disabled ? RGB(0x80, 0x80, 0x80) : (i == selected_option? RGB(0xF5, 0xFE, 0x56): RGB(0xF7, 0xF7, 0xEA));
// Draw option name
PutText(x, y - font_height / 2, options_menu->options[i].name, option_colour);
// Draw option value, if it has one
if (options_menu->options[i].value_string != NULL){
const char* attribute_format = "%s %s %s";
const char* left_move_arrow = options_menu->options[i].attribute_index > 0 ? "<" : " ";
const char* right_move_arrow = options_menu->options[i].attribute_index < options_menu->options[i].attribute_size -1? ">" : " ";
char attribute_str[80] = { };
sprintf(attribute_str, attribute_format, left_move_arrow, options_menu->options[i].value_string, right_move_arrow);
PutText(x + 130, y - (font_height / 2), attribute_str, option_colour);
}
}
PutFramePerSecound();
if (!Flip_SystemTask())
{
// Quit if window is closed
return_value = CALLBACK_EXIT;
break;
}
}
// Deinitialise options
for (size_t i = 0; i < options_menu->total_options; ++i)
options_menu->options[i].callback(options_menu, i, ACTION_DEINIT);
return return_value;
}
///////////////////
// Controls menu //
///////////////////
typedef struct Control
{
const char *name;
size_t binding_index;
unsigned char groups;
} Control;
// The bitfield on the right determines which 'group' the
// control belongs to - if two controls are in the same group,
// they cannot be bound to the same key.
static const Control controls[] = {
{menu_strings_table[CONTROLS_UP], BINDING_UP, (1 << 0) | (1 << 1)},
{menu_strings_table[CONTROLS_DOWN], BINDING_DOWN, (1 << 0) | (1 << 1)},
{menu_strings_table[CONTROLS_LEFT], BINDING_LEFT, (1 << 0) | (1 << 1)},
{menu_strings_table[CONTROLS_RIGHT], BINDING_RIGHT, (1 << 0) | (1 << 1)},
{menu_strings_table[CONTROLS_OK], BINDING_OK, 1 << 1},
{menu_strings_table[CONTROLS_CANCEL], BINDING_CANCEL, 1 << 1},
{menu_strings_table[CONTROLS_JUMP], BINDING_JUMP, 1 << 0},
{menu_strings_table[CONTROLS_SHOOT], BINDING_SHOT, 1 << 0},
{menu_strings_table[CONTROLS_NEXT_WEAPON], BINDING_ARMS, 1 << 0},
{menu_strings_table[CONTROLS_PREV_WEAPON], BINDING_ARMSREV, 1 << 0},
{menu_strings_table[CONTROLS_INVENTORY], BINDING_ITEM, 1 << 0},
{menu_strings_table[CONTROLS_MAP], BINDING_MAP, 1 << 0},
{menu_strings_table[CONTROLS_PAUSE], BINDING_PAUSE, 1 << 0},
{menu_strings_table[CONTROLS_STRAFE], BINDING_STRAFE, 1 << 0}
};
static char bound_name_buffers[sizeof(controls) / sizeof(controls[0])][20];
static int Callback_ControlsKeyboard_Rebind(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
switch (action)
{
default:
break;
case ACTION_INIT:
strncpy(bound_name_buffers[this_option], GetKeyName(bindings[controls[this_option].binding_index].keyboard), sizeof(bound_name_buffers[0]) - 1);
break;
case ACTION_OK:
PlaySoundObject(5, SOUND_MODE_PLAY);
char timeout_string[2];
timeout_string[1] = '\0';
bool previous_keyboard_state[BACKEND_KEYBOARD_TOTAL];
memcpy(previous_keyboard_state, gKeyboardState, sizeof(gKeyboardState));
// Time-out and exit if the user takes too long (they probably don't want to rebind)
for (unsigned int timeout = (60 * 5) - 1; timeout != 0; --timeout)
{
for (int scancode = 0; scancode < BACKEND_KEYBOARD_TOTAL; ++scancode)
{
// Wait for user to press a key
if (!previous_keyboard_state[scancode] && gKeyboardState[scancode])
{
const char *key_name = GetKeyName(scancode);
// If another control in the same group uses this key, swap them
for (size_t other_option = 0; other_option < parent_menu->total_options; ++other_option)
{
if (other_option != this_option && controls[other_option].groups & controls[this_option].groups && bindings[controls[other_option].binding_index].keyboard == scancode)
{
bindings[controls[other_option].binding_index].keyboard = bindings[controls[this_option].binding_index].keyboard;
memcpy(bound_name_buffers[other_option], bound_name_buffers[this_option], sizeof(bound_name_buffers[0]));
break;
}
}
// Otherwise just overwrite the selected control
bindings[controls[this_option].binding_index].keyboard = scancode;
strncpy(bound_name_buffers[this_option], key_name, sizeof(bound_name_buffers[0]) - 1);
PlaySoundObject(18, SOUND_MODE_PLAY);
gKeyTrg = gKey = 0; // Prevent weird input-ghosting by doing this
return CALLBACK_CONTINUE;
}
}
memcpy(previous_keyboard_state, gKeyboardState, sizeof(gKeyboardState));
// Draw screen
CortBox(&grcFull, 0x000000);
const char *string = menu_strings_table[CONTROLS_PUSH_KEY];
PutTextCentred((WINDOW_WIDTH / 2), (WINDOW_HEIGHT / 2) - 10, string, RGB(0xFF, 0xFF, 0xFF));
PutTextCentred((WINDOW_WIDTH / 2) , (WINDOW_HEIGHT / 2) + 10, parent_menu->options[this_option].name, RGB(0xFF, 0xFF, 0xFF));
timeout_string[0] = '0' + (timeout / 60) + 1;
PutTextCentred(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 + 60, timeout_string, RGB(0xFF, 0xFF, 0xFF));
PutFramePerSecound();
if (!Flip_SystemTask())
{
// Quit if window is closed
return CALLBACK_EXIT;
}
}
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_ControlsKeyboard(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
Option options[sizeof(controls) / sizeof(controls[0])];
for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i)
{
options[i].name = controls[i].name;
options[i].callback = Callback_ControlsKeyboard_Rebind;
options[i].value_string = bound_name_buffers[i];
options[i].disabled = FALSE;
options[i].attribute_index = -1;
options[i].attribute_size = 0;
strncpy(bound_name_buffers[i], GetKeyName(bindings[controls[i].binding_index].keyboard), sizeof(bound_name_buffers[0]) - 1);
}
OptionsMenu options_menu = {
menu_strings_table[CONTROLS_KEYBOARD_TITLE],
NULL,
options,
sizeof(options) / sizeof(options[0]),
-60,
TRUE
};
PlaySoundObject(5, SOUND_MODE_PLAY);
const int return_value = EnterOptionsMenu(&options_menu, 0);
PlaySoundObject(5, SOUND_MODE_PLAY);
return return_value;
}
static int Callback_ControlsController_Rebind(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
switch (action)
{
default:
break;
case ACTION_INIT:
// Name each bound button
if (bindings[controls[this_option].binding_index].controller == 0xFF)
strncpy(bound_name_buffers[this_option], menu_strings_table[CONTROLS_UNBOUND], sizeof(bound_name_buffers[0]));
else
strncpy(bound_name_buffers[this_option], ControllerBackend_GetButtonName(bindings[controls[this_option].binding_index].controller), sizeof(bound_name_buffers[0]));
break;
case ACTION_OK:
PlaySoundObject(5, SOUND_MODE_PLAY);
DIRECTINPUTSTATUS old_state = gJoystickState;
char timeout_string[2];
timeout_string[1] = '\0';
// Time-out and exit if the user takes too long (they probably don't want to rebind)
for (unsigned int timeout = (60 * 5) - 1; timeout != 0; --timeout)
{
for (int button = 0; button < sizeof(gJoystickState.bButton) / sizeof(gJoystickState.bButton[0]); ++button)
{
// Wait for user to press a button
if (!old_state.bButton[button] && gJoystickState.bButton[button])
{
// If another control in the same group uses this button, swap them
for (size_t other_option = 0; other_option < parent_menu->total_options; ++other_option)
{
if (other_option != this_option && controls[other_option].groups & controls[this_option].groups && bindings[controls[other_option].binding_index].controller == button)
{
bindings[controls[other_option].binding_index].controller = bindings[controls[this_option].binding_index].controller;
memcpy(bound_name_buffers[other_option], bound_name_buffers[this_option], sizeof(bound_name_buffers[0]));
break;
}
}
// Otherwise just overwrite the selected control
bindings[controls[this_option].binding_index].controller = button;
strncpy(bound_name_buffers[this_option], ControllerBackend_GetButtonName(button), sizeof(bound_name_buffers[0]));
PlaySoundObject(18, SOUND_MODE_PLAY);
gKeyTrg = gKey = 0; // Prevent weird input-ghosting by doing this
return CALLBACK_CONTINUE;
}
}
old_state = gJoystickState;
// Draw screen
CortBox(&grcFull, 0x000000);
const char *string = menu_strings_table[CONTROLS_PUSH_BUTTON];
PutTextCentred((WINDOW_WIDTH / 2) , (WINDOW_HEIGHT / 2) - 10, string, RGB(0xFF, 0xFF, 0xFF));
PutTextCentred((WINDOW_WIDTH / 2) , (WINDOW_HEIGHT / 2) + 10, parent_menu->options[this_option].name, RGB(0xFF, 0xFF, 0xFF));
timeout_string[0] = '0' + (timeout / 60) + 1;
PutTextCentred(WINDOW_WIDTH, WINDOW_HEIGHT / 2 + 60, timeout_string, RGB(0xFF, 0xFF, 0xFF));
PutFramePerSecound();
if (!Flip_SystemTask())
{
// Quit if window is closed
return CALLBACK_EXIT;
}
}
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_ControlsController(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
Option options[sizeof(controls) / sizeof(controls[0])];
for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i)
{
options[i].name = controls[i].name;
options[i].callback = Callback_ControlsController_Rebind;
options[i].value_string = bound_name_buffers[i];
options[i].disabled = FALSE;
options[i].attribute_index = -1;
options[i].attribute_size = 0;
}
OptionsMenu options_menu = {
#if !defined(__WIIU__) && !defined(_3DS)
menu_strings_table[CONTROLS_TITLE],
NULL,
#else
menu_strings_table[CONTROLS_GAMEPAD_TITLE],
ControllerBackend_GetControllerName(),
#endif
options,
sizeof(options) / sizeof(options[0]),
-70,
TRUE
};
PlaySoundObject(5, SOUND_MODE_PLAY);
const int return_value = EnterOptionsMenu(&options_menu, 0);
PlaySoundObject(18, SOUND_MODE_PLAY);
return return_value;
}
/////////////////////
// Soundtrack menu //
/////////////////////
static int Callback_Soundtrack_Option(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
switch (action)
{
default:
break;
case ACTION_INIT:
parent_menu->options[this_option].disabled = !CheckSoundtrackExists(this_option);
break;
case ACTION_OK:
conf->soundtrack = gSoundtrack = this_option;
// Restart the songs, with the new soundtrack setting
MusicID current_song = gMusicNo;
MusicID previous_song = gOldNo;
gMusicNo = gOldNo = MUS_SILENCE;
ChangeMusic(previous_song);
ChangeMusic(current_song);
return CALLBACK_PREVIOUS_MENU;
}
return CALLBACK_CONTINUE;
}
static int Callback_Soundtrack(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
const char *strings[] = {"Organya", "NES", "SNES", "Arranged", "New", "Remastered", "Famitracks", "Ridiculon"};
Option options[sizeof(strings) / sizeof(strings[0])];
for (size_t i = 0; i < sizeof(strings) / sizeof(strings[0]); ++i)
{
options[i].name = strings[i];
options[i].callback = Callback_Soundtrack_Option;
options[i].user_data = conf;
options[i].value_string = NULL;
}
OptionsMenu options_menu = {
menu_strings_table[SELECT_SOUNDTRACK],
"Check data/Soundtracks to obtain greyed-out soundtracks",
options,
sizeof(options) / sizeof(options[0]),
-30,
TRUE
};
PlaySoundObject(5, SOUND_MODE_PLAY);
int return_value = EnterOptionsMenu(&options_menu, conf->soundtrack);
// Check if we just want to go back to the previous menu
if (return_value == CALLBACK_PREVIOUS_MENU)
{
return_value = CALLBACK_CONTINUE;
PlaySoundObject(18, SOUND_MODE_PLAY);
}
else
{
PlaySoundObject(5, SOUND_MODE_PLAY);
}
return return_value;
}
//////////////////
// Options menu //
//////////////////
static int Callback_Framerate(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[FRAMERATE_50], menu_strings_table[FRAMERATE_60]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->b60fps;
parent_menu->options[this_option].value_string = strings[conf->b60fps];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->b60fps = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
gb60fps = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_Font(OptionsMenu *parent_menu, size_t this_option, CallbackAction action){
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {"OpenDyslexic", "Monogram", "Lekton", "Courier New"};
const FONT_DATA f_data[] = {
{"opendyslexic", 15, 15, 29, 30},
{"monogram", 13, 13, 26, 26},
{"lekton", 12, 12, 26, 26},
{"courier", 12, 12, 26, 26},
};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->font_select;
parent_menu->options[this_option].value_string = strings[conf->font_select];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->font_select = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
gbFontData = f_data[parent_menu->options[this_option].value];
#if !defined(_3DS)
InitTextObject("hi");
#else
parent_menu->subtitle = menu_strings_table[RESTART_REQUIRED];
#endif
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_Vsync(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bVsync;
parent_menu->options[this_option].value_string = strings[conf->bVsync];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bVsync = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
restart_required = TRUE;
parent_menu->subtitle = menu_strings_table[RESTART_REQUIRED];
// Increment value (with wrapping)
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_ScreenShake(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bScreenShake;
parent_menu->options[this_option].value_string = strings[conf->bScreenShake];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bScreenShake = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
gbScreenShake = parent_menu->options[this_option].value;
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_Resolution(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {
menu_strings_table[RESOLUTION_FULL],
menu_strings_table[RESOLUTION_240],
menu_strings_table[RESOLUTION_480],
menu_strings_table[RESOLUTION_720],
menu_strings_table[RESOLUTION_960]
};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->display_mode;
parent_menu->options[this_option].value_string = strings[conf->display_mode];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->display_mode = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
restart_required = TRUE;
parent_menu->subtitle = menu_strings_table[RESTART_REQUIRED];
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_SmoothScrolling(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bSmoothScrolling;
parent_menu->options[this_option].value_string = strings[conf->bSmoothScrolling];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bSmoothScrolling = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
gbSmoothScrolling = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_ColorFilters(OptionsMenu *parent_menu, size_t this_option, CallbackAction action){
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {
menu_strings_table[COLOR_NONE],
menu_strings_table[COLOR_PROTANOMALY],
menu_strings_table[COLOR_PROTANOPIA],
menu_strings_table[COLOR_DEUTERANOMALY],
menu_strings_table[COLOR_DEUTERANOPIA],
menu_strings_table[COLOR_TRITANOMALY],
menu_strings_table[COLOR_TRITANOPIA],
menu_strings_table[COLOR_GRAYSCALE],
menu_strings_table[COLOR_GENESIS],
menu_strings_table[COLOR_MSX],
menu_strings_table[COLOR_GAME_BOY]
};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->color_filter;
parent_menu->options[this_option].value_string = strings[conf->color_filter];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->color_filter = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
gFilterIndex = parent_menu->options[this_option].value;
ReloadAll();
if (bMode == 1){
Reload_CurrentStageTiles();
}
else if (bMode == 0){
Reload_MenuBackground();
}
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_FlashMode(OptionsMenu *parent_menu, size_t this_option, CallbackAction action){
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {
menu_strings_table[PERCENT_100],
menu_strings_table[PERCENT_50],
menu_strings_table[PERCENT_0]
};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->flash_mode;
parent_menu->options[this_option].value_string = strings[conf->flash_mode];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->flash_mode = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
gFlashMode = parent_menu->options[this_option].value;
InitFlash();
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_ExtendedUI(OptionsMenu *parent_menu, size_t this_option, CallbackAction action){
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bExtendedUI;
parent_menu->options[this_option].value_string = strings[conf->bExtendedUI];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bExtendedUI = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
gExtendedUI = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_EnableController(OptionsMenu *parent_menu, size_t this_option, CallbackAction action){
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bUseJoystick;
parent_menu->options[this_option].value_string = strings[conf->bUseJoystick];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bUseJoystick = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
gbUseJoystick = parent_menu->options[this_option].value;
parent_menu->options[this_option + 1].disabled = !gbUseJoystick;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_BackgroundBrightness(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {"100%", "75%", "50%", "25%"};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->backgroundBrightness;
parent_menu->options[this_option].value_string = strings[conf->backgroundBrightness];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->backgroundBrightness = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
gDimmingFactor = (4.0 - parent_menu->options[this_option].value)/6;
ReloadAll();
if (bMode == 1){
Reload_CurrentStageTiles();
}
else if (bMode == 0){
Reload_MenuBackground();
}
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_Graphics(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {"Original", "Upscaled"};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->graphics_set;
parent_menu->options[this_option].value_string = strings[conf->graphics_set];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->graphics_set = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
gSpriteScale = 1 + parent_menu->options[this_option].value;
gSpritePath = gDataPath + (gSpriteScale == 2? "/sprites_up": "/sprites_og");
ReloadAll();
if (bMode == 1){
Reload_CurrentStageTiles();
}
else if (bMode == 0){
Reload_MenuBackground();
}
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_Options(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
// Make the options match the configuration data
CONFIGDATA conf;
if (!LoadConfigData(&conf))
DefaultConfigData(&conf);
#if !defined(__WIIU__) && !defined(_3DS)
Option options[] = {
{menu_strings_table[CONTROLS_KEYBOARD], Callback_ControlsKeyboard, NULL, NULL, 0, FALSE},
{menu_strings_table[CONTROLS_ENABLE_GAMEPAD], Callback_EnableController, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[CONTROLS_GAMEPAD], Callback_ControlsController, NULL, NULL, 0, !gbUseJoystick, 0, 0},
{menu_strings_table[SOUNDTRACK], Callback_Soundtrack, &conf, NULL, 0, FALSE},
{menu_strings_table[FRAMERATE], Callback_Framerate, &conf, NULL, 0, FALSE},
{menu_strings_table[V_SYNC], Callback_Vsync, &conf, NULL, 0, FALSE},
{menu_strings_table[RESOLUTION], Callback_Resolution, &conf, NULL, 0, FALSE},
{menu_strings_table[SMOOTH_SCROLLING], Callback_SmoothScrolling, &conf, NULL, 0, FALSE},
{menu_strings_table[SCREEN_SHAKE], Callback_ScreenShake, &conf, NULL, 0, FALSE, 0, 0},
#if GAMELANG != JP
{"Font", Callback_Font, &conf, NULL, 0, FALSE, 0, 0},
#endif
{menu_strings_table[COLOR_FILTERS], Callback_ColorFilters, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[SCREEN_FLASHING], Callback_FlashMode, &conf, NULL, 0, FALSE, 0, 0},
{"Background Brightness", Callback_BackgroundBrightness, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[EXTENDED_UI], Callback_ExtendedUI, &conf, NULL, 0, FALSE, 0, 0}
};
#else
Option options[] = {
{menu_strings_table[CONTROLS], Callback_ControlsController, NULL, NULL, 0, FALSE},
{menu_strings_table[SOUNDTRACK], Callback_Soundtrack, &conf, NULL, 0, FALSE},
{menu_strings_table[FRAMERATE], Callback_Framerate, &conf, NULL, 0, FALSE},
{menu_strings_table[SMOOTH_SCROLLING], Callback_SmoothScrolling, &conf, NULL, 0, FALSE},
{menu_strings_table[SCREEN_SHAKE], Callback_ScreenShake, &conf, NULL, 0, FALSE, 0, 0},
#if GAMELANG != JP
{"Font", Callback_Font, &conf, NULL, 0, FALSE, 0, 0},
#endif
{menu_strings_table[COLOR_FILTERS], Callback_ColorFilters, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[SCREEN_FLASHING], Callback_FlashMode, &conf, NULL, 0, FALSE, 0, 0},
{"Background Brightness", Callback_BackgroundBrightness, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[EXTENDED_UI], Callback_ExtendedUI, &conf, NULL, 0, FALSE, 0, 0}
};
#endif
OptionsMenu options_menu = {
menu_strings_table[OPTIONS_TITLE],
restart_required ? menu_strings_table[RESTART_REQUIRED] : NULL,
options,
(sizeof(options) / sizeof(options[0])),
-130,
TRUE
};
PlaySoundObject(5, SOUND_MODE_PLAY);
const int return_value = EnterOptionsMenu(&options_menu, 0);
PlaySoundObject(18, SOUND_MODE_PLAY);
// Save our changes to the configuration file
memcpy(conf.bindings, bindings, sizeof(bindings));
SaveConfigData(&conf);
return return_value;
}
/////////////////
// Tweaks Menu //
/////////////////
static int Callback_NoExpDrops(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bNoExpDrops;
parent_menu->options[this_option].value_string = strings[conf->bNoExpDrops];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bNoExpDrops = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
gbNoExpDrops = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_DamageModifier(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {
menu_strings_table[PERCENT_100],
menu_strings_table[PERCENT_200],
menu_strings_table[DAMAGE_OHKO],
menu_strings_table[PERCENT_0],
menu_strings_table[PERCENT_50]
};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->damage_modifier;
parent_menu->options[this_option].value_string = strings[conf->damage_modifier];
parent_menu->options[this_option].attribute_index = (parent_menu->options[this_option].value +2) % 5;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->damage_modifier = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
switch(parent_menu->options[this_option].value){
case 0:
gbDamageModifier = 1;
break;
case 1:
gbDamageModifier = 2;
break;
case 2:
gbDamageModifier = -1;
break;
case 3:
gbDamageModifier = 0;
break;
case 4:
gbDamageModifier = 0.5;
break;
}
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = (parent_menu->options[this_option].value +2) % 5;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_AutoFire(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {
menu_strings_table[OFF],
menu_strings_table[AUTOFIRE_HOLD],
menu_strings_table[AUTOFIRE_SWITCH]
};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->autoFire;
parent_menu->options[this_option].value_string = strings[conf->autoFire];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->autoFire = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
gbAutoFire = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_InfiniteAmmo(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bInfiniteAmmo;
parent_menu->options[this_option].value_string = strings[conf->bInfiniteAmmo];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bInfiniteAmmo = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
gbInfiniteAmmo = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_DefaultBooster(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {
menu_strings_table[DEFAULT_BOOSTER_NONE],
menu_strings_table[DEFAULT_BOOSTER_08],
menu_strings_table[DEFAULT_BOOSTER_20]
};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->defaultBooster;
parent_menu->options[this_option].value_string = strings[conf->defaultBooster];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->defaultBooster = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
gDefaultBooster = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_InfiniteBooster(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bInfiniteBooster;
parent_menu->options[this_option].value_string = strings[conf->bInfiniteBooster];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bInfiniteBooster = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
gbInfiniteBoost = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_GraceJump(OptionsMenu *parent_menu, size_t this_option, CallbackAction action){
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {menu_strings_table[OFF], menu_strings_table[ON]};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->bGraceJumps;
parent_menu->options[this_option].value_string = strings[conf->bGraceJumps];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->bGraceJumps = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
parent_menu->options[this_option].value = (parent_menu->options[this_option].value + 1) % (sizeof(strings) / sizeof(strings[0]));
gbGraceJump = parent_menu->options[this_option].value;
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_GameSpeed(OptionsMenu *parent_menu, size_t this_option, CallbackAction action){
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {
menu_strings_table[PERCENT_50],
menu_strings_table[PERCENT_60],
menu_strings_table[PERCENT_70],
menu_strings_table[PERCENT_80],
menu_strings_table[PERCENT_90],
menu_strings_table[PERCENT_100],
menu_strings_table[PERCENT_110],
menu_strings_table[PERCENT_120],
menu_strings_table[PERCENT_130],
menu_strings_table[PERCENT_140],
menu_strings_table[PERCENT_150],
};
const double values[] = {0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->game_speed_multiplier;
parent_menu->options[this_option].value_string = strings[conf->game_speed_multiplier];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->game_speed_multiplier = parent_menu->options[this_option].value;
gCounter = gCorrectedCounter = 0;
gSpeedMultiplier = values[parent_menu->options[this_option].value];
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
// Increment value (with wrapping)
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = parent_menu->options[this_option].value;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_BossHealthModifier(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
CONFIGDATA *conf = (CONFIGDATA*)parent_menu->options[this_option].user_data;
const char *strings[] = {
menu_strings_table[PERCENT_100],
menu_strings_table[PERCENT_150],
menu_strings_table[PERCENT_200],
menu_strings_table[BOSS_1_HP],
menu_strings_table[PERCENT_50],
};
switch (action)
{
case ACTION_INIT:
parent_menu->options[this_option].value = conf->boss_health_multiplier;
parent_menu->options[this_option].value_string = strings[conf->boss_health_multiplier];
parent_menu->options[this_option].attribute_index = (parent_menu->options[this_option].value + 2) % 5;
parent_menu->options[this_option].attribute_size = sizeof(strings)/sizeof(strings[0]);
break;
case ACTION_DEINIT:
conf->boss_health_multiplier = parent_menu->options[this_option].value;
break;
case ACTION_OK:
case ACTION_LEFT:
case ACTION_RIGHT:
if (action == ACTION_LEFT)
{
// Decrement value (with wrapping)
if (--parent_menu->options[this_option].value < 0)
parent_menu->options[this_option].value = (sizeof(strings) / sizeof(strings[0])) - 1;
}
else
{
// Increment value (with wrapping)
if (++parent_menu->options[this_option].value > (sizeof(strings) / sizeof(strings[0])) - 1)
parent_menu->options[this_option].value = 0;
}
switch(parent_menu->options[this_option].value){
case 0:
gBossHPMultiplier = 1;
break;
case 1:
gBossHPMultiplier = 1.5;
break;
case 2:
gBossHPMultiplier = 2;
break;
case 3:
gBossHPMultiplier = -1;
break;
case 4:
gBossHPMultiplier = 0.5;
break;
}
PlaySoundObject(SND_YES_NO_CHANGE_CHOICE, SOUND_MODE_PLAY);
parent_menu->options[this_option].value_string = strings[parent_menu->options[this_option].value];
parent_menu->options[this_option].attribute_index = (parent_menu->options[this_option].value + 2) % 5;
break;
case ACTION_UPDATE:
break;
}
return CALLBACK_CONTINUE;
}
static int Callback_Tweaks(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
// Make the options match the configuration data
CONFIGDATA conf;
if (!LoadConfigData(&conf))
DefaultConfigData(&conf);
Option submenu_options[] = {
{menu_strings_table[DAMAGE_RECEIVED], Callback_DamageModifier, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[BOSS_HP], Callback_BossHealthModifier, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[AUTOFIRE], Callback_AutoFire, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[INFINITE_AMMO], Callback_InfiniteAmmo, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[DEFAULT_BOOSTER], Callback_DefaultBooster, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[INFINITE_BOOSTER], Callback_InfiniteBooster, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[GRACE_JUMPS], Callback_GraceJump, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[NO_EXPERIENCE_DROPS], Callback_NoExpDrops, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[GAME_SPEED], Callback_GameSpeed, &conf, NULL, 0, FALSE, 0, 0}
};
OptionsMenu options_menu = {
menu_strings_table[TWEAKS_TITLE],
tweaks_restart_required ? menu_strings_table[RESTART_REQUIRED] : NULL,
submenu_options,
(sizeof(submenu_options) / sizeof(submenu_options[0])),
-130,
TRUE
};
PlaySoundObject(5, SOUND_MODE_PLAY);
const int return_value = EnterOptionsMenu(&options_menu, 0);
PlaySoundObject(18, SOUND_MODE_PLAY);
// Save our changes to the configuration file
memcpy(conf.bindings, bindings, sizeof(bindings));
SaveConfigData(&conf);
return return_value;
}
////////////////
// Pause menu //
////////////////
static int PromptAreYouSure(void)
{
struct FunctionHolder
{
static int Callback_Yes(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
(void)this_option;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
return 1; // Yes
}
static int Callback_No(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
(void)this_option;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
return 0; // No
}
};
Option options[] = {
{menu_strings_table[YES], FunctionHolder::Callback_Yes, NULL, NULL, 0, FALSE},
{menu_strings_table[NO], FunctionHolder::Callback_No, NULL, NULL, 0, FALSE}
};
OptionsMenu options_menu = {
menu_strings_table[ARE_YOU_SURE],
menu_strings_table[UNSAVED_PROGRESS],
options,
sizeof(options) / sizeof(options[0]),
-10,
TRUE
};
PlaySoundObject(5, SOUND_MODE_PLAY);
int return_value = EnterOptionsMenu(&options_menu, 1);
PlaySoundObject(18, SOUND_MODE_PLAY);
return return_value;
}
static int Callback_Resume(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
PlaySoundObject(18, SOUND_MODE_PLAY);
return enum_ESCRETURN_continue;
}
static int Callback_Reset(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
int return_value = PromptAreYouSure();
switch (return_value)
{
case 0:
return_value = CALLBACK_CONTINUE; // Go back to previous menu
break;
case 1:
return_value = CALLBACK_RESET; // Restart game
break;
}
return return_value;
}
static int Callback_Quit(OptionsMenu *parent_menu, size_t this_option, CallbackAction action)
{
(void)parent_menu;
if (action != ACTION_OK)
return CALLBACK_CONTINUE;
int return_value = PromptAreYouSure();
switch (return_value)
{
case 0:
return_value = CALLBACK_CONTINUE; // Go back to previous menu
break;
case 1:
return_value = CALLBACK_EXIT; // Exit game
break;
}
return return_value;
}
int Call_Pause(unsigned int mode_action)
{
Option options[] = {
{menu_strings_table[RESUME], Callback_Resume, NULL, NULL, 0, FALSE},
{menu_strings_table[RESET], Callback_Reset, NULL, NULL, 0, FALSE},
{menu_strings_table[OPTIONS], Callback_Options, NULL, NULL, 0, FALSE},
{menu_strings_table[TWEAKS], Callback_Tweaks, NULL, NULL, 0, FALSE},
{menu_strings_table[QUIT], Callback_Quit, NULL, NULL, 0, FALSE}
};
OptionsMenu options_menu = {
menu_strings_table[PAUSED],
NULL,
options,
sizeof(options) / sizeof(options[0]),
-24,
FALSE
};
bMode = mode_action;
int return_value = EnterOptionsMenu(&options_menu, 0);
// Filter internal return values to something Cave Story can understand
switch (return_value)
{
case CALLBACK_CONTINUE:
return_value = enum_ESCRETURN_continue;
break;
case CALLBACK_RESET:
return_value = enum_ESCRETURN_restart;
break;
case CALLBACK_EXIT:
return_value = enum_ESCRETURN_exit;
break;
}
gKeyTrg = gKey = 0; // Avoid input-ghosting
return return_value;
}
int Call_Options(unsigned int mode_action)
{
// Make the options match the configuration data
CONFIGDATA conf;
if (!LoadConfigData(&conf))
DefaultConfigData(&conf);
#if !defined(__WIIU__) && !defined(_3DS)
Option options[] = {
{menu_strings_table[CONTROLS_KEYBOARD], Callback_ControlsKeyboard, NULL, NULL, 0, FALSE, 0, 0},
{menu_strings_table[CONTROLS_ENABLE_GAMEPAD], Callback_EnableController, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[CONTROLS_GAMEPAD], Callback_ControlsController, NULL, NULL, 0, !gbUseJoystick, 0, 0},
{menu_strings_table[SOUNDTRACK], Callback_Soundtrack, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[FRAMERATE], Callback_Framerate, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[V_SYNC], Callback_Vsync, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[RESOLUTION], Callback_Resolution, &conf, NULL, 0, FALSE, 0, 0},
#if !defined(JAPANESE) && !defined(SPANISH)
{"Graphics Set", Callback_Graphics, &conf, NULL, 0, FALSE, 0, 0},
#endif
{menu_strings_table[SMOOTH_SCROLLING], Callback_SmoothScrolling, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[SCREEN_SHAKE], Callback_ScreenShake, &conf, NULL, 0, FALSE, 0, 0},
#ifndef JAPANESE
{"Font", Callback_Font, &conf, NULL, 0, FALSE, 0, 0},
#endif
{menu_strings_table[COLOR_FILTERS], Callback_ColorFilters, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[SCREEN_FLASHING], Callback_FlashMode, &conf, NULL, 0, FALSE, 0, 0},
{"Background Brightness", Callback_BackgroundBrightness, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[EXTENDED_UI], Callback_ExtendedUI, &conf, NULL, 0, FALSE, 0, 0}
};
#else
Option options[] = {
{menu_strings_table[CONTROLS], Callback_ControlsController, NULL, NULL, 0, FALSE, 0, 0},
{menu_strings_table[SOUNDTRACK], Callback_Soundtrack, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[FRAMERATE], Callback_Framerate, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[SMOOTH_SCROLLING], Callback_SmoothScrolling, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[SCREEN_SHAKE], Callback_ScreenShake, &conf, NULL, 0, FALSE, 0, 0},
#ifndef JAPANESE
{"Font", Callback_Font, &conf, NULL, 0, FALSE, 0, 0},
#endif
{menu_strings_table[COLOR_FILTERS], Callback_ColorFilters, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[SCREEN_FLASHING], Callback_FlashMode, &conf, NULL, 0, FALSE, 0, 0},
{"Background Brightness", Callback_BackgroundBrightness, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[EXTENDED_UI], Callback_ExtendedUI, &conf, NULL, 0, FALSE, 0, 0}
};
#endif
OptionsMenu options_menu = {
menu_strings_table[OPTIONS_TITLE],
restart_required ? menu_strings_table[RESTART_REQUIRED] : NULL,
options,
(sizeof(options) / sizeof(options[0])),
-130,
TRUE
};
PlaySoundObject(5, SOUND_MODE_PLAY);
bMode = mode_action;
int return_value = EnterOptionsMenu(&options_menu, 0);
PlaySoundObject(18, SOUND_MODE_PLAY);
// Save our changes to the configuration file
memcpy(conf.bindings, bindings, sizeof(bindings));
SaveConfigData(&conf);
// Filter internal return values to something Cave Story can understand
switch (return_value)
{
case CALLBACK_CONTINUE:
return_value = enum_ESCRETURN_continue;
break;
case CALLBACK_RESET:
return_value = enum_ESCRETURN_restart;
break;
case CALLBACK_EXIT:
return_value = enum_ESCRETURN_exit;
break;
}
gKeyTrg = gKey = 0; // Avoid input-ghosting
return return_value;
}
int Call_Tweaks(unsigned int mode_action)
{
// Make the options match the configuration data
CONFIGDATA conf;
if (!LoadConfigData(&conf))
DefaultConfigData(&conf);
Option submenu_options[] = {
{menu_strings_table[DAMAGE_RECEIVED], Callback_DamageModifier, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[BOSS_HP], Callback_BossHealthModifier, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[AUTOFIRE], Callback_AutoFire, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[INFINITE_AMMO], Callback_InfiniteAmmo, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[DEFAULT_BOOSTER], Callback_DefaultBooster, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[INFINITE_BOOSTER], Callback_InfiniteBooster, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[GRACE_JUMPS], Callback_GraceJump, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[NO_EXPERIENCE_DROPS], Callback_NoExpDrops, &conf, NULL, 0, FALSE, 0, 0},
{menu_strings_table[GAME_SPEED], Callback_GameSpeed, &conf, NULL, 0, FALSE, 0, 0}
};
OptionsMenu options_menu = {
menu_strings_table[TWEAKS_TITLE],
tweaks_restart_required ? menu_strings_table[RESTART_REQUIRED] : NULL,
submenu_options,
(sizeof(submenu_options) / sizeof(submenu_options[0])),
-130,
TRUE
};
PlaySoundObject(5, SOUND_MODE_PLAY);
int return_value = EnterOptionsMenu(&options_menu, 0);
PlaySoundObject(18, SOUND_MODE_PLAY);
SaveConfigData(&conf);
// Filter internal return values to something Cave Story can understand
switch (return_value)
{
case CALLBACK_CONTINUE:
return_value = enum_ESCRETURN_continue;
break;
case CALLBACK_RESET:
return_value = enum_ESCRETURN_restart;
break;
case CALLBACK_EXIT:
return_value = enum_ESCRETURN_exit;
break;
}
gKeyTrg = gKey = 0; // Avoid input-ghosting
return return_value;
}