Support for a selectable weapon system

much quicker and cleaner than "next" and "previous" on the right stick. That approach can still be set up using the mappings
This commit is contained in:
Simon 2022-03-06 15:19:38 +00:00
parent e4d49b44e6
commit 73bbcf8882
10 changed files with 201 additions and 9 deletions

View file

@ -26,10 +26,10 @@ set vr_button_map_Y_ALT ""
set vr_button_map_SECONDARYTHUMBSTICK "+scores"
set vr_button_map_SECONDARYTHUMBSTICK_ALT ""
set vr_button_map_PRIMARYTHUMBSTICK ""
set vr_button_map_PRIMARYTHUMBSTICK_ALT "weapon 1"
set vr_button_map_RTHUMBFORWARD "weapnext"
set vr_button_map_PRIMARYTHUMBSTICK_ALT ""
set vr_button_map_RTHUMBFORWARD "+weapon_select"
set vr_button_map_RTHUMBFORWARD_ALT ""
set vr_button_map_RTHUMBBACK "weapprev"
set vr_button_map_RTHUMBBACK "+weapon_select"
set vr_button_map_RTHUMBBACK_ALT ""
set vr_button_map_SECONDARYTRIGGER "+moveup"
set vr_button_map_SECONDARYTRIGGER_ALT ""

View file

@ -470,6 +470,7 @@ static consoleCommand_t commands[] = {
{ "tcmd", CG_TargetCommand_f },
{ "tell_target", CG_TellTarget_f },
{ "tell_attacker", CG_TellAttacker_f },
{ "holster_select", CG_HolsterSelect_f },
#ifdef MISSIONPACK
{ "vtell_target", CG_VoiceTellTarget_f },
{ "vtell_attacker", CG_VoiceTellAttacker_f },

View file

@ -2789,9 +2789,13 @@ void CG_DrawActive( stereoFrame_t stereoView ) {
VectorCopy( baseOrg, cg.refdef.vieworg );
// draw status bar and other floating elements
hudStereoView = stereoView;
CG_Draw2D(hudStereoView);
//Don't draw HUD whilst selecting the weapon with the holster (it gets in the way)
if (cg.weaponHolsterTime == 0)
{
// draw status bar and other floating elements
hudStereoView = stereoView;
CG_Draw2D(hudStereoView);
}
}

View file

@ -618,6 +618,9 @@ typedef struct {
int weaponAnimation;
int weaponAnimationTime;
int weaponHolsterSelection;
int weaponHolsterTime;
// blend blobs
float damageTime;
float damageX, damageY, damageValue;
@ -783,6 +786,8 @@ typedef struct {
qhandle_t blueKamikazeShader;
#endif
qhandle_t smallSphereModel;
// weapon effect models
qhandle_t bulletFlashModel;
qhandle_t ringFlashModel;
@ -1114,6 +1119,7 @@ extern vmCvar_t cg_drawFPS;
extern vmCvar_t cg_drawSnapshot;
extern vmCvar_t cg_draw3dIcons;
extern vmCvar_t cg_debugWeaponAiming;
extern vmCvar_t cg_holsterSimple2DIcons;
extern vmCvar_t cg_drawIcons;
extern vmCvar_t cg_drawAmmoWarning;
extern vmCvar_t cg_drawCrosshair;
@ -1380,6 +1386,7 @@ void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *pare
void CG_NextWeapon_f( void );
void CG_PrevWeapon_f( void );
void CG_Weapon_f( void );
void CG_HolsterSelect_f( void );
void rotateAboutOrigin(float x, float y, float rotation, vec2_t out);
void CG_CalculateVRWeaponPosition( vec3_t origin, vec3_t angles );
@ -1397,6 +1404,7 @@ void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean fles
void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end );
void CG_GrappleTrail( centity_t *ent, const weaponInfo_t *wi );
void CG_AddViewWeapon (playerState_t *ps);
void CG_DrawHolsteredWeapons( void );
void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team );
void CG_DrawWeaponSelect( void );
void CG_LaserSight( vec3_t start, vec3_t end );

View file

@ -117,6 +117,7 @@ vmCvar_t cg_drawAmmoWarning;
vmCvar_t cg_drawCrosshair;
vmCvar_t cg_drawCrosshairNames;
vmCvar_t cg_debugWeaponAiming;
vmCvar_t cg_holsterSimple2DIcons;
vmCvar_t cg_fragMessage;
vmCvar_t cg_drawRewards;
vmCvar_t cg_crosshairSize;
@ -235,6 +236,7 @@ static cvarTable_t cvarTable[] = {
{ &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
{ &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE },
{ &cg_debugWeaponAiming, "cg_debugWeaponAiming", "0", CVAR_ARCHIVE },
{ &cg_holsterSimple2DIcons, "cg_holsterSimple2DIcons", "0", CVAR_ARCHIVE },
{ &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE },
{ &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
{ &cg_drawAttacker, "cg_drawAttacker", "0", CVAR_ARCHIVE },
@ -1047,6 +1049,9 @@ static void CG_RegisterGraphics( void ) {
cgs.media.reticleShader = trap_R_RegisterShader( "scope.tga" );
//Used for the weapon selector
cgs.media.smallSphereModel = trap_R_RegisterModel("models/powerups/health/small_sphere.md3");
// register the inline models
cgs.numInlineModels = trap_CM_NumInlineModels();
for ( i = 1 ; i < cgs.numInlineModels ; i++ ) {

View file

@ -975,6 +975,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo
CG_AddParticles ();
CG_AddLocalEntities();
}
CG_AddViewWeapon( &cg.predictedPlayerState );
// add buffered sounds

View file

@ -1635,7 +1635,6 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent
}
}
}
/*
==============
CG_AddViewWeapon
@ -1692,6 +1691,12 @@ void CG_AddViewWeapon( playerState_t *ps ) {
}
*/
if (vr->weapon_select)
{
CG_DrawHolsteredWeapons();
return;
}
cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
CG_RegisterWeapon( ps->weapon );
weapon = &cg_weapons[ ps->weapon ];
@ -1997,6 +2002,147 @@ void CG_Weapon_f( void ) {
cg.weaponSelect = num;
}
//Selects the currently selected holstered weapon (if one _is_ selected)
void CG_HolsterSelect_f( void )
{
cg.weaponHolsterTime = 0;
if (cg.weaponHolsterSelection == WP_NONE ||
cg.weaponSelect == cg.weaponHolsterSelection)
{
return;
}
cg.weaponSelectTime = cg.time;
cg.weaponSelect = cg.weaponHolsterSelection;
cg.weaponHolsterSelection = WP_NONE;
}
void CG_DrawHolsteredWeapons( void )
{
int weapons[MAX_WEAPONS];
memset(weapons, 0, sizeof(int) * MAX_WEAPONS);
if (cg.weaponHolsterTime == 0)
{
cg.weaponHolsterTime = cg.time;
}
int j = 0;
for ( int i = 0 ; i < MAX_WEAPONS ; i++ ) {
if (cg.weaponSelect == i)
{
continue;
}
if ( CG_WeaponSelectable( i ) ) {
weapons[j++] = i;
}
}
const float SCALE = 0.1f;
const float DIST = 10.0f;
const float SEP = 14.0f;
cg.weaponHolsterSelection = WP_NONE;
vec3_t weaponOrigin, weaponAngles;
CG_CalculateVRWeaponPosition(weaponOrigin, weaponAngles);
{
refEntity_t blob;
memset( &blob, 0, sizeof( blob ) );
VectorCopy( weaponOrigin, blob.origin );
AnglesToAxis(weaponAngles, blob.axis);
VectorScale( blob.axis[0], 0.07f, blob.axis[0] );
VectorScale( blob.axis[1], 0.07f, blob.axis[1] );
VectorScale( blob.axis[2], 0.07f, blob.axis[2] );
blob.nonNormalizedAxes = qtrue;
blob.hModel = cgs.media.smallSphereModel;
trap_R_AddRefEntityToScene( &blob );
}
float startingPositionYaw = cg.refdefViewAngles[YAW] + (((j - (j&1 ? 0 : 1)) / 2.0f) * SEP);
startingPositionYaw = AngleNormalize360(startingPositionYaw);
for (int w = j-1; w >= 0; --w)
{
if ( cg_weapons[ weapons[w] ].item ) {
//first calculate holster slot position
vec3_t angles, iconOrigin;
VectorClear(angles);
angles[YAW] = startingPositionYaw - (w * SEP) - 4; // add a few degrees as models aren't central
vec3_t forward;
AngleVectors(angles, forward, NULL, NULL);
int dist = (cg.time - cg.weaponHolsterTime) / 10;
if (dist > DIST) dist = DIST;
VectorMA(cg.refdef.vieworg, dist, forward, iconOrigin);
float worldscale = trap_Cvar_VariableValue("vr_worldscale");
iconOrigin[2] -= PLAYER_HEIGHT;
iconOrigin[2] += (vr->hmdposition[1] * 0.85f) * worldscale;
//Float sprite above selected weapon
qboolean selected = qfalse;
vec3_t length;
VectorSubtract(weaponOrigin, iconOrigin, length);
if (VectorLength(length) <= 1.75f && dist == DIST)
{
cg.weaponHolsterSelection = weapons[w];
selected = qtrue;
refEntity_t sprite;
memset( &sprite, 0, sizeof( sprite ) );
VectorCopy( iconOrigin, sprite.origin );
sprite.origin[2] += 2.5f + (0.5f * sinf(DEG2RAD(AngleNormalize360(cg.time/6))));
sprite.reType = RT_SPRITE;
sprite.customShader = cgs.media.friendShader;
sprite.radius = 0.5f;
sprite.shaderRGBA[0] = 255;
sprite.shaderRGBA[1] = 255;
sprite.shaderRGBA[2] = 255;
sprite.shaderRGBA[3] = 255;
trap_R_AddRefEntityToScene( &sprite );
}
if (!cg_holsterSimple2DIcons.integer)
{
refEntity_t ent;
memset(&ent, 0, sizeof(ent));
VectorCopy(iconOrigin, ent.origin);
vec3_t iconAngles;
VectorCopy(cg.refdefViewAngles, iconAngles);
iconAngles[YAW] -= 145.0f;
if (weapons[w] == WP_GAUNTLET)
{
iconAngles[ROLL] -= 90.0f;
}
AnglesToAxis(iconAngles, ent.axis);
VectorScale(ent.axis[0], SCALE + (selected ? 0.04f : 0), ent.axis[0]);
VectorScale(ent.axis[1], SCALE + (selected ? 0.04f : 0), ent.axis[1]);
VectorScale(ent.axis[2], SCALE + (selected ? 0.04f : 0), ent.axis[2]);
ent.nonNormalizedAxes = qtrue;
ent.hModel = cg_weapons[weapons[w]].weaponModel;
trap_R_AddRefEntityToScene(&ent);
}
else
{
refEntity_t sprite;
memset( &sprite, 0, sizeof( sprite ) );
VectorCopy( iconOrigin, sprite.origin );
sprite.reType = RT_SPRITE;
sprite.customShader = cg_weapons[weapons[w]].weaponIcon;
sprite.radius = 0.6f + (selected ? 0.1f : 0);
sprite.shaderRGBA[0] = 255;
sprite.shaderRGBA[1] = 255;
sprite.shaderRGBA[2] = 255;
sprite.shaderRGBA[3] = 255;
trap_R_AddRefEntityToScene( &sprite );
}
}
}
}
/*
===================
CG_OutOfAmmoChange

View file

@ -56,8 +56,9 @@ VR OPTIONS MENU
#define ID_LASERSIGHT 142
#define ID_GORE 143
#define ID_HAPTICINTENSITY 144
#define ID_HOLSTER2D 145
#define ID_BACK 145
#define ID_BACK 146
#define NUM_HUDDEPTH 6
#define NUM_DIRECTIONMODE 2
@ -88,6 +89,7 @@ typedef struct {
menuradiobutton_s sendroll;
menuradiobutton_s lasersight;
menuslider_s hapticintensity;
menuradiobutton_s holster2d;
menulist_s gore;
menubitmap_s back;
@ -127,6 +129,8 @@ static void VR_SetMenuItems( void ) {
s_VR.hudyoffset.curvalue = trap_Cvar_VariableValue( "vr_hudYOffset" ) + 200;
s_VR.sendroll.curvalue = trap_Cvar_VariableValue( "vr_sendRollToServer" ) != 0;
s_VR.lasersight.curvalue = trap_Cvar_VariableValue( "vr_lasersight" ) != 0;
s_VR.hapticintensity.curvalue = trap_Cvar_VariableValue( "vr_hapticIntensity" );
s_VR.holster2d.curvalue = trap_Cvar_VariableValue( "cg_holsterSimple2DIcons" ) != 0;
//GORE
{
@ -225,7 +229,11 @@ static void VR_Event( void* ptr, int notification ) {
trap_Cvar_SetValue( "vr_hapticIntensity", s_VR.hapticintensity.curvalue);
break;
case ID_GORE: {
case ID_HOLSTER2D:
trap_Cvar_SetValue( "cg_holsterSimple2DIcons", s_VR.holster2d.curvalue);
break;
case ID_GORE: {
switch ((int)s_VR.gore.curvalue) {
case 0:
trap_Cvar_SetValue( "com_blood", 0);
@ -495,6 +503,15 @@ static void VR_MenuInit( void ) {
s_VR.hapticintensity.minvalue = 0;
s_VR.hapticintensity.maxvalue = 1.0;
y += BIGCHAR_HEIGHT;
s_VR.holster2d.generic.type = MTYPE_RADIOBUTTON;
s_VR.holster2d.generic.name = "Simple Icons on Weapon Selector:";
s_VR.holster2d.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
s_VR.holster2d.generic.callback = VR_Event;
s_VR.holster2d.generic.id = ID_HOLSTER2D;
s_VR.holster2d.generic.x = VR_X_POS;
s_VR.holster2d.generic.y = y;
y += BIGCHAR_HEIGHT + 10;
s_VR.gore.generic.type = MTYPE_SPINCONTROL;
s_VR.gore.generic.flags = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
@ -535,6 +552,7 @@ static void VR_MenuInit( void ) {
Menu_AddItem( &s_VR.menu, &s_VR.hudyoffset );
Menu_AddItem( &s_VR.menu, &s_VR.sendroll );
Menu_AddItem( &s_VR.menu, &s_VR.lasersight );
Menu_AddItem( &s_VR.menu, &s_VR.holster2d );
Menu_AddItem( &s_VR.menu, &s_VR.hapticintensity );
Menu_AddItem( &s_VR.menu, &s_VR.gore );

View file

@ -19,6 +19,7 @@ typedef struct {
qboolean virtual_screen;
qboolean local_server; // used in bg_pmove.c
followMode_t follow_mode;
qboolean weapon_select;
int realign; // used to realign the fake 6DoF playspace in a multiplayer game

View file

@ -252,6 +252,14 @@ static void IN_SendButtonAction(const char* action, qboolean pressed)
{
vr.weapon_stabilised = pressed;
}
else if (strcmp(action, "+weapon_select") == 0)
{
vr.weapon_select = pressed;
if (!pressed)
{
Cbuf_AddText("holster_select");
}
}
else if (action[0] == '+')
{
char command[256];