summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--src/cgame/cg_draw.c122
-rw-r--r--src/cgame/cg_local.h11
-rw-r--r--src/cgame/cg_main.c22
-rw-r--r--src/cgame/cg_players.c29
-rw-r--r--src/cgame/cg_public.h6
-rw-r--r--src/cgame/cg_syscalls.asm25
-rw-r--r--src/cgame/cg_syscalls.c13
-rw-r--r--src/cgame/cg_tutorial.c610
-rw-r--r--src/client/cl_cgame.c10
-rw-r--r--src/client/cl_keys.c43
-rw-r--r--src/client/cl_ui.c45
-rw-r--r--src/client/keys.h2
-rw-r--r--src/game/bg_misc.c169
-rw-r--r--src/game/bg_public.h8
-rw-r--r--src/game/g_active.c15
-rw-r--r--src/game/g_cmds.c22
-rw-r--r--src/game/g_local.h5
-rw-r--r--src/game/g_main.c107
-rw-r--r--src/ui/ui_main.c127
-rw-r--r--ui/ingame_options.menu34
-rw-r--r--ui/menudef.h1
-rw-r--r--ui/tremulous_alien_builder_hud.menu17
-rw-r--r--ui/tremulous_alien_general_hud.menu17
-rw-r--r--ui/tremulous_default_hud.menu17
-rw-r--r--ui/tremulous_human_hud.menu17
26 files changed, 1121 insertions, 374 deletions
diff --git a/Makefile b/Makefile
index b87285ee..8a0c89f8 100644
--- a/Makefile
+++ b/Makefile
@@ -1319,6 +1319,7 @@ CGOBJ_ = \
$(B)/base/cgame/cg_trails.o \
$(B)/base/cgame/cg_particles.o \
$(B)/base/cgame/cg_ptr.o \
+ $(B)/base/cgame/cg_tutorial.o \
$(B)/base/ui/ui_shared.o \
\
$(B)/base/qcommon/q_math.o \
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c
index a3959ed7..7aa724b9 100644
--- a/src/cgame/cg_draw.c
+++ b/src/cgame/cg_draw.c
@@ -543,34 +543,6 @@ void CG_SetPrintString( int type, const char *p )
}
}
-/*
-===============
-CG_AtHighestClass
-
-Is the local client at the highest class possible?
-===============
-*/
-static qboolean CG_AtHighestClass( void )
-{
- int i;
- qboolean superiorClasses = qfalse;
-
- for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
- {
- if( BG_ClassCanEvolveFromTo(
- cg.predictedPlayerState.stats[ STAT_PCLASS ], i,
- ALIEN_MAX_KILLS, 0 ) >= 0 &&
- BG_FindStagesForClass( i, cgs.alienStage )
- /*FIXME && G_ClassIsAllowed( i )*/ )
- {
- superiorClasses = qtrue;
- break;
- }
- }
-
- return !superiorClasses;
-}
-
#define NO_CREDITS_TIME 2000
static void CG_DrawPlayerCreditsValue( rectDef_t *rect, vec4_t color, qboolean padding )
@@ -2285,67 +2257,95 @@ static void CG_DrawLagometer( rectDef_t *rect, float text_x, float text_y,
/*
==============
-CG_DrawConsole
+CG_DrawTextBlock
==============
*/
-static void CG_DrawConsole( rectDef_t *rect, float text_x, float text_y, vec4_t color,
- float scale, int align, int textStyle )
+static void CG_DrawTextBlock( rectDef_t *rect, float text_x, float text_y, vec4_t color,
+ float scale, int align, int textStyle, const char *text,
+ menuDef_t *parent, itemDef_t *textItem )
{
float x, y, w, h;
- //for some reason if these are stored locally occasionally rendering fails
- //even though they are both live until the end of the function, hence static
- //possible compiler bug??
- static menuDef_t dummyParent;
- static itemDef_t textItem;
-
//offset the text
x = rect->x;
y = rect->y;
w = rect->w - ( 16 + ( 2 * text_x ) ); //16 to ensure text within frame
h = rect->h;
- textItem.text = cg.consoleText;
+ textItem->text = text;
- textItem.parent = &dummyParent;
- memcpy( textItem.window.foreColor, color, sizeof( vec4_t ) );
- textItem.window.flags = 0;
+ textItem->parent = parent;
+ memcpy( textItem->window.foreColor, color, sizeof( vec4_t ) );
+ textItem->window.flags = 0;
switch( align )
{
case ITEM_ALIGN_LEFT:
- textItem.window.rect.x = x;
+ textItem->window.rect.x = x;
break;
case ITEM_ALIGN_RIGHT:
- textItem.window.rect.x = x + w;
+ textItem->window.rect.x = x + w;
break;
case ITEM_ALIGN_CENTER:
- textItem.window.rect.x = x + ( w / 2 );
+ textItem->window.rect.x = x + ( w / 2 );
break;
default:
- textItem.window.rect.x = x;
+ textItem->window.rect.x = x;
break;
}
- textItem.window.rect.y = y;
- textItem.window.rect.w = w;
- textItem.window.rect.h = h;
- textItem.window.borderSize = 0;
- textItem.textRect.x = 0;
- textItem.textRect.y = 0;
- textItem.textRect.w = 0;
- textItem.textRect.h = 0;
- textItem.textalignment = align;
- textItem.textalignx = text_x;
- textItem.textaligny = text_y;
- textItem.textscale = scale;
- textItem.textStyle = textStyle;
+ textItem->window.rect.y = y;
+ textItem->window.rect.w = w;
+ textItem->window.rect.h = h;
+ textItem->window.borderSize = 0;
+ textItem->textRect.x = 0;
+ textItem->textRect.y = 0;
+ textItem->textRect.w = 0;
+ textItem->textRect.h = 0;
+ textItem->textalignment = align;
+ textItem->textalignx = text_x;
+ textItem->textaligny = text_y;
+ textItem->textscale = scale;
+ textItem->textStyle = textStyle;
//hack to utilise existing autowrap code
- Item_Text_AutoWrapped_Paint( &textItem );
+ Item_Text_AutoWrapped_Paint( textItem );
+}
+
+/*
+===================
+CG_DrawConsole
+===================
+*/
+static void CG_DrawConsole( rectDef_t *rect, float text_x, float text_y, vec4_t color,
+ float scale, int align, int textStyle )
+{
+ static menuDef_t dummyParent;
+ static itemDef_t textItem;
+
+ CG_DrawTextBlock( rect, text_x, text_y, color, scale, align, textStyle,
+ cg.consoleText, &dummyParent, &textItem );
+}
+
+/*
+===================
+CG_DrawTutorial
+===================
+*/
+static void CG_DrawTutorial( rectDef_t *rect, float text_x, float text_y, vec4_t color,
+ float scale, int align, int textStyle )
+{
+ static menuDef_t dummyParent;
+ static itemDef_t textItem;
+
+ if( !cg_tutorial.integer )
+ return;
+
+ CG_DrawTextBlock( rect, text_x, text_y, color, scale, align, textStyle,
+ CG_TutorialText( ), &dummyParent, &textItem );
}
/*
@@ -2731,6 +2731,10 @@ void CG_OwnerDraw( float x, float y, float w, float h, float text_x,
CG_DrawConsole( &rect, text_x, text_y, color, scale, align, textStyle );
break;
+ case CG_TUTORIAL:
+ CG_DrawTutorial( &rect, text_x, text_y, color, scale, align, textStyle );
+ break;
+
default:
break;
}
diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h
index 43d924d0..6fbd815c 100644
--- a/src/cgame/cg_local.h
+++ b/src/cgame/cg_local.h
@@ -1479,6 +1479,7 @@ extern vmCvar_t cg_debugTrails;
extern vmCvar_t cg_debugPVS;
extern vmCvar_t cg_disableWarningDialogs;
extern vmCvar_t cg_disableScannerPlane;
+extern vmCvar_t cg_tutorial;
extern vmCvar_t cg_painBlendUpRate;
extern vmCvar_t cg_painBlendDownRate;
@@ -1508,6 +1509,7 @@ void QDECL CG_Printf( const char *msg, ... );
void QDECL CG_Error( const char *msg, ... );
void CG_StartMusic( void );
+int CG_PlayerCount( void );
void CG_UpdateCvars( void );
@@ -1606,6 +1608,7 @@ void CG_PrecacheClientInfo( pClass_t class, char *model, char *skin );
sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
void CG_PlayerDisconnect( vec3_t org );
void CG_Bleed( vec3_t origin, vec3_t normal, int entityNum );
+qboolean CG_AtHighestClass( void );
//
// cg_buildable.c
@@ -1814,6 +1817,11 @@ int CG_ReadPTRCode( void );
void CG_WritePTRCode( int code );
//
+// cg_tutorial.c
+//
+const char *CG_TutorialText( void );
+
+//
//===============================================
//
@@ -2000,6 +2008,9 @@ qboolean trap_Key_IsDown( int keynum );
int trap_Key_GetCatcher( void );
void trap_Key_SetCatcher( int catcher );
int trap_Key_GetKey( const char *binding );
+void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
+void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen );
+void trap_Key_SetBinding( int keynum, const char *binding );
typedef enum
{
diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c
index 34928132..5963d0bf 100644
--- a/src/cgame/cg_main.c
+++ b/src/cgame/cg_main.c
@@ -217,6 +217,7 @@ vmCvar_t cg_debugTrails;
vmCvar_t cg_debugPVS;
vmCvar_t cg_disableWarningDialogs;
vmCvar_t cg_disableScannerPlane;
+vmCvar_t cg_tutorial;
vmCvar_t cg_painBlendUpRate;
vmCvar_t cg_painBlendDownRate;
@@ -330,6 +331,7 @@ static cvarTable_t cvarTable[ ] =
{ &cg_debugPVS, "cg_debugPVS", "0", CVAR_CHEAT },
{ &cg_disableWarningDialogs, "cg_disableWarningDialogs", "0", CVAR_ARCHIVE },
{ &cg_disableScannerPlane, "cg_disableScannerPlane", "0", CVAR_ARCHIVE },
+ { &cg_tutorial, "cg_tutorial", "1", CVAR_ARCHIVE },
{ &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
{ &cg_painBlendUpRate, "cg_painBlendUpRate", "10.0", 0 },
@@ -992,6 +994,25 @@ void CG_StartMusic( void )
trap_S_StartBackgroundTrack( parm1, parm2 );
}
+/*
+======================
+CG_PlayerCount
+======================
+*/
+int CG_PlayerCount( void )
+{
+ int i, count = 0;
+
+ for( i = 0; i < cg.numScores; i++ )
+ {
+ if( cg.scores[ i ].team == PTE_ALIENS ||
+ cg.scores[ i ].team == PTE_HUMANS )
+ count++;
+ }
+
+ return count;
+}
+
//
// ==============================
// new hud stuff ( mission pack )
@@ -1708,6 +1729,7 @@ void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
//TA: load overrides
BG_InitClassOverrides( );
BG_InitBuildableOverrides( );
+ BG_InitAllowedGameElements( );
//TA: dyn memory
CG_InitMemory( );
diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c
index 3eb5e998..c6db37f1 100644
--- a/src/cgame/cg_players.c
+++ b/src/cgame/cg_players.c
@@ -2540,3 +2540,32 @@ void CG_Bleed( vec3_t origin, vec3_t normal, int entityNum )
CG_SetParticleSystemNormal( ps, normal );
}
}
+
+/*
+===============
+CG_AtHighestClass
+
+Is the local client at the highest class possible?
+===============
+*/
+qboolean CG_AtHighestClass( void )
+{
+ int i;
+ qboolean superiorClasses = qfalse;
+
+ for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
+ {
+ if( BG_ClassCanEvolveFromTo(
+ cg.predictedPlayerState.stats[ STAT_PCLASS ], i,
+ ALIEN_MAX_KILLS, 0 ) >= 0 &&
+ BG_FindStagesForClass( i, cgs.alienStage ) &&
+ BG_ClassIsAllowed( i ) )
+ {
+ superiorClasses = qtrue;
+ break;
+ }
+ }
+
+ return !superiorClasses;
+}
+
diff --git a/src/cgame/cg_public.h b/src/cgame/cg_public.h
index 0687cdfd..09f40d10 100644
--- a/src/cgame/cg_public.h
+++ b/src/cgame/cg_public.h
@@ -173,7 +173,11 @@ typedef enum
CG_GETDEMOPOS,
CG_GETDEMONAME,
- CG_MEMSET = 100,
+ CG_KEY_KEYNUMTOSTRINGBUF,
+ CG_KEY_GETBINDINGBUF,
+ CG_KEY_SETBINDING,
+
+ CG_MEMSET = 200,
CG_MEMCPY,
CG_STRNCPY,
CG_SIN,
diff --git a/src/cgame/cg_syscalls.asm b/src/cgame/cg_syscalls.asm
index cf373b8c..2fcc5296 100644
--- a/src/cgame/cg_syscalls.asm
+++ b/src/cgame/cg_syscalls.asm
@@ -97,16 +97,19 @@ equ trap_CM_TransformedBiSphereTrace -94
equ trap_GetDemoState -95
equ trap_GetDemoPos -96
equ trap_GetDemoName -97
+equ trap_Key_KeynumToStringBuf -98
+equ trap_Key_GetBindingBuf -99
+equ trap_Key_SetBinding -100
-equ memset -101
-equ memcpy -102
-equ strncpy -103
-equ sin -104
-equ cos -105
-equ atan2 -106
-equ sqrt -107
-equ floor -108
-equ ceil -109
-equ testPrintInt -110
-equ testPrintFloat -111
+equ memset -201
+equ memcpy -202
+equ strncpy -203
+equ sin -204
+equ cos -205
+equ atan2 -206
+equ sqrt -207
+equ floor -208
+equ ceil -209
+equ testPrintInt -210
+equ testPrintFloat -211
diff --git a/src/cgame/cg_syscalls.c b/src/cgame/cg_syscalls.c
index 37820fb4..1d982734 100644
--- a/src/cgame/cg_syscalls.c
+++ b/src/cgame/cg_syscalls.c
@@ -555,3 +555,16 @@ void trap_GetDemoName( char *buffer, int size )
{
syscall( CG_GETDEMONAME, buffer, size );
}
+
+void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {
+ syscall( CG_KEY_KEYNUMTOSTRINGBUF, keynum, buf, buflen );
+}
+
+void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
+ syscall( CG_KEY_GETBINDINGBUF, keynum, buf, buflen );
+}
+
+void trap_Key_SetBinding( int keynum, const char *binding ) {
+ syscall( CG_KEY_SETBINDING, keynum, binding );
+}
+
diff --git a/src/cgame/cg_tutorial.c b/src/cgame/cg_tutorial.c
new file mode 100644
index 00000000..f54786be
--- /dev/null
+++ b/src/cgame/cg_tutorial.c
@@ -0,0 +1,610 @@
+/*
+===========================================================================
+Copyright (C) 2000-2006 Tim Angus
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+// cg_tutorial.c -- the tutorial system
+
+#include "cg_local.h"
+
+typedef struct
+{
+ char *command;
+ char *humanName;
+ keyNum_t keys[ 2 ];
+} bind_t;
+
+static bind_t bindings[ ] =
+{
+ { "+button2", "Activate Upgrade", { -1, -1 } },
+ { "+speed", "Run/Walk", { -1, -1 } },
+ { "boost", "Sprint", { -1, -1 } },
+ { "+moveup", "Jump", { -1, -1 } },
+ { "+movedown", "Crouch", { -1, -1 } },
+ { "+zoom", "ZoomView", { -1, -1 } },
+ { "+attack", "Primary Attack", { -1, -1 } },
+ { "+button5", "Secondary Attack", { -1, -1 } },
+ { "reload", "Reload", { -1, -1 } },
+ { "buy ammo", "Buy Ammo", { -1, -1 } },
+ { "itemact medkit", "Use Medkit", { -1, -1 } },
+ { "+button7", "Use Structure/Evolve", { -1, -1 } },
+ { "deconstruct", "Deconstruct Structure", { -1, -1 } },
+ { "weapprev", "Previous Upgrade", { -1, -1 } },
+ { "weapnext", "Next Upgrade", { -1, -1 } }
+};
+
+static const int numBindings = sizeof( bindings ) / sizeof( bind_t );
+
+/*
+=================
+CG_GetBindings
+=================
+*/
+static void CG_GetBindings( void )
+{
+ int i, j, numKeys;
+ char buffer[ MAX_STRING_CHARS ];
+
+ for( i = 0; i < numBindings; i++ )
+ {
+ bindings[ i ].keys[ 0 ] = bindings[ i ].keys[ 1 ] = -1;
+ numKeys = 0;
+
+ for( j = 0; j < K_LAST_KEY; j++ )
+ {
+ trap_Key_GetBindingBuf( j, buffer, MAX_STRING_CHARS );
+
+ if( buffer[ 0 ] == 0 )
+ continue;
+
+ if( !Q_stricmp( buffer, bindings[ i ].command ) )
+ {
+ bindings[ i ].keys[ numKeys++ ] = j;
+
+ if( numKeys > 1 )
+ break;
+ }
+ }
+ }
+}
+
+/*
+===============
+CG_KeyNameForCommand
+===============
+*/
+static const char *CG_KeyNameForCommand( const char *command )
+{
+ int i, j;
+ static char buffer[ MAX_STRING_CHARS ];
+ int firstKeyLength;
+
+ buffer[ 0 ] = '\0';
+
+ for( i = 0; i < numBindings; i++ )
+ {
+ if( !Q_stricmp( command, bindings[ i ].command ) )
+ {
+ if( bindings[ i ].keys[ 0 ] >= 0 )
+ {
+ trap_Key_KeynumToStringBuf( bindings[ i ].keys[ 0 ],
+ buffer, MAX_STRING_CHARS );
+ firstKeyLength = strlen( buffer );
+
+ for( j = 0; j < firstKeyLength; j++ )
+ buffer[ j ] = toupper( buffer[ j ] );
+
+ if( bindings[ i ].keys[ 1 ] >= 0 )
+ {
+ Q_strcat( buffer, MAX_STRING_CHARS, " or " );
+ trap_Key_KeynumToStringBuf( bindings[ i ].keys[ 1 ],
+ buffer + strlen( buffer ), MAX_STRING_CHARS );
+
+ for( j = firstKeyLength + 4; j < strlen( buffer ); j++ )
+ buffer[ j ] = toupper( buffer[ j ] );
+ }
+ }
+ else
+ {
+ Q_strncpyz( buffer, va( "\"%s\"", bindings[ i ].humanName ),
+ MAX_STRING_CHARS );
+ Q_strcat( buffer, MAX_STRING_CHARS, " (unbound)" );
+ }
+
+ return buffer;
+ }
+ }
+
+ return "";
+}
+
+#define MAX_TUTORIAL_TEXT 4096
+
+/*
+===============
+CG_BuildableInRange
+===============
+*/
+static qboolean CG_BuildableInRange( playerState_t *ps )
+{
+ vec3_t view, point;
+ trace_t trace;
+ entityState_t *es;
+
+ AngleVectors( cg.refdefViewAngles, view, NULL, NULL );
+ VectorMA( cg.refdef.vieworg, 64, view, point );
+ CG_Trace( &trace, cg.refdef.vieworg, NULL, NULL,
+ point, ps->clientNum, MASK_SHOT );
+
+ es = &cg_entities[ trace.entityNum ].currentState;
+
+ if( es->eType == ET_BUILDABLE &&
+ ps->stats[ STAT_PTEAM ] == BG_FindTeamForBuildable( es->modelindex ) )
+ return qtrue;
+ else
+ return qfalse;
+}
+
+/*
+===============
+CG_AlienBuilderText
+===============
+*/
+static void CG_AlienBuilderText( char *text, playerState_t *ps )
+{
+ buildable_t buildable = ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT;
+
+ if( buildable > BA_NONE )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to place the %s\n",
+ CG_KeyNameForCommand( "+attack" ),
+ BG_FindHumanNameForBuildable( buildable ) ) );
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to cancel placing the %s\n",
+ CG_KeyNameForCommand( "+button5" ),
+ BG_FindHumanNameForBuildable( buildable ) ) );
+ }
+ else
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to build a structure\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+
+ if( CG_BuildableInRange( ps ) )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to destroy this structure\n",
+ CG_KeyNameForCommand( "deconstruct" ) ) );
+ }
+ }
+
+ if( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG )
+ {
+ if( ( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) == BA_NONE )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to swipe\n",
+ CG_KeyNameForCommand( "+button5" ) ) );
+ }
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to lauch a projectile\n",
+ CG_KeyNameForCommand( "+button2" ) ) );
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to walk on walls\n",
+ CG_KeyNameForCommand( "+movedown" ) ) );
+ }
+}
+
+/*
+===============
+CG_AlienLevel0Text
+===============
+*/
+static void CG_AlienLevel0Text( char *text, playerState_t *ps )
+{
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ "Touch a human to damage it\n" );
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to walk on walls\n",
+ CG_KeyNameForCommand( "+movedown" ) ) );
+}
+
+/*
+===============
+CG_AlienLevel1Text
+===============
+*/
+static void CG_AlienLevel1Text( char *text, playerState_t *ps )
+{
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to swipe\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+
+ if( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL1_UPG )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to spray poisonous gas\n",
+ CG_KeyNameForCommand( "+button5" ) ) );
+ }
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to walk on walls\n",
+ CG_KeyNameForCommand( "+movedown" ) ) );
+}
+
+/*
+===============
+CG_AlienLevel2Text
+===============
+*/
+static void CG_AlienLevel2Text( char *text, playerState_t *ps )
+{
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to bite\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+
+ if( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL2_UPG )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to invoke an electrical attack\n",
+ CG_KeyNameForCommand( "+button5" ) ) );
+ }
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Hold down %s then touch a wall to wall jump\n",
+ CG_KeyNameForCommand( "+moveup" ) ) );
+}
+
+/*
+===============
+CG_AlienLevel3Text
+===============
+*/
+static void CG_AlienLevel3Text( char *text, playerState_t *ps )
+{
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to bite\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+
+ if( ps->stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL3_UPG )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to launch a projectile\n",
+ CG_KeyNameForCommand( "+button2" ) ) );
+ }
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Hold down and release %s to pounce\n",
+ CG_KeyNameForCommand( "+button5" ) ) );
+}
+
+/*
+===============
+CG_AlienLevel4Text
+===============
+*/
+static void CG_AlienLevel4Text( char *text, playerState_t *ps )
+{
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to swipe\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Hold down and release %s to charge\n",
+ CG_KeyNameForCommand( "+button5" ) ) );
+}
+
+/*
+===============
+CG_HumanCkitText
+===============
+*/
+static void CG_HumanCkitText( char *text, playerState_t *ps )
+{
+ buildable_t buildable = ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT;
+
+ if( buildable > BA_NONE )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to place the %s\n",
+ CG_KeyNameForCommand( "+attack" ),
+ BG_FindHumanNameForBuildable( buildable ) ) );
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to cancel placing the %s\n",
+ CG_KeyNameForCommand( "+button5" ),
+ BG_FindHumanNameForBuildable( buildable ) ) );
+ }
+ else
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to build a structure\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+
+ if( CG_BuildableInRange( ps ) )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to destroy this structure\n",
+ CG_KeyNameForCommand( "deconstruct" ) ) );
+ }
+ }
+}
+
+/*
+===============
+CG_HumanText
+===============
+*/
+static void CG_HumanText( char *text, playerState_t *ps )
+{
+ char *name;
+ int ammo, clips;
+ upgrade_t upgrade = UP_NONE;
+
+ if( cg.weaponSelect <= 32 )
+ name = cg_weapons[ cg.weaponSelect ].humanName;
+ else if( cg.weaponSelect > 32 )
+ {
+ name = cg_upgrades[ cg.weaponSelect - 32 ].humanName;
+ upgrade = cg.weaponSelect - 32;
+ }
+
+ BG_UnpackAmmoArray( ps->weapon, ps->ammo, ps->powerups, &ammo, &clips );
+
+ if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( ps->weapon ) )
+ {
+ //no ammo
+ switch( ps->weapon )
+ {
+ case WP_MACHINEGUN:
+ case WP_CHAINGUN:
+ case WP_SHOTGUN:
+ case WP_FLAMER:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Find an Armoury and press %s for more ammo\n",
+ CG_KeyNameForCommand( "buy ammo" ) ) );
+ break;
+
+ case WP_LAS_GUN:
+ case WP_PULSE_RIFLE:
+ case WP_MASS_DRIVER:
+ case WP_LUCIFER_CANNON:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Find a Reactor or Repeater and press %s for more ammo\n",
+ CG_KeyNameForCommand( "buy ammo" ) ) );
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch( ps->weapon )
+ {
+ case WP_BLASTER:
+ case WP_MACHINEGUN:
+ case WP_SHOTGUN:
+ case WP_LAS_GUN:
+ case WP_CHAINGUN:
+ case WP_PULSE_RIFLE:
+ case WP_FLAMER:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to fire the %s\n",
+ CG_KeyNameForCommand( "+attack" ),
+ BG_FindHumanNameForWeapon( ps->weapon ) ) );
+ break;
+
+ case WP_MASS_DRIVER:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to fire the %s\n",
+ CG_KeyNameForCommand( "+attack" ),
+ BG_FindHumanNameForWeapon( ps->weapon ) ) );
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Hold %s to zoom\n",
+ CG_KeyNameForCommand( "+zoom" ) ) );
+ break;
+
+ case WP_PAIN_SAW:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Hold %s to activate the %s\n",
+ CG_KeyNameForCommand( "+attack" ),
+ BG_FindHumanNameForWeapon( ps->weapon ) ) );
+ break;
+
+ case WP_LUCIFER_CANNON:
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Hold and release %s to fire a charged shot\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to fire the %s\n",
+ CG_KeyNameForCommand( "+button5" ),
+ BG_FindHumanNameForWeapon( ps->weapon ) ) );
+ break;
+
+ case WP_HBUILD:
+ case WP_HBUILD2:
+ CG_HumanCkitText( text, ps );
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s and ",
+ CG_KeyNameForCommand( "weapprev" ) ) );
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "%s to select an upgrade\n",
+ CG_KeyNameForCommand( "weapnext" ) ) );
+
+ if( upgrade == UP_NONE ||
+ ( upgrade > UP_NONE && BG_FindUsableForUpgrade( upgrade ) ) )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to use the %s\n",
+ CG_KeyNameForCommand( "+button2" ),
+ name ) );
+ }
+
+ if( ps->stats[ STAT_HEALTH ] <= 35 &&
+ BG_InventoryContainsUpgrade( UP_MEDKIT, ps->stats ) )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to use your %s\n",
+ CG_KeyNameForCommand( "itemact medkit" ),
+ BG_FindHumanNameForUpgrade( UP_MEDKIT ) ) );
+ }
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to use a structure\n",
+ CG_KeyNameForCommand( "+button7" ) ) );
+}
+
+/*
+===============
+CG_SpectatorText
+===============
+*/
+static void CG_SpectatorText( char *text, playerState_t *ps )
+{
+ if( ps->pm_type == PM_SPECTATOR )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to join a team\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+
+ if( ps->pm_flags & PMF_FOLLOW )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to return to free spectator mode\n",
+ CG_KeyNameForCommand( "+button2" ) ) );
+
+ if( CG_PlayerCount( ) > 1 )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s or ",
+ CG_KeyNameForCommand( "weapprev" ) ) );
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "%s to change player\n",
+ CG_KeyNameForCommand( "weapnext" ) ) );
+ }
+ }
+ else
+ {
+ if( CG_PlayerCount( ) > 0 )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to enter spectator follow mode\n",
+ CG_KeyNameForCommand( "+button2" ) ) );
+ }
+ }
+ }
+ else
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to spawn\n",
+ CG_KeyNameForCommand( "+attack" ) ) );
+ }
+}
+
+/*
+===============
+CG_TutorialText
+
+Returns context help for the current class/weapon
+===============
+*/
+const char *CG_TutorialText( void )
+{
+ playerState_t *ps;
+ static char text[ MAX_TUTORIAL_TEXT ];
+
+ CG_GetBindings( );
+
+ text[ 0 ] = '\0';
+ ps = &cg.snap->ps;
+
+ if( !cg.intermissionStarted )
+ {
+ if( ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
+ CG_SpectatorText( text, ps );
+ else if( ps->stats[ STAT_HEALTH ] > 0 )
+ {
+ switch( ps->stats[ STAT_PCLASS ] )
+ {
+ case PCL_ALIEN_BUILDER0:
+ case PCL_ALIEN_BUILDER0_UPG:
+ CG_AlienBuilderText( text, ps );
+ break;
+
+ case PCL_ALIEN_LEVEL0:
+ CG_AlienLevel0Text( text, ps );
+ break;
+
+ case PCL_ALIEN_LEVEL1:
+ case PCL_ALIEN_LEVEL1_UPG:
+ CG_AlienLevel1Text( text, ps );
+ break;
+
+ case PCL_ALIEN_LEVEL2:
+ case PCL_ALIEN_LEVEL2_UPG:
+ CG_AlienLevel2Text( text, ps );
+ break;
+
+ case PCL_ALIEN_LEVEL3:
+ case PCL_ALIEN_LEVEL3_UPG:
+ CG_AlienLevel3Text( text, ps );
+ break;
+
+ case PCL_ALIEN_LEVEL4:
+ CG_AlienLevel4Text( text, ps );
+ break;
+
+ case PCL_HUMAN:
+ CG_HumanText( text, ps );
+ break;
+
+ default:
+ break;
+ }
+
+ if( ps->stats[ STAT_PTEAM ] == PTE_ALIENS &&
+ BG_UpgradeClassAvailable( ps ) )
+ {
+ Q_strcat( text, MAX_TUTORIAL_TEXT,
+ va( "Press %s to evolve\n",
+ CG_KeyNameForCommand( "+button7" ) ) );
+ }
+ }
+
+ Q_strcat( text, MAX_TUTORIAL_TEXT, "Press ESC for the menu" );
+ }
+
+ return text;
+}
diff --git a/src/client/cl_cgame.c b/src/client/cl_cgame.c
index 5b09acfa..96a18f6e 100644
--- a/src/client/cl_cgame.c
+++ b/src/client/cl_cgame.c
@@ -636,6 +636,16 @@ long CL_CgameSystemCalls( long *args ) {
CL_DemoName( VMA(1), args[2] );
return 0;
+ case CG_KEY_KEYNUMTOSTRINGBUF:
+ Key_KeynumToStringBuf( args[1], VMA(2), args[3] );
+ return 0;
+ case CG_KEY_GETBINDINGBUF:
+ Key_GetBindingBuf( args[1], VMA(2), args[3] );
+ return 0;
+ case CG_KEY_SETBINDING:
+ Key_SetBinding( args[1], VMA(2) );
+ return 0;
+
case CG_MEMSET:
Com_Memset( VMA(1), args[2], args[3] );
diff --git a/src/client/cl_keys.c b/src/client/cl_keys.c
index 8a1eb2cf..f80c24c3 100644
--- a/src/client/cl_keys.c
+++ b/src/client/cl_keys.c
@@ -1251,3 +1251,46 @@ void Key_ClearStates (void)
}
}
+/*
+====================
+Key_KeynumToStringBuf
+====================
+*/
+void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {
+ Q_strncpyz( buf, Key_KeynumToString( keynum ), buflen );
+}
+
+/*
+====================
+Key_GetBindingBuf
+====================
+*/
+void Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
+ char *value;
+
+ value = Key_GetBinding( keynum );
+ if ( value ) {
+ Q_strncpyz( buf, value, buflen );
+ }
+ else {
+ *buf = 0;
+ }
+}
+
+/*
+====================
+Key_GetCatcher
+====================
+*/
+int Key_GetCatcher( void ) {
+ return cls.keyCatchers;
+}
+
+/*
+====================
+Ket_SetCatcher
+====================
+*/
+void Key_SetCatcher( int catcher ) {
+ cls.keyCatchers = catcher;
+}
diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c
index 7351d77e..eee0ba1f 100644
--- a/src/client/cl_ui.c
+++ b/src/client/cl_ui.c
@@ -627,51 +627,6 @@ static void GetClipboardData( char *buf, int buflen ) {
/*
====================
-Key_KeynumToStringBuf
-====================
-*/
-static void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) {
- Q_strncpyz( buf, Key_KeynumToString( keynum ), buflen );
-}
-
-/*
-====================
-Key_GetBindingBuf
-====================
-*/
-static void Key_GetBindingBuf( int keynum, char *buf, int buflen ) {
- char *value;
-
- value = Key_GetBinding( keynum );
- if ( value ) {
- Q_strncpyz( buf, value, buflen );
- }
- else {
- *buf = 0;
- }
-}
-
-/*
-====================
-Key_GetCatcher
-====================
-*/
-int Key_GetCatcher( void ) {
- return cls.keyCatchers;
-}
-
-/*
-====================
-Ket_SetCatcher
-====================
-*/
-void Key_SetCatcher( int catcher ) {
- cls.keyCatchers = catcher;
-}
-
-
-/*
-====================
GetConfigString
====================
*/
diff --git a/src/client/keys.h b/src/client/keys.h
index b1498a88..fbab475f 100644
--- a/src/client/keys.h
+++ b/src/client/keys.h
@@ -56,3 +56,5 @@ qboolean Key_GetOverstrikeMode( void );
void Key_SetOverstrikeMode( qboolean state );
void Key_ClearStates( void );
int Key_GetKey(const char *binding);
+void Key_KeynumToStringBuf( int keynum, char *buf, int buflen );
+void Key_GetBindingBuf( int keynum, char *buf, int buflen );
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
index cf2649ee..f04d562f 100644
--- a/src/game/bg_misc.c
+++ b/src/game/bg_misc.c
@@ -3989,6 +3989,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"Light Armour", //char *upgradeHumanName;
"icons/iconu_larmour",
qtrue, //qboolean purchasable
+ qfalse, //qboolean usable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4000,6 +4001,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"Helmet", //char *upgradeHumanName;
"icons/iconu_helmet",
qtrue, //qboolean purchasable
+ qfalse, //qboolean usable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4011,6 +4013,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"Medkit", //char *upgradeHumanName;
"icons/iconu_atoxin",
qfalse, //qboolean purchasable
+ qtrue, //qboolean usable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4022,6 +4025,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"Battery Pack", //char *upgradeHumanName;
"icons/iconu_battpack",
qtrue, //qboolean purchasable
+ qfalse, //qboolean usable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4033,6 +4037,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"Jet Pack", //char *upgradeHumanName;
"icons/iconu_jetpack",
qtrue, //qboolean purchasable
+ qtrue, //qboolean usable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4044,6 +4049,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"Battlesuit", //char *upgradeHumanName;
"icons/iconu_bsuit",
qtrue, //qboolean purchasable
+ qfalse, //qboolean usable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4055,6 +4061,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"Grenade", //char *upgradeHumanName;
0,
qtrue, //qboolean purchasable
+ qtrue, //qboolean usable
WUT_HUMANS //WUTeam_t team;
},
{
@@ -4066,6 +4073,7 @@ upgradeAttributes_t bg_upgrades[ ] =
"Ammunition", //char *upgradeHumanName;
0,
qtrue, //qboolean purchasable
+ qfalse, //qboolean usable
WUT_HUMANS //WUTeam_t team;
}
};
@@ -4231,6 +4239,24 @@ qboolean BG_FindPurchasableForUpgrade( int upgrade )
/*
==============
+BG_FindUsableForUpgrade
+==============
+*/
+qboolean BG_FindUsableForUpgrade( int upgrade )
+{
+ int i;
+
+ for( i = 0; i < bg_numUpgrades; i++ )
+ {
+ if( bg_upgrades[ i ].upgradeNum == upgrade )
+ return bg_upgrades[ i ].usable;
+ }
+
+ return qfalse;
+}
+
+/*
+==============
BG_FindTeamForUpgrade
==============
*/
@@ -5254,3 +5280,146 @@ void BG_ParseCSVBuildableList( const char *string, buildable_t *buildables, int
buildables[ i ] = BA_NONE;
}
+
+/*
+============
+BG_UpgradeClassAvailable
+============
+*/
+qboolean BG_UpgradeClassAvailable( playerState_t *ps )
+{
+ int i;
+ char buffer[ MAX_STRING_CHARS ];
+ stage_t currentStage;
+
+ trap_Cvar_VariableStringBuffer( "g_alienStage", buffer, MAX_STRING_CHARS );
+ currentStage = atoi( buffer );
+
+ for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ )
+ {
+ if( BG_ClassCanEvolveFromTo( ps->stats[ STAT_PCLASS ], i,
+ ps->persistant[ PERS_CREDIT ], 0 ) >= 0 &&
+ BG_FindStagesForClass( i, currentStage ) &&
+ BG_ClassIsAllowed( i ) )
+ {
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+}
+
+typedef struct gameElements_s
+{
+ buildable_t buildables[ BA_NUM_BUILDABLES ];
+ pClass_t classes[ PCL_NUM_CLASSES ];
+ weapon_t weapons[ WP_NUM_WEAPONS ];
+ upgrade_t upgrades[ UP_NUM_UPGRADES ];
+} gameElements_t;
+
+static gameElements_t bg_disabledGameElements;
+
+/*
+============
+BG_InitAllowedGameElements
+============
+*/
+void BG_InitAllowedGameElements( void )
+{
+ char cvar[ MAX_CVAR_VALUE_STRING ];
+
+ trap_Cvar_VariableStringBuffer( "g_disabledEquipment",
+ cvar, MAX_CVAR_VALUE_STRING );
+
+ BG_ParseCSVEquipmentList( cvar,
+ bg_disabledGameElements.weapons, WP_NUM_WEAPONS,
+ bg_disabledGameElements.upgrades, UP_NUM_UPGRADES );
+
+ trap_Cvar_VariableStringBuffer( "g_disabledClasses",
+ cvar, MAX_CVAR_VALUE_STRING );
+
+ BG_ParseCSVClassList( cvar,
+ bg_disabledGameElements.classes, PCL_NUM_CLASSES );
+
+ trap_Cvar_VariableStringBuffer( "g_disabledBuildables",
+ cvar, MAX_CVAR_VALUE_STRING );
+
+ BG_ParseCSVBuildableList( cvar,
+ bg_disabledGameElements.buildables, BA_NUM_BUILDABLES );
+}
+
+/*
+============
+BG_WeaponIsAllowed
+============
+*/
+qboolean BG_WeaponIsAllowed( weapon_t weapon )
+{
+ int i;
+
+ for( i = 0; i < WP_NUM_WEAPONS &&
+ bg_disabledGameElements.weapons[ i ] != WP_NONE; i++ )
+ {
+ if( bg_disabledGameElements.weapons[ i ] == weapon )
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+============
+BG_UpgradeIsAllowed
+============
+*/
+qboolean BG_UpgradeIsAllowed( upgrade_t upgrade )
+{
+ int i;
+
+ for( i = 0; i < UP_NUM_UPGRADES &&
+ bg_disabledGameElements.upgrades[ i ] != UP_NONE; i++ )
+ {
+ if( bg_disabledGameElements.upgrades[ i ] == upgrade )
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+============
+BG_ClassIsAllowed
+============
+*/
+qboolean BG_ClassIsAllowed( pClass_t class )
+{
+ int i;
+
+ for( i = 0; i < PCL_NUM_CLASSES &&
+ bg_disabledGameElements.classes[ i ] != PCL_NONE; i++ )
+ {
+ if( bg_disabledGameElements.classes[ i ] == class )
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+============
+BG_BuildableIsAllowed
+============
+*/
+qboolean BG_BuildableIsAllowed( buildable_t buildable )
+{
+ int i;
+
+ for( i = 0; i < BA_NUM_BUILDABLES &&
+ bg_disabledGameElements.buildables[ i ] != BA_NONE; i++ )
+ {
+ if( bg_disabledGameElements.buildables[ i ] == buildable )
+ return qfalse;
+ }
+
+ return qtrue;
+}
diff --git a/src/game/bg_public.h b/src/game/bg_public.h
index 38e7b3ee..b7e1411e 100644
--- a/src/game/bg_public.h
+++ b/src/game/bg_public.h
@@ -1078,6 +1078,7 @@ typedef struct
char *icon;
qboolean purchasable;
+ qboolean usable;
WUTeam_t team;
} upgradeAttributes_t;
@@ -1207,6 +1208,7 @@ int BG_FindUpgradeNumForName( char *name );
char *BG_FindHumanNameForUpgrade( int upgrade );
char *BG_FindIconForUpgrade( int upgrade );
qboolean BG_FindPurchasableForUpgrade( int upgrade );
+qboolean BG_FindUsableForUpgrade( int upgrade );
WUTeam_t BG_FindTeamForUpgrade( int upgrade );
// content masks
@@ -1276,3 +1278,9 @@ void BG_ParseCSVEquipmentList( const char *string, weapon_t *weapons, int weapon
upgrade_t *upgrades, int upgradesSize );
void BG_ParseCSVClassList( const char *string, pClass_t *classes, int classesSize );
void BG_ParseCSVBuildableList( const char *string, buildable_t *buildables, int buildablesSize );
+void BG_InitAllowedGameElements( void );
+qboolean BG_WeaponIsAllowed( weapon_t weapon );
+qboolean BG_UpgradeIsAllowed( upgrade_t upgrade );
+qboolean BG_ClassIsAllowed( pClass_t class );
+qboolean BG_BuildableIsAllowed( buildable_t buildable );
+qboolean BG_UpgradeClassAvailable( playerState_t *ps );
diff --git a/src/game/g_active.c b/src/game/g_active.c
index 86bfbdc5..9c8f8a1c 100644
--- a/src/game/g_active.c
+++ b/src/game/g_active.c
@@ -1292,8 +1292,6 @@ void ClientThink_real( gentity_t *ent )
vec3_t range = { USE_OBJECT_RANGE, USE_OBJECT_RANGE, USE_OBJECT_RANGE };
vec3_t mins, maxs;
int i, num;
- int j;
- qboolean upgrade = qfalse;
//TA: look for object infront of player
AngleVectors( client->ps.viewangles, view, NULL, NULL );
@@ -1325,18 +1323,7 @@ void ClientThink_real( gentity_t *ent )
if( i == num && client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS )
{
- for( j = PCL_NONE + 1; j < PCL_NUM_CLASSES; j++ )
- {
- if( BG_ClassCanEvolveFromTo( client->ps.stats[ STAT_PCLASS ], j,
- client->ps.persistant[ PERS_CREDIT ], 0 ) >= 0 &&
- BG_FindStagesForClass( j, g_alienStage.integer ) && G_ClassIsAllowed( j ) )
- {
- upgrade = qtrue;
- break;
- }
- }
-
- if( upgrade )
+ if( BG_UpgradeClassAvailable( &client->ps ) )
{
//no nearby objects and alien - show class menu
G_TriggerMenu( ent->client->ps.clientNum, MN_A_INFEST );
diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c
index b53d4bd2..f091ff48 100644
--- a/src/game/g_cmds.c
+++ b/src/game/g_cmds.c
@@ -1121,14 +1121,14 @@ void Cmd_Class_f( gentity_t *ent )
clientNum = ent->client - level.clients;
trap_Argv( 1, s, sizeof( s ) );
- if( G_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) )
+ if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) )
allowedClasses[ numClasses++ ] = PCL_ALIEN_BUILDER0;
- if( G_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) &&
+ if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) &&
BG_FindStagesForClass( PCL_ALIEN_BUILDER0_UPG, g_alienStage.integer ) )
allowedClasses[ numClasses++ ] = PCL_ALIEN_BUILDER0_UPG;
- if( G_ClassIsAllowed( PCL_ALIEN_LEVEL0 ) )
+ if( BG_ClassIsAllowed( PCL_ALIEN_LEVEL0 ) )
allowedClasses[ numClasses++ ] = PCL_ALIEN_LEVEL0;
if( ent->client->pers.teamSelection == PTE_ALIENS &&
@@ -1216,7 +1216,7 @@ void Cmd_Class_f( gentity_t *ent )
//...check we can evolve to that class
if( numLevels >= 0 &&
BG_FindStagesForClass( ent->client->pers.classSelection, g_alienStage.integer ) &&
- G_ClassIsAllowed( ent->client->pers.classSelection ) )
+ BG_ClassIsAllowed( ent->client->pers.classSelection ) )
{
ent->client->pers.evolveHealthFraction = (float)ent->client->ps.stats[ STAT_HEALTH ] /
(float)BG_FindHealthForClass( currentClass );
@@ -1261,7 +1261,7 @@ void Cmd_Class_f( gentity_t *ent )
{
if( allowedClasses[ i ] == ent->client->pers.classSelection &&
BG_FindStagesForClass( ent->client->pers.classSelection, g_alienStage.integer ) &&
- G_ClassIsAllowed( ent->client->pers.classSelection ) )
+ BG_ClassIsAllowed( ent->client->pers.classSelection ) )
{
G_PushSpawnQueue( &level.alienSpawnQueue, clientNum );
return;
@@ -1291,11 +1291,11 @@ void Cmd_Class_f( gentity_t *ent )
ent->client->ps.stats[ STAT_PCLASS ] = PCL_HUMAN;
//set the item to spawn with
- if( !Q_stricmp( s, BG_FindNameForWeapon( WP_MACHINEGUN ) ) && G_WeaponIsAllowed( WP_MACHINEGUN ) )
+ if( !Q_stricmp( s, BG_FindNameForWeapon( WP_MACHINEGUN ) ) && BG_WeaponIsAllowed( WP_MACHINEGUN ) )
ent->client->pers.humanItemSelection = WP_MACHINEGUN;
- else if( !Q_stricmp( s, BG_FindNameForWeapon( WP_HBUILD ) ) && G_WeaponIsAllowed( WP_HBUILD ) )
+ else if( !Q_stricmp( s, BG_FindNameForWeapon( WP_HBUILD ) ) && BG_WeaponIsAllowed( WP_HBUILD ) )
ent->client->pers.humanItemSelection = WP_HBUILD;
- else if( !Q_stricmp( s, BG_FindNameForWeapon( WP_HBUILD2 ) ) && G_WeaponIsAllowed( WP_HBUILD2 ) &&
+ else if( !Q_stricmp( s, BG_FindNameForWeapon( WP_HBUILD2 ) ) && BG_WeaponIsAllowed( WP_HBUILD2 ) &&
BG_FindStagesForWeapon( WP_HBUILD2, g_humanStage.integer ) )
ent->client->pers.humanItemSelection = WP_HBUILD2;
else
@@ -1569,7 +1569,7 @@ void Cmd_Buy_f( gentity_t *ent )
}
//are we /allowed/ to buy this?
- if( !BG_FindStagesForWeapon( weapon, g_humanStage.integer ) || !G_WeaponIsAllowed( weapon ) )
+ if( !BG_FindStagesForWeapon( weapon, g_humanStage.integer ) || !BG_WeaponIsAllowed( weapon ) )
{
G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
return;
@@ -1632,7 +1632,7 @@ void Cmd_Buy_f( gentity_t *ent )
}
//are we /allowed/ to buy this?
- if( !BG_FindStagesForUpgrade( upgrade, g_humanStage.integer ) || !G_UpgradeIsAllowed( upgrade ) )
+ if( !BG_FindStagesForUpgrade( upgrade, g_humanStage.integer ) || !BG_UpgradeIsAllowed( upgrade ) )
{
G_SendCommandFromServer( ent-g_entities, va( "print \"You can't buy this item\n\"" ) );
return;
@@ -1844,7 +1844,7 @@ void Cmd_Build_f( gentity_t *ent )
( ( 1 << ent->client->ps.weapon ) & BG_FindBuildWeaponForBuildable( buildable ) ) &&
!( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) &&
!( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) &&
- G_BuildableIsAllowed( buildable ) &&
+ BG_BuildableIsAllowed( buildable ) &&
( ( team == PTE_ALIENS && BG_FindStagesForBuildable( buildable, g_alienStage.integer ) ) ||
( team == PTE_HUMANS && BG_FindStagesForBuildable( buildable, g_humanStage.integer ) ) ) )
{
diff --git a/src/game/g_local.h b/src/game/g_local.h
index 4431edaf..1648f116 100644
--- a/src/game/g_local.h
+++ b/src/game/g_local.h
@@ -886,11 +886,6 @@ void SendScoreboardMessageToAllClients( void );
void QDECL G_Printf( const char *fmt, ... );
void QDECL G_Error( const char *fmt, ... );
-qboolean G_WeaponIsAllowed( weapon_t weapon );
-qboolean G_UpgradeIsAllowed( upgrade_t upgrade );
-qboolean G_ClassIsAllowed( pClass_t class );
-qboolean G_BuildableIsAllowed( buildable_t buildable );
-
//
// g_client.c
//
diff --git a/src/game/g_main.c b/src/game/g_main.c
index e77b5b76..d3e5b13e 100644
--- a/src/game/g_main.c
+++ b/src/game/g_main.c
@@ -426,111 +426,6 @@ void G_UpdateCvars( void )
G_RemapTeamShaders( );
}
-
-typedef struct gameElements_s
-{
- buildable_t buildables[ BA_NUM_BUILDABLES ];
- pClass_t classes[ PCL_NUM_CLASSES ];
- weapon_t weapons[ WP_NUM_WEAPONS ];
- upgrade_t upgrades[ UP_NUM_UPGRADES ];
-} gameElements_t;
-
-static gameElements_t disabledGameElements;
-
-/*
-============
-G_InitAllowedGameElements
-============
-*/
-static void G_InitAllowedGameElements( void )
-{
- BG_ParseCSVEquipmentList( g_disabledEquipment.string,
- disabledGameElements.weapons, WP_NUM_WEAPONS,
- disabledGameElements.upgrades, UP_NUM_UPGRADES );
-
- BG_ParseCSVClassList( g_disabledClasses.string,
- disabledGameElements.classes, PCL_NUM_CLASSES );
-
- BG_ParseCSVBuildableList( g_disabledBuildables.string,
- disabledGameElements.buildables, BA_NUM_BUILDABLES );
-}
-
-/*
-============
-G_WeaponIsAllowed
-============
-*/
-qboolean G_WeaponIsAllowed( weapon_t weapon )
-{
- int i;
-
- for( i = 0; i < WP_NUM_WEAPONS &&
- disabledGameElements.weapons[ i ] != WP_NONE; i++ )
- {
- if( disabledGameElements.weapons[ i ] == weapon )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-============
-G_UpgradeIsAllowed
-============
-*/
-qboolean G_UpgradeIsAllowed( upgrade_t upgrade )
-{
- int i;
-
- for( i = 0; i < UP_NUM_UPGRADES &&
- disabledGameElements.upgrades[ i ] != UP_NONE; i++ )
- {
- if( disabledGameElements.upgrades[ i ] == upgrade )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-============
-G_ClassIsAllowed
-============
-*/
-qboolean G_ClassIsAllowed( pClass_t class )
-{
- int i;
-
- for( i = 0; i < PCL_NUM_CLASSES &&
- disabledGameElements.classes[ i ] != PCL_NONE; i++ )
- {
- if( disabledGameElements.classes[ i ] == class )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-============
-G_BuildableIsAllowed
-============
-*/
-qboolean G_BuildableIsAllowed( buildable_t buildable )
-{
- int i;
-
- for( i = 0; i < BA_NUM_BUILDABLES &&
- disabledGameElements.buildables[ i ] != BA_NONE; i++ )
- {
- if( disabledGameElements.buildables[ i ] == buildable )
- return qfalse;
- }
-
- return qtrue;
-}
-
/*
============
G_InitGame
@@ -610,7 +505,7 @@ void G_InitGame( int levelTime, int randomSeed, int restart )
G_SpawnEntitiesFromString( );
// the map might disable some things
- G_InitAllowedGameElements( );
+ BG_InitAllowedGameElements( );
// general initialization
G_FindTeams( );
diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c
index 198a33f6..aee374bd 100644
--- a/src/ui/ui_main.c
+++ b/src/ui/ui_main.c
@@ -3153,110 +3153,6 @@ static void UI_LoadTremTeams( void )
}
/*
-============
-UI_WeaponIsAllowed
-============
-*/
-qboolean UI_WeaponIsAllowed( weapon_t weapon )
-{
- int i;
- weapon_t weapons[ WP_NUM_WEAPONS ];
- char cvar[ MAX_CVAR_VALUE_STRING ];
-
- trap_Cvar_VariableStringBuffer( "g_disabledEquipment",
- cvar, MAX_CVAR_VALUE_STRING );
-
- BG_ParseCSVEquipmentList( cvar, weapons, WP_NUM_WEAPONS, NULL, 0 );
-
- for( i = 0; i < WP_NUM_WEAPONS &&
- weapons[ i ] != WP_NONE; i++ )
- {
- if( weapons[ i ] == weapon )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-============
-UI_UpgradeIsAllowed
-============
-*/
-qboolean UI_UpgradeIsAllowed( upgrade_t upgrade )
-{
- int i;
- upgrade_t upgrades[ UP_NUM_UPGRADES ];
- char cvar[ MAX_CVAR_VALUE_STRING ];
-
- trap_Cvar_VariableStringBuffer( "g_disabledEquipment",
- cvar, MAX_CVAR_VALUE_STRING );
-
- BG_ParseCSVEquipmentList( cvar, NULL, 0, upgrades, UP_NUM_UPGRADES );
-
- for( i = 0; i < UP_NUM_UPGRADES &&
- upgrades[ i ] != UP_NONE; i++ )
- {
- if( upgrades[ i ] == upgrade )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-============
-UI_ClassIsAllowed
-============
-*/
-qboolean UI_ClassIsAllowed( pClass_t class )
-{
- int i;
- pClass_t classes[ PCL_NUM_CLASSES ];
- char cvar[ MAX_CVAR_VALUE_STRING ];
-
- trap_Cvar_VariableStringBuffer( "g_disabledClasses",
- cvar, MAX_CVAR_VALUE_STRING );
-
- BG_ParseCSVClassList( cvar, classes, PCL_NUM_CLASSES );
-
- for( i = 0; i < PCL_NUM_CLASSES &&
- classes[ i ] != PCL_NONE; i++ )
- {
- if( classes[ i ] == class )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
-============
-UI_BuildableIsAllowed
-============
-*/
-qboolean UI_BuildableIsAllowed( buildable_t buildable )
-{
- int i;
- buildable_t buildables[ BA_NUM_BUILDABLES ];
- char cvar[ MAX_CVAR_VALUE_STRING ];
-
- trap_Cvar_VariableStringBuffer( "g_disabledBuildables",
- cvar, MAX_CVAR_VALUE_STRING );
-
- BG_ParseCSVBuildableList( cvar, buildables, BA_NUM_BUILDABLES );
-
- for( i = 0; i < BA_NUM_BUILDABLES &&
- buildables[ i ] != BA_NONE; i++ )
- {
- if( buildables[ i ] == buildable )
- return qfalse;
- }
-
- return qtrue;
-}
-
-/*
===============
UI_AddClass
===============
@@ -3282,13 +3178,13 @@ static void UI_LoadTremAlienClasses( void )
{
uiInfo.tremAlienClassCount = 0;
- if( UI_ClassIsAllowed( PCL_ALIEN_LEVEL0 ) )
+ if( BG_ClassIsAllowed( PCL_ALIEN_LEVEL0 ) )
UI_AddClass( PCL_ALIEN_LEVEL0 );
- if( UI_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) &&
+ if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) &&
BG_FindStagesForClass( PCL_ALIEN_BUILDER0_UPG, UI_GetCurrentAlienStage( ) ) )
UI_AddClass( PCL_ALIEN_BUILDER0_UPG );
- else if( UI_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) )
+ else if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) )
UI_AddClass( PCL_ALIEN_BUILDER0 );
}
@@ -3318,13 +3214,13 @@ static void UI_LoadTremHumanItems( void )
{
uiInfo.tremHumanItemCount = 0;
- if( UI_WeaponIsAllowed( WP_MACHINEGUN ) )
+ if( BG_WeaponIsAllowed( WP_MACHINEGUN ) )
UI_AddItem( WP_MACHINEGUN );
- if( UI_WeaponIsAllowed( WP_HBUILD2 ) &&
+ if( BG_WeaponIsAllowed( WP_HBUILD2 ) &&
BG_FindStagesForWeapon( WP_HBUILD2, UI_GetCurrentHumanStage( ) ) )
UI_AddItem( WP_HBUILD2 );
- else if( UI_WeaponIsAllowed( WP_HBUILD ) )
+ else if( BG_WeaponIsAllowed( WP_HBUILD ) )
UI_AddItem( WP_HBUILD );
}
@@ -3421,7 +3317,7 @@ static void UI_LoadTremHumanArmouryBuys( void )
if( BG_FindTeamForWeapon( i ) == WUT_HUMANS &&
BG_FindPurchasableForWeapon( i ) &&
BG_FindStagesForWeapon( i, stage ) &&
- UI_WeaponIsAllowed( i ) &&
+ BG_WeaponIsAllowed( i ) &&
!( BG_FindSlotsForWeapon( i ) & slots ) &&
!( weapons & ( 1 << i ) ) )
{
@@ -3443,7 +3339,7 @@ static void UI_LoadTremHumanArmouryBuys( void )
if( BG_FindTeamForUpgrade( i ) == WUT_HUMANS &&
BG_FindPurchasableForUpgrade( i ) &&
BG_FindStagesForUpgrade( i, stage ) &&
- UI_UpgradeIsAllowed( i ) &&
+ BG_UpgradeIsAllowed( i ) &&
!( BG_FindSlotsForUpgrade( i ) & slots ) &&
!( upgrades & ( 1 << i ) ) )
{
@@ -3528,7 +3424,7 @@ static void UI_LoadTremAlienUpgrades( void )
{
if( BG_ClassCanEvolveFromTo( class, i, credits, 0 ) >= 0 &&
BG_FindStagesForClass( i, stage ) &&
- UI_ClassIsAllowed( i ) )
+ BG_ClassIsAllowed( i ) )
{
uiInfo.tremAlienUpgradeList[ j ].text = String_Alloc( BG_FindHumanNameForClassNum( i ) );
uiInfo.tremAlienUpgradeList[ j ].cmd =
@@ -3564,7 +3460,7 @@ static void UI_LoadTremAlienBuilds( void )
if( BG_FindTeamForBuildable( i ) == BIT_ALIENS &&
BG_FindBuildWeaponForBuildable( i ) & weapons &&
BG_FindStagesForBuildable( i, stage ) &&
- UI_BuildableIsAllowed( i ) )
+ BG_BuildableIsAllowed( i ) )
{
uiInfo.tremAlienBuildList[ j ].text =
String_Alloc( BG_FindHumanNameForBuildable( i ) );
@@ -3601,7 +3497,7 @@ static void UI_LoadTremHumanBuilds( void )
if( BG_FindTeamForBuildable( i ) == BIT_HUMANS &&
BG_FindBuildWeaponForBuildable( i ) & weapons &&
BG_FindStagesForBuildable( i, stage ) &&
- UI_BuildableIsAllowed( i ) )
+ BG_BuildableIsAllowed( i ) )
{
uiInfo.tremHumanBuildList[ j ].text =
String_Alloc( BG_FindHumanNameForBuildable( i ) );
@@ -5520,6 +5416,7 @@ void _UI_Init( qboolean inGameLoad ) {
int start;
BG_InitClassOverrides( );
+ BG_InitAllowedGameElements( );
//uiInfo.inGameLoad = inGameLoad;
diff --git a/ui/ingame_options.menu b/ui/ingame_options.menu
index 99f4074c..eda5020c 100644
--- a/ui/ingame_options.menu
+++ b/ui/ingame_options.menu
@@ -143,7 +143,7 @@
type ITEM_TYPE_YESNO
text "Auto Download:"
cvar "cl_allowDownload"
- rect 90 120 192 15
+ rect 90 115 192 15
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 12
@@ -163,7 +163,7 @@
type ITEM_TYPE_YESNO
text "Taunts Off:"
cvar "cg_noTaunt"
- rect 90 135 192 15
+ rect 90 130 192 15
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 12
@@ -183,7 +183,7 @@
type ITEM_TYPE_YESNO
text "Team Chats Only:"
cvar "cg_teamChatsOnly"
- rect 90 150 192 15
+ rect 90 145 192 15
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 12
@@ -203,7 +203,7 @@
type ITEM_TYPE_YESNO
text "Auto Wallwalk Pitching:"
cvar "cg_wwFollow"
- rect 90 165 192 15
+ rect 90 160 192 15
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 12
@@ -224,7 +224,7 @@
text "Wallwalking Speed:"
cvarfloat "cg_wwSmoothTime" 300 0 1000
cvarFloatList { "Medium" 300 "Fast" 150 "Instant" 0 "Slow" 600 }
- rect 90 180 192 15
+ rect 90 175 192 15
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 12
@@ -244,7 +244,7 @@
type ITEM_TYPE_YESNO
text "Wallwalk Control Toggles:"
cvar "cg_wwToggle"
- rect 90 195 192 15
+ rect 90 190 192 15
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 12
@@ -264,7 +264,27 @@
type ITEM_TYPE_YESNO
text "Disable Warning Dialogs:"
cvar "cg_disableWarningDialogs"
- rect 90 210 192 15
+ rect 90 205 192 15
+ textalign ITEM_ALIGN_RIGHT
+ textalignx 128
+ textaligny 12
+ textscale .25
+ forecolor 1 1 1 1
+ visible 0
+ action
+ {
+ play "sound/misc/menu1.wav";
+ }
+ }
+
+ itemDef
+ {
+ name game
+ group optionsGrp
+ type ITEM_TYPE_YESNO
+ text "Tutorial Mode:"
+ cvar "cg_tutorial"
+ rect 90 220 192 15
textalign ITEM_ALIGN_RIGHT
textalignx 128
textaligny 12
diff --git a/ui/menudef.h b/ui/menudef.h
index d69957fe..dbd5b193 100644
--- a/ui/menudef.h
+++ b/ui/menudef.h
@@ -257,6 +257,7 @@
#define CG_DEMO_RECORDING 118
#define CG_CONSOLE 91
+#define CG_TUTORIAL 119
diff --git a/ui/tremulous_alien_builder_hud.menu b/ui/tremulous_alien_builder_hud.menu
index f30ba0bd..cd177266 100644
--- a/ui/tremulous_alien_builder_hud.menu
+++ b/ui/tremulous_alien_builder_hud.menu
@@ -29,6 +29,23 @@
ownerdraw CG_CONSOLE
}
+ //TUTORIAL
+ itemDef
+ {
+ name "tutorial"
+ rect 8 250 640 180
+ style WINDOW_STYLE_EMPTY
+ visible 1
+ decoration
+ forecolor 1 1 1 0.35
+ align ITEM_ALIGN_LEFT
+ textalignx 0
+ textaligny 18
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_TUTORIAL
+ }
+
//LAGOMETER
itemDef
{
diff --git a/ui/tremulous_alien_general_hud.menu b/ui/tremulous_alien_general_hud.menu
index 5ecc0181..6ed8721f 100644
--- a/ui/tremulous_alien_general_hud.menu
+++ b/ui/tremulous_alien_general_hud.menu
@@ -29,6 +29,23 @@
ownerdraw CG_CONSOLE
}
+ //TUTORIAL
+ itemDef
+ {
+ name "tutorial"
+ rect 8 250 640 180
+ style WINDOW_STYLE_EMPTY
+ visible 1
+ decoration
+ forecolor 1 1 1 0.35
+ align ITEM_ALIGN_LEFT
+ textalignx 0
+ textaligny 18
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_TUTORIAL
+ }
+
//LAGOMETER
itemDef
{
diff --git a/ui/tremulous_default_hud.menu b/ui/tremulous_default_hud.menu
index 5940b22e..b8385c53 100644
--- a/ui/tremulous_default_hud.menu
+++ b/ui/tremulous_default_hud.menu
@@ -25,6 +25,23 @@
ownerdraw CG_CONSOLE
}
+ //TUTORIAL
+ itemDef
+ {
+ name "tutorial"
+ rect 8 250 640 180
+ style WINDOW_STYLE_EMPTY
+ visible 1
+ decoration
+ forecolor 1 1 1 0.35
+ align ITEM_ALIGN_LEFT
+ textalignx 0
+ textaligny 18
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_TUTORIAL
+ }
+
//FPS
itemDef
{
diff --git a/ui/tremulous_human_hud.menu b/ui/tremulous_human_hud.menu
index 715e9a57..d362fc6a 100644
--- a/ui/tremulous_human_hud.menu
+++ b/ui/tremulous_human_hud.menu
@@ -29,6 +29,23 @@
ownerdraw CG_CONSOLE
}
+ //TUTORIAL
+ itemDef
+ {
+ name "tutorial"
+ rect 8 250 640 180
+ style WINDOW_STYLE_EMPTY
+ visible 1
+ decoration
+ forecolor 1 1 1 0.35
+ align ITEM_ALIGN_LEFT
+ textalignx 0
+ textaligny 18
+ textscale 0.3
+ textstyle ITEM_TEXTSTYLE_NORMAL
+ ownerdraw CG_TUTORIAL
+ }
+
//LAGOMETER
itemDef
{