mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-07-15 22:09:58 +00:00
Restore Stargate VGUI flow
This commit is contained in:
parent
d2e77350e6
commit
2846c9e45d
@ -14,7 +14,7 @@ $Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE;hl2mp\ui,.\hl2mp,$SRCDIR\game\shared\hl2mp,.\hl2,.\hl2\elements,$SRCDIR\game\shared\hl2,$SRCDIR\game\shared\stargate"
|
||||
$AdditionalIncludeDirectories "$BASE;hl2mp\ui,.\hl2mp,$SRCDIR\game\shared\hl2mp,.\hl2,.\hl2\elements,$SRCDIR\game\shared\hl2,$SRCDIR\game\shared\stargate,.\stargate"
|
||||
$PreprocessorDefinitions "$BASE;HL2MP;HL2_CLIENT_DLL"
|
||||
}
|
||||
}
|
||||
@ -176,6 +176,10 @@ $Project "Client (HL2MP)"
|
||||
$File "$SRCDIR\game\shared\stargate\sg_weapons.cpp"
|
||||
$File "$SRCDIR\game\shared\stargate\sg_mcp_debug_client.cpp"
|
||||
$File "$SRCDIR\game\shared\stargate\sg_constants.h"
|
||||
$File "stargate\sg_hud.cpp"
|
||||
$File "stargate\sg_hud.h"
|
||||
$File "stargate\sg_teammenu.cpp"
|
||||
$File "stargate\sg_teammenu.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "hl2mpclientscoreboard.h"
|
||||
#include "hl2mptextwindow.h"
|
||||
#include "ienginevgui.h"
|
||||
#include "stargate/sg_teammenu.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
@ -60,6 +61,12 @@ protected:
|
||||
}
|
||||
|
||||
virtual IViewPortPanel *CreatePanelByName( const char *szPanelName );
|
||||
|
||||
virtual void CreateDefaultPanels( void )
|
||||
{
|
||||
BaseClass::CreateDefaultPanels();
|
||||
AddNewPanel( CreatePanelByName( PANEL_TEAM ), "PANEL_TEAM" );
|
||||
}
|
||||
};
|
||||
|
||||
int ClientModeHL2MPNormal::GetDeathMessageStartHeight( void )
|
||||
@ -83,12 +90,17 @@ IViewPortPanel* CHudViewport::CreatePanelByName( const char *szPanelName )
|
||||
}
|
||||
else if ( Q_strcmp(PANEL_SPECGUI, szPanelName) == 0 )
|
||||
{
|
||||
newpanel = new CHL2MPSpectatorGUI( this );
|
||||
newpanel = new CHL2MPSpectatorGUI( this );
|
||||
return newpanel;
|
||||
}
|
||||
else if ( Q_strcmp( PANEL_TEAM, szPanelName ) == 0 )
|
||||
{
|
||||
newpanel = new CSgTeamMenu( this );
|
||||
return newpanel;
|
||||
}
|
||||
|
||||
|
||||
return BaseClass::CreatePanelByName( szPanelName );
|
||||
|
||||
return BaseClass::CreatePanelByName( szPanelName );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
570
game/client/stargate/sg_hud.cpp
Normal file
570
game/client/stargate/sg_hud.cpp
Normal file
@ -0,0 +1,570 @@
|
||||
//========= StargateTC ============================================================//
|
||||
//
|
||||
// sg_hud.cpp - StargateTC custom HUD (1:1 port of the single GoldSrc client HUD
|
||||
// element). Paints radar+compass+blips, vertical life/armor/stamina stat bars,
|
||||
// naquada/progress bar, teammate portrait roster + local avatar, tactical alert,
|
||||
// territory tickets, round timer, bomb key and the zat-stun overlay.
|
||||
//
|
||||
// Sprites come from the AI-enhanced VGUI materials at vgui/stargate/hud/* built
|
||||
// by `stgs textures compile-hud`. Each is a 4x atlas padded to a power of two;
|
||||
// DrawSpr() derives the content UV from the GoldSrc-native sprite size.
|
||||
//=================================================================================//
|
||||
#include "cbase.h"
|
||||
#include "sg_hud.h"
|
||||
#include "hud.h"
|
||||
#include "hud_macros.h"
|
||||
#include "iclientmode.h"
|
||||
#include "c_baseplayer.h"
|
||||
#include "view.h"
|
||||
#include <vgui/ISurface.h>
|
||||
#include <vgui_controls/Controls.h>
|
||||
#include "vgui/IScheme.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
using namespace vgui;
|
||||
|
||||
DECLARE_HUDELEMENT( CHudStargate );
|
||||
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgAddPortrait );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgReset );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgAboutMe );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgTogglePor );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgSetRndTim );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgNewRnd );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgZatTouch );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgRadio );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgArmor );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgStamina );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgSubModel );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgHasKey );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgHideHud );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgHudInfoMode );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgTicketMode );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgGtickets );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgTtickets );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgProgress );
|
||||
DECLARE_HUD_MESSAGE( CHudStargate, SgBlip );
|
||||
|
||||
// GoldSrc cvars: view_radar / view_portraits.
|
||||
ConVar sg_view_radar( "sg_view_radar", "1", FCVAR_ARCHIVE, "Show the StargateTC radar." );
|
||||
ConVar sg_view_portraits( "sg_view_portraits", "1", FCVAR_ARCHIVE, "Show the teammate portrait roster." );
|
||||
// Inject dummy state so every HUD block can be verified in a single screenshot.
|
||||
ConVar sg_hud_test( "sg_hud_test", "0", FCVAR_CHEAT, "Force-populate all StargateTC HUD blocks for layout testing." );
|
||||
|
||||
// GoldSrc team coloring: Tau'ri side green, Goa'uld side red.
|
||||
#define SG_TEAM_TAURI 2 // StargateTC: team 2 = Tau'ri
|
||||
#define SG_TEAM_GOAULD 3 // StargateTC: team 3 = Goa'uld
|
||||
|
||||
static const char *SG_NUM[ 10 ] = {
|
||||
"vgui/stargate/hud/num/0", "vgui/stargate/hud/num/1", "vgui/stargate/hud/num/2",
|
||||
"vgui/stargate/hud/num/3", "vgui/stargate/hud/num/4", "vgui/stargate/hud/num/5",
|
||||
"vgui/stargate/hud/num/6", "vgui/stargate/hud/num/7", "vgui/stargate/hud/num/8",
|
||||
"vgui/stargate/hud/num/9",
|
||||
};
|
||||
#define SG_NUM_W 16
|
||||
#define SG_NUM_H 24
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CHudStargate::CHudStargate( const char *pElementName )
|
||||
: CHudElement( pElementName ), BaseClass( NULL, "HudStargate" )
|
||||
{
|
||||
vgui::Panel *pParent = g_pClientMode->GetViewport();
|
||||
SetParent( pParent );
|
||||
|
||||
SetPaintBackgroundEnabled( false );
|
||||
SetPaintBorderEnabled( false );
|
||||
// We manage our own visibility; only hide while fully HUD-suppressed.
|
||||
SetHiddenBits( HIDEHUD_PLAYERDEAD );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHudStargate::Init( void )
|
||||
{
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgAddPortrait );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgReset );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgAboutMe );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgTogglePor );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgSetRndTim );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgNewRnd );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgZatTouch );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgRadio );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgArmor );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgStamina );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgSubModel );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgHasKey );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgHideHud );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgHudInfoMode );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgTicketMode );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgGtickets );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgTtickets );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgProgress );
|
||||
HOOK_HUD_MESSAGE( CHudStargate, SgBlip );
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHudStargate::Reset( void )
|
||||
{
|
||||
m_iLocalTeam = 0;
|
||||
m_iLocalId = 0;
|
||||
m_flArmor = 0;
|
||||
m_flStamina = 0;
|
||||
m_iSubModel = 0;
|
||||
m_bHasKey = false;
|
||||
m_iHideBits = 0;
|
||||
m_iInfoMode = 0;
|
||||
m_bTicketMode = false;
|
||||
m_iGtickets = 0;
|
||||
m_iTtickets = 0;
|
||||
m_iProgress = 0;
|
||||
m_flRoundLen = 0;
|
||||
m_flRoundStart = 0;
|
||||
m_bZat = false;
|
||||
m_flZatTime = 0;
|
||||
m_flSlideOffset = 0;
|
||||
Q_memset( m_Blips, 0, sizeof( m_Blips ) );
|
||||
Q_memset( m_Portraits, 0, sizeof( m_Portraits ) );
|
||||
}
|
||||
|
||||
void CHudStargate::VidInit( void )
|
||||
{
|
||||
// Texture ids are bound to the surface; drop the cache on resolution change.
|
||||
m_TexIds.RemoveAll();
|
||||
}
|
||||
|
||||
void CHudStargate::ApplySchemeSettings( vgui::IScheme *pScheme )
|
||||
{
|
||||
BaseClass::ApplySchemeSettings( pScheme );
|
||||
int sw, sh;
|
||||
surface()->GetScreenSize( sw, sh );
|
||||
SetBounds( 0, 0, sw, sh );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CHudStargate::ShouldDraw( void )
|
||||
{
|
||||
if ( !engine->IsInGame() )
|
||||
return false;
|
||||
// NOTE: intentionally NOT gating on CHudElement::ShouldDraw() yet - the
|
||||
// player sits in an unassigned/observer limbo until the team/class join
|
||||
// flow exists, which would otherwise suppress the whole HUD. Re-add the
|
||||
// CHudElement::ShouldDraw() gate once join/spawn is wired (Phase 7-8).
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHudStargate::OnThink( void )
|
||||
{
|
||||
int sw, sh;
|
||||
surface()->GetScreenSize( sw, sh );
|
||||
if ( GetWide() != sw || GetTall() != sh )
|
||||
SetBounds( 0, 0, sw, sh );
|
||||
|
||||
// Decay radar blips (GoldSrc: alpha -= 5 each frame).
|
||||
for ( int i = 0; i < SG_MAX_BLIPS; i++ )
|
||||
{
|
||||
if ( m_Blips[ i ].alpha > 0 )
|
||||
{
|
||||
m_Blips[ i ].alpha -= 5;
|
||||
if ( m_Blips[ i ].alpha < 0 )
|
||||
m_Blips[ i ].alpha = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
float CHudStargate::Scale( void ) const
|
||||
{
|
||||
int sw, sh;
|
||||
surface()->GetScreenSize( sw, sh );
|
||||
float s = sh / 600.0f; // GoldSrc HUD was authored ~640x480..800x600
|
||||
return ( s < 1.0f ) ? 1.0f : s;
|
||||
}
|
||||
|
||||
Color CHudStargate::TeamColor( int team ) const
|
||||
{
|
||||
if ( team == SG_TEAM_TAURI )
|
||||
return Color( 0, 180, 0, 255 );
|
||||
if ( team == SG_TEAM_GOAULD )
|
||||
return Color( 210, 0, 0, 255 );
|
||||
return Color( 200, 200, 200, 255 );
|
||||
}
|
||||
|
||||
int CHudStargate::GetTex( const char *pszMat )
|
||||
{
|
||||
int idx = m_TexIds.Find( pszMat );
|
||||
if ( idx != m_TexIds.InvalidIndex() )
|
||||
return m_TexIds[ idx ];
|
||||
int id = surface()->CreateNewTextureID();
|
||||
surface()->DrawSetTextureFile( id, pszMat, true, false );
|
||||
m_TexIds.Insert( pszMat, id );
|
||||
return id;
|
||||
}
|
||||
|
||||
static int SgNextPow2( int n ) { int p = 1; while ( p < n ) p <<= 1; return p; }
|
||||
|
||||
void CHudStargate::DrawSpr( const char *pszMat, float sx, float sy,
|
||||
int nativeW, int nativeH, const Color &c )
|
||||
{
|
||||
// content texels = native * 4 (HAT upscale); atlas padded to next pow2.
|
||||
const int texW = nativeW * 4, texH = nativeH * 4;
|
||||
const float u = (float)texW / (float)SgNextPow2( texW );
|
||||
const float v = (float)texH / (float)SgNextPow2( texH );
|
||||
const float s = Scale();
|
||||
const int x0 = (int)sx, y0 = (int)sy;
|
||||
const int x1 = x0 + (int)( nativeW * s ), y1 = y0 + (int)( nativeH * s );
|
||||
|
||||
surface()->DrawSetColor( c );
|
||||
surface()->DrawSetTexture( GetTex( pszMat ) );
|
||||
surface()->DrawTexturedSubRect( x0, y0, x1, y1, 0.0f, 0.0f, u, v );
|
||||
}
|
||||
|
||||
void CHudStargate::DrawHudNumber( int value, float x, float y, float s, const Color &c )
|
||||
{
|
||||
if ( value < 0 )
|
||||
value = 0;
|
||||
char buf[ 16 ];
|
||||
Q_snprintf( buf, sizeof( buf ), "%d", value );
|
||||
float cx = x;
|
||||
for ( const char *p = buf; *p; ++p )
|
||||
{
|
||||
int d = *p - '0';
|
||||
if ( d >= 0 && d <= 9 )
|
||||
DrawSpr( SG_NUM[ d ], cx, y, SG_NUM_W, SG_NUM_H, c );
|
||||
cx += SG_NUM_W * s;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHudStargate::Paint( void )
|
||||
{
|
||||
int sw, sh;
|
||||
surface()->GetScreenSize( sw, sh );
|
||||
const float s = Scale();
|
||||
|
||||
if ( sg_hud_test.GetBool() )
|
||||
{
|
||||
// Inject dummy state so every block is visible for layout verification.
|
||||
m_flArmor = 70; m_flStamina = 55; m_bHasKey = true;
|
||||
m_iInfoMode = 2; m_bTicketMode = true; m_iGtickets = 42; m_iTtickets = 37;
|
||||
m_iProgress = 66; if ( m_flRoundLen == 0 ) { m_flRoundLen = 300; m_flRoundStart = gpGlobals->curtime; }
|
||||
|
||||
// A small paint probe makes VGUI-present-but-assets-missing cases obvious.
|
||||
surface()->DrawSetColor( 0, 0, 0, 180 );
|
||||
surface()->DrawFilledRect( 16, 16, 228, 88 );
|
||||
surface()->DrawSetColor( 255, 60, 40, 255 );
|
||||
surface()->DrawFilledRect( 24, 24, 220, 40 );
|
||||
surface()->DrawSetColor( 0, 190, 90, 255 );
|
||||
surface()->DrawFilledRect( 24, 48, 220, 64 );
|
||||
surface()->DrawSetColor( 60, 140, 255, 255 );
|
||||
surface()->DrawFilledRect( 24, 72, 220, 80 );
|
||||
}
|
||||
|
||||
DrawFrame( sw, sh, s );
|
||||
DrawStatBars( sw, sh, s );
|
||||
if ( sg_view_radar.GetBool() )
|
||||
DrawRadar( sw, sh, s );
|
||||
DrawNaquada( sw, sh, s );
|
||||
DrawTac( sw, sh, s );
|
||||
DrawTickets( sw, sh, s );
|
||||
DrawRoundTimer( sw, sh, s );
|
||||
DrawBombKey( sw, sh, s );
|
||||
if ( sg_view_portraits.GetBool() )
|
||||
DrawPortraits( sw, sh, s );
|
||||
DrawZatOverlay( sw, sh, s );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// sub-blocks
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHudStargate::DrawFrame( int sw, int sh, float s )
|
||||
{
|
||||
// Bottom-left and bottom-right HUD chrome (hud_left 200x168, Hud_Right 200x168).
|
||||
const Color white( 255, 255, 255, 255 );
|
||||
DrawSpr( "vgui/stargate/hud/hud_left", 0, sh - (int)( 168 * s ), 200, 168, white );
|
||||
DrawSpr( "vgui/stargate/hud/Hud_Right", sw - (int)( 200 * s ), sh - (int)( 168 * s ), 200, 168, white );
|
||||
}
|
||||
|
||||
void CHudStargate::DrawRadar( int sw, int sh, float s )
|
||||
{
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
int team = pPlayer ? pPlayer->GetTeamNumber() : m_iLocalTeam;
|
||||
Color disk = ( team == SG_TEAM_TAURI ) ? Color( 0, 160, 0, 255 ) : Color( 160, 0, 0, 255 );
|
||||
|
||||
// Disk: top-right, 200x200 native. y shifts down when portraits present.
|
||||
bool hasPortraits = false;
|
||||
for ( int i = 0; i < SG_MAX_PORTRAITS; i++ ) if ( m_Portraits[ i ].used ) { hasPortraits = true; break; }
|
||||
const int rx = sw - (int)( 208 * s );
|
||||
const int ry = (int)( ( hasPortraits ? 112 : 8 ) * s );
|
||||
DrawSpr( "vgui/stargate/hud/radar", rx, ry, 200, 200, disk );
|
||||
|
||||
// Compass needle: 16-frame ladder driven by view yaw, centered on the disk.
|
||||
float yaw = pPlayer ? pPlayer->EyeAngles().y : 0.0f;
|
||||
yaw = anglemod( yaw );
|
||||
int frame = (int)( ( yaw / 360.0f ) * 16.0f ) & 15;
|
||||
frame = ( frame + 3 ) & 15;
|
||||
frame = 15 - frame;
|
||||
char needle[ 64 ];
|
||||
Q_snprintf( needle, sizeof( needle ), "vgui/stargate/hud/needle_%03d", frame );
|
||||
const int ncx = rx + (int)( ( 100 - 16 ) * s ); // disk center - half needle
|
||||
const int ncy = ry + (int)( ( 100 - 16 ) * s );
|
||||
DrawSpr( needle, ncx, ncy, 32, 32, Color( 210, disk.g(), 0, 255 ) );
|
||||
|
||||
// Blips (decaying), positioned relative to disk centre.
|
||||
const int cx = rx + (int)( 100 * s ), cy = ry + (int)( 100 * s );
|
||||
for ( int i = 0; i < SG_MAX_BLIPS; i++ )
|
||||
{
|
||||
if ( m_Blips[ i ].alpha <= 0 )
|
||||
continue;
|
||||
int bf = m_Blips[ i ].type % 6; if ( bf < 0 ) bf += 6;
|
||||
char blip[ 64 ];
|
||||
Q_snprintf( blip, sizeof( blip ), "vgui/stargate/hud/blip_%03d", bf );
|
||||
const int bx = cx - (int)( m_Blips[ i ].x * s ) - (int)( 8 * s );
|
||||
const int by = cy + (int)( m_Blips[ i ].y * s ) - (int)( 8 * s );
|
||||
DrawSpr( blip, bx, by, 16, 16, Color( 255, 255, 255, m_Blips[ i ].alpha ) );
|
||||
}
|
||||
}
|
||||
|
||||
void CHudStargate::DrawStatBars( int sw, int sh, float s )
|
||||
{
|
||||
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
||||
const float maxv = 100.0f;
|
||||
float life = pPlayer ? (float)pPlayer->GetHealth() : 0.0f;
|
||||
const int barY = sh - (int)( 24 * s );
|
||||
const int barH = 64;
|
||||
|
||||
// Vertical bars crop from the top by (max-value)/max - statbar.spr is 16x64.
|
||||
struct { const char *mat; float val; int x; Color c; } bars[] = {
|
||||
{ "vgui/stargate/hud/statbar", life, 4, Color( 0, 220, 0, 255 ) },
|
||||
{ "vgui/stargate/hud/statbar", m_flArmor, 28, Color( 80, 160, 255, 255 ) },
|
||||
{ "vgui/stargate/hud/statbar", m_flStamina, 52, Color( 255, 170, 0, 255 ) },
|
||||
};
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
float val = bars[ i ].val;
|
||||
// life (i==0) draws even at full/empty; armor/stamina only when > 0.
|
||||
if ( i > 0 && val <= 0 )
|
||||
continue;
|
||||
float frac = val / maxv; if ( frac < 0 ) frac = 0; if ( frac > 1 ) frac = 1;
|
||||
int filledH = (int)( barH * frac );
|
||||
int topGap = barH - filledH; // empty portion at top
|
||||
// UV: statbar is 16x64 native -> 64x256 atlas, pow2 64x256, u=v=1.
|
||||
const int texW = 16 * 4, texH = 64 * 4;
|
||||
float u = (float)texW / SgNextPow2( texW );
|
||||
float vTop = (float)topGap / 64.0f * ( (float)texH / SgNextPow2( texH ) );
|
||||
float vBot = (float)texH / SgNextPow2( texH );
|
||||
int x0 = bars[ i ].x;
|
||||
int y0 = barY + (int)( topGap * s );
|
||||
int x1 = x0 + (int)( 16 * s );
|
||||
int y1 = barY + (int)( barH * s );
|
||||
surface()->DrawSetColor( bars[ i ].c );
|
||||
surface()->DrawSetTexture( GetTex( bars[ i ].mat ) );
|
||||
surface()->DrawTexturedSubRect( x0, y0, x1, y1, 0.0f, vTop, u, vBot );
|
||||
}
|
||||
}
|
||||
|
||||
void CHudStargate::DrawNaquada( int sw, int sh, float s )
|
||||
{
|
||||
if ( m_iProgress <= 0 || m_iProgress >= 100 )
|
||||
return;
|
||||
const int bx = sw / 2 - (int)( 71 * s );
|
||||
const int by = sh - sh / 4 - (int)( 7 * s );
|
||||
DrawSpr( "vgui/stargate/hud/pbar", bx, by, 128, 32, Color( 255, 255, 255, 255 ) );
|
||||
// Fill width scaled by progress.
|
||||
float frac = m_iProgress / 100.0f;
|
||||
const int fx = sw / 2 - (int)( 64 * s );
|
||||
int fullW = 144, drawW = (int)( fullW * frac );
|
||||
const int texW = 144 * 4, texH = 48 * 4;
|
||||
float uFull = (float)texW / SgNextPow2( texW );
|
||||
float v = (float)texH / SgNextPow2( texH );
|
||||
float u = uFull * frac;
|
||||
surface()->DrawSetColor( Color( (int)( 255 * ( 1 - frac ) ), (int)( 255 * frac ), 40, 255 ) );
|
||||
surface()->DrawSetTexture( GetTex( "vgui/stargate/hud/pbare" ) );
|
||||
surface()->DrawTexturedSubRect( fx, by, fx + (int)( drawW * s ), by + (int)( 48 * s ), 0.0f, 0.0f, u, v );
|
||||
}
|
||||
|
||||
void CHudStargate::DrawTac( int sw, int sh, float s )
|
||||
{
|
||||
if ( m_iInfoMode <= 0 )
|
||||
return;
|
||||
const char *mat = "vgui/stargate/hud/tac_green";
|
||||
if ( m_iInfoMode == 1 ) mat = "vgui/stargate/hud/tac_red";
|
||||
else if ( m_iInfoMode == 2 ) mat = "vgui/stargate/hud/tac_yellow";
|
||||
DrawSpr( mat, (int)( 115 * s ), sh - (int)( 76 * s ), 64, 8, Color( 200, 200, 200, 255 ) );
|
||||
}
|
||||
|
||||
void CHudStargate::DrawTickets( int sw, int sh, float s )
|
||||
{
|
||||
if ( !m_bTicketMode )
|
||||
return;
|
||||
DrawSpr( "vgui/stargate/hud/ticketdock", (int)( 120 * s ), sh - (int)( 37 * s ), 120, 64, Color( 200, 200, 200, 255 ) );
|
||||
DrawHudNumber( m_iGtickets, (int)( 70 * s ), sh - (int)( 37 * s ), s, Color( 210, 0, 0, 255 ) );
|
||||
DrawHudNumber( m_iTtickets, (int)( 130 * s ), sh - (int)( 37 * s ), s, Color( 0, 180, 0, 255 ) );
|
||||
}
|
||||
|
||||
void CHudStargate::DrawRoundTimer( int sw, int sh, float s )
|
||||
{
|
||||
if ( m_flRoundLen <= 0 )
|
||||
return;
|
||||
int remaining = (int)( m_flRoundLen - ( gpGlobals->curtime - m_flRoundStart ) );
|
||||
if ( remaining < 0 ) remaining = 0;
|
||||
int mins = remaining / 60, secs = remaining % 60;
|
||||
const Color cyan( 168, 211, 255, 255 );
|
||||
float cx = sw / 2 - (int)( 28 * s );
|
||||
float cy = (int)( sh / 10 );
|
||||
DrawHudNumber( mins, cx, cy, s, cyan );
|
||||
DrawSpr( "vgui/stargate/hud/dots", cx + (int)( SG_NUM_W * 2 * s ), cy, 8, 24, cyan );
|
||||
// seconds, zero-padded
|
||||
char sb[ 8 ]; Q_snprintf( sb, sizeof( sb ), "%02d", secs );
|
||||
float dx = cx + (int)( ( SG_NUM_W * 2 + 8 ) * s );
|
||||
for ( const char *p = sb; *p; ++p )
|
||||
{
|
||||
DrawSpr( SG_NUM[ *p - '0' ], dx, cy, SG_NUM_W, SG_NUM_H, cyan );
|
||||
dx += SG_NUM_W * s;
|
||||
}
|
||||
}
|
||||
|
||||
void CHudStargate::DrawBombKey( int sw, int sh, float s )
|
||||
{
|
||||
if ( !m_bHasKey )
|
||||
return;
|
||||
DrawSpr( "vgui/stargate/hud/key", (int)( 75 * s ), sh - (int)( 52 * s ), 72, 48, Color( 200, 200, 200, 255 ) );
|
||||
}
|
||||
|
||||
void CHudStargate::DrawPortraits( int sw, int sh, float s )
|
||||
{
|
||||
// Bottom-right teammate avatar column (Portrait_middel cells, 80px wide).
|
||||
int n = 0;
|
||||
for ( int i = 0; i < SG_MAX_PORTRAITS; i++ )
|
||||
{
|
||||
if ( !m_Portraits[ i ].used )
|
||||
continue;
|
||||
int px = sw - (int)( ( ( n + 1 ) * 80 + 16 ) * s );
|
||||
int py = sh - (int)( 120 * s );
|
||||
DrawSpr( "vgui/stargate/hud/Portrait_middel", px, py, 80, 104, TeamColor( m_Portraits[ i ].team ) );
|
||||
if ( m_Portraits[ i ].avatar[ 0 ] )
|
||||
{
|
||||
char av[ 96 ];
|
||||
Q_snprintf( av, sizeof( av ), "vgui/stargate/avatars/%s", m_Portraits[ i ].avatar );
|
||||
DrawSpr( av, px + (int)( 8 * s ), py + (int)( 8 * s ), 64, 64, Color( 255, 255, 255, 255 ) );
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
void CHudStargate::DrawZatOverlay( int sw, int sh, float s )
|
||||
{
|
||||
if ( !m_bZat )
|
||||
return;
|
||||
float age = gpGlobals->curtime - m_flZatTime;
|
||||
if ( age > 1.5f ) { m_bZat = false; return; }
|
||||
int a = (int)( 200 * ( 1.0f - age / 1.5f ) );
|
||||
surface()->DrawSetColor( Color( 0, 130, 255, a ) );
|
||||
surface()->DrawSetTexture( GetTex( "vgui/stargate/weapons/d_zap" ) );
|
||||
surface()->DrawTexturedRect( 0, 0, sw, sh );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// message handlers
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHudStargate::MsgFunc_SgArmor( bf_read &msg ) { m_flArmor = msg.ReadShort(); }
|
||||
void CHudStargate::MsgFunc_SgStamina( bf_read &msg ) { m_flStamina = msg.ReadShort(); }
|
||||
void CHudStargate::MsgFunc_SgSubModel( bf_read &msg ) { m_iSubModel = msg.ReadShort(); }
|
||||
void CHudStargate::MsgFunc_SgHasKey( bf_read &msg ) { m_bHasKey = msg.ReadShort() != 0; }
|
||||
void CHudStargate::MsgFunc_SgHideHud( bf_read &msg ) { m_iHideBits = msg.ReadShort(); }
|
||||
void CHudStargate::MsgFunc_SgHudInfoMode( bf_read &msg ){ m_iInfoMode = msg.ReadByte(); }
|
||||
void CHudStargate::MsgFunc_SgTicketMode( bf_read &msg ) { m_bTicketMode = msg.ReadByte() != 0; }
|
||||
void CHudStargate::MsgFunc_SgGtickets( bf_read &msg ) { m_iGtickets = msg.ReadByte(); }
|
||||
void CHudStargate::MsgFunc_SgTtickets( bf_read &msg ) { m_iTtickets = msg.ReadByte(); }
|
||||
void CHudStargate::MsgFunc_SgTogglePor( bf_read &msg ) { sg_view_portraits.SetValue( !sg_view_portraits.GetBool() ); }
|
||||
void CHudStargate::MsgFunc_SgNewRnd( bf_read &msg ) { m_iSubModel = 0; Q_memset( m_Portraits, 0, sizeof( m_Portraits ) ); }
|
||||
void CHudStargate::MsgFunc_SgRadio( bf_read &msg ) { msg.ReadByte(); msg.ReadByte(); /* TODO radio text */ }
|
||||
|
||||
void CHudStargate::MsgFunc_SgAboutMe( bf_read &msg )
|
||||
{
|
||||
m_iLocalId = msg.ReadShort();
|
||||
m_iLocalTeam = msg.ReadShort();
|
||||
}
|
||||
|
||||
void CHudStargate::MsgFunc_SgSetRndTim( bf_read &msg )
|
||||
{
|
||||
m_flRoundLen = msg.ReadShort();
|
||||
msg.ReadByte();
|
||||
m_flRoundStart = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
void CHudStargate::MsgFunc_SgZatTouch( bf_read &msg )
|
||||
{
|
||||
m_bZat = true;
|
||||
m_flZatTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
void CHudStargate::MsgFunc_SgProgress( bf_read &msg )
|
||||
{
|
||||
m_iProgress = msg.ReadByte();
|
||||
// remaining payload (flags + 28-entry array + trailer) consumed but unused.
|
||||
int remaining = msg.GetNumBytesLeft();
|
||||
for ( int i = 0; i < remaining; i++ )
|
||||
msg.ReadByte();
|
||||
}
|
||||
|
||||
void CHudStargate::MsgFunc_SgBlip( bf_read &msg )
|
||||
{
|
||||
int cmd = msg.ReadByte();
|
||||
float x = msg.ReadShort();
|
||||
float y = msg.ReadShort();
|
||||
if ( cmd == '=' ) // 0x3d - clear origin reference
|
||||
return;
|
||||
// add a blip into the first free/decayed slot
|
||||
for ( int i = 0; i < SG_MAX_BLIPS; i++ )
|
||||
{
|
||||
if ( m_Blips[ i ].alpha <= 0 )
|
||||
{
|
||||
m_Blips[ i ].type = ( cmd == '2' ) ? 1 : 0;
|
||||
m_Blips[ i ].x = x;
|
||||
m_Blips[ i ].y = y;
|
||||
m_Blips[ i ].alpha = 255;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CHudStargate::MsgFunc_SgReset( bf_read &msg )
|
||||
{
|
||||
int id = msg.ReadShort();
|
||||
int flag = msg.ReadByte();
|
||||
if ( flag == 0 )
|
||||
{
|
||||
Q_memset( m_Portraits, 0, sizeof( m_Portraits ) );
|
||||
return;
|
||||
}
|
||||
for ( int i = 0; i < SG_MAX_PORTRAITS; i++ )
|
||||
if ( m_Portraits[ i ].used && m_Portraits[ i ].id == id )
|
||||
m_Portraits[ i ].used = false;
|
||||
}
|
||||
|
||||
void CHudStargate::MsgFunc_SgAddPortrait( bf_read &msg )
|
||||
{
|
||||
int id = msg.ReadShort();
|
||||
int team = msg.ReadShort();
|
||||
char avatar[ 32 ];
|
||||
msg.ReadString( avatar, sizeof( avatar ) );
|
||||
// find existing or free slot
|
||||
int slot = -1;
|
||||
for ( int i = 0; i < SG_MAX_PORTRAITS; i++ )
|
||||
{
|
||||
if ( m_Portraits[ i ].used && m_Portraits[ i ].id == id ) { slot = i; break; }
|
||||
if ( slot < 0 && !m_Portraits[ i ].used ) slot = i;
|
||||
}
|
||||
if ( slot < 0 )
|
||||
return;
|
||||
m_Portraits[ slot ].used = true;
|
||||
m_Portraits[ slot ].id = id;
|
||||
m_Portraits[ slot ].team = team;
|
||||
Q_strncpy( m_Portraits[ slot ].avatar, avatar, sizeof( m_Portraits[ slot ].avatar ) );
|
||||
}
|
||||
128
game/client/stargate/sg_hud.h
Normal file
128
game/client/stargate/sg_hud.h
Normal file
@ -0,0 +1,128 @@
|
||||
//========= StargateTC ============================================================//
|
||||
//
|
||||
// sg_hud.h - StargateTC custom HUD element.
|
||||
//
|
||||
// 1:1 port of the single large GoldSrc client HUD element (decompiled
|
||||
// FUN_100718df / Init FUN_10071193 / VidInit FUN_10071390, singleton
|
||||
// &DAT_100e67f0). The original drew ALL Stargate-specific HUD from one element;
|
||||
// we keep that structure here as one full-screen CHudElement that paints every
|
||||
// sub-block with ScreenWidth/Height-relative coordinates, matching the original.
|
||||
//
|
||||
// See StargateTCSource/docs/HUD_PORT_SPEC.md for the full element/message map.
|
||||
//=================================================================================//
|
||||
#ifndef SG_HUD_H
|
||||
#define SG_HUD_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "hudelement.h"
|
||||
#include <vgui_controls/Panel.h>
|
||||
#include "tier1/UtlDict.h"
|
||||
|
||||
#define SG_MAX_BLIPS 256
|
||||
#define SG_MAX_PORTRAITS 33
|
||||
|
||||
struct SgBlip_t
|
||||
{
|
||||
int type;
|
||||
float x; // world-relative offset supplied by server
|
||||
float y;
|
||||
int alpha; // 0..255, decays each frame
|
||||
};
|
||||
|
||||
struct SgPortrait_t
|
||||
{
|
||||
bool used;
|
||||
int id; // player entindex
|
||||
int team;
|
||||
char avatar[32];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CHudStargate - the whole Stargate HUD in one element (faithful to GoldSrc).
|
||||
//-----------------------------------------------------------------------------
|
||||
class CHudStargate : public CHudElement, public vgui::Panel
|
||||
{
|
||||
DECLARE_CLASS_SIMPLE( CHudStargate, vgui::Panel );
|
||||
|
||||
public:
|
||||
explicit CHudStargate( const char *pElementName );
|
||||
|
||||
virtual void Init( void );
|
||||
virtual void VidInit( void );
|
||||
virtual void Reset( void );
|
||||
virtual bool ShouldDraw( void );
|
||||
virtual void OnThink( void );
|
||||
virtual void Paint( void );
|
||||
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
|
||||
|
||||
// --- Server user messages (19, prefixed Sg to avoid HL2MP clashes) ---
|
||||
void MsgFunc_SgAddPortrait( bf_read &msg );
|
||||
void MsgFunc_SgReset( bf_read &msg );
|
||||
void MsgFunc_SgAboutMe( bf_read &msg );
|
||||
void MsgFunc_SgTogglePor( bf_read &msg );
|
||||
void MsgFunc_SgSetRndTim( bf_read &msg );
|
||||
void MsgFunc_SgNewRnd( bf_read &msg );
|
||||
void MsgFunc_SgZatTouch( bf_read &msg );
|
||||
void MsgFunc_SgRadio( bf_read &msg );
|
||||
void MsgFunc_SgArmor( bf_read &msg );
|
||||
void MsgFunc_SgStamina( bf_read &msg );
|
||||
void MsgFunc_SgSubModel( bf_read &msg );
|
||||
void MsgFunc_SgHasKey( bf_read &msg );
|
||||
void MsgFunc_SgHideHud( bf_read &msg );
|
||||
void MsgFunc_SgHudInfoMode( bf_read &msg );
|
||||
void MsgFunc_SgTicketMode( bf_read &msg );
|
||||
void MsgFunc_SgGtickets( bf_read &msg );
|
||||
void MsgFunc_SgTtickets( bf_read &msg );
|
||||
void MsgFunc_SgProgress( bf_read &msg );
|
||||
void MsgFunc_SgBlip( bf_read &msg );
|
||||
|
||||
private:
|
||||
// texture cache + sprite draw helpers
|
||||
int GetTex( const char *pszMat );
|
||||
// Draw a HUD sprite sized in GoldSrc-native px (auto pow2-UV from 4x atlas).
|
||||
void DrawSpr( const char *pszMat, float sx, float sy,
|
||||
int nativeW, int nativeH, const Color &c );
|
||||
float Scale( void ) const; // screen-height based HUD scale
|
||||
Color TeamColor( int team ) const;
|
||||
|
||||
// draw sub-blocks
|
||||
void DrawFrame( int sw, int sh, float s );
|
||||
void DrawRadar( int sw, int sh, float s );
|
||||
void DrawStatBars( int sw, int sh, float s );
|
||||
void DrawNaquada( int sw, int sh, float s );
|
||||
void DrawTickets( int sw, int sh, float s );
|
||||
void DrawRoundTimer( int sw, int sh, float s );
|
||||
void DrawTac( int sw, int sh, float s );
|
||||
void DrawBombKey( int sw, int sh, float s );
|
||||
void DrawPortraits( int sw, int sh, float s );
|
||||
void DrawZatOverlay( int sw, int sh, float s );
|
||||
void DrawHudNumber( int value, float x, float y, float s, const Color &c );
|
||||
|
||||
CUtlDict< int, int > m_TexIds; // material name -> surface texture id
|
||||
|
||||
// --- HUD state (mirrors the GoldSrc element's fields) ---
|
||||
int m_iLocalTeam;
|
||||
int m_iLocalId;
|
||||
float m_flArmor;
|
||||
float m_flStamina;
|
||||
int m_iSubModel;
|
||||
bool m_bHasKey;
|
||||
int m_iHideBits;
|
||||
int m_iInfoMode; // 0 none / 1 red / 2 yellow / 3 green
|
||||
bool m_bTicketMode;
|
||||
int m_iGtickets;
|
||||
int m_iTtickets;
|
||||
int m_iProgress; // 0..100
|
||||
float m_flRoundLen;
|
||||
float m_flRoundStart;
|
||||
bool m_bZat;
|
||||
float m_flZatTime;
|
||||
float m_flSlideOffset;
|
||||
|
||||
SgBlip_t m_Blips[ SG_MAX_BLIPS ];
|
||||
SgPortrait_t m_Portraits[ SG_MAX_PORTRAITS ];
|
||||
};
|
||||
|
||||
#endif // SG_HUD_H
|
||||
275
game/client/stargate/sg_teammenu.cpp
Normal file
275
game/client/stargate/sg_teammenu.cpp
Normal file
@ -0,0 +1,275 @@
|
||||
//========= StargateTC ============================================================//
|
||||
//
|
||||
// sg_teammenu.cpp - combined team + class selection panel.
|
||||
// See sg_teammenu.h. Buttons are built in code (no .res dependency) and laid out
|
||||
// in PerformLayout, so the panel is self-contained.
|
||||
//=================================================================================//
|
||||
#include "cbase.h"
|
||||
#include "sg_teammenu.h"
|
||||
#include <cdll_client_int.h>
|
||||
#include <vgui/IScheme.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <vgui/IVGui.h>
|
||||
#include <KeyValues.h>
|
||||
#include <vgui_controls/Button.h>
|
||||
#include <vgui_controls/Label.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
using namespace vgui;
|
||||
|
||||
// StargateTC team numbering (matches server: 2 = Tau'ri, 3 = Goa'uld).
|
||||
#define SG_TEAM_AUTO 0
|
||||
#define SG_TEAM_SPECTATOR 1
|
||||
#define SG_TEAM_TAURI 2
|
||||
#define SG_TEAM_GOAULD 3
|
||||
|
||||
struct SgClassDef_t { const char *cmd; const char *label; };
|
||||
|
||||
// Class rosters recovered from the GoldSrc panel (FUN_1002bec0 / Titles.txt).
|
||||
static const SgClassDef_t s_TauClasses[] = {
|
||||
{ "oneill", "O'Neill" },
|
||||
{ "carter", "Carter" },
|
||||
{ "jackson", "Jackson" },
|
||||
{ "tealc", "Teal'c" },
|
||||
{ "soldat", "Soldier" },
|
||||
};
|
||||
static const SgClassDef_t s_GoaClasses[] = {
|
||||
{ "dieu", "System Lord" },
|
||||
{ "anubis", "Anubis Guard" },
|
||||
{ "jaffa", "Jaffa" },
|
||||
{ "prima", "First Prime" },
|
||||
{ "esclave", "Horus Guard" },
|
||||
};
|
||||
|
||||
static void SgStyleButton( Button *pButton, const Color &fg, const Color &bg )
|
||||
{
|
||||
if ( !pButton )
|
||||
return;
|
||||
|
||||
pButton->SetButtonBorderEnabled( true );
|
||||
pButton->SetDefaultColor( fg, bg );
|
||||
pButton->SetArmedColor( Color( 255, 255, 255, 255 ), Color( 45, 94, 110, 245 ) );
|
||||
pButton->SetDepressedColor( Color( 255, 255, 255, 255 ), Color( 23, 58, 72, 255 ) );
|
||||
pButton->SetSelectedColor( fg, Color( 29, 68, 82, 245 ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CSgTeamMenu::CSgTeamMenu( IViewPort *pViewPort ) : Frame( NULL, PANEL_TEAM )
|
||||
{
|
||||
m_pViewPort = pViewPort;
|
||||
|
||||
SetScheme( "ClientScheme" );
|
||||
SetTitle( "", true );
|
||||
SetMoveable( false );
|
||||
SetSizeable( false );
|
||||
SetTitleBarVisible( false );
|
||||
SetProportional( false );
|
||||
SetPaintBackgroundEnabled( true );
|
||||
SetPaintBorderEnabled( false );
|
||||
|
||||
m_pTitle = new Label( this, "Title", "Identify yourself" );
|
||||
m_pTauHeader = new Label( this, "TauHeader", "Tau'ri" );
|
||||
m_pGoaHeader = new Label( this, "GoaHeader", "Goa'uld" );
|
||||
|
||||
for ( int i = 0; i < ARRAYSIZE( s_TauClasses ); i++ )
|
||||
m_TauButtons.AddToTail( AddClassButton( SG_TEAM_TAURI, s_TauClasses[i].cmd, s_TauClasses[i].label ) );
|
||||
for ( int i = 0; i < ARRAYSIZE( s_GoaClasses ); i++ )
|
||||
m_GoaButtons.AddToTail( AddClassButton( SG_TEAM_GOAULD, s_GoaClasses[i].cmd, s_GoaClasses[i].label ) );
|
||||
|
||||
m_BottomButtons.AddToTail( AddTeamButton( SG_TEAM_AUTO, "Auto-Assign", "auto" ) );
|
||||
m_BottomButtons.AddToTail( AddTeamButton( SG_TEAM_SPECTATOR, "Spectate", "spec" ) );
|
||||
m_BottomButtons.AddToTail( AddTeamButton( -1, "Cancel", "cancel" ) );
|
||||
|
||||
SetVisible( false );
|
||||
}
|
||||
|
||||
CSgTeamMenu::~CSgTeamMenu()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
vgui::Button *CSgTeamMenu::AddClassButton( int teamId, const char *cls, const char *label )
|
||||
{
|
||||
Button *b = new Button( this, cls, label );
|
||||
KeyValues *kv = new KeyValues( "JoinClass" );
|
||||
kv->SetInt( "team", teamId );
|
||||
kv->SetString( "cls", cls );
|
||||
b->SetCommand( kv );
|
||||
b->AddActionSignalTarget( this );
|
||||
return b;
|
||||
}
|
||||
|
||||
vgui::Button *CSgTeamMenu::AddTeamButton( int teamId, const char *label, const char *key )
|
||||
{
|
||||
Button *b = new Button( this, key, label );
|
||||
KeyValues *kv = new KeyValues( "JoinTeam" );
|
||||
kv->SetInt( "team", teamId );
|
||||
b->SetCommand( kv );
|
||||
b->AddActionSignalTarget( this );
|
||||
return b;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSgTeamMenu::ApplySchemeSettings( vgui::IScheme *pScheme )
|
||||
{
|
||||
BaseClass::ApplySchemeSettings( pScheme );
|
||||
SetBgColor( Color( 5, 9, 12, 238 ) );
|
||||
|
||||
m_pTitle->SetFgColor( Color( 235, 243, 235, 255 ) );
|
||||
m_pTauHeader->SetFgColor( Color( 90, 220, 130, 255 ) );
|
||||
m_pGoaHeader->SetFgColor( Color( 235, 88, 78, 255 ) );
|
||||
|
||||
for ( int i = 0; i < m_TauButtons.Count(); i++ )
|
||||
SgStyleButton( m_TauButtons[i], Color( 210, 255, 220, 255 ), Color( 16, 46, 30, 235 ) );
|
||||
for ( int i = 0; i < m_GoaButtons.Count(); i++ )
|
||||
SgStyleButton( m_GoaButtons[i], Color( 255, 220, 210, 255 ), Color( 54, 25, 22, 235 ) );
|
||||
for ( int i = 0; i < m_BottomButtons.Count(); i++ )
|
||||
SgStyleButton( m_BottomButtons[i], Color( 230, 235, 230, 255 ), Color( 32, 39, 43, 235 ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSgTeamMenu::PaintBackground( void )
|
||||
{
|
||||
int w, h;
|
||||
GetSize( w, h );
|
||||
|
||||
surface()->DrawSetColor( 5, 9, 12, 238 );
|
||||
surface()->DrawFilledRect( 0, 0, w, h );
|
||||
|
||||
surface()->DrawSetColor( 76, 155, 118, 255 );
|
||||
surface()->DrawOutlinedRect( 0, 0, w, h );
|
||||
surface()->DrawSetColor( 18, 57, 36, 210 );
|
||||
surface()->DrawFilledRect( 22, 44, w / 2 - 10, h - 58 );
|
||||
surface()->DrawSetColor( 76, 32, 28, 210 );
|
||||
surface()->DrawFilledRect( w / 2 + 10, 44, w - 22, h - 58 );
|
||||
surface()->DrawSetColor( 28, 37, 40, 235 );
|
||||
surface()->DrawFilledRect( 22, h - 54, w - 22, h - 16 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSgTeamMenu::PerformLayout( void )
|
||||
{
|
||||
BaseClass::PerformLayout();
|
||||
|
||||
int sw, sh;
|
||||
surface()->GetScreenSize( sw, sh );
|
||||
const int w = 460, h = 360;
|
||||
const int x = ( sw - w ) / 2, y = ( sh - h ) / 2;
|
||||
SetBounds( x, y, w, h );
|
||||
|
||||
m_pTitle->SetBounds( 0, 12, w, 24 );
|
||||
m_pTitle->SetContentAlignment( Label::a_center );
|
||||
|
||||
const int colW = 180, btnH = 26, gap = 6;
|
||||
const int leftX = 30, rightX = w - 30 - colW;
|
||||
int hy = 48;
|
||||
m_pTauHeader->SetBounds( leftX, hy, colW, 22 );
|
||||
m_pTauHeader->SetContentAlignment( Label::a_center );
|
||||
m_pGoaHeader->SetBounds( rightX, hy, colW, 22 );
|
||||
m_pGoaHeader->SetContentAlignment( Label::a_center );
|
||||
|
||||
int by = hy + 28;
|
||||
for ( int i = 0; i < m_TauButtons.Count(); i++ )
|
||||
m_TauButtons[i]->SetBounds( leftX, by + i * ( btnH + gap ), colW, btnH );
|
||||
for ( int i = 0; i < m_GoaButtons.Count(); i++ )
|
||||
m_GoaButtons[i]->SetBounds( rightX, by + i * ( btnH + gap ), colW, btnH );
|
||||
|
||||
// bottom row: auto / spectate / cancel
|
||||
int bottomY = h - 40;
|
||||
int n = m_BottomButtons.Count();
|
||||
int bw = 130, totalW = n * bw + ( n - 1 ) * gap;
|
||||
int bx = ( w - totalW ) / 2;
|
||||
for ( int i = 0; i < n; i++ )
|
||||
m_BottomButtons[i]->SetBounds( bx + i * ( bw + gap ), bottomY, bw, btnH );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSgTeamMenu::ShowPanel( bool bShow )
|
||||
{
|
||||
if ( BaseClass::IsVisible() == bShow )
|
||||
return;
|
||||
|
||||
if ( bShow )
|
||||
{
|
||||
Activate();
|
||||
SetVisible( true );
|
||||
SetMouseInputEnabled( true );
|
||||
SetKeyBoardInputEnabled( true );
|
||||
InvalidateLayout();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVisible( false );
|
||||
SetMouseInputEnabled( false );
|
||||
}
|
||||
|
||||
if ( m_pViewPort )
|
||||
m_pViewPort->ShowBackGround( bShow );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSgTeamMenu::OnJoinClass( KeyValues *data )
|
||||
{
|
||||
int team = data->GetInt( "team" );
|
||||
const char *cls = data->GetString( "cls" );
|
||||
char cmd[ 128 ];
|
||||
Q_snprintf( cmd, sizeof( cmd ), "jointeam %d; joinclass %s\n", team, cls );
|
||||
engine->ClientCmd( cmd );
|
||||
ShowPanel( false );
|
||||
}
|
||||
|
||||
void CSgTeamMenu::OnJoinTeam( KeyValues *data )
|
||||
{
|
||||
int team = data->GetInt( "team" );
|
||||
if ( team < 0 ) // Cancel
|
||||
{
|
||||
ShowPanel( false );
|
||||
return;
|
||||
}
|
||||
char cmd[ 96 ];
|
||||
if ( team == SG_TEAM_AUTO )
|
||||
Q_snprintf( cmd, sizeof( cmd ), "jointeam 0; joinclass auto\n" );
|
||||
else
|
||||
Q_snprintf( cmd, sizeof( cmd ), "jointeam %d\n", team );
|
||||
engine->ClientCmd( cmd );
|
||||
ShowPanel( false );
|
||||
}
|
||||
|
||||
void CSgTeamMenu::OnKeyCodePressed( vgui::KeyCode code )
|
||||
{
|
||||
if ( code == KEY_ESCAPE )
|
||||
{
|
||||
ShowPanel( false );
|
||||
return;
|
||||
}
|
||||
BaseClass::OnKeyCodePressed( code );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console commands to open the menu (also bind a key, e.g. bind m chooseteam).
|
||||
//-----------------------------------------------------------------------------
|
||||
CON_COMMAND( chooseteam, "Open the StargateTC team/class selection menu" )
|
||||
{
|
||||
if ( gViewPortInterface )
|
||||
gViewPortInterface->ShowPanel( PANEL_TEAM, true );
|
||||
}
|
||||
|
||||
CON_COMMAND( changeclass, "Open the StargateTC class selection menu" )
|
||||
{
|
||||
if ( gViewPortInterface )
|
||||
gViewPortInterface->ShowPanel( PANEL_TEAM, true );
|
||||
}
|
||||
|
||||
CON_COMMAND( showmenu, "Open the StargateTC team/class selection menu" )
|
||||
{
|
||||
if ( gViewPortInterface )
|
||||
gViewPortInterface->ShowPanel( PANEL_TEAM, true );
|
||||
}
|
||||
|
||||
CON_COMMAND( showequip, "Open the StargateTC equipment/class selection menu" )
|
||||
{
|
||||
if ( gViewPortInterface )
|
||||
gViewPortInterface->ShowPanel( PANEL_TEAM, true );
|
||||
}
|
||||
68
game/client/stargate/sg_teammenu.h
Normal file
68
game/client/stargate/sg_teammenu.h
Normal file
@ -0,0 +1,68 @@
|
||||
//========= StargateTC ============================================================//
|
||||
//
|
||||
// sg_teammenu.h - combined team + class selection panel (IViewPortPanel).
|
||||
//
|
||||
// 1:1 port of the GoldSrc "Identifiez-vous" panel (decompiled FUN_1002bec0):
|
||||
// two team columns (Tau'ri / Goa'uld), five classes each, plus Auto-Assign,
|
||||
// Spectate and Cancel. Class buttons issue `jointeam <id>` + `joinclass <name>`.
|
||||
// Opened by the `chooseteam` / `changeclass` console commands or server VGUIMenu.
|
||||
//=================================================================================//
|
||||
#ifndef SG_TEAMMENU_H
|
||||
#define SG_TEAMMENU_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <vgui_controls/Frame.h>
|
||||
#include <vgui_controls/Button.h>
|
||||
#include <vgui_controls/Label.h>
|
||||
#include <game/client/iviewport.h>
|
||||
#include <utlvector.h>
|
||||
|
||||
class CSgTeamMenu : public vgui::Frame, public IViewPortPanel
|
||||
{
|
||||
DECLARE_CLASS_SIMPLE( CSgTeamMenu, vgui::Frame );
|
||||
|
||||
public:
|
||||
explicit CSgTeamMenu( IViewPort *pViewPort );
|
||||
virtual ~CSgTeamMenu();
|
||||
|
||||
// IViewPortPanel
|
||||
virtual const char *GetName( void ) { return PANEL_TEAM; }
|
||||
virtual void SetData( KeyValues *data ) {}
|
||||
virtual void Reset( void ) {}
|
||||
virtual void Update( void ) {}
|
||||
virtual bool NeedsUpdate( void ) { return false; }
|
||||
virtual bool HasInputElements( void ) { return true; }
|
||||
virtual void ShowPanel( bool bShow );
|
||||
|
||||
// both vgui::Frame and IViewPortPanel define these -> passthroughs
|
||||
vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); }
|
||||
virtual bool IsVisible() { return BaseClass::IsVisible(); }
|
||||
virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); }
|
||||
virtual GameActionSet_t GetPreferredActionSet() { return GAME_ACTION_SET_IN_GAME_HUD; }
|
||||
|
||||
protected:
|
||||
virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
|
||||
virtual void PaintBackground( void );
|
||||
virtual void PerformLayout( void );
|
||||
virtual void OnKeyCodePressed( vgui::KeyCode code );
|
||||
|
||||
MESSAGE_FUNC_PARAMS( OnJoinClass, "JoinClass", data );
|
||||
MESSAGE_FUNC_PARAMS( OnJoinTeam, "JoinTeam", data );
|
||||
|
||||
private:
|
||||
vgui::Button *AddClassButton( int teamId, const char *cls, const char *label );
|
||||
vgui::Button *AddTeamButton( int teamId, const char *label, const char *key );
|
||||
|
||||
IViewPort *m_pViewPort;
|
||||
|
||||
vgui::Label *m_pTitle;
|
||||
vgui::Label *m_pTauHeader;
|
||||
vgui::Label *m_pGoaHeader;
|
||||
CUtlVector< vgui::Button * > m_TauButtons;
|
||||
CUtlVector< vgui::Button * > m_GoaButtons;
|
||||
CUtlVector< vgui::Button * > m_BottomButtons;
|
||||
};
|
||||
|
||||
#endif // SG_TEAMMENU_H
|
||||
@ -35,12 +35,21 @@ void Host_Say( edict_t *pEdict, bool teamonly );
|
||||
|
||||
ConVar sv_motd_unload_on_dismissal( "sv_motd_unload_on_dismissal", "0", 0, "If enabled, the MOTD contents will be unloaded when the player closes the MOTD." );
|
||||
|
||||
// StargateTC: the MOTD info panel popped over the screen on every join and the
|
||||
// mod ships no MOTD content, so it just obscured the game. Default it OFF;
|
||||
// set "sv_show_motd 1" to restore the vanilla HL2DM message-of-the-day panel.
|
||||
ConVar sv_show_motd( "sv_show_motd", "0", FCVAR_NOTIFY, "Show the MOTD info panel to players when they join." );
|
||||
|
||||
extern CBaseEntity* FindPickerEntityClass( CBasePlayer *pPlayer, char *classname );
|
||||
extern bool g_fGameOver;
|
||||
|
||||
void FinishClientPutInServer( CHL2MP_Player *pPlayer )
|
||||
{
|
||||
pPlayer->InitialSpawn();
|
||||
|
||||
extern void Sg_ResetPlayerClass( CHL2MP_Player *pPlayer );
|
||||
Sg_ResetPlayerClass( pPlayer );
|
||||
|
||||
pPlayer->Spawn();
|
||||
|
||||
|
||||
@ -61,20 +70,24 @@ void FinishClientPutInServer( CHL2MP_Player *pPlayer )
|
||||
if ( HL2MPRules()->IsTeamplay() == true )
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTTALK, "You are on team %s1\n", pPlayer->GetTeam()->GetName() );
|
||||
pPlayer->ShowViewPortPanel( PANEL_TEAM, true );
|
||||
}
|
||||
|
||||
const ConVar *hostname = cvar->FindVar( "hostname" );
|
||||
const char *title = (hostname) ? hostname->GetString() : "MESSAGE OF THE DAY";
|
||||
if ( sv_show_motd.GetBool() )
|
||||
{
|
||||
const ConVar *hostname = cvar->FindVar( "hostname" );
|
||||
const char *title = (hostname) ? hostname->GetString() : "MESSAGE OF THE DAY";
|
||||
|
||||
KeyValues *data = new KeyValues("data");
|
||||
data->SetString( "title", title ); // info panel title
|
||||
data->SetString( "type", "1" ); // show userdata from stringtable entry
|
||||
data->SetString( "msg", "motd" ); // use this stringtable entry
|
||||
data->SetBool( "unload", sv_motd_unload_on_dismissal.GetBool() );
|
||||
KeyValues *data = new KeyValues("data");
|
||||
data->SetString( "title", title ); // info panel title
|
||||
data->SetString( "type", "1" ); // show userdata from stringtable entry
|
||||
data->SetString( "msg", "motd" ); // use this stringtable entry
|
||||
data->SetBool( "unload", sv_motd_unload_on_dismissal.GetBool() );
|
||||
|
||||
pPlayer->ShowViewPortPanel( PANEL_INFO, true, data );
|
||||
pPlayer->ShowViewPortPanel( PANEL_INFO, true, data );
|
||||
|
||||
data->deleteThis();
|
||||
data->deleteThis();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "grenade_satchel.h"
|
||||
#include "eventqueue.h"
|
||||
#include "gamestats.h"
|
||||
#include "viewport_panel_names.h"
|
||||
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
||||
@ -35,6 +36,9 @@ extern CBaseEntity *g_pLastSpawn;
|
||||
|
||||
#define HL2MP_COMMAND_MAX_RATE 0.3
|
||||
|
||||
ConVar mp_wepselmode( "mp_wepselmode", "2", FCVAR_GAMEDLL | FCVAR_NOTIFY, "StargateTC weapon selection: 0=team melee only, 1=team melee plus class weapon, 2=team default pack plus class weapon." );
|
||||
ConVar mp_autobalance( "mp_autobalance", "2", FCVAR_GAMEDLL | FCVAR_NOTIFY, "StargateTC team auto-balance: 0=off, non-zero blocks joins that would stack Tau'ri/Goa'uld." );
|
||||
|
||||
void DropPrimedFragGrenade( CHL2MP_Player *pPlayer, CBaseCombatWeapon *pGrenade );
|
||||
|
||||
LINK_ENTITY_TO_CLASS( player, CHL2MP_Player );
|
||||
@ -48,6 +52,7 @@ IMPLEMENT_SERVERCLASS_ST(CHL2MP_Player, DT_HL2MP_Player)
|
||||
SendPropEHandle( SENDINFO( m_hRagdoll ) ),
|
||||
SendPropInt( SENDINFO( m_iSpawnInterpCounter), 4 ),
|
||||
SendPropInt( SENDINFO( m_iPlayerSoundType), 3 ),
|
||||
SendPropInt( SENDINFO( m_iStargateClass ), 4 ),
|
||||
|
||||
SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ),
|
||||
SendPropExclude( "DT_BaseFlex", "m_viewtarget" ),
|
||||
@ -60,35 +65,82 @@ END_SEND_TABLE()
|
||||
BEGIN_DATADESC( CHL2MP_Player )
|
||||
END_DATADESC()
|
||||
|
||||
const char *g_ppszRandomCitizenModels[] =
|
||||
// StargateTC: team 3 (Goa'uld, == TEAM_REBELS index) draws from this list.
|
||||
const char *g_ppszRandomCitizenModels[] =
|
||||
{
|
||||
"models/humans/group03/male_01.mdl",
|
||||
"models/humans/group03/male_02.mdl",
|
||||
"models/humans/group03/female_01.mdl",
|
||||
"models/humans/group03/male_03.mdl",
|
||||
"models/humans/group03/female_02.mdl",
|
||||
"models/humans/group03/male_04.mdl",
|
||||
"models/humans/group03/female_03.mdl",
|
||||
"models/humans/group03/male_05.mdl",
|
||||
"models/humans/group03/female_04.mdl",
|
||||
"models/humans/group03/male_06.mdl",
|
||||
"models/humans/group03/female_06.mdl",
|
||||
"models/humans/group03/male_07.mdl",
|
||||
"models/humans/group03/female_07.mdl",
|
||||
"models/humans/group03/male_08.mdl",
|
||||
"models/humans/group03/male_09.mdl",
|
||||
"models/stargate/player/goauld3/goauld3.mdl",
|
||||
"models/stargate/player/anubis/anubis.mdl",
|
||||
"models/stargate/player/horus/horus.mdl",
|
||||
"models/stargate/player/systemlord/systemlord.mdl",
|
||||
"models/stargate/player/snakegoauld/snakegoauld.mdl",
|
||||
};
|
||||
|
||||
// StargateTC: team 2 (Tau'ri, == TEAM_COMBINE index) draws from this list (SG-1).
|
||||
const char *g_ppszRandomCombineModels[] =
|
||||
{
|
||||
"models/combine_soldier.mdl",
|
||||
"models/combine_soldier_prisonguard.mdl",
|
||||
"models/combine_super_soldier.mdl",
|
||||
"models/police.mdl",
|
||||
"models/stargate/player/oneill/oneill.mdl",
|
||||
"models/stargate/player/carter/carter.mdl",
|
||||
"models/stargate/player/jackson/jackson.mdl",
|
||||
"models/stargate/player/tealc/tealc.mdl",
|
||||
"models/stargate/player/commander/commander.mdl",
|
||||
};
|
||||
|
||||
static bool Sg_IsModelInList( const char *pModel, const char * const *ppModels, int iModelCount )
|
||||
{
|
||||
if ( !pModel || !pModel[0] )
|
||||
return false;
|
||||
|
||||
#define MAX_COMBINE_MODELS 4
|
||||
for ( int i = 0; i < iModelCount; i++ )
|
||||
{
|
||||
if ( !Q_stricmp( ppModels[i], pModel ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int Sg_CountTeamPlayers( int iTeam )
|
||||
{
|
||||
CTeam *pTeam = GetGlobalTeam( iTeam );
|
||||
return pTeam ? pTeam->GetNumPlayers() : 0;
|
||||
}
|
||||
|
||||
static int Sg_GetAutoTeam()
|
||||
{
|
||||
const int iTorri = Sg_CountTeamPlayers( TEAM_COMBINE );
|
||||
const int iGoauld = Sg_CountTeamPlayers( TEAM_REBELS );
|
||||
|
||||
if ( iTorri < iGoauld )
|
||||
return TEAM_COMBINE;
|
||||
if ( iGoauld < iTorri )
|
||||
return TEAM_REBELS;
|
||||
|
||||
return random->RandomInt( 0, 1 ) ? TEAM_COMBINE : TEAM_REBELS;
|
||||
}
|
||||
|
||||
static bool Sg_WouldStackTeams( CHL2MP_Player *pPlayer, int iTeam )
|
||||
{
|
||||
if ( mp_autobalance.GetInt() <= 0 )
|
||||
return false;
|
||||
|
||||
if ( iTeam != TEAM_COMBINE && iTeam != TEAM_REBELS )
|
||||
return false;
|
||||
|
||||
const int iOtherTeam = ( iTeam == TEAM_COMBINE ) ? TEAM_REBELS : TEAM_COMBINE;
|
||||
int iJoinTeamPlayers = Sg_CountTeamPlayers( iTeam );
|
||||
int iOtherTeamPlayers = Sg_CountTeamPlayers( iOtherTeam );
|
||||
|
||||
if ( pPlayer && pPlayer->GetTeamNumber() == iTeam )
|
||||
return false;
|
||||
|
||||
if ( pPlayer && pPlayer->GetTeamNumber() == iOtherTeam )
|
||||
iOtherTeamPlayers--;
|
||||
|
||||
return iJoinTeamPlayers > iOtherTeamPlayers;
|
||||
}
|
||||
|
||||
|
||||
#define MAX_COMBINE_MODELS 5
|
||||
#define MODEL_CHANGE_INTERVAL 5.0f
|
||||
#define TEAM_CHANGE_INTERVAL 5.0f
|
||||
|
||||
@ -106,6 +158,7 @@ CHL2MP_Player::CHL2MP_Player() : m_PlayerAnimState( this )
|
||||
m_flNextTeamChangeTime = 0.0f;
|
||||
|
||||
m_iSpawnInterpCounter = 0;
|
||||
m_iStargateClass = 0;
|
||||
|
||||
m_bEnterObserver = false;
|
||||
m_bReady = false;
|
||||
@ -198,38 +251,52 @@ void CHL2MP_Player::GiveDefaultItems( void )
|
||||
{
|
||||
EquipSuit();
|
||||
|
||||
CBasePlayer::GiveAmmo( 255, "Pistol");
|
||||
CBasePlayer::GiveAmmo( 45, "SMG1");
|
||||
CBasePlayer::GiveAmmo( 1, "grenade" );
|
||||
CBasePlayer::GiveAmmo( 6, "Buckshot");
|
||||
CBasePlayer::GiveAmmo( 6, "357" );
|
||||
// StargateTC: no Half-Life 2 weapons. The recovered GoldSrc rules use
|
||||
// mp_wepselmode 0/1/2 for melee-only, class choice, or the team pack.
|
||||
CBasePlayer::GiveAmmo( 255, "Pistol" );
|
||||
CBasePlayer::GiveAmmo( 255, "SMG1" );
|
||||
CBasePlayer::GiveAmmo( 64, "Buckshot" );
|
||||
CBasePlayer::GiveAmmo( 32, "357" );
|
||||
CBasePlayer::GiveAmmo( 5, "Grenade" );
|
||||
|
||||
if ( GetPlayerModelType() == PLAYER_SOUNDS_METROPOLICE || GetPlayerModelType() == PLAYER_SOUNDS_COMBINESOLDIER )
|
||||
const int iWeaponMode = mp_wepselmode.GetInt();
|
||||
const char *pSwitchTo = "weapon_couteau";
|
||||
|
||||
if ( GetTeamNumber() == TEAM_REBELS ) // Goa'uld (StargateTC::TEAM_GOAULD == 3)
|
||||
{
|
||||
GiveNamedItem( "weapon_stunstick" );
|
||||
GiveNamedItem( "weapon_coujaf" ); // team melee
|
||||
pSwitchTo = "weapon_coujaf";
|
||||
|
||||
if ( iWeaponMode >= 2 )
|
||||
{
|
||||
GiveNamedItem( "weapon_zat" );
|
||||
GiveNamedItem( "weapon_glstaff" ); // Goa'uld staff
|
||||
GiveNamedItem( "weapon_gacgoa" );
|
||||
pSwitchTo = "weapon_glstaff";
|
||||
}
|
||||
}
|
||||
else if ( GetPlayerModelType() == PLAYER_SOUNDS_CITIZEN )
|
||||
else if ( GetTeamNumber() == TEAM_COMBINE ) // Tau'ri / Torri (StargateTC::TEAM_TORRI == 2)
|
||||
{
|
||||
GiveNamedItem( "weapon_crowbar" );
|
||||
}
|
||||
|
||||
GiveNamedItem( "weapon_pistol" );
|
||||
GiveNamedItem( "weapon_smg1" );
|
||||
GiveNamedItem( "weapon_frag" );
|
||||
GiveNamedItem( "weapon_physcannon" );
|
||||
GiveNamedItem( "weapon_couteau" ); // team melee (knife)
|
||||
|
||||
const char *szDefaultWeaponName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_defaultweapon" );
|
||||
|
||||
CBaseCombatWeapon *pDefaultWeapon = Weapon_OwnsThisType( szDefaultWeaponName );
|
||||
|
||||
if ( pDefaultWeapon )
|
||||
{
|
||||
Weapon_Switch( pDefaultWeapon );
|
||||
if ( iWeaponMode >= 2 )
|
||||
{
|
||||
GiveNamedItem( "weapon_m92s" );
|
||||
GiveNamedItem( "weapon_m16" );
|
||||
GiveNamedItem( "weapon_zat" );
|
||||
GiveNamedItem( "weapon_flashbang" );
|
||||
pSwitchTo = "weapon_m16";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Weapon_Switch( Weapon_OwnsThisType( "weapon_physcannon" ) );
|
||||
// Unassigned / spectator: only a knife so they spawn with something SG.
|
||||
GiveNamedItem( "weapon_couteau" );
|
||||
}
|
||||
|
||||
CBaseCombatWeapon *pWeapon = Weapon_OwnsThisType( pSwitchTo );
|
||||
if ( pWeapon )
|
||||
Weapon_Switch( pWeapon );
|
||||
}
|
||||
|
||||
void CHL2MP_Player::PickDefaultSpawnTeam( void )
|
||||
@ -256,28 +323,9 @@ void CHL2MP_Player::PickDefaultSpawnTeam( void )
|
||||
}
|
||||
else
|
||||
{
|
||||
CTeam *pCombine = g_Teams[TEAM_COMBINE];
|
||||
CTeam *pRebels = g_Teams[TEAM_REBELS];
|
||||
|
||||
if ( pCombine == NULL || pRebels == NULL )
|
||||
{
|
||||
ChangeTeam( random->RandomInt( TEAM_COMBINE, TEAM_REBELS ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pCombine->GetNumPlayers() > pRebels->GetNumPlayers() )
|
||||
{
|
||||
ChangeTeam( TEAM_REBELS );
|
||||
}
|
||||
else if ( pCombine->GetNumPlayers() < pRebels->GetNumPlayers() )
|
||||
{
|
||||
ChangeTeam( TEAM_COMBINE );
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeTeam( random->RandomInt( TEAM_COMBINE, TEAM_REBELS ) );
|
||||
}
|
||||
}
|
||||
// GoldSrc StargateTC starts clients as spectators and opens the
|
||||
// team/class menu; it does not auto-spawn them onto a combat team.
|
||||
BaseClass::ChangeTeam( TEAM_SPECTATOR );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -302,6 +350,10 @@ void CHL2MP_Player::Spawn(void)
|
||||
RemoveEffects( EF_NODRAW );
|
||||
|
||||
GiveDefaultItems();
|
||||
|
||||
// StargateTC: re-apply the chosen class loadout + refresh HUD team state.
|
||||
extern void Sg_OnPlayerSpawn( CHL2MP_Player *pPlayer );
|
||||
Sg_OnPlayerSpawn( this );
|
||||
}
|
||||
|
||||
SetNumAnimOverlays( 3 );
|
||||
@ -366,25 +418,18 @@ bool CHL2MP_Player::ValidatePlayerModel( const char *pModel )
|
||||
|
||||
void CHL2MP_Player::SetPlayerTeamModel( void )
|
||||
{
|
||||
if ( GetTeamNumber() == TEAM_SPECTATOR )
|
||||
return;
|
||||
|
||||
if ( GetStargateClass() > 0 )
|
||||
return;
|
||||
|
||||
const char *szModelName = NULL;
|
||||
szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_playermodel" );
|
||||
|
||||
int modelIndex = modelinfo->GetModelIndex( szModelName );
|
||||
|
||||
if ( modelIndex == -1 || ValidatePlayerModel( szModelName ) == false )
|
||||
{
|
||||
szModelName = "models/Combine_Soldier.mdl";
|
||||
m_iModelType = TEAM_COMBINE;
|
||||
|
||||
char szReturnString[512];
|
||||
|
||||
Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", szModelName );
|
||||
engine->ClientCommand ( edict(), szReturnString );
|
||||
}
|
||||
|
||||
if ( GetTeamNumber() == TEAM_COMBINE )
|
||||
{
|
||||
if ( Q_stristr( szModelName, "models/human") )
|
||||
if ( !Sg_IsModelInList( szModelName, g_ppszRandomCombineModels, ARRAYSIZE( g_ppszRandomCombineModels ) ) )
|
||||
{
|
||||
int nHeads = ARRAYSIZE( g_ppszRandomCombineModels );
|
||||
|
||||
@ -396,7 +441,7 @@ void CHL2MP_Player::SetPlayerTeamModel( void )
|
||||
}
|
||||
else if ( GetTeamNumber() == TEAM_REBELS )
|
||||
{
|
||||
if ( !Q_stristr( szModelName, "models/human") )
|
||||
if ( !Sg_IsModelInList( szModelName, g_ppszRandomCitizenModels, ARRAYSIZE( g_ppszRandomCitizenModels ) ) )
|
||||
{
|
||||
int nHeads = ARRAYSIZE( g_ppszRandomCitizenModels );
|
||||
|
||||
@ -406,6 +451,11 @@ void CHL2MP_Player::SetPlayerTeamModel( void )
|
||||
|
||||
m_iModelType = TEAM_REBELS;
|
||||
}
|
||||
else
|
||||
{
|
||||
szModelName = g_ppszRandomCitizenModels[0];
|
||||
m_iModelType = TEAM_REBELS;
|
||||
}
|
||||
|
||||
SetModel( szModelName );
|
||||
SetupPlayerSoundsByModel( szModelName );
|
||||
@ -426,7 +476,7 @@ void CHL2MP_Player::SetPlayerModel( void )
|
||||
|
||||
if ( ValidatePlayerModel( pszCurrentModelName ) == false )
|
||||
{
|
||||
pszCurrentModelName = "models/Combine_Soldier.mdl";
|
||||
pszCurrentModelName = "models/stargate/player/oneill/oneill.mdl";
|
||||
}
|
||||
|
||||
Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", pszCurrentModelName );
|
||||
@ -474,7 +524,7 @@ void CHL2MP_Player::SetPlayerModel( void )
|
||||
|
||||
if ( modelIndex == -1 )
|
||||
{
|
||||
szModelName = "models/Combine_Soldier.mdl";
|
||||
szModelName = "models/stargate/player/oneill/oneill.mdl";
|
||||
m_iModelType = TEAM_COMBINE;
|
||||
|
||||
char szReturnString[512];
|
||||
@ -503,6 +553,10 @@ void CHL2MP_Player::SetupPlayerSoundsByModel( const char *pModelName )
|
||||
{
|
||||
m_iPlayerSoundType = (int)PLAYER_SOUNDS_COMBINESOLDIER;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iPlayerSoundType = (int)PLAYER_SOUNDS_CITIZEN;
|
||||
}
|
||||
}
|
||||
|
||||
void CHL2MP_Player::ResetAnimation( void )
|
||||
@ -900,6 +954,7 @@ void CHL2MP_Player::ChangeTeam( int iTeam )
|
||||
}*/
|
||||
|
||||
bool bKill = false;
|
||||
const int iOldTeam = GetTeamNumber();
|
||||
|
||||
if ( HL2MPRules()->IsTeamplay() != true && iTeam != TEAM_SPECTATOR )
|
||||
{
|
||||
@ -909,7 +964,7 @@ void CHL2MP_Player::ChangeTeam( int iTeam )
|
||||
|
||||
if ( HL2MPRules()->IsTeamplay() == true )
|
||||
{
|
||||
if ( iTeam != GetTeamNumber() && GetTeamNumber() != TEAM_UNASSIGNED )
|
||||
if ( iTeam != iOldTeam && iOldTeam != TEAM_UNASSIGNED && iOldTeam != TEAM_SPECTATOR && iTeam != TEAM_SPECTATOR && IsAlive() )
|
||||
{
|
||||
bKill = true;
|
||||
}
|
||||
@ -919,7 +974,13 @@ void CHL2MP_Player::ChangeTeam( int iTeam )
|
||||
|
||||
m_flNextTeamChangeTime = gpGlobals->curtime + TEAM_CHANGE_INTERVAL;
|
||||
|
||||
if ( HL2MPRules()->IsTeamplay() == true )
|
||||
if ( iTeam == TEAM_SPECTATOR )
|
||||
{
|
||||
RemoveAllItems( true );
|
||||
|
||||
State_Transition( STATE_OBSERVER_MODE );
|
||||
}
|
||||
else if ( HL2MPRules()->IsTeamplay() == true )
|
||||
{
|
||||
SetPlayerTeamModel();
|
||||
}
|
||||
@ -928,13 +989,6 @@ void CHL2MP_Player::ChangeTeam( int iTeam )
|
||||
SetPlayerModel();
|
||||
}
|
||||
|
||||
if ( iTeam == TEAM_SPECTATOR )
|
||||
{
|
||||
RemoveAllItems( true );
|
||||
|
||||
State_Transition( STATE_OBSERVER_MODE );
|
||||
}
|
||||
|
||||
if ( bKill == true )
|
||||
{
|
||||
CommitSuicide();
|
||||
@ -943,7 +997,12 @@ void CHL2MP_Player::ChangeTeam( int iTeam )
|
||||
|
||||
bool CHL2MP_Player::HandleCommand_JoinTeam( int team )
|
||||
{
|
||||
if ( !GetGlobalTeam( team ) || team == 0 )
|
||||
if ( team == 0 )
|
||||
{
|
||||
team = Sg_GetAutoTeam();
|
||||
}
|
||||
|
||||
if ( !GetGlobalTeam( team ) )
|
||||
{
|
||||
Warning( "HandleCommand_JoinTeam( %d ) - invalid team index.\n", team );
|
||||
return false;
|
||||
@ -974,12 +1033,25 @@ bool CHL2MP_Player::HandleCommand_JoinTeam( int team )
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( Sg_WouldStackTeams( this, team ) )
|
||||
{
|
||||
ClientPrint( this, HUD_PRINTCENTER, "That team has too many players." );
|
||||
ShowViewPortPanel( PANEL_TEAM, true );
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool bNeedsRespawn = ( GetTeamNumber() == TEAM_UNASSIGNED || GetTeamNumber() == TEAM_SPECTATOR || IsObserver() || IsDead() );
|
||||
StopObserverMode();
|
||||
State_Transition(STATE_ACTIVE);
|
||||
}
|
||||
|
||||
// Switch their actual team...
|
||||
ChangeTeam( team );
|
||||
// Switch their actual team...
|
||||
ChangeTeam( team );
|
||||
|
||||
if ( bNeedsRespawn )
|
||||
{
|
||||
Spawn();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1000,6 +1072,7 @@ bool CHL2MP_Player::ClientCommand( const CCommand &args )
|
||||
if ( args.ArgC() < 2 )
|
||||
{
|
||||
Warning( "Player sent bad jointeam syntax\n" );
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ShouldRunRateLimitedCommand( args ) )
|
||||
@ -1009,6 +1082,39 @@ bool CHL2MP_Player::ClientCommand( const CCommand &args )
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if ( FStrEq( args[0], "joinclass" ) )
|
||||
{
|
||||
extern void Sg_HandleJoinClass( CHL2MP_Player *pPlayer, const char *pszClass );
|
||||
Sg_HandleJoinClass( this, args.ArgC() >= 2 ? args[1] : "" );
|
||||
return true;
|
||||
}
|
||||
else if ( FStrEq( args[0], "autopick" ) )
|
||||
{
|
||||
if ( ShouldRunRateLimitedCommand( args ) )
|
||||
{
|
||||
HandleCommand_JoinTeam( 0 );
|
||||
extern void Sg_HandleJoinClass( CHL2MP_Player *pPlayer, const char *pszClass );
|
||||
Sg_HandleJoinClass( this, "auto" );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if ( FStrEq( args[0], "classe" ) )
|
||||
{
|
||||
extern void Sg_HandleJoinClass( CHL2MP_Player *pPlayer, const char *pszClass );
|
||||
Sg_HandleJoinClass( this, args.ArgC() >= 2 ? args[1] : "" );
|
||||
return true;
|
||||
}
|
||||
else if ( FStrEq( args[0], "showmenu" ) )
|
||||
{
|
||||
ShowViewPortPanel( PANEL_TEAM, true );
|
||||
return true;
|
||||
}
|
||||
else if ( FStrEq( args[0], "showequip" ) )
|
||||
{
|
||||
if ( mp_wepselmode.GetInt() > 0 )
|
||||
ShowViewPortPanel( PANEL_TEAM, true );
|
||||
return true;
|
||||
}
|
||||
else if ( FStrEq( args[0], "joingame" ) )
|
||||
{
|
||||
return true;
|
||||
@ -1576,7 +1682,7 @@ CHL2MPPlayerStateInfo *CHL2MP_Player::State_LookupInfo( HL2MPPlayerState state )
|
||||
bool CHL2MP_Player::StartObserverMode(int mode)
|
||||
{
|
||||
//we only want to go into observer mode if the player asked to, not on a death timeout
|
||||
if ( m_bEnterObserver == true )
|
||||
if ( m_bEnterObserver == true || GetTeamNumber() == TEAM_SPECTATOR )
|
||||
{
|
||||
VPhysicsDestroyObject();
|
||||
return BaseClass::StartObserverMode( mode );
|
||||
|
||||
@ -97,6 +97,8 @@ public:
|
||||
void SetPlayerModel( void );
|
||||
void SetPlayerTeamModel( void );
|
||||
Activity TranslateTeamActivity( Activity ActToTranslate );
|
||||
int GetStargateClass() const { return m_iStargateClass; }
|
||||
void SetStargateClass( int iClass ) { m_iStargateClass = iClass; }
|
||||
|
||||
float GetNextModelChangeTime( void ) { return m_flNextModelChangeTime; }
|
||||
float GetNextTeamChangeTime( void ) { return m_flNextTeamChangeTime; }
|
||||
@ -147,6 +149,7 @@ private:
|
||||
int m_iModelType;
|
||||
CNetworkVar( int, m_iSpawnInterpCounter );
|
||||
CNetworkVar( int, m_iPlayerSoundType );
|
||||
CNetworkVar( int, m_iStargateClass );
|
||||
|
||||
float m_flNextModelChangeTime;
|
||||
float m_flNextTeamChangeTime;
|
||||
|
||||
@ -304,6 +304,7 @@ $Project "Server (HL2MP)"
|
||||
$File "stargate\sg_kawoosh.cpp"
|
||||
$File "stargate\sg_mcp_debug.cpp"
|
||||
$File "stargate\sg_player_spawn.cpp"
|
||||
$File "stargate\sg_player_class.cpp"
|
||||
$File "stargate\STUBS.cpp"
|
||||
$File "$SRCDIR\game\shared\stargate\sg_weapons.cpp"
|
||||
$File "$SRCDIR\game\shared\stargate\sg_constants.h"
|
||||
|
||||
295
game/server/stargate/sg_player_class.cpp
Normal file
295
game/server/stargate/sg_player_class.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
//============= Copyright (c) StargateTC Source Team ============================
|
||||
//
|
||||
// Server side of the StargateTC team/class selection flow.
|
||||
//
|
||||
// The behavior mirrors the recovered GoldSrc rules: clients enter spectator,
|
||||
// choose Tau'ri or Goa'uld, then choose one of five team classes. mp_wepselmode
|
||||
// controls whether that class contributes a weapon on top of the team melee or
|
||||
// default team pack.
|
||||
//
|
||||
//==============================================================================
|
||||
#include "cbase.h"
|
||||
#include "hl2mp_player.h"
|
||||
#include "recipientfilter.h"
|
||||
#include "stargate/sg_constants.h"
|
||||
#include <limits.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
extern ConVar mp_wepselmode;
|
||||
|
||||
struct SgClassInfo_t
|
||||
{
|
||||
const char *name; // joinclass token
|
||||
const char *display; // scoreboard/chat label
|
||||
const char *avatar; // avatar sprite name (vgui/stargate/avatars/<avatar>)
|
||||
const char *model; // player model
|
||||
const char *weapon; // signature loadout weapon
|
||||
int team; // owning team
|
||||
int slot; // original class slot, 1..5 inside team
|
||||
int limit; // 0 means unlimited
|
||||
};
|
||||
|
||||
// Class roster recovered from the GoldSrc class menu and class-limit checks.
|
||||
static const SgClassInfo_t s_Classes[] = {
|
||||
{ "oneill", "O'Neill", "oneill", "models/stargate/player/oneill/oneill.mdl", "weapon_m92s", StargateTC::TEAM_TORRI, 1, 2 },
|
||||
{ "carter", "Carter", "carter", "models/stargate/player/carter/carter.mdl", "weapon_zat", StargateTC::TEAM_TORRI, 2, 3 },
|
||||
{ "jackson", "Jackson", "jackson", "models/stargate/player/jackson/jackson.mdl", "weapon_zat", StargateTC::TEAM_TORRI, 3, 3 },
|
||||
{ "tealc", "Teal'c", "tealc", "models/stargate/player/tealc/tealc.mdl", "weapon_lance", StargateTC::TEAM_TORRI, 4, 0 },
|
||||
{ "soldat", "Soldier", "commder", "models/stargate/player/commander/commander.mdl", "weapon_m16", StargateTC::TEAM_TORRI, 5, 0 },
|
||||
{ "dieu", "System Lord", "lord", "models/stargate/player/systemlord/systemlord.mdl", "weapon_zatarc", StargateTC::TEAM_GOAULD, 1, 2 },
|
||||
{ "anubis", "Anubis Guard", "anubis", "models/stargate/player/anubis/anubis.mdl", "weapon_lance", StargateTC::TEAM_GOAULD, 2, 2 },
|
||||
{ "jaffa", "Jaffa", "goauld3", "models/stargate/player/goauld3/goauld3.mdl", "weapon_lance", StargateTC::TEAM_GOAULD, 3, 0 },
|
||||
{ "prima", "First Prime", "snake", "models/stargate/player/snakegoauld/snakegoauld.mdl", "weapon_lance", StargateTC::TEAM_GOAULD, 4, 3 },
|
||||
{ "esclave", "Horus Guard", "slave", "models/stargate/player/horus/horus.mdl", "weapon_lance", StargateTC::TEAM_GOAULD, 5, 3 },
|
||||
};
|
||||
|
||||
// Chosen class per player slot (1..MAX_PLAYERS).
|
||||
static char s_PlayerClass[ MAX_PLAYERS + 1 ][ 32 ];
|
||||
|
||||
static const SgClassInfo_t *Sg_FindClass( const char *name )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( s_Classes ); i++ )
|
||||
{
|
||||
if ( name && !Q_stricmp( s_Classes[i].name, name ) )
|
||||
return &s_Classes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const SgClassInfo_t *Sg_FindClassBySlot( int team, int slot )
|
||||
{
|
||||
for ( int i = 0; i < ARRAYSIZE( s_Classes ); i++ )
|
||||
{
|
||||
if ( s_Classes[i].team == team && s_Classes[i].slot == slot )
|
||||
return &s_Classes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int Sg_CountPlayersUsingClass( const SgClassInfo_t *pClass, CHL2MP_Player *pIgnore )
|
||||
{
|
||||
if ( !pClass )
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CHL2MP_Player *pOther = ToHL2MPPlayer( UTIL_PlayerByIndex( i ) );
|
||||
if ( !pOther || pOther == pIgnore )
|
||||
continue;
|
||||
|
||||
if ( pOther->GetTeamNumber() != pClass->team )
|
||||
continue;
|
||||
|
||||
if ( !Q_stricmp( s_PlayerClass[i], pClass->name ) )
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool Sg_ClassHasRoom( const SgClassInfo_t *pClass, CHL2MP_Player *pPlayer )
|
||||
{
|
||||
if ( !pClass || pClass->limit <= 0 )
|
||||
return true;
|
||||
|
||||
return Sg_CountPlayersUsingClass( pClass, pPlayer ) < pClass->limit;
|
||||
}
|
||||
|
||||
static const SgClassInfo_t *Sg_FindAutoClass( int team, CHL2MP_Player *pPlayer )
|
||||
{
|
||||
const int start = random->RandomInt( 0, ARRAYSIZE( s_Classes ) - 1 );
|
||||
const SgClassInfo_t *pBest = NULL;
|
||||
int bestCount = INT_MAX;
|
||||
|
||||
for ( int offset = 0; offset < ARRAYSIZE( s_Classes ); offset++ )
|
||||
{
|
||||
const SgClassInfo_t *pClass = &s_Classes[( start + offset ) % ARRAYSIZE( s_Classes )];
|
||||
if ( pClass->team != team )
|
||||
continue;
|
||||
|
||||
if ( !Sg_ClassHasRoom( pClass, pPlayer ) )
|
||||
continue;
|
||||
|
||||
const int count = Sg_CountPlayersUsingClass( pClass, pPlayer );
|
||||
if ( count < bestCount )
|
||||
{
|
||||
pBest = pClass;
|
||||
bestCount = count;
|
||||
}
|
||||
}
|
||||
|
||||
return pBest;
|
||||
}
|
||||
|
||||
static const SgClassInfo_t *Sg_GetStoredClass( CHL2MP_Player *pPlayer )
|
||||
{
|
||||
if ( !pPlayer )
|
||||
return NULL;
|
||||
|
||||
const int idx = pPlayer->entindex();
|
||||
if ( idx < 1 || idx > MAX_PLAYERS )
|
||||
return NULL;
|
||||
|
||||
const SgClassInfo_t *pClass = Sg_FindClass( s_PlayerClass[idx] );
|
||||
if ( pClass && pClass->team == pPlayer->GetTeamNumber() )
|
||||
return pClass;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HUD message senders (client side: CHudStargate::MsgFunc_*).
|
||||
//-----------------------------------------------------------------------------
|
||||
void Sg_SendAboutMe( CBasePlayer *pPlayer )
|
||||
{
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
CSingleUserRecipientFilter filter( pPlayer );
|
||||
filter.MakeReliable();
|
||||
UserMessageBegin( filter, "SgAboutMe" );
|
||||
WRITE_SHORT( pPlayer->entindex() );
|
||||
WRITE_SHORT( pPlayer->GetTeamNumber() );
|
||||
MessageEnd();
|
||||
}
|
||||
|
||||
void Sg_SendAddPortrait( CBasePlayer *pPlayer, const char *avatar )
|
||||
{
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
CSingleUserRecipientFilter filter( pPlayer );
|
||||
filter.MakeReliable();
|
||||
UserMessageBegin( filter, "SgAddPortrait" );
|
||||
WRITE_SHORT( pPlayer->entindex() );
|
||||
WRITE_SHORT( pPlayer->GetTeamNumber() );
|
||||
WRITE_STRING( avatar ? avatar : "" );
|
||||
MessageEnd();
|
||||
}
|
||||
|
||||
void Sg_ResetPlayerClass( CHL2MP_Player *pPlayer )
|
||||
{
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
const int idx = pPlayer->entindex();
|
||||
if ( idx < 1 || idx > MAX_PLAYERS )
|
||||
return;
|
||||
|
||||
s_PlayerClass[idx][0] = '\0';
|
||||
pPlayer->SetStargateClass( 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Apply the stored class. Safe to call from spawn and from joinclass.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Sg_ApplyClass( CHL2MP_Player *pPlayer, bool bResetLoadout )
|
||||
{
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
Sg_SendAboutMe( pPlayer );
|
||||
|
||||
const SgClassInfo_t *pClass = Sg_GetStoredClass( pPlayer );
|
||||
if ( !pClass )
|
||||
{
|
||||
pPlayer->SetStargateClass( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
pPlayer->SetStargateClass( pClass->slot );
|
||||
pPlayer->SetModel( pClass->model );
|
||||
pPlayer->SetupPlayerSoundsByModel( pClass->model );
|
||||
|
||||
Sg_SendAddPortrait( pPlayer, pClass->avatar );
|
||||
|
||||
if ( !pPlayer->IsAlive() )
|
||||
return;
|
||||
|
||||
if ( bResetLoadout )
|
||||
{
|
||||
pPlayer->RemoveAllItems( true );
|
||||
pPlayer->GiveDefaultItems();
|
||||
}
|
||||
|
||||
if ( mp_wepselmode.GetInt() <= 0 || !pClass->weapon[0] )
|
||||
return;
|
||||
|
||||
if ( !pPlayer->Weapon_OwnsThisType( pClass->weapon ) )
|
||||
pPlayer->GiveNamedItem( pClass->weapon );
|
||||
|
||||
CBaseCombatWeapon *pWeapon = pPlayer->Weapon_OwnsThisType( pClass->weapon );
|
||||
if ( pWeapon )
|
||||
pPlayer->Weapon_Switch( pWeapon );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// `joinclass <name>`, `joinclass auto`, and legacy `classe <1..5>`.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Sg_HandleJoinClass( CHL2MP_Player *pPlayer, const char *pszClass )
|
||||
{
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
const int idx = pPlayer->entindex();
|
||||
if ( idx < 1 || idx > MAX_PLAYERS )
|
||||
return;
|
||||
|
||||
const SgClassInfo_t *pClass = NULL;
|
||||
const char *pClassArg = pszClass ? pszClass : "";
|
||||
|
||||
if ( !Q_stricmp( pClassArg, "auto" ) )
|
||||
{
|
||||
if ( pPlayer->GetTeamNumber() != StargateTC::TEAM_TORRI && pPlayer->GetTeamNumber() != StargateTC::TEAM_GOAULD )
|
||||
pPlayer->HandleCommand_JoinTeam( 0 );
|
||||
|
||||
pClass = Sg_FindAutoClass( pPlayer->GetTeamNumber(), pPlayer );
|
||||
}
|
||||
else if ( pClassArg[0] >= '0' && pClassArg[0] <= '9' )
|
||||
{
|
||||
pClass = Sg_FindClassBySlot( pPlayer->GetTeamNumber(), atoi( pClassArg ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pClass = Sg_FindClass( pClassArg );
|
||||
}
|
||||
|
||||
if ( !pClass )
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTCONSOLE, "joinclass: unknown class\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( pPlayer->GetTeamNumber() != pClass->team )
|
||||
{
|
||||
if ( !pPlayer->HandleCommand_JoinTeam( pClass->team ) )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !Sg_ClassHasRoom( pClass, pPlayer ) )
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTCENTER, "That class is full." );
|
||||
return;
|
||||
}
|
||||
|
||||
Q_strncpy( s_PlayerClass[idx], pClass->name, sizeof( s_PlayerClass[idx] ) );
|
||||
|
||||
char msg[ 96 ];
|
||||
Q_snprintf( msg, sizeof( msg ), "Class: %s\n", pClass->display );
|
||||
ClientPrint( pPlayer, HUD_PRINTTALK, msg );
|
||||
|
||||
Sg_ApplyClass( pPlayer, true );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Called from CHL2MP_Player::Spawn so the class loadout/HUD survive respawns.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Sg_OnPlayerSpawn( CHL2MP_Player *pPlayer )
|
||||
{
|
||||
Sg_ApplyClass( pPlayer, false );
|
||||
}
|
||||
@ -811,14 +811,7 @@ void CHL2MPRules::ClientSettingsChanged( CBasePlayer *pPlayer )
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( Q_stristr( szModelName, "models/human") )
|
||||
{
|
||||
pHL2Player->ChangeTeam( TEAM_REBELS );
|
||||
}
|
||||
else
|
||||
{
|
||||
pHL2Player->ChangeTeam( TEAM_COMBINE );
|
||||
}
|
||||
pHL2Player->SetPlayerTeamModel();
|
||||
}
|
||||
}
|
||||
if ( sv_report_client_settings.GetInt() == 1 )
|
||||
|
||||
Loading…
Reference in New Issue
Block a user