diff --git a/sp/src/game/client/C_Env_Projected_Texture.h b/sp/src/game/client/C_Env_Projected_Texture.h index df916201..6fbb6f12 100644 --- a/sp/src/game/client/C_Env_Projected_Texture.h +++ b/sp/src/game/client/C_Env_Projected_Texture.h @@ -88,6 +88,11 @@ private: int m_nSpotlightTextureFrame; int m_nShadowQuality; #ifdef MAPBASE + float m_flConstantAtten; + float m_flLinearAtten; + float m_flQuadraticAtten; + float m_flShadowAtten; + bool m_bAlwaysDraw; //bool m_bProjectedTextureVersion; #endif diff --git a/sp/src/game/client/c_baseflex.cpp b/sp/src/game/client/c_baseflex.cpp index d13e5a75..606ba009 100644 --- a/sp/src/game/client/c_baseflex.cpp +++ b/sp/src/game/client/c_baseflex.cpp @@ -1149,9 +1149,7 @@ void C_BaseFlex::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightC { // hack in an initialization LinkToGlobalFlexControllers( GetModelPtr() ); -#ifdef MAPBASE - m_iBlink = AddGlobalFlexController( "blink" ); -#else +#ifndef MAPBASE m_iBlink = AddGlobalFlexController( "UH" ); #endif diff --git a/sp/src/game/client/c_effects.cpp b/sp/src/game/client/c_effects.cpp index b2a5f21c..447b6494 100644 --- a/sp/src/game/client/c_effects.cpp +++ b/sp/src/game/client/c_effects.cpp @@ -33,14 +33,7 @@ Vector g_vSplashColor( 0.5, 0.5, 0.5 ); float g_flSplashScale = 0.15; float g_flSplashLifetime = 0.5f; float g_flSplashAlpha = 0.3f; -#ifdef MAPBASE -// Rain splash stuff based on Tony Sergei's VDC code -// (r_RainParticle can be found in effects.cpp on the server as well) -ConVar r_RainParticle("r_RainParticle", "Rain_01_impact", FCVAR_CHEAT | FCVAR_REPLICATED); -ConVar r_RainSplashPercentage( "r_RainSplashPercentage", "99", FCVAR_CHEAT ); // N% chance of a rain particle making a splash. -#else ConVar r_RainSplashPercentage( "r_RainSplashPercentage", "20", FCVAR_CHEAT ); // N% chance of a rain particle making a splash. -#endif float GUST_INTERVAL_MIN = 1; @@ -331,20 +324,6 @@ inline bool CClient_Precipitation::SimulateRain( CPrecipitationParticle* pPartic } } -#ifdef MAPBASE - // Based on Tony Sergi's code on the VDC. This version re-uses m_Splashes instead of dispatching the effect immediately. - trace_t trace; - UTIL_TraceLine(vOldPos, pParticle->m_Pos, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trace); - - if (trace.fraction < 1 || trace.DidHit()) - { - if (RandomInt(0, 100) <= r_RainSplashPercentage.GetInt()) - m_Splashes.AddToTail( trace.endpos ); - - // Tell the framework it's time to remove the particle from the list - return false; - } -#else // No longer in the air? punt. if ( !IsInAir( pParticle->m_Pos ) ) { @@ -365,7 +344,6 @@ inline bool CClient_Precipitation::SimulateRain( CPrecipitationParticle* pPartic // Tell the framework it's time to remove the particle from the list return false; } -#endif // We still want this particle return true; @@ -572,15 +550,7 @@ void CClient_Precipitation::CreateWaterSplashes() if ( CurrentViewForward().Dot( vSplash - CurrentViewOrigin() ) > 1 ) { -#ifdef MAPBASE - // Use a particle or - if ( r_RainParticle.GetString()[0] != NULL ) - DispatchParticleEffect(r_RainParticle.GetString(), vSplash, QAngle(RandomFloat(0, 360), RandomFloat(0, 360), RandomFloat(0, 360)), NULL); - else - FX_WaterRipple( vSplash, g_flSplashScale, &g_vSplashColor, g_flSplashLifetime, g_flSplashAlpha ); -#else FX_WaterRipple( vSplash, g_flSplashScale, &g_vSplashColor, g_flSplashLifetime, g_flSplashAlpha ); -#endif } } m_Splashes.Purge(); @@ -698,13 +668,6 @@ void CClient_Precipitation::Precache( ) case PRECIPITATION_TYPE_RAIN: Assert( m_nPrecipType == PRECIPITATION_TYPE_RAIN ); -#ifdef MAPBASE - if (r_RainParticle.GetString()[0] != NULL) - { - PrecacheParticleSystem( r_RainParticle.GetString() ); - DevMsg("Rain particle system \"%s\" precached!\n", r_RainParticle.GetString()); - } -#endif m_Speed = RAIN_SPEED; m_MatHandle = materials->FindMaterial( "particle/rain", TEXTURE_GROUP_CLIENT_EFFECTS ); m_InitialRamp = 1.0f; diff --git a/sp/src/game/client/c_env_projectedtexture.cpp b/sp/src/game/client/c_env_projectedtexture.cpp index f4e6cffb..c78cddb2 100644 --- a/sp/src/game/client/c_env_projectedtexture.cpp +++ b/sp/src/game/client/c_env_projectedtexture.cpp @@ -56,6 +56,10 @@ IMPLEMENT_CLIENTCLASS_DT( C_EnvProjectedTexture, DT_EnvProjectedTexture, CEnvPro RecvPropFloat( RECVINFO( m_flFarZ ) ), RecvPropInt( RECVINFO( m_nShadowQuality ) ), #ifdef MAPBASE + RecvPropFloat( RECVINFO( m_flConstantAtten ) ), + RecvPropFloat( RECVINFO( m_flLinearAtten ) ), + RecvPropFloat( RECVINFO( m_flQuadraticAtten ) ), + RecvPropFloat( RECVINFO( m_flShadowAtten ) ), RecvPropBool( RECVINFO( m_bAlwaysDraw ) ), // Not needed on the client right now, change when it actually is needed @@ -89,6 +93,10 @@ C_EnvProjectedTexture *C_EnvProjectedTexture::Create( ) pEnt->m_bState = true; #ifdef MAPBASE pEnt->m_bAlwaysDraw = false; + pEnt->m_flConstantAtten = 0.0f; + pEnt->m_flLinearAtten = 100.0f; + pEnt->m_flQuadraticAtten = 0.0f; + pEnt->m_flShadowAtten = 0.0f; //pEnt->m_bProjectedTextureVersion = 1; #endif @@ -381,18 +389,23 @@ void C_EnvProjectedTexture::UpdateLight( void ) float flAlpha = m_flCurrentLinearFloatLightAlpha * ( 1.0f / 255.0f ); - state.m_fQuadraticAtten = 0.0; - state.m_fLinearAtten = 100; - state.m_fConstantAtten = 0.0f; - state.m_FarZAtten = m_flFarZ; #ifdef MAPBASE + state.m_fConstantAtten = m_flConstantAtten; + state.m_fLinearAtten = m_flLinearAtten; + state.m_fQuadraticAtten = m_flQuadraticAtten; + state.m_FarZAtten = m_flFarZ; state.m_Color[0] = (m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * flAlpha) * m_flCurrentBrightnessScale; state.m_Color[1] = (m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * flAlpha) * m_flCurrentBrightnessScale; state.m_Color[2] = (m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * flAlpha) * m_flCurrentBrightnessScale; state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); + state.m_flShadowAtten = m_flShadowAtten; #else + state.m_fQuadraticAtten = 0.0; + state.m_fLinearAtten = 100; + state.m_fConstantAtten = 0.0f; + state.m_FarZAtten = m_flFarZ; state.m_fBrightnessScale = m_flBrightnessScale; state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * flAlpha; state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * flAlpha; diff --git a/sp/src/game/client/c_world.cpp b/sp/src/game/client/c_world.cpp index 3ae6bdcc..44a59723 100644 --- a/sp/src/game/client/c_world.cpp +++ b/sp/src/game/client/c_world.cpp @@ -59,6 +59,9 @@ BEGIN_RECV_TABLE( C_World, DT_World ) RecvPropFloat(RECVINFO(m_flMinPropScreenSpaceWidth)), RecvPropString(RECVINFO(m_iszDetailSpriteMaterial)), RecvPropInt(RECVINFO(m_bColdWorld)), +#ifdef MAPBASE + RecvPropString(RECVINFO(m_iszChapterTitle)), +#endif END_RECV_TABLE() diff --git a/sp/src/game/client/c_world.h b/sp/src/game/client/c_world.h index 3cdbd6a0..5f1538f9 100644 --- a/sp/src/game/client/c_world.h +++ b/sp/src/game/client/c_world.h @@ -56,6 +56,9 @@ public: float m_flMinPropScreenSpaceWidth; float m_flMaxPropScreenSpaceWidth; bool m_bColdWorld; +#ifdef MAPBASE + char m_iszChapterTitle[64]; +#endif private: void RegisterSharedActivities( void ); diff --git a/sp/src/game/client/client_mapbase.vpc b/sp/src/game/client/client_mapbase.vpc index 72cb3fc8..9a4645d0 100644 --- a/sp/src/game/client/client_mapbase.vpc +++ b/sp/src/game/client/client_mapbase.vpc @@ -26,6 +26,7 @@ $Project { $File "$SRCDIR\game\shared\mapbase\mapbase_shared.cpp" $File "$SRCDIR\game\shared\mapbase\mapbase_rpc.cpp" + $File "$SRCDIR\game\shared\mapbase\mapbase_game_log.cpp" $File "$SRCDIR\game\shared\mapbase\MapEdit.cpp" $File "$SRCDIR\game\shared\mapbase\MapEdit.h" diff --git a/sp/src/game/client/fx.cpp b/sp/src/game/client/fx.cpp index b7f12cbd..78a70a77 100644 --- a/sp/src/game/client/fx.cpp +++ b/sp/src/game/client/fx.cpp @@ -1256,6 +1256,13 @@ void FX_BuildTeslaHitbox( const CEffectData &data ) { Vector vColor( 1, 1, 1 ); +#ifdef MAPBASE + if ( data.m_bCustomColors ) + { + vColor = data.m_CustomColors.m_vecColor1; + } +#endif + C_BaseEntity *pEntity = ClientEntityList().GetEnt( data.entindex() ); C_BaseAnimating *pAnimating = pEntity ? pEntity->GetBaseAnimating() : NULL; if (!pAnimating) diff --git a/sp/src/game/client/hl2/c_script_intro.cpp b/sp/src/game/client/hl2/c_script_intro.cpp index 1c0da0e8..66c59aa8 100644 --- a/sp/src/game/client/hl2/c_script_intro.cpp +++ b/sp/src/game/client/hl2/c_script_intro.cpp @@ -59,6 +59,7 @@ private: #ifdef MAPBASE bool m_bDrawSky; bool m_bDrawSky2; + bool m_bUseEyePosition; #endif // Fades @@ -81,6 +82,7 @@ IMPLEMENT_CLIENTCLASS_DT( C_ScriptIntro, DT_ScriptIntro, CScriptIntro ) #ifdef MAPBASE RecvPropBool( RECVINFO( m_bDrawSky ) ), RecvPropBool( RECVINFO( m_bDrawSky2 ) ), + RecvPropBool( RECVINFO( m_bUseEyePosition ) ), #endif // Fov & fov blends @@ -181,10 +183,13 @@ void C_ScriptIntro::PostDataUpdate( DataUpdateType_t updateType ) // If it's a point_camera and it's ortho, send it to the intro data // Change this code if the purpose of m_hCameraEntity in intro data ever goes beyond ortho - C_PointCamera *pCamera = dynamic_cast(m_hCameraEntity.Get()); - if (pCamera && pCamera->IsOrtho()) + if ( Q_strncmp(m_hCameraEntity->GetClassname(), "point_camera", 12) == 0 ) { - m_IntroData.m_hCameraEntity = m_hCameraEntity; + C_PointCamera *pCamera = dynamic_cast(m_hCameraEntity.Get()); + if (pCamera && pCamera->IsOrtho()) + { + m_IntroData.m_hCameraEntity = m_hCameraEntity; + } } #endif } @@ -265,8 +270,21 @@ void C_ScriptIntro::ClientThink( void ) if ( m_hCameraEntity ) { +#ifdef MAPBASE + if ( m_bUseEyePosition ) + { + m_IntroData.m_vecCameraView = m_hCameraEntity->EyePosition(); + m_IntroData.m_vecCameraViewAngles = m_hCameraEntity->EyeAngles(); + } + else + { + m_IntroData.m_vecCameraView = m_hCameraEntity->GetAbsOrigin(); + m_IntroData.m_vecCameraViewAngles = m_hCameraEntity->GetAbsAngles(); + } +#else m_IntroData.m_vecCameraView = m_hCameraEntity->GetAbsOrigin(); m_IntroData.m_vecCameraViewAngles = m_hCameraEntity->GetAbsAngles(); +#endif } CalculateFOV(); diff --git a/sp/src/game/client/view.cpp b/sp/src/game/client/view.cpp index 333a2756..a7be86f3 100644 --- a/sp/src/game/client/view.cpp +++ b/sp/src/game/client/view.cpp @@ -736,7 +736,11 @@ void CViewRender::SetUpViews() float flFOVOffset = fDefaultFov - view.fov; //Adjust the viewmodel's FOV to move with any FOV offsets on the viewer's end +#ifdef MAPBASE + view.fovViewmodel = fabs(g_pClientMode->GetViewModelFOV()) - flFOVOffset; +#else view.fovViewmodel = g_pClientMode->GetViewModelFOV() - flFOVOffset; +#endif if ( UseVR() ) { diff --git a/sp/src/game/server/RagdollBoogie.cpp b/sp/src/game/server/RagdollBoogie.cpp index 9233872e..0d54418d 100644 --- a/sp/src/game/server/RagdollBoogie.cpp +++ b/sp/src/game/server/RagdollBoogie.cpp @@ -17,6 +17,7 @@ #include "IEffects.h" #ifdef MAPBASE #include "saverestore_utlvector.h" +#include "interval.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -40,6 +41,10 @@ BEGIN_DATADESC( CRagdollBoogie ) // Think this should be handled by StartTouch/etc. // DEFINE_FIELD( m_nSuppressionCount, FIELD_INTEGER ), +#ifdef MAPBASE + DEFINE_FIELD( m_vecColor, FIELD_VECTOR ), +#endif + DEFINE_FUNCTION( BoogieThink ), DEFINE_FUNCTION( ZapThink ), @@ -53,7 +58,11 @@ LINK_ENTITY_TO_CLASS( env_ragdoll_boogie, CRagdollBoogie ); // Input : pTarget - //----------------------------------------------------------------------------- CRagdollBoogie *CRagdollBoogie::Create( CBaseEntity *pTarget, float flMagnitude, +#ifdef MAPBASE + float flStartTime, float flLengthTime, int nSpawnFlags, const Vector *vecColor ) +#else float flStartTime, float flLengthTime, int nSpawnFlags ) +#endif { CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( pTarget ); if ( !pRagdoll ) @@ -67,6 +76,10 @@ CRagdollBoogie *CRagdollBoogie::Create( CBaseEntity *pTarget, float flMagnitude, pBoogie->AttachToEntity( pTarget ); pBoogie->SetBoogieTime( flStartTime, flLengthTime ); pBoogie->SetMagnitude( flMagnitude ); +#ifdef MAPBASE + if (vecColor != NULL) + pBoogie->SetColor( *vecColor ); +#endif pBoogie->Spawn(); return pBoogie; } @@ -118,6 +131,13 @@ void CRagdollBoogie::ZapThink() data.m_nEntIndex = GetMoveParent()->entindex(); data.m_flMagnitude = 4; data.m_flScale = HasSpawnFlags(SF_RAGDOLL_BOOGIE_ELECTRICAL_NARROW_BEAM) ? 1.0f : 2.0f; +#ifdef MAPBASE + if (!m_vecColor.IsZero()) + { + data.m_bCustomColors = true; + data.m_CustomColors.m_vecColor1 = m_vecColor; + } +#endif DispatchEffect( "TeslaHitboxes", data ); } @@ -285,14 +305,19 @@ public: void InputActivate( inputdata_t &inputdata ); void InputDeactivate( inputdata_t &inputdata ); void InputBoogieTarget( inputdata_t &inputdata ); + void InputSetZapColor( inputdata_t &inputdata ); + + bool KeyValue( const char *szKeyName, const char *szValue ); private: float m_flStartTime; - float m_flBoogieLength; + interval_t m_BoogieLength; float m_flMagnitude; - // This allows us to remove active boogies later. - CUtlVector m_Boogies; + Vector m_vecZapColor; + + // This allows us to change or remove active boogies later. + CUtlVector> m_Boogies; }; //----------------------------------------------------------------------------- @@ -301,9 +326,11 @@ private: BEGIN_DATADESC( CPointRagdollBoogie ) DEFINE_KEYFIELD( m_flStartTime, FIELD_FLOAT, "StartTime" ), - DEFINE_KEYFIELD( m_flBoogieLength, FIELD_FLOAT, "BoogieLength" ), + DEFINE_KEYFIELD( m_BoogieLength, FIELD_INTERVAL, "BoogieLength" ), DEFINE_KEYFIELD( m_flMagnitude, FIELD_FLOAT, "Magnitude" ), + DEFINE_KEYFIELD( m_vecZapColor, FIELD_VECTOR, "ZapColor" ), + // Think this should be handled by StartTouch/etc. // DEFINE_FIELD( m_nSuppressionCount, FIELD_INTEGER ), @@ -313,6 +340,7 @@ BEGIN_DATADESC( CPointRagdollBoogie ) DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ), DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ), DEFINE_INPUTFUNC( FIELD_STRING, "BoogieTarget", InputBoogieTarget ), + DEFINE_INPUTFUNC( FIELD_VECTOR, "SetZapColor", InputSetZapColor ), END_DATADESC() @@ -326,7 +354,7 @@ bool CPointRagdollBoogie::ApplyBoogie( CBaseEntity *pTarget, CBaseEntity *pActiv { if (dynamic_cast(pTarget)) { - m_Boogies.AddToTail(CRagdollBoogie::Create(pTarget, m_flMagnitude, gpGlobals->curtime + m_flStartTime, m_flBoogieLength, GetSpawnFlags())); + m_Boogies.AddToTail(CRagdollBoogie::Create(pTarget, m_flMagnitude, gpGlobals->curtime + m_flStartTime, RandomInterval(m_BoogieLength), GetSpawnFlags(), &m_vecZapColor)); } else if (pTarget->MyCombatCharacterPointer()) { @@ -337,7 +365,7 @@ bool CPointRagdollBoogie::ApplyBoogie( CBaseEntity *pTarget, CBaseEntity *pActiv pRagdoll->SetCollisionBounds(CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs()); - m_Boogies.AddToTail(CRagdollBoogie::Create(pRagdoll, m_flMagnitude, gpGlobals->curtime + m_flStartTime, m_flBoogieLength, GetSpawnFlags())); + m_Boogies.AddToTail(CRagdollBoogie::Create(pRagdoll, m_flMagnitude, gpGlobals->curtime + m_flStartTime, RandomInterval(m_BoogieLength), GetSpawnFlags(), &m_vecZapColor)); CTakeDamageInfo ragdollInfo(this, pActivator, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL); ragdollInfo.SetDamagePosition(WorldSpaceCenter()); @@ -382,6 +410,8 @@ void CPointRagdollBoogie::InputDeactivate( inputdata_t &inputdata ) UTIL_Remove(m_Boogies[i]); } + m_Boogies.Purge(); + //m_Boogies.RemoveAll(); } @@ -402,4 +432,47 @@ void CPointRagdollBoogie::InputBoogieTarget( inputdata_t &inputdata ) pEnt = gEntList.FindEntityByName(pEnt, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller); } } + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CPointRagdollBoogie::InputSetZapColor( inputdata_t &inputdata ) +{ + inputdata.value.Vector3D( m_vecZapColor ); + if (!m_vecZapColor.IsZero()) + { + // Turn into ratios of 255 + m_vecZapColor /= 255.0f; + } + + // Apply to existing boogies + for (int i = 0; i < m_Boogies.Count(); i++) + { + if (m_Boogies[i]) + { + m_Boogies[i]->SetColor( m_vecZapColor ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handles key values from the BSP before spawn is called. +//----------------------------------------------------------------------------- +bool CPointRagdollBoogie::KeyValue( const char *szKeyName, const char *szValue ) +{ + if ( FStrEq( szKeyName, "ZapColor" ) ) + { + UTIL_StringToVector(m_vecZapColor.Base(), szValue); + if (!m_vecZapColor.IsZero()) + { + // Turn into ratios of 255 + m_vecZapColor /= 255.0f; + } + } + else + return BaseClass::KeyValue( szKeyName, szValue ); + + return true; +} #endif diff --git a/sp/src/game/server/RagdollBoogie.h b/sp/src/game/server/RagdollBoogie.h index cb52c955..8ca99e81 100644 --- a/sp/src/game/server/RagdollBoogie.h +++ b/sp/src/game/server/RagdollBoogie.h @@ -28,10 +28,18 @@ class CRagdollBoogie : public CBaseEntity DECLARE_CLASS( CRagdollBoogie, CBaseEntity ); public: +#ifdef MAPBASE + static CRagdollBoogie *Create( CBaseEntity *pTarget, float flMagnitude, float flStartTime, float flLengthTime = 0.0f, int nSpawnFlags = 0, const Vector *vecColor = NULL ); +#else static CRagdollBoogie *Create( CBaseEntity *pTarget, float flMagnitude, float flStartTime, float flLengthTime = 0.0f, int nSpawnFlags = 0 ); +#endif static void IncrementSuppressionCount( CBaseEntity *pTarget ); static void DecrementSuppressionCount( CBaseEntity *pTarget ); +#ifdef MAPBASE + void SetColor( const Vector &vecColor ) { m_vecColor = vecColor; } +#endif + void Spawn(); private: @@ -45,6 +53,10 @@ private: float m_flBoogieLength; float m_flMagnitude; int m_nSuppressionCount; + +#ifdef MAPBASE + Vector m_vecColor = Vector(1, 1, 1); +#endif }; #endif // RAGDOLLBOOGIE_H diff --git a/sp/src/game/server/ai_baseactor.cpp b/sp/src/game/server/ai_baseactor.cpp index 30382ab7..03104d49 100644 --- a/sp/src/game/server/ai_baseactor.cpp +++ b/sp/src/game/server/ai_baseactor.cpp @@ -1934,7 +1934,7 @@ void CAI_BaseActor::OnStateChange( NPC_STATE OldState, NPC_STATE NewState ) { PlayExpressionForState( NewState ); -#ifdef HL2_EPISODIC +#if defined(HL2_EPISODIC) || defined(MAPBASE) // If we've just switched states, ensure we stop any scenes that asked to be stopped if ( OldState == NPC_STATE_IDLE ) { diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index ea1b71d5..ede98f5b 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -13705,7 +13705,11 @@ void CAI_BaseNPC::TestPlayerPushing( CBaseEntity *pEntity ) // Heuristic for determining if the player is pushing me away CBasePlayer *pPlayer = ToBasePlayer( pEntity ); +#ifdef MAPBASE + if ( pPlayer && !( pPlayer->GetFlags() & FL_NOTARGET ) && IRelationType( pPlayer ) > D_FR ) +#else if ( pPlayer && !( pPlayer->GetFlags() & FL_NOTARGET ) ) +#endif { if ( (pPlayer->m_nButtons & (IN_FORWARD|IN_BACK|IN_MOVELEFT|IN_MOVERIGHT)) || pPlayer->GetAbsVelocity().AsVector2D().LengthSqr() > 50*50 ) diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index a508837e..18719d43 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -2900,6 +2900,9 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask ) // if ( m_hCine->m_iszPreIdle != NULL_STRING ) { +#ifdef MAPBASE + m_hCine->OnPreIdleSequence( this ); +#endif m_hCine->StartSequence( ( CAI_BaseNPC * )this, m_hCine->m_iszPreIdle, false ); if ( FStrEq( STRING( m_hCine->m_iszPreIdle ), STRING( m_hCine->m_iszPlay ) ) ) { diff --git a/sp/src/game/server/ai_concommands.cpp b/sp/src/game/server/ai_concommands.cpp index 17e77120..ac4e65d7 100644 --- a/sp/src/game/server/ai_concommands.cpp +++ b/sp/src/game/server/ai_concommands.cpp @@ -390,6 +390,149 @@ void CC_NPC_Focus( const CCommand &args ) static ConCommand npc_focus("npc_focus", CC_NPC_Focus, "Displays red line to NPC's enemy (if has one) and blue line to NPC's target entity (if has one)\n\tArguments: {npc_name} / {npc class_name} / no argument picks what player is looking at", FCVAR_CHEAT); ConVar npc_create_equipment("npc_create_equipment", ""); + +#ifdef MAPBASE +extern int EntityFactory_AutoComplete( const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0 ); +extern bool UtlStringLessFunc( const CUtlString &lhs, const CUtlString &rhs ); + +//------------------------------------------------------------------------------ +// Purpose: Create an NPC of the given type +//------------------------------------------------------------------------------ +class CNPCCreateAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback +{ +public: + virtual bool CreateAimed() { return false; } + + virtual void CommandCallback( const CCommand &args ) + { + MDLCACHE_CRITICAL_SECTION(); + + bool allowPrecache = CBaseEntity::IsPrecacheAllowed(); + CBaseEntity::SetAllowPrecache( true ); + + // Try to create entity + CAI_BaseNPC *baseNPC = dynamic_cast< CAI_BaseNPC * >( CreateEntityByName(args[1]) ); + if (baseNPC) + { + baseNPC->KeyValue( "additionalequipment", npc_create_equipment.GetString() ); + + if ( args.ArgC() == 3 ) + { + baseNPC->SetName( AllocPooledString( args[2] ) ); + } + else if ( args.ArgC() > 3 ) + { + baseNPC->SetName( AllocPooledString( args[2] ) ); + + // Pass in any additional parameters. + for ( int i = 3; i + 1 < args.ArgC(); i += 2 ) + { + const char *pKeyName = args[i]; + const char *pValue = args[i+1]; + baseNPC->KeyValue( pKeyName, pValue ); + } + } + + DispatchSpawn(baseNPC); + + // Now attempt to drop into the world + CBasePlayer* pPlayer = UTIL_GetCommandClient(); + trace_t tr; + Vector forward; + QAngle angles; + pPlayer->EyeVectors( &forward ); + + bool bCreateAimed = CreateAimed(); + if (bCreateAimed) + { + VectorAngles( forward, angles ); + angles.x = 0; + angles.z = 0; + } + + AI_TraceLine(pPlayer->EyePosition(), + pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_NPCSOLID, + pPlayer, COLLISION_GROUP_NONE, &tr ); + if ( tr.fraction != 1.0) + { + if (baseNPC->CapabilitiesGet() & bits_CAP_MOVE_FLY) + { + Vector pos = tr.endpos - forward * 36; + baseNPC->Teleport( &pos, bCreateAimed ? &angles : NULL, NULL ); + } + else + { + // Raise the end position a little up off the floor, place the npc and drop him down + tr.endpos.z += 12; + baseNPC->Teleport( &tr.endpos, bCreateAimed ? &angles : NULL, NULL ); + UTIL_DropToFloor( baseNPC, MASK_NPCSOLID ); + } + + // Now check that this is a valid location for the new npc to be + Vector vUpBit = baseNPC->GetAbsOrigin(); + vUpBit.z += 1; + + AI_TraceHull( baseNPC->GetAbsOrigin(), vUpBit, baseNPC->GetHullMins(), baseNPC->GetHullMaxs(), + MASK_NPCSOLID, baseNPC, COLLISION_GROUP_NONE, &tr ); + if ( tr.startsolid || (tr.fraction < 1.0) ) + { + baseNPC->SUB_Remove(); + DevMsg("Can't create %s. Bad Position!\n",args[1]); + NDebugOverlay::Box(baseNPC->GetAbsOrigin(), baseNPC->GetHullMins(), baseNPC->GetHullMaxs(), 255, 0, 0, 0, 0); + } + } + else if (bCreateAimed) + { + baseNPC->Teleport( NULL, &angles, NULL ); + } + + baseNPC->Activate(); + } + CBaseEntity::SetAllowPrecache( allowPrecache ); + } + + virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands ) + { + if ( !g_pGameRules ) + { + return 0; + } + + const char *cmdname = CreateAimed() ? "npc_create_aimed" : "npc_create"; + + char *substring = (char *)partial; + if ( Q_strstr( partial, cmdname ) ) + { + substring = (char *)partial + strlen( cmdname ) + 1; + } + + int checklen = Q_strlen( substring ); + + if (checklen <= 0) + { + // Only show classnames prefixed with "npc" unless the user starts typing other characters + substring = "npc"; + checklen = 3; + } + + CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc ); + return EntityFactory_AutoComplete( cmdname, commands, symbols, substring, checklen ); + } +}; + +static CNPCCreateAutoCompletionFunctor g_NPCCreateAutoComplete; +static ConCommand npc_create("npc_create", &g_NPCCreateAutoComplete, "Creates an NPC of the given type where the player is looking (if the given NPC can actually stand at that location).\n\tArguments: {npc_class_name}", FCVAR_CHEAT, &g_NPCCreateAutoComplete); + +class CNPCCreateAimedAutoCompletionFunctor : public CNPCCreateAutoCompletionFunctor +{ +public: + virtual bool CreateAimed() { return true; } +}; + +static CNPCCreateAimedAutoCompletionFunctor g_NPCCreateAimedAutoComplete; + +static ConCommand npc_create_aimed("npc_create_aimed", &g_NPCCreateAimedAutoComplete, "Creates an NPC aimed away from the player of the given type where the player is looking (if the given NPC can actually stand at that location).\n\tArguments: {npc_class_name}", FCVAR_CHEAT, &g_NPCCreateAimedAutoComplete); +#else //------------------------------------------------------------------------------ // Purpose: Create an NPC of the given type //------------------------------------------------------------------------------ @@ -540,6 +683,7 @@ void CC_NPC_Create_Aimed( const CCommand &args ) CBaseEntity::SetAllowPrecache( allowPrecache ); } static ConCommand npc_create_aimed("npc_create_aimed", CC_NPC_Create_Aimed, "Creates an NPC aimed away from the player of the given type where the player is looking (if the given NPC can actually stand at that location). Note that this only works for npc classes that are already in the world. You can not create an entity that doesn't have an instance in the level.\n\tArguments: {npc_class_name}", FCVAR_CHEAT); +#endif //------------------------------------------------------------------------------ // Purpose: Destroy unselected NPCs @@ -711,6 +855,134 @@ void CC_NPC_Reset( void ) } static ConCommand npc_reset("npc_reset", CC_NPC_Reset, "Reloads schedules for all NPC's from their script files\n\tArguments: -none-", FCVAR_CHEAT); +#ifdef MAPBASE +extern bool UtlStringLessFunc( const CUtlString &lhs, const CUtlString &rhs ); + +//------------------------------------------------------------------------------ +// Purpose : Auto-completes with entities in the entity list, but only uses NPC-derived entities. +// Input : cmdname - The name of the command. +// &commands - Where the complete autocompletes should be sent to. +// substring - The current search query. (only pool entities that start with this) +// checklen - The number of characters to check. +// Output : A pointer to a cUtlRBTRee containing all of the entities. +//------------------------------------------------------------------------------ +static int AutoCompleteNPCs(const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0) +{ + CBaseEntity *pos = NULL; + while ((pos = gEntList.NextEnt(pos)) != NULL) + { + if (!pos->IsNPC()) + continue; + + const char *name = pos->GetClassname(); + if (pos->GetEntityName() == NULL_STRING || Q_strnicmp(STRING(pos->GetEntityName()), substring, checklen)) + { + if (Q_strnicmp(pos->GetClassname(), substring, checklen)) + continue; + } + else + name = STRING(pos->GetEntityName()); + + CUtlString sym = name; + int idx = symbols.Find(sym); + if (idx == symbols.InvalidIndex()) + { + symbols.Insert(sym); + } + + // Too many + if (symbols.Count() >= COMMAND_COMPLETION_MAXITEMS) + break; + } + + // Now fill in the results + for (int i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder(i)) + { + const char *name = symbols[i].String(); + + char buf[512]; + Q_strncpy(buf, name, sizeof(buf)); + Q_strlower(buf); + + CUtlString command; + command = CFmtStr("%s %s", cmdname, buf); + commands.AddToTail(command); + } + + return symbols.Count(); +} + +//------------------------------------------------------------------------------ +// There's a big set of NPC debug commands that do similar operations and +// can fall under this base class for auto-completion, etc. +//------------------------------------------------------------------------------ +class CNPCDebugAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback +{ +public: + virtual const char *CommandName() { return NULL; } + virtual void CommandCallback( const CCommand &args ) + { + SetDebugBits( UTIL_GetCommandClient(), args[1], OVERLAY_NPC_NEAREST_BIT ); + } + + virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands ) + { + if ( !g_pGameRules ) + { + return 0; + } + + const char *cmdname = CommandName(); + + char *substring = (char *)partial; + if ( Q_strstr( partial, cmdname ) ) + { + substring = (char *)partial + strlen( cmdname ) + 1; + } + + int checklen = Q_strlen( substring ); + + if (checklen == 0 || atoi(substring) != 0) + { + // Must be the picker or an entity index + return 0; + } + + CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc ); + return AutoCompleteNPCs(cmdname, commands, symbols, substring, checklen); + } +}; + +#define NPCDebugCommand(name, functor, bit, help) class CNPC##functor##AutoCompletionFunctor : public CNPCDebugAutoCompletionFunctor \ +{ \ +public: \ + virtual const char *CommandName() { return #name; } \ + virtual void CommandCallback( const CCommand &args ) \ + { \ + SetDebugBits( UTIL_GetCommandClient(), args[1], bit ); \ + } \ +}; \ +static CNPC##functor##AutoCompletionFunctor g_NPC##functor##AutoCompletionFunctor; \ +static ConCommand name(#name, &g_NPC##functor##AutoCompletionFunctor, help, FCVAR_CHEAT, &g_NPC##functor##AutoCompletionFunctor); + +NPCDebugCommand( npc_nearest, Nearest, OVERLAY_NPC_NEAREST_BIT, "Draw's a while box around the NPC(s) nearest node\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at " ); +NPCDebugCommand( npc_route, Route, OVERLAY_NPC_ROUTE_BIT, "Displays the current route of the given NPC as a line on the screen. Waypoints along the route are drawn as small cyan rectangles. Line is color coded in the following manner:\n\tBlue - path to a node\n\tCyan - detour around an object (triangulation)\n\tRed - jump\n\tMaroon - path to final target position\n\tArguments: {npc_name} / {npc_class_name} / no argument picks what player is looking at " ); +NPCDebugCommand( npc_select, Select, OVERLAY_NPC_SELECTED_BIT, "Select or deselects the given NPC(s) for later manipulation. Selected NPC's are shown surrounded by a red translucent box\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at " ); +NPCDebugCommand( npc_combat, Combat, OVERLAY_NPC_SQUAD_BIT, "Displays text debugging information about the squad and enemy of the selected NPC (See Overlay Text)\n\tArguments: {npc_name} / {npc class_name} / no argument picks what player is looking at" ); +NPCDebugCommand( npc_tasks, Tasks, OVERLAY_NPC_TASK_BIT, "Displays detailed text debugging information about the all the tasks of the selected NPC current schedule (See Overlay Text)\n\tArguments: {npc_name} / {npc class_name} / no argument picks what player is looking at " ); +NPCDebugCommand( npc_task_text, TaskText, OVERLAY_TASK_TEXT_BIT, "Outputs text debugging information to the console about the all the tasks + break conditions of the selected NPC current schedule\n\tArguments: {npc_name} / {npc class_name} / no argument picks what player is looking at " ); +NPCDebugCommand( npc_conditions, Conditions, OVERLAY_NPC_CONDITIONS_BIT, "Displays all the current AI conditions that an NPC has in the overlay text.\n\tArguments: {npc_name} / {npc class_name} / no argument picks what player is looking at" ); +NPCDebugCommand( npc_viewcone, Viewcone, OVERLAY_NPC_VIEWCONE_BIT, "Displays the viewcone of the NPC (where they are currently looking and what the extents of there vision is)\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at" ); +NPCDebugCommand( npc_relationships, Relationships, OVERLAY_NPC_RELATION_BIT, "Displays the relationships between this NPC and all others.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at" ); +NPCDebugCommand( npc_steering, Steering, OVERLAY_NPC_STEERING_REGULATIONS, "Displays the steering obstructions of the NPC( used to perform local avoidance )\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at" ); + +// For backwards compatibility +void CC_NPC_Squads( const CCommand &args ) +{ + SetDebugBits( UTIL_GetCommandClient(),args[1],OVERLAY_NPC_SQUAD_BIT); +} +static ConCommand npc_squads("npc_squads", CC_NPC_Squads, "Obsolete. Replaced by npc_combat", FCVAR_CHEAT); +#else //------------------------------------------------------------------------------ // Purpose: Show the selected NPC's nearest node //------------------------------------------------------------------------------ @@ -805,6 +1077,7 @@ void CC_NPC_ViewSteeringRegulations( const CCommand &args ) SetDebugBits( UTIL_GetCommandClient(), args[1], OVERLAY_NPC_STEERING_REGULATIONS); } static ConCommand npc_steering("npc_steering", CC_NPC_ViewSteeringRegulations, "Displays the steering obstructions of the NPC (used to perform local avoidance)\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at", FCVAR_CHEAT); +#endif void CC_NPC_ViewSteeringRegulationsAll( void ) { diff --git a/sp/src/game/server/ai_speech.cpp b/sp/src/game/server/ai_speech.cpp index f62918a4..6d47b961 100644 --- a/sp/src/game/server/ai_speech.cpp +++ b/sp/src/game/server/ai_speech.cpp @@ -608,7 +608,11 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t concept, AI_Response *res if ( !result->ShouldntUseScene() ) { // This generates a fake CChoreoScene wrapping the sound.txt name +#ifdef MAPBASE + spoke = SpeakAutoGeneratedScene( response, delay, result, filter ); +#else spoke = SpeakAutoGeneratedScene( response, delay ); +#endif } else { @@ -863,9 +867,17 @@ bool CAI_Expresser::SpeakRawScene( const char *pszScene, float delay, AI_Respons } // This will create a fake .vcd/CChoreoScene to wrap the sound to be played +#ifdef MAPBASE +bool CAI_Expresser::SpeakAutoGeneratedScene( char const *soundname, float delay, AI_Response *response, IRecipientFilter *filter ) +#else bool CAI_Expresser::SpeakAutoGeneratedScene( char const *soundname, float delay ) +#endif { +#ifdef MAPBASE + float speakTime = GetOuter()->PlayAutoGeneratedSoundScene( soundname, delay, response, filter ); +#else float speakTime = GetOuter()->PlayAutoGeneratedSoundScene( soundname ); +#endif if ( speakTime > 0 ) { SpeechMsg( GetOuter(), "SpeakAutoGeneratedScene( %s, %f) %f\n", soundname, delay, speakTime ); diff --git a/sp/src/game/server/ai_speech.h b/sp/src/game/server/ai_speech.h index 41e99980..519df955 100644 --- a/sp/src/game/server/ai_speech.h +++ b/sp/src/game/server/ai_speech.h @@ -208,7 +208,11 @@ protected: bool SpeakRawScene( const char *pszScene, float delay, AI_Response *response, IRecipientFilter *filter = NULL ); // This will create a fake .vcd/CChoreoScene to wrap the sound to be played +#ifdef MAPBASE + bool SpeakAutoGeneratedScene( char const *soundname, float delay, AI_Response *response = NULL, IRecipientFilter *filter = NULL ); +#else bool SpeakAutoGeneratedScene( char const *soundname, float delay ); +#endif void DumpHistories(); diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index 37764b22..aab5d4e3 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -1524,6 +1524,30 @@ bool CBaseCombatCharacter::BecomeRagdollBoogie( CBaseEntity *pKiller, const Vect return true; } +#ifdef MAPBASE +CBaseEntity *CBaseCombatCharacter::BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags, const Vector *vecColor ) +{ + Assert( CanBecomeRagdoll() ); + + CTakeDamageInfo info( pKiller, pKiller, 1.0f, DMG_GENERIC ); + + info.SetDamageForce( forceVector ); + + CBaseEntity *pRagdoll = CreateServerRagdoll( this, 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, true ); + + pRagdoll->SetCollisionBounds( CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs() ); + + CBaseEntity *pBoogie = CRagdollBoogie::Create( pRagdoll, 200, gpGlobals->curtime, duration, flags, vecColor ); + + CTakeDamageInfo ragdollInfo( pKiller, pKiller, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL ); + ragdollInfo.SetDamagePosition( WorldSpaceCenter() ); + ragdollInfo.SetDamageForce( Vector( 0, 0, 1 ) ); + TakeDamage( ragdollInfo ); + + return pBoogie; +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -4020,6 +4044,11 @@ void CBaseCombatCharacter::InputPickupWeaponInstant( inputdata_t &inputdata ) if (inputdata.value.Entity() && inputdata.value.Entity()->IsBaseCombatWeapon()) { CBaseCombatWeapon *pWeapon = inputdata.value.Entity()->MyCombatWeaponPointer(); + if (pWeapon->GetOwner()) + { + Msg("Ignoring PickupWeaponInstant on %s because %s already has an owner\n", GetDebugName(), pWeapon->GetDebugName()); + return; + } if (CBaseCombatWeapon *pExistingWeapon = Weapon_OwnsThisType(pWeapon->GetClassname())) { @@ -4036,6 +4065,8 @@ void CBaseCombatCharacter::InputPickupWeaponInstant( inputdata_t &inputdata ) { Weapon_Equip(pWeapon); } + + pWeapon->OnPickedUp( this ); } else { diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index 31ba9998..c6208cf9 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -333,6 +333,12 @@ public: virtual bool BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags ); +#ifdef MAPBASE + // A version of BecomeRagdollBoogie() that allows the color to change and returns the entity itself instead. + // In order to avoid breaking anything, it doesn't change the original function. + virtual CBaseEntity *BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags, const Vector *vecColor ); +#endif + CBaseEntity *FindHealthItem( const Vector &vecPosition, const Vector &range ); diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 0f440a9d..1e5dc43e 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2037,6 +2037,8 @@ BEGIN_DATADESC_NO_BASE( CBaseEntity ) DEFINE_INPUTFUNC( FIELD_VECTOR, "SetLocalOrigin", InputSetLocalOrigin ), DEFINE_INPUTFUNC( FIELD_VECTOR, "SetLocalAngles", InputSetLocalAngles ), + DEFINE_INPUTFUNC( FIELD_VECTOR, "SetAbsOrigin", InputSetAbsOrigin ), + DEFINE_INPUTFUNC( FIELD_VECTOR, "SetAbsAngles", InputSetAbsAngles ), DEFINE_INPUTFUNC( FIELD_VECTOR, "SetLocalVelocity", InputSetLocalVelocity ), DEFINE_INPUTFUNC( FIELD_VECTOR, "SetLocalAngularVelocity", InputSetLocalAngularVelocity ), @@ -7092,7 +7094,7 @@ const char *CBaseEntity::GetContextValue( const char *contextName ) const { int idx = FindContextByName( contextName ); if ( idx == -1 ) - return NULL; + return ""; return m_ResponseContexts[ idx ].m_iszValue.ToCStr(); } @@ -7554,10 +7556,30 @@ void CBaseEntity::InputSetLocalOrigin( inputdata_t& inputdata ) // Purpose: Sets our angles. //----------------------------------------------------------------------------- void CBaseEntity::InputSetLocalAngles( inputdata_t& inputdata ) +{ + QAngle ang; + inputdata.value.Angle3D(ang); + SetLocalAngles(ang); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets our origin. +//----------------------------------------------------------------------------- +void CBaseEntity::InputSetAbsOrigin( inputdata_t& inputdata ) { Vector vec; inputdata.value.Vector3D(vec); - SetLocalAngles(QAngle(vec.x, vec.y, vec.z)); + SetAbsOrigin(vec); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets our angles. +//----------------------------------------------------------------------------- +void CBaseEntity::InputSetAbsAngles( inputdata_t& inputdata ) +{ + QAngle ang; + inputdata.value.Angle3D(ang); + SetAbsAngles(ang); } //----------------------------------------------------------------------------- @@ -8746,6 +8768,130 @@ void CBaseEntity::SetCollisionBoundsFromModel() } +#ifdef MAPBASE +extern int EntityFactory_AutoComplete( const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0 ); + +//------------------------------------------------------------------------------ +// Purpose: Create an entity of the given type +//------------------------------------------------------------------------------ +class CEntCreateAutoCompletionFunctor : public ICommandCallback, public ICommandCompletionCallback +{ +public: + virtual bool CreateAimed() { return false; } + + virtual void CommandCallback( const CCommand &args ) + { + MDLCACHE_CRITICAL_SECTION(); + + CBasePlayer *pPlayer = UTIL_GetCommandClient(); + if (!pPlayer) + { + return; + } + + // Don't allow regular users to create point_servercommand entities for the same reason as blocking ent_fire + if ( !Q_stricmp( args[1], "point_servercommand" ) ) + { + if ( engine->IsDedicatedServer() ) + { + // We allow people with disabled autokick to do it, because they already have rcon. + if ( pPlayer->IsAutoKickDisabled() == false ) + return; + } + else if ( gpGlobals->maxClients > 1 ) + { + // On listen servers with more than 1 player, only allow the host to create point_servercommand. + CBasePlayer *pHostPlayer = UTIL_GetListenServerHost(); + if ( pPlayer != pHostPlayer ) + return; + } + } + + bool allowPrecache = CBaseEntity::IsPrecacheAllowed(); + CBaseEntity::SetAllowPrecache( true ); + + // Try to create entity + CBaseEntity *entity = dynamic_cast< CBaseEntity * >( CreateEntityByName(args[1]) ); + if (entity) + { + // Pass in any additional parameters. + for ( int i = 2; i + 1 < args.ArgC(); i += 2 ) + { + const char *pKeyName = args[i]; + const char *pValue = args[i+1]; + entity->KeyValue( pKeyName, pValue ); + } + + DispatchSpawn(entity); + + // Now attempt to drop into the world + trace_t tr; + Vector forward; + pPlayer->EyeVectors( &forward ); + UTIL_TraceLine(pPlayer->EyePosition(), + pPlayer->EyePosition() + forward * MAX_TRACE_LENGTH,MASK_SOLID, + pPlayer, COLLISION_GROUP_NONE, &tr ); + if ( tr.fraction != 1.0 ) + { + // Raise the end position a little up off the floor, place the npc and drop him down + tr.endpos.z += 12; + + if (CreateAimed()) + { + QAngle angles; + VectorAngles( forward, angles ); + angles.x = 0; + angles.z = 0; + entity->Teleport( &tr.endpos, &angles, NULL ); + } + else + { + entity->Teleport( &tr.endpos, NULL, NULL ); + } + + UTIL_DropToFloor( entity, MASK_SOLID ); + } + + entity->Activate(); + } + CBaseEntity::SetAllowPrecache( allowPrecache ); + } + + virtual int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands ) + { + if ( !g_pGameRules ) + { + return 0; + } + + const char *cmdname = CreateAimed() ? "ent_create_aimed" : "ent_create"; + + char *substring = (char *)partial; + if ( Q_strstr( partial, cmdname ) ) + { + substring = (char *)partial + strlen( cmdname ) + 1; + } + + int checklen = Q_strlen( substring ); + + CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc ); + return EntityFactory_AutoComplete( cmdname, commands, symbols, substring, checklen ); + } +}; + +static CEntCreateAutoCompletionFunctor g_EntCreateAutoComplete; +static ConCommand ent_create("ent_create", &g_EntCreateAutoComplete, "Creates an entity of the given type where the player is looking. Additional parameters can be passed in in the form: ent_create ... ", FCVAR_GAMEDLL | FCVAR_CHEAT, &g_EntCreateAutoComplete); + +class CEntCreateAimedAutoCompletionFunctor : public CEntCreateAutoCompletionFunctor +{ +public: + virtual bool CreateAimed() { return true; } +}; + +static CEntCreateAimedAutoCompletionFunctor g_EntCreateAimedAutoComplete; + +static ConCommand ent_create_aimed("ent_create_aimed", &g_EntCreateAimedAutoComplete, "Creates an entity of the given type where the player is looking. Additional parameters can be passed in in the form: ent_create_aimed ... ", FCVAR_CHEAT, &g_EntCreateAimedAutoComplete); +#else //------------------------------------------------------------------------------ // Purpose: Create an NPC of the given type //------------------------------------------------------------------------------ @@ -8816,6 +8962,7 @@ void CC_Ent_Create( const CCommand& args ) CBaseEntity::SetAllowPrecache( allowPrecache ); } static ConCommand ent_create("ent_create", CC_Ent_Create, "Creates an entity of the given type where the player is looking. Additional parameters can be passed in in the form: ent_create ... ", FCVAR_GAMEDLL | FCVAR_CHEAT); +#endif //------------------------------------------------------------------------------ // Purpose: Teleport a specified entity to where the player is looking diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 73c270df..e609b079 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -700,6 +700,8 @@ public: void InputSetLocalOrigin( inputdata_t &inputdata ); void InputSetLocalAngles( inputdata_t &inputdata ); + void InputSetAbsOrigin( inputdata_t &inputdata ); + void InputSetAbsAngles( inputdata_t &inputdata ); void InputSetLocalVelocity( inputdata_t &inputdata ); void InputSetLocalAngularVelocity( inputdata_t &inputdata ); @@ -1267,6 +1269,18 @@ public: virtual float GetDamage() { return 0; } virtual void SetDamage(float flDamage) {} +#ifdef MAPBASE + // Some entities want to use interactions regardless of whether they're a CBaseCombatCharacter. + // Valve ran into this issue with frag grenades when they started deriving from CBaseAnimating instead of CBaseCombatCharacter, + // preventing them from using the barnacle interactions for rigged grenade timing so it's guaranteed to blow up in the barnacle's face. + // We're used to unaltered behavior now, so we're not restoring that as default, but making this a "base entity" thing is supposed to help in situtions like those. + // + // Also, keep in mind pretty much all existing DispatchInteraction() calls are only performed on CBaseCombatCharacters. + // You'll need to change their code manually if you want other, non-character entities to use the interaction. + bool DispatchInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ) { return ( interactionType > 0 ) ? HandleInteraction( interactionType, data, sourceEnt ) : false; } + virtual bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ) { return false; } +#endif + virtual Vector EyePosition( void ); // position of eyes virtual const QAngle &EyeAngles( void ); // Direction of eyes in world space virtual const QAngle &LocalEyeAngles( void ); // Direction of eyes diff --git a/sp/src/game/server/baseflex.cpp b/sp/src/game/server/baseflex.cpp index 4e6b4629..90c38cdf 100644 --- a/sp/src/game/server/baseflex.cpp +++ b/sp/src/game/server/baseflex.cpp @@ -2004,10 +2004,17 @@ float CBaseFlex::PlayScene( const char *pszScene, float flDelay, AI_Response *re // Input : *soundname - // Output : float //----------------------------------------------------------------------------- +#ifdef MAPBASE +float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname, float flDelay, AI_Response *response, IRecipientFilter *filter ) +{ + return InstancedAutoGeneratedSoundScene( this, soundname, NULL, flDelay, false, response, false, filter ); +} +#else float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname ) { return InstancedAutoGeneratedSoundScene( this, soundname ); } +#endif diff --git a/sp/src/game/server/baseflex.h b/sp/src/game/server/baseflex.h index 1f0009ec..4ac775ea 100644 --- a/sp/src/game/server/baseflex.h +++ b/sp/src/game/server/baseflex.h @@ -116,7 +116,11 @@ public: void SentenceStop( void ) { EmitSound( "AI_BaseNPC.SentenceStop" ); } virtual float PlayScene( const char *pszScene, float flDelay = 0.0f, AI_Response *response = NULL, IRecipientFilter *filter = NULL ); +#ifdef MAPBASE + virtual float PlayAutoGeneratedSoundScene( const char *soundname, float flDelay = 0.0f, AI_Response *response = NULL, IRecipientFilter *filter = NULL ); +#else virtual float PlayAutoGeneratedSoundScene( const char *soundname ); +#endif virtual int GetSpecialDSP( void ) { return 0; } diff --git a/sp/src/game/server/effects.cpp b/sp/src/game/server/effects.cpp index 94e5dc30..c181254a 100644 --- a/sp/src/game/server/effects.cpp +++ b/sp/src/game/server/effects.cpp @@ -1504,12 +1504,6 @@ void CItemSoda::CanTouch ( CBaseEntity *pOther ) // technology demo //========================================================= -#ifdef MAPBASE -// I would leave this on the client, but it sems as if I could only precache the particle system on the server for some reason. -// That desn't sound right...look into this further later. -ConVar r_RainParticle( "r_RainParticle", "Rain_01_impact", FCVAR_CHEAT | FCVAR_REPLICATED ); -#endif - class CPrecipitation : public CBaseEntity { public: @@ -1546,9 +1540,6 @@ void CPrecipitation::Spawn( void ) PrecacheMaterial( "effects/fleck_ash2" ); PrecacheMaterial( "effects/fleck_ash3" ); PrecacheMaterial( "effects/ember_swirling001" ); -#ifdef MAPBASE - PrecacheParticleSystem( r_RainParticle.GetString() ); -#endif Precache(); SetSolid( SOLID_NONE ); // Remove model & collisions diff --git a/sp/src/game/server/entityoutput.h b/sp/src/game/server/entityoutput.h index 6aa36b84..792ac6da 100644 --- a/sp/src/game/server/entityoutput.h +++ b/sp/src/game/server/entityoutput.h @@ -152,6 +152,29 @@ public: { m_Value.Vector3D(vec); } + +#ifdef MAPBASE + // Shortcut to using QAngles in Vector outputs, makes it look cleaner and allows easy modification + void Init( const QAngle &value ) + { + // reinterpret_cast(value) + m_Value.SetAngle3D( value ); + } + + // Shortcut to using QAngles in Vector outputs, makes it look cleaner and allows easy modification + void Set( const QAngle &value, CBaseEntity *pActivator, CBaseEntity *pCaller ) + { + // reinterpret_cast(value) + m_Value.SetAngle3D( value ); + FireOutput( m_Value, pActivator, pCaller ); + } + + // Shortcut to using QAngles in Vector outputs, makes it look cleaner and allows easy modification + void Get( QAngle &ang ) + { + m_Value.Angle3D(ang); + } +#endif }; diff --git a/sp/src/game/server/env_global_light.cpp b/sp/src/game/server/env_global_light.cpp index 5ebd520b..357e1225 100644 --- a/sp/src/game/server/env_global_light.cpp +++ b/sp/src/game/server/env_global_light.cpp @@ -40,6 +40,13 @@ public: #ifdef MAPBASE void InputSetBrightness( inputdata_t &inputdata ); void InputSetColorTransitionTime( inputdata_t &inputdata ); + void InputSetXOffset( inputdata_t &inputdata ) { m_flEastOffset = inputdata.value.Float(); } + void InputSetYOffset( inputdata_t &inputdata ) { m_flForwardOffset = inputdata.value.Float(); } + void InputSetOrthoSize( inputdata_t &inputdata ) { m_flOrthoSize = inputdata.value.Float(); } + void InputSetDistance( inputdata_t &inputdata ) { m_flSunDistance = inputdata.value.Float(); } + void InputSetFOV( inputdata_t &inputdata ) { m_flFOV = inputdata.value.Float(); } + void InputSetNearZDistance( inputdata_t &inputdata ) { m_flNearZ = inputdata.value.Float(); } + void InputSetNorthOffset( inputdata_t &inputdata ) { m_flNorthOffset = inputdata.value.Float(); } #endif virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } @@ -101,14 +108,19 @@ BEGIN_DATADESC( CGlobalLight ) DEFINE_KEYFIELD( m_flColorTransitionTime, FIELD_FLOAT, "colortransitiontime" ), // Inputs +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetXOffset", InputSetXOffset ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetYOffset", InputSetYOffset ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetOrthoSize", InputSetOrthoSize ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetDistance", InputSetDistance ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFOV", InputSetFOV ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetNearZDistance", InputSetNearZDistance ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetNorthOffset", InputSetNorthOffset ), +#else DEFINE_INPUT( m_flSunDistance, FIELD_FLOAT, "SetDistance" ), DEFINE_INPUT( m_flFOV, FIELD_FLOAT, "SetFOV" ), DEFINE_INPUT( m_flNearZ, FIELD_FLOAT, "SetNearZDistance" ), DEFINE_INPUT( m_flNorthOffset, FIELD_FLOAT, "SetNorthOffset" ), -#ifdef MAPBASE - DEFINE_INPUT( m_flEastOffset, FIELD_FLOAT, "SetXOffset" ), - DEFINE_INPUT( m_flForwardOffset, FIELD_FLOAT, "SetYOffset" ), - DEFINE_INPUT( m_flOrthoSize, FIELD_FLOAT, "SetOrthoSize" ), #endif DEFINE_INPUTFUNC( FIELD_COLOR32, "LightColor", InputSetLightColor ), @@ -183,7 +195,11 @@ int CGlobalLight::UpdateTransmitState() bool CGlobalLight::KeyValue( const char *szKeyName, const char *szValue ) { +#ifdef MAPBASE + if ( FStrEq( szKeyName, "lightcolor" ) || FStrEq( szKeyName, "color" ) ) +#else if ( FStrEq( szKeyName, "color" ) ) +#endif { float tmp[4]; UTIL_StringToFloatArray( tmp, 4, szValue ); diff --git a/sp/src/game/server/env_projectedtexture.cpp b/sp/src/game/server/env_projectedtexture.cpp index 237e77d4..29d8d3ba 100644 --- a/sp/src/game/server/env_projectedtexture.cpp +++ b/sp/src/game/server/env_projectedtexture.cpp @@ -44,6 +44,12 @@ BEGIN_DATADESC( CEnvProjectedTexture ) DEFINE_KEYFIELD( m_flBrightnessScale, FIELD_FLOAT, "brightnessscale" ), DEFINE_FIELD( m_LightColor, FIELD_COLOR32 ), DEFINE_KEYFIELD( m_flColorTransitionTime, FIELD_FLOAT, "colortransitiontime" ), +#ifdef MAPBASE + DEFINE_FIELD( m_flConstantAtten, FIELD_FLOAT ), + DEFINE_FIELD( m_flLinearAtten, FIELD_FLOAT ), + DEFINE_FIELD( m_flQuadraticAtten, FIELD_FLOAT ), + DEFINE_KEYFIELD( m_flShadowAtten, FIELD_FLOAT, "shadowatten" ), +#endif DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ), DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ), @@ -66,9 +72,14 @@ BEGIN_DATADESC( CEnvProjectedTexture ) DEFINE_INPUTFUNC( FIELD_INTEGER, "SetSpotlightFrame", InputSetSpotlightFrame ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetBrightness", InputSetBrightness ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetColorTransitionTime", InputSetColorTransitionTime ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetQuadratic", InputSetQuadratic ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetLinear", InputSetLinear ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetConstant", InputSetConstant ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetShadowAtten", InputSetShadowAtten ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetNearZ", InputSetNearZ ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFarZ", InputSetFarZ ), DEFINE_INPUTFUNC( FIELD_VOID, "AlwaysDrawOn", InputAlwaysDrawOn ), + DEFINE_INPUTFUNC( FIELD_VOID, "AlwaysDrawOff", InputAlwaysDrawOff ), DEFINE_INPUTFUNC( FIELD_VOID, "StopFollowingTarget", InputStopFollowingTarget ), DEFINE_INPUTFUNC( FIELD_VOID, "StartFollowingTarget", InputStartFollowingTarget ), #endif @@ -100,6 +111,10 @@ IMPLEMENT_SERVERCLASS_ST( CEnvProjectedTexture, DT_EnvProjectedTexture ) SendPropFloat( SENDINFO( m_flFarZ ), 18, SPROP_ROUNDDOWN, 0.0f, 1500.0f ), SendPropInt( SENDINFO( m_nShadowQuality ), 1, SPROP_UNSIGNED ), // Just one bit for now #ifdef MAPBASE + SendPropFloat( SENDINFO( m_flConstantAtten ) ), + SendPropFloat( SENDINFO( m_flLinearAtten ) ), + SendPropFloat( SENDINFO( m_flQuadraticAtten ) ), + SendPropFloat( SENDINFO( m_flShadowAtten ) ), SendPropBool( SENDINFO( m_bAlwaysDraw ) ), // Not needed on the client right now, change when it actually is needed @@ -128,11 +143,21 @@ CEnvProjectedTexture::CEnvProjectedTexture( void ) m_nSpotlightTextureFrame = 0; m_flBrightnessScale = 1.0f; m_LightColor.Init( 255, 255, 255, 255 ); +#ifdef MAPBASE + m_flColorTransitionTime = 0.0f; +#else m_flColorTransitionTime = 0.5f; +#endif m_flAmbient = 0.0f; m_flNearZ = 4.0f; m_flFarZ = 750.0f; m_nShadowQuality = 0; +#ifdef MAPBASE + m_flQuadraticAtten = 0.0f; + m_flLinearAtten = 100.0f; + m_flConstantAtten = 0.0f; + m_flShadowAtten = 0.0f; +#endif } void UTIL_ColorStringToLinearFloatColor( Vector &color, const char *pString ) @@ -195,6 +220,20 @@ bool CEnvProjectedTexture::KeyValue( const char *szKeyName, const char *szValue Q_strcpy( m_SpotlightTextureName.GetForModify(), szValue ); #endif } +#ifdef MAPBASE + else if ( FStrEq( szKeyName, "constant_attn" ) ) + { + m_flConstantAtten = CorrectConstantAtten( atof( szValue ) ); + } + else if ( FStrEq( szKeyName, "linear_attn" ) ) + { + m_flLinearAtten = CorrectLinearAtten( atof( szValue ) ); + } + else if ( FStrEq( szKeyName, "quadratic_attn" ) ) + { + m_flQuadraticAtten = CorrectQuadraticAtten( atof( szValue ) ); + } +#endif else { return BaseClass::KeyValue( szKeyName, szValue ); @@ -215,6 +254,26 @@ bool CEnvProjectedTexture::GetKeyValue( const char *szKeyName, char *szValue, in Q_snprintf( szValue, iMaxLen, "%s", m_SpotlightTextureName.Get() ); return true; } +#ifdef MAPBASE + else if ( FStrEq( szKeyName, "constant_attn" ) ) + { + // Undo correction + Q_snprintf( szValue, iMaxLen, "%f", m_flConstantAtten *= 2.0f ); + return true; + } + else if ( FStrEq( szKeyName, "linear_attn" ) ) + { + // Undo correction + Q_snprintf( szValue, iMaxLen, "%f", m_flLinearAtten *= 0.01f ); + return true; + } + else if ( FStrEq( szKeyName, "quadratic_attn" ) ) + { + // Undo correction + Q_snprintf( szValue, iMaxLen, "%f", m_flQuadraticAtten *= 0.0001f ); + return true; + } +#endif return BaseClass::GetKeyValue( szKeyName, szValue, iMaxLen ); } diff --git a/sp/src/game/server/env_projectedtexture.h b/sp/src/game/server/env_projectedtexture.h index c2ad6647..06ff04ee 100644 --- a/sp/src/game/server/env_projectedtexture.h +++ b/sp/src/game/server/env_projectedtexture.h @@ -54,12 +54,21 @@ public: void InputSetSpotlightFrame( inputdata_t &inputdata ); void InputSetBrightness( inputdata_t &inputdata ); void InputSetColorTransitionTime( inputdata_t &inputdata ); + void InputSetConstant( inputdata_t &inputdata ) { m_flConstantAtten = CorrectConstantAtten(inputdata.value.Float()); } + void InputSetLinear( inputdata_t &inputdata ) { m_flLinearAtten = CorrectLinearAtten(inputdata.value.Float()); } + void InputSetQuadratic( inputdata_t &inputdata ) { m_flQuadraticAtten = CorrectQuadraticAtten(inputdata.value.Float()); } + void InputSetShadowAtten( inputdata_t &inputdata ) { m_flShadowAtten = inputdata.value.Float(); } void InputSetNearZ( inputdata_t &inputdata ); void InputSetFarZ( inputdata_t &inputdata ); void InputAlwaysDrawOn( inputdata_t &inputdata ) { m_bAlwaysDraw = true; } void InputAlwaysDrawOff( inputdata_t &inputdata ) { m_bAlwaysDraw = false; } void InputStopFollowingTarget( inputdata_t &inputdata ) { m_bDontFollowTarget = true; } void InputStartFollowingTarget( inputdata_t &inputdata ) { m_bDontFollowTarget = false; } + + // Corrects keyvalue/input attenuation for internal FlashlightEffect_t attenuation. + float CorrectConstantAtten( float fl ) { return fl * 0.5f; } + float CorrectLinearAtten( float fl ) { return fl * 100.0f; } + float CorrectQuadraticAtten( float fl ) { return fl * 10000.0f; } #endif void InitialThink( void ); @@ -91,11 +100,17 @@ private: CNetworkVar( float, m_flFarZ ); CNetworkVar( int, m_nShadowQuality ); #ifdef MAPBASE + CNetworkVar( float, m_flConstantAtten ); + CNetworkVar( float, m_flLinearAtten ); + CNetworkVar( float, m_flQuadraticAtten ); + CNetworkVar( float, m_flShadowAtten ); + CNetworkVar( bool, m_bAlwaysDraw ); // 1 = New projected texture // 0 = Non-Mapbase projected texture, e.g. one that uses the VDC parenting fix instead of the spawnflag - CNetworkVar( bool, m_bProjectedTextureVersion ); + // Not needed on the client right now, change to CNetworkVar when it actually is needed + bool m_bProjectedTextureVersion; #endif }; #endif diff --git a/sp/src/game/server/episodic/npc_hunter.cpp b/sp/src/game/server/episodic/npc_hunter.cpp index dcc1fb0b..ac904b81 100644 --- a/sp/src/game/server/episodic/npc_hunter.cpp +++ b/sp/src/game/server/episodic/npc_hunter.cpp @@ -3504,7 +3504,13 @@ void CNPC_Hunter::StartTask( const Task_t *pTask ) { SetLastAttackTime( gpGlobals->curtime ); +#ifdef MAPBASE + // The "VS_PLAYER" animation looks better than the regular animation when used against non-humans + if ( GetEnemy() && (GetEnemy()->IsPlayer() || + (GetEnemy()->IsCombatCharacter() && GetEnemy()->MyCombatCharacterPointer()->GetHullType() != HULL_HUMAN)) ) +#else if ( GetEnemy() && GetEnemy()->IsPlayer() ) +#endif { ResetIdealActivity( ( Activity )ACT_HUNTER_MELEE_ATTACK1_VS_PLAYER ); } diff --git a/sp/src/game/server/episodic/vehicle_jeep_episodic.cpp b/sp/src/game/server/episodic/vehicle_jeep_episodic.cpp index b5db0d1b..69bb4c3f 100644 --- a/sp/src/game/server/episodic/vehicle_jeep_episodic.cpp +++ b/sp/src/game/server/episodic/vehicle_jeep_episodic.cpp @@ -369,6 +369,11 @@ BEGIN_DATADESC( CPropJeepEpisodic ) DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetCargoHopperVisibility", InputSetCargoVisibility ), +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_VOID, "EnableHazardLights", InputEnableHazardLights ), + DEFINE_INPUTFUNC( FIELD_VOID, "DisableHazardLights", InputDisableHazardLights ), +#endif + END_DATADESC(); IMPLEMENT_SERVERCLASS_ST(CPropJeepEpisodic, DT_CPropJeepEpisodic) @@ -1422,6 +1427,26 @@ void CPropJeepEpisodic::DestroyHazardLights( void ) SetContextThink( NULL, gpGlobals->curtime, "HazardBlink" ); } +#ifdef MAPBASE +void CPropJeepEpisodic::InputEnableHazardLights( inputdata_t &data ) +{ + if (m_bNoHazardLights) + { + m_bNoHazardLights = false; + CreateHazardLights(); + } +} + +void CPropJeepEpisodic::InputDisableHazardLights( inputdata_t &data ) +{ + if (!m_bNoHazardLights) + { + m_bNoHazardLights = true; + DestroyHazardLights(); + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: // Input : nRole - diff --git a/sp/src/game/server/episodic/vehicle_jeep_episodic.h b/sp/src/game/server/episodic/vehicle_jeep_episodic.h index e18e559b..869cf33a 100644 --- a/sp/src/game/server/episodic/vehicle_jeep_episodic.h +++ b/sp/src/game/server/episodic/vehicle_jeep_episodic.h @@ -104,6 +104,10 @@ private: void InputEnableRadarDetectEnemies( inputdata_t &data ); void InputAddBusterToCargo( inputdata_t &data ); void InputSetCargoVisibility( inputdata_t &data ); +#ifdef MAPBASE + void InputEnableHazardLights( inputdata_t &data ); + void InputDisableHazardLights( inputdata_t &data ); +#endif void InputOutsideTransition( inputdata_t &data ); #ifndef MAPBASE void InputDisablePhysGun( inputdata_t &data ); diff --git a/sp/src/game/server/explode.cpp b/sp/src/game/server/explode.cpp index 186c0997..d0321356 100644 --- a/sp/src/game/server/explode.cpp +++ b/sp/src/game/server/explode.cpp @@ -17,6 +17,10 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +#ifdef MAPBASE +ConVar explosion_sparks("explosion_sparks", "0", FCVAR_NONE); +#endif + //----------------------------------------------------------------------------- // Purpose: Spark shower, created by the explosion entity. //----------------------------------------------------------------------------- @@ -358,7 +362,11 @@ void CEnvExplosion::InputExplode( inputdata_t &inputdata ) SetNextThink( gpGlobals->curtime + 0.3 ); // Only do these effects if we're not submerged +#ifdef MAPBASE + if ( explosion_sparks.GetBool() && !(UTIL_PointContents( GetAbsOrigin() ) & CONTENTS_WATER) ) +#else if ( UTIL_PointContents( GetAbsOrigin() ) & CONTENTS_WATER ) +#endif { // draw sparks if ( !( m_spawnflags & SF_ENVEXPLOSION_NOSPARKS ) ) diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index 10724b04..c4e8efeb 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -171,6 +171,12 @@ class CFilterMultiple : public CBaseFilter bool PassesDamageFilterImpl(const CTakeDamageInfo &info); #endif void Activate(void); + +#ifdef MAPBASE + bool BloodAllowed( CBaseEntity *pCaller, const CTakeDamageInfo &info ); + bool PassesFinalDamageFilter( CBaseEntity *pCaller, const CTakeDamageInfo &info ); + bool DamageMod( CBaseEntity *pCaller, CTakeDamageInfo &info ); +#endif }; LINK_ENTITY_TO_CLASS(filter_multi, CFilterMultiple); @@ -304,9 +310,9 @@ bool CFilterMultiple::PassesDamageFilterImpl(const CTakeDamageInfo &info) { CBaseFilter* pFilter = (CBaseFilter *)(m_hFilter[i].Get()); #ifdef MAPBASE - if (!pFilter->PassesDamageFilter(pCaller, info)) + if (pFilter->PassesDamageFilter(pCaller, info)) #else - if (!pFilter->PassesDamageFilter(info)) + if (pFilter->PassesDamageFilter(info)) #endif { return true; @@ -317,6 +323,125 @@ bool CFilterMultiple::PassesDamageFilterImpl(const CTakeDamageInfo &info) } } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Returns true if blood should be allowed, false if not. +// Input : pEntity - Entity to test. +//----------------------------------------------------------------------------- +bool CFilterMultiple::BloodAllowed( CBaseEntity *pCaller, const CTakeDamageInfo &info ) +{ + // Test against each filter + if (m_nFilterType == FILTER_AND) + { + for (int i=0;iBloodAllowed(pCaller, info)) + { + return false; + } + } + } + return true; + } + else // m_nFilterType == FILTER_OR + { + for (int i=0;iBloodAllowed(pCaller, info)) + { + return true; + } + } + } + return false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if the entity passes our filter, false if not. +// Input : pEntity - Entity to test. +//----------------------------------------------------------------------------- +bool CFilterMultiple::PassesFinalDamageFilter( CBaseEntity *pCaller, const CTakeDamageInfo &info ) +{ + // Test against each filter + if (m_nFilterType == FILTER_AND) + { + for (int i=0;iPassesFinalDamageFilter(pCaller, info)) + { + return false; + } + } + } + return true; + } + else // m_nFilterType == FILTER_OR + { + for (int i=0;iPassesFinalDamageFilter(pCaller, info)) + { + return true; + } + } + } + return false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if damage should be modded, false if not. +// Input : pEntity - Entity to test. +//----------------------------------------------------------------------------- +bool CFilterMultiple::DamageMod( CBaseEntity *pCaller, CTakeDamageInfo &info ) +{ + // Test against each filter + if (m_nFilterType == FILTER_AND) + { + for (int i=0;iDamageMod(pCaller, info)) + { + return false; + } + } + } + return true; + } + else // m_nFilterType == FILTER_OR + { + for (int i=0;iDamageMod(pCaller, info)) + { + return true; + } + } + } + return false; + } +} +#endif + // ################################################################### // > FilterName diff --git a/sp/src/game/server/func_break.cpp b/sp/src/game/server/func_break.cpp index 7c097e3f..bb7dff50 100644 --- a/sp/src/game/server/func_break.cpp +++ b/sp/src/game/server/func_break.cpp @@ -1059,11 +1059,6 @@ void CBreakable::Die( void ) iCount = func_break_max_pieces.GetInt(); } -#ifdef MAPBASE - // TEMP TEMP TEMP TEMP - DevMsg("vSize: %f %f %f\n", vSize.x, vSize.y, vSize.z); -#endif - ConVarRef breakable_disable_gib_limit( "breakable_disable_gib_limit" ); if ( !breakable_disable_gib_limit.GetBool() && iCount ) { diff --git a/sp/src/game/server/gameinterface.cpp b/sp/src/game/server/gameinterface.cpp index ff077ea5..9da779ca 100644 --- a/sp/src/game/server/gameinterface.cpp +++ b/sp/src/game/server/gameinterface.cpp @@ -89,6 +89,9 @@ #include "tier3/tier3.h" #include "serverbenchmark_base.h" #include "querycache.h" +#ifdef MAPBASE +#include "world.h" +#endif #ifdef TF_DLL @@ -701,6 +704,9 @@ bool CServerGameDLL::DLLInit( CreateInterfaceFn appSystemFactory, IGameSystem::Add( SoundEmitterSystem() ); // load Mod specific game events ( MUST be before InitAllSystems() so it can pickup the mod specific events) +#ifdef MAPBASE + gameeventmanager->LoadEventsFromFile("resource/MapbaseEvents.res"); +#endif gameeventmanager->LoadEventsFromFile("resource/ModEvents.res"); #ifdef CSTRIKE_DLL // BOTPORT: TODO: move these ifdefs out @@ -1733,6 +1739,17 @@ void CServerGameDLL::GetTitleName( const char *pMapName, char* pTitleBuff, int t return; } } + +#ifdef MAPBASE + // Check the world entity for a chapter title. + if ( CWorld *pWorld = GetWorldEntity() ) + { + const char *pWorldChapter = pWorld->GetChapterTitle(); + if ( pWorldChapter && pWorldChapter[0] != '\0' ) + Q_strncpy( chapterTitle, pWorldChapter, sizeof( chapterTitle ) ); + } +#endif + Q_strncpy( pTitleBuff, pMapName, titleBuffSize ); } #endif @@ -1770,6 +1787,16 @@ void CServerGameDLL::GetSaveComment( char *text, int maxlength, float flMinutes, break; } } + +#ifdef MAPBASE + // Check the world entity for a chapter title. + if ( CWorld *pWorld = GetWorldEntity() ) + { + const char *pWorldChapter = pWorld->GetChapterTitle(); + if ( pWorldChapter && pWorldChapter[0] != '\0' ) + pName = pWorldChapter; + } +#endif // If we didn't get one, use the designer's map name, or the BSP name itself if ( !pName ) @@ -2065,6 +2092,16 @@ void UpdateChapterRestrictions( const char *mapname ) } } +#ifdef MAPBASE + // Check the world entity for a chapter title. + if ( CWorld *pWorld = GetWorldEntity() ) + { + const char *pWorldChapter = pWorld->GetChapterTitle(); + if ( pWorldChapter && pWorldChapter[0] != '\0' ) + Q_strncpy( chapterTitle, pWorldChapter, sizeof( chapterTitle ) ); + } +#endif + if ( !chapterTitle[0] ) return; diff --git a/sp/src/game/server/genericactor.cpp b/sp/src/game/server/genericactor.cpp index fff148ff..bb0dfe0b 100644 --- a/sp/src/game/server/genericactor.cpp +++ b/sp/src/game/server/genericactor.cpp @@ -17,6 +17,9 @@ #include "tier1/strtools.h" #include "vstdlib/random.h" #include "engine/IEngineSound.h" +#ifdef MAPBASE +#include "ai_speech.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -148,10 +151,11 @@ void CGenericActor::Spawn() m_flFieldOfView = 0.5;// indicates the width of this NPC's forward view cone ( as a dotproduct result ) m_NPCState = NPC_STATE_NONE; - CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS ); - #ifdef MAPBASE CapabilitiesAdd( bits_CAP_SQUAD ); + CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_DOORS_GROUP ); +#else + CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS ); #endif // remove head turn if no eyes or forward attachment @@ -187,6 +191,163 @@ void CGenericActor::Precache() +#ifdef MAPBASE +//========================================================= +#define TLK_ACTOR_PAIN "TLK_WOUND" +#define TLK_ACTOR_DEATH "TLK_DEATH" +#define TLK_ACTOR_ALERT "TLK_STARTCOMBAT" +#define TLK_ACTOR_IDLE "TLK_IDLE" +#define TLK_ACTOR_FEAR "TLK_FEAR" +#define TLK_ACTOR_LOSTENEMY "TLK_LOSTENEMY" +#define TLK_ACTOR_FOUNDENEMY "TLK_REFINDENEMY" +//========================================================= +// Enhanced generic actor with built-in response system usage, weapon capabilities, and more. +//========================================================= +class CGenericActorCustom : public CGenericActor +{ +private: + DECLARE_CLASS( CGenericActorCustom, CGenericActor ); +public: + //DECLARE_DATADESC(); + + CGenericActorCustom() { } + void Spawn( void ); + void Precache( void ); + + bool KeyValue( const char *szKeyName, const char *szValue ); + + void SpeakIfAllowed( const char *concept, AI_CriteriaSet *modifiers = NULL ); + void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + + void PainSound( const CTakeDamageInfo &info ); + void DeathSound( const CTakeDamageInfo &info ); + void AlertSound( void ); + void IdleSound( void ); + void FearSound( void ); + void LostEnemySound( void ); + void FoundEnemySound( void ); +}; + +LINK_ENTITY_TO_CLASS( generic_actor_custom, CGenericActorCustom ); + +//BEGIN_DATADESC( CGenericActorCustom ) +//END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::Spawn() +{ + BaseClass::Spawn(); + + CapabilitiesAdd( bits_CAP_USE_WEAPONS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::Precache() +{ + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: Cache user entity field values until spawn is called. +// Input : szKeyName - Key to handle. +// szValue - Value for key. +// Output : Returns true if the key was handled, false if not. +//----------------------------------------------------------------------------- +bool CGenericActorCustom::KeyValue( const char *szKeyName, const char *szValue ) +{ + if (FStrEq(szKeyName, "UseShotRegulator")) + { + if (atoi(szValue) > 0) + CapabilitiesAdd( bits_CAP_USE_SHOT_REGULATOR ); + else + CapabilitiesRemove( bits_CAP_USE_SHOT_REGULATOR ); + + return true; + } + + return BaseClass::KeyValue( szKeyName, szValue ); +} + +//----------------------------------------------------------------------------- +// Purpose: Speak concept +//----------------------------------------------------------------------------- +void CGenericActorCustom::SpeakIfAllowed( const char *concept, AI_CriteriaSet *modifiers ) +{ + Speak( concept, modifiers ? *modifiers : AI_CriteriaSet() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::ModifyOrAppendCriteria( AI_CriteriaSet& set ) +{ + BaseClass::ModifyOrAppendCriteria( set ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::PainSound( const CTakeDamageInfo &info ) +{ + AI_CriteriaSet modifiers; + ModifyOrAppendDamageCriteria( modifiers, info ); + SpeakIfAllowed( TLK_ACTOR_PAIN, &modifiers ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::DeathSound( const CTakeDamageInfo &info ) +{ + AI_CriteriaSet modifiers; + ModifyOrAppendDamageCriteria( modifiers, info ); + SpeakIfAllowed( TLK_ACTOR_DEATH, &modifiers ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::AlertSound( void ) +{ + SpeakIfAllowed( TLK_ACTOR_ALERT ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::IdleSound( void ) +{ + SpeakIfAllowed( TLK_ACTOR_IDLE ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::FearSound( void ) +{ + SpeakIfAllowed( TLK_ACTOR_FEAR ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::LostEnemySound( void ) +{ + SpeakIfAllowed( TLK_ACTOR_LOSTENEMY ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CGenericActorCustom::FoundEnemySound( void ) +{ + SpeakIfAllowed( TLK_ACTOR_FOUNDENEMY ); +} +#endif diff --git a/sp/src/game/server/hl2/combine_mine.cpp b/sp/src/game/server/hl2/combine_mine.cpp index dbc73c6f..c3b54a82 100644 --- a/sp/src/game/server/hl2/combine_mine.cpp +++ b/sp/src/game/server/hl2/combine_mine.cpp @@ -1283,6 +1283,38 @@ void CBounceBomb::CloseHooks() #endif } +#ifdef MAPBASE +extern int g_interactionBarnacleVictimBite; +extern int g_interactionBarnacleVictimFinalBite; +extern int ACT_BARNACLE_BITE_SMALL_THINGS; +//----------------------------------------------------------------------------- +// Purpose: Uses the new CBaseEntity interaction implementation and +// replaces the dynamic_casting from npc_barnacle +// Input : The type of interaction, extra info pointer, and who started it +// Output : true - if sub-class has a response for the interaction +// false - if sub-class has no response +//----------------------------------------------------------------------------- +bool CBounceBomb::HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ) +{ + // This was originally done in npc_barnacle itself, but + // we've transitioned to interactions so we could extend special behavior to others + // without just adding more casting. + if ( interactionType == g_interactionBarnacleVictimBite ) + { + Assert( sourceEnt && sourceEnt->IsNPC() ); + sourceEnt->MyNPCPointer()->SetActivity( (Activity)ACT_BARNACLE_BITE_SMALL_THINGS ); + return true; + } + else if ( interactionType == g_interactionBarnacleVictimFinalBite ) + { + ExplodeThink(); + return true; + } + + return BaseClass::HandleInteraction(interactionType, data, sourceEnt); +} +#endif + //--------------------------------------------------------- //--------------------------------------------------------- void CBounceBomb::InputDisarm( inputdata_t &inputdata ) diff --git a/sp/src/game/server/hl2/combine_mine.h b/sp/src/game/server/hl2/combine_mine.h index 56ab6cd2..21205955 100644 --- a/sp/src/game/server/hl2/combine_mine.h +++ b/sp/src/game/server/hl2/combine_mine.h @@ -83,6 +83,11 @@ public: void OpenHooks( bool bSilent = false ); void CloseHooks(); +#ifdef MAPBASE + // Uses the new CBaseEntity interaction implementation and replaces the dynamic_casting from npc_barnacle + bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ); +#endif + DECLARE_DATADESC(); static string_t gm_iszFloorTurretClassname; diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index a12b7ff7..5bedb5b5 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -297,7 +297,7 @@ public: ~CCommandRedirect() { - g_pCommandRedirects.AddToTail(this); + g_pCommandRedirects.FindAndRemove(this); /* for (int i = 0; i < g_pCommandRedirects.Count(); i++) { @@ -1790,7 +1790,16 @@ bool CHL2_Player::CommanderFindGoal( commandgoal_t *pGoal ) //--------------------------------- // MASK_SHOT on purpose! So that you don't hit the invisible hulls of the NPCs. +#ifdef MAPBASE + // Get either our +USE entity or the gravity gun entity + CBaseEntity *pHeldEntity = GetPlayerHeldEntity(this); + if ( !pHeldEntity ) + PhysCannonGetHeldEntity( GetActiveWeapon() ); + + CTraceFilterSkipTwoEntities filter( this, pHeldEntity, COLLISION_GROUP_INTERACTIVE_DEBRIS ); +#else CTraceFilterSkipTwoEntities filter( this, PhysCannonGetHeldEntity( GetActiveWeapon() ), COLLISION_GROUP_INTERACTIVE_DEBRIS ); +#endif UTIL_TraceLine( EyePosition(), EyePosition() + forward * MAX_COORD_RANGE, MASK_SHOT, &filter, &tr ); diff --git a/sp/src/game/server/hl2/hl2_triggers.cpp b/sp/src/game/server/hl2/hl2_triggers.cpp index 55f718fe..9aeee1a9 100644 --- a/sp/src/game/server/hl2/hl2_triggers.cpp +++ b/sp/src/game/server/hl2/hl2_triggers.cpp @@ -589,6 +589,10 @@ class CTriggerWateryDeath : public CBaseTrigger public: DECLARE_DATADESC(); +#ifdef MAPBASE + CTriggerWateryDeath(); +#endif + void Spawn( void ); void Precache( void ); void Touch( CBaseEntity *pOther ); @@ -614,6 +618,13 @@ private: CUtlVector< float > m_flEntityKillTimes; float m_flNextPullSound; float m_flPainValue; + +#ifdef MAPBASE + float m_flBiteInterval; + float m_flPainStep; + float m_flMaxPain; + COutputInt m_OnDamage; +#endif }; BEGIN_DATADESC( CTriggerWateryDeath ) @@ -621,6 +632,12 @@ BEGIN_DATADESC( CTriggerWateryDeath ) DEFINE_UTLVECTOR( m_hLeeches, FIELD_EHANDLE ), DEFINE_FIELD( m_flNextPullSound, FIELD_TIME ), DEFINE_FIELD( m_flPainValue, FIELD_FLOAT ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_flBiteInterval, FIELD_FLOAT, "BiteInterval" ), + DEFINE_KEYFIELD( m_flPainStep, FIELD_FLOAT, "PainStep" ), + DEFINE_KEYFIELD( m_flMaxPain, FIELD_FLOAT, "MaxPain" ), + DEFINE_OUTPUT( m_OnDamage, "OnDamage" ), +#endif END_DATADESC() @@ -631,6 +648,15 @@ LINK_ENTITY_TO_CLASS( trigger_waterydeath, CTriggerWateryDeath ); #define WD_PAINVALUE_STEP 2.0 #define WD_MAX_DAMAGE 15.0f +#ifdef MAPBASE +CTriggerWateryDeath::CTriggerWateryDeath() +{ + m_flBiteInterval = WD_KILLTIME_NEXT_BITE; + m_flPainStep = WD_PAINVALUE_STEP; + m_flMaxPain = WD_MAX_DAMAGE; +} +#endif + //----------------------------------------------------------------------------- // Purpose: Called when spawning, after keyvalues have been handled. //----------------------------------------------------------------------------- @@ -707,6 +733,23 @@ void CTriggerWateryDeath::Touch( CBaseEntity *pOther ) { //EmitSound( filter, entindex(), "WateryDeath.Bite", &pOther->GetAbsOrigin() ); // Kill it +#ifdef MAPBASE + if ( pOther->IsPlayer() ) + { + m_flPainValue = MIN( m_flPainValue + m_flPainStep, m_flMaxPain ); + } + else + { + m_flPainValue = m_flMaxPain; + } + + // Do nothing if there is no damage + if (m_flPainValue <= 0.0f) + { + m_flEntityKillTimes[iIndex] = gpGlobals->curtime + m_flBiteInterval; + return; + } +#else if ( pOther->IsPlayer() ) { m_flPainValue = MIN( m_flPainValue + WD_PAINVALUE_STEP, WD_MAX_DAMAGE ); @@ -715,6 +758,7 @@ void CTriggerWateryDeath::Touch( CBaseEntity *pOther ) { m_flPainValue = WD_MAX_DAMAGE; } +#endif // Use DMG_GENERIC & make the target inflict the damage on himself. // This ensures that if the target is the player, the damage isn't modified by skill @@ -723,7 +767,13 @@ void CTriggerWateryDeath::Touch( CBaseEntity *pOther ) GuessDamageForce( &info, (pOther->GetAbsOrigin() - GetAbsOrigin()), pOther->GetAbsOrigin() ); pOther->TakeDamage( info ); +#ifdef MAPBASE + m_OnDamage.Set(m_flPainValue, pOther, this); + + m_flEntityKillTimes[iIndex] = gpGlobals->curtime + m_flBiteInterval; +#else m_flEntityKillTimes[iIndex] = gpGlobals->curtime + WD_KILLTIME_NEXT_BITE; +#endif } } diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index d88a139f..c8d2865d 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -226,6 +226,7 @@ BEGIN_DATADESC( CNPC_BaseZombie ) #ifdef MAPBASE DEFINE_OUTPUT( m_OnSwattedProp, "OnSwattedProp" ), + DEFINE_OUTPUT( m_OnCrab, "OnCrab" ), #endif END_DATADESC() @@ -1089,6 +1090,10 @@ bool CNPC_BaseZombie::ShouldIgniteZombieGib( void ) #endif } +#ifdef MAPBASE +extern CBaseAnimating *CreateServerRagdollSubmodel( CBaseAnimating *pOwner, const char *pModelName, const Vector &position, const QAngle &angles, int collisionGroup ); +#endif + //----------------------------------------------------------------------------- // Purpose: Handle the special case of a zombie killed by a physics chopper. //----------------------------------------------------------------------------- @@ -1138,9 +1143,32 @@ void CNPC_BaseZombie::DieChopped( const CTakeDamageInfo &info ) vecLegsForce.z *= -10; } +#ifdef MAPBASE + CBaseEntity *pLegGib = NULL; + if ( m_bForceServerRagdoll ) + { + pLegGib = CreateServerRagdollSubmodel( this, GetLegsModel(), GetAbsOrigin(), GetAbsAngles(), COLLISION_GROUP_INTERACTIVE_DEBRIS ); + pLegGib->VPhysicsGetObject()->AddVelocity(&vecLegsForce, NULL); + if (ShouldIgniteZombieGib()) + static_cast(pLegGib)->Ignite( random->RandomFloat( 8.0, 12.0 ), false ); + + if ( flFadeTime > 0.0 ) + { + pLegGib->SUB_StartFadeOut( flFadeTime ); + } + } + else + pLegGib = CreateRagGib( GetLegsModel(), GetAbsOrigin(), GetAbsAngles(), vecLegsForce, flFadeTime, ShouldIgniteZombieGib() ); +#else CBaseEntity *pLegGib = CreateRagGib( GetLegsModel(), GetAbsOrigin(), GetAbsAngles(), vecLegsForce, flFadeTime, ShouldIgniteZombieGib() ); +#endif if ( pLegGib ) { +#ifdef MAPBASE + // Inherit some misc. properties + pLegGib->m_iViewHideFlags = m_iViewHideFlags; +#endif + CopyRenderColorTo( pLegGib ); } @@ -1157,7 +1185,25 @@ void CNPC_BaseZombie::DieChopped( const CTakeDamageInfo &info ) QAngle TorsoAngles; TorsoAngles = GetAbsAngles(); TorsoAngles.x -= 90.0f; +#ifdef MAPBASE + CBaseEntity *pTorsoGib = NULL; + if ( m_bForceServerRagdoll ) + { + pTorsoGib = CreateServerRagdollSubmodel( this, GetTorsoModel(), GetAbsOrigin() + Vector( 0, 0, 64 ), TorsoAngles, COLLISION_GROUP_INTERACTIVE_DEBRIS ); + pTorsoGib->VPhysicsGetObject()->AddVelocity(&forceVector, NULL); + if (ShouldIgniteZombieGib()) + static_cast(pLegGib)->Ignite( random->RandomFloat( 8.0, 12.0 ), false ); + + if ( flFadeTime > 0.0 ) + { + pTorsoGib->SUB_StartFadeOut( flFadeTime ); + } + } + else + pTorsoGib = CreateRagGib( GetTorsoModel(), GetAbsOrigin() + Vector( 0, 0, 64 ), TorsoAngles, forceVector, flFadeTime, ShouldIgniteZombieGib() ); +#else CBaseEntity *pTorsoGib = CreateRagGib( GetTorsoModel(), GetAbsOrigin() + Vector( 0, 0, 64 ), TorsoAngles, forceVector, flFadeTime, ShouldIgniteZombieGib() ); +#endif if ( pTorsoGib ) { CBaseAnimating *pAnimating = dynamic_cast(pTorsoGib); @@ -1166,6 +1212,11 @@ void CNPC_BaseZombie::DieChopped( const CTakeDamageInfo &info ) pAnimating->SetBodygroup( ZOMBIE_BODYGROUP_HEADCRAB, !m_fIsHeadless ); } +#ifdef MAPBASE + // Inherit some misc. properties + pTorsoGib->m_iViewHideFlags = m_iViewHideFlags; +#endif + pTorsoGib->SetOwnerEntity( this ); CopyRenderColorTo( pTorsoGib ); @@ -2294,7 +2345,23 @@ void CNPC_BaseZombie::BecomeTorso( const Vector &vecTorsoForce, const Vector &ve if ( m_fIsTorso == true ) { // -40 on Z to make up for the +40 on Z that we did above. This stops legs spawning above the head. +#ifdef MAPBASE + CBaseEntity *pGib = NULL; + if ( m_bForceServerRagdoll ) + { + pGib = CreateServerRagdollSubmodel( this, GetLegsModel(), GetAbsOrigin() - Vector(0, 0, 40), GetAbsAngles(), COLLISION_GROUP_INTERACTIVE_DEBRIS ); + pGib->VPhysicsGetObject()->AddVelocity( &vecLegsForce, NULL ); + + if (flFadeTime > 0.0) + { + pGib->SUB_StartFadeOut( flFadeTime ); + } + } + else + pGib = CreateRagGib( GetLegsModel(), GetAbsOrigin() - Vector(0, 0, 40), GetAbsAngles(), vecLegsForce, flFadeTime ); +#else CBaseEntity *pGib = CreateRagGib( GetLegsModel(), GetAbsOrigin() - Vector(0, 0, 40), GetAbsAngles(), vecLegsForce, flFadeTime ); +#endif // don't collide with this thing ever if ( pGib ) @@ -2430,7 +2497,22 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve if( fRagdollCrab ) { //Vector vecForce = Vector( 0, 0, random->RandomFloat( 700, 1100 ) ); +#ifdef MAPBASE + CBaseEntity *pGib = NULL; + if ( m_bForceServerRagdoll ) + { + pGib = CreateServerRagdollSubmodel( this, GetHeadcrabModel(), vecOrigin, GetLocalAngles(), COLLISION_GROUP_INTERACTIVE_DEBRIS ); + pGib->VPhysicsGetObject()->AddVelocity(&vecVelocity, NULL); + if (ShouldIgniteZombieGib()) + static_cast(pGib)->Ignite( random->RandomFloat( 8.0, 12.0 ), false ); + + pGib->SUB_StartFadeOut( 15 ); + } + else + pGib = CreateRagGib( GetHeadcrabModel(), vecOrigin, GetLocalAngles(), vecVelocity, 15, ShouldIgniteZombieGib() ); +#else CBaseEntity *pGib = CreateRagGib( GetHeadcrabModel(), vecOrigin, GetLocalAngles(), vecVelocity, 15, ShouldIgniteZombieGib() ); +#endif if ( pGib ) { @@ -2449,6 +2531,11 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve return; } +#ifdef MAPBASE + // Inherit some misc. properties + pGib->m_iViewHideFlags = m_iViewHideFlags; +#endif + pGib->SetOwnerEntity( this ); CopyRenderColorTo( pGib ); @@ -2488,6 +2575,12 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve // add on the parent flags pCrab->AddSpawnFlags( m_spawnflags & ZOMBIE_CRAB_INHERITED_SPAWNFLAGS ); + +#ifdef MAPBASE + // Inherit some misc. properties + pCrab->m_bForceServerRagdoll = m_bForceServerRagdoll; + pCrab->m_iViewHideFlags = m_iViewHideFlags; +#endif // make me the crab's owner to avoid collision issues pCrab->SetOwnerEntity( this ); @@ -2541,6 +2634,10 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve CopyRenderColorTo( pCrab ); pCrab->Activate(); + +#ifdef MAPBASE + m_OnCrab.Set( pCrab, pCrab, this ); +#endif } if( fRemoveHead ) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.h b/sp/src/game/server/hl2/npc_BaseZombie.h index 2934fcb9..743186de 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.h +++ b/sp/src/game/server/hl2/npc_BaseZombie.h @@ -265,6 +265,7 @@ protected: EHANDLE m_hPhysicsEnt; #ifdef MAPBASE COutputEHANDLE m_OnSwattedProp; + COutputEHANDLE m_OnCrab; #endif float m_flNextMoanSound; diff --git a/sp/src/game/server/hl2/npc_barnacle.cpp b/sp/src/game/server/hl2/npc_barnacle.cpp index 38d9aad3..68b7064c 100644 --- a/sp/src/game/server/hl2/npc_barnacle.cpp +++ b/sp/src/game/server/hl2/npc_barnacle.cpp @@ -40,6 +40,10 @@ ConVar sk_barnacle_health( "sk_barnacle_health","0"); static ConVar npc_barnacle_swallow( "npc_barnacle_swallow", "0", 0, "Use prototype swallow code." ); +#ifdef MAPBASE +ConVar npc_barnacle_ignite( "npc_barnacle_ignite", "0", FCVAR_NONE, "Allows barnacles to be ignited by flares and beyond." ); +#endif + const char *CNPC_Barnacle::m_szGibNames[NUM_BARNACLE_GIBS] = { "models/gibs/hgibs.mdl", @@ -69,6 +73,9 @@ int g_interactionBarnacleVictimDangle = 0; int g_interactionBarnacleVictimReleased = 0; int g_interactionBarnacleVictimGrab = 0; int g_interactionBarnacleVictimBite = 0; +#ifdef MAPBASE +int g_interactionBarnacleVictimFinalBite = 0; +#endif LINK_ENTITY_TO_CLASS( npc_barnacle, CNPC_Barnacle ); @@ -187,7 +194,9 @@ BEGIN_DATADESC( CNPC_Barnacle ) DEFINE_THINKFUNC( BarnacleThink ), DEFINE_THINKFUNC( WaitTillDead ), +#ifndef MAPBASE DEFINE_FIELD( m_bSwallowingBomb, FIELD_BOOLEAN ), +#endif END_DATADESC() @@ -275,7 +284,9 @@ void CNPC_Barnacle::Spawn() m_cGibs = 0; m_bLiftingPrey = false; m_bSwallowingPrey = false; +#ifndef MAPBASE m_bSwallowingBomb = false; +#endif m_flDigestFinish = 0; m_takedamage = DAMAGE_YES; m_pConstraint = NULL; @@ -406,6 +417,16 @@ void CNPC_Barnacle::PlayerHasIlluminatedNPC( CBasePlayer *pPlayer, float flDot ) } } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CNPC_Barnacle::AllowedToIgnite( void ) +{ + return npc_barnacle_ignite.GetBool(); +} +#endif + //----------------------------------------------------------------------------- // Purpose: Initialize tongue position when first spawned // Input : @@ -509,7 +530,11 @@ void CNPC_Barnacle::BarnacleThink ( void ) } else if ( GetEnemy() ) { +#ifdef MAPBASE + if ( m_bLiftingPrey ) +#else if ( m_bLiftingPrey || m_bSwallowingBomb == true ) +#endif { LiftPrey(); } @@ -1145,6 +1170,24 @@ void CNPC_Barnacle::LiftPhysicsObject( float flBiteZOffset ) // If we got a physics prop, wait until the thing has settled down m_bLiftingPrey = false; +#ifdef MAPBASE + Vector tipPos = m_vecTip.Get(); + Activity curAct = GetActivity(); + + // Other, non-character entities use this now + if (pVictim->DispatchInteraction( g_interactionBarnacleVictimBite, &tipPos, this )) + { + // Make sure the interaction isn't making us use an irregular activity + // (e.g. biting) + if (GetActivity() == curAct) + SetActivity( (Activity)ACT_BARNACLE_TASTE_SPIT ); + } + else + { + // Start the spit animation. + SetActivity( (Activity)ACT_BARNACLE_TASTE_SPIT ); + } +#else if ( hl2_episodic.GetBool() ) { CBounceBomb *pBounce = dynamic_cast( pVictim ); @@ -1181,6 +1224,7 @@ void CNPC_Barnacle::LiftPhysicsObject( float flBiteZOffset ) pBCC->DispatchInteraction( g_interactionBarnacleVictimBite, &tipPos, this ); } +#endif #endif } else @@ -1577,6 +1621,18 @@ void CNPC_Barnacle::BitePrey( void ) CBaseCombatCharacter *pVictim = GetEnemyCombatCharacterPointer(); +#ifdef MAPBASE + if ( pVictim == NULL ) + { + if ( GetEnemy() ) + { + Vector tipPos = m_vecTip.Get(); + GetEnemy()->DispatchInteraction( g_interactionBarnacleVictimFinalBite, &tipPos, this ); + } + + return; + } +#else #ifdef HL2_EPISODIC if ( pVictim == NULL ) { @@ -1614,6 +1670,7 @@ void CNPC_Barnacle::BitePrey( void ) { return; } +#endif EmitSound( "NPC_Barnacle.FinalBite" ); @@ -1701,6 +1758,12 @@ void CNPC_Barnacle::BitePrey( void ) #endif +#ifdef MAPBASE + Vector tipPos = m_vecTip.Get(); + if (pVictim->DispatchInteraction( g_interactionBarnacleVictimFinalBite, &tipPos, this )) + return; +#endif + // Players are never swallowed, nor is anything we don't have a ragdoll for if ( !m_hRagdoll || pVictim->IsPlayer() ) { @@ -1885,13 +1948,20 @@ void CNPC_Barnacle::LostPrey( bool bRemoveRagdoll ) PhysEnableEntityCollisions( this, pEnemy ); #endif +#ifdef MAPBASE + // These can be CBaseEntity-based now + pEnemy->DispatchInteraction( g_interactionBarnacleVictimReleased, NULL, this ); +#endif + //No one survives being snatched by a barnacle anymore, so leave // this flag set so that their entity gets removed. //GetEnemy()->RemoveEFlags( EFL_IS_BEING_LIFTED_BY_BARNACLE ); CBaseCombatCharacter *pVictim = GetEnemyCombatCharacterPointer(); if ( pVictim ) { +#ifndef MAPBASE pVictim->DispatchInteraction( g_interactionBarnacleVictimReleased, NULL, this ); +#endif pVictim->RemoveEFlags( EFL_IS_BEING_LIFTED_BY_BARNACLE ); if ( m_hRagdoll ) @@ -2721,6 +2791,9 @@ AI_BEGIN_CUSTOM_NPC( npc_barnacle, CNPC_Barnacle ) DECLARE_INTERACTION( g_interactionBarnacleVictimReleased ) DECLARE_INTERACTION( g_interactionBarnacleVictimGrab ) DECLARE_INTERACTION( g_interactionBarnacleVictimBite ) +#ifdef MAPBASE + DECLARE_INTERACTION( g_interactionBarnacleVictimFinalBite ) +#endif // Conditions diff --git a/sp/src/game/server/hl2/npc_barnacle.h b/sp/src/game/server/hl2/npc_barnacle.h index 1ede1d70..373be24b 100644 --- a/sp/src/game/server/hl2/npc_barnacle.h +++ b/sp/src/game/server/hl2/npc_barnacle.h @@ -84,6 +84,10 @@ public: int OnTakeDamage_Alive( const CTakeDamageInfo &info ); void PlayerHasIlluminatedNPC( CBasePlayer *pPlayer, float flDot ); +#ifdef MAPBASE + bool AllowedToIgnite( void ); +#endif + // The tongue's vphysics updated void OnTongueTipUpdated(); @@ -209,7 +213,9 @@ private: Vector m_vLastEnemyPos; float m_flLastPull; CSimpleSimTimer m_StuckTimer; +#ifndef MAPBASE // Handled by interactions now bool m_bSwallowingBomb; +#endif #ifdef HL2_EPISODIC bool m_bSwallowingPoison; #endif diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 62590a92..57517a34 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -32,6 +32,7 @@ #ifdef MAPBASE #include "mapbase/GlobalStrings.h" #include "globalstate.h" +#include "sceneentity.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -448,6 +449,14 @@ void CNPC_Combine::Spawn( void ) m_flNextAltFireTime = gpGlobals->curtime; NPCInit(); + +#ifdef MAPBASE + // This was moved from CalcWeaponProficiency() so soldiers don't change skin unnaturally and uncontrollably + if ( GetActiveWeapon() && EntIsClass(GetActiveWeapon(), gm_isz_class_Shotgun) && m_nSkin != COMBINE_SKIN_SHOTGUNNER ) + { + m_nSkin = COMBINE_SKIN_SHOTGUNNER; + } +#endif } //----------------------------------------------------------------------------- @@ -2950,6 +2959,10 @@ bool CNPC_Combine::SpeakIfAllowed( const char *concept, AI_CriteriaSet& modifier if ( !GetExpresser()->CanSpeakConcept( concept ) ) return false; + // Don't interrupt scripted VCD dialogue + if ( IsRunningScriptedSceneWithSpeechAndNotPaused( this, true ) ) + return false; + if ( Speak( concept, modifiers ) ) { JustMadeSound( sentencepriority, 2.0f /*GetTimeSpeechComplete()*/ ); @@ -3655,10 +3668,12 @@ WeaponProficiency_t CNPC_Combine::CalcWeaponProficiency( CBaseCombatWeapon *pWea else if( FClassnameIs( pWeapon, "weapon_shotgun" ) ) #endif { +#ifndef MAPBASE // Moved so soldiers don't change skin unnaturally and uncontrollably if( m_nSkin != COMBINE_SKIN_SHOTGUNNER ) { m_nSkin = COMBINE_SKIN_SHOTGUNNER; } +#endif return WEAPON_PROFICIENCY_PERFECT; } diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 63c6ca2c..7cfc3a24 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -276,7 +276,7 @@ void CNPC_PlayerCompanion::Spawn() m_AnnounceAttackTimer.Set( 10, 30 ); -#ifdef HL2_EPISODIC +#if HL2_EPISODIC && !MAPBASE // Mapbase permits this flag since the warning can be distracting and stripping the flag might break some HL2 maps in Episodic mods // We strip this flag because it's been made obsolete by the StartScripting behavior if ( HasSpawnFlags( SF_NPC_ALTCOLLISION ) ) { @@ -306,7 +306,7 @@ int CNPC_PlayerCompanion::Restore( IRestore &restore ) m_StandoffBehavior.SetActive( false ); } -#ifdef HL2_EPISODIC +#if HL2_EPISODIC && !MAPBASE // Mapbase permits this flag since the warning can be distracting and stripping the flag might break some HL2 maps in Episodic mods // We strip this flag because it's been made obsolete by the StartScripting behavior if ( HasSpawnFlags( SF_NPC_ALTCOLLISION ) ) { diff --git a/sp/src/game/server/hl2/npc_zombie.cpp b/sp/src/game/server/hl2/npc_zombie.cpp index d40c8cc6..dfb5d0cd 100644 --- a/sp/src/game/server/hl2/npc_zombie.cpp +++ b/sp/src/game/server/hl2/npc_zombie.cpp @@ -19,6 +19,7 @@ #include "ammodef.h" #ifdef MAPBASE #include "AI_ResponseSystem.h" +#include "ai_speech.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -1028,10 +1029,10 @@ AI_END_CUSTOM_NPC() //============================================================================= #ifdef MAPBASE -class CZombieCustom : public CZombie +class CZombieCustom : public CAI_ExpresserHost { DECLARE_DATADESC(); - DECLARE_CLASS( CZombieCustom, CZombie ); + DECLARE_CLASS( CZombieCustom, CAI_ExpresserHost ); public: CZombieCustom(); @@ -1039,10 +1040,11 @@ public: void Spawn( void ); void Precache( void ); -#ifdef EXPANDED_RESPONSE_SYSTEM_USAGE - DeclareResponseSystem() - void SpeakIfAllowed(const char *concept); + void SpeakIfAllowed( const char *concept, AI_CriteriaSet *modifiers = NULL ); void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + virtual CAI_Expresser *CreateExpresser( void ); + virtual CAI_Expresser *GetExpresser() { return m_pExpresser; } + virtual void PostConstructor( const char *szClassname ); void PainSound( const CTakeDamageInfo &info ); void DeathSound( const CTakeDamageInfo &info ); @@ -1051,7 +1053,6 @@ public: void AttackSound( void ); const char *GetMoanSound( int nSound ); -#endif void SetZombieModel( void ); @@ -1064,6 +1065,8 @@ public: string_t m_iszTorsoModel; string_t m_iszHeadcrabClassname; string_t m_iszHeadcrabModel; + + CAI_Expresser *m_pExpresser; }; BEGIN_DATADESC( CZombieCustom ) @@ -1166,20 +1169,24 @@ void CZombieCustom::SetZombieModel( void ) } } -#ifdef EXPANDED_RESPONSE_SYSTEM_USAGE //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CZombieCustom::PainSound( const CTakeDamageInfo &info ) { - SpeakIfAllowed( TLK_ZOMBIE_PAIN ); + AI_CriteriaSet modifiers; + ModifyOrAppendDamageCriteria( modifiers, info ); + SpeakIfAllowed( TLK_ZOMBIE_PAIN, &modifiers ); } //----------------------------------------------------------------------------- +// Purpose: //----------------------------------------------------------------------------- void CZombieCustom::DeathSound( const CTakeDamageInfo &info ) { - SpeakIfAllowed( TLK_ZOMBIE_DEATH ); + AI_CriteriaSet modifiers; + ModifyOrAppendDamageCriteria( modifiers, info ); + SpeakIfAllowed( TLK_ZOMBIE_DEATH, &modifiers ); } //----------------------------------------------------------------------------- @@ -1198,64 +1205,21 @@ void CZombieCustom::AlertSound( void ) //----------------------------------------------------------------------------- const char *CZombieCustom::GetMoanSound( int nSound ) { - // This whole thing is really complicated and largely a copy-paste of CBaseEntity::DispatchResponse(). + AI_CriteriaSet modifiers; - AddContext( "moansound", UTIL_VarArgs("%i", nSound & 4), 5.0f ); + // We could probably do this through the response system alone now, but whatever. + modifiers.AppendCriteria( "moansound", UTIL_VarArgs("%i", nSound & 4) ); - IResponseSystem *rs = GetResponseSystem(); - if ( !rs ) + AI_Response *response = SpeakFindResponse(TLK_ZOMBIE_MOAN, modifiers); + + if ( !response ) return "NPC_BaseZombie.Moan1"; - AI_CriteriaSet set; - set.AppendCriteria( "concept", TLK_ZOMBIE_MOAN, CONCEPT_WEIGHT ); - ModifyOrAppendCriteria( set ); - CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); - if( pPlayer ) - pPlayer->ModifyOrAppendPlayerCriteria( set ); - ReAppendContextCriteria( set ); + // Must be static so it could be returned + static char szSound[128]; + response->GetName(szSound, sizeof(szSound)); - AI_Response result; - rs->FindBestResponse(set, result); - - // Get the response and turn it into something we can use - char response[256]; - result.GetResponse(response, sizeof(response)); - switch (result.GetType()) - { - case RESPONSE_SENTENCE: - { - if (response[0] != '!') - { - SENTENCEG_PlayRndSz( edict(), response, 1, result.GetSoundLevel(), 0, PITCH_NORM ); - break; - } - int sentenceIndex = SENTENCEG_Lookup( response ); - if( sentenceIndex == -1 ) - { - // sentence not found - break; - } - - // Not sure how else to get around this - CPASAttenuationFilter filter( this ); - CBaseEntity::EmitSentenceByIndex( filter, entindex(), CHAN_VOICE, sentenceIndex, 1, result.GetSoundLevel(), 0, PITCH_NORM ); - return "AI_BaseNPC.SentenceStop"; - } - break; - case RESPONSE_SCENE: - { - extern const char *GetFirstSoundInScene(const char *pszScene); - - // Expand gender string - GenderExpandString( response, response, sizeof( response ) ); - - // Trust that it's been precached - Q_strncpy(response, GetFirstSoundInScene(response), sizeof(response)); - } - break; - } - - const char *szSound = response; + delete response; return szSound; } @@ -1285,9 +1249,9 @@ void CZombieCustom::AttackSound( void ) //----------------------------------------------------------------------------- // Purpose: Speak concept //----------------------------------------------------------------------------- -void CZombieCustom::SpeakIfAllowed(const char *concept) +void CZombieCustom::SpeakIfAllowed(const char *concept, AI_CriteriaSet *modifiers) { - DispatchResponse(concept); + Speak( concept, modifiers ? *modifiers : AI_CriteriaSet() ); } //----------------------------------------------------------------------------- @@ -1305,5 +1269,26 @@ void CZombieCustom::ModifyOrAppendCriteria( AI_CriteriaSet& set ) // This can be overridden with response contexts. set.AppendCriteria( "classname", "npc_zombie" ); } -#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CAI_Expresser *CZombieCustom::CreateExpresser( void ) +{ + m_pExpresser = new CAI_Expresser(this); + if (!m_pExpresser) + return NULL; + + m_pExpresser->Connect(this); + return m_pExpresser; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CZombieCustom::PostConstructor(const char *szClassname) +{ + BaseClass::PostConstructor(szClassname); + CreateExpresser(); +} #endif diff --git a/sp/src/game/server/hl2/proto_sniper.cpp b/sp/src/game/server/hl2/proto_sniper.cpp index 22cfd495..93fff599 100644 --- a/sp/src/game/server/hl2/proto_sniper.cpp +++ b/sp/src/game/server/hl2/proto_sniper.cpp @@ -284,7 +284,7 @@ public: void ModifyOrAppendCriteria( AI_CriteriaSet& set ); virtual CAI_Expresser *CreateExpresser( void ); - virtual CAI_Expresser *GetExpresser() { return m_pExpresser; } + virtual CAI_Expresser *GetExpresser() { return m_pExpresser; } virtual void PostConstructor( const char *szClassname ); #endif diff --git a/sp/src/game/server/hl2/script_intro.cpp b/sp/src/game/server/hl2/script_intro.cpp index fd86edeb..62a126b0 100644 --- a/sp/src/game/server/hl2/script_intro.cpp +++ b/sp/src/game/server/hl2/script_intro.cpp @@ -49,6 +49,8 @@ BEGIN_DATADESC(CScriptIntro) #ifdef MAPBASE DEFINE_KEYFIELD( m_bDrawSky, FIELD_BOOLEAN, "DrawSky" ), DEFINE_KEYFIELD( m_bDrawSky2, FIELD_BOOLEAN, "DrawSky2" ), + + DEFINE_KEYFIELD( m_bUseEyePosition, FIELD_BOOLEAN, "UseEyePosition" ), #endif // Inputs @@ -83,6 +85,7 @@ IMPLEMENT_SERVERCLASS_ST( CScriptIntro, DT_ScriptIntro ) #ifdef MAPBASE SendPropBool( SENDINFO( m_bDrawSky ) ), SendPropBool( SENDINFO( m_bDrawSky2 ) ), + SendPropBool( SENDINFO( m_bUseEyePosition ) ), #endif // Fov & fov blends diff --git a/sp/src/game/server/hl2/script_intro.h b/sp/src/game/server/hl2/script_intro.h index d5be4da2..552c6188 100644 --- a/sp/src/game/server/hl2/script_intro.h +++ b/sp/src/game/server/hl2/script_intro.h @@ -69,6 +69,7 @@ private: #ifdef MAPBASE CNetworkVar( bool, m_bDrawSky ); CNetworkVar( bool, m_bDrawSky2 ); + CNetworkVar( bool, m_bUseEyePosition ); #endif // Fov & fov blends diff --git a/sp/src/game/server/logic_measure_movement.cpp b/sp/src/game/server/logic_measure_movement.cpp index 1333e3fc..9ceba13d 100644 --- a/sp/src/game/server/logic_measure_movement.cpp +++ b/sp/src/game/server/logic_measure_movement.cpp @@ -276,7 +276,7 @@ void CLogicMeasureMovement::MeasureThink( ) if (m_bOutputPosition) { m_OutPosition.Set(vecNewOrigin, m_hTarget.Get(), this); - m_OutAngles.Set(*(reinterpret_cast(vecNewAngles.Base())), m_hTarget.Get(), this); + m_OutAngles.Set(vecNewAngles, m_hTarget.Get(), this); } if (HasSpawnFlags( SF_LOGIC_MEASURE_MOVEMENT_TELEPORT )) diff --git a/sp/src/game/server/logicentities.cpp b/sp/src/game/server/logicentities.cpp index ae2a8cf2..d4a49bf2 100644 --- a/sp/src/game/server/logicentities.cpp +++ b/sp/src/game/server/logicentities.cpp @@ -18,6 +18,7 @@ #include "mapbase/variant_tools.h" #include "mapbase/matchers.h" #include "mapbase/datadesc_mod.h" +#include "activitylist.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -1917,6 +1918,7 @@ private: bool m_bPreserveValue; bool m_bAlwaysOutputAsInt; + float m_flLerpPercent; void UpdateOutValue(CBaseEntity *pActivator, float fNewValue); @@ -1937,6 +1939,8 @@ private: void InputRandomInt( inputdata_t &inputdata ); void InputRandomFloat( inputdata_t &inputdata ); + void InputLerpTo( inputdata_t &inputdata ); + DECLARE_DATADESC(); }; @@ -1948,6 +1952,7 @@ BEGIN_DATADESC( CMathCounterAdvanced ) // Keys DEFINE_INPUT(m_bPreserveValue, FIELD_BOOLEAN, "PreserveValue"), DEFINE_INPUT(m_bAlwaysOutputAsInt, FIELD_BOOLEAN, "AlwaysOutputAsInt"), + DEFINE_INPUT(m_flLerpPercent, FIELD_FLOAT, "SetLerpPercent"), // Inputs DEFINE_INPUTFUNC(FIELD_VOID, "SetValueToPi", InputSetValueToPi), @@ -1967,6 +1972,8 @@ BEGIN_DATADESC( CMathCounterAdvanced ) DEFINE_INPUTFUNC(FIELD_STRING, "RandomInt", InputRandomInt), DEFINE_INPUTFUNC(FIELD_STRING, "RandomFloat", InputRandomFloat), + DEFINE_INPUTFUNC(FIELD_FLOAT, "LerpTo", InputLerpTo), + END_DATADESC() //----------------------------------------------------------------------------- @@ -2280,6 +2287,21 @@ void CMathCounterAdvanced::InputRandomFloat( inputdata_t &inputdata ) UpdateOutValue( inputdata.pActivator, fNewValue ); } +//----------------------------------------------------------------------------- +// Purpose: Input handler for random float generation. +//----------------------------------------------------------------------------- +void CMathCounterAdvanced::InputLerpTo( inputdata_t &inputdata ) +{ + if( m_bDisabled ) + { + DevMsg("Math Counter %s ignoring LERPTO because it is disabled\n", GetDebugName() ); + return; + } + + float fNewValue = m_OutValue.Get() + (inputdata.value.Float() - m_OutValue.Get()) * m_flLerpPercent; + UpdateOutValue( inputdata.pActivator, fNewValue ); +} + //----------------------------------------------------------------------------- // Purpose: Sets the value to the new value, clamping and firing the output value. // Input : fNewValue - Value to set. @@ -3058,6 +3080,11 @@ int CLogicBranch::DrawDebugTextOverlays( void ) return text_offset; } +#ifdef MAPBASE +extern void MapbaseGameLog_Record( const char *szContext ); +extern ConVar mapbase_game_log_on_autosave; +#endif + //----------------------------------------------------------------------------- // Purpose: Autosaves when triggered //----------------------------------------------------------------------------- @@ -3094,6 +3121,13 @@ END_DATADESC() //----------------------------------------------------------------------------- void CLogicAutosave::InputSave( inputdata_t &inputdata ) { +#ifdef MAPBASE + if (mapbase_game_log_on_autosave.GetBool()) + { + MapbaseGameLog_Record( "autosave" ); + } +#endif + if ( m_bForceNewLevelUnit ) { engine->ClearSaveDir(); @@ -3107,6 +3141,13 @@ void CLogicAutosave::InputSave( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CLogicAutosave::InputSaveDangerous( inputdata_t &inputdata ) { +#ifdef MAPBASE + if (mapbase_game_log_on_autosave.GetBool()) + { + MapbaseGameLog_Record( "autosave_dangerous" ); + } +#endif + CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); if ( g_ServerGameDLL.m_fAutoSaveDangerousTime != 0.0f && g_ServerGameDLL.m_fAutoSaveDangerousTime >= gpGlobals->curtime ) @@ -3609,7 +3650,9 @@ public: void InputNewLine( inputdata_t &inputdata ) { LCMsg("\n"); } void InputDevNewLine( inputdata_t &inputdata ) { LCDevMsg(m_iDevLevel, "\n"); } - void InputClearConsole( inputdata_t &inputdata ) { engine->ServerCommand("clear"); } + // MAPBASE MP TODO: "ClearConsoleOnTarget" + // (and make this input broadcast to all players) + void InputClearConsole( inputdata_t &inputdata ) { UTIL_GetLocalPlayer() ? engine->ClientCommand(UTIL_GetLocalPlayer()->edict(), "clear") : NULL; } DECLARE_DATADESC(); }; @@ -3632,6 +3675,8 @@ BEGIN_DATADESC( CLogicConsole ) DEFINE_INPUTFUNC( FIELD_VOID, "NewLine", InputNewLine ), DEFINE_INPUTFUNC( FIELD_VOID, "DevNewLine", InputDevNewLine ), + DEFINE_INPUTFUNC( FIELD_VOID, "ClearConsole", InputClearConsole ), + END_DATADESC() ConVar sv_allow_logic_convar("sv_allow_logic_convar", "1"); @@ -3696,23 +3741,31 @@ const char *CLogicConvar::GetConVarString( inputdata_t &inputdata ) ConVarRef pCVar = ConVarRef(STRING(m_iszConVar), true); if (!pCVar.IsValid()) { - // It's not a convar, so check if it's a common cheat command a player might be using + const char *pszCVar = STRING( m_iszConVar ); CBasePlayer *pPlayer = ToBasePlayer( inputdata.pActivator ); if (!pPlayer && AI_IsSinglePlayer()) pPlayer = UTIL_PlayerByIndex( 1 ); if (pPlayer) { - const char *pszCVar = STRING( m_iszConVar ); + // Check if it's a common cheat command a player might be using if (FStrEq( pszCVar, "god" )) return (pPlayer->GetFlags() & FL_GODMODE) ? "1" : "0"; if (FStrEq( pszCVar, "notarget" )) return (pPlayer->GetFlags() & FL_NOTARGET) ? "1" : "0"; if (FStrEq( pszCVar, "noclip" )) return (pPlayer->IsEFlagSet(EFL_NOCLIP_ACTIVE)) ? "1" : "0"; + + // It might be a client convar + // This function returns a blank string if the convar doesn't exist, so we have to put this at the end + const char *pszClientValue = engine->GetClientConVarValue( pPlayer->GetClientIndex(), pszCVar ); + if (pszClientValue) + { + return pszClientValue; + } } - Warning("Warning: %s has invalid convar \"%s\"\n", GetDebugName(), STRING(m_iszConVar)); + //Warning("Warning: %s has invalid convar \"%s\"\n", GetDebugName(), STRING(m_iszConVar)); } return pCVar.GetString(); @@ -4587,6 +4640,7 @@ private: void InputDisable( inputdata_t &inputdata ); void InputNormalize( inputdata_t &inputdata ); + void InputNormalizeAngles( inputdata_t &inputdata ); void SetCoordinate(float value, char coord, CBaseEntity *pActivator); void GetCoordinate(char coord, CBaseEntity *pActivator); @@ -4640,6 +4694,7 @@ BEGIN_DATADESC( CMathVector ) DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), DEFINE_INPUTFUNC(FIELD_VOID, "Normalize", InputNormalize), + DEFINE_INPUTFUNC(FIELD_VOID, "NormalizeAngles", InputNormalizeAngles), DEFINE_INPUTFUNC(FIELD_FLOAT, "SetX", InputSetX), DEFINE_INPUTFUNC(FIELD_FLOAT, "SetY", InputSetY), @@ -4879,6 +4934,24 @@ void CMathVector::InputNormalize( inputdata_t &inputdata ) UpdateOutValue( inputdata.pActivator, cur ); } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CMathVector::InputNormalizeAngles( inputdata_t &inputdata ) +{ + if( m_bDisabled ) + { + DevMsg("Math Vector %s ignoring NORMALIZEANGLES because it is disabled\n", GetDebugName() ); + return; + } + + Vector cur; + m_OutValue.Get(cur); + cur.x = AngleNormalize(cur.x); + cur.y = AngleNormalize(cur.y); + cur.z = AngleNormalize(cur.z); + UpdateOutValue( inputdata.pActivator, cur ); +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CMathVector::SetCoordinate(float value, char coord, CBaseEntity *pActivator) @@ -5354,6 +5427,7 @@ private: //void InputSetTarget( inputdata_t &inputdata ) { BaseClass::InputSetTarget(inputdata); m_hTarget = NULL; } void InputGetNumSkins( inputdata_t &inputdata ); void InputLookupSequence( inputdata_t &inputdata ); + void InputLookupActivity( inputdata_t &inputdata ); // Outputs COutputInt m_OutNumSkins; @@ -5371,6 +5445,7 @@ BEGIN_DATADESC( CLogicModelInfo ) // Inputs DEFINE_INPUTFUNC( FIELD_VOID, "GetNumSkins", InputGetNumSkins ), DEFINE_INPUTFUNC( FIELD_STRING, "LookupSequence", InputLookupSequence ), + DEFINE_INPUTFUNC( FIELD_STRING, "LookupActivity", InputLookupActivity ), // Outputs DEFINE_OUTPUT(m_OutNumSkins, "OutNumSkins"), @@ -5416,6 +5491,34 @@ void CLogicModelInfo::InputLookupSequence( inputdata_t &inputdata ) } } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CLogicModelInfo::InputLookupActivity( inputdata_t &inputdata ) +{ + CBaseAnimating *pAnimating = GetTarget(inputdata); + if (pAnimating && pAnimating->GetModelPtr()) + { + int iActivity = ActivityList_IndexForName(inputdata.value.String()); + if (iActivity == -1) + { + // Check if it's a raw activity ID + iActivity = atoi(inputdata.value.String()); + if (!ActivityList_NameForIndex(iActivity)) + { + Msg("%s received invalid LookupActivity %s\n", inputdata.value.String()); + return; + } + } + + int index = pAnimating->SelectWeightedSequence((Activity)iActivity); + + if (index != ACT_INVALID) + m_OnHasSequence.Set(index, pAnimating, this); + else + m_OnLacksSequence.FireOutput(pAnimating, this); + } +} + //----------------------------------------------------------------------------- // Purpose: Checks and calculates an entity's position. //----------------------------------------------------------------------------- @@ -5441,7 +5544,8 @@ private: CBaseEntity *GetTarget(CBaseEntity *pActivator, CBaseEntity *pCaller); - Vector GetPosition(CBaseEntity *pEntity); + const Vector &GetPosition(CBaseEntity *pEntity); + const QAngle &GetAngles(CBaseEntity *pEntity); // Inputs void InputGetPosition( inputdata_t &inputdata ); @@ -5452,6 +5556,7 @@ private: // Outputs COutputVector m_OutPosition; + COutputVector m_OutAngles; DECLARE_DATADESC(); }; @@ -5472,6 +5577,7 @@ BEGIN_DATADESC( CLogicEntityPosition ) // Outputs DEFINE_OUTPUT(m_OutPosition, "OutPosition"), + DEFINE_OUTPUT(m_OutAngles, "OutAngles"), END_DATADESC() @@ -5487,16 +5593,15 @@ inline CBaseEntity *CLogicEntityPosition::GetTarget(CBaseEntity *pActivator, CBa //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -Vector CLogicEntityPosition::GetPosition(CBaseEntity *pEntity) +const Vector &CLogicEntityPosition::GetPosition(CBaseEntity *pEntity) { - Vector vecPosition = vec3_origin; switch (m_iPositionType) { - case POSITION_ORIGIN: vecPosition = pEntity->GetAbsOrigin(); break; - case POSITION_LOCAL: vecPosition = pEntity->GetLocalOrigin(); break; - case POSITION_BBOX: vecPosition = pEntity->WorldSpaceCenter(); break; - case POSITION_EYES: vecPosition = pEntity->EyePosition(); break; - case POSITION_EARS: vecPosition = pEntity->EarPosition(); break; + case POSITION_ORIGIN: return pEntity->GetAbsOrigin(); + case POSITION_LOCAL: return pEntity->GetLocalOrigin(); + case POSITION_BBOX: return pEntity->WorldSpaceCenter(); + case POSITION_EYES: return pEntity->EyePosition(); + case POSITION_EARS: return pEntity->EarPosition(); case POSITION_ATTACHMENT: { CBaseAnimating *pAnimating = pEntity->GetBaseAnimating(); @@ -5506,10 +5611,47 @@ Vector CLogicEntityPosition::GetPosition(CBaseEntity *pEntity) break; } + // Attachment position doesn't originate anywhere, so use a static variable + static Vector vecPosition; pAnimating->GetAttachment(STRING(m_iszPositionParameter), vecPosition); + return vecPosition; + } + } + + return vec3_origin; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +const QAngle &CLogicEntityPosition::GetAngles(CBaseEntity *pEntity) +{ + const QAngle *angAngles = &vec3_angle; + switch (m_iPositionType) + { + case POSITION_BBOX: + case POSITION_EARS: + case POSITION_ORIGIN: angAngles = &pEntity->GetAbsAngles(); break; + case POSITION_LOCAL: angAngles = &pEntity->GetLocalAngles(); break; + case POSITION_EYES: angAngles = &pEntity->EyeAngles(); break; + case POSITION_ATTACHMENT: + { + CBaseAnimating *pAnimating = pEntity->GetBaseAnimating(); + if (!pAnimating) + { + Warning("%s wants to measure one of %s's attachments, but %s doesn't support them!\n", GetDebugName(), pEntity->GetDebugName(), pEntity->GetDebugName()); + break; + } + + // Attachment angles don't originate anywhere, so use a static variable + static QAngle AttachmentAngles; + matrix3x4_t attachmentToWorld; + pAnimating->GetAttachment( pAnimating->LookupAttachment( STRING( m_iszPositionParameter ) ), attachmentToWorld ); + MatrixAngles( attachmentToWorld, AttachmentAngles ); + angAngles = &AttachmentAngles; } break; } - return vecPosition; + + return *angAngles; } //----------------------------------------------------------------------------- @@ -5518,9 +5660,14 @@ void CLogicEntityPosition::InputGetPosition( inputdata_t &inputdata ) { CBaseEntity *pEntity = GetTarget(inputdata.pActivator, inputdata.pCaller); if (!pEntity) - m_OutPosition.Set(vec3_origin, NULL, this); + { + m_OutPosition.Set( vec3_origin, NULL, this ); + m_OutAngles.Set( vec3_angle, NULL, this ); + return; + } - m_OutPosition.Set(GetPosition(pEntity), pEntity, this); + m_OutPosition.Set( GetPosition(pEntity), pEntity, this ); + m_OutAngles.Set( GetAngles(pEntity), pEntity, this ); } //----------------------------------------------------------------------------- @@ -5550,12 +5697,20 @@ void CLogicEntityPosition::InputPredictPosition( inputdata_t &inputdata ) { CBaseEntity *pEntity = GetTarget(inputdata.pActivator, inputdata.pCaller); if (!pEntity) - m_OutPosition.Set(vec3_origin, NULL, this); + { + m_OutPosition.Set( vec3_origin, NULL, this ); + m_OutAngles.Set( vec3_angle, NULL, this ); + return; + } Vector vecPosition; UTIL_PredictedPosition(pEntity, GetPosition(pEntity), inputdata.value.Float(), &vecPosition); - m_OutPosition.Set(vecPosition, pEntity, this); + QAngle angAngles; + UTIL_PredictedAngles(pEntity, GetAngles(pEntity), inputdata.value.Float(), &angAngles); + + m_OutPosition.Set( vecPosition, pEntity, this ); + m_OutAngles.Set( angAngles, pEntity, this ); } //----------------------------------------------------------------------------- @@ -6190,12 +6345,16 @@ public: // Inputs void InputSetValue( inputdata_t &inputdata ); void InputSetValueNoFire( inputdata_t &inputdata ); + void InputGetValue( inputdata_t &inputdata ); void InputSetGenerateType( inputdata_t &inputdata ); void InputEnable( inputdata_t &inputdata ); void InputDisable( inputdata_t &inputdata ); void InputToggle( inputdata_t &inputdata ); + void UpdateOutValue( float fNewValue, CBaseEntity *pActivator = NULL ); + void UpdateOutValueSine( float fNewValue, CBaseEntity *pActivator = NULL ); + // Basic functions void Spawn(); bool KeyValue( const char *szKeyName, const char *szValue ); @@ -6213,8 +6372,16 @@ public: // The gaussian stream normally only exists on the client, so we use our own. static CGaussianRandomStream m_GaussianStream; + bool m_bHitMin; // Set when we reach or go below our minimum value, cleared if we go above it again. + bool m_bHitMax; // Set when we reach or exceed our maximum value, cleared if we fall below it again. + // Outputs - COutputFloat m_Value; + COutputFloat m_OutValue; + COutputFloat m_OnGetValue; // Used for polling the counter value. + COutputEvent m_OnHitMin; + COutputEvent m_OnHitMax; + COutputEvent m_OnChangedFromMin; + COutputEvent m_OnChangedFromMax; DECLARE_DATADESC(); }; @@ -6232,15 +6399,24 @@ BEGIN_DATADESC( CMathGenerate ) DEFINE_KEYFIELD( m_iGenerateType, FIELD_INTEGER, "GenerateType" ), + DEFINE_FIELD( m_bHitMax, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bHitMin, FIELD_BOOLEAN ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetValue", InputSetValue ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetValueNoFire", InputSetValueNoFire ), + DEFINE_INPUTFUNC( FIELD_VOID, "GetValue", InputGetValue ), DEFINE_INPUTFUNC( FIELD_INTEGER, "SetGenerateType", InputSetGenerateType ), DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ), - DEFINE_OUTPUT( m_Value, "OutValue" ), + DEFINE_OUTPUT( m_OutValue, "OutValue" ), + DEFINE_OUTPUT( m_OnHitMin, "OnHitMin" ), + DEFINE_OUTPUT( m_OnHitMax, "OnHitMax" ), + DEFINE_OUTPUT( m_OnGetValue, "OnGetValue" ), + DEFINE_OUTPUT( m_OnChangedFromMin, "OnChangedFromMin" ), + DEFINE_OUTPUT( m_OnChangedFromMax, "OnChangedFromMax" ), DEFINE_THINKFUNC( GenerateSineWave ), DEFINE_THINKFUNC( GenerateLinearRamp ), @@ -6278,7 +6454,7 @@ bool CMathGenerate::KeyValue( const char *szKeyName, const char *szValue ) { if (FStrEq( szKeyName, "InitialValue" )) { - m_Value.Init( atof(szValue) ); + m_OutValue.Init( atof(szValue) ); } else return BaseClass::KeyValue( szKeyName, szValue ); @@ -6290,14 +6466,22 @@ bool CMathGenerate::KeyValue( const char *szKeyName, const char *szValue ) //----------------------------------------------------------------------------- void CMathGenerate::InputSetValue( inputdata_t &inputdata ) { - m_Value.Set(inputdata.value.Float(), inputdata.pActivator, this); + UpdateOutValue(inputdata.value.Float(), inputdata.pActivator); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CMathGenerate::InputSetValueNoFire( inputdata_t &inputdata ) { - m_Value.Init(inputdata.value.Float()); + m_OutValue.Init(inputdata.value.Float()); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CMathGenerate::InputGetValue( inputdata_t &inputdata ) +{ + float flOutValue = m_OutValue.Get(); + m_OnGetValue.Set( flOutValue, inputdata.pActivator, inputdata.pCaller ); } //----------------------------------------------------------------------------- @@ -6337,6 +6521,123 @@ void CMathGenerate::InputToggle( inputdata_t &inputdata ) m_bDisabled ? InputEnable(inputdata) : InputDisable(inputdata); } +//----------------------------------------------------------------------------- +// Purpose: Sets the value to the new value, clamping and firing the output value. +// Input : fNewValue - Value to set. +//----------------------------------------------------------------------------- +void CMathGenerate::UpdateOutValue( float fNewValue, CBaseEntity *pActivator ) +{ + if ((m_flMin != 0) || (m_flMax != 0)) + { + // + // Fire an output any time we reach or exceed our maximum value. + // + if ( fNewValue >= m_flMax || (m_iGenerateType == GENERATE_SINE_WAVE && fNewValue >= (m_flMax * 0.995f)) ) + { + if ( !m_bHitMax ) + { + m_bHitMax = true; + m_OnHitMax.FireOutput( pActivator, this ); + } + } + else + { + // Fire an output if we just changed from the maximum value + if ( m_OutValue.Get() == m_flMax ) + { + m_OnChangedFromMax.FireOutput( pActivator, this ); + } + + m_bHitMax = false; + } + + // + // Fire an output any time we reach or go below our minimum value. + // + if ( fNewValue <= m_flMin ) + { + if ( !m_bHitMin ) + { + m_bHitMin = true; + m_OnHitMin.FireOutput( pActivator, this ); + } + } + else + { + // Fire an output if we just changed from the maximum value + if ( m_OutValue.Get() == m_flMin ) + { + m_OnChangedFromMin.FireOutput( pActivator, this ); + } + + m_bHitMin = false; + } + + fNewValue = clamp(fNewValue, m_flMin, m_flMax); + } + + m_OutValue.Set(fNewValue, pActivator, this); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the value to the new value, clamping and firing the output value. +// Sine generation needs to use a different function to account for skips and imprecision. +// Input : fNewValue - Value to set. +//----------------------------------------------------------------------------- +void CMathGenerate::UpdateOutValueSine( float fNewValue, CBaseEntity *pActivator ) +{ + if ((m_flMin != 0) || (m_flMax != 0)) + { + // + // Fire an output any time we reach or exceed our maximum value. + // + if ( fNewValue >= (m_flMax * 0.995f) ) + { + if ( !m_bHitMax ) + { + m_bHitMax = true; + m_OnHitMax.FireOutput( pActivator, this ); + } + } + else + { + // Fire an output if we just changed from the maximum value + if ( m_bHitMax ) + { + m_OnChangedFromMax.FireOutput( pActivator, this ); + } + + m_bHitMax = false; + } + + // + // Fire an output any time we reach or go below our minimum value. + // + if ( fNewValue <= (m_flMin * 1.005f) ) + { + if ( !m_bHitMin ) + { + m_bHitMin = true; + m_OnHitMin.FireOutput( pActivator, this ); + } + } + else + { + // Fire an output if we just changed from the maximum value + if ( m_bHitMin ) + { + m_OnChangedFromMin.FireOutput( pActivator, this ); + } + + m_bHitMin = false; + } + + //fNewValue = clamp(fNewValue, m_flMin, m_flMax); + } + + m_OutValue.Set(fNewValue, pActivator, this); +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CMathGenerate::StartGenerating() @@ -6402,7 +6703,7 @@ void CMathGenerate::GenerateSineWave() // get a value in [min,max] flValue = ( m_flMax - m_flMin ) * flValue + m_flMin; - m_Value.Set( flValue, NULL, this ); + UpdateOutValueSine( flValue ); SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); } @@ -6414,7 +6715,7 @@ void CMathGenerate::GenerateLinearRamp() // CLinearRampProxy in mathproxy.cpp // Param1 = rate - float flVal = m_flParam1 * gpGlobals->curtime + m_Value.Get(); + float flVal = m_flParam1 * gpGlobals->curtime + m_OutValue.Get(); // clamp if (flVal < m_flMin) @@ -6422,7 +6723,7 @@ void CMathGenerate::GenerateLinearRamp() else if (flVal > m_flMax) flVal = m_flMax; - m_Value.Set( flVal, NULL, this ); + UpdateOutValue( flVal ); SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); } @@ -6433,7 +6734,7 @@ void CMathGenerate::GenerateUniformNoise() { // CUniformNoiseProxy in mathproxy.cpp - m_Value.Set( random->RandomFloat( m_flMin, m_flMax ), NULL, this ); + UpdateOutValue( random->RandomFloat( m_flMin, m_flMax ) ); SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); } @@ -6454,7 +6755,7 @@ void CMathGenerate::GenerateGaussianNoise() else if (flVal > m_flMax) flVal = m_flMax; - m_Value.Set( flVal, NULL, this ); + UpdateOutValue( flVal ); SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); } @@ -6467,7 +6768,7 @@ void CMathGenerate::GenerateExponential() // Param1 = scale // Param2 = offset - float flVal = m_flParam1 * exp( m_Value.Get() + m_flParam2 ); + float flVal = m_flParam1 * exp( m_OutValue.Get() + m_flParam2 ); // clamp if (flVal < m_flMin) @@ -6475,7 +6776,7 @@ void CMathGenerate::GenerateExponential() else if (flVal > m_flMax) flVal = m_flMax; - m_Value.Set( flVal, NULL, this ); + UpdateOutValue( flVal ); SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); } diff --git a/sp/src/game/server/mapbase/SystemConvarMod.cpp b/sp/src/game/server/mapbase/SystemConvarMod.cpp index d3e610ba..7b0c52e1 100644 --- a/sp/src/game/server/mapbase/SystemConvarMod.cpp +++ b/sp/src/game/server/mapbase/SystemConvarMod.cpp @@ -92,19 +92,17 @@ void CVEnt_Precache(CMapbaseCVarModEntity *modent) if (Q_strstr(STRING(modent->m_target), "sv_allow_logic_convar")) return; +#ifdef MAPBASE_MP + if (gpGlobals->maxClients > 1 && !modent->m_bUseServer) + { + Warning("WARNING: %s is using the local player in a multiplayer game and will not function.\n", modent->GetDebugName()); + } +#endif + CV_InitMod(); } -void CVEnt_Activate(CMapbaseCVarModEntity *modent, CBaseEntity *pActivator = UTIL_GetLocalPlayer()) +void CVEnt_Activate(CMapbaseCVarModEntity *modent) { - edict_t *edict = pActivator ? pActivator->edict() : NULL; - if (!edict) - return; - - SetChangingCVars( modent ); - - if (m_ModEntities.Find(modent) == m_ModEntities.InvalidIndex()) - m_ModEntities.AddToTail(modent); - const char *pszCommands = STRING( modent->m_target ); if ( Q_strnchr(pszCommands, '^', MAX_CONVARMOD_STRING_SIZE) ) { @@ -123,8 +121,29 @@ void CVEnt_Activate(CMapbaseCVarModEntity *modent, CBaseEntity *pActivator = UTI pszCommands = szTmp; } - engine->ClientCommand( edict, pszCommands ); - engine->ClientCommand( edict, "mapbase_cvarsnotchanging\n" ); + if (modent->m_bUseServer) + { + SetChangingCVars( modent ); + + engine->ServerCommand( pszCommands ); + engine->ServerCommand( "mapbase_cvarsnotchanging" ); + } + else + { + CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); + edict_t *edict = pPlayer ? pPlayer->edict() : NULL; + if (edict) + { + SetChangingCVars( modent ); + + engine->ClientCommand( edict, pszCommands ); + engine->ClientCommand( edict, "mapbase_cvarsnotchanging" ); + } + else + { + Warning("%s unable to find local player edict\n", modent->GetDebugName()); + } + } } void CVEnt_Deactivate(CMapbaseCVarModEntity *modent) { @@ -173,6 +192,7 @@ LINK_ENTITY_TO_CLASS( mapbase_convar_mod, CMapbaseCVarModEntity ); BEGIN_DATADESC( CMapbaseCVarModEntity ) DEFINE_UTLVECTOR( m_ModifiedConvars, FIELD_EMBEDDED ), + DEFINE_KEYFIELD( m_bUseServer, FIELD_BOOLEAN, "UseServer" ), // Inputs DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ), diff --git a/sp/src/game/server/mapbase/SystemConvarMod.h b/sp/src/game/server/mapbase/SystemConvarMod.h index f33a7471..10c583da 100644 --- a/sp/src/game/server/mapbase/SystemConvarMod.h +++ b/sp/src/game/server/mapbase/SystemConvarMod.h @@ -42,6 +42,7 @@ public: bool NewCVar( ConVarRef *var, const char *pOldString, CBaseEntity *modent ); CUtlVector< modifiedconvars_t > m_ModifiedConvars; + bool m_bUseServer; DECLARE_DATADESC(); }; diff --git a/sp/src/game/server/physobj.cpp b/sp/src/game/server/physobj.cpp index 8bb78cbd..c486fa80 100644 --- a/sp/src/game/server/physobj.cpp +++ b/sp/src/game/server/physobj.cpp @@ -565,6 +565,13 @@ int CPhysBox::ObjectCaps() } } +#ifdef MAPBASE + if ( HasSpawnFlags( SF_PHYSBOX_RADIUS_PICKUP ) ) + { + caps |= FCAP_USE_IN_RADIUS; + } +#endif + return caps; } diff --git a/sp/src/game/server/physobj.h b/sp/src/game/server/physobj.h index 4c95c28c..09d333c5 100644 --- a/sp/src/game/server/physobj.h +++ b/sp/src/game/server/physobj.h @@ -37,6 +37,9 @@ #define SF_PHYSBOX_NEVER_PICK_UP 0x200000 // Physcannon will never be able to pick this up. #define SF_PHYSBOX_NEVER_PUNT 0x400000 // Physcannon will never be able to punt this object. #define SF_PHYSBOX_PREVENT_PLAYER_TOUCH_ENABLE 0x800000 // If set, the player will not cause the object to enable its motion when bumped into +#ifdef MAPBASE +#define SF_PHYSBOX_RADIUS_PICKUP 0x1000000 // Allows this object to be picked up in a radius, useful for smaller objects. Based on the prop_physics input +#endif // UNDONE: Hook collisions into the physics system to generate touch functions and take damage on falls // UNDONE: Base class PhysBrush diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 026b3ea3..511ebd0b 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -82,6 +82,7 @@ #include "weapon_physcannon.h" #ifdef MAPBASE #include "mapbase/GlobalStrings.h" +#include "mapbase/matchers.h" #endif #endif @@ -7982,11 +7983,17 @@ public: #ifdef MAPBASE void InputEnable(inputdata_t &data); void InputDisable(inputdata_t &data); + + void InputSetAdditionalButtons(inputdata_t &data); #endif private: int GetDisabledButtonMask( void ); +#ifdef MAPBASE + int m_iAdditionalButtons; +#endif + DECLARE_DATADESC(); }; @@ -7997,6 +8004,9 @@ BEGIN_DATADESC( CMovementSpeedMod ) #ifdef MAPBASE DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), + + DEFINE_KEYFIELD( m_iAdditionalButtons, FIELD_INTEGER, "AdditionalButtons" ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetAdditionalButtons", InputSetAdditionalButtons ), #endif END_DATADESC() @@ -8034,6 +8044,13 @@ int CMovementSpeedMod::GetDisabledButtonMask( void ) nMask |= IN_ZOOM; } +#ifdef MAPBASE + if ( m_iAdditionalButtons != 0 ) + { + nMask |= m_iAdditionalButtons; + } +#endif + return nMask; } @@ -8102,8 +8119,15 @@ void CMovementSpeedMod::InputSpeedMod(inputdata_t &data) } } +#ifdef MAPBASE + if ( !HasSpawnFlags( SF_SPEED_MOD_DONT_SUPPRESS_FLASHLIGHT ) ) + { +#endif // Allow the flashlight again pPlayer->SetFlashlightEnabled( true ); +#ifdef MAPBASE + } +#endif pPlayer->EnableButtons( GetDisabledButtonMask() ); // Restore the HUD @@ -8200,6 +8224,120 @@ void CMovementSpeedMod::InputDisable(inputdata_t &data) } } } + +void CMovementSpeedMod::InputSetAdditionalButtons(inputdata_t &data) +{ + CBasePlayer *pPlayer = NULL; + + if ( data.pActivator && data.pActivator->IsPlayer() ) + { + pPlayer = (CBasePlayer *)data.pActivator; + } + else if ( !g_pGameRules->IsDeathmatch() ) + { + pPlayer = UTIL_GetLocalPlayer(); + } + + bool bAlreadyDisabled = false; + if ( pPlayer ) + { + bAlreadyDisabled = (pPlayer->m_afButtonDisabled & GetDisabledButtonMask()) != 0; + } + + m_iAdditionalButtons = data.value.Int(); + + // If we were already disabling buttons, re-disable them + if ( bAlreadyDisabled ) + { + // We should probably do something better than this. + pPlayer->m_afButtonForced = GetDisabledButtonMask(); + } +} +#endif + +#ifdef MAPBASE +class CLogicPlayerInfo : public CPointEntity +{ + DECLARE_CLASS( CLogicPlayerInfo, CPointEntity ); +public: + void InputGetPlayerInfo( inputdata_t &inputdata ); + void InputGetPlayerByID( inputdata_t &inputdata ); + void InputGetPlayerByName( inputdata_t &inputdata ); + + void GetPlayerInfo( CBasePlayer *pPlayer ); + + COutputInt m_OutUserID; + COutputString m_OutPlayerName; + COutputEHANDLE m_OutPlayerEntity; + + DECLARE_DATADESC(); +}; + +LINK_ENTITY_TO_CLASS( logic_playerinfo, CLogicPlayerInfo ); + +BEGIN_DATADESC( CLogicPlayerInfo ) + DEFINE_INPUTFUNC( FIELD_EHANDLE, "GetPlayerInfo", InputGetPlayerInfo ), + DEFINE_INPUTFUNC( FIELD_STRING, "GetPlayerByID", InputGetPlayerByID ), + DEFINE_INPUTFUNC( FIELD_STRING, "GetPlayerByName", InputGetPlayerByName ), + + DEFINE_OUTPUT( m_OutUserID, "OutUserID" ), + DEFINE_OUTPUT( m_OutPlayerName, "OutPlayerName" ), + DEFINE_OUTPUT( m_OutPlayerEntity, "OutPlayerEntity" ), +END_DATADESC() + + +void CLogicPlayerInfo::InputGetPlayerInfo( inputdata_t &inputdata ) +{ + CBasePlayer *pPlayer = ToBasePlayer(inputdata.value.Entity()); + + // If there was no entity to begin with, try the local player + if (!pPlayer && !inputdata.value.Entity()) + pPlayer = UTIL_GetLocalPlayer(); + + if (pPlayer) + GetPlayerInfo( pPlayer ); +} + +void CLogicPlayerInfo::InputGetPlayerByID( inputdata_t &inputdata ) +{ + for (int i = 1; i < gpGlobals->maxClients; i++) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + if (pPlayer) + { + if (Matcher_NamesMatch( inputdata.value.String(), UTIL_VarArgs("%i", pPlayer->GetUserID()) )) + { + GetPlayerInfo( pPlayer ); + return; + } + } + } +} + +void CLogicPlayerInfo::InputGetPlayerByName( inputdata_t &inputdata ) +{ + for (int i = 1; i < gpGlobals->maxClients; i++) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + if (pPlayer) + { + if (Matcher_NamesMatch( inputdata.value.String(), pPlayer->GetPlayerName() )) + { + GetPlayerInfo( pPlayer ); + return; + } + } + } +} + +void CLogicPlayerInfo::GetPlayerInfo( CBasePlayer *pPlayer ) +{ + m_OutUserID.Set( pPlayer->GetUserID(), pPlayer, this ); + + m_OutPlayerName.Set( AllocPooledString(pPlayer->GetPlayerName()), pPlayer, this ); + + m_OutPlayerEntity.Set( pPlayer, pPlayer, this ); +} #endif diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 878046af..82226fac 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -755,6 +755,41 @@ void CBreakableProp::HandleInteractionStick( int index, gamevcollisionevent_t *p } } +#ifdef MAPBASE +extern int g_interactionBarnacleVictimBite; +extern ConVar npc_barnacle_ignite; +//----------------------------------------------------------------------------- +// Purpose: Uses the new CBaseEntity interaction implementation +// Input : The type of interaction, extra info pointer, and who started it +// Output : true - if sub-class has a response for the interaction +// false - if sub-class has no response +//----------------------------------------------------------------------------- +bool CBreakableProp::HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ) +{ +#ifdef HL2_EPISODIC + // Allows flares to ignite barnacles. + if ( interactionType == g_interactionBarnacleVictimBite ) + { + if ( npc_barnacle_ignite.GetBool() && sourceEnt->IsOnFire() == false ) + { + sourceEnt->Ignite( 25.0f ); + KillFlare( this, m_hFlareEnt, PROP_FLARE_IGNITE_SUBSTRACT ); + IGameEvent *event = gameeventmanager->CreateEvent( "flare_ignite_npc" ); + if ( event ) + { + event->SetInt( "entindex", sourceEnt->entindex() ); + gameeventmanager->FireEvent( event ); + } + } + + return true; + } +#endif + + return BaseClass::HandleInteraction(interactionType, data, sourceEnt); +} +#endif + //----------------------------------------------------------------------------- // Purpose: Turn on prop debugging mode //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/props.h b/sp/src/game/server/props.h index 844c1f6c..121dd5c3 100644 --- a/sp/src/game/server/props.h +++ b/sp/src/game/server/props.h @@ -119,6 +119,11 @@ public: void HandleFirstCollisionInteractions( int index, gamevcollisionevent_t *pEvent ); void HandleInteractionStick( int index, gamevcollisionevent_t *pEvent ); void StickAtPosition( const Vector &stickPosition, const Vector &savePosition, const QAngle &saveAngles ); + +#ifdef MAPBASE + // Uses the new CBaseEntity interaction implementation + bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt ); +#endif // Disable auto fading under dx7 or when level fades are specified void DisableAutoFade(); diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index 4dc00f69..14936198 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -4840,7 +4840,13 @@ float InstancedScriptedScene( CBaseFlex *pActor, const char *pszScene, EHANDLE * // *phSceneEnt - // Output : float //----------------------------------------------------------------------------- +#ifdef MAPBASE +float InstancedAutoGeneratedSoundScene( CBaseFlex *pActor, const char *soundname, EHANDLE *phSceneEnt, + float flPostDelay, bool bIsBackground, AI_Response *response, + bool bMultiplayer, IRecipientFilter *filter /* = NULL */ ) +#else float InstancedAutoGeneratedSoundScene( CBaseFlex *pActor, char const *soundname, EHANDLE *phSceneEnt /*= NULL*/ ) +#endif { if ( !pActor ) { @@ -4858,10 +4864,38 @@ float InstancedAutoGeneratedSoundScene( CBaseFlex *pActor, char const *soundname pScene->GenerateSoundScene( pActor, soundname ); +#ifdef MAPBASE + pScene->m_bMultiplayer = bMultiplayer; + pScene->SetPostSpeakDelay( flPostDelay ); + DispatchSpawn( pScene ); + pScene->Activate(); + pScene->m_bIsBackground = bIsBackground; + + pScene->SetBackground( bIsBackground ); + pScene->SetRecipientFilter( filter ); + + if ( response ) + { + float flPreDelay = response->GetPreDelay(); + if ( flPreDelay ) + { + pScene->SetPreDelay( flPreDelay ); + } + } +#else pScene->Spawn(); pScene->Activate(); +#endif pScene->StartPlayback(); +#ifdef MAPBASE + if ( response ) + { + // If the response wants us to abort on NPC state switch, remember that + pScene->SetBreakOnNonIdle( response->ShouldBreakOnNonIdle() ); + } +#endif + if ( phSceneEnt ) { *phSceneEnt = pScene; diff --git a/sp/src/game/server/sceneentity.h b/sp/src/game/server/sceneentity.h index 5fe6a9f0..78a499a2 100644 --- a/sp/src/game/server/sceneentity.h +++ b/sp/src/game/server/sceneentity.h @@ -24,7 +24,11 @@ struct recentNPCSpeech_t int GetRecentNPCSpeech( recentNPCSpeech_t speech[ SPEECH_LIST_MAX_SOUNDS ] ); float InstancedScriptedScene( CBaseFlex *pActor, const char *pszScene, EHANDLE *phSceneEnt = NULL, float flPostDelay = 0.0f, bool bIsBackground = false, AI_Response *response = NULL, bool bMultiplayer = false, IRecipientFilter *filter = NULL ); +#ifdef MAPBASE +float InstancedAutoGeneratedSoundScene( CBaseFlex *pActor, char const *soundname, EHANDLE *phSceneEnt = NULL, float flPostDelay = 0.0f, bool bIsBackground = false, AI_Response *response = NULL, bool bMultiplayer = false, IRecipientFilter *filter = NULL ); +#else float InstancedAutoGeneratedSoundScene( CBaseFlex *pActor, char const *soundname, EHANDLE *phSceneEnt = NULL ); +#endif void StopScriptedScene( CBaseFlex *pActor, EHANDLE hSceneEnt ); void RemoveActorFromScriptedScenes( CBaseFlex *pActor, bool instancedscenesonly, bool nonidlescenesonly = false, const char *pszThisSceneOnly = NULL ); void RemoveAllScenesInvolvingActor( CBaseFlex *pActor ); diff --git a/sp/src/game/server/scripted.cpp b/sp/src/game/server/scripted.cpp index 7a7b615c..3a282ca1 100644 --- a/sp/src/game/server/scripted.cpp +++ b/sp/src/game/server/scripted.cpp @@ -118,6 +118,9 @@ BEGIN_DATADESC( CAI_ScriptedSequence ) DEFINE_OUTPUT(m_OnScriptEvent[5], "OnScriptEvent06"), DEFINE_OUTPUT(m_OnScriptEvent[6], "OnScriptEvent07"), DEFINE_OUTPUT(m_OnScriptEvent[7], "OnScriptEvent08"), +#ifdef MAPBASE + DEFINE_OUTPUT(m_OnPreIdleSequence, "OnPreIdleSequence"), +#endif END_DATADESC() @@ -838,6 +841,11 @@ void CAI_ScriptedSequence::OnBeginSequence( CBaseEntity *pActor ) { m_OnBeginSequence.FireOutput( pActor, this ); } + +void CAI_ScriptedSequence::OnPreIdleSequence( CBaseEntity *pActor ) +{ + m_OnPreIdleSequence.FireOutput( pActor, this ); +} #else void CAI_ScriptedSequence::OnBeginSequence( void ) { @@ -1125,7 +1133,11 @@ void CAI_ScriptedSequence::PostIdleDone( CAI_BaseNPC *pNPC ) } //Msg("%s finished post idle at %0.2f\n", pNPC->GetDebugName(), gpGlobals->curtime ); +#ifdef MAPBASE + m_OnPostIdleEndSequence.FireOutput(pNPC, this); +#else m_OnPostIdleEndSequence.FireOutput(NULL, this); +#endif } diff --git a/sp/src/game/server/scripted.h b/sp/src/game/server/scripted.h index 50f962f3..20ac4c1d 100644 --- a/sp/src/game/server/scripted.h +++ b/sp/src/game/server/scripted.h @@ -97,6 +97,7 @@ public: void FireScriptEvent( int nEvent ); #ifdef MAPBASE void OnBeginSequence( CBaseEntity *pActor ); + void OnPreIdleSequence( CBaseEntity *pActor ); #else void OnBeginSequence( void ); #endif @@ -218,6 +219,9 @@ private: COutputEvent m_OnCancelSequence; COutputEvent m_OnCancelFailedSequence; // Fired when a scene is cancelled before it's ever run COutputEvent m_OnScriptEvent[MAX_SCRIPT_EVENTS]; +#ifdef MAPBASE + COutputEvent m_OnPreIdleSequence; +#endif static void ScriptEntityCancel( CBaseEntity *pentCine, bool bPretendSuccess = false ); diff --git a/sp/src/game/server/server_mapbase.vpc b/sp/src/game/server/server_mapbase.vpc index 9cc3c160..0df92c87 100644 --- a/sp/src/game/server/server_mapbase.vpc +++ b/sp/src/game/server/server_mapbase.vpc @@ -26,6 +26,7 @@ $Project { $File "$SRCDIR\game\shared\mapbase\mapbase_shared.cpp" $File "$SRCDIR\game\shared\mapbase\mapbase_rpc.cpp" + $File "$SRCDIR\game\shared\mapbase\mapbase_game_log.cpp" $File "$SRCDIR\game\shared\mapbase\MapEdit.cpp" $File "$SRCDIR\game\shared\mapbase\MapEdit.h" diff --git a/sp/src/game/server/util.cpp b/sp/src/game/server/util.cpp index 3adaeafe..c0e8912d 100644 --- a/sp/src/game/server/util.cpp +++ b/sp/src/game/server/util.cpp @@ -36,6 +36,9 @@ #include "datacache/imdlcache.h" #include "util.h" #include "cdll_int.h" +#ifdef MAPBASE +#include "fmtstr.h" +#endif #ifdef PORTAL #include "PortalSimulation.h" @@ -204,6 +207,46 @@ void CEntityFactoryDictionary::ReportEntitySizes() } } +#ifdef MAPBASE +int EntityFactory_AutoComplete( const char *cmdname, CUtlVector< CUtlString > &commands, CUtlRBTree< CUtlString > &symbols, char *substring, int checklen = 0 ) +{ + CEntityFactoryDictionary *pFactoryDict = (CEntityFactoryDictionary*)EntityFactoryDictionary(); + for ( int i = pFactoryDict->m_Factories.First(); i != pFactoryDict->m_Factories.InvalidIndex(); i = pFactoryDict->m_Factories.Next( i ) ) + { + const char *name = pFactoryDict->m_Factories.GetElementName( i ); + if (Q_strnicmp(name, substring, checklen)) + continue; + + CUtlString sym = name; + int idx = symbols.Find(sym); + if (idx == symbols.InvalidIndex()) + { + symbols.Insert(sym); + } + + // Too many + if (symbols.Count() >= COMMAND_COMPLETION_MAXITEMS) + break; + } + + // Now fill in the results + for (int i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder(i)) + { + const char *name = symbols[i].String(); + + char buf[512]; + Q_strncpy(buf, name, sizeof(buf)); + Q_strlower(buf); + + CUtlString command; + command = CFmtStr("%s %s", cmdname, buf); + commands.AddToTail(command); + } + + return symbols.Count(); +} +#endif + //----------------------------------------------------------------------------- // class CFlaggedEntitiesEnum @@ -2507,6 +2550,10 @@ void UTIL_PredictedPosition( CBaseEntity *pTarget, float flTimeDelta, Vector *ve if ( pAnimating != NULL ) { vecPredictedVel = pAnimating->GetGroundSpeedVelocity(); +#ifdef MAPBASE + if (vecPredictedVel.IsZero()) + vecPredictedVel = pAnimating->GetSmoothedVelocity(); +#endif } else { @@ -2524,7 +2571,7 @@ void UTIL_PredictedPosition( CBaseEntity *pTarget, float flTimeDelta, Vector *ve //----------------------------------------------------------------------------- // Purpose: Same as above, except you don't have to use the absolute origin and can use your own position to predict from. //----------------------------------------------------------------------------- -void UTIL_PredictedPosition( CBaseEntity *pTarget, Vector &vecActualPosition, float flTimeDelta, Vector *vecPredictedPosition ) +void UTIL_PredictedPosition( CBaseEntity *pTarget, const Vector &vecActualPosition, float flTimeDelta, Vector *vecPredictedPosition ) { if ( ( pTarget == NULL ) || ( vecPredictedPosition == NULL ) ) return; @@ -2547,7 +2594,11 @@ void UTIL_PredictedPosition( CBaseEntity *pTarget, Vector &vecActualPosition, fl { CBaseAnimating *pAnimating = dynamic_cast(pTarget); if ( pAnimating != NULL ) + { vecPredictedVel = pAnimating->GetGroundSpeedVelocity(); + if (vecPredictedVel.IsZero()) + vecPredictedVel = pAnimating->GetSmoothedVelocity(); + } else vecPredictedVel = pTarget->GetSmoothedVelocity(); } @@ -2556,6 +2607,38 @@ void UTIL_PredictedPosition( CBaseEntity *pTarget, Vector &vecActualPosition, fl // Get the result (*vecPredictedPosition) = vecActualPosition + ( vecPredictedVel * flTimeDelta ); } + +//----------------------------------------------------------------------------- +// Purpose: Predicts angles through angular velocity instead of predicting origin through regular velocity. +//----------------------------------------------------------------------------- +void UTIL_PredictedAngles( CBaseEntity *pTarget, const QAngle &angActualAngles, float flTimeDelta, QAngle *angPredictedAngles ) +{ + if ( ( pTarget == NULL ) || ( angPredictedAngles == NULL ) ) + return; + + QAngle angPredictedVel; + CBasePlayer *pPlayer = ToBasePlayer( pTarget ); + if ( pPlayer != NULL ) + { + if ( pPlayer->IsInAVehicle() ) + angPredictedVel = pPlayer->GetVehicleEntity()->GetLocalAngularVelocity(); + else + angPredictedVel = pPlayer->GetLocalAngularVelocity(); + } + else + { + CBaseCombatCharacter *pCCTarget = pTarget->MyCombatCharacterPointer(); + if ( pCCTarget != NULL && pCCTarget->IsInAVehicle() ) + angPredictedVel = pCCTarget->GetVehicleEntity()->GetLocalAngularVelocity(); + else + { + angPredictedVel = pTarget->GetLocalAngularVelocity(); + } + } + + // Get the result + (*angPredictedAngles) = angActualAngles + ( angPredictedVel * flTimeDelta ); +} #endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/util.h b/sp/src/game/server/util.h index beebed8a..d13cb3a7 100644 --- a/sp/src/game/server/util.h +++ b/sp/src/game/server/util.h @@ -379,7 +379,8 @@ void UTIL_AxisStringToUnitDir( Vector &dir, const char *pString ); void UTIL_ClipPunchAngleOffset( QAngle &in, const QAngle &punch, const QAngle &clip ); void UTIL_PredictedPosition( CBaseEntity *pTarget, float flTimeDelta, Vector *vecPredictedPosition ); #ifdef MAPBASE -void UTIL_PredictedPosition( CBaseEntity *pTarget, Vector &vecActualPosition, float flTimeDelta, Vector *vecPredictedPosition ); +void UTIL_PredictedPosition( CBaseEntity *pTarget, const Vector &vecActualPosition, float flTimeDelta, Vector *vecPredictedPosition ); +void UTIL_PredictedAngles( CBaseEntity *pTarget, const QAngle &angActualAngles, float flTimeDelta, QAngle *angPredictedAngles ); #endif void UTIL_Beam( Vector &Start, Vector &End, int nModelIndex, int nHaloIndex, unsigned char FrameStart, unsigned char FrameRate, float Life, unsigned char Width, unsigned char EndWidth, unsigned char FadeLength, unsigned char Noise, unsigned char Red, unsigned char Green, diff --git a/sp/src/game/server/variant_t.h b/sp/src/game/server/variant_t.h index 8c37d852..ffd69144 100644 --- a/sp/src/game/server/variant_t.h +++ b/sp/src/game/server/variant_t.h @@ -49,6 +49,10 @@ public: inline const CHandle &Entity(void) const; inline color32 Color32(void) const { return rgbaVal; } inline void Vector3D(Vector &vec) const; +#ifdef MAPBASE + // Gets angles from a vector + inline void Angle3D(QAngle &ang) const; +#endif fieldtype_t FieldType( void ) { return fieldType; } @@ -59,6 +63,10 @@ public: void SetEntity( CBaseEntity *val ); void SetVector3D( const Vector &val ) { vecVal[0] = val[0]; vecVal[1] = val[1]; vecVal[2] = val[2]; fieldType = FIELD_VECTOR; } void SetPositionVector3D( const Vector &val ) { vecVal[0] = val[0]; vecVal[1] = val[1]; vecVal[2] = val[2]; fieldType = FIELD_POSITION_VECTOR; } +#ifdef MAPBASE + // Passes in angles as a vector + void SetAngle3D( const QAngle &val ) { vecVal[0] = val[0]; vecVal[1] = val[1]; vecVal[2] = val[2]; fieldType = FIELD_VECTOR; } +#endif void SetColor32( color32 val ) { rgbaVal = val; fieldType = FIELD_COLOR32; } void SetColor32( int r, int g, int b, int a ) { rgbaVal.r = r; rgbaVal.g = g; rgbaVal.b = b; rgbaVal.a = a; fieldType = FIELD_COLOR32; } void Set( fieldtype_t ftype, void *data ); @@ -112,6 +120,25 @@ inline void variant_t::Vector3D(Vector &vec) const } } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Returns this variant as angles. +//----------------------------------------------------------------------------- +inline void variant_t::Angle3D(QAngle &ang) const +{ + if (( fieldType == FIELD_VECTOR ) || ( fieldType == FIELD_POSITION_VECTOR )) + { + ang[0] = vecVal[0]; + ang[1] = vecVal[1]; + ang[2] = vecVal[2]; + } + else + { + ang = vec3_angle; + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: Returns this variant as an EHANDLE. //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/world.cpp b/sp/src/game/server/world.cpp index 55c1e7b5..af1fea2b 100644 --- a/sp/src/game/server/world.cpp +++ b/sp/src/game/server/world.cpp @@ -376,6 +376,9 @@ BEGIN_DATADESC( CWorld ) // keyvalues are parsed from map, but not saved/loaded DEFINE_KEYFIELD( m_iszChapterTitle, FIELD_STRING, "chaptertitle" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_bChapterTitleNoMessage, FIELD_BOOLEAN, "chaptertitlenomessage" ), +#endif DEFINE_KEYFIELD( m_bStartDark, FIELD_BOOLEAN, "startdark" ), DEFINE_KEYFIELD( m_bDisplayTitle, FIELD_BOOLEAN, "gametitle" ), DEFINE_FIELD( m_WorldMins, FIELD_VECTOR ), @@ -407,6 +410,9 @@ IMPLEMENT_SERVERCLASS_ST(CWorld, DT_WORLD) SendPropFloat (SENDINFO(m_flMinPropScreenSpaceWidth), 0, SPROP_NOSCALE ), SendPropStringT (SENDINFO(m_iszDetailSpriteMaterial) ), SendPropInt (SENDINFO(m_bColdWorld), 1, SPROP_UNSIGNED ), +#ifdef MAPBASE + SendPropStringT (SENDINFO(m_iszChapterTitle) ), +#endif END_SEND_TABLE() // @@ -678,6 +684,23 @@ void CWorld::Precache( void ) // Call all registered precachers. CPrecacheRegister::Precache(); +#ifdef MAPBASE + if ( m_iszChapterTitle.Get() != NULL_STRING && !m_bChapterTitleNoMessage ) + { + DevMsg( 2, "Chapter title: %s\n", STRING(m_iszChapterTitle.Get()) ); + CMessage *pMessage = (CMessage *)CBaseEntity::Create( "env_message", vec3_origin, vec3_angle, NULL ); + if ( pMessage ) + { + pMessage->SetMessage( m_iszChapterTitle.Get() ); + m_iszChapterTitle.Set( NULL_STRING ); + + // send the message entity a play message command, delayed by 1 second + pMessage->AddSpawnFlags( SF_MESSAGE_ONCE ); + pMessage->SetThink( &CMessage::SUB_CallUseToggle ); + pMessage->SetNextThink( gpGlobals->curtime + 1.0f ); + } + } +#else if ( m_iszChapterTitle != NULL_STRING ) { DevMsg( 2, "Chapter title: %s\n", STRING(m_iszChapterTitle) ); @@ -693,6 +716,7 @@ void CWorld::Precache( void ) pMessage->SetNextThink( gpGlobals->curtime + 1.0f ); } } +#endif g_iszFuncBrushClassname = AllocPooledString("func_brush"); } diff --git a/sp/src/game/server/world.h b/sp/src/game/server/world.h index a8547d3c..9c63432f 100644 --- a/sp/src/game/server/world.h +++ b/sp/src/game/server/world.h @@ -52,10 +52,26 @@ public: bool IsColdWorld( void ); +#ifdef MAPBASE + inline const char *GetChapterTitle() + { + return STRING(m_iszChapterTitle.Get()); + } +#endif + private: DECLARE_DATADESC(); +#ifdef MAPBASE + // Now needs to show up on the client for RPC + CNetworkVar( string_t, m_iszChapterTitle ); + + // Suppresses m_iszChapterTitle's env_message creation, + // allowing it to only be used for saves and RPC + bool m_bChapterTitleNoMessage; +#else string_t m_iszChapterTitle; +#endif CNetworkVar( float, m_flWaveHeight ); CNetworkVector( m_WorldMins ); diff --git a/sp/src/game/shared/achievementmgr.cpp b/sp/src/game/shared/achievementmgr.cpp index 93a7167b..7b4727ef 100644 --- a/sp/src/game/shared/achievementmgr.cpp +++ b/sp/src/game/shared/achievementmgr.cpp @@ -1651,6 +1651,13 @@ void CAchievementMgr::OnMapEvent( const char *pchEventName ) CBaseAchievement *pAchievement = m_vecMapEventListeners[iAchievement]; pAchievement->OnMapEvent( pchEventName ); } + +#ifdef MAPBASE + if (cc_achievement_debug.GetBool()) + { + Msg( "CAchievementMgr::OnMapEvent: Achievement \"%s\" not found\n", pchEventName ); + } +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 083e744f..8287cde0 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -814,6 +814,10 @@ void CBaseCombatWeapon::OnPickedUp( CBaseCombatCharacter *pNewOwner ) // Robin: We don't want to delete weapons the player has picked up, so // clear the name of the weapon. This prevents wildcards that are meant // to find NPCs finding weapons dropped by the NPCs as well. +#ifdef MAPBASE + // Level designers might want some weapons to preserve their original names, however. + if ( !HasSpawnFlags(SF_WEAPON_PRESERVE_NAME) ) +#endif SetName( NULL_STRING ); } else diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index 04593691..a35847d6 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -52,20 +52,17 @@ class CUserCmd; // I really, REALLY hope no weapon uses their own spawnflags. // If you want yours to use spawnflags, start at 16 just to be safe. -// Prevents NPCs from picking up the weapon. -#define SF_WEAPON_NO_NPC_PICKUP (1<<3) -// Prevents the weapon from filling up to max automatically -// when picked up by the player or dropped. -#define SF_WEAPON_PRESERVE_AMMO (1<<4) +#define SF_WEAPON_NO_NPC_PICKUP (1<<3) // Prevents NPCs from picking up the weapon. +#define SF_WEAPON_PRESERVE_AMMO (1<<4) // Prevents the weapon from filling up to max automatically when dropped or picked up by players. +#define SF_WEAPON_PRESERVE_NAME (1<<5) // Prevents the weapon's name from being cleared upon being picked up by a player. // ---------------------------------------------- -// Internal Spawnflags -// -// For all of the weapons that show up in-game, I personally feel like -// this beats adding new variables by at least a long shot. +// These spawnflags are not supposed to be used by level designers. +// They're just my way of trying to avoid adding new variables +// that have to stay in memory and save/load. // ---------------------------------------------- -#define SF_WEAPON_NO_AUTO_SWITCH_WHEN_EMPTY (1<<5) // So weapons with ammo preserved at 0 don't switch. -#define SF_WEAPON_USED (1<<6) // Weapon is being +USE'd, not bumped +#define SF_WEAPON_NO_AUTO_SWITCH_WHEN_EMPTY (1<<6) // So weapons with ammo preserved at 0 don't switch. +#define SF_WEAPON_USED (1<<7) // Weapon is being +USE'd, not bumped #endif //Percent diff --git a/sp/src/game/shared/gamerules.cpp b/sp/src/game/shared/gamerules.cpp index f604e408..9fc5ccea 100644 --- a/sp/src/game/shared/gamerules.cpp +++ b/sp/src/game/shared/gamerules.cpp @@ -620,6 +620,14 @@ void CGameRules::OnSkillLevelChanged( int iNewLevel ) pEntity->AcceptInput("SkillLevelChanged", UTIL_GetLocalPlayer(), NULL, varNewLevel, 0); pEntity = gEntList.FindEntityByClassname(pEntity, "logic_skill"); } + + // Fire game event for difficulty level changed + IGameEvent *event = gameeventmanager->CreateEvent("skill_changed"); + if (event) + { + event->SetInt("skill_level", iNewLevel); + gameeventmanager->FireEvent(event); + } } #endif diff --git a/sp/src/game/shared/mapbase/mapbase_game_log.cpp b/sp/src/game/shared/mapbase/mapbase_game_log.cpp new file mode 100644 index 00000000..d87714ab --- /dev/null +++ b/sp/src/game/shared/mapbase/mapbase_game_log.cpp @@ -0,0 +1,243 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A special system designed to record game information for map testing. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include "tier0/icommandline.h" +#include "igamesystem.h" +#include "filesystem.h" +#include "utlbuffer.h" +#ifdef CLIENT_DLL +#else +#include "ammodef.h" +#include "ai_basenpc.h" +#include "ai_squad.h" +#include "fmtstr.h" +#include "GameEventListener.h" +#include "saverestore_utlvector.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#ifdef GAME_DLL +// ------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------ + +class CMapbaseGameLogger : public CLogicalEntity, public CGameEventListener +{ +public: + DECLARE_DATADESC(); + DECLARE_CLASS( CMapbaseGameLogger, CLogicalEntity ); + + CMapbaseGameLogger() + { + pGameLoggerEnt = this; + } + + void Activate() + { + BaseClass::Activate(); + + ListenForGameEvent("skill_changed"); + } + + void FireGameEvent( IGameEvent *event ) + { + if (FStrEq(event->GetName(), "skill_changed")) + { + m_ListSkillChanged.AddToTail(event->GetInt("skill_level")); + m_ListSkillChangedTime.AddToTail(gpGlobals->curtime); + } + } + + float m_flLastLogTime; + int m_iSaveID; + + CUtlVector m_ListSkillChanged; + CUtlVector m_ListSkillChangedTime; + + static CMapbaseGameLogger *GetGameLoggerEnt() + { + if (!pGameLoggerEnt) + pGameLoggerEnt = static_cast(CBaseEntity::Create("mapbase_game_logger", vec3_origin, vec3_angle)); + + return pGameLoggerEnt; + } + +private: + static CHandle pGameLoggerEnt; +}; + +LINK_ENTITY_TO_CLASS( mapbase_game_logger, CMapbaseGameLogger ); + +BEGIN_DATADESC( CMapbaseGameLogger ) + + DEFINE_FIELD( m_flLastLogTime, FIELD_TIME ), + DEFINE_FIELD( m_iSaveID, FIELD_INTEGER ), + + DEFINE_UTLVECTOR( m_ListSkillChanged, FIELD_INTEGER ), + DEFINE_UTLVECTOR( m_ListSkillChangedTime, FIELD_TIME ), + +END_DATADESC() + +CHandle CMapbaseGameLogger::pGameLoggerEnt; + +void MapbaseGameLog_CVarToggle( IConVar *var, const char *pOldString, float flOldValue ); +ConVar mapbase_game_log_on_autosave( "mapbase_game_log_on_autosave", "0", FCVAR_NONE, "Logs information to %mapname%_log_%number%.txt on each autosave", MapbaseGameLog_CVarToggle ); + +void MapbaseGameLog_Init() +{ + if (mapbase_game_log_on_autosave.GetBool()) + { + // Create the game logger ent + CMapbaseGameLogger::GetGameLoggerEnt(); + } +} + +void MapbaseGameLog_Record( const char *szContext ) +{ + CMapbaseGameLogger *pGameLoggerEnt = CMapbaseGameLogger::GetGameLoggerEnt(); + if (!pGameLoggerEnt) + { + Warning("Failed to get game logger ent\n"); + return; + } + + KeyValues *pKV = new KeyValues( "Log" ); + + KeyValues *pKVLogInfo = pKV->FindKey( "logging_info", true ); + if ( pKVLogInfo ) + { + pKVLogInfo->SetString("context", szContext); + pKVLogInfo->SetFloat("last_log", pGameLoggerEnt->m_flLastLogTime > 0.0f ? gpGlobals->curtime - pGameLoggerEnt->m_flLastLogTime : -1.0f); + } + + KeyValues *pKVGameInfo = pKV->FindKey( "game_info", true ); + if ( pKVGameInfo ) + { + pKVGameInfo->SetInt("skill", g_pGameRules->GetSkillLevel()); + + if (pGameLoggerEnt->m_ListSkillChanged.Count() > 0) + { + KeyValues *pKVSkill = pKVGameInfo->FindKey("skill_changes", true); + for (int i = 0; i < pGameLoggerEnt->m_ListSkillChanged.Count(); i++) + { + float flTime = pGameLoggerEnt->m_ListSkillChangedTime[i]; + switch (pGameLoggerEnt->m_ListSkillChanged[i]) + { + case SKILL_EASY: pKVSkill->SetString(CNumStr(flTime), "easy"); break; + case SKILL_MEDIUM: pKVSkill->SetString(CNumStr(flTime), "normal"); break; + case SKILL_HARD: pKVSkill->SetString(CNumStr(flTime), "hard"); break; + } + } + } + } + + KeyValues *pKVPlayer = pKV->FindKey( "player", true ); + if ( pKVPlayer ) + { + CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); + + if ( pPlayer ) + { + pKVPlayer->SetInt("health", pPlayer->GetHealth()); + pKVPlayer->SetInt("armor", pPlayer->ArmorValue()); + + pKVPlayer->SetString("position", CFmtStrN<128>("[%f %f %f]", pPlayer->GetAbsOrigin().x, pPlayer->GetAbsOrigin().y, pPlayer->GetAbsOrigin().z)); + pKVPlayer->SetString("angles", CFmtStrN<128>("[%f %f %f]", pPlayer->EyeAngles().x, pPlayer->EyeAngles().y, pPlayer->EyeAngles().z)); + + KeyValues *pKVWeapons = pKVPlayer->FindKey( "weapons", true ); + if ( pKVWeapons ) + { + // Cycle through all of the player's weapons + for ( int i = 0; i < pPlayer->WeaponCount(); i++ ) + { + CBaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i); + if ( !pWeapon ) + continue; + + if ( pPlayer->GetActiveWeapon() == pWeapon ) + pKVWeapons->SetString(pWeapon->GetClassname(), CFmtStrN<32>("%i; %i (active)", pWeapon->m_iClip1, pWeapon->m_iClip2)); + else + pKVWeapons->SetString(pWeapon->GetClassname(), CFmtStrN<32>("%i; %i", pWeapon->m_iClip1, pWeapon->m_iClip2)); + } + } + + KeyValues *pKVAmmo = pKVPlayer->FindKey( "ammo", true ); + if ( pKVAmmo ) + { + // Cycle through all of the player's ammo + for ( int i = 0; i < GetAmmoDef()->m_nAmmoIndex; i++ ) + { + int iAmmo = pPlayer->GetAmmoCount( i ); + if ( iAmmo > 0 ) + pKVAmmo->SetInt( GetAmmoDef()->m_AmmoType[i].pName, iAmmo ); + } + } + } + } + + CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); + int nAIs = g_AI_Manager.NumAIs(); + for (int i = 0; i < nAIs; i++) + { + CAI_BaseNPC *pNPC = ppAIs[i]; + + if (!pNPC->IsAlive() || pNPC->GetSleepState() != AISS_AWAKE) + continue; + + KeyValues *pKVNPC = pKV->FindKey( CNumStr( pNPC->entindex() ), true ); + if (pKVNPC) + { + pKVNPC->SetString("classname", pNPC->GetClassname()); + pKVNPC->SetString("name", STRING(pNPC->GetEntityName())); + + pKVNPC->SetString("position", CFmtStrN<128>("[%f %f %f]", pNPC->GetAbsOrigin().x, pNPC->GetAbsOrigin().y, pNPC->GetAbsOrigin().z)); + + pKVNPC->SetInt("health", pNPC->GetHealth()); + + if (pNPC->GetActiveWeapon()) + pKVNPC->SetString("weapon", pNPC->GetActiveWeapon()->GetClassname()); + + if (pNPC->GetSquad()) + pKVNPC->SetString("squad", pNPC->GetSquad()->GetName()); + } + } + + CFmtStrN pathfmt("map_logs/%s_log_%i.txt", gpGlobals->mapname, pGameLoggerEnt->m_iSaveID); + + pGameLoggerEnt->m_flLastLogTime = gpGlobals->curtime; + pGameLoggerEnt->m_iSaveID++; + + // Create the folder first, since "map_logs" is not standard and is unlikely to exist + g_pFullFileSystem->CreateDirHierarchy( "map_logs", "MOD" ); + + if (pKV->SaveToFile( g_pFullFileSystem, pathfmt, "MOD" )) + { + Msg("Saved game log file to \"%s\"\n", pathfmt); + } + + pKV->deleteThis(); +} + +static void CC_Mapbase_GameLogRecord( const CCommand& args ) +{ + MapbaseGameLog_Record( "command" ); +} + +static ConCommand mapbase_game_log_record("mapbase_game_log_record", CC_Mapbase_GameLogRecord, "Records game data to %mapname%_log_%number%." ); + +void MapbaseGameLog_CVarToggle( IConVar *var, const char *pOldString, float flOldValue ) +{ + if (mapbase_game_log_on_autosave.GetBool()) + { + // Create the game logger ent + CMapbaseGameLogger::GetGameLoggerEnt(); + } +} +#endif diff --git a/sp/src/game/shared/mapbase/mapbase_rpc.cpp b/sp/src/game/shared/mapbase/mapbase_rpc.cpp index b68a0dee..2c7d34b7 100644 --- a/sp/src/game/shared/mapbase/mapbase_rpc.cpp +++ b/sp/src/game/shared/mapbase/mapbase_rpc.cpp @@ -17,10 +17,13 @@ #ifdef DISCORD_RPC #include "discord_rpc.h" #include +#include "c_world.h" #endif #include "filesystem.h" #include "c_playerresource.h" +#include +#include #endif @@ -448,6 +451,35 @@ void MapbaseRPC_UpdateSteam( int iType, const char *pMapName ) #endif #ifdef DISCORD_RPC +void MapbaseRPC_GetDiscordMapInfo( char *pDetails, size_t iSize, const char *pMapName ) +{ + if (!pMapName) + pMapName = "N/A"; + + // Say we're in the main menu if it's a background map + if (engine->IsLevelMainMenuBackground()) + { + Q_snprintf( pDetails, iSize, "Main Menu (%s)", pMapName ); + } + else + { + C_World *pWorld = GetClientWorldEntity(); + if ( pWorld && pWorld->m_iszChapterTitle[0] != '\0' ) + { + // Show the chapter title first + const char *pChapterTitle = g_pVGuiLocalize->FindAsUTF8( pWorld->m_iszChapterTitle ); + if (!pChapterTitle || pChapterTitle[0] == '\0') + pChapterTitle = pWorld->m_iszChapterTitle; + + Q_snprintf( pDetails, iSize, "%s (%s)", pChapterTitle, pMapName ); + } + else + { + Q_snprintf( pDetails, iSize, "%s", pMapName ); + } + } +} + void MapbaseRPC_GetDiscordParameters( DiscordRichPresence &discordPresence, int iType, const char *pMapName ) { static char details[128]; @@ -469,10 +501,7 @@ void MapbaseRPC_GetDiscordParameters( DiscordRichPresence &discordPresence, int Q_strncpy( details, pMetadata->m_iszRPCDetails, sizeof(details) ); else { - if (engine->IsLevelMainMenuBackground()) - Q_snprintf( details, sizeof(details), "Main Menu (%s)", pMapName ? pMapName : "N/A" ); - else - Q_snprintf( details, sizeof(details), "%s", pMapName ? pMapName : "N/A" ); + MapbaseRPC_GetDiscordMapInfo( details, sizeof(details), pMapName ); } } else @@ -489,15 +518,7 @@ void MapbaseRPC_GetDiscordParameters( DiscordRichPresence &discordPresence, int case RPCSTATE_LEVEL_INIT: default: { - // Say we're in the main menu if it's a background map - if (engine->IsLevelMainMenuBackground()) - { - Q_snprintf( details, sizeof(details), "Main Menu (%s)", pMapName ? pMapName : "N/A" ); - } - else - { - Q_snprintf( details, sizeof(details), "%s", pMapName ? pMapName : "N/A" ); - } + MapbaseRPC_GetDiscordMapInfo( details, sizeof(details), pMapName ); } break; } } diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index bd31f4e3..188f6dd2 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -74,6 +74,8 @@ ConVar mapbase_load_actbusy("mapbase_load_actbusy", "1", FCVAR_ARCHIVE, "Should #endif #ifdef GAME_DLL +extern void MapbaseGameLog_Init(); + extern void ParseCustomActbusyFile(const char *file); extern bool LoadResponseSystemFile(const char *scriptfile); @@ -203,6 +205,13 @@ public: } } +#ifdef GAME_DLL + virtual void LevelInitPostEntity() + { + MapbaseGameLog_Init(); + } +#endif + virtual void LevelShutdownPreEntity() { // How would we make sure they don't last between maps? diff --git a/sp/src/materialsystem/stdshaders/SDK_skin_ps20b.fxc b/sp/src/materialsystem/stdshaders/SDK_skin_ps20b.fxc index 5f3bbbbe..8b54473d 100644 --- a/sp/src/materialsystem/stdshaders/SDK_skin_ps20b.fxc +++ b/sp/src/materialsystem/stdshaders/SDK_skin_ps20b.fxc @@ -170,7 +170,7 @@ float4 main( PS_INPUT i ) : COLOR float4 stretchColor = tex2D( StretchSampler, i.baseTexCoordDetailTexCoord.xy ); // Apply wrinkle blend to only RGB. Alpha comes from the base texture - baseColor.rgb = flTextureAmount * baseColor + flWrinkleAmount * wrinkleColor + flStretchAmount * stretchColor; + baseColor.rgb = flTextureAmount * baseColor.rgb + flWrinkleAmount * wrinkleColor.rgb + flStretchAmount * stretchColor.rgb; #endif #if DETAILTEXTURE @@ -235,7 +235,7 @@ float4 main( PS_INPUT i ) : COLOR envMapColor = (ENV_MAP_SCALE * lerp(1, fFresnelRanges, g_EnvMapFresnel.x) * lerp(fEnvMapMask, 1-fEnvMapMask, g_fInvertPhongMask)) * - texCUBE( EnvmapSampler, vReflect ) * + texCUBE( EnvmapSampler, vReflect ).xyz * g_EnvmapTint_ShadowTweaks.xyz; } } @@ -332,7 +332,7 @@ float4 main( PS_INPUT i ) : COLOR float flSelfIllumFresnel = ( pow( saturate( dot( vVertexNormal.xyz, vEyeDir.xyz ) ), g_SelfIllumScaleBiasExpBrightness.z ) * g_SelfIllumScaleBiasExpBrightness.x ) + g_SelfIllumScaleBiasExpBrightness.y; diffuseComponent = lerp( diffuseComponent, g_SelfIllumTint_and_DetailBlendFactor.rgb * albedo * g_SelfIllumScaleBiasExpBrightness.w, baseColor.a * saturate( flSelfIllumFresnel ) ); #else - float3 vSelfIllumMask = tex2D( SelfIllumMaskSampler, i.baseTexCoordDetailTexCoord.xy ); + float3 vSelfIllumMask = tex2D( SelfIllumMaskSampler, i.baseTexCoordDetailTexCoord.xy ).xyz; vSelfIllumMask = lerp( baseColor.aaa, vSelfIllumMask, g_SelfIllumMaskControl ); diffuseComponent = lerp( diffuseComponent, g_SelfIllumTint_and_DetailBlendFactor.rgb * albedo, vSelfIllumMask ); #endif diff --git a/sp/src/materialsystem/stdshaders/common_ps_fxc.h b/sp/src/materialsystem/stdshaders/common_ps_fxc.h index 330edd36..c7a1a059 100644 --- a/sp/src/materialsystem/stdshaders/common_ps_fxc.h +++ b/sp/src/materialsystem/stdshaders/common_ps_fxc.h @@ -192,7 +192,7 @@ float4 DecompressNormal( sampler NormalSampler, float2 tc, int nDecompressionMod HALF3 NormalizeWithCubemap( sampler normalizeSampler, HALF3 input ) { // return texCUBE( normalizeSampler, input ) * 2.0f - 1.0f; - return texCUBE( normalizeSampler, input ); + return texCUBE( normalizeSampler, input ).xyz; } /* @@ -209,6 +209,13 @@ HALF4 EnvReflect( sampler envmapSampler, } */ +// Vectorized smoothstep for doing three smoothsteps at once. Used by uberlight +float3 smoothstep3( float3 edge0, float3 edge1, float3 OneOverWidth, float3 x ) +{ + x = saturate((x - edge0) * OneOverWidth); // Scale, bias and saturate x to the range of zero to one + return x*x*(3-2*x); // Evaluate polynomial +} + float CalcWaterFogAlpha( const float flWaterZ, const float flEyePosZ, const float flWorldPosZ, const float flProjPosZ, const float flFogOORange ) { #if 0 diff --git a/sp/src/materialsystem/stdshaders/common_vertexlitgeneric_dx9.h b/sp/src/materialsystem/stdshaders/common_vertexlitgeneric_dx9.h index 2eb7bb3c..c1260591 100644 --- a/sp/src/materialsystem/stdshaders/common_vertexlitgeneric_dx9.h +++ b/sp/src/materialsystem/stdshaders/common_vertexlitgeneric_dx9.h @@ -116,7 +116,7 @@ float3 DiffuseTerm(const bool bHalfLambert, const float3 worldNormal, const floa float3 fOut = float3( fResult, fResult, fResult ); if ( bDoLightingWarp ) { - fOut = 2.0f * tex1D( lightWarpSampler, fResult ); + fOut = 2.0f * tex1D( lightWarpSampler, fResult ).xyz; } return fOut; @@ -146,7 +146,7 @@ float3 PixelShaderGetLightVector( const float3 worldPos, PixelShaderLightInfo cL } else { - return normalize( cLightInfo[nLightIndex].pos - worldPos ); + return normalize( cLightInfo[nLightIndex].pos.xyz - worldPos ); } } @@ -181,7 +181,7 @@ void SpecularAndRimTerms( const float3 vWorldNormal, const float3 vLightDir, con // Optionally warp as function of scalar specular and fresnel if ( bDoSpecularWarp ) - specularLighting *= tex2D( specularWarpSampler, float2(specularLighting.x, fFresnel) ); // Sample at { (L.R)^k, fresnel } + specularLighting *= tex2D( specularWarpSampler, float2(specularLighting.x, fFresnel) ).xyz; // Sample at { (L.R)^k, fresnel } specularLighting *= saturate(dot( vWorldNormal, vLightDir )); // Mask with N.L specularLighting *= color; // Modulate with light color @@ -286,19 +286,19 @@ float3 PixelShaderDoLightingLinear( const float3 worldPos, const float3 worldNor if ( nNumLights > 0 ) { linearColor += PixelShaderDoGeneralDiffuseLight( lightAtten.x, worldPos, worldNormal, NormalizeSampler, - cLightInfo[0].pos, cLightInfo[0].color, bHalfLambert, + cLightInfo[0].pos.xyz, cLightInfo[0].color.xyz, bHalfLambert, bDoAmbientOcclusion, fAmbientOcclusion, bDoLightingWarp, lightWarpSampler ); if ( nNumLights > 1 ) { linearColor += PixelShaderDoGeneralDiffuseLight( lightAtten.y, worldPos, worldNormal, NormalizeSampler, - cLightInfo[1].pos, cLightInfo[1].color, bHalfLambert, + cLightInfo[1].pos.xyz, cLightInfo[1].color.xyz, bHalfLambert, bDoAmbientOcclusion, fAmbientOcclusion, bDoLightingWarp, lightWarpSampler ); if ( nNumLights > 2 ) { linearColor += PixelShaderDoGeneralDiffuseLight( lightAtten.z, worldPos, worldNormal, NormalizeSampler, - cLightInfo[2].pos, cLightInfo[2].color, bHalfLambert, + cLightInfo[2].pos.xyz, cLightInfo[2].color.xyz, bHalfLambert, bDoAmbientOcclusion, fAmbientOcclusion, bDoLightingWarp, lightWarpSampler ); if ( nNumLights > 3 ) diff --git a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp index 496f8205..e363f70a 100644 --- a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp +++ b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp @@ -1715,13 +1715,15 @@ void DrawLightmappedGeneric_DX9(CBaseVSShader *pShader, IMaterialVar** params, { bool hasFlashlight = pShader->UsingFlashlight( params ); - ConVarRef r_flashlight_version2 = ConVarRef( "r_flashlight_version2" ); - - if ( !IsX360() && !r_flashlight_version2.GetInt() ) - { - DrawLightmappedGeneric_DX9_Internal( pShader, params, hasFlashlight, pShaderAPI, pShaderShadow, info, pContextDataPtr ); - return; - } - DrawLightmappedGeneric_DX9_Internal( pShader, params, hasFlashlight, pShaderAPI, pShaderShadow, info, pContextDataPtr ); + + //ConVarRef r_flashlight_version2 = ConVarRef( "r_flashlight_version2" ); + // + //if ( !IsX360() && !r_flashlight_version2.GetInt() ) + //{ + // DrawLightmappedGeneric_DX9_Internal( pShader, params, hasFlashlight, pShaderAPI, pShaderShadow, info, pContextDataPtr ); + // return; + //} + // + //DrawLightmappedGeneric_DX9_Internal( pShader, params, hasFlashlight, pShaderAPI, pShaderShadow, info, pContextDataPtr ); } \ No newline at end of file diff --git a/sp/src/materialsystem/stdshaders/skin_dx9_helper.cpp b/sp/src/materialsystem/stdshaders/skin_dx9_helper.cpp index 698668e9..1f27201d 100644 --- a/sp/src/materialsystem/stdshaders/skin_dx9_helper.cpp +++ b/sp/src/materialsystem/stdshaders/skin_dx9_helper.cpp @@ -992,18 +992,18 @@ void DrawSkin_DX9( CBaseVSShader *pShader, IMaterialVar** params, IShaderDynamic CBasePerMaterialContextData **pContextDataPtr ) { - ConVarRef r_flashlight_version2 = ConVarRef( "r_flashlight_version2" ); + //ConVarRef r_flashlight_version2 = ConVarRef( "r_flashlight_version2" ); bool bHasFlashlight = pShader->UsingFlashlight( params ); - if ( bHasFlashlight && ( IsX360() || r_flashlight_version2.GetBool() ) ) - { - DrawSkin_DX9_Internal( pShader, params, pShaderAPI, - pShaderShadow, false, info, vertexCompression, pContextDataPtr++ ); - if ( pShaderShadow ) - { - pShader->SetInitialShadowState( ); - } - } + //if ( bHasFlashlight && ( IsX360() || r_flashlight_version2.GetBool() ) ) + //{ + // DrawSkin_DX9_Internal( pShader, params, pShaderAPI, + // pShaderShadow, false, info, vertexCompression, pContextDataPtr++ ); + // if ( pShaderShadow ) + // { + // pShader->SetInitialShadowState( ); + // } + //} DrawSkin_DX9_Internal( pShader, params, pShaderAPI, pShaderShadow, bHasFlashlight, info, vertexCompression, pContextDataPtr ); } diff --git a/sp/src/materialsystem/stdshaders/unlitgeneric_dx9.cpp b/sp/src/materialsystem/stdshaders/unlitgeneric_dx9.cpp index 1043df5c..f6c7fd73 100644 --- a/sp/src/materialsystem/stdshaders/unlitgeneric_dx9.cpp +++ b/sp/src/materialsystem/stdshaders/unlitgeneric_dx9.cpp @@ -187,10 +187,10 @@ BEGIN_VS_SHADER( SDK_UnlitGeneric, "Help for SDK_UnlitGeneric" ) VertexLitGeneric_DX9_Vars_t vars; SetupVars( vars ); - ConVarRef r_flashlight_version2 = ConVarRef( "r_flashlight_version2" ); + //ConVarRef r_flashlight_version2 = ConVarRef( "r_flashlight_version2" ); - bool bNewFlashlightPath = IsX360() || ( r_flashlight_version2.GetInt() != 0 ); - if ( ( pShaderShadow == NULL ) && ( pShaderAPI != NULL ) && !bNewFlashlightPath && pShaderAPI->InFlashlightMode() ) // Not snapshotting && flashlight pass + //bool bNewFlashlightPath = IsX360() || ( r_flashlight_version2.GetInt() != 0 ); + if ( ( pShaderShadow == NULL ) && ( pShaderAPI != NULL ) && /*!bNewFlashlightPath &&*/ pShaderAPI->InFlashlightMode() ) // Not snapshotting && flashlight pass { Draw( false ); } diff --git a/sp/src/materialsystem/stdshaders/worldtwotextureblend.cpp b/sp/src/materialsystem/stdshaders/worldtwotextureblend.cpp index f90b9662..bc6b2f28 100644 --- a/sp/src/materialsystem/stdshaders/worldtwotextureblend.cpp +++ b/sp/src/materialsystem/stdshaders/worldtwotextureblend.cpp @@ -487,10 +487,10 @@ END_SHADER_PARAMS SHADER_DRAW { - ConVarRef r_flashlight_version2 = ConVarRef( "r_flashlight_version2" ); + //ConVarRef r_flashlight_version2 = ConVarRef( "r_flashlight_version2" ); bool bHasFlashlight = UsingFlashlight( params ); - if ( bHasFlashlight && ( IsX360() || r_flashlight_version2.GetInt() ) ) + if ( bHasFlashlight /*&& ( IsX360() || r_flashlight_version2.GetInt() )*/ ) { DrawPass( params, pShaderAPI, pShaderShadow, false, vertexCompression ); SHADOW_STATE diff --git a/sp/src/public/gamebspfile.h b/sp/src/public/gamebspfile.h index 373368b7..f8029bae 100644 --- a/sp/src/public/gamebspfile.h +++ b/sp/src/public/gamebspfile.h @@ -139,10 +139,6 @@ enum STATIC_PROP_NO_SELF_SHADOWING = 0x80, // disable self shadowing in vrad -#ifdef MAPBASE - STATIC_PROP_OVERRIDE_PROPDATA = 0x100, -#endif - STATIC_PROP_WC_MASK = 0xd8, // all flags settable in hammer (?) }; diff --git a/sp/src/utils/common/utilmatlib.cpp b/sp/src/utils/common/utilmatlib.cpp index f2dc49fa..7e62e000 100644 --- a/sp/src/utils/common/utilmatlib.cpp +++ b/sp/src/utils/common/utilmatlib.cpp @@ -59,6 +59,7 @@ void InitMaterialSystem( const char *materialBaseDirPath, CreateInterfaceFn file LoadMaterialSystemInterface( fileSystemFactory ); MaterialSystem_Config_t config; g_pMaterialSystem->OverrideConfig( config, false ); + g_pMaterialSystem->ModInit(); } void ShutdownMaterialSystem( ) diff --git a/sp/src/utils/vbsp/cubemap.cpp b/sp/src/utils/vbsp/cubemap.cpp index aeff12f1..a95a46d9 100644 --- a/sp/src/utils/vbsp/cubemap.cpp +++ b/sp/src/utils/vbsp/cubemap.cpp @@ -84,9 +84,15 @@ inline bool SideHasCubemapAndWasntManuallyReferenced( int iSide ) return s_aCubemapSideData[iSide].bHasEnvMapInMaterial && !s_aCubemapSideData[iSide].bManuallyPickedByAnEnvCubemap; } - +#ifdef PARALLAX_CORRECTED_CUBEMAPS +char* g_pParallaxObbStrs[MAX_MAP_CUBEMAPSAMPLES]; +void Cubemap_InsertSample( const Vector& origin, int size, char* pParallaxObbStr = "" ) +{ + g_pParallaxObbStrs[g_nCubemapSamples] = pParallaxObbStr; +#else void Cubemap_InsertSample( const Vector& origin, int size ) { +#endif dcubemapsample_t *pSample = &g_CubemapSamples[g_nCubemapSamples]; pSample->origin[0] = ( int )origin[0]; pSample->origin[1] = ( int )origin[1]; @@ -529,7 +535,11 @@ static void GeneratePatchedName( const char *pMaterialName, const PatchInfo_t &i //----------------------------------------------------------------------------- // Patches the $envmap for a material and all its dependents, returns true if any patching happened //----------------------------------------------------------------------------- +#ifdef PARALLAX_CORRECTED_CUBEMAPS +static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, const PatchInfo_t &info, const char *pCubemapTexture, const char *pParallaxObbMatrix = "" ) +#else static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, const PatchInfo_t &info, const char *pCubemapTexture ) +#endif { // Do *NOT* patch the material if there is an $envmap specified and it's not 'env_cubemap' @@ -547,7 +557,11 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons const char *pDependentMaterial = FindDependentMaterial( pMaterialName, &pDependentMaterialVar ); if ( pDependentMaterial ) { +#ifdef PARALLAX_CORRECTED_CUBEMAPS + bDependentMaterialPatched = PatchEnvmapForMaterialAndDependents( pDependentMaterial, info, pCubemapTexture, pParallaxObbMatrix ); +#else bDependentMaterialPatched = PatchEnvmapForMaterialAndDependents( pDependentMaterial, info, pCubemapTexture ); +#endif } // If we have neither to patch, we're done @@ -558,7 +572,11 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons char pPatchedMaterialName[1024]; GeneratePatchedName( pMaterialName, info, true, pPatchedMaterialName, 1024 ); +#ifdef PARALLAX_CORRECTED_CUBEMAPS + MaterialPatchInfo_t pPatchInfo[6]; +#else MaterialPatchInfo_t pPatchInfo[2]; +#endif int nPatchCount = 0; if ( bShouldPatchEnvCubemap ) { @@ -568,6 +586,31 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons ++nPatchCount; } +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Parallax cubemap matrix + CUtlVector matRowList; + if (pParallaxObbMatrix[0] != '\0') + { + V_SplitString( pParallaxObbMatrix, ";", matRowList ); + + pPatchInfo[nPatchCount].m_pKey = "$envMapParallax"; + pPatchInfo[nPatchCount].m_pValue = "1"; + ++nPatchCount; + pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB1"; + pPatchInfo[nPatchCount].m_pValue = matRowList[0]; + ++nPatchCount; + pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB2"; + pPatchInfo[nPatchCount].m_pValue = matRowList[1]; + ++nPatchCount; + pPatchInfo[nPatchCount].m_pKey = "$envMapParallaxOBB3"; + pPatchInfo[nPatchCount].m_pValue = matRowList[2]; + ++nPatchCount; + pPatchInfo[nPatchCount].m_pKey = "$envMapOrigin"; + pPatchInfo[nPatchCount].m_pValue = matRowList[3]; + ++nPatchCount; + } +#endif + char pDependentPatchedMaterialName[1024]; if ( bDependentMaterialPatched ) { @@ -579,7 +622,14 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons ++nPatchCount; } +#ifdef PARALLAX_CORRECTED_CUBEMAPS + CreateMaterialPatch( pMaterialName, pPatchedMaterialName, nPatchCount, pPatchInfo, PATCH_INSERT ); + + // Clean up parallax stuff + matRowList.PurgeAndDeleteElements(); +#else CreateMaterialPatch( pMaterialName, pPatchedMaterialName, nPatchCount, pPatchInfo, PATCH_REPLACE ); +#endif return true; } @@ -598,7 +648,11 @@ static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, cons // default (skybox) cubemap into this file so the cubemap doesn't have the pink checkerboard at // runtime before they run buildcubemaps. //----------------------------------------------------------------------------- +#ifdef PARALLAX_CORRECTED_CUBEMAPS +static int Cubemap_CreateTexInfo( int originalTexInfo, int origin[3], int cubemapIndex ) +#else static int Cubemap_CreateTexInfo( int originalTexInfo, int origin[3] ) +#endif { // Don't make cubemap tex infos for nodes if ( originalTexInfo == TEXINFO_NODE ) @@ -630,6 +684,15 @@ static int Cubemap_CreateTexInfo( int originalTexInfo, int origin[3] ) char pGeneratedTexDataName[1024]; GeneratePatchedName( pMaterialName, info, true, pGeneratedTexDataName, 1024 ); +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Append origin info if this cubemap has a parallax OBB + char originAppendedString[1024] = ""; + if (g_pParallaxObbStrs[cubemapIndex][0] != '\0') + { + Q_snprintf(originAppendedString, 1024, "%s;[%d %d %d]", g_pParallaxObbStrs[cubemapIndex], origin[0], origin[1], origin[2]); + } +#endif + // Make sure the texdata doesn't already exist. int nTexDataID = FindTexData( pGeneratedTexDataName ); bool bHasTexData = (nTexDataID != -1); @@ -641,7 +704,11 @@ static int Cubemap_CreateTexInfo( int originalTexInfo, int origin[3] ) // Hook the texture into the material and all dependent materials // but if no hooking was necessary, exit out +#ifdef PARALLAX_CORRECTED_CUBEMAPS + if ( !PatchEnvmapForMaterialAndDependents( pMaterialName, info, pTextureName, originAppendedString ) ) +#else if ( !PatchEnvmapForMaterialAndDependents( pMaterialName, info, pTextureName ) ) +#endif return originalTexInfo; // Store off the name of the cubemap that we need to create since we successfully patched @@ -731,7 +798,11 @@ void Cubemap_FixupBrushSidesMaterials( void ) } #endif +#ifdef PARALLAX_CORRECTED_CUBEMAPS + pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[cubemapID].origin, cubemapID ); +#else pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[cubemapID].origin ); +#endif if ( pSide->pMapDisp ) { pSide->pMapDisp->face.texinfo = pSide->texinfo; @@ -947,7 +1018,11 @@ void Cubemap_AttachDefaultCubemapToSpecularSides( void ) Assert( pSide->texinfo == pSide->pMapDisp->face.texinfo ); } #endif +#ifdef PARALLAX_CORRECTED_CUBEMAPS + pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[iCubemap].origin, iCubemap ); +#else pSide->texinfo = Cubemap_CreateTexInfo( pSide->texinfo, g_CubemapSamples[iCubemap].origin ); +#endif if ( pSide->pMapDisp ) { pSide->pMapDisp->face.texinfo = pSide->texinfo; diff --git a/sp/src/utils/vbsp/map.cpp b/sp/src/utils/vbsp/map.cpp index 9dfe7dfc..77262686 100644 --- a/sp/src/utils/vbsp/map.cpp +++ b/sp/src/utils/vbsp/map.cpp @@ -15,6 +15,9 @@ #include "materialsub.h" #include "fgdlib/fgdlib.h" #include "manifest.h" +#ifdef PARALLAX_CORRECTED_CUBEMAPS +#include "matrixinvert.h" +#endif #ifdef VSVMFIO #include "VmfImport.h" @@ -1618,9 +1621,16 @@ ChunkFileResult_t CMapFile::LoadEntityCallback(CChunkFile *pFile, int nParam) if( ( g_nDXLevel == 0 ) || ( g_nDXLevel >= 70 ) ) { const char *pSideListStr = ValueForKey( mapent, "sides" ); +#ifdef PARALLAX_CORRECTED_CUBEMAPS + char *pParallaxObbStr = ValueForKey( mapent, "parallaxobb" ); +#endif int size; size = IntForKey( mapent, "cubemapsize" ); +#ifdef PARALLAX_CORRECTED_CUBEMAPS + Cubemap_InsertSample( mapent->origin, size, pParallaxObbStr ); +#else Cubemap_InsertSample( mapent->origin, size ); +#endif Cubemap_SaveBrushSides( pSideListStr ); } // clear out this entity @@ -1628,6 +1638,88 @@ ChunkFileResult_t CMapFile::LoadEntityCallback(CChunkFile *pFile, int nParam) return(ChunkFile_Ok); } +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // + // parallax_obb brushes are removed after the transformation matrix is found and saved into + // the entity's data (ent will be removed after data transferred to patched materials) + // + if (!strcmp("parallax_obb", pClassName)) + { + matrix3x4_t obbMatrix, invObbMatrix; + SetIdentityMatrix(obbMatrix); + SetIdentityMatrix(invObbMatrix); + + // Get corner and its 3 edges (scaled, local x, y, and z axes) + mapbrush_t *brush = &mapbrushes[mapent->firstbrush]; + Vector corner, x, y, z; + + // Find first valid winding (with these whiles, if not enough valid windings then identity matrix is passed through to vmts) + int i = 0; + while (i < brush->numsides) + { + winding_t* wind = brush->original_sides[i].winding; + if (!wind) + { + i++; + continue; + } + + corner = wind->p[0]; + y = wind->p[1] - corner; + z = wind->p[3] - corner; + x = CrossProduct(y, z).Normalized(); + + i++; + break; + } + + // Skip second valid winding (opposite face from first, unusable for finding Z's length) + while (i < brush->numsides) + { + winding_t* wind = brush->original_sides[i].winding; + if (!wind) + { + i++; + continue; + } + i++; + break; + } + + // Find third valid winding + while (i < brush->numsides) + { + winding_t* wind = brush->original_sides[i].winding; + if (!wind) + { + i++; + continue; + } + + // Find length of x + // Start with diagonal, then scale x by the projection of diag onto x + Vector diag = wind->p[0] - wind->p[2]; + x *= abs(DotProduct(diag, x)); + + // Build transformation matrix (what is needed to turn a [0,0,0] - [1,1,1] cube into this brush) + MatrixSetColumn(x, 0, obbMatrix); + MatrixSetColumn(y, 1, obbMatrix); + MatrixSetColumn(z, 2, obbMatrix); + MatrixSetColumn(corner, 3, obbMatrix); + + //find inverse (we need the world to local matrix, "transformationmatrix" is kind of a misnomer) + MatrixInversion(obbMatrix, invObbMatrix); + break; + } + + char szMatrix[1024]; + Q_snprintf(szMatrix, 1024, "[%f %f %f %f];[%f %f %f %f];[%f %f %f %f]", invObbMatrix[0][0], invObbMatrix[0][1], invObbMatrix[0][2], invObbMatrix[0][3], invObbMatrix[1][0], invObbMatrix[1][1], invObbMatrix[1][2], invObbMatrix[1][3], invObbMatrix[2][0], invObbMatrix[2][1], invObbMatrix[2][2], invObbMatrix[2][3]); + SetKeyValue(mapent, "transformationmatrix", szMatrix); + + return (ChunkFile_Ok); + } +#endif + if ( !strcmp( "test_sidelist", pClassName ) ) { ConvertSideList(mapent, "sides"); @@ -2615,6 +2707,30 @@ bool LoadMapFile( const char *pszFileName ) } } +#ifdef PARALLAX_CORRECTED_CUBEMAPS + // Fill out parallax obb matrix array + for (int i = 0; i < g_nCubemapSamples; i++) + { + if (g_pParallaxObbStrs[i][0] != '\0') + { + entity_t* obbEnt = EntityByName(g_pParallaxObbStrs[i]); + g_pParallaxObbStrs[i] = ValueForKey(obbEnt, "transformationmatrix"); + } + } + + // Remove parallax_obb entities (in a nice slow linear search) + for (int i = 0; i < g_MainMap->num_entities; i++) + { + entity_t* mapent = &g_MainMap->entities[i]; + const char *pClassName = ValueForKey( mapent, "classname" ); + if ( !strcmp( "parallax_obb", pClassName ) ) + { + mapent->numbrushes = 0; + mapent->epairs = NULL; + } + } +#endif + if ((eResult == ChunkFile_Ok) || (eResult == ChunkFile_EOF)) { // Update the overlay/side list(s). diff --git a/sp/src/utils/vbsp/staticprop.cpp b/sp/src/utils/vbsp/staticprop.cpp index 75567224..6c643413 100644 --- a/sp/src/utils/vbsp/staticprop.cpp +++ b/sp/src/utils/vbsp/staticprop.cpp @@ -102,6 +102,7 @@ isstaticprop_ret IsStaticProp( studiohdr_t* pHdr ) if (!(pHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP)) return RET_FAIL_NOT_MARKED_STATIC_PROP; +#ifndef MAPBASE // If it's got a propdata section in the model's keyvalues, it's not allowed to be a prop_static KeyValues *modelKeyValues = new KeyValues(pHdr->pszName()); if ( StudioKeyValues( pHdr, modelKeyValues ) ) @@ -117,6 +118,7 @@ isstaticprop_ret IsStaticProp( studiohdr_t* pHdr ) } } modelKeyValues->deleteThis(); +#endif return RET_VALID; } @@ -166,11 +168,7 @@ bool LoadStudioModel( char const* pModelName, char const* pEntityType, CUtlBuffe } isstaticprop_ret isStaticProp = IsStaticProp(pHdr); -#ifdef MAPBASE - if ( isStaticProp != RET_VALID && strcmp(pEntityType, "prop_static_override") != 0 ) -#else if ( isStaticProp != RET_VALID ) -#endif { if ( isStaticProp == RET_FAIL_NOT_MARKED_STATIC_PROP ) { @@ -244,11 +242,7 @@ CPhysCollide* ComputeConvexHull( studiohdr_t* pStudioHdr ) //----------------------------------------------------------------------------- // Add, find collision model in cache //----------------------------------------------------------------------------- -#ifdef MAPBASE -static CPhysCollide* GetCollisionModel( char const* pModelName, bool bOverridePropdata = false ) -#else static CPhysCollide* GetCollisionModel( char const* pModelName ) -#endif { // Convert to a common string char* pTemp = (char*)_alloca(strlen(pModelName) + 1); @@ -271,11 +265,7 @@ static CPhysCollide* GetCollisionModel( char const* pModelName ) // Load the studio model file CUtlBuffer buf; -#ifdef MAPBASE - if (!LoadStudioModel(pModelName, bOverridePropdata ? "prop_static_override" : "prop_static", buf)) -#else if (!LoadStudioModel(pModelName, "prop_static", buf)) -#endif { Warning("Error loading studio model \"%s\"!\n", pModelName ); @@ -486,11 +476,7 @@ static bool ComputeLightingOrigin( StaticPropBuild_t const& build, Vector& light static void AddStaticPropToLump( StaticPropBuild_t const& build ) { // Get the collision model -#ifdef MAPBASE - CPhysCollide* pConvexHull = GetCollisionModel( build.m_pModelName, (build.m_Flags & STATIC_PROP_OVERRIDE_PROPDATA) > 0 ); -#else CPhysCollide* pConvexHull = GetCollisionModel( build.m_pModelName ); -#endif if (!pConvexHull) return; @@ -602,11 +588,7 @@ void EmitStaticProps() for ( i = 0; i < num_entities; ++i) { char* pEntity = ValueForKey(&entities[i], "classname"); -#ifdef MAPBASE - if (!strncmp(pEntity, "prop_static", 11) || !strcmp(pEntity, "static_prop")) -#else if (!strcmp(pEntity, "static_prop") || !strcmp(pEntity, "prop_static")) -#endif { StaticPropBuild_t build; @@ -639,14 +621,6 @@ void EmitStaticProps() build.m_Flags |= STATIC_PROP_SCREEN_SPACE_FADE; } -#ifdef MAPBASE - //if (IntForKey(&entities[i], "override_propdata") == 1) - if (!strcmp(pEntity + 11, "_override")) - { - build.m_Flags |= STATIC_PROP_OVERRIDE_PROPDATA; - } -#endif - const char *pKey = ValueForKey( &entities[i], "fadescale" ); if ( pKey && pKey[0] ) { diff --git a/sp/src/utils/vbsp/textures.cpp b/sp/src/utils/vbsp/textures.cpp index 4f49c5d4..3a7cffde 100644 --- a/sp/src/utils/vbsp/textures.cpp +++ b/sp/src/utils/vbsp/textures.cpp @@ -153,6 +153,13 @@ int FindMiptex (const char *name) { textureref[i].flags |= SURF_NOLIGHT; } +#ifdef MAPBASE + // handle Slammin-inspired %compileNoShadows% + else if ( ( propVal = GetMaterialVar( matID, "%compileNoShadows" ) ) && StringIsTrue( propVal ) ) + { + textureref[i].flags |= SURF_NOSHADOWS; + } +#endif else { // HANDLE ALL OF THE STUFF THAT IS RENDERED WITH THE MATERIAL THAT IS ON IT. diff --git a/sp/src/utils/vbsp/vbsp.cpp b/sp/src/utils/vbsp/vbsp.cpp index 55452170..c1fae6e6 100644 --- a/sp/src/utils/vbsp/vbsp.cpp +++ b/sp/src/utils/vbsp/vbsp.cpp @@ -43,7 +43,11 @@ qboolean noshare; qboolean nosubdiv; qboolean notjunc; qboolean noopt; +#ifdef MAPBASE +qboolean noleaktest; +#else qboolean leaktest; +#endif qboolean verboseentities; qboolean dumpcollide = false; qboolean g_bLowPriority = false; @@ -85,182 +89,6 @@ int entity_num; node_t *block_nodes[BLOCKS_SPACE+2][BLOCKS_SPACE+2]; -#ifdef MAPBASE -//----------------------------------------------------------------------------- -// Manifest stuff -//----------------------------------------------------------------------------- -CUtlVector g_szManifestFiles; -bool g_bManifestVerbose = true; // Change to false when testing is over - -#define ManifestMsg(msg, ...) g_bManifestVerbose ? Msg(msg, __VA_ARGS__) : NULL -#define ManifestWarning(msg, ...) g_bManifestVerbose ? Warning(msg, __VA_ARGS__) : NULL - -void SetManifestFile(char const *file) -{ - if (g_pFileSystem->FileExists( file )) - { - Msg("Manifest file: %s\n", file); - g_szManifestFiles.AddToTail(file); - } -} - -void ZipDirectory(const char *dir, const char *relative, IZip *package, int *filecount) -{ - ManifestMsg(" MANIFEST: Mounting directory \"%s\"\n", dir); - - FileFindHandle_t handle = NULL; - const char *file = g_pFullFileSystem->FindFirst(dir, &handle); - - // Prevents us from packaging the folder itself - //if (file) - // file = g_pFullFileSystem->FindNext(handle); - - while (file) - { - // Don't use hidden files/folders - if (file[0] != '.') - { - char subdir[MAX_PATH]; - Q_strncpy(subdir, dir, strlen(dir) - 1); // Remove wildcard - Q_ComposeFileName(subdir, file, subdir, sizeof(subdir)); - - char subrelative[MAX_PATH]; - Q_strncpy(subrelative, relative, sizeof(subrelative)); - Q_ComposeFileName(subrelative, file, subrelative, sizeof(subrelative)); - - if (g_pFullFileSystem->FindIsDirectory(handle)) - { - // Append wildcard - Q_ComposeFileName(subdir, "*", subdir, sizeof(subdir)); - - // Mount subdirectory - ZipDirectory(subdir, subrelative, package, filecount); - } - else - { - // Mount file - ManifestMsg(" MANIFEST: File \"%s\" packed into BSP at \"%s\"\n", subdir, subrelative); - *filecount++; - AddFileToPak(package, subrelative, subdir); - } - } - - file = g_pFullFileSystem->FindNext(handle); - } - g_pFullFileSystem->FindClose(handle); -} - -void ParseManifestFile() -{ - if (g_szManifestFiles.Count() == 0) - return; - - Msg("Starting pack manifest with %i files\n", g_szManifestFiles.Count()); - - int totalfilecount = 0; - - for (int i = 0; i < g_szManifestFiles.Count(); i++) - { - FileHandle_t manifestfile = g_pFileSystem->Open( g_szManifestFiles[i], "rb" ); - if (!manifestfile) - { - Warning("Manifest file \"%s\" cannot be read!\n", g_szManifestFiles[i]); - continue; - } - - //FileHandle_t curfile; - bool curfile; - char buf[1024]; - char *scan; - int filecount = 0; - bool fullpath = false; - while ( CmdLib_FGets( buf, sizeof( buf ), manifestfile ) ) - { - scan = buf; - - // Check if it's an actual path or just relative - fullpath = (scan[0] == '#'); - if (fullpath) - scan += 1; - else - { - char file[128]; - Q_strncpy(file, scan, sizeof(file)); - char path[_MAX_PATH]; - Q_ExtractFilePath(source, path, sizeof(path)); - sprintf(scan, "%s%s", path, file); - } - - bool inquotes = (scan[0] == '"'); - int namelength; - if (inquotes) - { - scan += 1; - namelength = strcspn( scan, "\"" ); - } - else - { - namelength = strcspn( scan, " \t" ); - } - - char filename[FILENAME_MAX]; - Q_strncpy(filename, scan, namelength + 1); - - scan += (namelength + inquotes); - scan += strspn(scan, " \t"); - - // Remove any quotes in the internal path. - // The fact they're actually optional in the second path is irrelevant. - if (scan[0] == '"') - { - scan[0] = '\0'; - if (scan[strlen(scan) - 1] == '"') - scan[strlen(scan) - 1] = '\0'; - } - - curfile = g_pFileSystem->FileExists(filename); - if (curfile) - { - // Assume internal file is a directory if no extension - if (Q_GetFileExtension(scan) == NULL) - Q_ComposeFileName(scan, filename, scan, sizeof(filename)); - - ManifestMsg(" MANIFEST: File \"%s\" packed into BSP at \"%s\"\n", filename, scan); - filecount++; - AddFileToPak(GetPakFile(), scan, filename); - } - else if (g_pFullFileSystem->IsDirectory(filename)) - { - // Append wildcard - if (!Q_strstr(filename, "*")) - Q_ComposeFileName(filename, "*", filename, sizeof(filename)); - - // Internal path must be a directory - if (scan[0] == NULL || Q_GetFileExtension(scan) == NULL) - ZipDirectory(filename, scan, GetPakFile(), &filecount); - else - Warning("\n MANIFEST WARNING: Directory \"%s\" tried to pack to a file!\nIf you are not trying to package a directory to the BSP, add an extension to \"%s\".\nIf you are trying to package a directory, remove the extension from \"%s\".\n\n", filename, filename, scan); - } - else - { - Warning(" MANIFEST WARNING: File \"%s\" does not exist!\n", filename); - } - } - - if (filecount > 0) - ManifestMsg("%i file(s) packed from manifest %s\n", filecount, g_szManifestFiles[i]); - else - ManifestWarning("*** No files zipped from manifest %s!\n ***", g_szManifestFiles[i]); - - totalfilecount += filecount; - - g_pFileSystem->Close( manifestfile ); - } - - Msg("%i total file(s) packed from manifests\n", totalfilecount); -} -#endif - //----------------------------------------------------------------------------- // Assign occluder areas (must happen *after* the world model is processed) //----------------------------------------------------------------------------- @@ -473,7 +301,11 @@ void ProcessWorldModel (void) Warning( ("**** leaked ****\n") ); leaked = true; LeakFile (tree); +#ifdef MAPBASE + if (!noleaktest) +#else if (leaktest) +#endif { Warning( ("--- MAP LEAKED ---\n") ); exit (0); @@ -1178,11 +1010,19 @@ int RunVBSP( int argc, char **argv ) Msg ("microvolume = %f\n", microvolume); i++; } +#ifdef MAPBASE + else if (!Q_stricmp(argv[i], "-noleaktest")) + { + Msg ("noleaktest = true\n"); + noleaktest = true; + } +#else else if (!Q_stricmp(argv[i], "-leaktest")) { Msg ("leaktest = true\n"); leaktest = true; } +#endif else if (!Q_stricmp(argv[i], "-verboseentities")) { Msg ("verboseentities = true\n"); @@ -1316,19 +1156,10 @@ int RunVBSP( int argc, char **argv ) EnableFullMinidumps( true ); } #ifdef MAPBASE - else if ( !Q_stricmp( argv[i], "-deletecubemaps" ) ) + else if ( !Q_stricmp( argv[i], "-nodefaultcubemap" ) ) { g_bNoDefaultCubemaps = true; } - else if ( !Q_stricmp( argv[i], "-manifest" ) ) - { - SetManifestFile(argv[i+1]); - i++; - } - else if ( !Q_stricmp( argv[i], "-manifest_verbose" ) ) - { - g_bManifestVerbose = true; - } #endif else if (argv[i][0] == '-') { @@ -1445,13 +1276,6 @@ int RunVBSP( int argc, char **argv ) ThreadSetDefault (); numthreads = 1; // multiple threads aren't helping... -#ifdef MAPBASE - // Any additional files to pack? - char ManifestFile[512]; - _snprintf( ManifestFile, sizeof(ManifestFile), "%s_zipmanifest.txt", source ); - SetManifestFile(ManifestFile); -#endif - // Setup the logfile. char logFile[512]; _snprintf( logFile, sizeof(logFile), "%s.log", source ); @@ -1568,11 +1392,6 @@ int RunVBSP( int argc, char **argv ) AddBufferToPak( GetPakFile(), "stale.txt", "stale", strlen( "stale" ) + 1, false ); } -#ifdef MAPBASE - // Is this a good place for this? - ParseManifestFile(); -#endif - LoadMapFile (name); WorldVertexTransitionFixup(); if( ( g_nDXLevel == 0 ) || ( g_nDXLevel >= 70 ) ) diff --git a/sp/src/utils/vbsp/vbsp.h b/sp/src/utils/vbsp/vbsp.h index 689bbaa8..12fd9db5 100644 --- a/sp/src/utils/vbsp/vbsp.h +++ b/sp/src/utils/vbsp/vbsp.h @@ -34,6 +34,12 @@ class CUtlBuffer; // this will output glview files for the given brushmodel. Brushmodel 1 is the world, 2 is the first brush entity, etc. #define DEBUG_BRUSHMODEL 0 +#ifdef MAPBASE +// Activates compiler code for parallax corrected cubemaps +// https://developer.valvesoftware.com/wiki/Parallax_Corrected_Cubemaps +#define PARALLAX_CORRECTED_CUBEMAPS 1 +#endif + struct portal_t; struct node_t; @@ -607,7 +613,12 @@ void SaveVertexNormals( void ); //============================================================================= // cubemap.cpp +#ifdef PARALLAX_CORRECTED_CUBEMAPS +extern char* g_pParallaxObbStrs[MAX_MAP_CUBEMAPSAMPLES]; +void Cubemap_InsertSample( const Vector& origin, int size, char* pParallaxObbStr ); +#else void Cubemap_InsertSample( const Vector& origin, int size ); +#endif void Cubemap_CreateDefaultCubemaps( void ); void Cubemap_SaveBrushSides( const char *pSideListStr ); void Cubemap_FixupBrushSidesMaterials( void ); diff --git a/sp/src/utils/vbsp/vbsp.vpc b/sp/src/utils/vbsp/vbsp.vpc index 9737a803..d5a0c10e 100644 --- a/sp/src/utils/vbsp/vbsp.vpc +++ b/sp/src/utils/vbsp/vbsp.vpc @@ -6,7 +6,7 @@ $Macro SRCDIR "..\.." $Macro OUTBINDIR "$SRCDIR\..\game\bin" -$Macro OUTBINNAME "mapbase_vbsp" +$Macro OUTBINNAME "vbsp" $Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" diff --git a/sp/src/utils/vrad/vrad_dll.vpc b/sp/src/utils/vrad/vrad_dll.vpc index 2ff81363..e4a34226 100644 --- a/sp/src/utils/vrad/vrad_dll.vpc +++ b/sp/src/utils/vrad/vrad_dll.vpc @@ -6,7 +6,7 @@ $Macro SRCDIR "..\.." $Macro OUTBINDIR "$SRCDIR\..\game\bin" -$Macro OUTBINNAME "mapbase_vrad_dll" +$Macro OUTBINNAME "vrad_dll" $Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" diff --git a/sp/src/utils/vrad_launcher/vrad_launcher.vpc b/sp/src/utils/vrad_launcher/vrad_launcher.vpc index ed6fd3cc..293e5514 100644 --- a/sp/src/utils/vrad_launcher/vrad_launcher.vpc +++ b/sp/src/utils/vrad_launcher/vrad_launcher.vpc @@ -6,7 +6,7 @@ $Macro SRCDIR "..\.." $Macro OUTBINDIR "$SRCDIR\..\game\bin" -$Macro OUTBINNAME "mapbase_vrad" +$Macro OUTBINNAME "vrad" $Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" diff --git a/sp/src/utils/vvis/vvis_dll.vpc b/sp/src/utils/vvis/vvis_dll.vpc index 7b782c56..dbd2b955 100644 --- a/sp/src/utils/vvis/vvis_dll.vpc +++ b/sp/src/utils/vvis/vvis_dll.vpc @@ -6,7 +6,7 @@ $Macro SRCDIR "..\.." $Macro OUTBINDIR "$SRCDIR\..\game\bin" -$Macro OUTBINNAME "mapbase_vvis_dll" +$Macro OUTBINNAME "vvis_dll" $Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" diff --git a/sp/src/utils/vvis_launcher/vvis_launcher.vpc b/sp/src/utils/vvis_launcher/vvis_launcher.vpc index 0eb73d22..f3c5e958 100644 --- a/sp/src/utils/vvis_launcher/vvis_launcher.vpc +++ b/sp/src/utils/vvis_launcher/vvis_launcher.vpc @@ -6,7 +6,7 @@ $Macro SRCDIR "..\.." $Macro OUTBINDIR "$SRCDIR\..\game\bin" -$Macro OUTBINNAME "mapbase_vvis" +$Macro OUTBINNAME "vvis" $Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"