From b5a24aab3dbb3d65950843c19ab2fa9934064281 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Wed, 18 Jan 2006 01:54:21 +0000 Subject: * Added BG_FindUsableForUpgrade * Added BG_UpgradeClassAvailable * Added generalised BG_*IsAllowed functions * Added some binding traps to cgame * Added tutorial mode (cg_tutorial) --- Makefile | 1 + src/cgame/cg_draw.c | 122 ++++---- src/cgame/cg_local.h | 11 + src/cgame/cg_main.c | 22 ++ src/cgame/cg_players.c | 29 ++ src/cgame/cg_public.h | 6 +- src/cgame/cg_syscalls.asm | 25 +- src/cgame/cg_syscalls.c | 13 + src/cgame/cg_tutorial.c | 610 ++++++++++++++++++++++++++++++++++++ src/client/cl_cgame.c | 10 + src/client/cl_keys.c | 43 +++ src/client/cl_ui.c | 45 --- src/client/keys.h | 2 + src/game/bg_misc.c | 169 ++++++++++ src/game/bg_public.h | 8 + src/game/g_active.c | 15 +- src/game/g_cmds.c | 22 +- src/game/g_local.h | 5 - src/game/g_main.c | 107 +------ src/ui/ui_main.c | 127 +------- ui/ingame_options.menu | 34 +- ui/menudef.h | 1 + ui/tremulous_alien_builder_hud.menu | 17 + ui/tremulous_alien_general_hud.menu | 17 + ui/tremulous_default_hud.menu | 17 + ui/tremulous_human_hud.menu | 17 + 26 files changed, 1121 insertions(+), 374 deletions(-) create mode 100644 src/cgame/cg_tutorial.c 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 @@ -1813,6 +1816,11 @@ void CG_DestroyTestTS_f( void ); 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 @@ -625,51 +625,6 @@ static void GetClipboardData( char *buf, int buflen ) { Z_Free( cbd ); } -/* -==================== -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; } }; @@ -4229,6 +4237,24 @@ qboolean BG_FindPurchasableForUpgrade( int upgrade ) return qfalse; } +/* +============== +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 @@ -3152,110 +3152,6 @@ static void UI_LoadTremTeams( void ) uiInfo.tremTeamList[ 3 ].infopane = UI_FindInfoPaneByName( "autoteam" ); } -/* -============ -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 { -- cgit