VR: the game's actions moved between the controllers' buttons

A BUTTONS page in the VR options (between PLAY and MORE) puts jump, the
flashlight (held: switch grenades), action/reload, switch weapon, crouch,
zoom and melee on any of seven buttons: A, B, X, Y, the move and turning
sticks' clicks and the weapon hand's grip. Moving an action to a button
swaps it with the action there, so every action always has a button;
"Reset buttons to defaults" puts them back. The triggers, the free hand's
grip (both hands on the weapon), the menu button, the Steam Frame's
bumpers, D-pad and View button keep what they do, and the menus keep
their buttons.

Settings vr.button_jump, _light, _action, _weapon, _crouch, _zoom and
_melee ("a", "b", "x", "y", "move_stick", "turn_stick", "grip"; the
defaults are today's layout), named as right-handed. vr.c reads them with
the live settings and, after the left-handed mirroring
(controllers_mirrored), reads each action's button and hands it on as the
button that action has by default (controls_remapped), so xinput_sdl.c's
table is unchanged and the defaults change nothing. Because the mapping
sits after the mirroring it works the same on the Quest's Touch and the
Steam Frame's controllers (mirrored on the Frame the left D-pad is A, B,
X, Y), and a mirrored player's swaps are the mirror image of the
right-handed ones. The guest/host ABI is unchanged.

- The melee's aim and the weapon's jab (melee_update) follow the melee's
  button, not the grip as such; the grips holding a Warthog's wheel press
  nothing whatever action the grip has (moved from xinput_sdl.c).
- The controller buttons page (now on the BUTTONS page) shows each action
  under the controller and name of its button, for both layouts and the
  mirrored hands; its ON FOOT tab no longer draws the MENUS tab's notes
  over its own.
- debug.vr_options (Android, false): the VR options panel off the
  headset, for checking its pages in the emulator.

Checked in the emulator (debug.vr_options): the rows, swaps, reset, the
controls page right- and left-handed, the settings kept over a restart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Stefan MaierandClaude Opus 5.5 committed 2026-10-06 21:57:15 +02:00
1 parent 3b5796f1a0
commit cf19bcfdfa
5 files changed
+443 -56

No files matched your search

+33
View File
@@ -252,6 +252,39 @@ int halo_vr_controller_layout(void);
/* the hand that holds the weapon (HALO_XR_HAND_*: 1 the right, 0 the left,
vr.handedness) */
int halo_vr_weapon_hand(void);
/* The game's actions on the controllers' buttons (vr.button_*; the VR
options' BUTTONS page): each action on one of seven buttons, named as
right-handed (A and B on the right controller, X and Y, the Quest's, on
the left; the move stick's click, the turning stick's, the weapon hand's
grip); left-handed with vr.mirror_controls, their mirror images. The
actions are numbered by the button each has by default. The triggers, the
free hand's grip, the menu button and the Steam Frame's bumpers, D-pad and
View button keep theirs; the menus keep the buttons as they are. */
enum
{
HALO_VR_INPUT_A = 0,
HALO_VR_INPUT_B,
HALO_VR_INPUT_X,
HALO_VR_INPUT_Y,
HALO_VR_INPUT_MOVE_STICK,
HALO_VR_INPUT_TURN_STICK,
HALO_VR_INPUT_GRIP,
HALO_VR_INPUT_COUNT,
HALO_VR_ACTION_JUMP = HALO_VR_INPUT_A,
HALO_VR_ACTION_LIGHT = HALO_VR_INPUT_B, /* a tap the flashlight; held, switch grenades */
HALO_VR_ACTION_ACTION = HALO_VR_INPUT_X, /* action, reload */
HALO_VR_ACTION_WEAPON = HALO_VR_INPUT_Y, /* switch weapon */
HALO_VR_ACTION_CROUCH = HALO_VR_INPUT_MOVE_STICK,
HALO_VR_ACTION_ZOOM = HALO_VR_INPUT_TURN_STICK,
HALO_VR_ACTION_MELEE = HALO_VR_INPUT_GRIP,
HALO_VR_ACTION_COUNT = HALO_VR_INPUT_COUNT,
};
/* an action's setting ("vr.button_jump"), a button's value in it ("a"),
and the button an action is on, as set */
const char *halo_vr_action_setting(int action);
const char *halo_vr_input_value(int input);
int halo_vr_action_input(int action);
/* the graphics preset (vr.graphics; HALO_VR_GRAPHICS_HIGH outside VR): which
effects are drawn (port/linux/game/vr_graphics.c), and with "max" the
models lit for each pixel and larger shadows (d3d8_gl.c) */
+25
View File
@@ -201,6 +201,28 @@ static const struct config_setting config_settings[] =
"and the left one turns, X jumps and A reloads (on the Steam Frame the\n"
"D-pad takes A, B, X and Y as their mirror image); false keeps them as\n"
"right-handed. The menus keep their buttons either way." },
{ "vr.button_jump", _config_string, "\"a\"", "HALO_VR_BUTTON_JUMP", _environment_value, _platform_android,
"The button each of the game's actions is on (the VR options' BUTTONS\n"
"page swaps them): \"a\", \"b\", \"x\", \"y\" (A and B on the right\n"
"controller, X and Y the Quest's on the left; the Steam Frame has all\n"
"four on the right), \"move_stick\" and \"turn_stick\" (their clicks),\n"
"\"grip\" (the weapon hand's), named as right-handed: left-handed with\n"
"mirror_controls, their mirror images. Jump," },
{ "vr.button_light", _config_string, "\"b\"", "HALO_VR_BUTTON_LIGHT", _environment_value, _platform_android,
"the flashlight (held: switch grenades)," },
{ "vr.button_action", _config_string, "\"x\"", "HALO_VR_BUTTON_ACTION", _environment_value, _platform_android,
"action and reload," },
{ "vr.button_weapon", _config_string, "\"y\"", "HALO_VR_BUTTON_WEAPON", _environment_value, _platform_android,
"switch weapon," },
{ "vr.button_crouch", _config_string, "\"move_stick\"", "HALO_VR_BUTTON_CROUCH", _environment_value,
_platform_android,
"crouch," },
{ "vr.button_zoom", _config_string, "\"turn_stick\"", "HALO_VR_BUTTON_ZOOM", _environment_value,
_platform_android,
"zoom" },
{ "vr.button_melee", _config_string, "\"grip\"", "HALO_VR_BUTTON_MELEE", _environment_value, _platform_android,
"and melee. The triggers, the free hand's grip and the menu button keep\n"
"theirs, as do the menus." },
{ "vr.laser", _config_boolean, "false", "HALO_VR_LASER", _environment_value, _platform_android,
"A laser from the weapon to what it aims at (with aim_with = \"controller\")." },
{ "vr.crosshair", _config_boolean, "true", "HALO_VR_CROSSHAIR", _environment_value, _platform_android,
@@ -573,6 +595,9 @@ static const struct config_setting config_settings[] =
"The headset's layer copies: 1 deferred (no waits for the GL thread or the\n"
"GPU in the middle of the frame), 0 each one restored and released at once,\n"
"-1 as the runtime needs (deferred on SteamVR). Read when the app starts." },
{ "debug.vr_options", _config_boolean, "false", "HALO_DEBUG_VR_OPTIONS", _environment_value, _platform_android,
"Off the headset (the emulator), show the VR options panel on the main\n"
"and pause menus all the same, for checking its pages." },
{ "debug.mirror_first_person", _config_boolean, "false", "HALO_MIRROR_FIRST_PERSON", _environment_value,
_platform_android,
"Off the headset (flat), the first-person weapon drawn mirrored, as the\n"
+107 -10
View File
@@ -17,6 +17,28 @@ yaw plus the head's.
#include "halo_vr.h"
/* the actions' settings and the buttons' values in them (halo_vr.h's
HALO_VR_ACTION_* and HALO_VR_INPUT_*), by number */
static const char *const vr_action_settings[HALO_VR_ACTION_COUNT] =
{
"vr.button_jump", "vr.button_light", "vr.button_action", "vr.button_weapon", "vr.button_crouch",
"vr.button_zoom", "vr.button_melee",
};
static const char *const vr_input_values[HALO_VR_INPUT_COUNT] =
{
"a", "b", "x", "y", "move_stick", "turn_stick", "grip",
};
const char *halo_vr_action_setting(int action)
{
return action >= 0 && action < HALO_VR_ACTION_COUNT ? vr_action_settings[action] : "";
}
const char *halo_vr_input_value(int input)
{
return input >= 0 && input < HALO_VR_INPUT_COUNT ? vr_input_values[input] : "";
}
#ifdef HALO_ANDROID
#include "platform.h"
@@ -220,9 +242,9 @@ static struct
/* until when a melee attack aims where the head looks: its damage is
dealt some ticks into the attack, along the unit's aim */
unsigned long long melee_aim_until_us;
int melee_grip_down;
int melee_button_down;
float melee_strength; /* 0..1, the last attack's swing */
unsigned long long melee_jab_start_us; /* the weapon hand's grip's attack: the weapon jabs */
unsigned long long melee_jab_start_us; /* the melee button's attack: the weapon jabs */
/* the laser along the barrel, for the frame it was set in */
unsigned long frame_number;
unsigned long laser_frame;
@@ -250,6 +272,9 @@ static struct
vr.mirror_controls the sticks and face buttons mirrored too */
int left_handed;
int mirror_controls;
/* the button each action is on (vr.button_*: HALO_VR_INPUT_* by
HALO_VR_ACTION_*) */
int action_inputs[HALO_VR_ACTION_COUNT];
/* vr.refresh_rate as last asked for (the VR options change it), and
vr.resolution_scale as the app started with it */
float refresh_rate_wanted;
@@ -307,6 +332,7 @@ static int name_pose(const float point[3], struct halo_xr_pose *pose, float *wid
static int weapon_hand_tracked(short local_player_index);
static void controller_axes(float forward[3], float up[3], float right[3]);
static void hand_offset(float out[3]);
static void controls_in_play(struct halo_xr_hand hands[HALO_XR_HAND_COUNT]);
/* the hand that holds the weapon, the free one (the grenade, the
foregrip), and the one whose stick turns the body and steers */
@@ -517,6 +543,12 @@ static void vr_read_live_settings(void)
vr.left_handed = left_handed;
vr.mirror_controls = config_boolean("vr.mirror_controls");
}
{
int action;
for (action = 0; action < HALO_VR_ACTION_COUNT; action++)
vr.action_inputs[action] = halo_vr_action_input(action);
}
{
/* (the refresh rate changes at once where the runtime lets it) */
float refresh_rate = (float)config_real("vr.refresh_rate");
@@ -619,6 +651,22 @@ int halo_vr_weapon_hand(void)
return weapon_hand();
}
int halo_vr_action_input(int action)
{
const char *value;
int input;
if (action < 0 || action >= HALO_VR_ACTION_COUNT)
return HALO_VR_INPUT_A;
value = config_string(vr_action_settings[action]);
for (input = 0; input < HALO_VR_INPUT_COUNT; input++)
{
if (!strcmp(value, vr_input_values[input]))
return input;
}
return action;
}
int halo_vr_refresh_rates(float *rates, int maximum, float *current)
{
*current = 0.0f;
@@ -980,18 +1028,21 @@ static void melee_update(void)
vr.hand_last_us = now;
{
/* the weapon hand's grip's melee attack (xinput_sdl.c) aims the
same way */
int grip_down = vr.frame.hands[weapon_hand()].active &&
(vr.frame.hands[weapon_hand()].buttons & HALO_XR_BUTTON_SQUEEZE);
/* the melee button's attack (xinput_sdl.c; the weapon hand's grip
unless vr.button_melee moves it) aims the same way */
struct halo_xr_hand hands[HALO_XR_HAND_COUNT];
int button_down;
if (grip_down && !vr.melee_grip_down)
memcpy(hands, vr.frame.hands, sizeof(hands));
controls_in_play(hands);
button_down = (hands[HALO_XR_HAND_RIGHT].buttons & HALO_XR_BUTTON_SQUEEZE) != 0;
if (button_down && !vr.melee_button_down)
{
vr.melee_aim_until_us = now + 700000;
vr.melee_strength = 0.75f;
vr.melee_jab_start_us = now;
}
vr.melee_grip_down = grip_down;
vr.melee_button_down = button_down;
}
quaternion_rotate(vr.frame.head.orientation, look, facing);
facing[1] = 0.0f;
@@ -3046,6 +3097,51 @@ static void controllers_mirrored(struct halo_xr_hand hands[HALO_XR_HAND_COUNT])
}
}
/* The buttons the actions are on (vr.button_*), as the gamepad's sides
have them once mirrored: A and B the right hand's, X and Y the left's
A and B, the move stick's click the left's, the turning stick's the
right's, the grip the right's (the weapon hand's). Each action's button
is read and handed on as the button the action has by default, which
xinput_sdl.c turns into it; with the defaults nothing changes. The grips
holding a Warthog's wheel press nothing. */
static const int input_hands[HALO_VR_INPUT_COUNT] =
{
HALO_XR_HAND_RIGHT, HALO_XR_HAND_RIGHT, HALO_XR_HAND_LEFT, HALO_XR_HAND_LEFT, HALO_XR_HAND_LEFT,
HALO_XR_HAND_RIGHT, HALO_XR_HAND_RIGHT,
};
static const int input_buttons[HALO_VR_INPUT_COUNT] =
{
HALO_XR_BUTTON_A, HALO_XR_BUTTON_B, HALO_XR_BUTTON_A, HALO_XR_BUTTON_B, HALO_XR_BUTTON_THUMBSTICK,
HALO_XR_BUTTON_THUMBSTICK, HALO_XR_BUTTON_SQUEEZE,
};
static void controls_remapped(struct halo_xr_hand hands[HALO_XR_HAND_COUNT])
{
int down[HALO_VR_INPUT_COUNT];
int input, action;
for (input = 0; input < HALO_VR_INPUT_COUNT; input++)
down[input] = (hands[input_hands[input]].buttons & input_buttons[input]) != 0;
if (vr.wheel_hands)
down[HALO_VR_INPUT_GRIP] = 0;
for (input = 0; input < HALO_VR_INPUT_COUNT; input++)
hands[input_hands[input]].buttons &= ~input_buttons[input];
for (action = 0; action < HALO_VR_ACTION_COUNT; action++)
{
if (down[vr.action_inputs[action]])
hands[input_hands[action]].buttons |= input_buttons[action];
}
}
/* the controllers as the game is played with them: mirrored (left-handed)
and the actions on their buttons */
static void controls_in_play(struct halo_xr_hand hands[HALO_XR_HAND_COUNT])
{
if (vr.left_handed)
controllers_mirrored(hands);
controls_remapped(hands);
}
/* the controllers, for the gamepad the game reads (xinput_sdl.c) */
int halo_vr_controllers(struct halo_xr_hand hands[HALO_XR_HAND_COUNT], int *menus)
{
@@ -3053,8 +3149,8 @@ int halo_vr_controllers(struct halo_xr_hand hands[HALO_XR_HAND_COUNT], int *menu
return 0;
memcpy(hands, vr.frame.hands, sizeof(vr.frame.hands));
*menus = vr.last_overlay_mode == HALO_XR_OVERLAY_SCREEN;
if (vr.left_handed && !*menus)
controllers_mirrored(hands);
if (!*menus)
controls_in_play(hands);
return 1;
}
@@ -3062,6 +3158,7 @@ int halo_vr_controllers(struct halo_xr_hand hands[HALO_XR_HAND_COUNT], int *menu
int halo_vr_controller_layout(void) { return 0; }
int halo_vr_weapon_hand(void) { return 1; }
int halo_vr_action_input(int action) { return action; }
int halo_vr_graphics(void) { return HALO_VR_GRAPHICS_HIGH; }
int halo_vr_refresh_rates(float *rates, int maximum, float *current)
{
+7 -3
View File
@@ -859,6 +859,11 @@ face buttons too (the right stick moves, X jumps, A reloads; on the Steam
Frame the left D-pad takes A, B, X and Y). Here "right" and "left" are the
sides so handed over.
The VR options' BUTTONS page (vr.button_*) moves jump, the flashlight,
action, switch weapon, crouch, zoom and melee between A, B, X, Y, the
stick clicks and the weapon hand's grip: vr.c hands each action's button
over as the one above, so "A" here is the jump wherever it is.
In the menus the buttons are the Xbox's by position: A accepts, B goes back. */
#include "guest_host.h"
@@ -937,9 +942,8 @@ static void vr_gamepad_state(XINPUT_GAMEPAD *pad)
}
merge_button(pad, XINPUT_GAMEPAD_A, (right->buttons & HALO_XR_BUTTON_A) != 0);
merge_button(pad, XINPUT_GAMEPAD_X, (left->buttons & HALO_XR_BUTTON_A) != 0);
/* (the grips holding a Warthog's wheel are not a blow) */
merge_button(pad, XINPUT_GAMEPAD_B,
((right->buttons & HALO_XR_BUTTON_SQUEEZE) != 0 && !halo_vr_wheel_held()) || halo_vr_melee());
/* (the grips holding a Warthog's wheel are not a blow: vr.c) */
merge_button(pad, XINPUT_GAMEPAD_B, (right->buttons & HALO_XR_BUTTON_SQUEEZE) != 0 || halo_vr_melee());
merge_button(pad, XINPUT_GAMEPAD_Y, (left->buttons & HALO_XR_BUTTON_B) != 0);
/* (the Steam Frame's bumpers: the left switches grenades, the right is
the flashlight) */
+271 -43
View File
@@ -6648,6 +6648,7 @@ double config_real(char const *name);
char const *config_string(char const *name);
int config_write(char const *name, char const *value);
int config_write_boolean(char const *name, int value);
int config_default(char const *name, char *text, size_t size);
enum
{
@@ -6663,6 +6664,10 @@ enum
_vr_option_motion_tracker,
_vr_option_body,
_vr_option_fingers,
/* (the game's actions on the buttons, HALO_VR_ACTION_*'s order) */
_vr_option_button_first,
_vr_option_button_last = _vr_option_button_first + HALO_VR_ACTION_COUNT - 1,
_vr_option_buttons_reset,
_vr_option_graphics,
_vr_option_refresh_rate,
_vr_option_resolution,
@@ -6675,7 +6680,16 @@ enum
VR_OPTIONS_ROW_HEIGHT = 22,
VR_OPTIONS_FOOTER = 362,
VR_OPTIONS_PER_PAGE = 12,
NUMBER_OF_VR_OPTION_PAGES = 2,
_vr_options_page_play = 0,
_vr_options_page_buttons,
_vr_options_page_more,
NUMBER_OF_VR_OPTION_PAGES,
/* (the pages' tabs, beside the title, as wide as there is room) */
VR_OPTIONS_TABS_LEFT = 250,
VR_OPTIONS_TABS_RIGHT = 522,
VR_OPTIONS_TAB_WIDTH = (VR_OPTIONS_TABS_RIGHT - VR_OPTIONS_TABS_LEFT) / NUMBER_OF_VR_OPTION_PAGES,
_vr_controls_on_foot = 0,
_vr_controls_vehicles,
@@ -6694,14 +6708,19 @@ static struct
} ui_vr_options_globals;
/* the panel's pages (its tabs), their rows in order (NONE past the last) */
static char const *const vr_option_page_names[NUMBER_OF_VR_OPTION_PAGES] = { "PLAY", "MORE" };
static char const *const vr_option_page_names[NUMBER_OF_VR_OPTION_PAGES] = { "PLAY", "BUTTONS", "MORE" };
static short const vr_option_pages[NUMBER_OF_VR_OPTION_PAGES][VR_OPTIONS_PER_PAGE] =
{
{ _vr_option_turning, _vr_option_snap_angle, _vr_option_smooth_speed, _vr_option_vignette, _vr_option_wheel,
_vr_option_handedness, _vr_option_mirror_controls, _vr_option_laser, _vr_option_crosshair,
_vr_option_motion_tracker, _vr_option_body, _vr_option_fingers },
{ _vr_option_graphics, _vr_option_refresh_rate, _vr_option_resolution, _vr_option_controls, _vr_option_quit,
NONE, NONE, NONE, NONE, NONE, NONE, NONE },
{ _vr_option_button_first + HALO_VR_ACTION_JUMP, _vr_option_button_first + HALO_VR_ACTION_LIGHT,
_vr_option_button_first + HALO_VR_ACTION_ACTION, _vr_option_button_first + HALO_VR_ACTION_WEAPON,
_vr_option_button_first + HALO_VR_ACTION_CROUCH, _vr_option_button_first + HALO_VR_ACTION_ZOOM,
_vr_option_button_first + HALO_VR_ACTION_MELEE, _vr_option_buttons_reset, _vr_option_controls,
NONE, NONE, NONE },
{ _vr_option_graphics, _vr_option_refresh_rate, _vr_option_resolution, _vr_option_quit,
NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },
};
/* the page a row is on, and its place there */
@@ -6754,6 +6773,113 @@ static boolean ui_vr_controls_mirrored(
return ui_vr_left_handed() && config_boolean("vr.mirror_controls");
}
/* Where a button the game's actions go on (HALO_VR_INPUT_*) is, as the
hands are set: its controller (0 the left, 1 the right) and its name,
short under its controller on the controls page, or full in the
options' rows. On the Quest A and B are on the right, X and Y on the
left, and mirrored the other way round; on the Steam Frame all four are
on the right, and mirrored the left D-pad takes them (down, left, right,
up). The sticks' clicks change sides with them; the grip is the weapon
hand's. */
static char const *ui_vr_input_name(
short input,
boolean full,
short *column)
{
static char const *const buttons[] = { "A", "B", "X", "Y" };
static char const *const quest_mirrored[] = { "X", "Y", "A", "B" };
static char const *const frame_mirrored[] = { "D-pad down", "D-pad left", "D-pad right", "D-pad up" };
boolean frame = halo_vr_controller_layout() == 1;
boolean mirrored = ui_vr_controls_mirrored();
short side;
char const *name;
switch (input)
{
case HALO_VR_INPUT_MOVE_STICK:
case HALO_VR_INPUT_TURN_STICK:
side = (short)((input == HALO_VR_INPUT_TURN_STICK) != (mirrored != 0));
name = full ? (side ? "Right stick click" : "Left stick click") : "Stick click";
break;
case HALO_VR_INPUT_GRIP:
side = (short)(ui_vr_left_handed() ? 0 : 1);
name = full ? (side ? "Right grip" : "Left grip") : "Grip";
break;
default:
input = (short)PIN(input, HALO_VR_INPUT_A, HALO_VR_INPUT_Y);
if (frame)
{
side = (short)(mirrored ? 0 : 1);
name = mirrored ? frame_mirrored[input] : buttons[input];
}
else
{
side = (short)((input <= HALO_VR_INPUT_B) != (mirrored != 0));
name = mirrored ? quest_mirrored[input] : buttons[input];
}
break;
}
if (column)
*column = side;
return name;
}
/* the game's actions on the buttons (HALO_VR_ACTION_*'s order): as the
options' rows name them, and in short (the Steam Frame's stick lines) */
static char const *const vr_action_names[HALO_VR_ACTION_COUNT] =
{
"Jump", "Light; held: grenades", "Action, reload", "Switch weapon", "Crouch", "Zoom", "Melee",
};
static char const *const vr_action_short_names[HALO_VR_ACTION_COUNT] =
{
"jump", "light", "action", "weapon", "crouch", "zoom", "melee",
};
/* an action moved to the next button or the one before: the action that
was there takes its old one (so that every action keeps a button) */
static void ui_vr_options_button_change(
short action,
short change)
{
short input = (short)halo_vr_action_input(action);
short wanted = (short)((input + change + HALO_VR_INPUT_COUNT) % HALO_VR_INPUT_COUNT);
short other;
for (other = 0; other < HALO_VR_ACTION_COUNT; other++)
{
if (other != action && halo_vr_action_input(other) == wanted)
config_write(halo_vr_action_setting(other), halo_vr_input_value(input));
}
config_write(halo_vr_action_setting(action), halo_vr_input_value(wanted));
}
static boolean ui_vr_options_buttons_default(
void)
{
short action;
for (action = 0; action < HALO_VR_ACTION_COUNT; action++)
{
if (halo_vr_action_input(action) != action)
return FALSE;
}
return TRUE;
}
static void ui_vr_options_buttons_reset(
void)
{
short action;
for (action = 0; action < HALO_VR_ACTION_COUNT; action++)
{
char text[32];
if (config_default(halo_vr_action_setting(action), text, sizeof(text)))
config_write(halo_vr_action_setting(action), text);
}
}
void platform_request_quit(void);
static real const vr_snap_angles[] = { 30.0f, 45.0f, 60.0f, 90.0f };
@@ -6838,8 +6964,9 @@ static boolean ui_vr_options_screen(
{
struct widget_instance *screen = widget_globals.active_widgets[0];
/* (the Xbox's main menu, or the PC version's: vr.menus) */
return halo_vr_active() && screen && screen->name &&
/* (the Xbox's main menu, or the PC version's: vr.menus; off the
headset with debug.vr_options, to check the pages) */
return (halo_vr_active() || config_boolean("debug.vr_options")) && screen && screen->name &&
(main_menu_screen_is_active() || strstr(screen->name, "pause_game") != NULL ||
strcmp(screen->name, "main_menu") == 0);
}
@@ -6928,6 +7055,9 @@ static void ui_vr_options_change(
case _vr_option_resolution:
ui_vr_options_step("vr.resolution_scale", vr_resolution_scales, NUMBEROF(vr_resolution_scales), change);
break;
case _vr_option_buttons_reset:
ui_vr_options_buttons_reset();
break;
case _vr_option_controls:
ui_vr_options_globals.controls = TRUE;
ui_vr_options_globals.page = _vr_controls_on_foot;
@@ -6940,6 +7070,11 @@ static void ui_vr_options_change(
ui_vr_options_globals.quit_armed = TRUE;
break;
}
if (ui_vr_options_globals.selection >= _vr_option_button_first &&
ui_vr_options_globals.selection <= _vr_option_button_last)
{
ui_vr_options_button_change((short)(ui_vr_options_globals.selection - _vr_option_button_first), change);
}
ui_play_audio_feedback_sound(_ui_audio_feedback_forward);
}
@@ -7056,7 +7191,8 @@ static boolean ui_vr_options_take_event(
{
ui_vr_options_change(1);
}
else if (change && ui_vr_options_globals.selection != _vr_option_controls)
else if (change && ui_vr_options_globals.selection != _vr_option_controls &&
ui_vr_options_globals.selection != _vr_option_buttons_reset)
{
ui_vr_options_change(change);
}
@@ -7113,10 +7249,11 @@ static boolean ui_vr_options_take_pointer(
{
short page = ui_vr_options_page_of(ui_vr_options_globals.selection, NULL);
if (pointer->left_clicks && y >= 68 && y < 88 && x >= 330 && x < 514)
if (pointer->left_clicks && y >= 68 && y < 88 && x >= VR_OPTIONS_TABS_LEFT && x < VR_OPTIONS_TABS_RIGHT)
{
/* (a tab: its page) */
short tab = (short)PIN((x - 330) / 92, 0, NUMBER_OF_VR_OPTION_PAGES - 1);
short tab = (short)PIN((x - VR_OPTIONS_TABS_LEFT) / VR_OPTIONS_TAB_WIDTH, 0,
NUMBER_OF_VR_OPTION_PAGES - 1);
if (tab != page)
{
@@ -7196,6 +7333,77 @@ static void ui_vr_controls_add(
}
}
/* the action on a button (vr.button_*; the swaps keep one on each) */
static short ui_vr_input_action(
short input)
{
short action;
for (action = 0; action < HALO_VR_ACTION_COUNT; action++)
{
if (halo_vr_action_input(action) == input)
return action;
}
return input;
}
/* in a vehicle: the action button gets in and out, the light's is the
flashlight */
static void ui_vr_controls_add_vehicle_actions(
struct ui_vr_controls_column columns[2])
{
short column;
char const *name = ui_vr_input_name((short)halo_vr_action_input(HALO_VR_ACTION_ACTION), FALSE, &column);
ui_vr_controls_add(&columns[column], name, "Get in, get out");
name = ui_vr_input_name((short)halo_vr_action_input(HALO_VR_ACTION_LIGHT), FALSE, &column);
ui_vr_controls_add(&columns[column], name, "Flashlight");
}
/* an action's line under the controller its button is on (vr.button_*), as
the Quest's page words it or, shorter, the Steam Frame's (whose page has
more lines) */
static void ui_vr_controls_add_action(
struct ui_vr_controls_column columns[2],
short action,
boolean frame)
{
/* (one action is held: its name lives on with the column) */
static char held[24];
short column;
char const *name = ui_vr_input_name((short)halo_vr_action_input(action), FALSE, &column);
switch (action)
{
case HALO_VR_ACTION_LIGHT:
if (frame)
{
ui_vr_controls_add(&columns[column], name, "Light; held: grenades");
}
else
{
snprintf(held, sizeof(held), "%s held", strcmp(name, "Stick click") == 0 ? "Click" : name);
ui_vr_controls_add(&columns[column], name, "Flashlight");
ui_vr_controls_add(&columns[column], held, "Switch grenades");
}
break;
case HALO_VR_ACTION_MELEE:
if (frame)
{
ui_vr_controls_add(&columns[column], name, "Melee (or punch)");
}
else
{
ui_vr_controls_add(&columns[column], name, "Melee (or punch");
ui_vr_controls_add(&columns[column], "", "forward)");
}
break;
default:
ui_vr_controls_add(&columns[column], name, vr_action_names[action]);
break;
}
}
static void ui_vr_controls_column_render(
short x,
short y,
@@ -7264,26 +7472,27 @@ static void ui_vr_controls_render(
{
/* the Steam Frame's controllers: A, B, X, Y and a menu button on the
right one, a D-pad and a View button on the left one; mirrored, the
D-pad does what A, B, X and Y do (down, left, right, up) */
char const *jump = mirrored ? "D-pad down" : "A";
char const *light = mirrored ? "D-pad left" : "B";
char const *act = mirrored ? "D-pad right" : "X";
char const *weapon = mirrored ? "D-pad up" : "Y";
short buttons = mirrored ? 0 : 1;
D-pad does what A, B, X and Y do (down, left, right, up). The sticks'
clicks on the sticks' lines, to keep to the page's lines */
static char move_line[32], turn_line[32];
switch (ui_vr_options_globals.page)
{
case _vr_controls_on_foot:
ui_vr_controls_add(&columns[move], "Stick", "Move; click: crouch");
ui_vr_controls_add(&columns[turn], "Stick", "Turn; click: zoom");
snprintf(move_line, sizeof(move_line), "Move; click: %s",
vr_action_short_names[ui_vr_input_action(HALO_VR_INPUT_MOVE_STICK)]);
snprintf(turn_line, sizeof(turn_line), "Turn; click: %s",
vr_action_short_names[ui_vr_input_action(HALO_VR_INPUT_TURN_STICK)]);
ui_vr_controls_add(&columns[move], "Stick", move_line);
ui_vr_controls_add(&columns[turn], "Stick", turn_line);
ui_vr_controls_add(&columns[gun], "Trigger", "Fire");
ui_vr_controls_add(&columns[free_column], "Trigger", "Grenade: hold, throw");
ui_vr_controls_add(&columns[gun], "Grip", "Melee (or punch)");
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_GRIP), TRUE);
ui_vr_controls_add(&columns[free_column], "Grip", "Weapon in both hands");
ui_vr_controls_add(&columns[buttons], jump, "Jump");
ui_vr_controls_add(&columns[buttons], light, "Light; held: grenades");
ui_vr_controls_add(&columns[buttons], act, "Action, reload");
ui_vr_controls_add(&columns[buttons], weapon, "Switch weapon");
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_A), TRUE);
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_B), TRUE);
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_X), TRUE);
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_Y), TRUE);
ui_vr_controls_add(&columns[mirrored ? 0 : 1], "Bumper", "Flashlight");
ui_vr_controls_add(&columns[mirrored ? 1 : 0], "Bumper", "Switch grenades");
ui_vr_controls_add(&columns[0], "View", "Scores");
@@ -7302,8 +7511,7 @@ static void ui_vr_controls_render(
ui_vr_controls_add(&columns[gun], "Trigger", "Fire");
ui_vr_controls_add(&columns[free_column], "Trigger", "Second weapon");
ui_vr_controls_add(&columns[free_column], "", "(Banshee, tank)");
ui_vr_controls_add(&columns[buttons], act, "Get in, get out");
ui_vr_controls_add(&columns[buttons], light, "Flashlight");
ui_vr_controls_add_vehicle_actions(columns);
break;
default:
ui_vr_controls_add(&columns[0], "Stick", "Choose");
@@ -7322,27 +7530,22 @@ static void ui_vr_controls_render(
/* the Quest's: A and B on the right controller, X, Y and the menu
button on the left; mirrored, X and Y do what A and B do, and the
other way round */
short jumps = mirrored ? 0 : 1;
short acts = (short)(1 - jumps);
switch (ui_vr_options_globals.page)
{
case _vr_controls_on_foot:
ui_vr_controls_add(&columns[move], "Stick", "Move");
ui_vr_controls_add(&columns[move], "Stick click", "Crouch");
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_MOVE_STICK), FALSE);
ui_vr_controls_add(&columns[turn], "Stick", "Turn");
ui_vr_controls_add(&columns[turn], "Stick click", "Zoom");
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_TURN_STICK), FALSE);
ui_vr_controls_add(&columns[gun], "Trigger", "Fire");
ui_vr_controls_add(&columns[gun], "Grip", "Melee (or punch");
ui_vr_controls_add(&columns[gun], "", "forward)");
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_GRIP), FALSE);
ui_vr_controls_add(&columns[free_column], "Trigger", "Grenade: hold it,");
ui_vr_controls_add(&columns[free_column], "", "let go as you throw");
ui_vr_controls_add(&columns[free_column], "Grip", "Weapon in both hands");
ui_vr_controls_add(&columns[jumps], jumps ? "A" : "X", "Jump");
ui_vr_controls_add(&columns[jumps], jumps ? "B" : "Y", "Flashlight");
ui_vr_controls_add(&columns[jumps], jumps ? "B held" : "Y held", "Switch grenades");
ui_vr_controls_add(&columns[acts], acts ? "A" : "X", "Action, reload");
ui_vr_controls_add(&columns[acts], acts ? "B" : "Y", "Switch weapon");
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_A), FALSE);
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_B), FALSE);
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_X), FALSE);
ui_vr_controls_add_action(columns, ui_vr_input_action(HALO_VR_INPUT_Y), FALSE);
ui_vr_controls_add(&columns[0], "Menu", "Pause");
ui_vr_controls_note(320, wrist_note);
ui_vr_controls_note(340, "Scope: zoom, and look through the disc above the weapon.");
@@ -7355,8 +7558,7 @@ static void ui_vr_controls_render(
ui_vr_controls_add(&columns[gun], "Trigger", "Fire");
ui_vr_controls_add(&columns[free_column], "Trigger", "Second weapon");
ui_vr_controls_add(&columns[free_column], "", "(Banshee, tank)");
ui_vr_controls_add(&columns[acts], acts ? "A" : "X", "Get in, get out");
ui_vr_controls_add(&columns[jumps], jumps ? "B" : "Y", "Flashlight");
ui_vr_controls_add_vehicle_actions(columns);
break;
default:
ui_vr_controls_add(&columns[0], "Stick", "Choose");
@@ -7373,6 +7575,9 @@ static void ui_vr_controls_render(
ui_vr_controls_column_render(right, y, &columns[1]);
switch (ui_vr_options_globals.page)
{
case _vr_controls_on_foot:
/* (its notes are with its lines, above) */
break;
case _vr_controls_vehicles:
ui_vr_controls_note(300, "Warthog: grip the wheel with one hand or both and turn it.");
ui_vr_controls_note(320, left_handed ? "Holding it, the left trigger accelerates, the right one brakes" :
@@ -7429,15 +7634,15 @@ static void ui_vr_options_render(
ui_join_code_draw_quad(110, 62, 530, 396, 0xFF050A18);
ui_join_code_draw_quad(110, 62, 530, 64, 0xFF3A6EA5);
ui_join_code_draw_quad(110, 394, 530, 396, 0xFF3A6EA5);
ui_join_code_draw_text(126, 330, 72, "VR OPTIONS", FALSE, 0, &title_color);
ui_join_code_draw_text(126, VR_OPTIONS_TABS_LEFT, 72, "VR OPTIONS", FALSE, 0, &title_color);
/* (the pages' tabs, beside the title) */
for (tab = 0; tab < NUMBER_OF_VR_OPTION_PAGES; tab++)
{
short x0 = (short)(330 + tab * 92);
short x0 = (short)(VR_OPTIONS_TABS_LEFT + tab * VR_OPTIONS_TAB_WIDTH);
if (tab == page)
ui_join_code_draw_quad(x0, 68, (short)(x0 + 88), 88, 0x803A6EA5);
ui_join_code_draw_text(x0, (short)(x0 + 88), 72, vr_option_page_names[tab], FALSE, 2,
ui_join_code_draw_quad(x0, 68, (short)(x0 + VR_OPTIONS_TAB_WIDTH - 4), 88, 0x803A6EA5);
ui_join_code_draw_text(x0, (short)(x0 + VR_OPTIONS_TAB_WIDTH - 4), 72, vr_option_page_names[tab], FALSE, 2,
tab == page ? &text_color : &dim_color);
}
for (row = 0; row < ui_vr_options_page_rows(page); row++)
@@ -7537,9 +7742,23 @@ static void ui_vr_options_render(
snprintf(value, sizeof(value), "%.0f%%", scale * 100.0f);
break;
}
case _vr_option_buttons_reset:
label = "Reset buttons to defaults";
unused = ui_vr_options_buttons_default();
break;
case _vr_option_controls:
label = "Controller buttons...";
break;
default:
if (option >= _vr_option_button_first && option <= _vr_option_button_last)
{
short action = (short)(option - _vr_option_button_first);
label = vr_action_names[action];
snprintf(value, sizeof(value), "%s", ui_vr_input_name((short)halo_vr_action_input(action), TRUE,
NULL));
}
break;
case _vr_option_quit:
label = ui_vr_options_globals.quit_armed && ui_vr_options_globals.selection == _vr_option_quit ?
"Quit Halo? Once more to quit" : "Quit Halo";
@@ -7556,7 +7775,16 @@ static void ui_vr_options_render(
ui_join_code_draw_text(330, 512, y, shown, FALSE, 1, unused ? &dim_color : &text_color);
}
}
if (page == 1)
if (page == _vr_options_page_buttons)
{
/* (what the buttons' rows do) */
ui_join_code_draw_text(128, 512, 302, "An action moved to a button swaps with the one there;", FALSE, 0,
&dim_color);
ui_join_code_draw_text(128, 512, 320, "left-handed and mirrored, the buttons are mirrored too.", FALSE, 0,
&dim_color);
ui_join_code_draw_text(128, 512, 338, "The menus keep their buttons.", FALSE, 0, &dim_color);
}
if (page == _vr_options_page_more)
{
/* (what the graphics rows do) */
ui_join_code_draw_text(128, 512, 230, "Graphics: Medium and Low leave effects out (shadows,", FALSE, 0,