mirror of https://github.com/sm64pc/sm64pc.git
Add in-game control binding menu
Originally on the testing branch
This commit is contained in:
parent
fd74e20373
commit
4a13fd3380
6
Makefile
6
Makefile
|
@ -448,8 +448,8 @@ endif
|
||||||
|
|
||||||
# Check for better camera option
|
# Check for better camera option
|
||||||
ifeq ($(BETTERCAMERA),1)
|
ifeq ($(BETTERCAMERA),1)
|
||||||
CC_CHECK += -DBETTERCAMERA
|
CC_CHECK += -DBETTERCAMERA -DEXT_OPTIONS_MENU
|
||||||
CFLAGS += -DBETTERCAMERA
|
CFLAGS += -DBETTERCAMERA -DEXT_OPTIONS_MENU
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Check for no drawing distance option
|
# Check for no drawing distance option
|
||||||
|
@ -588,11 +588,13 @@ ifeq ($(VERSION),eu)
|
||||||
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||||
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||||
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||||
|
$(BUILD_DIR)/src/game/options_menu.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||||
O_FILES += $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
O_FILES += $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o
|
||||||
else
|
else
|
||||||
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h
|
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h
|
||||||
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h
|
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h
|
||||||
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h
|
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h
|
||||||
|
$(BUILD_DIR)/src/game/options_menu.o: $(BUILD_DIR)/include/text_strings.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
@ -3,20 +3,39 @@
|
||||||
|
|
||||||
#include "text_menu_strings.h"
|
#include "text_menu_strings.h"
|
||||||
|
|
||||||
#define NC_CAMX _("Camera X Sensitivity")
|
#define TEXT_OPT_CAMX _("Camera X Sensitivity")
|
||||||
#define NC_CAMY _("Camera Y Sensitivity")
|
#define TEXT_OPT_CAMY _("Camera Y Sensitivity")
|
||||||
#define NC_INVERTX _("Invert X Axis")
|
#define TEXT_OPT_INVERTX _("Invert X Axis")
|
||||||
#define NC_INVERTY _("Invert Y Axis")
|
#define TEXT_OPT_INVERTY _("Invert Y Axis")
|
||||||
#define NC_CAMC _("Camera Centre Aggression")
|
#define TEXT_OPT_CAMC _("Camera Centre Aggression")
|
||||||
#define NC_CAMP _("Camera Pan Level")
|
#define TEXT_OPT_CAMP _("Camera Pan Level")
|
||||||
#define NC_ENABLED _("Enabled")
|
#define TEXT_OPT_ENABLED _("Enabled")
|
||||||
#define NC_DISABLED _("Disabled")
|
#define TEXT_OPT_DISABLED _("Disabled")
|
||||||
#define NC_BUTTON _("[R]: Options")
|
#define TEXT_OPT_BUTTON1 _("[R]: Options")
|
||||||
#define NC_BUTTON2 _("[R]: Return")
|
#define TEXT_OPT_BUTTON2 _("[R]: Return")
|
||||||
#define NC_OPTION _("OPTIONS")
|
#define TEXT_OPT_OPTIONS _("OPTIONS")
|
||||||
#define NC_HIGHLIGHT _("O")
|
#define TEXT_OPT_CAMERA _("CAMERA")
|
||||||
#define NC_ANALOGUE _("Analogue Camera")
|
#define TEXT_OPT_CONTROLS _("CONTROLS")
|
||||||
#define NC_MOUSE _("Mouse Look")
|
#define TEXT_OPT_HIGHLIGHT _("O")
|
||||||
|
#define TEXT_OPT_ANALOGUE _("Analogue Camera")
|
||||||
|
#define TEXT_OPT_MOUSE _("Mouse Look")
|
||||||
|
|
||||||
|
#define TEXT_OPT_UNBOUND _("NONE")
|
||||||
|
#define TEXT_OPT_PRESSKEY _("...")
|
||||||
|
#define TEXT_BIND_A _("A Button")
|
||||||
|
#define TEXT_BIND_B _("B Button")
|
||||||
|
#define TEXT_BIND_START _("Start Button")
|
||||||
|
#define TEXT_BIND_L _("L Trigger")
|
||||||
|
#define TEXT_BIND_R _("R Trigger")
|
||||||
|
#define TEXT_BIND_Z _("Z Trigger")
|
||||||
|
#define TEXT_BIND_C_UP _("C-Up")
|
||||||
|
#define TEXT_BIND_C_DOWN _("C-Down")
|
||||||
|
#define TEXT_BIND_C_LEFT _("C-Left")
|
||||||
|
#define TEXT_BIND_C_RIGHT _("C-Right")
|
||||||
|
#define TEXT_BIND_UP _("Stick Up")
|
||||||
|
#define TEXT_BIND_DOWN _("Stick Down")
|
||||||
|
#define TEXT_BIND_LEFT _("Stick Left")
|
||||||
|
#define TEXT_BIND_RIGHT _("Stick Right")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Global Symbols
|
* Global Symbols
|
||||||
|
|
|
@ -26,14 +26,9 @@ enum newcam_flagvalues
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void newcam_display_options(void);
|
|
||||||
extern void newcam_check_pause_buttons(void);
|
|
||||||
extern void newcam_init_settings(void);
|
extern void newcam_init_settings(void);
|
||||||
extern void newcam_save_settings(void);
|
|
||||||
extern void newcam_render_option_text(void);
|
|
||||||
extern void newcam_diagnostics(void);
|
extern void newcam_diagnostics(void);
|
||||||
|
|
||||||
extern u8 newcam_option_open;
|
|
||||||
|
|
||||||
extern u8 newcam_sensitivityX; //How quick the camera works.
|
extern u8 newcam_sensitivityX; //How quick the camera works.
|
||||||
extern u8 newcam_sensitivityY;
|
extern u8 newcam_sensitivityY;
|
||||||
|
|
|
@ -105,17 +105,6 @@ u16 newcam_mode;
|
||||||
u16 newcam_intendedmode = 0; // which camera mode the camera's going to try to be in when not forced into another.
|
u16 newcam_intendedmode = 0; // which camera mode the camera's going to try to be in when not forced into another.
|
||||||
u16 newcam_modeflags;
|
u16 newcam_modeflags;
|
||||||
|
|
||||||
u8 newcam_option_open = 0;
|
|
||||||
s8 newcam_option_selection = 0;
|
|
||||||
f32 newcam_option_timer = 0;
|
|
||||||
u8 newcam_option_index = 0;
|
|
||||||
u8 newcam_option_scroll = 0;
|
|
||||||
u8 newcam_option_scroll_last = 0;
|
|
||||||
u8 newcam_total = 8; //How many options there are in newcam_uptions.
|
|
||||||
|
|
||||||
u8 newcam_options[][64] = {{NC_ANALOGUE}, {NC_MOUSE}, {NC_CAMX}, {NC_CAMY}, {NC_INVERTX}, {NC_INVERTY}, {NC_CAMC}, {NC_CAMP}};
|
|
||||||
u8 newcam_flags[][64] = {{NC_DISABLED}, {NC_ENABLED}};
|
|
||||||
u8 newcam_strings[][64] = {{NC_BUTTON}, {NC_BUTTON2}, {NC_OPTION}, {NC_HIGHLIGHT}};
|
|
||||||
|
|
||||||
extern int mouse_x;
|
extern int mouse_x;
|
||||||
extern int mouse_y;
|
extern int mouse_y;
|
||||||
|
@ -168,18 +157,6 @@ void newcam_init_settings(void)
|
||||||
newcam_analogue = (u8)configEnableCamera;
|
newcam_analogue = (u8)configEnableCamera;
|
||||||
}
|
}
|
||||||
|
|
||||||
void newcam_save_settings(void)
|
|
||||||
{
|
|
||||||
configCameraXSens = newcam_sensitivityX;
|
|
||||||
configCameraYSens = newcam_sensitivityY;
|
|
||||||
configCameraAggr = newcam_aggression;
|
|
||||||
configCameraPan = newcam_panlevel;
|
|
||||||
configCameraInvertX = newcam_invertX != 0;
|
|
||||||
configCameraInvertY = newcam_invertY != 0;
|
|
||||||
configEnableCamera = newcam_analogue != 0;
|
|
||||||
configCameraMouse = newcam_mouse != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Mathematic calculations. This stuffs so basic even *I* understand it lol
|
/** Mathematic calculations. This stuffs so basic even *I* understand it lol
|
||||||
Basically, it just returns a position based on angle */
|
Basically, it just returns a position based on angle */
|
||||||
static s16 lengthdir_x(f32 length, s16 dir)
|
static s16 lengthdir_x(f32 length, s16 dir)
|
||||||
|
@ -670,234 +647,10 @@ void newcam_loop(struct Camera *c)
|
||||||
newcam_position_cam();
|
newcam_position_cam();
|
||||||
newcam_find_fixed();
|
newcam_find_fixed();
|
||||||
if (gMarioObject)
|
if (gMarioObject)
|
||||||
newcam_apply_values(c);
|
newcam_apply_values(c);
|
||||||
|
|
||||||
//Just some visual information on the values of the camera. utilises ifdef because it's better at runtime.
|
//Just some visual information on the values of the camera. utilises ifdef because it's better at runtime.
|
||||||
#ifdef NEWCAM_DEBUG
|
#ifdef NEWCAM_DEBUG
|
||||||
newcam_diagnostics();
|
newcam_diagnostics();
|
||||||
#endif // NEWCAM_DEBUG
|
#endif // NEWCAM_DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Displays a box.
|
|
||||||
void newcam_display_box(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b)
|
|
||||||
{
|
|
||||||
gDPPipeSync(gDisplayListHead++);
|
|
||||||
gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
|
|
||||||
gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
|
|
||||||
gDPSetFillColor(gDisplayListHead++, GPACK_RGBA5551(r, g, b, 255));
|
|
||||||
gDPFillRectangle(gDisplayListHead++, x1, y1, x2 - 1, y2 - 1);
|
|
||||||
gDPPipeSync(gDisplayListHead++);
|
|
||||||
gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//I actually took the time to redo this, properly. Lmao. Please don't bully me over this anymore :(
|
|
||||||
void newcam_change_setting(u8 toggle)
|
|
||||||
{
|
|
||||||
switch (newcam_option_selection)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
newcam_analogue ^= 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
newcam_mouse ^= 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
newcam_sensitivityX = newcam_clamp(newcam_sensitivityX + toggle, 10, 250);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
newcam_sensitivityY = newcam_clamp(newcam_sensitivityY + toggle, 10, 250);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
newcam_invertX ^= 1;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
newcam_invertY ^= 1;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
newcam_aggression = newcam_clamp(newcam_aggression + toggle, 0, 100);
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
newcam_panlevel = newcam_clamp(newcam_panlevel + toggle, 0, 100);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void newcam_text(s16 x, s16 y, u8 str[], u8 col)
|
|
||||||
{
|
|
||||||
u8 textX;
|
|
||||||
textX = get_str_x_pos_from_center(x,str,10.0f);
|
|
||||||
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
|
|
||||||
print_generic_string(textX+1,y-1,str);
|
|
||||||
if (col != 0)
|
|
||||||
{
|
|
||||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gDPSetEnvColor(gDisplayListHead++, 255, 32, 32, 255);
|
|
||||||
}
|
|
||||||
print_generic_string(textX,y,str);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Options menu
|
|
||||||
void newcam_display_options()
|
|
||||||
{
|
|
||||||
u8 i = 0;
|
|
||||||
u8 newstring[32];
|
|
||||||
s16 scroll;
|
|
||||||
s16 scrollpos;
|
|
||||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
|
||||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
||||||
print_hud_lut_string(HUD_LUT_GLOBAL, 118, 40, newcam_strings[2]);
|
|
||||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
|
||||||
|
|
||||||
if (newcam_total>4)
|
|
||||||
{
|
|
||||||
newcam_display_box(272,90,280,208,0x80,0x80,0x80);
|
|
||||||
scrollpos = (54)*((f32)newcam_option_scroll/(newcam_total-4));
|
|
||||||
newcam_display_box(272,90+scrollpos,280,154+scrollpos,0xFF,0xFF,0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
|
||||||
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 80, SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
||||||
for (i = 0; i < newcam_total; i++)
|
|
||||||
{
|
|
||||||
scroll = 140-(32*i)+(newcam_option_scroll*32);
|
|
||||||
if (scroll <= 140 && scroll > 32)
|
|
||||||
{
|
|
||||||
newcam_text(160,scroll,newcam_options[i],newcam_option_selection-i);
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
newcam_text(160,scroll-12,newcam_flags[newcam_analogue],newcam_option_selection-i);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
newcam_text(160,scroll-12,newcam_flags[newcam_mouse],newcam_option_selection-i);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
int_to_str(newcam_sensitivityX,newstring);
|
|
||||||
newcam_text(160,scroll-12,newstring,newcam_option_selection-i);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
int_to_str(newcam_sensitivityY,newstring);
|
|
||||||
newcam_text(160,scroll-12,newstring,newcam_option_selection-i);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
newcam_text(160,scroll-12,newcam_flags[newcam_invertX],newcam_option_selection-i);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
newcam_text(160,scroll-12,newcam_flags[newcam_invertY],newcam_option_selection-i);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
int_to_str(newcam_aggression,newstring);
|
|
||||||
newcam_text(160,scroll-12,newstring,newcam_option_selection-i);
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
int_to_str(newcam_panlevel,newstring);
|
|
||||||
newcam_text(160,scroll-12,newstring,newcam_option_selection-i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
||||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
|
||||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
|
||||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
|
||||||
print_hud_lut_string(HUD_LUT_GLOBAL, 80, 90+(32*(newcam_option_selection-newcam_option_scroll)), newcam_strings[3]);
|
|
||||||
print_hud_lut_string(HUD_LUT_GLOBAL, 224, 90+(32*(newcam_option_selection-newcam_option_scroll)), newcam_strings[3]);
|
|
||||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
//This has been separated for interesting reasons. Don't question it.
|
|
||||||
void newcam_render_option_text(void)
|
|
||||||
{
|
|
||||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
|
||||||
newcam_text(278,212,newcam_strings[newcam_option_open],1);
|
|
||||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void newcam_check_pause_buttons()
|
|
||||||
{
|
|
||||||
if (gPlayer1Controller->buttonPressed & R_TRIG)
|
|
||||||
{
|
|
||||||
if (newcam_option_open == 0)
|
|
||||||
{
|
|
||||||
#ifndef nosound
|
|
||||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
|
||||||
#endif
|
|
||||||
newcam_option_open = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifndef nosound
|
|
||||||
play_sound(SOUND_MENU_MARIO_CASTLE_WARP2, gDefaultSoundArgs);
|
|
||||||
#endif
|
|
||||||
newcam_option_open = 0;
|
|
||||||
newcam_save_settings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newcam_option_open)
|
|
||||||
{
|
|
||||||
if (ABS(gPlayer1Controller->stickY) > 60)
|
|
||||||
{
|
|
||||||
newcam_option_timer -= 1;
|
|
||||||
if (newcam_option_timer <= 0)
|
|
||||||
{
|
|
||||||
switch (newcam_option_index)
|
|
||||||
{
|
|
||||||
case 0: newcam_option_index++; newcam_option_timer += 10; break;
|
|
||||||
default: newcam_option_timer += 3; break;
|
|
||||||
}
|
|
||||||
#ifndef nosound
|
|
||||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
|
||||||
#endif
|
|
||||||
if (gPlayer1Controller->stickY >= 60)
|
|
||||||
{
|
|
||||||
newcam_option_selection--;
|
|
||||||
if (newcam_option_selection < 0)
|
|
||||||
newcam_option_selection = newcam_total-1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newcam_option_selection++;
|
|
||||||
if (newcam_option_selection >= newcam_total)
|
|
||||||
newcam_option_selection = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (ABS(gPlayer1Controller->stickX) > 60)
|
|
||||||
{
|
|
||||||
newcam_option_timer -= 1;
|
|
||||||
if (newcam_option_timer <= 0)
|
|
||||||
{
|
|
||||||
switch (newcam_option_index)
|
|
||||||
{
|
|
||||||
case 0: newcam_option_index++; newcam_option_timer += 10; break;
|
|
||||||
default: newcam_option_timer += 3; break;
|
|
||||||
}
|
|
||||||
#ifndef nosound
|
|
||||||
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
|
||||||
#endif
|
|
||||||
if (gPlayer1Controller->stickX >= 60)
|
|
||||||
newcam_change_setting(1);
|
|
||||||
else
|
|
||||||
newcam_change_setting(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newcam_option_timer = 0;
|
|
||||||
newcam_option_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (newcam_option_scroll - newcam_option_selection < -3 && newcam_option_selection > newcam_option_scroll)
|
|
||||||
newcam_option_scroll +=1;
|
|
||||||
while (newcam_option_scroll + newcam_option_selection > 0 && newcam_option_selection < newcam_option_scroll)
|
|
||||||
newcam_option_scroll -=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#ifdef BETTERCAMERA
|
#ifdef BETTERCAMERA
|
||||||
#include "bettercamera.h"
|
#include "bettercamera.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef EXT_OPTIONS_MENU
|
||||||
|
#include "options_menu.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern Gfx *gDisplayListHead;
|
extern Gfx *gDisplayListHead;
|
||||||
extern s16 gCurrCourseNum;
|
extern s16 gCurrCourseNum;
|
||||||
|
@ -2629,9 +2632,8 @@ s16 render_pause_courses_and_castle(void) {
|
||||||
#ifdef VERSION_EU
|
#ifdef VERSION_EU
|
||||||
gInGameLanguage = eu_get_language();
|
gInGameLanguage = eu_get_language();
|
||||||
#endif
|
#endif
|
||||||
#ifdef BETTERCAMERA
|
#ifdef EXT_OPTIONS_MENU
|
||||||
if (newcam_option_open == 0)
|
if (optmenu_open == 0) {
|
||||||
{
|
|
||||||
#endif
|
#endif
|
||||||
switch (gDialogBoxState) {
|
switch (gDialogBoxState) {
|
||||||
case DIALOG_STATE_OPENING:
|
case DIALOG_STATE_OPENING:
|
||||||
|
@ -2708,15 +2710,13 @@ s16 render_pause_courses_and_castle(void) {
|
||||||
if (gDialogTextAlpha < 250) {
|
if (gDialogTextAlpha < 250) {
|
||||||
gDialogTextAlpha += 25;
|
gDialogTextAlpha += 25;
|
||||||
}
|
}
|
||||||
#ifdef BETTERCAMERA
|
#ifdef EXT_OPTIONS_MENU
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
shade_screen();
|
shade_screen();
|
||||||
newcam_display_options();
|
optmenu_draw();
|
||||||
}
|
}
|
||||||
newcam_check_pause_buttons();
|
optmenu_check_buttons();
|
||||||
newcam_render_option_text();
|
optmenu_draw_prompt();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -179,7 +179,7 @@ u8 unused3[4];
|
||||||
u8 unused4[2];
|
u8 unused4[2];
|
||||||
|
|
||||||
// For configfile intro skipping
|
// For configfile intro skipping
|
||||||
extern unsigned int configSkipIntro;
|
//extern unsigned int configSkipIntro;
|
||||||
|
|
||||||
|
|
||||||
void basic_update(s16 *arg);
|
void basic_update(s16 *arg);
|
||||||
|
@ -1217,7 +1217,7 @@ s32 init_level(void) {
|
||||||
if (gMarioState->action != ACT_UNINITIALIZED) {
|
if (gMarioState->action != ACT_UNINITIALIZED) {
|
||||||
if (save_file_exists(gCurrSaveFileNum - 1)) {
|
if (save_file_exists(gCurrSaveFileNum - 1)) {
|
||||||
set_mario_action(gMarioState, ACT_IDLE, 0);
|
set_mario_action(gMarioState, ACT_IDLE, 0);
|
||||||
} else if (gCLIOpts.SkipIntro == 0 && configSkipIntro == 0) {
|
} else if (gCLIOpts.SkipIntro == 0) {
|
||||||
set_mario_action(gMarioState, ACT_INTRO_CUTSCENE, 0);
|
set_mario_action(gMarioState, ACT_INTRO_CUTSCENE, 0);
|
||||||
val4 = 1;
|
val4 = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,463 @@
|
||||||
|
#ifdef EXT_OPTIONS_MENU
|
||||||
|
|
||||||
|
#include "sm64.h"
|
||||||
|
#include "include/text_strings.h"
|
||||||
|
#include "engine/math_util.h"
|
||||||
|
#include "audio/external.h"
|
||||||
|
#include "game/camera.h"
|
||||||
|
#include "game/level_update.h"
|
||||||
|
#include "game/print.h"
|
||||||
|
#include "game/segment2.h"
|
||||||
|
#include "game/save_file.h"
|
||||||
|
#include "game/bettercamera.h"
|
||||||
|
#include "game/mario_misc.h"
|
||||||
|
#include "game/game_init.h"
|
||||||
|
#include "game/ingame_menu.h"
|
||||||
|
#include "game/options_menu.h"
|
||||||
|
#include "pc/configfile.h"
|
||||||
|
#include "pc/controller/controller_api.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
u8 optmenu_open = 0;
|
||||||
|
|
||||||
|
static u8 optmenu_binding = 0;
|
||||||
|
static u8 optmenu_bind_idx = 0;
|
||||||
|
|
||||||
|
// How to add stuff:
|
||||||
|
// strings: add them to include/text_strings.h.in
|
||||||
|
// and to menuStr[] / opts*Str[]
|
||||||
|
// options: add them to the relevant options list
|
||||||
|
// menus: add a new submenu definition and a new
|
||||||
|
// option to the optsMain list
|
||||||
|
|
||||||
|
static const u8 toggleStr[][64] = {
|
||||||
|
{ TEXT_OPT_DISABLED },
|
||||||
|
{ TEXT_OPT_ENABLED },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 menuStr[][64] = {
|
||||||
|
{ TEXT_OPT_HIGHLIGHT },
|
||||||
|
{ TEXT_OPT_BUTTON1 },
|
||||||
|
{ TEXT_OPT_BUTTON2 },
|
||||||
|
{ TEXT_OPT_OPTIONS },
|
||||||
|
{ TEXT_OPT_CAMERA },
|
||||||
|
{ TEXT_OPT_CONTROLS },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 optsCameraStr[][64] = {
|
||||||
|
{ TEXT_OPT_CAMX },
|
||||||
|
{ TEXT_OPT_CAMY },
|
||||||
|
{ TEXT_OPT_INVERTX },
|
||||||
|
{ TEXT_OPT_INVERTY },
|
||||||
|
{ TEXT_OPT_CAMC },
|
||||||
|
{ TEXT_OPT_CAMP },
|
||||||
|
{ TEXT_OPT_ANALOGUE },
|
||||||
|
{ TEXT_OPT_MOUSE },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 bindStr[][64] = {
|
||||||
|
{ TEXT_OPT_UNBOUND },
|
||||||
|
{ TEXT_OPT_PRESSKEY },
|
||||||
|
{ TEXT_BIND_A },
|
||||||
|
{ TEXT_BIND_B },
|
||||||
|
{ TEXT_BIND_START },
|
||||||
|
{ TEXT_BIND_L },
|
||||||
|
{ TEXT_BIND_R },
|
||||||
|
{ TEXT_BIND_Z },
|
||||||
|
{ TEXT_BIND_C_UP },
|
||||||
|
{ TEXT_BIND_C_DOWN },
|
||||||
|
{ TEXT_BIND_C_LEFT },
|
||||||
|
{ TEXT_BIND_C_RIGHT },
|
||||||
|
{ TEXT_BIND_UP },
|
||||||
|
{ TEXT_BIND_DOWN },
|
||||||
|
{ TEXT_BIND_LEFT },
|
||||||
|
{ TEXT_BIND_RIGHT },
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OptType {
|
||||||
|
OPT_INVALID = 0,
|
||||||
|
OPT_TOGGLE,
|
||||||
|
OPT_CHOICE,
|
||||||
|
OPT_SCROLL,
|
||||||
|
OPT_SUBMENU,
|
||||||
|
OPT_BIND,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SubMenu;
|
||||||
|
|
||||||
|
struct Option {
|
||||||
|
enum OptType type;
|
||||||
|
const u8 *label;
|
||||||
|
union {
|
||||||
|
u32 *uval;
|
||||||
|
bool *bval;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
const u8 **choices;
|
||||||
|
u32 numChoices;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
u32 scrMin;
|
||||||
|
u32 scrMax;
|
||||||
|
u32 scrStep;
|
||||||
|
};
|
||||||
|
struct SubMenu *nextMenu;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SubMenu {
|
||||||
|
struct SubMenu *prev; // this is set at runtime to avoid needless complication
|
||||||
|
const u8 *label;
|
||||||
|
struct Option *opts;
|
||||||
|
s32 numOpts;
|
||||||
|
s32 select;
|
||||||
|
s32 scroll;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* submenu option lists */
|
||||||
|
|
||||||
|
static struct Option optsCamera[] = {
|
||||||
|
{ .type = OPT_TOGGLE, .label = optsCameraStr[6], .bval = &configEnableCamera, },
|
||||||
|
{ .type = OPT_TOGGLE, .label = optsCameraStr[7], .bval = &configCameraMouse, },
|
||||||
|
{ .type = OPT_TOGGLE, .label = optsCameraStr[2], .bval = &configCameraInvertX, },
|
||||||
|
{ .type = OPT_TOGGLE, .label = optsCameraStr[3], .bval = &configCameraInvertY, },
|
||||||
|
{ .type = OPT_SCROLL, .label = optsCameraStr[0], .uval = &configCameraXSens, .scrMin = 10, .scrMax = 250, .scrStep = 1 },
|
||||||
|
{ .type = OPT_SCROLL, .label = optsCameraStr[1], .uval = &configCameraYSens, .scrMin = 10, .scrMax = 250, .scrStep = 1 },
|
||||||
|
{ .type = OPT_SCROLL, .label = optsCameraStr[4], .uval = &configCameraAggr, .scrMin = 0, .scrMax = 100, .scrStep = 1 },
|
||||||
|
{ .type = OPT_SCROLL, .label = optsCameraStr[5], .uval = &configCameraPan, .scrMin = 0, .scrMax = 100, .scrStep = 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct Option optsControls[] = {
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[2], .uval = configKeyA, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[3], .uval = configKeyB, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[4], .uval = configKeyStart, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[5], .uval = configKeyL, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[6], .uval = configKeyR, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[7], .uval = configKeyZ, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[8], .uval = configKeyCUp, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[9], .uval = configKeyCDown, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[10], .uval = configKeyCLeft, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[11], .uval = configKeyCRight, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[12], .uval = configKeyStickUp, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[13], .uval = configKeyStickDown, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[14], .uval = configKeyStickLeft, },
|
||||||
|
{ .type = OPT_BIND, .label = bindStr[15], .uval = configKeyStickRight, },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* submenu definitions */
|
||||||
|
|
||||||
|
static struct SubMenu menuCamera = {
|
||||||
|
.label = menuStr[4],
|
||||||
|
.opts = optsCamera,
|
||||||
|
.numOpts = sizeof(optsCamera) / sizeof(optsCamera[0]),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct SubMenu menuControls = {
|
||||||
|
.label = menuStr[5],
|
||||||
|
.opts = optsControls,
|
||||||
|
.numOpts = sizeof(optsControls) / sizeof(optsControls[0]),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* main options menu definition */
|
||||||
|
|
||||||
|
static struct Option optsMain[] = {
|
||||||
|
{ .type = OPT_SUBMENU, .label = menuStr[4], .nextMenu = &menuCamera, },
|
||||||
|
{ .type = OPT_SUBMENU, .label = menuStr[5], .nextMenu = &menuControls, },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct SubMenu menuMain = {
|
||||||
|
.label = menuStr[3],
|
||||||
|
.opts = optsMain,
|
||||||
|
.numOpts = sizeof(optsMain) / sizeof(optsMain[0]),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* implementation */
|
||||||
|
|
||||||
|
static s32 optmenu_option_timer = 0;
|
||||||
|
static u8 optmenu_hold_count = 0;
|
||||||
|
|
||||||
|
static struct SubMenu *currentMenu = &menuMain;
|
||||||
|
|
||||||
|
static inline s32 wrap_add(s32 a, const s32 b, const s32 min, const s32 max) {
|
||||||
|
a += b;
|
||||||
|
if (a < min) a = max - (min - a) + 1;
|
||||||
|
else if (a > max) a = min + (a - max) - 1;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uint_to_hex(u32 num, u8 *dst) {
|
||||||
|
u8 places = 4;
|
||||||
|
while (places--) {
|
||||||
|
const u32 digit = num & 0xF;
|
||||||
|
dst[places] = digit;
|
||||||
|
num >>= 4;
|
||||||
|
}
|
||||||
|
dst[4] = DIALOG_CHAR_TERMINATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Displays a box.
|
||||||
|
static void optmenu_draw_box(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b) {
|
||||||
|
gDPPipeSync(gDisplayListHead++);
|
||||||
|
gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
|
||||||
|
gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
|
||||||
|
gDPSetFillColor(gDisplayListHead++, GPACK_RGBA5551(r, g, b, 255));
|
||||||
|
gDPFillRectangle(gDisplayListHead++, x1, y1, x2 - 1, y2 - 1);
|
||||||
|
gDPPipeSync(gDisplayListHead++);
|
||||||
|
gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void optmenu_draw_text(s16 x, s16 y, const u8 *str, u8 col) {
|
||||||
|
const u8 textX = get_str_x_pos_from_center(x, (u8*)str, 10.0f);
|
||||||
|
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
|
||||||
|
print_generic_string(textX+1, y-1, str);
|
||||||
|
if (col == 0) {
|
||||||
|
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||||
|
} else {
|
||||||
|
gDPSetEnvColor(gDisplayListHead++, 255, 32, 32, 255);
|
||||||
|
}
|
||||||
|
print_generic_string(textX, y, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void optmenu_draw_opt(const struct Option *opt, s16 x, s16 y, u8 sel) {
|
||||||
|
u8 buf[32] = { 0 };
|
||||||
|
|
||||||
|
if (opt->type == OPT_SUBMENU)
|
||||||
|
y -= 6;
|
||||||
|
|
||||||
|
optmenu_draw_text(x, y, opt->label, sel);
|
||||||
|
|
||||||
|
switch (opt->type) {
|
||||||
|
case OPT_TOGGLE:
|
||||||
|
optmenu_draw_text(x, y-13, toggleStr[(int)*opt->bval], sel);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_CHOICE:
|
||||||
|
optmenu_draw_text(x, y-13, opt->choices[*opt->uval], sel);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_SCROLL:
|
||||||
|
int_to_str(*opt->uval, buf);
|
||||||
|
optmenu_draw_text(x, y-13, buf, sel);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_BIND:
|
||||||
|
x = 112;
|
||||||
|
for (u8 i = 0; i < MAX_BINDS; ++i, x += 48) {
|
||||||
|
const u8 white = (sel && (optmenu_bind_idx == i));
|
||||||
|
// TODO: button names
|
||||||
|
if (opt->uval[i] == VK_INVALID) {
|
||||||
|
if (optmenu_binding && white)
|
||||||
|
optmenu_draw_text(x, y-13, bindStr[1], 1);
|
||||||
|
else
|
||||||
|
optmenu_draw_text(x, y-13, bindStr[0], white);
|
||||||
|
} else {
|
||||||
|
uint_to_hex(opt->uval[i], buf);
|
||||||
|
optmenu_draw_text(x, y-13, buf, white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void optmenu_opt_change(struct Option *opt, s32 val) {
|
||||||
|
switch (opt->type) {
|
||||||
|
case OPT_TOGGLE:
|
||||||
|
*opt->bval = !*opt->bval;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_CHOICE:
|
||||||
|
*opt->uval = wrap_add(*opt->uval, val, 0, opt->numChoices - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_SCROLL:
|
||||||
|
*opt->uval = wrap_add(*opt->uval, val, opt->scrMin, opt->scrMax);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_SUBMENU:
|
||||||
|
opt->nextMenu->prev = currentMenu;
|
||||||
|
currentMenu = opt->nextMenu;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_BIND:
|
||||||
|
if (val == 0xFF) {
|
||||||
|
// clear the bind
|
||||||
|
opt->uval[optmenu_bind_idx] = VK_INVALID;
|
||||||
|
} else if (val == 0) {
|
||||||
|
opt->uval[optmenu_bind_idx] = VK_INVALID;
|
||||||
|
optmenu_binding = 1;
|
||||||
|
controller_get_raw_key(); // clear the last key, which is probably A
|
||||||
|
} else {
|
||||||
|
optmenu_bind_idx = wrap_add(optmenu_bind_idx, val, 0, MAX_BINDS - 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline s16 get_hudstr_centered_x(const s16 sx, const u8 *str) {
|
||||||
|
const u8 *chr = str;
|
||||||
|
s16 len = 0;
|
||||||
|
while (*chr != GLOBAR_CHAR_TERMINATOR) ++chr, ++len;
|
||||||
|
return sx - len * 6; // stride is 12
|
||||||
|
}
|
||||||
|
|
||||||
|
//Options menu
|
||||||
|
void optmenu_draw(void) {
|
||||||
|
s16 scroll;
|
||||||
|
s16 scrollpos;
|
||||||
|
|
||||||
|
const s16 labelX = get_hudstr_centered_x(160, currentMenu->label);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||||
|
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||||
|
print_hud_lut_string(HUD_LUT_GLOBAL, labelX, 40, currentMenu->label);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||||
|
|
||||||
|
if (currentMenu->numOpts > 4) {
|
||||||
|
optmenu_draw_box(272, 90, 280, 208, 0x80, 0x80, 0x80);
|
||||||
|
scrollpos = 54 * ((f32)currentMenu->scroll / (currentMenu->numOpts-4));
|
||||||
|
optmenu_draw_box(272, 90+scrollpos, 280, 154+scrollpos, 0xFF, 0xFF, 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||||
|
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 80, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
for (u8 i = 0; i < currentMenu->numOpts; i++) {
|
||||||
|
scroll = 140 - 32 * i + currentMenu->scroll * 32;
|
||||||
|
// FIXME: just start from the first visible option bruh
|
||||||
|
if (scroll <= 140 && scroll > 32)
|
||||||
|
optmenu_draw_opt(¤tMenu->opts[i], 160, scroll, (currentMenu->select == i));
|
||||||
|
}
|
||||||
|
|
||||||
|
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||||
|
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||||
|
print_hud_lut_string(HUD_LUT_GLOBAL, 80, 90 + (32 * (currentMenu->select - currentMenu->scroll)), menuStr[0]);
|
||||||
|
print_hud_lut_string(HUD_LUT_GLOBAL, 224, 90 + (32 * (currentMenu->select - currentMenu->scroll)), menuStr[0]);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
//This has been separated for interesting reasons. Don't question it.
|
||||||
|
void optmenu_draw_prompt(void) {
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||||
|
optmenu_draw_text(278, 212, menuStr[1 + optmenu_open], 0);
|
||||||
|
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void optmenu_toggle(void) {
|
||||||
|
if (optmenu_open == 0) {
|
||||||
|
#ifndef nosound
|
||||||
|
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||||
|
#endif
|
||||||
|
currentMenu = &menuMain;
|
||||||
|
optmenu_open = 1;
|
||||||
|
} else {
|
||||||
|
#ifndef nosound
|
||||||
|
play_sound(SOUND_MENU_MARIO_CASTLE_WARP2, gDefaultSoundArgs);
|
||||||
|
#endif
|
||||||
|
optmenu_open = 0;
|
||||||
|
newcam_init_settings(); // load bettercam settings from config vars
|
||||||
|
controller_reconfigure(); // rebind using new config values
|
||||||
|
configfile_save(CONFIG_FILE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void optmenu_check_buttons(void) {
|
||||||
|
if (optmenu_binding) {
|
||||||
|
u32 key = controller_get_raw_key();
|
||||||
|
if (key != VK_INVALID) {
|
||||||
|
#ifndef nosound
|
||||||
|
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||||
|
#endif
|
||||||
|
currentMenu->opts[currentMenu->select].uval[optmenu_bind_idx] = key;
|
||||||
|
optmenu_binding = 0;
|
||||||
|
optmenu_option_timer = 12;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gPlayer1Controller->buttonPressed & R_TRIG)
|
||||||
|
optmenu_toggle();
|
||||||
|
|
||||||
|
if (!optmenu_open) return;
|
||||||
|
|
||||||
|
u8 allowInput = 0;
|
||||||
|
|
||||||
|
optmenu_option_timer--;
|
||||||
|
if (optmenu_option_timer <= 0) {
|
||||||
|
if (optmenu_hold_count == 0) {
|
||||||
|
optmenu_hold_count++;
|
||||||
|
optmenu_option_timer = 10;
|
||||||
|
} else {
|
||||||
|
optmenu_option_timer = 3;
|
||||||
|
}
|
||||||
|
allowInput = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ABS(gPlayer1Controller->stickY) > 60) {
|
||||||
|
if (allowInput) {
|
||||||
|
#ifndef nosound
|
||||||
|
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (gPlayer1Controller->stickY >= 60) {
|
||||||
|
currentMenu->select--;
|
||||||
|
if (currentMenu->select < 0)
|
||||||
|
currentMenu->select = currentMenu->numOpts-1;
|
||||||
|
} else {
|
||||||
|
currentMenu->select++;
|
||||||
|
if (currentMenu->select >= currentMenu->numOpts)
|
||||||
|
currentMenu->select = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentMenu->select < currentMenu->scroll)
|
||||||
|
currentMenu->scroll = currentMenu->select;
|
||||||
|
else if (currentMenu->select > currentMenu->scroll + 3)
|
||||||
|
currentMenu->scroll = currentMenu->select - 3;
|
||||||
|
}
|
||||||
|
} else if (ABS(gPlayer1Controller->stickX) > 60) {
|
||||||
|
if (allowInput) {
|
||||||
|
#ifndef nosound
|
||||||
|
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||||
|
#endif
|
||||||
|
if (gPlayer1Controller->stickX >= 60)
|
||||||
|
optmenu_opt_change(¤tMenu->opts[currentMenu->select], 1);
|
||||||
|
else
|
||||||
|
optmenu_opt_change(¤tMenu->opts[currentMenu->select], -1);
|
||||||
|
}
|
||||||
|
} else if (gPlayer1Controller->buttonPressed & A_BUTTON) {
|
||||||
|
if (allowInput) {
|
||||||
|
#ifndef nosound
|
||||||
|
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||||
|
#endif
|
||||||
|
optmenu_opt_change(¤tMenu->opts[currentMenu->select], 0);
|
||||||
|
}
|
||||||
|
} else if (gPlayer1Controller->buttonPressed & B_BUTTON) {
|
||||||
|
if (allowInput) {
|
||||||
|
if (currentMenu->prev) {
|
||||||
|
#ifndef nosound
|
||||||
|
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
|
||||||
|
#endif
|
||||||
|
currentMenu = currentMenu->prev;
|
||||||
|
} else {
|
||||||
|
// can't go back, exit the menu altogether
|
||||||
|
optmenu_toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (gPlayer1Controller->buttonPressed & Z_TRIG) {
|
||||||
|
// HACK: clear binds with Z
|
||||||
|
if (allowInput && currentMenu->opts[currentMenu->select].type == OPT_BIND)
|
||||||
|
optmenu_opt_change(¤tMenu->opts[currentMenu->select], 0xFF);
|
||||||
|
} else if (gPlayer1Controller->buttonPressed & START_BUTTON) {
|
||||||
|
if (allowInput) optmenu_toggle();
|
||||||
|
} else {
|
||||||
|
optmenu_hold_count = 0;
|
||||||
|
optmenu_option_timer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // EXT_OPTIONS_MENU
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef OPTIONS_MENU_H
|
||||||
|
#define OPTIONS_MENU_H
|
||||||
|
|
||||||
|
void optmenu_toggle(void);
|
||||||
|
void optmenu_draw(void);
|
||||||
|
void optmenu_draw_prompt(void);
|
||||||
|
void optmenu_check_buttons(void);
|
||||||
|
|
||||||
|
extern u8 optmenu_open;
|
||||||
|
|
||||||
|
#endif // OPTIONS_MENU_H
|
|
@ -7,6 +7,7 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
|
#include "controller/controller_api.h"
|
||||||
|
|
||||||
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ enum ConfigOptionType {
|
||||||
CONFIG_TYPE_BOOL,
|
CONFIG_TYPE_BOOL,
|
||||||
CONFIG_TYPE_UINT,
|
CONFIG_TYPE_UINT,
|
||||||
CONFIG_TYPE_FLOAT,
|
CONFIG_TYPE_FLOAT,
|
||||||
|
CONFIG_TYPE_BIND,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConfigOption {
|
struct ConfigOption {
|
||||||
|
@ -29,35 +31,24 @@ struct ConfigOption {
|
||||||
/*
|
/*
|
||||||
*Config options and default values
|
*Config options and default values
|
||||||
*/
|
*/
|
||||||
bool configFullscreen = false;
|
|
||||||
// Keyboard mappings (scancode values)
|
bool configFullscreen = false;
|
||||||
unsigned int configKeyA = 0x26;
|
// Keyboard mappings (VK_ values, by default keyboard/gamepad/mouse)
|
||||||
unsigned int configKeyB = 0x33;
|
unsigned int configKeyA[MAX_BINDS] = { 0x0026, 0x1000, 0x1103 };
|
||||||
unsigned int configKeyStart = 0x39;
|
unsigned int configKeyB[MAX_BINDS] = { 0x0033, 0x1002, 0x1101 };
|
||||||
unsigned int configKeyL = 0x34;
|
unsigned int configKeyStart[MAX_BINDS] = { 0x0039, 0x1006, VK_INVALID };
|
||||||
unsigned int configKeyR = 0x36;
|
unsigned int configKeyL[MAX_BINDS] = { 0x0034, 0x1007, 0x1104 };
|
||||||
unsigned int configKeyZ = 0x25;
|
unsigned int configKeyR[MAX_BINDS] = { 0x0036, 0x100A, 0x1105 };
|
||||||
unsigned int configKeyCUp = 0x148;
|
unsigned int configKeyZ[MAX_BINDS] = { 0x0025, 0x1009, 0x1102 };
|
||||||
unsigned int configKeyCDown = 0x150;
|
unsigned int configKeyCUp[MAX_BINDS] = { 0x0148, VK_INVALID, VK_INVALID };
|
||||||
unsigned int configKeyCLeft = 0x14B;
|
unsigned int configKeyCDown[MAX_BINDS] = { 0x0150, VK_INVALID, VK_INVALID };
|
||||||
unsigned int configKeyCRight = 0x14D;
|
unsigned int configKeyCLeft[MAX_BINDS] = { 0x014B, VK_INVALID, VK_INVALID };
|
||||||
unsigned int configKeyStickUp = 0x11;
|
unsigned int configKeyCRight[MAX_BINDS] = { 0x014D, VK_INVALID, VK_INVALID };
|
||||||
unsigned int configKeyStickDown = 0x1F;
|
unsigned int configKeyStickUp[MAX_BINDS] = { 0x0011, VK_INVALID, VK_INVALID };
|
||||||
unsigned int configKeyStickLeft = 0x1E;
|
unsigned int configKeyStickDown[MAX_BINDS] = { 0x001F, VK_INVALID, VK_INVALID };
|
||||||
unsigned int configKeyStickRight = 0x20;
|
unsigned int configKeyStickLeft[MAX_BINDS] = { 0x001E, VK_INVALID, VK_INVALID };
|
||||||
// Gamepad mappings (SDL_GameControllerButton values)
|
unsigned int configKeyStickRight[MAX_BINDS] = { 0x0020, VK_INVALID, VK_INVALID };
|
||||||
unsigned int configJoyA = 0;
|
|
||||||
unsigned int configJoyB = 2;
|
|
||||||
unsigned int configJoyStart = 6;
|
|
||||||
unsigned int configJoyL = 7;
|
|
||||||
unsigned int configJoyR = 10;
|
|
||||||
unsigned int configJoyZ = 9;
|
|
||||||
// Mouse button mappings (0 for none, 1 for left, 2 for middle, 3 for right)
|
|
||||||
unsigned int configMouseA = 3;
|
|
||||||
unsigned int configMouseB = 1;
|
|
||||||
unsigned int configMouseL = 4;
|
|
||||||
unsigned int configMouseR = 5;
|
|
||||||
unsigned int configMouseZ = 2;
|
|
||||||
#ifdef BETTERCAMERA
|
#ifdef BETTERCAMERA
|
||||||
// BetterCamera settings
|
// BetterCamera settings
|
||||||
unsigned int configCameraXSens = 50;
|
unsigned int configCameraXSens = 50;
|
||||||
|
@ -69,35 +60,23 @@ bool configCameraInvertY = false;
|
||||||
bool configEnableCamera = false;
|
bool configEnableCamera = false;
|
||||||
bool configCameraMouse = false;
|
bool configCameraMouse = false;
|
||||||
#endif
|
#endif
|
||||||
unsigned int configSkipIntro = 0;
|
|
||||||
|
|
||||||
static const struct ConfigOption options[] = {
|
static const struct ConfigOption options[] = {
|
||||||
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configFullscreen},
|
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configFullscreen},
|
||||||
{.name = "key_a", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyA},
|
{.name = "key_a", .type = CONFIG_TYPE_BIND, .uintValue = configKeyA},
|
||||||
{.name = "key_b", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyB},
|
{.name = "key_b", .type = CONFIG_TYPE_BIND, .uintValue = configKeyB},
|
||||||
{.name = "key_start", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStart},
|
{.name = "key_start", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStart},
|
||||||
{.name = "key_l", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyL},
|
{.name = "key_l", .type = CONFIG_TYPE_BIND, .uintValue = configKeyL},
|
||||||
{.name = "key_r", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyR},
|
{.name = "key_r", .type = CONFIG_TYPE_BIND, .uintValue = configKeyR},
|
||||||
{.name = "key_z", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyZ},
|
{.name = "key_z", .type = CONFIG_TYPE_BIND, .uintValue = configKeyZ},
|
||||||
{.name = "key_cup", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCUp},
|
{.name = "key_cup", .type = CONFIG_TYPE_BIND, .uintValue = configKeyCUp},
|
||||||
{.name = "key_cdown", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCDown},
|
{.name = "key_cdown", .type = CONFIG_TYPE_BIND, .uintValue = configKeyCDown},
|
||||||
{.name = "key_cleft", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCLeft},
|
{.name = "key_cleft", .type = CONFIG_TYPE_BIND, .uintValue = configKeyCLeft},
|
||||||
{.name = "key_cright", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyCRight},
|
{.name = "key_cright", .type = CONFIG_TYPE_BIND, .uintValue = configKeyCRight},
|
||||||
{.name = "key_stickup", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickUp},
|
{.name = "key_stickup", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickUp},
|
||||||
{.name = "key_stickdown", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickDown},
|
{.name = "key_stickdown", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickDown},
|
||||||
{.name = "key_stickleft", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickLeft},
|
{.name = "key_stickleft", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickLeft},
|
||||||
{.name = "key_stickright", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyStickRight},
|
{.name = "key_stickright", .type = CONFIG_TYPE_BIND, .uintValue = configKeyStickRight},
|
||||||
{.name = "joy_a", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyA},
|
|
||||||
{.name = "joy_b", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyB},
|
|
||||||
{.name = "joy_start", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyStart},
|
|
||||||
{.name = "joy_l", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyL},
|
|
||||||
{.name = "joy_r", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyR},
|
|
||||||
{.name = "joy_z", .type = CONFIG_TYPE_UINT, .uintValue = &configJoyZ},
|
|
||||||
{.name = "mouse_a", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseA},
|
|
||||||
{.name = "mouse_b", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseB},
|
|
||||||
{.name = "mouse_l", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseL},
|
|
||||||
{.name = "mouse_r", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseR},
|
|
||||||
{.name = "mouse_z", .type = CONFIG_TYPE_UINT, .uintValue = &configMouseZ},
|
|
||||||
#ifdef BETTERCAMERA
|
#ifdef BETTERCAMERA
|
||||||
{.name = "bettercam_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configEnableCamera},
|
{.name = "bettercam_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configEnableCamera},
|
||||||
{.name = "bettercam_mouse_look", .type = CONFIG_TYPE_BOOL, .boolValue = &configCameraMouse},
|
{.name = "bettercam_mouse_look", .type = CONFIG_TYPE_BOOL, .boolValue = &configCameraMouse},
|
||||||
|
@ -108,7 +87,7 @@ static const struct ConfigOption options[] = {
|
||||||
{.name = "bettercam_aggression", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraAggr},
|
{.name = "bettercam_aggression", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraAggr},
|
||||||
{.name = "bettercam_pan_level", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraPan},
|
{.name = "bettercam_pan_level", .type = CONFIG_TYPE_UINT, .uintValue = &configCameraPan},
|
||||||
#endif
|
#endif
|
||||||
{.name = "skip_intro", .type = CONFIG_TYPE_UINT, .uintValue = &configSkipIntro},
|
//{.name = "skip_intro", .type = CONFIG_TYPE_UINT, .uintValue = &configSkipIntro}, // Add this back!
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reads an entire line from a file (excluding the newline character) and returns an allocated string
|
// Reads an entire line from a file (excluding the newline character) and returns an allocated string
|
||||||
|
@ -209,9 +188,13 @@ void configfile_load(const char *filename) {
|
||||||
|
|
||||||
while (isspace(*p))
|
while (isspace(*p))
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
|
if (!*p || *p == '#') // comment or empty line
|
||||||
|
continue;
|
||||||
|
|
||||||
numTokens = tokenize_string(p, 2, tokens);
|
numTokens = tokenize_string(p, 2, tokens);
|
||||||
if (numTokens != 0) {
|
if (numTokens != 0) {
|
||||||
if (numTokens == 2) {
|
if (numTokens >= 2) {
|
||||||
const struct ConfigOption *option = NULL;
|
const struct ConfigOption *option = NULL;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
|
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
|
||||||
|
@ -233,6 +216,10 @@ void configfile_load(const char *filename) {
|
||||||
case CONFIG_TYPE_UINT:
|
case CONFIG_TYPE_UINT:
|
||||||
sscanf(tokens[1], "%u", option->uintValue);
|
sscanf(tokens[1], "%u", option->uintValue);
|
||||||
break;
|
break;
|
||||||
|
case CONFIG_TYPE_BIND:
|
||||||
|
for (int i = 0; i < MAX_BINDS && i < numTokens - 1; ++i)
|
||||||
|
sscanf(tokens[i + 1], "%x", option->uintValue + i);
|
||||||
|
break;
|
||||||
case CONFIG_TYPE_FLOAT:
|
case CONFIG_TYPE_FLOAT:
|
||||||
sscanf(tokens[1], "%f", option->floatValue);
|
sscanf(tokens[1], "%f", option->floatValue);
|
||||||
break;
|
break;
|
||||||
|
@ -275,6 +262,12 @@ void configfile_save(const char *filename) {
|
||||||
case CONFIG_TYPE_FLOAT:
|
case CONFIG_TYPE_FLOAT:
|
||||||
fprintf(file, "%s %f\n", option->name, *option->floatValue);
|
fprintf(file, "%s %f\n", option->name, *option->floatValue);
|
||||||
break;
|
break;
|
||||||
|
case CONFIG_TYPE_BIND:
|
||||||
|
fprintf(file, "%s ", option->name);
|
||||||
|
for (int i = 0; i < MAX_BINDS; ++i)
|
||||||
|
fprintf(file, "%04x ", option->uintValue[i]);
|
||||||
|
fprintf(file, "\n");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0); // unknown type
|
assert(0); // unknown type
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,34 +4,23 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define CONFIG_FILE "sm64config.txt"
|
#define CONFIG_FILE "sm64config.txt"
|
||||||
|
#define MAX_BINDS 3
|
||||||
|
|
||||||
extern bool configFullscreen;
|
extern bool configFullscreen;
|
||||||
extern unsigned int configKeyA;
|
extern unsigned int configKeyA[];
|
||||||
extern unsigned int configKeyB;
|
extern unsigned int configKeyB[];
|
||||||
extern unsigned int configKeyStart;
|
extern unsigned int configKeyStart[];
|
||||||
extern unsigned int configKeyL;
|
extern unsigned int configKeyL[];
|
||||||
extern unsigned int configKeyR;
|
extern unsigned int configKeyR[];
|
||||||
extern unsigned int configKeyZ;
|
extern unsigned int configKeyZ[];
|
||||||
extern unsigned int configKeyCUp;
|
extern unsigned int configKeyCUp[];
|
||||||
extern unsigned int configKeyCDown;
|
extern unsigned int configKeyCDown[];
|
||||||
extern unsigned int configKeyCLeft;
|
extern unsigned int configKeyCLeft[];
|
||||||
extern unsigned int configKeyCRight;
|
extern unsigned int configKeyCRight[];
|
||||||
extern unsigned int configKeyStickUp;
|
extern unsigned int configKeyStickUp[];
|
||||||
extern unsigned int configKeyStickDown;
|
extern unsigned int configKeyStickDown[];
|
||||||
extern unsigned int configKeyStickLeft;
|
extern unsigned int configKeyStickLeft[];
|
||||||
extern unsigned int configKeyStickRight;
|
extern unsigned int configKeyStickRight[];
|
||||||
extern unsigned int configJoyA;
|
|
||||||
extern unsigned int configJoyB;
|
|
||||||
extern unsigned int configJoyStart;
|
|
||||||
extern unsigned int configJoyL;
|
|
||||||
extern unsigned int configJoyR;
|
|
||||||
extern unsigned int configJoyZ;
|
|
||||||
extern unsigned int configMouseA;
|
|
||||||
extern unsigned int configMouseB;
|
|
||||||
extern unsigned int configMouseStart;
|
|
||||||
extern unsigned int configMouseL;
|
|
||||||
extern unsigned int configMouseR;
|
|
||||||
extern unsigned int configMouseZ;
|
|
||||||
#ifdef BETTERCAMERA
|
#ifdef BETTERCAMERA
|
||||||
extern unsigned int configCameraXSens;
|
extern unsigned int configCameraXSens;
|
||||||
extern unsigned int configCameraYSens;
|
extern unsigned int configCameraYSens;
|
||||||
|
|
|
@ -2,15 +2,21 @@
|
||||||
#define CONTROLLER_API
|
#define CONTROLLER_API
|
||||||
|
|
||||||
#define DEADZONE 4960
|
#define DEADZONE 4960
|
||||||
|
#define VK_INVALID 0xFFFF
|
||||||
// Analog camera movement by Pathétique (github.com/vrmiguel), y0shin and Mors
|
#define VK_SIZE 0x1000
|
||||||
// Contribute or communicate bugs at github.com/vrmiguel/sm64-analog-camera
|
|
||||||
|
|
||||||
#include <ultra64.h>
|
#include <ultra64.h>
|
||||||
|
|
||||||
struct ControllerAPI {
|
struct ControllerAPI {
|
||||||
void (*init)(void);
|
const u32 vkbase; // base number in the virtual keyspace (e.g. keyboard is 0x0000-0x1000)
|
||||||
void (*read)(OSContPad *pad);
|
void (*init)(void); // call once, also calls reconfig()
|
||||||
|
void (*read)(OSContPad *pad); // read controller and update N64 pad values
|
||||||
|
u32 (*rawkey)(void); // returns last pressed virtual key or VK_INVALID if none
|
||||||
|
void (*reconfig)(void); // (optional) call when bindings have changed
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// used for binding keys
|
||||||
|
u32 controller_get_raw_key(void);
|
||||||
|
void controller_reconfigure(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,3 +56,18 @@ void osContGetReadData(OSContPad *pad) {
|
||||||
controller_implementations[i]->read(pad);
|
controller_implementations[i]->read(pad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 controller_get_raw_key(void) {
|
||||||
|
for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) {
|
||||||
|
u32 vk = controller_implementations[i]->rawkey();
|
||||||
|
if (vk != VK_INVALID) return vk + controller_implementations[i]->vkbase;
|
||||||
|
}
|
||||||
|
return VK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void controller_reconfigure(void) {
|
||||||
|
for (size_t i = 0; i < sizeof(controller_implementations) / sizeof(struct ControllerAPI *); i++) {
|
||||||
|
if (controller_implementations[i]->reconfig)
|
||||||
|
controller_implementations[i]->reconfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,14 +8,19 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../configfile.h"
|
#include "../configfile.h"
|
||||||
|
#include "controller_keyboard.h"
|
||||||
|
|
||||||
static int keyboard_buttons_down;
|
static int keyboard_buttons_down;
|
||||||
|
|
||||||
static int keyboard_mapping[14][2];
|
#define MAX_KEYBINDS 64
|
||||||
|
static int keyboard_mapping[MAX_KEYBINDS][2];
|
||||||
|
static int num_keybinds = 0;
|
||||||
|
|
||||||
|
static u32 keyboard_lastkey = VK_INVALID;
|
||||||
|
|
||||||
static int keyboard_map_scancode(int scancode) {
|
static int keyboard_map_scancode(int scancode) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
for (size_t i = 0; i < sizeof(keyboard_mapping) / sizeof(keyboard_mapping[0]); i++) {
|
for (int i = 0; i < num_keybinds; i++) {
|
||||||
if (keyboard_mapping[i][0] == scancode) {
|
if (keyboard_mapping[i][0] == scancode) {
|
||||||
ret |= keyboard_mapping[i][1];
|
ret |= keyboard_mapping[i][1];
|
||||||
}
|
}
|
||||||
|
@ -26,12 +31,15 @@ static int keyboard_map_scancode(int scancode) {
|
||||||
bool keyboard_on_key_down(int scancode) {
|
bool keyboard_on_key_down(int scancode) {
|
||||||
int mapped = keyboard_map_scancode(scancode);
|
int mapped = keyboard_map_scancode(scancode);
|
||||||
keyboard_buttons_down |= mapped;
|
keyboard_buttons_down |= mapped;
|
||||||
|
keyboard_lastkey = scancode;
|
||||||
return mapped != 0;
|
return mapped != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool keyboard_on_key_up(int scancode) {
|
bool keyboard_on_key_up(int scancode) {
|
||||||
int mapped = keyboard_map_scancode(scancode);
|
int mapped = keyboard_map_scancode(scancode);
|
||||||
keyboard_buttons_down &= ~mapped;
|
keyboard_buttons_down &= ~mapped;
|
||||||
|
if (keyboard_lastkey == (u32) scancode)
|
||||||
|
keyboard_lastkey = VK_INVALID;
|
||||||
return mapped != 0;
|
return mapped != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,28 +47,38 @@ void keyboard_on_all_keys_up(void) {
|
||||||
keyboard_buttons_down = 0;
|
keyboard_buttons_down = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_keyboard_mapping(int index, int mask, int scancode) {
|
static void keyboard_add_binds(int mask, unsigned int *scancode) {
|
||||||
keyboard_mapping[index][0] = scancode;
|
for (int i = 0; i < MAX_BINDS && num_keybinds < MAX_KEYBINDS; ++i) {
|
||||||
keyboard_mapping[index][1] = mask;
|
if (scancode[i] < VK_BASE_KEYBOARD + VK_SIZE) {
|
||||||
|
keyboard_mapping[num_keybinds][0] = scancode[i];
|
||||||
|
keyboard_mapping[num_keybinds][1] = mask;
|
||||||
|
num_keybinds++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_bindkeys(void) {
|
||||||
|
bzero(keyboard_mapping, sizeof(keyboard_mapping));
|
||||||
|
num_keybinds = 0;
|
||||||
|
|
||||||
|
keyboard_add_binds(0x80000, configKeyStickUp);
|
||||||
|
keyboard_add_binds(0x10000, configKeyStickLeft);
|
||||||
|
keyboard_add_binds(0x40000, configKeyStickDown);
|
||||||
|
keyboard_add_binds(0x20000, configKeyStickRight);
|
||||||
|
keyboard_add_binds(A_BUTTON, configKeyA);
|
||||||
|
keyboard_add_binds(B_BUTTON, configKeyB);
|
||||||
|
keyboard_add_binds(Z_TRIG, configKeyZ);
|
||||||
|
keyboard_add_binds(U_CBUTTONS, configKeyCUp);
|
||||||
|
keyboard_add_binds(L_CBUTTONS, configKeyCLeft);
|
||||||
|
keyboard_add_binds(D_CBUTTONS, configKeyCDown);
|
||||||
|
keyboard_add_binds(R_CBUTTONS, configKeyCRight);
|
||||||
|
keyboard_add_binds(L_TRIG, configKeyL);
|
||||||
|
keyboard_add_binds(R_TRIG, configKeyR);
|
||||||
|
keyboard_add_binds(START_BUTTON, configKeyStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboard_init(void) {
|
static void keyboard_init(void) {
|
||||||
int i = 0;
|
keyboard_bindkeys();
|
||||||
|
|
||||||
set_keyboard_mapping(i++, 0x80000, configKeyStickUp);
|
|
||||||
set_keyboard_mapping(i++, 0x10000, configKeyStickLeft);
|
|
||||||
set_keyboard_mapping(i++, 0x40000, configKeyStickDown);
|
|
||||||
set_keyboard_mapping(i++, 0x20000, configKeyStickRight);
|
|
||||||
set_keyboard_mapping(i++, A_BUTTON, configKeyA);
|
|
||||||
set_keyboard_mapping(i++, B_BUTTON, configKeyB);
|
|
||||||
set_keyboard_mapping(i++, Z_TRIG, configKeyZ);
|
|
||||||
set_keyboard_mapping(i++, U_CBUTTONS, configKeyCUp);
|
|
||||||
set_keyboard_mapping(i++, L_CBUTTONS, configKeyCLeft);
|
|
||||||
set_keyboard_mapping(i++, D_CBUTTONS, configKeyCDown);
|
|
||||||
set_keyboard_mapping(i++, R_CBUTTONS, configKeyCRight);
|
|
||||||
set_keyboard_mapping(i++, L_TRIG, configKeyL);
|
|
||||||
set_keyboard_mapping(i++, R_TRIG, configKeyR);
|
|
||||||
set_keyboard_mapping(i++, START_BUTTON, configKeyStart);
|
|
||||||
|
|
||||||
#ifdef TARGET_WEB
|
#ifdef TARGET_WEB
|
||||||
controller_emscripten_keyboard_init();
|
controller_emscripten_keyboard_init();
|
||||||
|
@ -83,7 +101,16 @@ static void keyboard_read(OSContPad *pad) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 keyboard_rawkey(void) {
|
||||||
|
const u32 ret = keyboard_lastkey;
|
||||||
|
keyboard_lastkey = VK_INVALID;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
struct ControllerAPI controller_keyboard = {
|
struct ControllerAPI controller_keyboard = {
|
||||||
|
VK_BASE_KEYBOARD,
|
||||||
keyboard_init,
|
keyboard_init,
|
||||||
keyboard_read
|
keyboard_read,
|
||||||
|
keyboard_rawkey,
|
||||||
|
keyboard_bindkeys,
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "controller_api.h"
|
#include "controller_api.h"
|
||||||
|
|
||||||
|
# define VK_BASE_KEYBOARD 0x0000
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,7 +23,14 @@ static void tas_read(OSContPad *pad) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 tas_rawkey(void) {
|
||||||
|
return VK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
struct ControllerAPI controller_recorded_tas = {
|
struct ControllerAPI controller_recorded_tas = {
|
||||||
|
VK_INVALID,
|
||||||
tas_init,
|
tas_init,
|
||||||
tas_read
|
tas_read,
|
||||||
|
tas_rawkey,
|
||||||
|
NULL, // no rebinding
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,9 +11,15 @@
|
||||||
#include <ultra64.h>
|
#include <ultra64.h>
|
||||||
|
|
||||||
#include "controller_api.h"
|
#include "controller_api.h"
|
||||||
|
#include "controller_sdl.h"
|
||||||
#include "../configfile.h"
|
#include "../configfile.h"
|
||||||
|
|
||||||
|
// mouse buttons are also in the controller namespace (why), just offset 0x100
|
||||||
|
#define VK_OFS_SDL_MOUSE 0x0100
|
||||||
|
#define VK_BASE_SDL_MOUSE (VK_BASE_SDL_GAMEPAD + VK_OFS_SDL_MOUSE)
|
||||||
|
#define MAX_JOYBINDS 32
|
||||||
|
#define MAX_MOUSEBUTTONS 8 // arbitrary
|
||||||
|
|
||||||
extern int16_t rightx;
|
extern int16_t rightx;
|
||||||
extern int16_t righty;
|
extern int16_t righty;
|
||||||
|
|
||||||
|
@ -27,6 +33,51 @@ extern u8 newcam_mouse;
|
||||||
static bool init_ok;
|
static bool init_ok;
|
||||||
static SDL_GameController *sdl_cntrl;
|
static SDL_GameController *sdl_cntrl;
|
||||||
|
|
||||||
|
|
||||||
|
static u32 num_joy_binds = 0;
|
||||||
|
static u32 num_mouse_binds = 0;
|
||||||
|
static u32 joy_binds[MAX_JOYBINDS][2];
|
||||||
|
static u32 mouse_binds[MAX_JOYBINDS][2];
|
||||||
|
|
||||||
|
static bool joy_buttons[SDL_CONTROLLER_BUTTON_MAX ] = { false };
|
||||||
|
static u32 mouse_buttons = 0;
|
||||||
|
static u32 last_mouse = VK_INVALID;
|
||||||
|
static u32 last_joybutton = VK_INVALID;
|
||||||
|
|
||||||
|
static inline void controller_add_binds(const u32 mask, const u32 *btns) {
|
||||||
|
for (u32 i = 0; i < MAX_BINDS; ++i) {
|
||||||
|
if (btns[i] >= VK_BASE_SDL_GAMEPAD && btns[i] <= VK_BASE_SDL_GAMEPAD + VK_SIZE) {
|
||||||
|
if (btns[i] >= VK_BASE_SDL_MOUSE && num_joy_binds < MAX_JOYBINDS) {
|
||||||
|
mouse_binds[num_mouse_binds][0] = btns[i] - VK_BASE_SDL_MOUSE;
|
||||||
|
mouse_binds[num_mouse_binds][1] = mask;
|
||||||
|
++num_mouse_binds;
|
||||||
|
} else if (num_mouse_binds < MAX_JOYBINDS) {
|
||||||
|
joy_binds[num_joy_binds][0] = btns[i] - VK_BASE_SDL_GAMEPAD;
|
||||||
|
joy_binds[num_joy_binds][1] = mask;
|
||||||
|
++num_joy_binds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void controller_sdl_bind(void) {
|
||||||
|
bzero(joy_binds, sizeof(joy_binds));
|
||||||
|
bzero(mouse_binds, sizeof(mouse_binds));
|
||||||
|
num_joy_binds = 0;
|
||||||
|
num_mouse_binds = 0;
|
||||||
|
|
||||||
|
controller_add_binds(A_BUTTON, configKeyA);
|
||||||
|
controller_add_binds(B_BUTTON, configKeyB);
|
||||||
|
controller_add_binds(Z_TRIG, configKeyZ);
|
||||||
|
controller_add_binds(U_CBUTTONS, configKeyCUp);
|
||||||
|
controller_add_binds(L_CBUTTONS, configKeyCLeft);
|
||||||
|
controller_add_binds(D_CBUTTONS, configKeyCDown);
|
||||||
|
controller_add_binds(R_CBUTTONS, configKeyCRight);
|
||||||
|
controller_add_binds(L_TRIG, configKeyL);
|
||||||
|
controller_add_binds(R_TRIG, configKeyR);
|
||||||
|
controller_add_binds(START_BUTTON, configKeyStart);
|
||||||
|
}
|
||||||
|
|
||||||
static void controller_sdl_init(void) {
|
static void controller_sdl_init(void) {
|
||||||
if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) {
|
if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) {
|
||||||
fprintf(stderr, "SDL init error: %s\n", SDL_GetError());
|
fprintf(stderr, "SDL init error: %s\n", SDL_GetError());
|
||||||
|
@ -39,6 +90,8 @@ static void controller_sdl_init(void) {
|
||||||
SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
controller_sdl_bind();
|
||||||
|
|
||||||
init_ok = true;
|
init_ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,13 +106,16 @@ static void controller_sdl_read(OSContPad *pad) {
|
||||||
else
|
else
|
||||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||||
|
|
||||||
const u32 mbuttons = SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
u32 mouse = SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < num_mouse_binds; ++i)
|
||||||
|
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
|
||||||
|
pad->button |= mouse_binds[i][1];
|
||||||
|
|
||||||
|
// remember buttons that changed from 0 to 1
|
||||||
|
last_mouse = (mouse_buttons ^ mouse) & mouse;
|
||||||
|
mouse_buttons = mouse;
|
||||||
|
|
||||||
if (configMouseA && (mbuttons & SDL_BUTTON(configMouseA))) pad->button |= A_BUTTON;
|
|
||||||
if (configMouseB && (mbuttons & SDL_BUTTON(configMouseB))) pad->button |= B_BUTTON;
|
|
||||||
if (configMouseL && (mbuttons & SDL_BUTTON(configMouseL))) pad->button |= L_TRIG;
|
|
||||||
if (configMouseR && (mbuttons & SDL_BUTTON(configMouseR))) pad->button |= R_TRIG;
|
|
||||||
if (configMouseZ && (mbuttons & SDL_BUTTON(configMouseZ))) pad->button |= Z_TRIG;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SDL_GameControllerUpdate();
|
SDL_GameControllerUpdate();
|
||||||
|
@ -82,12 +138,16 @@ static void controller_sdl_read(OSContPad *pad) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyStart)) pad->button |= START_BUTTON;
|
for (u32 i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i) {
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyZ)) pad->button |= Z_TRIG;
|
const bool new = SDL_GameControllerGetButton(sdl_cntrl, i);
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyL)) pad->button |= L_TRIG;
|
const bool pressed = !joy_buttons[i] && new;
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyR)) pad->button |= R_TRIG;
|
joy_buttons[i] = new;
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyA)) pad->button |= A_BUTTON;
|
if (pressed) last_joybutton = i;
|
||||||
if (SDL_GameControllerGetButton(sdl_cntrl, configJoyB)) pad->button |= B_BUTTON;
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < num_joy_binds; ++i)
|
||||||
|
if (joy_buttons[joy_binds[i][0]])
|
||||||
|
pad->button |= joy_binds[i][1];
|
||||||
|
|
||||||
int16_t leftx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTX);
|
int16_t leftx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTX);
|
||||||
int16_t lefty = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTY);
|
int16_t lefty = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTY);
|
||||||
|
@ -127,7 +187,27 @@ static void controller_sdl_read(OSContPad *pad) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 controller_sdl_rawkey(void) {
|
||||||
|
if (last_joybutton != VK_INVALID) {
|
||||||
|
const u32 ret = last_joybutton;
|
||||||
|
last_joybutton = VK_INVALID;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_MOUSEBUTTONS; ++i) {
|
||||||
|
if (last_mouse & SDL_BUTTON(i)) {
|
||||||
|
const u32 ret = VK_OFS_SDL_MOUSE + i;
|
||||||
|
last_mouse = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
struct ControllerAPI controller_sdl = {
|
struct ControllerAPI controller_sdl = {
|
||||||
|
VK_BASE_SDL_GAMEPAD,
|
||||||
controller_sdl_init,
|
controller_sdl_init,
|
||||||
controller_sdl_read
|
controller_sdl_read,
|
||||||
|
controller_sdl_rawkey,
|
||||||
|
controller_sdl_bind,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "controller_api.h"
|
#include "controller_api.h"
|
||||||
|
|
||||||
|
#define VK_BASE_SDL_GAMEPAD 0x1000
|
||||||
|
|
||||||
extern struct ControllerAPI controller_sdl;
|
extern struct ControllerAPI controller_sdl;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue