diff --git a/cl_dll/StudioModelRenderer.cpp b/cl_dll/StudioModelRenderer.cpp index fc168dfa..fa1d27e2 100644 --- a/cl_dll/StudioModelRenderer.cpp +++ b/cl_dll/StudioModelRenderer.cpp @@ -189,6 +189,9 @@ void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiob vec3_t angle1, angle2; mstudioanimvalue_t *panimvalue; + if( panim == NULL ) + return; + for( j = 0; j < 3; j++ ) { if( panim->offset[j + 3] == 0 ) diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index 500be69f..31954dc8 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -870,7 +870,7 @@ int CHudAmmo::Draw( float flTime ) if( m_fFade > 0 ) m_fFade -= ( (float)gHUD.m_flTimeDelta * 20.0f ); - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); ScaleColors( r, g, b, a ); @@ -898,7 +898,7 @@ int CHudAmmo::Draw( float flTime ) x += AmmoWidth / 2; - UnpackRGB( r,g,b, gHUD.uColor ); + UnpackRGB( r,g,b, gHUD.uColor ); // draw the | bar FillRGBA( x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a ); @@ -968,7 +968,7 @@ int DrawBar( int x, int y, int width, int height, float f ) width -= w; } - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); FillRGBA( x, y, width, height, r, g, b, 128 ); @@ -1036,7 +1036,7 @@ int CHudAmmo::DrawWList( float flTime ) { int iWidth; - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); if( iActiveSlot == i ) a = 255; @@ -1087,7 +1087,7 @@ int CHudAmmo::DrawWList( float flTime ) if( !p || !p->iId ) continue; - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); // if active, then we must have ammo. if( gpActiveSel == p ) @@ -1124,7 +1124,7 @@ int CHudAmmo::DrawWList( float flTime ) else { // Draw Row of weapons. - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); for( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) { @@ -1135,7 +1135,7 @@ int CHudAmmo::DrawWList( float flTime ) if( gWR.HasAmmo( p ) ) { - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); a = 128; } else diff --git a/cl_dll/ammo_secondary.cpp b/cl_dll/ammo_secondary.cpp index 4034c86f..7357b74d 100644 --- a/cl_dll/ammo_secondary.cpp +++ b/cl_dll/ammo_secondary.cpp @@ -60,7 +60,7 @@ int CHudAmmoSecondary::Draw( float flTime ) // draw secondary ammo icons above normal ammo readout int a, x, y, r, g, b, AmmoWidth; - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); a = (int)Q_max( MIN_ALPHA, m_fFade ); if( m_fFade > 0 ) m_fFade -= ( (float)gHUD.m_flTimeDelta * 20.0f ); // slowly lower alpha to fade out icons diff --git a/cl_dll/ammohistory.cpp b/cl_dll/ammohistory.cpp index a3961da7..de7bd6b6 100644 --- a/cl_dll/ammohistory.cpp +++ b/cl_dll/ammohistory.cpp @@ -125,7 +125,7 @@ int HistoryResource::DrawAmmoHistory( float flTime ) HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic ); int r, g, b; - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); float scale = ( rgAmmoHistory[i].DisplayTime - flTime ) * 80; ScaleColors( r, g, b, Q_min( scale, 255 ) ); @@ -152,7 +152,7 @@ int HistoryResource::DrawAmmoHistory( float flTime ) return 1; // we don't know about the weapon yet, so don't draw anything int r, g, b; - UnpackRGB( r,g,b, RGB_YELLOWISH ); + UnpackRGB( r,g,b, gHUD.uColor ); if( !gWR.HasAmmo( weap ) ) UnpackRGB( r, g, b, RGB_REDISH ); // if the weapon doesn't have ammo, display it as red @@ -174,7 +174,7 @@ int HistoryResource::DrawAmmoHistory( float flTime ) wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId ); - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); float scale = ( rgAmmoHistory[i].DisplayTime - flTime ) * 80; ScaleColors( r, g, b, Q_min( scale, 255 ) ); diff --git a/cl_dll/battery.cpp b/cl_dll/battery.cpp index b6cd9e0b..6e881e30 100644 --- a/cl_dll/battery.cpp +++ b/cl_dll/battery.cpp @@ -80,7 +80,7 @@ int CHudBattery::Draw( float flTime ) rc = *m_prc2; rc.top += m_iHeight * ( (float)( 100 - ( Q_min( 100, m_iBat ) ) ) * 0.01f ); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); if( !( gHUD.m_iWeaponBits & ( 1 << ( WEAPON_SUIT ) ) ) ) return 1; diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 2488f9ab..7b2f1fa4 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -71,6 +71,10 @@ void EV_SnarkFire( struct event_args_s *args ); void EV_TrainPitchAdjust( struct event_args_s *args ); void EV_VehiclePitchAdjust( event_args_t *args ); + +void EV_Vorti( struct event_args_s *args ); +void EV_FireVorti( struct event_args_s *args ); +void EV_SpinVorti( struct event_args_s *args ); } #define VECTOR_CONE_1DEGREES Vector( 0.00873f, 0.00873f, 0.00873f ) diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp index 3ec69973..a7928b49 100644 --- a/cl_dll/flashlight.cpp +++ b/cl_dll/flashlight.cpp @@ -122,7 +122,7 @@ int CHudFlashlight::Draw( float flTime ) if( m_flBat < 0.20f ) UnpackRGB( r,g,b, RGB_REDISH ); else - UnpackRGB( r,g,b, RGB_YELLOWISH ); + UnpackRGB( r,g,b, gHUD.uColor ); ScaleColors( r, g, b, a ); diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index 183686b0..ce5cee69 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -167,7 +167,7 @@ void CHudHealth::GetPainColor( int &r, int &g, int &b ) #else if( m_iHealth > 25 ) { - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); } else { @@ -178,6 +178,93 @@ void CHudHealth::GetPainColor( int &r, int &g, int &b ) #endif } +void CHudHealth::DrawAlienHealthBar( void ) +{ + if ( m_HUD_alien == -1 ) + return; + + HSPRITE m_hSprite1; + HSPRITE m_hSprite2; + wrect_t *m_prc1; + wrect_t *m_prc2; + + float m_fFade; + int m_iHeight, m_iWidth; // width of the battery innards + + m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded + m_prc1 = &gHUD.GetSpriteRect( m_HUD_alien /*HUD_suit_empty*/ ); + m_prc2 = &gHUD.GetSpriteRect( m_HUD_alien /*HUD_suit_full*/ ); + m_iHeight = m_prc2->bottom - m_prc1->top; + m_iWidth = m_prc2->right - m_prc1->left; + m_fFade = 0; + + //============================================= + int r, g, b, x, y, a; + wrect_t rc; + + rc = *m_prc2; + //rc.top += m_iHeight * ((float)(100-(min(100,m_iHealth))) * 0.01); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 + rc.left += m_iWidth * ((float)(100-(min(100,m_iHealth))) * 0.005); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 + rc.right -= m_iWidth * ((float)(100-(min(100,m_iHealth))) * 0.005); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 + + //UnpackRGB(r,g,b, gHUD.uColor); + r = 180; + g = 255; + b = 96; + + // Has health changed? Flash the health # + if (m_fFade) + { + if (m_fFade > FADE_TIME) + m_fFade = FADE_TIME; + + m_fFade -= (gHUD.m_flTimeDelta * 20); + if (m_fFade <= 0) + { + a = 128; + m_fFade = 0; + } + + // Fade the health number back to dim + + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; + + } + else + a = MIN_ALPHA; + + ScaleColors(r, g, b, a ); + + int iOffset = (m_prc1->bottom - m_prc1->top)/6; + + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; + x = ScreenWidth/2 - (m_prc1->right - m_prc1->left)/2; + + // make sure we have the right sprite handles + if ( !m_hSprite1 ) + m_hSprite1 = gHUD.GetSprite( m_HUD_alien ); + if ( !m_hSprite2 ) + m_hSprite2 = gHUD.GetSprite( m_HUD_alien ); + + SPR_Set(m_hSprite1, r, g, b ); + //SPR_DrawAdditive( 0, x, y - iOffset, m_prc1); + SPR_DrawAdditive( 0, x - iOffset, y, m_prc1); + + //if (rc.bottom > rc.top) + if (rc.right > rc.left) + { + SPR_Set(m_hSprite2, r, g, b ); + //SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc); + SPR_DrawAdditive( 0, x - iOffset + (rc.left - m_prc2->left), y, &rc); + } + + //x += (m_prc1->right - m_prc1->left); + x = 32; + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); + + return; //1 +} + int CHudHealth::Draw( float flTime ) { int r, g, b; @@ -187,6 +274,12 @@ int CHudHealth::Draw( float flTime ) if( ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) || gEngfuncs.IsSpectateOnly() ) return 1; + if( m_iFlags & HUD_ALIEN ) + { + DrawAlienHealthBar(); + return 1; + } + if( !m_hSprite ) m_hSprite = LoadSprite( PAIN_NAME ); @@ -233,7 +326,7 @@ int CHudHealth::Draw( float flTime ) int iHeight = gHUD.m_iFontHeight; int iWidth = HealthWidth / 10; - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); FillRGBA( x, y, iWidth, iHeight, r, g, b, a ); } @@ -382,7 +475,7 @@ int CHudHealth::DrawDamage( float flTime ) if( !m_bitsDamage ) return 1; - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); a = (int)( fabs( sin( flTime * 2.0f ) ) * 256.0f ); diff --git a/cl_dll/health.h b/cl_dll/health.h index 41375a69..b91d9726 100644 --- a/cl_dll/health.h +++ b/cl_dll/health.h @@ -105,11 +105,13 @@ public: virtual int VidInit( void ); virtual int Draw( float fTime ); virtual void Reset( void ); + void DrawAlienHealthBar( void ); int MsgFunc_Health( const char *pszName, int iSize, void *pbuf ); int MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ); int m_iHealth; int m_HUD_dmg_bio; int m_HUD_cross; + int m_HUD_alien; float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight; void GetPainColor( int &r, int &g, int &b ); float m_fFade; diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp index e68fabf9..20f712b3 100644 --- a/cl_dll/hl/hl_events.cpp +++ b/cl_dll/hl/hl_events.cpp @@ -41,6 +41,10 @@ void EV_SnarkFire( struct event_args_s *args ); void EV_TrainPitchAdjust( struct event_args_s *args ); void EV_VehiclePitchAdjust( event_args_t *args ); + +void EV_Vorti( struct event_args_s *args ); +void EV_FireVorti( struct event_args_s *args ); +void EV_SpinVorti( struct event_args_s *args ); } /* @@ -78,4 +82,7 @@ void Game_HookEvents( void ) gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); gEngfuncs.pfnHookEvent( "events/vehicle.sc", EV_VehiclePitchAdjust ); + gEngfuncs.pfnHookEvent( "events/vorti.sc", EV_Vorti ); + gEngfuncs.pfnHookEvent( "events/vortifire.sc", EV_FireVorti ); + gEngfuncs.pfnHookEvent( "events/vortispin.sc", EV_SpinVorti ); } diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 9c0eb91c..2b673252 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -609,6 +609,7 @@ void HUD_InitClientWeapons( void ) // Allocate slot(s) for each weapon that we are going to be predicting HUD_PrepEntity( &g_Glock, &player ); HUD_PrepEntity( &g_Crowbar, &player ); + HUD_PrepEntity( &g_VortiHands, &player ); HUD_PrepEntity( &g_Python, &player ); HUD_PrepEntity( &g_Mp5, &player ); HUD_PrepEntity( &g_Crossbow, &player ); @@ -687,6 +688,9 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm case WEAPON_CROWBAR: pWeapon = &g_Crowbar; break; + case WEAPON_VORTI: + pWeapon = &g_VortiHands; + break; case WEAPON_GLOCK: pWeapon = &g_Glock; break; diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index e0d30788..0a40ffee 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -254,6 +254,24 @@ int __MsgFunc_VGUIMenu( const char *pszName, int iSize, void *pbuf ) return 0; } +int __MsgFunc_Notepad( const char *pszName, int iSize, void *pbuf ) +{ +#if USE_VGUI + if( gViewPort ) + return gViewPort->MsgFunc_Notepad( pszName, iSize, pbuf ); +#endif + return 0; +} + +int __MsgFunc_SparePlayer( const char *pszName, int iSize, void *pbuf ) +{ +#if USE_VGUI + if( gViewPort ) + return gViewPort->MsgFunc_SparePlayer( pszName, iSize, pbuf ); +#endif + return 0; +} + #if USE_VGUI && !USE_NOVGUI_MOTD int __MsgFunc_MOTD(const char *pszName, int iSize, void *pbuf) { @@ -451,6 +469,8 @@ void CHud::Init( void ) m_AmmoSecondary.Init(); m_TextMessage.Init(); m_StatusIcons.Init(); + m_ModeIcon.Init(); + m_AlienCrosshair.Init(); #if USE_VGUI GetClientVoiceMgr()->Init(&g_VoiceStatusHelper, (vgui::Panel**)&gViewPort); #endif @@ -523,6 +543,8 @@ void CHud::VidInit( void ) m_hsprLogo = 0; m_hsprCursor = 0; + m_iLensIndex = 0; + if( ScreenWidth < 640 ) m_iRes = 320; else @@ -659,6 +681,8 @@ void CHud::VidInit( void ) m_AmmoSecondary.VidInit(); m_TextMessage.VidInit(); m_StatusIcons.VidInit(); + m_ModeIcon.VidInit(); + m_AlienCrosshair.VidInit(); #if USE_VGUI GetClientVoiceMgr()->VidInit(); #endif diff --git a/cl_dll/hud.h b/cl_dll/hud.h index e210faa5..fc0cd5ab 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -581,6 +581,8 @@ private: // //----------------------------------------------------- // +#define CAM_OFF 0 +#define CAM_ON 1 class CHud { private: @@ -673,6 +675,8 @@ public: CHudAmmoSecondary m_AmmoSecondary; CHudTextMessage m_TextMessage; CHudStatusIcons m_StatusIcons; + CHudModeIcon m_ModeIcon; + CHudAlienCrosshair m_AlienCrosshair; #if !USE_VGUI || USE_NOVGUI_SCOREBOARD CHudScoreboard m_Scoreboard; #endif @@ -692,12 +696,17 @@ public: // user messages int _cdecl MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_DecayName( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_ResetHUD( const char *pszName, int iSize, void *pbuf ); void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_LensFlare( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_AimFrame( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_Camera( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_ChangePlayer( const char *pszName, int iSize, void *pbuf ); // Screen information SCREENINFO m_scrinfo; diff --git a/cl_dll/hud_msg.cpp b/cl_dll/hud_msg.cpp index f4bca3fd..0ab412f5 100644 --- a/cl_dll/hud_msg.cpp +++ b/cl_dll/hud_msg.cpp @@ -87,16 +87,75 @@ void CHud::MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) pFlare = NULL; // Vit_amiN: clear egon's beam flare } -int CHud::MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ) +void CHud::MsgFunc_Camera( const char *pszName, int iSize, void *pbuf ) { BEGIN_READ( pbuf, iSize ); - m_Teamplay = READ_BYTE(); - if( m_Teamplay ) - ClientCmd( "richpresence_gamemode Teamplay\n" ); + m_iCamMode = READ_BYTE(); + m_vecCamPos.x = READ_COORD(); + m_vecCamPos.y = READ_COORD(); + m_vecCamPos.z = READ_COORD(); + + gHUD.DrawHudString( 100, 100, ScreenWidth, "Camera message received!", 255, 180, 0 ); +} + +int CHud::MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ) +{ + gEngfuncs.pfnConsolePrint("--- MsgFunc_GameMode ---\n"); + + m_Teamplay = 0; //READ_BYTE(); + + BEGIN_READ( pbuf, iSize ); + int bMode = READ_BYTE(); + + if ( bMode == 2 ) + { + m_bAlienMode = true; + m_Health.m_iFlags |= HUD_ALIEN; + //m_TextMessage.m_iFlags |= HUD_ALIEN; + gEngfuncs.pfnConsolePrint("--- AlIEN SLAVE MODE ---\n"); + } else - ClientCmd( "richpresence_gamemode\n" ); - ClientCmd( "richpresence_update\n" ); + if ( bMode == 3 ) + { + m_bAlienMode = false; + m_Health.m_iFlags &= ~HUD_ALIEN; + //m_TextMessage.m_iFlags &= ~HUD_ALIEN; + gEngfuncs.pfnConsolePrint("--- NORMAL MODE ---\n"); + } + + return 1; +} + +int CHud::MsgFunc_DecayName( const char *spzName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + int iPlayerDecayId; + + iPlayerDecayId = READ_BYTE(); + + char name[32]; + sprintf( name, "Spare player" ); + + if ( iPlayerDecayId == 1 ) + { + if ( m_bAlienMode ) + sprintf( name, "X-8973" ); + else + sprintf( name, "Gina" ); + } + if ( iPlayerDecayId == 2 ) + { + if ( m_bAlienMode ) + sprintf( name, "R-4913" ); + else + sprintf( name, "Colette" ); + } + + char buf[256]; + sprintf(buf, "name \"%s\"\n", name); + gEngfuncs.pfnClientCmd(buf); + return 1; } diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index f47821bf..0c98996a 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -12,6 +12,11 @@ * without written permission from Valve LLC. * ****/ +/*** + * + * (C) 2008 Vyacheslav Dzhura + * + ****/ // // hud_redraw.cpp // @@ -19,7 +24,11 @@ #include "hud.h" #include "cl_util.h" -//#include "triangleapi.h" +#include "triangleapi.h" +#include "pmtrace.h" +#include "pm_defs.h" +#include "event_api.h" + #if USE_VGUI #include "vgui_TeamFortressViewport.h" @@ -27,6 +36,9 @@ #define MAX_LOGO_FRAMES 56 +extern vec3_t v_origin; +int g_iFrameSize; + int grgLogoFrame[MAX_LOGO_FRAMES] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, @@ -233,17 +245,18 @@ int CHud::Redraw( float flTime, int intermission ) while( pList ) { - if( !intermission ) + if ( !m_bAlienMode ) { - if ( ( pList->p->m_iFlags & HUD_ACTIVE ) && !( m_iHideHUDDisplay & HIDEHUD_ALL ) ) - pList->p->Draw( flTime ); - } - else - { - // it's an intermission, so only draw hud elements that are set to draw during intermissions - if( pList->p->m_iFlags & HUD_INTERMISSION ) - pList->p->Draw( flTime ); - } + if ( !intermission ) + { + if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) ) + pList->p->Draw(flTime); + } + else + { // it's an intermission, so only draw hud elements that are set to draw during intermissions + if ( pList->p->m_iFlags & HUD_INTERMISSION ) + pList->p->Draw( flTime ); + } } else { // alien mode!!! if ( pList->p->m_iFlags & HUD_ALIEN ) diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index 8e03579b..d8ba4d75 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -1536,7 +1536,7 @@ void CHudSpectator::DrawOverviewEntities() z = m_OverviewData.layersHeights[0] * zScale; // get yellow/brown HUD color - UnpackRGB( ir, ig, ib, RGB_YELLOWISH ); + UnpackRGB( ir, ig, ib, gHUD.uColor ); r = (float)ir / 255.0f; g = (float)ig / 255.0f; b = (float)ib / 255.0f; diff --git a/cl_dll/message.cpp b/cl_dll/message.cpp index a07e85d5..84675e35 100644 --- a/cl_dll/message.cpp +++ b/cl_dll/message.cpp @@ -37,6 +37,8 @@ int CHudMessage::Init( void ) HOOK_MESSAGE( HudText ); HOOK_MESSAGE( GameTitle ); + iFlags |= HUD_ALIEN; + gHUD.AddHudElem( this ); Reset(); diff --git a/cl_dll/train.cpp b/cl_dll/train.cpp index de480ec2..606a7b9d 100644 --- a/cl_dll/train.cpp +++ b/cl_dll/train.cpp @@ -53,7 +53,7 @@ int CHudTrain::Draw( float fTime ) { int r, g, b, x, y; - UnpackRGB( r, g, b, RGB_YELLOWISH ); + UnpackRGB( r, g, b, gHUD.uColor ); SPR_Set( m_hSprite, r, g, b ); // This should show up to the right and part way up the armor number diff --git a/cl_dll/vgui_TeamFortressViewport.h b/cl_dll/vgui_TeamFortressViewport.h index 15c27357..7dc228ab 100644 --- a/cl_dll/vgui_TeamFortressViewport.h +++ b/cl_dll/vgui_TeamFortressViewport.h @@ -58,6 +58,8 @@ class DragNDropPanel; class CTransparentPanel; class CClassMenuPanel; class CTeamMenuPanel; +class CNotepad; +class CSparePlayerWindow; class TeamFortressViewport; char *GetVGUITGAName( const char *pszName ); @@ -551,6 +553,8 @@ public: int CreateCommandMenu( const char * menuFile, int direction, int yOffset, bool flatDesign, float flButtonSizeX, float flButtonSizeY, int xOffset ); void CreateScoreBoard( void ); + void CreateNotepad( void ); + void CreateSparePlayerWindow( void ); CommandButton * CreateCustomButton( char *pButtonText, char * pButtonName, int iYOffset ); CCommandMenu * CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText, int iYOffset, int iXOffset = 0 ); @@ -616,6 +620,8 @@ public: int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); int MsgFunc_Spectator( const char *pszName, int iSize, void *pbuf ); int MsgFunc_AllowSpec( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Notepad( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_SparePlayer( const char *pszName, int iSize, void *pbuf ); int MsgFunc_SpecFade( const char *pszName, int iSize, void *pbuf ); int MsgFunc_ResetFade( const char *pszName, int iSize, void *pbuf ); diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index b5d3d4f3..062f830e 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -423,6 +423,26 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams ) vec3_t camAngles, camForward, camRight, camUp; cl_entity_t *pwater; + // SKY START + static struct model_t *savedviewmodel; + + //LRC - if this is the second pass through, then we've just drawn the sky, and now we're setting up the normal view. + if( pparams->nextView == 1 ) + { + GrabCameraTexture(); + view = gEngfuncs.GetViewModel(); + view->model = savedviewmodel; + pparams->viewangles[0] = v_angles.x; + pparams->viewangles[1] = v_angles.y; + pparams->viewangles[2] = v_angles.z; + pparams->vieworg[0] = v_origin.x; + pparams->vieworg[1] = v_origin.y; + pparams->vieworg[2] = v_origin.z; + pparams->nextView = 0; + return; + } + // SKY END + if( gEngfuncs.IsSpectateOnly() ) { ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); @@ -1347,21 +1367,23 @@ int V_FindViewModelByWeaponModel( int weaponindex ) { static const char *modelmap[][2] = { - { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, - { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, - { "models/p_egon.mdl", "models/v_egon.mdl" }, - { "models/p_gauss.mdl", "models/v_gauss.mdl" }, - { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, - { "models/p_grenade.mdl", "models/v_grenade.mdl" }, - { "models/p_hgun.mdl", "models/v_hgun.mdl" }, - { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, - { "models/p_357.mdl", "models/v_357.mdl" }, - { "models/p_rpg.mdl", "models/v_rpg.mdl" }, - { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, - { "models/p_squeak.mdl", "models/v_squeak.mdl" }, - { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, - { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl" }, - { "models/p_satchel.mdl", "models/v_satchel.mdl" }, + { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, + { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, + { "models/p_egon.mdl", "models/v_egon.mdl" }, + { "models/p_gauss.mdl", "models/v_gauss.mdl" }, + { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, + { "models/p_grenade.mdl", "models/v_grenade.mdl" }, + { "models/p_hgun.mdl", "models/v_hgun.mdl" }, + { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, + { "models/p_357.mdl", "models/v_357.mdl" }, + { "models/p_rpg.mdl", "models/v_rpg.mdl" }, + { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, + { "models/p_squeak.mdl", "models/v_squeak.mdl" }, + { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, + { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl" }, + { "models/p_satchel.mdl", "models/v_satchel.mdl" }, + { "models/p_displacer.mdl", "models/v_displacer.mdl" }, + { "models/p_slave.mdl", "models/v_slave.mdl" }, { NULL, NULL } }; diff --git a/dlls/barney.cpp b/dlls/barney.cpp index 2795a544..0efc0b42 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -377,12 +377,12 @@ void CBarney::HandleAnimEvent( MonsterEvent_t *pEvent ) break; case BARNEY_AE_DRAW: // barney's bodygroup switches here so he can pull gun from holster - pev->body = BARNEY_BODY_GUNDRAWN; + SetBodygroup( GUN_GROUP, BARNEY_BODY_GUNDRAWN ); m_fGunDrawn = TRUE; break; case BARNEY_AE_HOLSTER: // change bodygroup to replace gun in holster - pev->body = BARNEY_BODY_GUNHOLSTERED; + SetBodygroup( GUN_GROUP, BARNEY_BODY_GUNHOLSTERED ); m_fGunDrawn = FALSE; break; default: @@ -609,13 +609,13 @@ void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir void CBarney::Killed( entvars_t *pevAttacker, int iGib ) { - if( pev->body < BARNEY_BODY_GUNGONE ) + if( GetBodygroup( GUN_GROUP ) < BARNEY_BODY_GUNGONE ) { // drop the gun! Vector vecGunPos; Vector vecGunAngles; - pev->body = BARNEY_BODY_GUNGONE; + SetBodygroup( GUN_GROUP, BARNEY_BODY_GUNGONE ); GetAttachment( 0, vecGunPos, vecGunAngles ); diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index afeaa534..a034a805 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -186,7 +186,10 @@ void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE } // CONSIDER: a Use input to the multisource always toggles. Could check useType for ON/OFF/TOGGLE - m_rgTriggered[i - 1] ^= 1; + if( !FBitSet( pev->spawnflags, SF_MULTI_NO_TOGGLE )) + m_rgTriggered[i - 1] ^= 1; + else + m_rgTriggered[i-1] = 1; // if( IsTriggered( pActivator ) ) @@ -1166,6 +1169,13 @@ void CMomentaryRotButton::Off( void ) { pev->avelocity = g_vecZero; m_lastUsed = 0; + if ( ( pev->angles == m_end ) && (!FStringNull( m_iszEndLockTarget )) ) + { + FireTargets(STRING( m_iszEndLockTarget ), this, this, USE_TOGGLE, 0); + SetThink( NULL ); + return; + } + if( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) && m_returnSpeed > 0 ) { SetThink( &CMomentaryRotButton::Return ); diff --git a/dlls/client.cpp b/dlls/client.cpp index 551fc111..c3afdb3c 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -39,6 +39,18 @@ #include "usercmd.h" #include "netadr.h" #include "pm_shared.h" +// START BOT +#include "bot.h" + +void BotCreate(const char *skin, const char *name, const char skill); +extern int f_Observer; // flag for observer mode +extern int f_botskill; // default bot skill level +extern int f_botdontshoot; // flag to disable targeting other ots +extern respawn_t bot_respawn[32]; +float bot_check_time = 10.0; +int min_bots = 0; +int max_bots = 0; +// END BOT extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; extern DLL_GLOBAL BOOL g_fGameOver; @@ -64,7 +76,9 @@ void LinkUserMessages( void ); */ void set_suicide_frame( entvars_t *pev ) { - if( !FStrEq( STRING( pev->model ), "models/player.mdl" ) ) + if( !FStrEq( STRING( pev->model ), "models/player.mdl" ) + || !FStrEq( STRING( pev->model ), "models/player/dm_slave/dm_slave.mdl" ) + || !FStrEq( STRING( pev->model ), "models/ginacol.mdl" )) return; // allready gibbed //pev->frame = $deatha11; @@ -528,6 +542,66 @@ void ClientCommand( edict_t *pEntity ) { Host_Say( pEntity, 0 ); } + else if ( FStrEq(pcmd, "changeplayer" ) ) // do Decay's player change (e.g. controllable-bot and vise-versa) + { + if (g_pGameRules->IsCoOp()) + { + CDecayRules *g_pDecayRules; + g_pDecayRules = (CDecayRules*)g_pGameRules; + g_pDecayRules->ChangePlayer(); + } + } + else if ( FStrEq(pcmd, "changeplayer2" ) ) // change player_index of active player to test Decay in SP mode + { + if (g_pGameRules->IsCoOp()) + { + CDecayRules *g_pDecayRules; + g_pDecayRules = (CDecayRules*)g_pGameRules; + if (g_pDecayRules->pPlayers[0]->m_iDecayId == 1) + { + g_pDecayRules->pPlayers[0]->m_iDecayId = 2; + // if ( !FNullEnt( g_pDecayRules->pPlayers[1]->pev )) + // g_pDecayRules->pPlayers[1]->m_iDecayId = 1; + } + else + { + g_pDecayRules->pPlayers[0]->m_iDecayId = 1; + // if ( !FNullEnt( g_pDecayRules->pPlayers[1]->pev )) + // g_pDecayRules->pPlayers[1]->m_iDecayId = 2; + } + ALERT( at_console, "Player 1 index changed to %d\n", g_pDecayRules->pPlayers[0]->m_iDecayId ); + //if ( !FNullEnt( g_pDecayRules->pPlayers[1]->pev )) + // ALERT( at_console, "Player 2 index changed to %d\n", g_pDecayRules->pPlayers[1]->m_iDecayId ); + } + } + else if ( FStrEq( pcmd, "euukraine" ) ) + { + if ( g_pGameRules->IsCoOp() ) + { + bool bUnlockAlien = strcmp( CMD_ARGV(1), "visafree" ) == 0; + + CDecayRules *g_pDecayRules; + g_pDecayRules = (CDecayRules*)g_pGameRules; + g_pDecayRules->unlockMissions( bUnlockAlien ); + g_pDecayRules->statsSave(); + } + } + else if ( FStrEq( pcmd, "test1" ) ) + { + MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); + MESSAGE_END(); + } + else if ( FStrEq(pcmd, "stripall" ) ) + { + if (g_pGameRules->IsCoOp()) + { + CDecayRules *g_pDecayRules; + g_pDecayRules = (CDecayRules*)g_pGameRules; + g_pDecayRules->pPlayers[0]->PackAllItems(); + if ( !FNullEnt(g_pDecayRules->pPlayers[1]->pev) ) + g_pDecayRules->pPlayers[1]->PackAllItems(); + } + } else if( FStrEq( pcmd, "say_team" ) ) { Host_Say( pEntity, 1 ); @@ -603,6 +677,81 @@ void ClientCommand( edict_t *pEntity ) { GetClassPtr( (CBasePlayer *)pev )->SelectLastItem(); } +// *************************** + // START BOT + else if (FStrEq(pcmd, "addbot" )) + { + if (!IS_DEDICATED_SERVER()) + { + //If user types "addbot" in console, add a bot with skin and name + if (!bSlaveCoop) + BotCreate("ginacol", "Colette", 0); // CMD_ARGV(1), CMD_ARGV(2), CMD_ARGV(3) + else + BotCreate("player/dm_slave/dm_slave", "R-4913", 0); + } + else + CLIENT_PRINTF( pEntity, print_console, "addbot not allowed from client!\n" ); + } + else if (FStrEq(pcmd, "debugbot" )) + { + if (!bSlaveCoop) + BotCreate("ginacol", "Colette", 0); // CMD_ARGV(1), CMD_ARGV(2), CMD_ARGV(3) + else + BotCreate("player/dm_slave/dm_slave", "R-4913", 0); + } + /* + else if ( FStrEq(pcmd, "observer" ) ) + { + if (!IS_DEDICATED_SERVER()) + { + if (CMD_ARGC() > 1) // is there an argument to the command? + { + f_Observer = atoi( CMD_ARGV(1) ); // set observer flag + CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs("\"observer\" set to %d\n", (int)f_Observer) ); + } + else + { + CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs("\"observer\" is %d\n", (int)f_Observer) ); + } + } + else + CLIENT_PRINTF( pEntity, print_console, "observer not allowed from client!\n" ); + }*/ + else if ( FStrEq(pcmd, "botskill" ) ) + { + if (!IS_DEDICATED_SERVER()) + { + if (CMD_ARGC() > 1) + { + f_botskill = atoi( CMD_ARGV(1) ); // set default bot skill level + CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs("\"botskill\" set to %d\n", (int)f_botskill) ); + } + else + { + CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs("\"botskill\" is %d\n", (int)f_botskill) ); + } + } + else + CLIENT_PRINTF( pEntity, print_console, "botskill not allowed from client!\n" ); + } + else if ( FStrEq(pcmd, "botdontshoot" ) ) + { + if (!IS_DEDICATED_SERVER()) + { + if (CMD_ARGC() > 1) // is there an argument to the command? + { + f_botdontshoot = atoi( CMD_ARGV(1) ); // set bot shoot flag + CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs("\"botdontshoot\" set to %d\n", (int)f_botdontshoot) ); + } + else + { + CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs("\"botdontshoot\" is %d\n", (int)f_botdontshoot) ); + } + } + else + CLIENT_PRINTF( pEntity, print_console, "botdontshoot not allowed from client!\n" ); + } +// *************************** else if( FStrEq( pcmd, "spectate" ) ) // clients wants to become a spectator { CBasePlayer *pPlayer = GetClassPtr( (CBasePlayer *)pev ); @@ -852,15 +1001,420 @@ void ParmsChangeLevel( void ) void StartFrame( void ) { //ALERT( at_console, "SV_Physics( %g, frametime %g )\n", gpGlobals->time, gpGlobals->frametime ); + // START BOT + static BOOL file_opened = FALSE; + static int length; + static char *pFileList, *aFileList; + static char cmd_line[80]; + static char server_cmd[80]; + static int index, i; + static float pause_time; + static float check_server_cmd = 0; + char *cmd, *arg1, *arg2, *arg3; + static float respawn_time = 0; + static float previous_time = 0.0; + char msg[120]; + // END BOT - if( g_pGameRules ) + // START BOT - thanks Jehannum! + + // loop through all the players... + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayer; + + pPlayer = UTIL_PlayerByIndex( i ); + + if (!pPlayer) // if invalid then continue with next index... + continue; + + // check if this is a FAKECLIENT (i.e. is it a bot?) + if (FBitSet(pPlayer->pev->flags, FL_FAKECLIENT)) + { + CBot *pBot = (CBot *)pPlayer; + + // call the think function for the bot... + pBot->BotThink(); + } + } + // END BOT + + // START BOT + /* + if ((g_fGameOver) && (respawn_time < 1.0)) + { + // if the game is over (time/frag limit) set the respawn time... + respawn_time = 5.0; + + // check if any players are using the botcam... + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pPlayer; + + pPlayer = (CBasePlayer *)UTIL_PlayerByIndex( i ); + + if (!pPlayer) + continue; // if invalid then continue with next index... + + if (pPlayer->pBotCam) + pPlayer->pBotCam->Disconnect(); + } + }*/ + + // check if a map was changed via "map" without kicking bots... + if (previous_time > gpGlobals->time) + { + bot_check_time = gpGlobals->time + 10.0; + + for (index = 0; index < 32; index++) + { + if ((bot_respawn[index].is_used) && // is this slot used? + (bot_respawn[index].state != BOT_NEED_TO_RESPAWN)) + { + // bot has already been "kicked" by server so just set flag + bot_respawn[index].state = BOT_NEED_TO_RESPAWN; + + // if the map was changed set the respawn time... + respawn_time = 5.0; + } + } + } + + // is new game started and time to respawn bots yet? + if ((!g_fGameOver) && (respawn_time > 1.0) && + (gpGlobals->time >= respawn_time)) + { + int index = 0; + + bot_check_time = gpGlobals->time + 5.0; + + // find bot needing to be respawned... + while ((index < 32) && + (bot_respawn[index].state != BOT_NEED_TO_RESPAWN)) + index++; + + if (index < 32) + { + bot_respawn[index].state = BOT_IS_RESPAWNING; + bot_respawn[index].is_used = FALSE; // free up this slot + + // respawn 1 bot then wait a while (otherwise engine crashes) + BotCreate(bot_respawn[index].skin, + bot_respawn[index].name, + bot_respawn[index].skill); + + respawn_time = gpGlobals->time + 1.0; // set next respawn time + } + else + { + respawn_time = 0.0; + } + } + // END BOT + + if ( g_pGameRules ) + { g_pGameRules->Think(); + //if (!botadded) + //{ + // botadded = TRUE; + // BotCreate("ginacol", "Colette", "1"); + //} + +/* + // START BOT + if (!file_opened) // have we open bot.cfg file yet? + { + ALERT( at_console, "Executing bot.cfg\n" ); + pFileList = (char *)LOAD_FILE_FOR_ME( "bot.cfg", &length); + file_opened = TRUE; + if (pFileList == NULL) + ALERT( at_console, "bot.cfg file not found\n" ); + + pause_time = gpGlobals->time; + + index = 0; + cmd_line[index] = 0; // null out command line + } + + // if the bot.cfg file is still open and time to execute command... + while ((pFileList && *pFileList) && (pause_time <= gpGlobals->time)) + { + while (*pFileList == ' ') // skip any leading blanks + pFileList++; + + while ((*pFileList != '\r') && (*pFileList != '\n') && + (*pFileList != 0)) + { + if (*pFileList == '\t') // convert tabs to spaces + *pFileList = ' '; + + cmd_line[index] = *pFileList; + pFileList++; + + while ((cmd_line[index] == ' ') && (*pFileList == ' ')) + pFileList++; // skip multiple spaces + + index++; + } + + if (*pFileList == '\r') + { + pFileList++; // skip the carriage return + pFileList++; // skip the linefeed + } + else if (*pFileList == '\n') + { + pFileList++; // skip the newline + } + + cmd_line[index] = 0; // terminate the command line + + // copy the command line to a server command buffer... + strcpy(server_cmd, cmd_line); + strcat(server_cmd, "\n"); + + index = 0; + cmd = cmd_line; + arg1 = arg2 = arg3 = NULL; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg1 = &cmd_line[index]; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg2 = &cmd_line[index]; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg3 = &cmd_line[index]; + } + } + } + + index = 0; // reset for next input line + + if ((cmd_line[0] == '#') || (cmd_line[0] == 0)) + { + continue; // ignore comments or blank lines + } + else if (strcmp(cmd, "addbot") == 0) + { + BotCreate( arg1, arg2, arg3 ); + + // have to delay here or engine gives "Tried to write to + // uninitialized sizebuf_t" error and crashes... + + pause_time = gpGlobals->time + 1; + + break; + } + else if (strcmp(cmd, "botskill") == 0) + { + f_botskill = atoi( arg1 ); // set default bot skill level + } + else if (strcmp(cmd, "observer") == 0) + { + f_Observer = atoi( arg1 ); // set observer flag + } + else if (strcmp(cmd, "botdontshoot") == 0) + { + f_botdontshoot = atoi( arg1 ); // set bot shoot flag + } + else if (strcmp(cmd, "min_bots") == 0) + { + min_bots = atoi( arg1 ); + + if (min_bots < 0) + min_bots = 0; + + if (IS_DEDICATED_SERVER()) + { + sprintf(msg, "min_bots set to %d\n", min_bots); + printf(msg); + } + } + else if (strcmp(cmd, "max_bots") == 0) + { + max_bots = atoi( arg1 ); + + if (max_bots >= gpGlobals->maxClients) + max_bots = gpGlobals->maxClients - 1; + + if (IS_DEDICATED_SERVER()) + { + sprintf(msg, "max_bots set to %d\n", max_bots); + printf(msg); + } + } + else if (strcmp(cmd, "pause") == 0) + { + pause_time = gpGlobals->time + atoi( arg1 ); + break; + } + else + { + sprintf(msg, "executing server command: %s\n", server_cmd); + ALERT( at_console, msg ); + + if (IS_DEDICATED_SERVER()) + printf(msg); + + SERVER_COMMAND(server_cmd); + } + } + + // if bot.cfg file is open and reached end of file, then close and free it + if (pFileList && (*pFileList == 0)) + { + FREE_FILE(aFileList); + pFileList = NULL; + } + */ + // if time to check for server commands then do so... + if (check_server_cmd <= gpGlobals->time) + { + check_server_cmd = gpGlobals->time + 1.0; + + char *cvar_bot = (char *)CVAR_GET_STRING( "bot" ); + + if ( cvar_bot && cvar_bot[0] ) + { + strcpy(cmd_line, cvar_bot); + + index = 0; + cmd = cmd_line; + arg1 = arg2 = arg3 = NULL; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg1 = &cmd_line[index]; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg2 = &cmd_line[index]; + + // skip to blank or end of string... + while ((cmd_line[index] != ' ') && (cmd_line[index] != 0)) + index++; + + if (cmd_line[index] == ' ') + { + cmd_line[index++] = 0; + arg3 = &cmd_line[index]; + } + } + } + + if (strcmp(cmd, "addbot") == 0) + { + printf("adding new bot...\n"); + + BotCreate( arg1, arg2, arg3 ); + } + else if (strcmp(cmd, "botskill") == 0) + { + if (arg1 != NULL) + { + printf("setting botskill to %d\n", atoi( arg1 )); + + f_botskill = atoi( arg1 ); // set default bot skill level + } + else + printf("botskill is %d\n", f_botskill); + } + else if (strcmp(cmd, "botdontshoot") == 0) + { + if (arg1 != NULL) + { + printf("setting botdontshoot to %d\n", atoi( arg1 )); + + f_botdontshoot = atoi( arg1 ); // set bot shoot flag + } + else + printf("botdontshoot is %d\n", f_botdontshoot); + } + + CVAR_SET_STRING("bot", ""); + } + } + // END BOT + } + if( g_fGameOver ) + { return; + // START BOT + check_server_cmd = 0; + // END BOT + } + + g_iSkillLevel = CVAR_GET_FLOAT("skill"); gpGlobals->teamplay = teamplay.value; g_ulFrameCount++; + + // START BOT + + // check if time to see if a bot needs to be created... + if (bot_check_time < gpGlobals->time) + { + int count = 0; + + bot_check_time = gpGlobals->time + 5.0; + + for ( i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *pPlayer; + + pPlayer = UTIL_PlayerByIndex( i ); + + if (!pPlayer) + continue; // if invalid then continue with next index... + + if (pPlayer->pev->takedamage == DAMAGE_NO) + continue; // if bot was kicked, don't count as a player... + + count++; // count the number of bots and players + } + + // if there are currently less than the maximum number of "players" + // then add another bot using the default skill level... + if (count < max_bots) + { + BotCreate( NULL, NULL, NULL ); + } + } + + previous_time = gpGlobals->time; // keep track of last time in StartFrame() + // END BOT } void ClientPrecache( void ) @@ -957,6 +1511,7 @@ void ClientPrecache( void ) PRECACHE_SOUND( "player/pl_pain7.wav" ); PRECACHE_MODEL( "models/player.mdl" ); + PRECACHE_MODEL("models/player/dm_slave/dm_slave.mdl"); // hud sounds PRECACHE_SOUND( "common/wpn_hudoff.wav" ); @@ -973,6 +1528,49 @@ void ClientPrecache( void ) PRECACHE_SOUND( "player/geiger2.wav" ); PRECACHE_SOUND( "player/geiger1.wav" ); + if (!IS_DEDICATED_SERVER()) + { + // + // Decay bot sounds + // + + PRECACHE_SOUND( GI_SND1 ); + PRECACHE_SOUND( GI_SND2 ); + PRECACHE_SOUND( GI_SND3 ); + PRECACHE_SOUND( GI_SND4 ); + PRECACHE_SOUND( GI_SND5 ); + + PRECACHE_SOUND( CO_SND1 ); + PRECACHE_SOUND( CO_SND2 ); + PRECACHE_SOUND( CO_SND3 ); + PRECACHE_SOUND( CO_SND4 ); + PRECACHE_SOUND( CO_SND5 ); + + // + // joy after successful enemy kill + // + + PRECACHE_SOUND( CO_TNT1 ); + PRECACHE_SOUND( CO_TNT2 ); + PRECACHE_SOUND( CO_TNT3 ); + PRECACHE_SOUND( CO_TNT4 ); + PRECACHE_SOUND( CO_TNT5 ); + + PRECACHE_SOUND( GI_TNT1 ); + PRECACHE_SOUND( GI_TNT2 ); + PRECACHE_SOUND( GI_TNT3 ); + PRECACHE_SOUND( GI_TNT4 ); + PRECACHE_SOUND( GI_TNT5 ); + + PRECACHE_SOUND( USE_TEAMPLAY_SND ); + PRECACHE_SOUND( USE_TEAMPLAY_LATER_SND ); + PRECACHE_SOUND( USE_TEAMPLAY_ENEMY_SND ); + + // + // end of Decay bot sounds + // + } + if( giPrecacheGrunt ) UTIL_PrecacheOther( "monster_human_grunt" ); } diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 609ab858..230f14c1 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -30,6 +30,7 @@ #include "weapons.h" #include "func_break.h" #include "game.h" +#include "gamerules.h" extern DLL_GLOBAL Vector g_vecAttackDir; extern DLL_GLOBAL int g_iSkillLevel; @@ -551,7 +552,10 @@ void CBaseMonster::CallGibMonster( void ) } if( ShouldFadeOnDeath() && !fade ) + { UTIL_Remove( this ); + // DECAY BOTAI FIX TODO: object gets removed here when killed with "blast" power + } } /* @@ -1480,6 +1484,12 @@ Vector CBaseEntity::FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDi ClearMultiDamage(); gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB; + // + // DECAY STATS!!! MISSES AND HITS GO THROUGH HERE + // + int ishotId = RANDOM_LONG(1, 1000); + g_pGameRules->BulletsFired( pevAttacker, cShots, iBulletType, ishotId ); + for( ULONG iShot = 1; iShot <= cShots; iShot++ ) { //Use player's random seed. @@ -1501,6 +1511,8 @@ Vector CBaseEntity::FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDi { CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + g_pGameRules->BulletHit( pEntity, pevAttacker, ishotId ); + if( iDamage ) { pEntity->TraceAttack( pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ( ( iDamage > 16 ) ? DMG_ALWAYSGIB : DMG_NEVERGIB ) ); diff --git a/dlls/controller.cpp b/dlls/controller.cpp index bfe3032e..2adf2005 100644 --- a/dlls/controller.cpp +++ b/dlls/controller.cpp @@ -544,43 +544,6 @@ void CController::StartTask( Task_t *pTask ) } } -Vector Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ) -{ - Vector vecTo = vecDst - vecSrc; - - float a = DotProduct( vecMove, vecMove ) - flSpeed * flSpeed; - float b = 0 * DotProduct( vecTo, vecMove ); // why does this work? - float c = DotProduct( vecTo, vecTo ); - float t; - - if( a == 0 ) - { - t = c / ( flSpeed * flSpeed ); - } - else - { - t = b * b - 4.0f * a * c; - t = sqrt( t ) / ( 2.0f * a ); - float t1 = -b +t; - float t2 = -b -t; - - if( t1 < 0 || t2 < t1 ) - t = t2; - else - t = t1; - } - - // ALERT( at_console, "Intersect %f\n", t ); - - if( t < 0.1f ) - t = 0.1f; - if( t > 10.0f ) - t = 10.0f; - - Vector vecHit = vecTo + vecMove * t; - return vecHit.Normalize() * flSpeed; -} - int CController::LookupFloat() { if( m_velocity.Length() < 32.0f ) @@ -642,7 +605,7 @@ void CController::RunTask( Task_t *pTask ) { m_vecEstVelocity = m_vecEstVelocity * 0.8f; } - vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( pev->origin ), m_vecEstVelocity, gSkillData.controllerSpeedBall ); + vecDir = UTIL_Intersect( vecSrc, m_hEnemy->BodyTarget( pev->origin ), m_vecEstVelocity, gSkillData.controllerSpeedBall ); float delta = 0.03490f; // +-2 degree vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.controllerSpeedBall; @@ -728,7 +691,7 @@ Schedule_t *CController::GetSchedule( void ) { case MONSTERSTATE_COMBAT: { - // Vector vecTmp = Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0f ); + // Vector vecTmp = UTIL_Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0f ); // dead enemy if( HasConditions( bits_COND_LIGHT_DAMAGE ) ) diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 5342e7c2..56f3cd22 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -109,50 +109,6 @@ void CCrowbar::Holster( int skiplocal /* = 0 */ ) SendWeaponAnim( CROWBAR_HOLSTER ); } -void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity ) -{ - int i, j, k; - float distance; - float *minmaxs[2] = {mins, maxs}; - TraceResult tmpTrace; - Vector vecHullEnd = tr.vecEndPos; - Vector vecEnd; - - distance = 1e6f; - - vecHullEnd = vecSrc + ( ( vecHullEnd - vecSrc ) * 2.0f ); - UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if( tmpTrace.flFraction < 1.0f ) - { - tr = tmpTrace; - return; - } - - for( i = 0; i < 2; i++ ) - { - for( j = 0; j < 2; j++ ) - { - for( k = 0; k < 2; k++ ) - { - vecEnd.x = vecHullEnd.x + minmaxs[i][0]; - vecEnd.y = vecHullEnd.y + minmaxs[j][1]; - vecEnd.z = vecHullEnd.z + minmaxs[k][2]; - - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if( tmpTrace.flFraction < 1.0f ) - { - float thisDistance = ( tmpTrace.vecEndPos - vecSrc ).Length(); - if( thisDistance < distance ) - { - tr = tmpTrace; - distance = thisDistance; - } - } - } - } - } -} - void CCrowbar::PrimaryAttack() { if( !Swing( 1 ) ) diff --git a/dlls/doors.cpp b/dlls/doors.cpp index 1f5b4b06..62c0ad8f 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -268,6 +268,7 @@ LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ) // func_water - same as a door. // LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ) +LINK_ENTITY_TO_CLASS( func_lasermirror, CBaseDoor ) void CBaseDoor::Spawn() { @@ -551,8 +552,21 @@ void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use { m_hActivator = pActivator; // if not ready to be used, ignore "use" command. + + // Decay's changes - door should correctly receive USE_TYPE from trigger_relay + // close - godown + // open - goup + if( m_toggle_state == TS_AT_BOTTOM || ( FBitSet( pev->spawnflags, SF_DOOR_NO_AUTO_RETURN ) && m_toggle_state == TS_AT_TOP ) ) - DoorActivate(); + { + if ( (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN)) && useType != USE_TOGGLE ) + { + if ( (( useType == USE_OFF ) && (m_toggle_state == TS_AT_TOP)) || (( useType == USE_ON ) && (m_toggle_state == TS_AT_BOTTOM)) ) + DoorActivate(); + } + else + DoorActivate(); + } } // @@ -670,8 +684,10 @@ void CBaseDoor::DoorHitTop( void ) } } + // Vyacheslav Dzhura TODO: think about logic here // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target if( pev->netname && ( pev->spawnflags & SF_DOOR_START_OPEN ) ) + //if ( pev->netname && m_toggle_state = TS_AT_BOTTOM ) FireTargets( STRING( pev->netname ), m_hActivator, this, USE_TOGGLE, 0 ); SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 7019aaa5..76f0def4 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -23,14 +23,171 @@ #include "decals.h" #include "func_break.h" #include "shake.h" +#include "animation.h" +#include "gamerules.h" +//#include "monstermaker.h" #define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired #define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them. +#define SF_MIRROR_FINAL 0x0001 // final part of the lasermirror chain +#define SF_MIRROR_FIREONCE 0x0002 // if global state is on, then fire our target only once + +extern int gmsgLensFlare; + // Lightning target, just alias landmark LINK_ENTITY_TO_CLASS( info_target, CPointEntity ) +//============================================================================== +// Decay's displacer's teleport target entity +//============================================================================== + +LINK_ENTITY_TO_CLASS( info_displacer_xen_target, CDisplacerTarget ); + +void CDisplacerTarget::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "player_index")) + { + m_iPlayerIndex = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +//============================================================================== +// Decay's spawnflags setter helper entity +//============================================================================== + +class CFlagHelper : public CPointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; +LINK_ENTITY_TO_CLASS( info_flaghelper, CFlagHelper ); + +void CFlagHelper::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( FStringNull( pev->target ) ) + return; + + CBaseEntity *pEnt = NULL; + pEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) ); + if ( pEnt ) + pEnt->pev->spawnflags = this->pev->spawnflags; +} + +//============================================================================== +// Decay's cheat helper entity +//============================================================================== + +class CCheatHelper : public CPointEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData *pkvd ); + void CheckCode(); + + // consists of "udlr stcx" (up down left right square triangle circle (x)cross ) + string_t m_sCheat1, target1; + string_t m_sCheat2, target2; + char m_sListener[16]; +}; +LINK_ENTITY_TO_CLASS( info_cheathelper, CCheatHelper ); + +void CCheatHelper::CheckCode() +{ + int i = 0; + while ( ( i < 16 ) && ( m_sListener[i] == 0 ) ) + i++; + + if ( i == 16 ) + return; + + char m_sCurrentCheat[16]; + memset( &m_sCurrentCheat, 0, sizeof(m_sCurrentCheat) ); + memmove( m_sCurrentCheat, m_sListener+i, 16-i ); + ALERT( at_console, "Current code: '%s'\n", m_sCurrentCheat ); + + char m_sCurrentCompareCheat[16]; + + + //memset( &m_sCurrentCompareCheat, 0, sizeof(m_sCurrentCompareCheat) ); + //strncpy( m_sCurrentCompareCheat, m_sCurrentCheat, strlen( STRING( m_sCheat1 ) ) ); + + if ( strstr( m_sCurrentCheat, STRING( m_sCheat1 ) ) ) + // if ( strcmp( m_sCurrentCompareCheat, STRING( m_sCheat1 ) ) == 0 ) + { + // cheat_bonus entered + if ( !FStringNull( target1 ) ) + FireTargets( STRING( target1 ), this, this, USE_TOGGLE, 0.0 ); + memset( &m_sListener, 0, sizeof(m_sListener) ); + } + + //memset( &m_sCurrentCompareCheat, 0, sizeof(m_sCurrentCompareCheat) ); + //strncpy( m_sCurrentCompareCheat, m_sCurrentCheat, strlen( STRING( m_sCheat2 ) ) ); + if ( strstr( m_sCurrentCheat, STRING( m_sCheat2 ) ) ) + //if ( strcmp( m_sCurrentCompareCheat, STRING( m_sCheat2 ) ) == 0 ) + { + // cheat_alien entered + CDecayRules *g_pDecayRules; + g_pDecayRules = (CDecayRules*)g_pGameRules; + g_pDecayRules->unlockMissions( true ); + g_pDecayRules->statsSave(); + + if ( !FStringNull( target1 ) ) + FireTargets( STRING( target2 ), this, this, USE_TOGGLE, 0.0 ); + memset( &m_sListener, 0, sizeof(m_sListener) ); + } +} + +void CCheatHelper::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( FStringNull( pCaller->pev->targetname ) ) + return; + + static char sCallersCheat[32]; + + sprintf( sCallersCheat, "%s", STRING( pCaller->pev->targetname )); + + // move all starting from 2 char to 1 char + memmove (m_sListener+1, m_sListener+2, 15); + m_sListener[15] = sCallersCheat[0]; + + CheckCode(); +} + +void CCheatHelper::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "cheat_bonus")) + { + m_sCheat1 = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } else + if (FStrEq(pkvd->szKeyName, "cheat_alien")) + { + m_sCheat2 = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } else + if (FStrEq(pkvd->szKeyName, "target1")) + { + target1 = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } else + if (FStrEq(pkvd->szKeyName, "target2")) + { + target2 = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + CPointEntity::KeyValue( pkvd ); +} + +//============================================================================== +// Bubbling entity +//============================================================================== + class CBubbling : public CBaseEntity { public: @@ -3306,4 +3463,4 @@ void CEnvLaserMirror::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY // char szMes[256]; // sprintf(szMes,"Server: ",pev->origin.x,pev->origin.y,pev->origin.z, entindex()); // ALERT( at_console, szMes ); -} \ No newline at end of file +} diff --git a/dlls/effects.h b/dlls/effects.h index 60e13952..3d06eab5 100644 --- a/dlls/effects.h +++ b/dlls/effects.h @@ -325,4 +325,105 @@ public: string_t m_iszSpriteName; Vector m_firePosition; }; + +class CFuncFrame : public CBaseEntity +{ +public: + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + + int m_iKind; +}; + +#define SF_AUTO_FIREONCE 0x0001 + +class CEnvWarpBall : public CBaseEntity +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Precache( void ); + void Spawn( void ) { Precache(); } + void Think( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + static CEnvWarpBall *WarpBallCreate(); + + //string_t m_iszMonsterClassname; // classname of the monster(s) that will be created. + string_t m_iszWarpTarget; +}; + +class CDisplacerTarget : public CPointEntity +{ +public: + void KeyValue( KeyValueData *pkvd ); + + int m_iPlayerIndex; +}; + +class CObjModel : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd); + + int m_iSkin, m_iScale, m_iBody, m_iBodyGroup, m_iSequence; + + float SetBoneController(int iController, float flValue ); + void ObjModelInit( const char *pModelName, int skin, int scale, int body, int bodygroup ); + static CObjModel *ObjModelCreate( const char *pModelName, int skin, int scale, int body, int bodygroup ); +}; + +class CEnvLaserMirror : public CBaseEntity +{ +public: + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DIRECTIONAL_USE; } + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Precache( void ); + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + void CheckTargets(bool DoActivate); + + int m_iszTargetUnlocked; + int m_iszTargetLocked; + bool bStateOn; + string_t m_globalstate; + int m_iUseStateMode; + int m_iSearchDistance; + byte bUsedCount; + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; +}; + +class CEnvMirroredLaser : public CBaseEntity +{ +public: + CBeam *pBeam[15]; // 15 reflections max + CEnvLaserMirror *pMirrors[15]; + int iBeamCount; + int iMirrorCount; + bool bActive; + + //Vector m_vecDir; + Vector m_vecEnd; + int iMaxStep; + int m_iSearchDistance; + int m_iPrimarySearchDistance; + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + //void Activate( void ); + void Spawn( void ); + void RebuildPath( void ); + void EXPORT ThinkOn( void ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void ReColorLasers( void ); +}; + + #endif //EFFECTS_H diff --git a/dlls/game.cpp b/dlls/game.cpp index a8011a37..a2cb70a7 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -44,7 +44,7 @@ cvar_t decalfrequency = { "decalfrequency","30", FCVAR_SERVER }; cvar_t teamlist = { "mp_teamlist","hgrunt;scientist", FCVAR_SERVER }; cvar_t teamoverride = { "mp_teamoverride","1" }; cvar_t defaultteam = { "mp_defaultteam","0" }; -cvar_t allowmonsters = { "mp_allowmonsters","0", FCVAR_SERVER }; +cvar_t allowmonsters = { "mp_allowmonsters","1", FCVAR_SERVER }; cvar_t bhopcap = { "mp_bhopcap", "1", FCVAR_SERVER }; cvar_t allow_spectators = { "allow_spectators", "0", FCVAR_SERVER }; // 0 prevents players from being spectators diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index eedf56f6..fc83860b 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -317,6 +317,14 @@ CGameRules *InstallGameRules( void ) { SERVER_COMMAND( "exec game.cfg\n" ); SERVER_EXECUTE(); + ALERT( at_console, "Installing game rule... "); +// ALERT( at_console, "Priest damaged - took %f hit points!\n", flDamage); + + if (bDecay) + { + // Decay game rules + return new CDecayRules; + } if( !gpGlobals->deathmatch ) { diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 8c01f34e..caf6b091 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -163,6 +163,13 @@ public: // Immediately end a multiplayer game virtual void EndMultiplayerGame( void ) {} virtual BOOL IsBustingGame( void ){ return FALSE; }; + + // Decay stats + virtual void MonsterKilled( entvars_t *pKiller, entvars_t *pVictim ) = 0; + virtual void PlayerDamaged( CBasePlayer *pPlayer, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) = 0; + virtual void BulletsFired( entvars_t *pevAttacker, ULONG cShots, int iBulletType, int iShotId ) {}; + virtual void BulletHit( CBaseEntity *pEntity, entvars_t *pevAttacker, int iShotId ) {}; + virtual void savePlayerStats( int playerId, int finalGrade, int damageGrade, int killsGrade, int accuracyGrade ) {}; }; extern CGameRules *InstallGameRules( void ); @@ -402,5 +409,142 @@ protected: float m_flEgonBustingCheckTime; }; +//========================================================= +// CDecayRules - rules for the cooperative Half-Life +// game (Decay) +//========================================================= + +typedef struct +{ + int kills; + int damage; + int shots; + int hits; + int lastShotId; + int magicWord1; + bool lastShotCounted; + int magicWord2; + float accuracy; + int gradeKills; + int gradeDamage; + int gradeAccuracy; + int gradeFinal; +} t_playerStats; + +class CDecayRules : public CGameRules +{ +public: + CDecayRules ( void ); + +// GR_Think + virtual void Think( void ); + virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); + virtual BOOL FAllowFlashlight( void ) { return TRUE; }; + + virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + +// Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer( void ); + virtual BOOL IsDeathmatch( void ); + virtual BOOL IsCoOp( void ); + +// Client connection/disconnection + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); + virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ); + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + virtual void PlayerThink( CBasePlayer *pPlayer ); + virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); + + virtual BOOL AllowAutoTargetCrosshair( void ); + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + +// Weapon retrieval + virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); // The player is touching an CBasePlayerItem, do I give it to him? + virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); + virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); + virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); + virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); + +// Item retrieval + virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ); + virtual float FlItemRespawnTime( CItem *pItem ); + virtual Vector VecItemRespawnSpot( CItem *pItem ); + +// Ammo retrieval + virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); + +// Ammo spawn/respawn control + virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); + virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); + virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ); + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); + +// Monsters + virtual BOOL FAllowMonsters( void ); + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}; + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + +// Decay stuff + // kicks player from server withing several seconds + void RemoveNewPlayer( int PlayerIdInArray ); + void unlockMissions( bool unlockAlien = false ); + + //edict_t *pLoopBack; + int PlayersCount; + CBasePlayer *pPlayers[8]; // was array of 2 + t_playerStats pStats[8]; + bool m_bAlienMode; + void ChangePlayer(); + void SetAlienMode( bool bMode ); + + int getDecayMapId(); + char *getDecayNextMap(); + char *getDecayMapName( int mapId ); + + char getGradeChar( int grade ); + void printXmlPlayerStats( FILE *fp, t_playerStats playerStats, bool bBest, int playerId ); + void statsExportXml(); + + void statsLoad(); + void statsSave(); + + virtual void MonsterKilled( entvars_t *pKiller, entvars_t *pVictim ); + virtual void PlayerDamaged( CBasePlayer *pPlayer, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + virtual void BulletsFired( entvars_t *pevAttacker, ULONG cShots, int iBulletType, int iShotId ); + virtual void BulletHit( CBaseEntity *pEntity, entvars_t *pevAttacker, int iShotId ); + virtual void savePlayerStats( int playerId, int finalGrade, int damageGrade, int killsGrade, int accuracyGrade ); + virtual void UpdateGameMode( CBasePlayer *pPlayer ); + virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); +}; + extern DLL_GLOBAL CGameRules *g_pGameRules; #endif // GAMERULES_H diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index 0df105e9..3109f946 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -28,6 +28,11 @@ #include "gamerules.h" #include "weapons.h" #include "game.h" +#include "actanimating.h" +#include "effects.h" + +#define CHARGER_ACTIVE 0 +#define CHARGER_EMPTY 1 class CRecharge : public CBaseToggle { @@ -663,4 +668,4 @@ void CMdlCharger::TurnOff(void) m_pBeam = NULL; SetUse( NULL ); SetSequence( seqCharge_RetractArm ); -} \ No newline at end of file +} diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index 52449d89..06cd56f3 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -23,6 +23,8 @@ #include "items.h" #include "gamerules.h" #include "game.h" +#include "actanimating.h" +//#include "effects.h" extern int gmsgItemPickup; @@ -757,4 +759,4 @@ void CMdlWallHealth::TurnOff( void ) pFluidTank->SetSequence( seq_ToRest ); SetUse( NULL ); SetSequence( seq_RetractArm ); -} \ No newline at end of file +} diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index cbfd78c4..685c740f 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -1000,6 +1000,9 @@ void CHGrunt::Spawn() m_HackedGunPos = Vector( 0, 0, 55 ); + SetBodygroup( LODS_GROUP, 0 ); + SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); + if( pev->weapons == 0 ) { // initialize to original values diff --git a/dlls/items.cpp b/dlls/items.cpp index 6d2e530e..412c1f30 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -192,15 +192,28 @@ class CItemSuit : public CItem { PRECACHE_MODEL( "models/w_suit.mdl" ); } + void KeyValue(KeyValueData *pkvd) + { + if (FStrEq(pkvd->szKeyName, "skin")) + { + pev->skin = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); + } BOOL MyTouch( CBasePlayer *pPlayer ) { if( pPlayer->pev->weapons & ( 1<spawnflags & SF_SUIT_SHORTLOGON ) - EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A0" ); // short version of suit logon, - else - EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_AAx" ); // long version of suit logon + if (!g_startSuit) + { + if( pev->spawnflags & SF_SUIT_SHORTLOGON ) + EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A0" ); // short version of suit logon, + else + EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_AAx" ); // long version of suit logon + } pPlayer->pev->weapons |= ( 1 << WEAPON_SUIT ); return TRUE; @@ -344,3 +357,426 @@ class CItemLongJump : public CItem }; LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ) + +// +// Decay's item_slave_collar for mission ht11lasers (Gamma labs) +// + +class CItemSlaveCollar : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT ZapThink( void ); + void EXPORT OffThink( void ); + + bool m_bIsOn; + int m_iBeams; + CBeam *m_pBeam[8]; // ISLAVE_MAX_BEAMS + + Vector m_vecDir; + Vector m_vecEnd; + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; +}; +LINK_ENTITY_TO_CLASS( item_slave_collar, CItemSlaveCollar ); + +TYPEDESCRIPTION CItemSlaveCollar::m_SaveData[] = +{ + DEFINE_FIELD( CItemSlaveCollar, m_bIsOn, FIELD_BOOLEAN ), + DEFINE_ARRAY( CItemSlaveCollar, m_pBeam, FIELD_CLASSPTR, 8 ), + DEFINE_FIELD( CItemSlaveCollar, m_iBeams, FIELD_INTEGER), + DEFINE_FIELD( CItemSlaveCollar, m_vecDir, FIELD_VECTOR), + DEFINE_FIELD( CItemSlaveCollar, m_vecEnd, FIELD_VECTOR), +}; +IMPLEMENT_SAVERESTORE( CItemSlaveCollar, CBaseEntity ); + +void CItemSlaveCollar::Spawn( void ) +{ + Precache(); + SET_MODEL(ENT(pev), "models/collar_test.mdl"); + + UTIL_MakeAimVectors( pev->angles ); + + m_vecDir = gpGlobals->v_forward; + m_vecEnd = pev->origin + m_vecDir * 2048; + + for ( m_iBeams = 0; m_iBeams < 2; m_iBeams++ ) + { + m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 50 ); + m_pBeam[m_iBeams]->pev->effects |= EF_NODRAW; + } + + if (FBitSet(pev->spawnflags, 1)) // Start on + { + m_bIsOn = true; + SetThink(ZapThink); // start zapping + pev->nextthink = gpGlobals->time; + } +} + +void CItemSlaveCollar::Precache( void ) +{ + PRECACHE_MODEL( "models/collar_test.mdl" ); + PRECACHE_SOUND( "weapons/electro4.wav" ); + PRECACHE_SOUND( "debris/zap4.wav" ); +} + +void CItemSlaveCollar::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( useType == USE_TOGGLE ) + m_bIsOn = !m_bIsOn; + if ( useType == USE_ON ) + m_bIsOn = true; + if ( useType == USE_OFF ) + m_bIsOn = false; + + if ( m_bIsOn ) + SetThink( ZapThink ); + else + SetThink( OffThink ); + pev->nextthink = gpGlobals->time + 0.01; +} + +void CItemSlaveCollar::OffThink( void ) +{ + for ( m_iBeams = 0; m_iBeams < 2; m_iBeams++ ) + { + m_pBeam[m_iBeams]->pev->effects |= EF_NODRAW; + } +} + +void CItemSlaveCollar::ZapThink( void ) +{ + // create alien slave beam here + //ALERT( at_console, "ZapThink!\n" ); + + TraceResult tr; + UTIL_TraceLine( pev->origin, m_vecEnd, ignore_monsters, ENT( pev ), &tr ); // dont_ignore_monsters + float m_flBeamLength = tr.flFraction; + + UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "debris/zap4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); + + Vector vecTmpEnd = pev->origin + m_vecDir * 2048 * m_flBeamLength; + tr.vecEndPos.z += 50; + + UTIL_Sparks( tr.vecEndPos ); + //if ( !tr.pHit ) + DecalGunshot( &tr, BULLET_PLAYER_CROWBAR ); + //UTIL_DecalTrace( &tr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); + + for ( m_iBeams = 0; m_iBeams < 2; m_iBeams++ ) + { + m_pBeam[m_iBeams]->pev->effects &= ~EF_NODRAW; + m_pBeam[m_iBeams]->PointEntInit( vecTmpEnd, entindex() ); + m_pBeam[m_iBeams]->SetEndAttachment( m_iBeams + 1 ); + m_pBeam[m_iBeams]->SetStartPos( tr.vecEndPos ); + m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); + m_pBeam[m_iBeams]->SetBrightness( 255 ); + m_pBeam[m_iBeams]->SetNoise( 20 ); + + /* + pEntity = CBaseEntity::Instance(tr.pHit); + if (pEntity != NULL && pEntity->pev->takedamage) + { + pEntity->TraceAttack( pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK ); + } + */ + } + UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); + pev->nextthink = gpGlobals->time + 5; +} + +// +// Decay's focus emitter code below +// + +// +// Decay's item_focusemitter for mission ht12fubar (Gamma labs) +// + +class CFocusEmitter : public CActAnimating +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT EmitterThink( void ); + void EXPORT DyingThink( void ); + void KeyValue(KeyValueData *pkvd); + void LookAt( Vector inputangles ); + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + void Killed( entvars_t *pevAttacker, int iGib ); + + bool m_bIsOn; + + Vector m_vecDir; + Vector m_vecEnd; + Vector m_angGun; + + int m_iszDeployedTarget; + int m_iszDeathTarget; + int m_iszLaserTarget; + CBeam *bWhiteBeam; + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; +}; + +LINK_ENTITY_TO_CLASS( item_focusemitter, CFocusEmitter ); + +TYPEDESCRIPTION CFocusEmitter::m_SaveData[] = +{ + DEFINE_FIELD( CFocusEmitter, m_bIsOn, FIELD_BOOLEAN ), + DEFINE_FIELD( CFocusEmitter, m_vecDir, FIELD_VECTOR), + DEFINE_FIELD( CFocusEmitter, m_vecEnd, FIELD_VECTOR), + DEFINE_FIELD( CFocusEmitter, m_iszDeployedTarget, FIELD_INTEGER), + DEFINE_FIELD( CFocusEmitter, m_iszDeathTarget, FIELD_INTEGER), + DEFINE_FIELD( CFocusEmitter, m_iszLaserTarget, FIELD_INTEGER), + DEFINE_FIELD( CFocusEmitter, bWhiteBeam, FIELD_CLASSPTR ), +}; +IMPLEMENT_SAVERESTORE( CFocusEmitter, CBaseEntity ); + +void CFocusEmitter::KeyValue(KeyValueData *pkvd) +{ + if (FStrEq(pkvd->szKeyName, "deploy_target")) + { + m_iszDeployedTarget = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + if (FStrEq(pkvd->szKeyName, "death_target")) + { + m_iszDeathTarget = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + if (FStrEq(pkvd->szKeyName, "lasertarget")) + { + m_iszLaserTarget = ALLOC_STRING(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +void CFocusEmitter::Spawn( void ) +{ + Precache(); + SET_MODEL(ENT(pev), "models/focus_emitter.mdl"); + + pev->takedamage = DAMAGE_YES; + pev->health = 150*4; // 4 HVR shots + pev->solid = SOLID_BBOX; + pev->flags |= FL_MONSTER; + UTIL_SetSize( pev, Vector(-30,-30,0), Vector(30,30,700)); + + SetBodygroup( 1, 2 ); + + SetSequence( seqEmitterClosed ); + SetThink( EmitterThink ); + pev->nextthink = gpGlobals->time; + + CBaseEntity *LasTarget; + LasTarget = UTIL_FindEntityByTargetname( NULL, STRING( m_iszLaserTarget )); + if (!LasTarget) + LasTarget = this; + bWhiteBeam = CBeam::BeamCreate( "sprites/lgtning.spr", 50 ); + bWhiteBeam->PointEntInit( LasTarget->pev->origin, entindex( ) ); + bWhiteBeam->SetEndAttachment( 2 ); + bWhiteBeam->SetColor( 255, 255, 255 ); + bWhiteBeam->SetScrollRate( 35 ); + bWhiteBeam->SetNoise( 3 ); + bWhiteBeam->pev->effects |= EF_NODRAW; + + if (FBitSet(pev->spawnflags, 1)) // Start on + { + m_bIsOn = true; + SetSequence( seqEmitterIdleOpen ); + bWhiteBeam->pev->effects &= ~EF_NODRAW; + pev->nextthink = gpGlobals->time; + } +} + +void CFocusEmitter::Precache( void ) +{ + PRECACHE_MODEL( "models/focus_emitter.mdl" ); + PRECACHE_MODEL( "sprites/lgtning.spr" ); + PRECACHE_SOUND( "debris/beamstart4.wav" ); +} + +void CFocusEmitter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if (m_bIsOn) + return; + + SetSequence( seqEmitterDeploy ); + m_bIsOn = true; +} + +void CFocusEmitter::EmitterThink( void ) +{ + StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + + //CBaseEntity *pPlayer; + //pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); + //if (pPlayer) + // LookAt( pPlayer->pev->origin ); + + switch( GetSequence() ) + { + case seqEmitterClosed: // 0 - still + break; + case seqEmitterDeploy: // 1 - slosh + if ( m_fSequenceFinished ) + { + SetSequence( seqEmitterIdleOpen ); + FireTargets( STRING( m_iszDeployedTarget ), this, this, USE_ON, 1.0 ); + bWhiteBeam->pev->effects &= ~EF_NODRAW; + UTIL_EmitAmbientSound( ENT(pev), pev->origin, "debris/beamstart4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); + UTIL_ScreenFadeAll( Vector( 255, 255, 255), 1.0, 0.1, 150, 0 ); + } + break; + case seqEmitterIdleOpen: + if (pev->health < 150*3) + SetSequence( seqEmitterBroken1); + break; + case seqEmitterBroken1: + if (pev->health < 150*2) + SetSequence( seqEmitterBroken2); + break; + case seqEmitterBroken2: // 2 - to rest + //if (pev->health = 0) + // SetSequence( seqEmitterDeath ); + break; + case seqEmitterDeath: + // random explosions + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now + WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); + WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); + WRITE_SHORT( g_sModelIndexFireball ); + WRITE_BYTE( RANDOM_LONG(0,29) + 30 ); // scale * 10 + WRITE_BYTE( 12 ); // framerate + WRITE_BYTE( TE_EXPLFLAG_NONE ); + MESSAGE_END(); + if ( m_fSequenceFinished ) + { + SetThink( DyingThink ); + pev->nextthink = gpGlobals->time + 0.1; + } + break; + default: + break; + } +} + +void CFocusEmitter::DyingThink( void ) +{ + // lots of smoke + MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_SMOKE ); + WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 ) ); + WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 ) ); + WRITE_COORD( pev->origin.z + 200 + RANDOM_FLOAT( -150, -50 ) ); + WRITE_SHORT( g_sModelIndexSmoke ); + WRITE_BYTE( 50 ); // scale * 10 + WRITE_BYTE( 10 ); // framerate + MESSAGE_END(); + + pev->nextthink = gpGlobals->time + 0.1; +} + +void CFocusEmitter :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->health = 0; + pev->takedamage = DAMAGE_NO; + bWhiteBeam->pev->effects |= EF_NODRAW; + FireTargets( STRING( m_iszDeathTarget ), this, this, USE_TOGGLE, 1.0 ); + SetSequence( seqEmitterDeath ); + pev->nextthink = gpGlobals->time + 0.1; + + //m_flDieCounter = gpGlobals->time + 2.5; + + //FireTargets( STRING(m_iszDeathTarget), this, this, USE_TOGGLE, 1.0 ); +} + +void CFocusEmitter::LookAt( Vector inputangles ) +{ + UTIL_MakeAimVectors( pev->angles ); + + Vector posGun, angGun; + GetAttachment( 2, posGun, angGun ); + + Vector vecTarget = (inputangles - posGun).Normalize( ); + + Vector vecOut; + + vecOut.x = DotProduct( gpGlobals->v_forward, vecTarget ); + vecOut.y = -DotProduct( gpGlobals->v_right, vecTarget ); + vecOut.z = DotProduct( gpGlobals->v_up, vecTarget ); + + Vector angles = UTIL_VecToAngles (vecOut); + + angles.x = -angles.x; + if (angles.x > 180) + angles.x = angles.x - 360; + if (angles.x < -180) + angles.x = angles.x + 360; + + m_angGun.x = angles.x; + m_angGun.y = angles.y; +/* + if (angles.x > m_angGun.x) + m_angGun.x = min( angles.x, m_angGun.x + 12 ); + if (angles.x < m_angGun.x) + m_angGun.x = max( angles.x, m_angGun.x - 12 ); + if (angles.y > m_angGun.y) + m_angGun.y = min( angles.y, m_angGun.y + 12 ); + if (angles.y < m_angGun.y) + m_angGun.y = max( angles.y, m_angGun.y - 12 ); +*/ + m_angGun.y = SetBoneController( 0, m_angGun.y ); + m_angGun.x = SetBoneController( 1, m_angGun.x ); +} + +int CFocusEmitter :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) +{ + if (pevInflictor->owner == edict()) + return 0; + + if (bitsDamageType & DMG_BLAST) + { + flDamage *= 2; + } + + // ALERT( at_console, "%.0f\n", flDamage ); + return CBaseEntity::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); +} + +// +// Emitter target +// + +class CEmitterTarget : public CBaseEntity +{ +public: + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; + +void CEmitterTarget :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + // TODO: find emitter, call LookAt(this) + CFocusEmitter *pEmitter; // = NULL; + pEmitter = (CFocusEmitter*)UTIL_FindEntityByClassname( NULL, "item_focusemitter" ); + if (pEmitter) + pEmitter->LookAt( pev->origin ); + + FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0.0 ); + ALERT( at_console, "info_emittertarget called Use! Firing %s\n", STRING(pev->target) ); +} +LINK_ENTITY_TO_CLASS( info_emittertarget, CEmitterTarget ); diff --git a/dlls/items.h b/dlls/items.h index 3c5ba6eb..ba46ddd4 100644 --- a/dlls/items.h +++ b/dlls/items.h @@ -16,6 +16,8 @@ #if !defined(ITEMS_H) #define ITEMS_H +extern BOOL g_startSuit; + class CItem : public CBaseEntity { public: diff --git a/dlls/monstermaker.cpp b/dlls/monstermaker.cpp index e15a36b5..23556a71 100644 --- a/dlls/monstermaker.cpp +++ b/dlls/monstermaker.cpp @@ -22,46 +22,15 @@ #include "cbase.h" #include "monsters.h" #include "saverestore.h" - -// Monstermaker spawnflags -#define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname ) -#define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired. -#define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip +#include "monstermaker.h" +#include "effects.h" //========================================================= // MonsterMaker - this ent creates monsters during the game. //========================================================= -class CMonsterMaker : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT CyclicUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT MakerThink( void ); - void DeathNotice( entvars_t *pevChild );// monster maker children use this to tell the monster maker that they have died. - void MakeMonster( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - string_t m_iszMonsterClassname;// classname of the monster(s) that will be created. - - int m_cNumMonsters;// max number of monsters this ent can create - - int m_cLiveChildren;// how many monsters made by this monster maker that are currently alive - int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time. - - float m_flGround; // z coord of the ground under me, used to make sure no monsters are under the maker when it drops a new child - - BOOL m_fActive; - BOOL m_fFadeChildren;// should we make the children fadeout? -}; LINK_ENTITY_TO_CLASS( monstermaker, CMonsterMaker ) +LINK_ENTITY_TO_CLASS( env_warpball, CMonsterMaker ) TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = { @@ -83,9 +52,10 @@ void CMonsterMaker::KeyValue( KeyValueData *pkvd ) if( FStrEq( pkvd->szKeyName, "monstercount" ) ) { m_cNumMonsters = atoi( pkvd->szValue ); + m_cTotalMonstersCount = m_cNumMonsters; pkvd->fHandled = TRUE; } - else if( FStrEq( pkvd->szKeyName, "m_imaxlivechildren" ) ) + else if ( FStrEq(pkvd->szKeyName, "m_imaxlivechildren") || FStrEq(pkvd->szKeyName, "maxlivechildren")) { m_iMaxLiveChildren = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; @@ -135,7 +105,7 @@ void CMonsterMaker::Spawn() SetUse( &CMonsterMaker::ToggleUse );// so can be turned on/off } - if( FBitSet( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) + if( !m_fIsWarpBall && FBitSet( pev->spawnflags, SF_MONSTERMAKER_START_ON )) { // start making monsters as soon as monstermaker spawns m_fActive = TRUE; @@ -200,18 +170,38 @@ void CMonsterMaker::MakeMonster( void ) return; } + bool bFoundTarget = false; + Vector DesiredOrigin; + Vector DesiredAngles; + if (!FStringNull( m_iszWarpTarget )) + { + m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_iszWarpTarget ) ); + if (m_pGoalEnt) + { + DesiredOrigin = m_pGoalEnt->pev->origin; + DesiredAngles = m_pGoalEnt->pev->angles; + bFoundTarget = true; + } + } + + if (!bFoundTarget) + { + DesiredOrigin = pev->origin; + DesiredAngles = pev->angles; + } + if( !m_flGround ) { // set altitude. Now that I'm activated, any breakables, etc should be out from under me. TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin - Vector( 0, 0, 2048 ), ignore_monsters, ENT( pev ), &tr ); + UTIL_TraceLine( DesiredOrigin, DesiredOrigin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr ); m_flGround = tr.vecEndPos.z; } - Vector mins = pev->origin - Vector( 34, 34, 0 ); - Vector maxs = pev->origin + Vector( 34, 34, 0 ); - maxs.z = pev->origin.z; + Vector mins = DesiredOrigin - Vector( 34, 34, 0 ); + Vector maxs = DesiredOrigin + Vector( 34, 34, 0 ); + maxs.z = DesiredOrigin.z; mins.z = m_flGround; CBaseEntity *pList[2]; @@ -219,9 +209,31 @@ void CMonsterMaker::MakeMonster( void ) if( count ) { // don't build a stack of monsters! - return; + bool bAllDead = true; + for ( int i = 0; i < count; i++ ) + { + if ( pList[i]->IsAlive() ) // Don't count dead monsters + bAllDead = false; + } + // don't build a stack of monsters if there are alive monsters nearby! + if (!bAllDead) + return; } + // If env_warpball then create teleport effect + if ( m_fIsWarpBall == true) + { + CEnvWarpBall *pWarpBall = CEnvWarpBall::WarpBallCreate(); + pWarpBall->pev->origin = DesiredOrigin; + pWarpBall->pev->angles = DesiredAngles; + SetBits( pWarpBall->pev->spawnflags, SF_AUTO_FIREONCE ); + pWarpBall->Use( this, this, USE_ON, 1); + + // if monstermaker is a warpball and doesn't have children class specified, play effect only + if (FStringNull(m_iszMonsterClassname)) + return; + } + pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname ); if( FNullEnt( pent ) ) @@ -333,3 +345,18 @@ void CMonsterMaker::DeathNotice( entvars_t *pevChild ) pevChild->owner = NULL; } } + +void CMonsterMaker :: MonsterMakerInit( const char* ChildName, int MaxLiveChildren, int NumMonsters ) +{ + m_cNumMonsters = NumMonsters; + m_iMaxLiveChildren = MaxLiveChildren; + m_iszMonsterClassname = MAKE_STRING( ChildName ); + Spawn(); +} + +CMonsterMaker *CMonsterMaker::MonsterMakerCreate( const char* ChildName, int MaxLiveChildren, int NumMonsters ) +{ + CMonsterMaker *pMonsterMaker = GetClassPtr( (CMonsterMaker *)NULL ); + pMonsterMaker->MonsterMakerInit( ChildName, MaxLiveChildren, NumMonsters ); + return pMonsterMaker; +} diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index ef2db2d5..9c71345a 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -74,6 +74,7 @@ static CMultiplayGameMgrHelper g_GameMgrHelper; //********************************************************* CHalfLifeMultiplay::CHalfLifeMultiplay() { + ALERT( at_console, "Half-Life multiplayer\n"); #if !NO_VOICEGAMEMGR g_VoiceGameMgr.Init( &g_GameMgrHelper, gpGlobals->maxClients ); #endif diff --git a/dlls/plats.cpp b/dlls/plats.cpp index 0f2dbe70..f7384b50 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -1059,9 +1059,9 @@ void CFuncTrackTrain::StopSound( void ) PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, g_vecZero, g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0 ); - /* + /* was commented before */ STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise ) ); - */ + EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100 ); } diff --git a/dlls/player.cpp b/dlls/player.cpp index 5f8a6c73..58ad5d84 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -45,6 +45,8 @@ extern DLL_GLOBAL BOOL g_fDrawLines; int gEvilImpulse101; extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle; +extern bool bSlaveCoop; + BOOL gInitHUD = TRUE; extern void CopyToBodyQue( entvars_t *pev); @@ -236,6 +238,16 @@ void LinkUserMessages( void ) gmsgStatusText = REG_USER_MSG( "StatusText", -1 ); gmsgStatusValue = REG_USER_MSG( "StatusValue", 3 ); + + gmsgLensFlare = REG_USER_MSG( "LensFlare", 1 ); //for sun effect + gmsgAimFrame = REG_USER_MSG( "AimFrame", 14 ); //for selection frame + gmsgNotepad = REG_USER_MSG( "Notepad", -1 ); + gmsgChangeMode = REG_USER_MSG( "ChangeMode", 1 ); + gmsgChangePlayer = REG_USER_MSG( "ChangePlr", 1 ); + gmsgCamera = REG_USER_MSG( "Camera", 7 ); + gmsgSparePlayer = REG_USER_MSG( "SparePlayer", 1 ); + gmsgAlienState = REG_USER_MSG ( "AlienState", 1 ); + gmsgUpdateDecayPlayerName = REG_USER_MSG( "DecayName", 1 ); } LINK_ENTITY_TO_CLASS( player, CBasePlayer ) @@ -431,6 +443,9 @@ void CBasePlayer::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve int CBasePlayer::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { + // DECAY STATS + g_pGameRules->PlayerDamaged( this, pevAttacker, flDamage, bitsDamageType ); + // have suit diagnose the problem - ie: report damage type int bitsDamage = bitsDamageType; int ffound = TRUE; @@ -811,6 +826,134 @@ void CBasePlayer::PackDeadPlayerItems( void ) RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above. } +void CBasePlayer::PackAllItems( void ) +{ + int iWeaponRules; + int iAmmoRules; + int i; + CBasePlayerWeapon *rgpPackWeapons[ 20 ];// 20 hardcoded for now. How to determine exactly how many weapons we have? + int iPackAmmo[ MAX_AMMO_SLOTS + 1]; + int iPW = 0;// index into packweapons array + int iPA = 0;// index into packammo array + + memset(rgpPackWeapons, NULL, sizeof(rgpPackWeapons) ); + memset(iPackAmmo, -1, sizeof(iPackAmmo) ); + + // get the game rules + /*iWeaponRules = g_pGameRules->DeadPlayerWeapons( this ); + iAmmoRules = g_pGameRules->DeadPlayerAmmo( this ); + + if ( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO ) + { + // nothing to pack. Remove the weapons and return. Don't call create on the box! + RemoveAllItems( TRUE ); + return; + }*/ + + iWeaponRules = GR_PLR_DROP_GUN_ALL; + iAmmoRules = GR_PLR_DROP_AMMO_ALL; + +// go through all of the weapons and make a list of the ones to pack + for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) + { + if ( m_rgpPlayerItems[ i ] ) + { + // there's a weapon here. Should I pack it? + CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; + + while ( pPlayerItem ) + { + switch( iWeaponRules ) + { + case GR_PLR_DROP_GUN_ACTIVE: + if ( m_pActiveItem && pPlayerItem == m_pActiveItem ) + { + // this is the active item. Pack it. + rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; + } + break; + + case GR_PLR_DROP_GUN_ALL: + rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; + break; + + default: + break; + } + + pPlayerItem = pPlayerItem->m_pNext; + } + } + } + +// now go through ammo and make a list of which types to pack. + if ( iAmmoRules != GR_PLR_DROP_AMMO_NO ) + { + for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) + { + if ( m_rgAmmo[ i ] > 0 ) + { + // player has some ammo of this type. + switch ( iAmmoRules ) + { + case GR_PLR_DROP_AMMO_ALL: + iPackAmmo[ iPA++ ] = i; + break; + + case GR_PLR_DROP_AMMO_ACTIVE: + if ( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) + { + // this is the primary ammo type for the active weapon + iPackAmmo[ iPA++ ] = i; + } + else if ( m_pActiveItem && i == m_pActiveItem->SecondaryAmmoIndex() ) + { + // this is the secondary ammo type for the active weapon + iPackAmmo[ iPA++ ] = i; + } + break; + + default: + break; + } + } + } + } + +// create a box to pack the stuff into. + CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 2, pev->angles, edict() ); + + pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt. + pWeaponBox->pev->angles.z = 0; + + pWeaponBox->SetThink( CWeaponBox::Kill ); + pWeaponBox->pev->nextthink = gpGlobals->time + 120; + +// back these two lists up to their first elements + iPA = 0; + iPW = 0; + +// pack the ammo + while ( iPackAmmo[ iPA ] != -1 ) + { + pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[ iPackAmmo[ iPA ] ].pszName ), m_rgAmmo[ iPackAmmo[ iPA ] ] ); + iPA++; + } + +// now pack all of the items in the lists + while ( rgpPackWeapons[ iPW ] ) + { + // weapon unhooked from the player. Pack it into der box. + pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] ); + + iPW++; + } + + pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. + + RemoveAllItems( FALSE );// now strip off everything that wasn't handled by the code above. +} + void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { int i; @@ -964,6 +1107,7 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) int animDesired; float speed; char szAnim[64]; + int m_iMode; speed = pev->velocity.Length2D(); @@ -973,6 +1117,7 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) playerAnim = PLAYER_IDLE; } + m_iMode = MODE_STAND; switch( playerAnim ) { case PLAYER_JUMP: @@ -1089,6 +1234,7 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) if( FBitSet( pev->flags, FL_DUCKING ) ) { + m_iMode = MODE_CROUCH; if( speed == 0 ) { pev->gaitsequence = LookupActivity( ACT_CROUCHIDLE ); @@ -1101,6 +1247,7 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) } else if( speed > 220 ) { + m_iMode = MODE_RUN; pev->gaitsequence = LookupActivity( ACT_RUN ); } else if( speed > 0 ) @@ -1113,6 +1260,12 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) pev->gaitsequence = LookupSequence( "deep_idle" ); } + MESSAGE_BEGIN( MSG_ONE, gmsgChangeMode, NULL, pev); + WRITE_BYTE( m_iMode ); + MESSAGE_END(); + + //ALERT( at_console, "Set mode to %d\n", m_iMode ); + // Already using the desired animation? if( pev->sequence == animDesired ) return; @@ -1655,6 +1808,10 @@ void CBasePlayer::Jump() // ClearBits( pev->flags, FL_ONGROUND ); // don't stairwalk + MESSAGE_BEGIN( MSG_ONE, gmsgChangeMode, NULL, pev); + WRITE_BYTE( MODE_JUMP ); + MESSAGE_END(); + SetAnimation( PLAYER_JUMP ); if( m_fLongJump && @@ -1777,6 +1934,9 @@ void CBasePlayer::UpdateStatusBar() char sbuf0[SBAR_STRING_SIZE]; char sbuf1[ SBAR_STRING_SIZE ]; + //Vyacheslav Dzhura: in Decay we need no StatusBar, just exit from here + //return; + strcpy( sbuf0, m_SbarString0 ); strcpy( sbuf1, m_SbarString1 ); @@ -2883,6 +3043,17 @@ ReturnSpot: return pSpot->edict(); } +inline char *GET_INFOBUFFER( edict_t *e ) +{ + return (*g_engfuncs.pfnGetInfoKeyBuffer)( e ); +} + +inline void SET_CLIENT_KEY_VALUE( int clientIndex, char *infobuffer, + char *key, char *value ) +{ + (*g_engfuncs.pfnSetClientKeyValue)( clientIndex, infobuffer, key, value ); +} + void CBasePlayer::Spawn( void ) { m_flStartCharge = gpGlobals->time; @@ -2925,7 +3096,11 @@ void CBasePlayer::Spawn( void ) m_iStepLeft = 0; m_flFieldOfView = 0.5f;// some monsters use this to determine whether or not the player is looking at them. - m_bloodColor = BLOOD_COLOR_RED; + if ( !bSlaveCoop ) + m_bloodColor = BLOOD_COLOR_RED; + else + m_bloodColor = BLOOD_COLOR_YELLOW; + m_flNextAttack = UTIL_WeaponTimeBase(); StartSneaking(); @@ -2938,7 +3113,11 @@ void CBasePlayer::Spawn( void ) g_pGameRules->SetDefaultPlayerTeam( this ); g_pGameRules->GetPlayerSpawnSpot( this ); - SET_MODEL( ENT( pev ), "models/player.mdl" ); + if ( !bSlaveCoop ) + SET_MODEL(ENT(pev), "models/player.mdl"); + else + SET_MODEL(ENT(pev), "models/player/dm_slave/dm_slave.mdl"); + g_ulModelIndexPlayer = pev->modelindex; pev->sequence = LookupActivity( ACT_IDLE ); @@ -2977,6 +3156,79 @@ void CBasePlayer::Spawn( void ) m_flNextChatTime = gpGlobals->time; g_pGameRules->PlayerSpawn( this ); + + // + // Decay: set head\skin for Decay players + // MOVED TO DECAY_GAMERULES.CPP + + char *infobuffer = GET_INFOBUFFER( edict( ) ); + int clientIndex = entindex( ); + + if (!bSlaveCoop) + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "model", "ginacol" ); + else + SET_CLIENT_KEY_VALUE( clientIndex, infobuffer, "model", "player/dm_slave/dm_slave" ); + + // model parts: + // 0: body 0: body + // 1: head 0: Colette + // 1: Gina + + // ****** HEADS CHANGE ********* + //for ( int i = 0; i < 2; i++ ) + { + this->SetBodygroup( 0, 0 ); + if ( this->m_iDecayId == 1 ) + { + this->SetBodygroup( 1, 1 ); + this->pev->skin = 1; + } else + if ( this->m_iDecayId == 2 ) + { + this->SetBodygroup( 1, 0 ); + this->pev->skin = 0; + } + } + + // + // Decay: update HUD color to match player (Silver for Gina, Orange for Colette) + // + + if ( gmsgChangePlayer != 0) + { + //MESSAGE_BEGIN( MSG_ALL, gmsgChangePlayer ); + MESSAGE_BEGIN( MSG_ONE, gmsgChangePlayer, NULL, this->edict() ); + WRITE_BYTE( m_iDecayId ); + MESSAGE_END(); + } else + ALERT( at_console, "Message gmsgChangePlayer not found in client.dll!\n" ); + + ALERT( at_console, "(CBasePlayer::Spawn) m_iDecay = %d\n", this->m_iDecayId ); + + /*if (this->m_iDecayId >= 3) + { + MESSAGE_BEGIN( MSG_ONE, gmsgSparePlayer, NULL, + //GetClassPtr((CBasePlayer *)this->pev)->pev + this->edict() ); + WRITE_BYTE( 0 ); + MESSAGE_END(); + }*/ + + // + // end of Decay stuff + // + + CBaseEntity *pWeaponEntity = NULL; + + if ( ( g_startSuit ) && ( !bSlaveCoop ) ) //if this flag is activated, then start level with suit and activate game_player_equip entity + { + GiveNamedItem( "item_suit" ); + + while ( pWeaponEntity = UTIL_FindEntityByClassname( pWeaponEntity, "game_player_equip" )) + { + pWeaponEntity->Touch( this ); + } + } } void CBasePlayer::Precache( void ) @@ -3066,7 +3318,10 @@ int CBasePlayer::Restore( CRestore &restore ) pev->fixangle = TRUE; // turn this way immediately // Copied from spawn() for now - m_bloodColor = BLOOD_COLOR_RED; + if ( !bSlaveCoop ) + m_bloodColor = BLOOD_COLOR_RED; + else + m_bloodColor = BLOOD_COLOR_YELLOW; g_ulModelIndexPlayer = pev->modelindex; @@ -3781,7 +4036,7 @@ int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem, bool bCallHolster ) if( m_pActiveItem == pItem ) { ResetAutoaim(); - if( bCallHolster ) + if( bCallHolster || !(pev->flags & FL_IMMUNE_WATER) ) pItem->Holster(); m_pActiveItem = NULL; pev->viewmodel = 0; @@ -4201,11 +4456,15 @@ void CBasePlayer::UpdateClientData( void ) SendAmmoUpdate(); - // Update all the items + // Update all the items (weapon slots) for( int i = 0; i < MAX_ITEM_TYPES; i++ ) { if( m_rgpPlayerItems[i] ) // each item updates it's successors + { + //ALERT( at_console, "updating item %d! ", i ); + //ALERT( at_console, "%s\n", m_rgpPlayerItems[i]->pszName ); m_rgpPlayerItems[i]->UpdateClientData( this ); + } } // Cache and client weapon change diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index 380e9e98..2a325ac6 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -27,18 +27,36 @@ #include "animation.h" #include "soundent.h" +// +// Model bodies +// + +#define LOD_COUNT 1 // IMPORTANT: 4 for original Decay; 5 for Half-Life PS2 + +#define BODY_GROUP 0 +#define BODY_LOD0 0 + +#define HEAD_GROUP 1 #define NUM_SCIENTIST_HEADS 4 // four heads available for scientist model static cvar_t *g_psv_override_scientist_mdl; enum { - HEAD_GLASSES = 0, - HEAD_EINSTEIN = 1, - HEAD_LUTHER = 2, - HEAD_SLICK = 3 + HEAD_GLASSES = 0 * LOD_COUNT, + HEAD_EINSTEIN = 1 * LOD_COUNT, + HEAD_LUTHER = 2 * LOD_COUNT, + HEAD_SLICK = 3 * LOD_COUNT }; +#define NEEDLE_GROUP 2 +#define NEEDLE_ON 1 +#define NEEDLE_OFF 0 + +// +// Schedules +// + enum { SCHED_HIDE = LAST_TALKMONSTER_SCHEDULE + 1, @@ -112,12 +130,13 @@ public: virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; + float m_painTime; + CUSTOM_SCHEDULES private: const char *GetScientistModel( void ); - float m_painTime; float m_healTime; float m_fearTime; }; @@ -465,7 +484,7 @@ void CScientist::StartTask( Task_t *pTask ) //if( FOkToSpeak() ) Talk( 2 ); m_hTalkTarget = m_hTargetEnt; - PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); + PlaySentence( m_szGrp[TLK_HEAL], 2, VOL_NORM, ATTN_IDLE ); TaskComplete(); break; case TASK_SCREAM: @@ -486,9 +505,9 @@ void CScientist::StartTask( Task_t *pTask ) //The enemy can be null here. - Solokiller //Discovered while testing the barnacle grapple on headcrabs with scientists in view. if( m_hEnemy != 0 && m_hEnemy->IsPlayer() ) - PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); + PlaySentence( m_szGrp[TLK_PLFEAR], 5, VOL_NORM, ATTN_NORM ); else - PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); + PlaySentence( m_szGrp[TLK_FEAR], 5, VOL_NORM, ATTN_NORM ); } TaskComplete(); break; @@ -637,14 +656,18 @@ void CScientist::HandleAnimEvent( MonsterEvent_t *pEvent ) break; case SCIENTIST_AE_NEEDLEON: { - int oldBody = pev->body; - pev->body = ( oldBody % NUM_SCIENTIST_HEADS ) + NUM_SCIENTIST_HEADS * 1; + //int oldBody = pev->body; + //pev->body = ( oldBody % NUM_SCIENTIST_HEADS ) + NUM_SCIENTIST_HEADS * 1; + + SetBodygroup( NEEDLE_GROUP, NEEDLE_ON ); } break; case SCIENTIST_AE_NEEDLEOFF: { - int oldBody = pev->body; - pev->body = ( oldBody % NUM_SCIENTIST_HEADS ) + NUM_SCIENTIST_HEADS * 0; + //int oldBody = pev->body; + //pev->body = ( oldBody % NUM_SCIENTIST_HEADS ) + NUM_SCIENTIST_HEADS * 0; + + SetBodygroup( NEEDLE_GROUP, NEEDLE_OFF ); } break; default: @@ -661,8 +684,14 @@ void CScientist::Spawn( void ) if( pev->body == -1 ) { // -1 chooses a random head - pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head + //pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head + + SetBodygroup( HEAD_GROUP, RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1) * LOD_COUNT ); + } else + { + SetBodygroup( HEAD_GROUP, pev->body * LOD_COUNT ); } + SetBodygroup( BODY_GROUP, BODY_LOD0 ); Precache(); @@ -685,7 +714,7 @@ void CScientist::Spawn( void ) pev->skin = 0; // Luther is black, make his hands black - if( pev->body == HEAD_LUTHER ) + if( GetBodygroup( HEAD_GROUP ) == HEAD_LUTHER ) pev->skin = 1; MonsterInit(); @@ -741,7 +770,7 @@ void CScientist::TalkInit() m_szGrp[TLK_MORTAL] = "SC_MORTAL"; // get voice for head - switch( pev->body % NUM_SCIENTIST_HEADS ) + switch ( GetBodygroup( HEAD_GROUP ) ) { default: case HEAD_GLASSES: @@ -1164,11 +1193,15 @@ void CDeadScientist::Spawn() if( pev->body == -1 ) { // -1 chooses a random head - pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head + SetBodygroup( HEAD_GROUP, RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1) * LOD_COUNT ); + } else + { + SetBodygroup( HEAD_GROUP, pev->body * LOD_COUNT ); } + SetBodygroup( BODY_GROUP, BODY_LOD0 ); // Luther is black, make his hands black - if( pev->body == HEAD_LUTHER ) + if( GetBodygroup( HEAD_GROUP ) == HEAD_LUTHER ) pev->skin = 1; else pev->skin = 0; @@ -1269,11 +1302,15 @@ void CSittingScientist::Spawn() if( pev->body == -1 ) { // -1 chooses a random head - pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head + SetBodygroup( HEAD_GROUP, RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1) * LOD_COUNT ); + } else + { + SetBodygroup( HEAD_GROUP, pev->body * LOD_COUNT ); } + SetBodygroup( BODY_GROUP, BODY_LOD0 ); // Luther is black, make his hands black - if( pev->body == HEAD_LUTHER ) + if( GetBodygroup( HEAD_GROUP ) == HEAD_LUTHER ) pev->skin = 1; m_baseSequence = LookupSequence( "sitlookleft" ); @@ -1704,4 +1741,4 @@ void CRosenberg :: TalkInit() int CRosenberg::FIdleSpeak( void ) { return -1; -} \ No newline at end of file +} diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index bdaa85c0..445b5d1f 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -278,7 +278,7 @@ int CCineMonster::FindEntity( void ) m_hTargetEnt = pTarget; return TRUE; } - ALERT( at_console, "Found %s, but can't play!\n", STRING( m_iszEntity ) ); + ALERT( at_console, "(%s::FindEntity) Found %s, but can't play!\n", STRING(pev->targetname), STRING( m_iszEntity ) ); } pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( m_iszEntity ) ); pTarget = NULL; diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index 06ad417c..afe06710 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -35,6 +35,7 @@ extern int gmsgMOTD; //========================================================= CHalfLifeRules::CHalfLifeRules( void ) { + ALERT( at_console, "Generic Half-Life singleplayer\n"); SERVER_COMMAND( "exec spserver.cfg\n" ); RefreshSkillData(); } diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 31a36085..a05857fa 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -627,6 +627,10 @@ void CAmbientGeneric::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, UTIL_EmitAmbientSound( ENT( pev ), pev->origin, szSoundFile, ( m_dpv.vol * 0.01f ), m_flAttenuation, 0, m_dpv.pitch ); + // Decay: subtitles code + if ( FBitSet ( pev->spawnflags, AMBIENT_SHOWMESSAGE ) ) + UTIL_ShowMessageAll( STRING(pev->message) ); //strings code + pev->nextthink = gpGlobals->time + 0.1f; } } diff --git a/dlls/subs.cpp b/dlls/subs.cpp index 4ee1fb96..a4970a38 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -66,6 +66,7 @@ private: // These are the new entry points to entities. LINK_ENTITY_TO_CLASS( info_player_deathmatch, CBaseDMStart ) LINK_ENTITY_TO_CLASS( info_player_start, CPointEntity ) +LINK_ENTITY_TO_CLASS( info_player_coop, CPointEntity ) // for Decay to spawn players properly LINK_ENTITY_TO_CLASS( info_landmark, CPointEntity ) void CBaseDMStart::KeyValue( KeyValueData *pkvd ) diff --git a/dlls/talkmonster.h b/dlls/talkmonster.h index def73180..3527eabd 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -61,6 +61,11 @@ typedef enum TLK_WOUND, TLK_MORTAL, + // added for Decay + TLK_HEAL, + TLK_PLFEAR, + TLK_FEAR, + TLK_CGROUPS // MUST be last entry } TALKGROUPNAMES; diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index fd7472db..3f893ec2 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -104,11 +104,109 @@ void CFrictionModifier::KeyValue( KeyValueData *pkvd ) CBaseEntity::KeyValue( pkvd ); } -// This trigger will fire when the level spawns (or respawns if not fire once) +// This trigger will fire when the client spawns in game world, just after the HUD INIT // It will check a global state before firing. It supports delay and killtargets #define SF_AUTO_FIREONCE 0x0001 +class CPlayerSpawnTrigger : public CBaseDelay +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Spawn( void ); + + int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + +private: + int m_globalstate; + int m_iPlayerIndex; + USE_TYPE triggerType; +}; +LINK_ENTITY_TO_CLASS( trigger_clientspawn, CPlayerSpawnTrigger ); + +TYPEDESCRIPTION CPlayerSpawnTrigger::m_SaveData[] = +{ + DEFINE_FIELD( CPlayerSpawnTrigger, m_globalstate, FIELD_STRING ), + DEFINE_FIELD( CPlayerSpawnTrigger, m_iPlayerIndex, FIELD_INTEGER ), + DEFINE_FIELD( CPlayerSpawnTrigger, triggerType, FIELD_INTEGER ), +}; + +IMPLEMENT_SAVERESTORE(CPlayerSpawnTrigger, CBaseDelay); + +void CPlayerSpawnTrigger::Spawn( void ) +{ + +} + +void CPlayerSpawnTrigger::KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "globalstate")) + { + m_globalstate = ALLOC_STRING( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "player_index")) + { + m_iPlayerIndex = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if (FStrEq(pkvd->szKeyName, "triggerstate")) + { + int type = atoi( pkvd->szValue ); + switch( type ) + { + case 0: + triggerType = USE_OFF; + break; + case 2: + triggerType = USE_TOGGLE; + break; + default: + triggerType = USE_ON; + break; + } + pkvd->fHandled = TRUE; + } + else + CBaseDelay::KeyValue( pkvd ); +} + +void CPlayerSpawnTrigger::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) + { + if ( pev->spawnflags & SF_SPECIFICPLAYER ) + { + if ( pActivator ) + if (pActivator->IsPlayer()) + { + CBasePlayer *g_pPlayer; + g_pPlayer = (CBasePlayer*)pActivator; + + if (m_iPlayerIndex != 0) + { // check if Gina or Colette + if (g_pPlayer->m_iDecayId != m_iPlayerIndex) + return; + } + } + } + + SUB_UseTargets( this, triggerType, 0 ); + + if ( pev->spawnflags & SF_AUTO_FIREONCE ) + UTIL_Remove( this ); + } +} + +// This trigger will fire when the level spawns (or respawns if not fire once) +// It will check a global state before firing. It supports delay and killtargets + + class CAutoTrigger : public CBaseDelay { public: @@ -173,7 +271,7 @@ void CAutoTrigger::Spawn( void ) void CAutoTrigger::Precache( void ) { - pev->nextthink = gpGlobals->time + 0.1f; + pev->nextthink = gpGlobals->time + 0.1f; // m_flDelay used automatically in SUB_UseTargets } void CAutoTrigger::Think( void ) @@ -186,6 +284,137 @@ void CAutoTrigger::Think( void ) } } +// +// This trigger will fire when the level spawns (or respawns if not fire once) +// It will check a global state before firing. It supports delay and killtargets +// + +class CTriggerAutoBot : public CBaseDelay +{ +public: + void KeyValue( KeyValueData *pkvd ); + void Spawn( void ); + void Precache( void ); + void Think( void ); + + int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } +}; +LINK_ENTITY_TO_CLASS( trigger_autobot, CTriggerAutoBot ); + +void CTriggerAutoBot::KeyValue( KeyValueData *pkvd ) +{ + CBaseDelay::KeyValue( pkvd ); +} + + +void CTriggerAutoBot::Spawn( void ) +{ + Precache(); +} + + +void CTriggerAutoBot::Precache( void ) +{ + pev->nextthink = gpGlobals->time + 9.0; +} + + +void CTriggerAutoBot::Think( void ) +{ + if (!bDecay) + return; + + if (!g_pGameRules->IsCoOp()) + return; + + CDecayRules *g_pDecayRules; + g_pDecayRules = (CDecayRules*)g_pGameRules; + if (g_pDecayRules->PlayersCount == 1) + { + char cmd[40]; + sprintf(cmd, "addbot\n" ); + SERVER_COMMAND(cmd); + } + + UTIL_Remove( this ); +} + +// +// fade screen and call endsection upon level spawn if mission is locked +// + +LINK_ENTITY_TO_CLASS( trigger_lockedmission, CTriggerLockedMission ); + +void CTriggerLockedMission::Spawn( void ) +{ + pev->nextthink = 0; + pev->message = ALLOC_STRING( "DYLOCKED" ); + m_flDelay = 7; +} + +void CTriggerLockedMission::Lock( void ) +{ + CBasePlayer *client; + client = NULL; + while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) + { + if ( !client->pev ) + continue; + if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) + continue; + client->EnableControl(FALSE); + } + UTIL_ScreenFadeAll( Vector(0, 0, 0), 7, 3, 255, FFADE_OUT ); + UTIL_ShowMessageAll( STRING(pev->message) ); + + pev->nextthink = gpGlobals->time + 7; +} + +void CTriggerLockedMission::Think( void ) +{ + if ( pev->message ) + g_engfuncs.pfnEndSection(STRING(pev->message)); + else + g_engfuncs.pfnEndSection( "Decay" ); +} + +// +// trigger for kicking the players (bots) +// + +LINK_ENTITY_TO_CLASS( trigger_kicker, CTriggerKicker ); + +void CTriggerKicker::Spawn( void ) +{ + pev->nextthink = 0; + m_flDelay = 3; +} + +void CTriggerKicker::KickPlayer( CBasePlayer *pKickMe ) +{ + ALERT( at_console, "Going to kick spare player %s!\n", STRING( pKickMe->pev->netname) ); + pPlayerToKick = pKickMe; + pev->nextthink = gpGlobals->time + m_flDelay; + // TODO: send message to player to display Decay Spare player screen here? +} + +void CTriggerKicker::Think( void ) +{ + if (!bDecay) + return; + + if (!g_pGameRules->IsCoOp()) + return; + + char cmd[128]; + sprintf(cmd, "kick \"%s\"\n", STRING(pPlayerToKick->pev->netname) ); + SERVER_COMMAND(cmd); + + UTIL_Remove( this ); +} + +// end of kicker code + #define SF_RELAY_FIREONCE 0x0001 class CTriggerRelay : public CBaseDelay @@ -385,7 +614,19 @@ void CMultiManager::ManagerThink( void ) time = gpGlobals->time - m_startTime; while( m_index < m_cTargets && m_flTargetDelay[m_index] <= time ) { - FireTargets( STRING( m_iTargetName[m_index] ), m_hActivator, this, USE_TOGGLE, 0 ); + if ( pev->spawnflags & SF_MM_KILLTARGETS ) + { + CBaseEntity *pEntity = NULL; + while (pEntity = UTIL_FindEntityByTargetname(pEntity, STRING( m_iTargetName[ m_index ] ))) + { + //ALERT( at_console, "Killing %s...\n", STRING( m_iTargetName[ m_index ] ) ); + UTIL_Remove( pEntity ); + } + } else + { + FireTargets( STRING( m_iTargetName[ m_index ] ), m_hActivator, this, USE_TOGGLE, 0 ); + } + m_index++; } @@ -482,6 +723,11 @@ void CRenderFxManager::Spawn( void ) pev->solid = SOLID_NOT; } +inline edict_t *FIND_ENTITY_BY_NETNAME(edict_t *entStart, const char *pszName) +{ + return FIND_ENTITY_BY_STRING(entStart, "netname", pszName); +} + void CRenderFxManager::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !FStringNull( pev->target ) ) @@ -541,6 +787,10 @@ void CRenderFxManager::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T class CBaseTrigger : public CBaseToggle { public: + int m_iPlayersInside; //TODO: implement saverestore + byte m_bCurrentPlayer, m_bPreviousPlayer; + float m_flLastTouch; + void EXPORT TeleportTouch( CBaseEntity *pOther ); void KeyValue( KeyValueData *pkvd ); void EXPORT MultiTouch( CBaseEntity *pOther ); @@ -612,6 +862,7 @@ public: }; LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt ) +LINK_ENTITY_TO_CLASS( trigger_new_hurt, CTriggerHurt ) // // trigger_monsterjump @@ -911,6 +1162,30 @@ void CTriggerHurt::RadiationThink( void ) // void CBaseTrigger::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { + //Decay's trigger_new_hurt used only mission ht04dampen + bool m_bIsNewHurt = !strcmp(STRING(pev->classname), "trigger_new_hurt"); + if ( m_bIsNewHurt ) + { + bool m_bIsOn = ( pev->solid == SOLID_TRIGGER ); + + if ( useType == USE_TOGGLE ) + m_bIsOn = !m_bIsOn; + if ( useType == USE_ON ) + m_bIsOn = true; + if ( useType == USE_OFF ) + m_bIsOn = false; + + if ( m_bIsOn ) + { + pev->solid = SOLID_TRIGGER; + gpGlobals->force_retouch++; + } else + pev->solid = SOLID_NOT; + + UTIL_SetOrigin( pev, pev->origin ); + return; + } + if( pev->solid == SOLID_NOT ) { // if the trigger is off, turn it on @@ -1144,6 +1419,17 @@ void CTriggerOnce::Spawn( void ) void CBaseTrigger::MultiTouch( CBaseEntity *pOther ) { + if (pOther->IsPlayer()) + { + CBasePlayer *g_pPlayer; + g_pPlayer = (CBasePlayer*)pOther; + //uncommentme + //ALERT( at_console, "(%s) inside %d need %d\n", STRING(pev->targetname), g_pPlayer->m_iDecayId, m_iPlayerIndex ); + + //DECAY debug: + //ALERT( at_console, "trigger %s targets %s\n", STRING(pev->targetname), STRING(pev->target) ); + } + entvars_t *pevToucher; pevToucher = pOther->pev; @@ -1163,7 +1449,60 @@ void CBaseTrigger::MultiTouch( CBaseEntity *pOther ) return; // not facing the right way } #endif + // Decay's specific player check + // DONE: bug found - when player 1 enters trigger, then exists and player 2 enters trigger + // it acts as if they both where here! :) How to solve that??? + if ( pev->spawnflags & SF_SPECIFICPLAYER ) + { + if (pOther->IsPlayer()) + { + CBasePlayer *g_pPlayer; + g_pPlayer = (CBasePlayer*)pOther; + + if (m_iPlayerIndex != 0) + { // check if Gina or Colette + if (g_pPlayer->m_iDecayId != m_iPlayerIndex) + return; + } else + { // check if both are inside + + m_bPreviousPlayer = m_bCurrentPlayer; + m_bCurrentPlayer = g_pPlayer->m_iDecayId; + + SetBits( m_iPlayersInside, g_pPlayer->m_iDecayId); + + byte m_bAnotherPlayer; + if ( m_bCurrentPlayer == 1) + m_bAnotherPlayer = 2; + else + m_bAnotherPlayer = 1; + + if (m_flLastTouch < gpGlobals->time - 0.1) + ClearBits( m_iPlayersInside, m_bAnotherPlayer ); + m_flLastTouch = gpGlobals->time; + + //m_iPlayersInside = m_iPlayersInside & g_pPlayer->m_iDecayId; + if (!(m_iPlayersInside & PF_PLAYER1) || !(m_iPlayersInside & PF_PLAYER2)) + return; + + /*if ( m_bCurrentPlayer == m_bPreviousPlayer ) + { + ClearBits( m_iPlayersInside, m_bAnotherPlayer ); + return; + }*/ + } + //m_flWait = -1; + } + } ActivateMultiTrigger( pOther ); + //if ( pev->spawnflags & SF_SPECIFICPLAYER ) + // if (m_iPlayerIndex == 0) + // m_iPlayersInside = 0; + + + //if ( pev->spawnflags & SF_SPECIFICPLAYER ) + // SetTouch( NULL ); + m_iPlayersInside = 0; } } @@ -1239,10 +1578,15 @@ void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US m_cTriggersLeft--; m_hActivator = pActivator; + ALERT( at_console, "(trigger_counter::%s) used, left: %d\n", STRING( this->pev->classname ), m_cTriggersLeft ); + if( m_cTriggersLeft < 0 ) return; - BOOL fTellActivator = + if (m_cTriggersLeft != 0) + return; + + /*BOOL fTellActivator = ( m_hActivator != 0 ) && m_hActivator->IsPlayer() && !FBitSet( pev->spawnflags, SPAWNFLAG_NOMESSAGE ); @@ -1272,9 +1616,22 @@ void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, US // !!!UNDONE: I don't think we want these Quakesque messages if( fTellActivator ) - ALERT( at_console, "Sequence completed!" ); + ALERT( at_console, "Sequence completed!" );*/ - ActivateMultiTrigger( m_hActivator ); + ALERT( at_console, "(trigger_counter::%s) sequence done! Firing %s\n", STRING( this->pev->classname ), STRING( this->pev->target ) ); + + if ( m_hActivator ) // Vyacheslav Dzhura: trigger_counter issue - access violation when counter activated by func_breakable + ActivateMultiTrigger( m_hActivator ); + else + ActivateMultiTrigger( pCaller ); + + if (m_iszKillTarget) + { + ALERT(at_console, "%s\n", STRING( m_iszKillTarget )); + CBaseEntity *pEntity = NULL; + pEntity = UTIL_FindEntityByTargetname(pEntity, STRING( m_iszKillTarget )); + UTIL_Remove( pEntity ); + } } /*QUAKED trigger_counter (.5 .5 .5) ? nomessage @@ -1926,9 +2283,24 @@ void CBaseTrigger::TeleportTouch( CBaseEntity *pOther ) } } - pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( pev->target ) ); - if( FNullEnt( pentTarget ) ) - return; + if ( pev->spawnflags & SF_SPECIFICPLAYER ) + { + if (pOther->IsPlayer()) + { + CBasePlayer *g_pPlayer; + g_pPlayer = (CBasePlayer*)pOther; + + if (m_iPlayerIndex != 0) + { // check if Gina or Colette + if (g_pPlayer->m_iDecayId != m_iPlayerIndex) + return; + } // Vyacheslav Dzhura: no need in "else", check if both are inside can't be applied for teleport + } + } + + pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pev->target) ); + if (FNullEnt(pentTarget)) + return; Vector tmp = VARS( pentTarget )->origin; @@ -2048,8 +2420,29 @@ void CTriggerEndSection::EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pC if( pev->message ) { - g_engfuncs.pfnEndSection( STRING( pev->message ) ); + if (!IS_DEDICATED_SERVER()) + g_engfuncs.pfnEndSection(STRING(pev->message)); + else + { + // + // FOR DEDICATED SERVER, SKIP TO THE FIRST MISSION + // + + static char szNextMap[128]; + sprintf( szNextMap, "null" ); + + if (g_pGameRules->IsCoOp()) + { + CDecayRules *g_pDecayRules = (CDecayRules*)g_pGameRules; + sprintf( szNextMap, g_pDecayRules->getDecayMapName( 1 ) ); + } + bool bHasNextMap = ( strcmp( szNextMap, "null" ) != 0 ); + + if ( bHasNextMap ) + CHANGE_LEVEL( szNextMap, NULL ); + } } + UTIL_Remove( this ); } diff --git a/dlls/turret.cpp b/dlls/turret.cpp index 556d7ede..fdddf594 100644 --- a/dlls/turret.cpp +++ b/dlls/turret.cpp @@ -940,7 +940,10 @@ void CBaseTurret::TurretDeath( void ) else m_vecGoalAngles.x = -90; - SetTurretAnim( TURRET_ANIM_DIE ); + SetTurretAnim( TURRET_ANIM_DIE ); + + // fixed for Decay - miniturrets now process TriggerConditions \ TriggerTargets + FCheckAITrigger(); EyeOn(); } diff --git a/dlls/util.h b/dlls/util.h index f890f95d..351cc040 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -567,8 +567,11 @@ private: void UTIL_SetGroupTrace( int groupmask, int op ); void UTIL_UnsetGroupTrace( void ); +Vector UTIL_Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ); int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); float UTIL_WeaponTimeBase( void ); + +void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity ); #endif // UTIL_H diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index a054a5e2..5ef7792b 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -320,6 +320,11 @@ void W_Precache( void ) // 9mm ammo box UTIL_PrecacheOther( "ammo_9mmbox" ); + // displacer + UTIL_PrecacheOtherWeapon( "weapon_displacer" ); + + UTIL_PrecacheOtherWeapon( "weapon_vorti" ); + #if !OEM_BUILD && !HLDEMO_BUILD // python UTIL_PrecacheOtherWeapon( "weapon_357" ); @@ -428,11 +433,33 @@ void CBasePlayerItem::SetObjectCollisionBox( void ) pev->absmax = pev->origin + Vector( 24, 24, 16 ); } +void CBasePlayerItem :: KeyValue( KeyValueData *pkvd ) +{ + if (FStrEq(pkvd->szKeyName, "player_index")) + { + DecayPlayerIndex = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else + { + CBaseDelay::KeyValue( pkvd ); + } +} + //========================================================= // Sets up movetype, size, solidtype for a new weapon. //========================================================= void CBasePlayerItem::FallInit( void ) { + if (pev->spawnflags & 1) + { + pev->solid = SOLID_TRIGGER; + UTIL_SetOrigin( pev, pev->origin );// link into world. + SetTouch (DefaultTouch); + SetThink (NULL); + return; + } + pev->movetype = MOVETYPE_TOSS; pev->solid = SOLID_BBOX; @@ -826,7 +853,15 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) } if( m_pNext ) - m_pNext->UpdateClientData( pPlayer ); + { + if ( m_pNext->m_iId >= 0 ) + m_pNext->UpdateClientData( pPlayer ); + else + { + ALERT( at_console, "'%s'->m_pNext sends to invalid class!\n", this->pszName ); + return 0; + } + } return 1; } @@ -1246,7 +1281,14 @@ void CWeaponBox::Precache( void ) //========================================================= void CWeaponBox::KeyValue( KeyValueData *pkvd ) { - if( m_cAmmoTypes < MAX_AMMO_SLOTS ) + if ( FStrEq(pkvd->szKeyName, "player_index") ) + { + m_iPlayerIndex = atoi( pkvd->szValue ); + pkvd->fHandled = true; + return; + } + + if (( m_cAmmoTypes < MAX_AMMO_SLOTS ) && (!FStrEq(pkvd->szKeyName, "player_index"))) { PackAmmo( ALLOC_STRING( pkvd->szKeyName ), atoi( pkvd->szValue ) ); m_cAmmoTypes++;// count this new ammo type. diff --git a/dlls/weapons.h b/dlls/weapons.h index e638af5e..777ed933 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -102,6 +102,7 @@ public: #define SNARK_WEIGHT 5 #define SATCHEL_WEIGHT -10 #define TRIPMINE_WEIGHT -10 +#define DISPLACER_WEIGHT 20 // weapon clip/carry ammo capacities #define URANIUM_MAX_CARRY 100 @@ -134,6 +135,7 @@ public: #define SATCHEL_MAX_CLIP WEAPON_NOCLIP #define TRIPMINE_MAX_CLIP WEAPON_NOCLIP #define SNARK_MAX_CLIP WEAPON_NOCLIP +#define DISPLACER_MAX_CLIP WEAPON_NOCLIP // the default amount of ammo that comes with each gun when it spawns #define GLOCK_DEFAULT_GIVE 17 @@ -1051,4 +1053,65 @@ public: private: unsigned short m_usSnarkFire; }; + +class CTeleBall: public CBaseMonster +{ +public: + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void Spawn( void ); + void Precache( void ); + void PlayEffect( Vector Origin, CBaseEntity *pEntity); + + void EXPORT TeleportThink( void );//think when fly + void EXPORT TeleportKill( void ); //think when kill + + void EXPORT TeleportTouch( CBaseEntity *pOther ); //touch 'n kill + + CBeam *pBeam[5]; + int ring_sprite; + + Vector m_vecIdeal ; + EHANDLE m_hTouch ; +}; + +class CDisplacer : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( ) { return 5; } //slot 5 + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + int AddToPlayer( CBasePlayer *pPlayer ); + + void Holster( int skiplocal = 0 ); + void Reload( void ); + void WeaponIdle( void ); + void PlayEffect( Vector Origin); + BOOL Deploy( void ); + + void EXPORT SpinupThink( void ); + void EXPORT FireThink( void ); + + BOOL PlayEmptySound( void ); + + /* + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + }*/ + +private: + CBeam *pBeam; +}; + #endif // WEAPONS_H diff --git a/dlls/world.cpp b/dlls/world.cpp index 3331d29e..d62cca40 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -451,6 +451,7 @@ LINK_ENTITY_TO_CLASS( worldspawn, CWorld ) #define SF_WORLD_FORCETEAM 0x0004 // Force teams extern DLL_GLOBAL BOOL g_fGameOver; +BOOL g_startSuit; // When level starts player will automatically receive a suit and game_player_equip will be targeted void CWorld::Spawn( void ) { @@ -626,18 +627,19 @@ void CWorld::Precache( void ) // g-cont. moved here to right restore global WaveHeight on save\restore level CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); + //ALERT( at_console, "Chapter title variable set to: '%s'\n", STRING(pev->netname) ); if( pev->netname ) { ALERT( at_aiconsole, "Chapter title: %s\n", STRING( pev->netname ) ); - CBaseEntity *pEntity = CBaseEntity::Create( "env_message", g_vecZero, g_vecZero, NULL ); + CBaseEntity *pEntity = CBaseEntity::Create( "env_message", g_vecZero, g_vecZero, edict() ); if( pEntity ) { pEntity->SetThink( &CBaseEntity::SUB_CallUseToggle ); pEntity->pev->message = pev->netname; pev->netname = 0; - pEntity->pev->nextthink = gpGlobals->time + 0.3f; + pEntity->pev->nextthink = gpGlobals->time + 1.3f; pEntity->pev->spawnflags = SF_MESSAGE_ONCE; - } + } else ALERT( at_aiconsole, "Chapter title message entity was not created!\n"); } if( pev->spawnflags & SF_WORLD_DARK ) diff --git a/dlls/xen.cpp b/dlls/xen.cpp index a02b4847..6cc5efc9 100644 --- a/dlls/xen.cpp +++ b/dlls/xen.cpp @@ -17,11 +17,12 @@ #include "cbase.h" #include "animation.h" #include "effects.h" +#include "actanimating.h" #define XEN_PLANT_GLOW_SPRITE "sprites/flare3.spr" #define XEN_PLANT_HIDE_TIME 5 -class CActAnimating : public CBaseAnimating +/*class CActAnimating : public CBaseAnimating { public: void SetActivity( Activity act ); @@ -55,6 +56,7 @@ void CActAnimating::SetActivity( Activity act ) ResetSequenceInfo(); } } +*/ class CXenPLight : public CActAnimating { diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index e520238c..e2691032 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -1962,6 +1962,7 @@ void PM_UnDuck( void ) VectorCopy( pmove->origin, newOrigin ); + /* if( pmove->onground != -1 ) { for( i = 0; i < 3; i++ )