From 9273b58cfd9150fa9961ba82b7abd1106b598c6f Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Thu, 21 Dec 2023 05:21:49 +0300 Subject: [PATCH 01/42] server: match sentences limit with Xash3D FWGS engine --- dlls/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/util.h b/dlls/util.h index ad3d8002..bfe0fd32 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -498,7 +498,7 @@ extern DLL_GLOBAL int g_Language; // sentence groups #define CBSENTENCENAME_MAX 16 -#define CVOXFILESENTENCEMAX 2048 // max number of sentences in game. NOTE: this must match +#define CVOXFILESENTENCEMAX 4096 // max number of sentences in game. NOTE: this must match // CVOXFILESENTENCEMAX in engine\sound.h!!! extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; From ecdcabfe99dd76aef98daba47aee6c6a789ac0ac Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Thu, 21 Dec 2023 05:22:12 +0300 Subject: [PATCH 02/42] server: warn mod developer about reaching the GoldSrc sentences limits --- dlls/sound.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 3dbd097a..992e0ebd 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1341,6 +1341,15 @@ void SENTENCEG_Init() g_engfuncs.pfnFreeFile( pMemFile ); + if( gcallsentences >= 2048 ) + { + ALERT( at_warning, "NOTE: this mod might not work properly under GoldSource (post-anniversary update) engine: more than 2048 sentences\n" ); + } + else if( gcallsentences >= 1536 ) + { + ALERT( at_warning, "NOTE: this mod might not work properly under GoldSource (pre-anniversary update) engine: more than 1536 sentences\n" ); + } + fSentencesInit = TRUE; // init lru lists From d77a7e4753b6e6d1becf3c9471fbbe649dc48bf2 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:14:47 +0500 Subject: [PATCH 03/42] Improve handgrenade throw physics. --- dlls/handgrenade.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index f9f360ec..fb729b2a 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -140,9 +140,9 @@ void CHandGrenade::WeaponIdle( void ) else angThrow.x = -10.0f + angThrow.x * ( ( 90.0f + 10.0f ) / 90.0f ); - float flVel = ( 90.0f - angThrow.x ) * 4.0f; - if( flVel > 500.0f ) - flVel = 500.0f; + float flVel = ( 90.0f - angThrow.x ) * 6.5f; + if( flVel > 1000.0f ) + flVel = 1000.0f; UTIL_MakeVectors( angThrow ); From 538e3a84d748ce8619493eece871403f10ea3fbe Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 20 Jan 2024 10:45:01 +0500 Subject: [PATCH 04/42] Improve spawn spot randomization in multiplayer. --- dlls/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/player.cpp b/dlls/player.cpp index 76f0ed7c..f08ac269 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -2718,7 +2718,7 @@ edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ) { pSpot = g_pLastSpawn; // Randomize the start spot - for( int i = RANDOM_LONG( 1, 5 ); i > 0; i-- ) + for( int i = RANDOM_LONG( 1, 9 ); i > 0; i-- ) pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); if( FNullEnt( pSpot ) ) // skip over the null point pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); From edd258e30244ebdca5012de9d13a3eeec2217b65 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Fri, 26 Jan 2024 21:22:21 +0500 Subject: [PATCH 05/42] When a player dies in multiplayer, make their body non-solid immediately. --- dlls/player.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/player.cpp b/dlls/player.cpp index f08ac269..35234835 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -903,6 +903,9 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) // UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12 // UTIL_ScreenFade( edict(), Vector( 128, 0, 0 ), 6, 15, 255, FFADE_OUT | FFADE_MODULATE ); + if( g_pGameRules->IsMultiplayer()) + pev->solid = SOLID_NOT; + if( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) { pev->solid = SOLID_NOT; From deee0dcbfbaa1aef409ce40fb863f3b42ca0dba5 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Fri, 26 Jan 2024 21:42:30 +0500 Subject: [PATCH 06/42] Avoid trigger_hurt's heal for dead players. --- dlls/triggers.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index a4bcbbc7..69b3ee3d 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -984,7 +984,12 @@ void CBaseTrigger::HurtTouch( CBaseEntity *pOther ) } #endif if( fldmg < 0 ) - pOther->TakeHealth( -fldmg, m_bitsDamageInflict ); + { + if( !( g_pGameRules->IsMultiplayer() + && pOther->IsPlayer() + && pOther->pev->deadflag )) + pOther->TakeHealth( -fldmg, m_bitsDamageInflict ); + } else pOther->TakeDamage( pev, pev, fldmg, m_bitsDamageInflict ); From 325c61f4879706c250ac004b636c7cdb86f6bb33 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 27 Jan 2024 00:33:17 +0500 Subject: [PATCH 07/42] Fix player's death animation in multiplayer. --- dlls/player.cpp | 15 +++++++++++---- dlls/player.h | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/dlls/player.cpp b/dlls/player.cpp index 35234835..fe5f92e6 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -867,7 +867,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) SetAnimation( PLAYER_DIE ); - m_iRespawnFrames = 0; + m_flRespawnTimer = 0; pev->modelindex = g_ulModelIndexPlayer; // don't use eyes @@ -1270,8 +1270,8 @@ void CBasePlayer::PlayerDeathThink( void ) { StudioFrameAdvance(); - m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands - if( m_iRespawnFrames < 120 ) // Animations should be no longer than this + m_flRespawnTimer = gpGlobals->frametime + m_flRespawnTimer; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands + if( m_flRespawnTimer < 4.0f ) // Animations should be no longer than this return; } @@ -1281,7 +1281,14 @@ void CBasePlayer::PlayerDeathThink( void ) pev->movetype = MOVETYPE_NONE; if( pev->deadflag == DEAD_DYING ) + { + if( g_pGameRules->IsMultiplayer() && pev->movetype == MOVETYPE_NONE ) + { + CopyToBodyQue( pev ); + pev->modelindex = 0; + } pev->deadflag = DEAD_DEAD; + } StopAnimation(); @@ -1322,7 +1329,7 @@ void CBasePlayer::PlayerDeathThink( void ) return; pev->button = 0; - m_iRespawnFrames = 0; + m_flRespawnTimer = 0; //ALERT( at_console, "Respawn\n" ); diff --git a/dlls/player.h b/dlls/player.h index b2484b15..f86d25b4 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -188,7 +188,7 @@ public: Vector m_vecAutoAim; BOOL m_fOnTarget; int m_iDeaths; - float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn + float m_flRespawnTimer; // used in PlayerDeathThink() to make sure players can always respawn int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE From b2161d18d05525dbe28f08f26e4f2c91658fca31 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 27 Jan 2024 01:46:15 +0500 Subject: [PATCH 08/42] Set flashlight time on restore. --- dlls/player.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/player.cpp b/dlls/player.cpp index fe5f92e6..83ff51cd 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -3012,6 +3012,9 @@ int CBasePlayer::Restore( CRestore &restore ) // Barring that, we clear it out here instead of using the incorrect restored time value. m_flNextAttack = UTIL_WeaponTimeBase(); #endif + if( m_flFlashLightTime == 0.0f ) + m_flFlashLightTime = 1.0f; + return status; } From 1f4a4140168f2042dbc55de2e4b50b025e185ade Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 27 Jan 2024 02:40:20 +0500 Subject: [PATCH 09/42] Fix gauss sound on level transition. --- dlls/gauss.cpp | 4 ++++ dlls/player.cpp | 1 + 2 files changed, 5 insertions(+) diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index fb512757..a997c804 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -170,6 +170,8 @@ void CGauss::PrimaryAttack() void CGauss::SecondaryAttack() { + if( m_pPlayer->m_flStartCharge > gpGlobals->time ) + m_pPlayer->m_flStartCharge = gpGlobals->time; // don't fire underwater if( m_pPlayer->pev->waterlevel == 3 ) { @@ -315,6 +317,8 @@ void CGauss::StartFire( void ) { float flDamage; + if( m_pPlayer->m_flStartCharge > gpGlobals->time ) + m_pPlayer->m_flStartCharge = gpGlobals->time; UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); Vector vecAiming = gpGlobals->v_forward; Vector vecSrc = m_pPlayer->GetGunPosition(); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8; diff --git a/dlls/player.cpp b/dlls/player.cpp index 83ff51cd..0d984b12 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -2797,6 +2797,7 @@ ReturnSpot: void CBasePlayer::Spawn( void ) { + m_flStartCharge = gpGlobals->time; pev->classname = MAKE_STRING( "player" ); pev->health = 100; pev->armorvalue = 0; From d2a43db7e3e17a3e32e7faaf5f610cdf42f31da8 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:13:49 +0000 Subject: [PATCH 10/42] HL 25th anniversary pushable fix. (#427) --- dlls/func_break.cpp | 76 +++++++++++++++++++++++++++++++-------------- dlls/game.cpp | 4 +++ dlls/game.h | 1 + 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/dlls/func_break.cpp b/dlls/func_break.cpp index 0c5e0114..f1829d6c 100644 --- a/dlls/func_break.cpp +++ b/dlls/func_break.cpp @@ -928,22 +928,25 @@ void CPushable::Move( CBaseEntity *pOther, int push ) if( pOther->IsPlayer() ) { - // g-cont. fix pushable acceleration bug (now implemented as cvar) - if (pushablemode.value == 1) - { - // Allow player push when moving right, left and back too - if ( push && !(pevToucher->button & (IN_FORWARD|IN_MOVERIGHT|IN_MOVELEFT|IN_BACK)) ) - return; - // Require player walking back when applying '+use' on pushable - if ( !push && !(pevToucher->button & (IN_BACK)) ) - return; - } - else + if( pushablemode.value == -1 ) { // Don't push unless the player is pushing forward and NOT use (pull) - if( push && !( pevToucher->button & ( IN_FORWARD | IN_USE ) ) ) + if( push && !( pevToucher->button & ( IN_FORWARD | IN_USE ))) return; } + // g-cont. fix pushable acceleration bug (now implemented as cvar) + else if( pushablemode.value != 0 ) + { + // Allow player push when moving right, left and back too + if( push && !( pevToucher->button & ( IN_FORWARD | IN_MOVERIGHT | IN_MOVELEFT | IN_BACK ))) + return; + // Require player walking back when applying '+use' on pushable + if( !push && !( pevToucher->button & ( IN_BACK ))) + return; + } + // Don't push when +use pressed + else if( push && ( pevToucher->button & ( IN_USE ))) + return; playerTouch = 1; } @@ -964,30 +967,55 @@ void CPushable::Move( CBaseEntity *pOther, int push ) else factor = 0.25f; - // Spirit fix for pushable acceleration - if (pushablemode.value == 2) + if( pushablemode.value != 0 ) { - if (!push) - factor *= 0.5f; + pev->velocity.x += pevToucher->velocity.x * factor; + pev->velocity.y += pevToucher->velocity.y * factor; } + else + { + if( push ) + { + factor = 0.25f; + pev->velocity.x += pevToucher->velocity.x * factor; + pev->velocity.y += pevToucher->velocity.y * factor; + } + else + { + // fix for pushable acceleration + if( sv_pushable_fixed_tick_fudge.value >= 0 ) + factor *= ( sv_pushable_fixed_tick_fudge.value * gpGlobals->frametime ); - pev->velocity.x += pevToucher->velocity.x * factor; - pev->velocity.y += pevToucher->velocity.y * factor; + if( fabs( pev->velocity.x ) < fabs( pevToucher->velocity.x - pevToucher->velocity.x * factor )) + pev->velocity.x += pevToucher->velocity.x * factor; + if( fabs( pev->velocity.y ) < fabs( pevToucher->velocity.y - pevToucher->velocity.y * factor )) + pev->velocity.y += pevToucher->velocity.y * factor; + } + } float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y ); - if( push && ( length > MaxSpeed() ) ) + if( ( push && pushablemode.value != 0 ) + || pushablemode.value == 0 ) { - pev->velocity.x = (pev->velocity.x * MaxSpeed() / length ); - pev->velocity.y = (pev->velocity.y * MaxSpeed() / length ); + if( length > MaxSpeed()) + { + pev->velocity.x = ( pev->velocity.x * MaxSpeed() / length ); + pev->velocity.y = ( pev->velocity.y * MaxSpeed() / length ); + } } + if( playerTouch ) { - pevToucher->velocity.x = pev->velocity.x; - pevToucher->velocity.y = pev->velocity.y; + if( push || pushablemode.value != 0 ) + { + pevToucher->velocity.x = pev->velocity.x; + pevToucher->velocity.y = pev->velocity.y; + } + if( ( gpGlobals->time - m_soundTime ) > 0.7f ) { m_soundTime = gpGlobals->time; - if( length > 0 && FBitSet( pev->flags,FL_ONGROUND ) ) + if( length > 0 && FBitSet( pev->flags, FL_ONGROUND )) { m_lastSound = RANDOM_LONG( 0, 2 ); EMIT_SOUND( ENT( pev ), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5f, ATTN_NORM ); diff --git a/dlls/game.cpp b/dlls/game.cpp index e64f0417..f2c74d6b 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -457,6 +457,8 @@ cvar_t sk_player_leg3 = { "sk_player_leg3","1" }; // END Cvars for Skill Level settings +cvar_t sv_pushable_fixed_tick_fudge = { "sv_pushable_fixed_tick_fudge", "15" }; + // Register your console variables here // This gets called one time when the game is initialied void GameDLLInit( void ) @@ -883,6 +885,8 @@ void GameDLLInit( void ) CVAR_REGISTER( &sk_player_leg3 ); // END REGISTER CVARS FOR SKILL LEVEL STUFF + CVAR_REGISTER( &sv_pushable_fixed_tick_fudge ); + SERVER_COMMAND( "exec skill.cfg\n" ); } diff --git a/dlls/game.h b/dlls/game.h index 5f7bee1c..069324bb 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -43,6 +43,7 @@ extern cvar_t teamoverride; extern cvar_t defaultteam; extern cvar_t allowmonsters; extern cvar_t bhopcap; +extern cvar_t sv_pushable_fixed_tick_fudge; // Engine Cvars extern cvar_t *g_psv_gravity; From ccbb5b763edfde7d03fa834a529d481133c4edc4 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:14:47 +0000 Subject: [PATCH 11/42] Port func_vehicle implementation from cs16-client/regamedll_cs. (#428) --- cl_dll/ev_hldm.cpp | 60 +++ cl_dll/hl/hl_events.cpp | 2 + contrib/iZarif/premake5.lua | 1 + dlls/Android.mk | 1 + dlls/CMakeLists.txt | 1 + dlls/cbase.h | 1 + dlls/client.cpp | 2 + dlls/compile.bat | 1 + dlls/multiplay_gamerules.cpp | 11 + dlls/player.cpp | 83 ++- dlls/trains.h | 85 +++ dlls/vehicle.cpp | 996 +++++++++++++++++++++++++++++++++++ 12 files changed, 1229 insertions(+), 15 deletions(-) create mode 100644 dlls/vehicle.cpp diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 9f5ede08..381ee25b 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -70,6 +70,7 @@ void EV_TripmineFire( struct event_args_s *args ); void EV_SnarkFire( struct event_args_s *args ); void EV_TrainPitchAdjust( struct event_args_s *args ); +void EV_VehiclePitchAdjust( event_args_t *args ); } #define VECTOR_CONE_1DEGREES Vector( 0.00873f, 0.00873f, 0.00873f ) @@ -1752,6 +1753,65 @@ void EV_TrainPitchAdjust( event_args_t *args ) } } +void EV_VehiclePitchAdjust( event_args_t *args ) +{ + int idx; + vec3_t origin; + + unsigned short us_params; + int noise; + float m_flVolume; + int pitch; + int stop; + + const char *pszSound; + + idx = args->entindex; + + VectorCopy( args->origin, origin ); + + us_params = (unsigned short)args->iparam1; + stop = args->bparam1; + + m_flVolume = (float)( us_params & 0x003f ) / 40.0f; + noise = (int)( ( ( us_params ) >> 12 ) & 0x0007 ); + pitch = (int)( 10.0f * (float)( ( us_params >> 6 ) & 0x003f ) ); + + switch( noise ) + { + case 1: + pszSound = "plats/vehicle1.wav"; + break; + case 2: + pszSound = "plats/vehicle2.wav"; + break; + case 3: + pszSound = "plats/vehicle3.wav"; + break; + case 4: + pszSound = "plats/vehicle4.wav"; + break; + case 5: + pszSound = "plats/vehicle6.wav"; + break; + case 6: + pszSound = "plats/vehicle7.wav"; + break; + default: + // no sound + return; + } + + if( stop ) + { + gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, pszSound ); + } + else + { + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, pszSound, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); + } +} + int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) { return 0; diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp index c79279dd..e68fabf9 100644 --- a/cl_dll/hl/hl_events.cpp +++ b/cl_dll/hl/hl_events.cpp @@ -40,6 +40,7 @@ void EV_TripmineFire( struct event_args_s *args ); void EV_SnarkFire( struct event_args_s *args ); void EV_TrainPitchAdjust( struct event_args_s *args ); +void EV_VehiclePitchAdjust( event_args_t *args ); } /* @@ -76,4 +77,5 @@ void Game_HookEvents( void ) gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); + gEngfuncs.pfnHookEvent( "events/vehicle.sc", EV_VehiclePitchAdjust ); } diff --git a/contrib/iZarif/premake5.lua b/contrib/iZarif/premake5.lua index 91817da5..d959d9ad 100644 --- a/contrib/iZarif/premake5.lua +++ b/contrib/iZarif/premake5.lua @@ -219,6 +219,7 @@ files{"dlls/agrunt.cpp", "dlls/triggers.cpp", "dlls/turret.cpp", "dlls/util.cpp", +"dlls/vehicle.cpp", "dlls/weapons.cpp", "dlls/world.cpp", "dlls/xen.cpp", diff --git a/dlls/Android.mk b/dlls/Android.mk index 1dc79616..80934949 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -122,6 +122,7 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \ tripmine.cpp \ turret.cpp \ util.cpp \ + vehicle.cpp \ weapons.cpp \ world.cpp \ xen.cpp \ diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index 7da665d9..9c518d39 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -144,6 +144,7 @@ set (SVDLL_SOURCES tripmine.cpp turret.cpp util.cpp + vehicle.cpp weapons.cpp world.cpp xen.cpp diff --git a/dlls/cbase.h b/dlls/cbase.h index d64c0f5c..88a161e0 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -103,6 +103,7 @@ typedef void(CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCalle #define CLASS_PLAYER_ALLY 11 #define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players #define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace +#define CLASS_VEHICLE 14 #define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures. class CBaseEntity; diff --git a/dlls/client.cpp b/dlls/client.cpp index c27b22d1..3ce82cfb 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -893,6 +893,8 @@ void ClientPrecache( void ) PRECACHE_SOUND( "plats/train_use1.wav" ); // use a train + PRECACHE_SOUND( "plats/vehicle_ignition.wav" ); + PRECACHE_SOUND( "buttons/spark5.wav" ); // hit computer texture PRECACHE_SOUND( "buttons/spark6.wav" ); PRECACHE_SOUND( "debris/glass1.wav" ); diff --git a/dlls/compile.bat b/dlls/compile.bat index 4eba92c7..20b7cc66 100644 --- a/dlls/compile.bat +++ b/dlls/compile.bat @@ -103,6 +103,7 @@ set SOURCES=agrunt.cpp ^ tripmine.cpp ^ turret.cpp ^ util.cpp ^ + vehicle.cpp ^ weapons.cpp ^ world.cpp ^ xen.cpp ^ diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index b9f35d41..49e24ab3 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -30,6 +30,7 @@ #include "voice_gamemgr.h" #endif #include "hltv.h" +#include "trains.h" extern DLL_GLOBAL CGameRules *g_pGameRules; extern DLL_GLOBAL BOOL g_fGameOver; @@ -647,6 +648,16 @@ void CHalfLifeMultiplay::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); if( ktmp && (ktmp->Classify() == CLASS_PLAYER ) ) peKiller = (CBasePlayer*)ktmp; + else if( ktmp && ktmp->Classify() == CLASS_VEHICLE ) + { + CBasePlayer *pDriver = (CBasePlayer *)( (CFuncVehicle *)ktmp )->m_pDriver; + + if( pDriver != NULL ) + { + pKiller = pDriver->pev; + peKiller = (CBasePlayer *)pDriver; + } + } if( pVictim->pev == pKiller ) { diff --git a/dlls/player.cpp b/dlls/player.cpp index 0d984b12..7f5df559 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -1494,18 +1494,31 @@ void CBasePlayer::PlayerUse( void ) { m_afPhysicsFlags &= ~PFLAG_ONTRAIN; m_iTrain = TRAIN_NEW|TRAIN_OFF; + + CBaseEntity *pTrain = Instance( pev->groundentity ); + if( pTrain && pTrain->Classify() == CLASS_VEHICLE ) + { + ( (CFuncVehicle *)pTrain )->m_pDriver = NULL; + } return; } else { // Start controlling the train! CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - if( pTrain && !( pev->button & IN_JUMP ) && FBitSet( pev->flags, FL_ONGROUND ) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE ) && pTrain->OnControls( pev ) ) + if( pTrain && !( pev->button & IN_JUMP ) && FBitSet( pev->flags, FL_ONGROUND ) && ( pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE ) && pTrain->OnControls( pev ) ) { m_afPhysicsFlags |= PFLAG_ONTRAIN; m_iTrain = TrainSpeed( (int)pTrain->pev->speed, pTrain->pev->impulse ); m_iTrain |= TRAIN_NEW; - EMIT_SOUND( ENT( pev ), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM ); + + if( pTrain->Classify() == CLASS_VEHICLE ) + { + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "plats/vehicle_ignition.wav", 0.8, ATTN_NORM ); + ( (CFuncVehicle *)pTrain )->m_pDriver = this; + } + else + EMIT_SOUND( ENT( pev ), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM ); return; } } @@ -1619,9 +1632,17 @@ void CBasePlayer::Jump() // If you're standing on a conveyor, add it's velocity to yours (for momentum) entvars_t *pevGround = VARS( pev->groundentity ); - if( pevGround && ( pevGround->flags & FL_CONVEYOR ) ) + if( pevGround ) { - pev->velocity = pev->velocity + pev->basevelocity; + if( pevGround->flags & FL_CONVEYOR ) + { + pev->velocity = pev->velocity + pev->basevelocity; + } + + if( FClassnameIs( pevGround, "func_vehicle" )) + { + pev->velocity = pevGround->velocity + pev->velocity; + } } } @@ -1886,30 +1907,62 @@ void CBasePlayer::PreThink( void ) //ALERT( at_error, "In train mode with no train!\n" ); m_afPhysicsFlags &= ~PFLAG_ONTRAIN; m_iTrain = TRAIN_NEW|TRAIN_OFF; + if( pTrain ) + ( (CFuncVehicle *)pTrain )->m_pDriver = NULL; return; } } - else if( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || ( pev->button & ( IN_MOVELEFT | IN_MOVERIGHT ) ) ) + else if( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) + || ( ( pev->button & ( IN_MOVELEFT | IN_MOVERIGHT )) && pTrain->Classify() != CLASS_VEHICLE )) { // Turn off the train if you jump, strafe, or the train controls go dead m_afPhysicsFlags &= ~PFLAG_ONTRAIN; m_iTrain = TRAIN_NEW | TRAIN_OFF; + ( (CFuncVehicle *)pTrain )->m_pDriver = NULL; return; } pev->velocity = g_vecZero; vel = 0; - if( m_afButtonPressed & IN_FORWARD ) - { - vel = 1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - else if( m_afButtonPressed & IN_BACK ) - { - vel = -1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } + if( pTrain->Classify() == CLASS_VEHICLE ) + { + if( pev->button & IN_FORWARD ) + { + vel = 1; + pTrain->Use( this, this, USE_SET, vel ); + } + + if( pev->button & IN_BACK ) + { + vel = -1; + pTrain->Use( this, this, USE_SET, vel ); + } + + if( pev->button & IN_MOVELEFT ) + { + vel = 20; + pTrain->Use( this, this, USE_SET, vel ); + } + if( pev->button & IN_MOVERIGHT ) + { + vel = 30; + pTrain->Use( this, this, USE_SET, vel ); + } + } + else + { + if( m_afButtonPressed & IN_FORWARD ) + { + vel = 1; + pTrain->Use( this, this, USE_SET, vel ); + } + else if( m_afButtonPressed & IN_BACK ) + { + vel = -1; + pTrain->Use( this, this, USE_SET, vel ); + } + } iGearId = TrainSpeed( pTrain->pev->speed, pTrain->pev->impulse ); if( iGearId != ( m_iTrain & 0x0F ) ) // Vit_amiN: speed changed diff --git a/dlls/trains.h b/dlls/trains.h index 046dbc24..652ecbc4 100644 --- a/dlls/trains.h +++ b/dlls/trains.h @@ -122,4 +122,89 @@ public: private: unsigned short m_usAdjustPitch; }; + +class CFuncVehicle: public CBaseEntity +{ +public: + virtual void Spawn(); + virtual void Precache(); + virtual void Restart(); + virtual void KeyValue( KeyValueData *pkvd ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + virtual int ObjectCaps() { return ( CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION ) | FCAP_DIRECTIONAL_USE; } + virtual int Classify(); + virtual void OverrideReset(); + virtual BOOL OnControls( entvars_t *pev ); + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual void Blocked( CBaseEntity *pOther ); + +public: + void EXPORT Next(); + void EXPORT Find(); + void EXPORT NearestPath(); + void EXPORT DeadEnd(); + + void NextThink( float thinkTime, BOOL alwaysThink ); + void CollisionDetection(); + void TerrainFollowing(); + void CheckTurning(); + + void SetTrack( CPathTrack *track ) { m_ppath = track->Nearest( pev->origin ); } + void SetControls( entvars_t *pevControls ); + + void StopSound(); + void UpdateSound(); + +public: + static CFuncVehicle *Instance( edict_t *pent ); + static TYPEDESCRIPTION m_SaveData[12]; + + CPathTrack *m_ppath; + float m_length; + float m_width; + float m_height; + float m_speed; + float m_dir; + float m_startSpeed; + Vector m_controlMins; + Vector m_controlMaxs; + int m_soundPlaying; + int m_sounds; + int m_acceleration; + float m_flVolume; + float m_flBank; + float m_oldSpeed; + int m_iTurnAngle; + float m_flSteeringWheelDecay; + float m_flAcceleratorDecay; + float m_flTurnStartTime; + float m_flLaunchTime; + float m_flLastNormalZ; + float m_flCanTurnNow; + float m_flUpdateSound; + Vector m_vFrontLeft; + Vector m_vFront; + Vector m_vFrontRight; + Vector m_vBackLeft; + Vector m_vBack; + Vector m_vBackRight; + Vector m_vSurfaceNormal; + Vector m_vVehicleDirection; + CBaseEntity *m_pDriver; + +private: + unsigned short m_usAdjustPitch; +}; + +class CFuncVehicleControls: public CBaseEntity +{ +public: + virtual void Spawn(); + virtual int ObjectCaps() { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + +public: + void EXPORT Find(); +}; + #endif diff --git a/dlls/vehicle.cpp b/dlls/vehicle.cpp new file mode 100644 index 00000000..66e5cc2f --- /dev/null +++ b/dlls/vehicle.cpp @@ -0,0 +1,996 @@ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "trains.h" +#include "saverestore.h" + +#define VEHICLE_SPEED0_ACCELERATION 0.005000000000000000 +#define VEHICLE_SPEED1_ACCELERATION 0.002142857142857143 +#define VEHICLE_SPEED2_ACCELERATION 0.003333333333333334 +#define VEHICLE_SPEED3_ACCELERATION 0.004166666666666667 +#define VEHICLE_SPEED4_ACCELERATION 0.004000000000000000 +#define VEHICLE_SPEED5_ACCELERATION 0.003800000000000000 +#define VEHICLE_SPEED6_ACCELERATION 0.004500000000000000 +#define VEHICLE_SPEED7_ACCELERATION 0.004250000000000000 +#define VEHICLE_SPEED8_ACCELERATION 0.002666666666666667 +#define VEHICLE_SPEED9_ACCELERATION 0.002285714285714286 +#define VEHICLE_SPEED10_ACCELERATION 0.001875000000000000 +#define VEHICLE_SPEED11_ACCELERATION 0.001444444444444444 +#define VEHICLE_SPEED12_ACCELERATION 0.001200000000000000 +#define VEHICLE_SPEED13_ACCELERATION 0.000916666666666666 + +#define VEHICLE_STARTPITCH 60 +#define VEHICLE_MAXPITCH 200 +#define VEHICLE_MAXSPEED 1500 + +TYPEDESCRIPTION CFuncVehicle::m_SaveData[] = +{ + DEFINE_FIELD( CFuncVehicle, m_ppath, FIELD_CLASSPTR ), + DEFINE_FIELD( CFuncVehicle, m_length, FIELD_FLOAT ), + DEFINE_FIELD( CFuncVehicle, m_height, FIELD_FLOAT ), + DEFINE_FIELD( CFuncVehicle, m_speed, FIELD_FLOAT ), + DEFINE_FIELD( CFuncVehicle, m_dir, FIELD_FLOAT ), + DEFINE_FIELD( CFuncVehicle, m_startSpeed, FIELD_FLOAT ), + DEFINE_FIELD( CFuncVehicle, m_controlMins, FIELD_VECTOR ), + DEFINE_FIELD( CFuncVehicle, m_controlMaxs, FIELD_VECTOR ), + DEFINE_FIELD( CFuncVehicle, m_sounds, FIELD_INTEGER ), + DEFINE_FIELD( CFuncVehicle, m_flVolume, FIELD_FLOAT ), + DEFINE_FIELD( CFuncVehicle, m_flBank, FIELD_FLOAT ), + DEFINE_FIELD( CFuncVehicle, m_oldSpeed, FIELD_FLOAT ), +}; + +static float Fix2( float angle ) +{ + while( angle < 0 ) + angle += 360; + + while( angle > 360 ) + angle -= 360; + + return angle; +} + +static void FixupAngles2( Vector &v ) +{ + v.x = Fix2( v.x ); + v.y = Fix2( v.y ); + v.z = Fix2( v.z ); +} + +IMPLEMENT_SAVERESTORE( CFuncVehicle, CBaseEntity ) + +LINK_ENTITY_TO_CLASS( func_vehicle, CFuncVehicle ) + +void CFuncVehicle::KeyValue( KeyValueData *pkvd ) +{ + if( FStrEq( pkvd->szKeyName, "length" )) + { + m_length = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "width" )) + { + m_width = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "height" )) + { + m_height = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "startspeed" )) + { + m_startSpeed = atof(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "sounds" )) + { + m_sounds = atoi( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "volume" )) + { + m_flVolume = (float)atoi( pkvd->szValue ); + m_flVolume *= 0.1f; + + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "bank" )) + { + m_flBank = atof( pkvd->szValue ); + pkvd->fHandled = TRUE; + } + else if( FStrEq( pkvd->szKeyName, "acceleration" )) + { + m_acceleration = atoi( pkvd->szValue ); + + if( m_acceleration < 1 ) + m_acceleration = 1; + + else if( m_acceleration > 10 ) + m_acceleration = 10; + + pkvd->fHandled = TRUE; + } + else + CBaseEntity::KeyValue( pkvd ); +} + +void CFuncVehicle::NextThink( float thinkTime, BOOL alwaysThink ) +{ + if( alwaysThink ) + pev->flags |= FL_ALWAYSTHINK; + else + pev->flags &= ~FL_ALWAYSTHINK; + + pev->nextthink = thinkTime; +} + +void CFuncVehicle::Blocked( CBaseEntity *pOther ) +{ + entvars_t *pevOther = pOther->pev; + + if( ( pevOther->flags & FL_ONGROUND ) && VARS( pevOther->groundentity ) == pev ) + { + pevOther->velocity = pev->velocity; + return; + } + + pevOther->velocity = ( pevOther->origin - pev->origin ).Normalize() * pev->dmg; + pevOther->velocity.z += 300; + pev->velocity = pev->velocity * 0.85f; + + ALERT( at_aiconsole, "TRAIN(%s): Blocked by %s (dmg:%.2f)\n", STRING( pev->targetname ), STRING( pOther->pev->classname ), pev->dmg ); + UTIL_MakeVectors( pev->angles ); + + Vector forward, right, vOrigin; + Vector vFrontLeft = ( gpGlobals->v_forward * -1 ) * ( m_length * 0.5f ); + Vector vFrontRight = ( gpGlobals->v_right * -1 ) * ( m_width * 0.5f ); + + Vector vBackLeft = pev->origin + vFrontLeft - vFrontRight; + Vector vBackRight = pev->origin - vFrontLeft + vFrontRight; + + float minx = Q_min( vBackLeft.x, vBackRight.x ); + float miny = Q_min( vBackLeft.y, vBackRight.y ); + float maxx = Q_max( vBackLeft.x, vBackRight.x ); + float maxy = Q_max( vBackLeft.y, vBackRight.y ); + + float minz = pev->origin.z; + float maxz = pev->origin.z + ( 2 * abs( (int)( pev->mins.z - pev->maxs.z ))); + + if ( pOther->pev->origin.x < minx + || pOther->pev->origin.x > maxx + || pOther->pev->origin.y < miny + || pOther->pev->origin.y > maxy + || pOther->pev->origin.z < pev->origin.z + || pOther->pev->origin.z > maxz ) + { + pOther->TakeDamage( pev, pev, 150, DMG_CRUSH ); + } +} + +void CFuncVehicle::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) +{ + float delta = value; + + if( useType != USE_SET ) + { + if( ShouldToggle( useType, pev->speed != 0 )) + { + if( pev->speed == 0 ) + { + pev->speed = m_dir * m_speed; + Next(); + } + else + { + pev->speed = 0; + pev->velocity = g_vecZero; + pev->avelocity = g_vecZero; + + StopSound(); + SetThink( NULL ); + } + } + + return; + } + + if( delta < 10 ) + { + if( delta < 0 ) + { + if( pev->speed > 145 ) + { + StopSound(); + } + } + + float flSpeedRatio = delta; + + if( delta > 0 ) + { + flSpeedRatio = (float)( pev->speed / m_speed ); + + if( pev->speed < 0 ) flSpeedRatio = m_acceleration * 0.0005 + flSpeedRatio + VEHICLE_SPEED0_ACCELERATION; + else if( pev->speed < 10 ) flSpeedRatio = m_acceleration * 0.0006 + flSpeedRatio + VEHICLE_SPEED1_ACCELERATION; + else if( pev->speed < 20 ) flSpeedRatio = m_acceleration * 0.0007 + flSpeedRatio + VEHICLE_SPEED2_ACCELERATION; + else if( pev->speed < 30 ) flSpeedRatio = m_acceleration * 0.0007 + flSpeedRatio + VEHICLE_SPEED3_ACCELERATION; + else if( pev->speed < 45 ) flSpeedRatio = m_acceleration * 0.0007 + flSpeedRatio + VEHICLE_SPEED4_ACCELERATION; + else if( pev->speed < 60 ) flSpeedRatio = m_acceleration * 0.0008 + flSpeedRatio + VEHICLE_SPEED5_ACCELERATION; + else if( pev->speed < 80 ) flSpeedRatio = m_acceleration * 0.0008 + flSpeedRatio + VEHICLE_SPEED6_ACCELERATION; + else if( pev->speed < 100 ) flSpeedRatio = m_acceleration * 0.0009 + flSpeedRatio + VEHICLE_SPEED7_ACCELERATION; + else if( pev->speed < 150 ) flSpeedRatio = m_acceleration * 0.0008 + flSpeedRatio + VEHICLE_SPEED8_ACCELERATION; + else if( pev->speed < 225 ) flSpeedRatio = m_acceleration * 0.0007 + flSpeedRatio + VEHICLE_SPEED9_ACCELERATION; + else if( pev->speed < 300 ) flSpeedRatio = m_acceleration * 0.0006 + flSpeedRatio + VEHICLE_SPEED10_ACCELERATION; + else if( pev->speed < 400 ) flSpeedRatio = m_acceleration * 0.0005 + flSpeedRatio + VEHICLE_SPEED11_ACCELERATION; + else if( pev->speed < 550 ) flSpeedRatio = m_acceleration * 0.0005 + flSpeedRatio + VEHICLE_SPEED12_ACCELERATION; + else if( pev->speed < 800 ) flSpeedRatio = m_acceleration * 0.0005 + flSpeedRatio + VEHICLE_SPEED13_ACCELERATION; + } + else if( delta < 0 ) + { + flSpeedRatio = pev->speed / m_speed; + + // TODO: fix float for test demo + if( flSpeedRatio > 0 ) flSpeedRatio = (float)flSpeedRatio - 0.0125f; + else if( flSpeedRatio <= 0 && flSpeedRatio > -0.05f ) flSpeedRatio = (float)flSpeedRatio - 0.0075f; + else if( flSpeedRatio <= 0.05f && flSpeedRatio > -0.1f ) flSpeedRatio = (float)flSpeedRatio - 0.01f; + else if( flSpeedRatio <= 0.15f && flSpeedRatio > -0.15f ) flSpeedRatio = (float)flSpeedRatio - 0.0125f; + else if( flSpeedRatio <= 0.15f && flSpeedRatio > -0.22f ) flSpeedRatio = (float)flSpeedRatio - 0.01375f; + else if( flSpeedRatio <= 0.22f && flSpeedRatio > -0.3f ) flSpeedRatio = (float)flSpeedRatio - 0.0175f; + else if( flSpeedRatio <= 0.3f ) flSpeedRatio = (float)flSpeedRatio - 0.0125f; + } + + if( flSpeedRatio > 1 ) + { + flSpeedRatio = 1; + } + else if( flSpeedRatio < -0.35f ) + { + flSpeedRatio = -0.35f; + } + + pev->speed = flSpeedRatio * m_speed; + Next(); + m_flAcceleratorDecay = gpGlobals->time + 0.25f; + } + else if( m_flCanTurnNow < gpGlobals->time ) + { + if( delta == 20 ) + { + m_iTurnAngle++; + m_flSteeringWheelDecay = gpGlobals->time + 0.075f; + + if (m_iTurnAngle > 8) + { + m_iTurnAngle = 8; + } + } + else if( delta == 30 ) + { + m_iTurnAngle--; + m_flSteeringWheelDecay = gpGlobals->time + 0.075f; + + if( m_iTurnAngle < -8 ) + { + m_iTurnAngle = -8; + } + } + + m_flCanTurnNow = gpGlobals->time + 0.05f; + } +} + +void CFuncVehicle::StopSound() +{ + if( m_soundPlaying && pev->noise ) + { + unsigned short us_sound = ( (unsigned short)m_sounds & 0x0007 ) << 12; + unsigned short us_encode = us_sound; + + PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0, g_vecZero, g_vecZero, 0, 0, us_encode, 0, 1, 0 ); + } + + m_soundPlaying = 0; +} + +void CFuncVehicle::UpdateSound() +{ + if( !pev->noise ) + return; + + float flpitch = VEHICLE_STARTPITCH + ( abs( (int)pev->speed ) * ( VEHICLE_MAXPITCH - VEHICLE_STARTPITCH ) / VEHICLE_MAXSPEED ); + + if( flpitch > 200 ) + flpitch = 200; + + if( !m_soundPlaying ) + { + if( m_sounds < 5 ) + { + EMIT_SOUND_DYN( ENT(pev), CHAN_ITEM, "plats/vehicle_brake1.wav", m_flVolume, ATTN_NORM, 0, PITCH_NORM ); + } + + EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM, 0, (int)flpitch ); + m_soundPlaying = 1; + } + else + { + unsigned short us_sound = ( (unsigned short)( m_sounds ) & 0x0007 ) << 12; + unsigned short us_pitch = ( (unsigned short)( flpitch / 10.0 ) & 0x003F ) << 6; + unsigned short us_volume = ( (unsigned short)( m_flVolume * 40 ) & 0x003F ); + unsigned short us_encode = us_sound | us_pitch | us_volume; + + PLAYBACK_EVENT_FULL( FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, g_vecZero, g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0 ); + } +} + +void CFuncVehicle::CheckTurning() +{ + float maxspeed; + TraceResult tr; + bool bTurnIntoWall = false; + + if( m_iTurnAngle < 0 ) + { + if( pev->speed > 0 ) + { + UTIL_TraceLine( m_vFrontRight, m_vFrontRight - ( gpGlobals->v_right * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + } + else if( pev->speed < 0 ) + { + UTIL_TraceLine( m_vBackLeft, m_vBackLeft + ( gpGlobals->v_right * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + } + + if( tr.flFraction != 1.0f ) + { + m_iTurnAngle = 1; + } + } + else if( m_iTurnAngle > 0 ) + { + if( pev->speed > 0 ) + { + UTIL_TraceLine( m_vFrontLeft, m_vFrontLeft + ( gpGlobals->v_right * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + } + else if( pev->speed < 0 ) + { + UTIL_TraceLine( m_vBackRight, m_vBackRight - ( gpGlobals->v_right * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + } + + if( tr.flFraction != 1.0f ) + { + m_iTurnAngle = -1; + } + } + + if( pev->speed > 0 ) + { + int iCountTurn = abs( m_iTurnAngle ); + + if( iCountTurn > 4 ) + { + if ( m_flTurnStartTime != -1 ) + { + float flTurnTime = gpGlobals->time - m_flTurnStartTime; + + if( flTurnTime >= 0 ) maxspeed = m_speed * 0.98f; + else if( flTurnTime > 0.3f ) maxspeed = m_speed * 0.95f; + else if( flTurnTime > 0.6f ) maxspeed = m_speed * 0.9f; + else if( flTurnTime > 0.8f ) maxspeed = m_speed * 0.8f; + else if( flTurnTime > 1 ) maxspeed = m_speed * 0.7f; + else if( flTurnTime > 1.2f ) maxspeed = m_speed * 0.5f; + else maxspeed = flTurnTime; + } + else + { + m_flTurnStartTime = gpGlobals->time; + maxspeed = m_speed; + } + } + else + { + m_flTurnStartTime = -1; + + if( iCountTurn > 2 ) + maxspeed = m_speed * 0.9f; + else + maxspeed = m_speed; + } + + if( maxspeed < pev->speed ) + { + pev->speed -= m_speed * 0.1f; + } + } +} + +void CFuncVehicle::CollisionDetection() +{ + TraceResult tr; + bool bHitSomething = false; + + if( pev->speed < 0 ) + { + UTIL_TraceLine( m_vBackLeft, m_vBackLeft + ( gpGlobals->v_forward * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + + if( tr.flFraction == 1.0f ) + { + UTIL_TraceLine( m_vBackRight, m_vBackRight + ( gpGlobals->v_forward * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + + if( tr.flFraction == 1.0f ) + { + UTIL_TraceLine( m_vBack, m_vBack + ( gpGlobals->v_forward * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + + if( tr.flFraction == 1.0f ) + { + return; + } + } + + if( DotProduct( gpGlobals->v_forward, tr.vecPlaneNormal * -1.0f ) < 0.7f && tr.vecPlaneNormal.z < 0.1f ) + { + m_vSurfaceNormal = tr.vecPlaneNormal; + m_vSurfaceNormal.z = 0; + + pev->speed *= 0.99f; + } + else if( tr.vecPlaneNormal.z < 0.65f || tr.fStartSolid ) + { + pev->speed *= -1.0f; + } + else + { + m_vSurfaceNormal = tr.vecPlaneNormal; + } + } + else + { + if( DotProduct( gpGlobals->v_forward, tr.vecPlaneNormal * -1.0f ) < 0.7f && tr.vecPlaneNormal.z < 0.1f ) + { + m_vSurfaceNormal = tr.vecPlaneNormal; + m_vSurfaceNormal.z = 0; + + pev->speed *= 0.99f; + } + else if( tr.vecPlaneNormal[2] < 0.65f || tr.fStartSolid ) + { + pev->speed *= -1.0f; + } + else + { + m_vSurfaceNormal = tr.vecPlaneNormal; + } + + CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); + + if( pHit && pHit->Classify() == CLASS_VEHICLE ) + { + bHitSomething = true; + ALERT( at_console, "I hit another vehicle\n" ); + } + } + } + else if( pev->speed > 0 ) + { + UTIL_TraceLine( m_vFrontLeft, m_vFrontLeft - ( gpGlobals->v_forward * 16.0f ), dont_ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + + if( tr.flFraction == 1.0f ) + { + UTIL_TraceLine( m_vFrontRight, m_vFrontRight - ( gpGlobals->v_forward * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + + if( tr.flFraction == 1.0f ) + { + UTIL_TraceLine( m_vFront, m_vFront - ( gpGlobals->v_forward * 16.0f ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + + if( tr.flFraction == 1.0f ) + { + return; + } + } + } + + if( DotProduct( gpGlobals->v_forward, tr.vecPlaneNormal * -1.0f ) > -0.7f && tr.vecPlaneNormal.z < 0.1f ) + { + m_vSurfaceNormal = tr.vecPlaneNormal; + m_vSurfaceNormal.z = 0; + + pev->speed *= 0.99f; + } + else if( tr.vecPlaneNormal.z < 0.65f || tr.fStartSolid ) + { + pev->speed *= -1.0f; + } + else + { + m_vSurfaceNormal = tr.vecPlaneNormal; + } + } +} + +void CFuncVehicle::TerrainFollowing() +{ + TraceResult tr; + UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, ( m_height + 48 ) * -1 ), ignore_monsters, dont_ignore_glass, ENT( pev ), &tr ); + + if( tr.flFraction != 1.0f ) + { + m_vSurfaceNormal = tr.vecPlaneNormal; + } + else if( tr.fInWater ) + { + m_vSurfaceNormal = Vector( 0, 0, 1 ); + } +} + +void CFuncVehicle::Next() +{ + Vector vGravityVector, forward, right, up; + float time = 0.1f; + + vGravityVector = g_vecZero; + UTIL_MakeVectors( pev->angles ); + + forward = ( gpGlobals->v_forward * -1 ) * ( m_length * 0.5f ); + right = ( gpGlobals->v_right * -1 ) * ( m_width * 0.5f ); + up = gpGlobals->v_up * 16; + + m_vFrontLeft = pev->origin + forward - right + up; + m_vFrontRight = pev->origin + forward + right + up; + m_vFront = pev->origin + forward + up; + m_vBackLeft = pev->origin - forward - right + up; + m_vBackRight = pev->origin - forward + right + up; + m_vBack = pev->origin - forward + up; + m_vSurfaceNormal = g_vecZero; + + CheckTurning(); + + if( m_flSteeringWheelDecay < gpGlobals->time ) + { + m_flSteeringWheelDecay = gpGlobals->time + 0.1f; + + if( m_iTurnAngle < 0 ) + m_iTurnAngle++; + + else if( m_iTurnAngle > 0 ) + m_iTurnAngle--; + } + + if( m_flAcceleratorDecay < gpGlobals->time ) + { + m_flAcceleratorDecay = gpGlobals->time + 0.1f; + + if( pev->speed < 0 ) + { + pev->speed += 20; + + if( pev->speed > 0 ) + pev->speed = 0; + } + else if( pev->speed > 0 ) + { + pev->speed -= 20; + + if( pev->speed < 0 ) + pev->speed = 0; + } + } + + if( pev->speed == 0 ) + { + m_iTurnAngle = 0; + pev->avelocity = g_vecZero; + pev->velocity = g_vecZero; + + SetThink( &CFuncVehicle::Next ); + NextThink( pev->ltime + time, TRUE ); + return; + } + + TerrainFollowing(); + CollisionDetection(); + + Vector temp; + if( m_vSurfaceNormal != g_vecZero ) + { + Vector vTargetAngle, vAngle; + + float vx; + float vy; + + m_vVehicleDirection = CrossProduct( m_vSurfaceNormal, gpGlobals->v_forward ); + m_vVehicleDirection = CrossProduct( m_vSurfaceNormal, m_vVehicleDirection ); + + vTargetAngle = UTIL_VecToAngles( m_vVehicleDirection ); + vAngle = pev->angles; + + vTargetAngle.y += 180; + + if( m_iTurnAngle != 0 ) + { + vTargetAngle.y += m_iTurnAngle; + } + + FixupAngles2( vTargetAngle ); + FixupAngles2( vAngle ); + + vx = UTIL_AngleDistance( vTargetAngle.x, vAngle.x ); + vy = UTIL_AngleDistance( vTargetAngle.y, vAngle.y ); + + if( vx > 10 ) + vx = 10; + else if( vx < -10 ) + vx = -10; + + if( vy > 10 ) + vy = 10; + else if( vy < -10 ) + vy = -10; + + pev->avelocity.y = (int)( vy * 10 ); + pev->avelocity.x = (int)( vx * 10 ); + + m_flLaunchTime = -1; + m_flLastNormalZ = m_vSurfaceNormal.z; + } + else + { + if( m_flLaunchTime != -1 ) + { + vGravityVector.x = 0; + vGravityVector.y = 0; + vGravityVector.z = ( gpGlobals->time - m_flLaunchTime ) * -35; + + if( vGravityVector.z < -400 ) + { + vGravityVector.z = -400; + } + } + else + { + m_flLaunchTime = gpGlobals->time; + vGravityVector = Vector( 0, 0, 0 ); + pev->velocity = pev->velocity * 1.5f; + } + + m_vVehicleDirection = gpGlobals->v_forward * -1; + } + + UTIL_VecToAngles( m_vVehicleDirection ); + + if( m_flUpdateSound < gpGlobals->time ) + { + UpdateSound(); + m_flUpdateSound = gpGlobals->time + 1.0f; + } + + if( m_vSurfaceNormal != g_vecZero ) + { + pev->velocity = m_vVehicleDirection.Normalize() * pev->speed; + } + else + { + pev->velocity = pev->velocity + vGravityVector; + } + + SetThink( &CFuncVehicle::Next ); + NextThink( pev->ltime + time, TRUE ); +} + +void CFuncVehicle::DeadEnd() +{ + CPathTrack *pTrack = m_ppath; + ALERT( at_aiconsole, "TRAIN(%s): Dead end ", STRING( pev->targetname )); + + if( pTrack != NULL ) + { + CPathTrack *pNext; + + if( m_oldSpeed < 0 ) + { + do + { + pNext = pTrack->ValidPath( pTrack->GetPrevious(), TRUE ); + + if( pNext != NULL ) + { + pTrack = pNext; + } + } + while( pNext != NULL ); + } + else + { + do + { + pNext = pTrack->ValidPath( pTrack->GetNext(), TRUE ); + + if( pNext != NULL ) + { + pTrack = pNext; + } + } + while( pNext != NULL ); + } + } + + pev->velocity = g_vecZero; + pev->avelocity = g_vecZero; + + if( pTrack != NULL ) + { + ALERT( at_aiconsole, "at %s\n", STRING( pTrack->pev->targetname )); + + if( !FStringNull( pTrack->pev->netname )) + { + FireTargets( STRING( pTrack->pev->netname ), this, this, USE_TOGGLE, 0 ); + } + } + else + ALERT( at_aiconsole, "\n" ); +} + +void CFuncVehicle::SetControls(entvars_t *pevControls) +{ + Vector offset = pevControls->origin - pev->oldorigin; + m_controlMins = pevControls->mins + offset; + m_controlMaxs = pevControls->maxs + offset; +} + +BOOL CFuncVehicle::OnControls(entvars_t *pevTest) +{ + if( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) + return FALSE; + + Vector offset = pevTest->origin - pev->origin; + + UTIL_MakeVectors( pev->angles ); + + Vector local; + local.x = DotProduct( offset, gpGlobals->v_forward ); + local.y = -DotProduct( offset, gpGlobals->v_right ); + local.z = DotProduct( offset, gpGlobals->v_up ); + + return ( local.x >= m_controlMins.x && local.y >= m_controlMins.y && local.z >= m_controlMins.z + && local.x <= m_controlMaxs.x && local.y <= m_controlMaxs.y && local.z <= m_controlMaxs.z ); +} + +void CFuncVehicle::Find() +{ + m_ppath = CPathTrack::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING( pev->target ))); + + if( !m_ppath ) + return; + + entvars_t *pevTarget = m_ppath->pev; + + if( !FClassnameIs( pevTarget, "path_track" )) + { + ALERT( at_error, "func_track_train must be on a path of path_track\n" ); + m_ppath = NULL; + return; + } + + Vector nextPos = pevTarget->origin; + nextPos.z += m_height; + + Vector look = nextPos; + look.z -= m_height; + m_ppath->LookAhead( &look, m_length, 0 ); + look.z += m_height; + + pev->angles = UTIL_VecToAngles( look - nextPos ); + pev->angles.y += 180; + + if( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) + { + pev->angles.x = 0; + } + + UTIL_SetOrigin( pev, nextPos ); + NextThink( pev->ltime + 0.1f, FALSE ); + SetThink( &CFuncVehicle::Next ); + pev->speed = m_startSpeed; + UpdateSound(); +} + +void CFuncVehicle::NearestPath() +{ + CBaseEntity *pTrack = NULL; + CBaseEntity *pNearest = NULL; + float dist; + float closest = 1024; + + while( ( pTrack = UTIL_FindEntityInSphere( pTrack, pev->origin, 1024 )) != NULL ) + { + if( !( pTrack->pev->flags & ( FL_CLIENT | FL_MONSTER )) && FClassnameIs( pTrack->pev, "path_track" )) + { + dist = ( pev->origin - pTrack->pev->origin ).Length(); + + if( dist < closest ) + { + closest = dist; + pNearest = pTrack; + } + } + } + + if( !pNearest ) + { + ALERT( at_console, "Can't find a nearby track !!!\n" ); + SetThink( NULL ); + return; + } + + ALERT( at_aiconsole, "TRAIN: %s, Nearest track is %s\n", STRING( pev->targetname ), STRING( pNearest->pev->targetname )); + pTrack = ( (CPathTrack *)pNearest )->GetNext(); + + if( pTrack != NULL ) + { + if( ( pev->origin - pTrack->pev->origin ).Length() < ( pev->origin - pNearest->pev->origin ).Length()) + { + pNearest = pTrack; + } + } + + m_ppath = (CPathTrack *)pNearest; + if( pev->speed != 0 ) + { + NextThink( pev->ltime + 0.1f, FALSE ); + SetThink( &CFuncVehicle::Next ); + } +} + +void CFuncVehicle::OverrideReset() +{ + NextThink( pev->ltime + 0.1f, FALSE ); + SetThink( &CFuncVehicle::NearestPath ); +} + +CFuncVehicle *CFuncVehicle::Instance(edict_t *pent) +{ + if( FClassnameIs( pent, "func_vehicle" )) + { + return (CFuncVehicle *)GET_PRIVATE( pent ); + } + + return NULL; +} + +int CFuncVehicle::Classify() +{ + return CLASS_VEHICLE; +} + +void CFuncVehicle::Spawn() +{ + if( pev->speed == 0 ) + m_speed = 165; + else + m_speed = pev->speed; + + if( !m_sounds ) + m_sounds = 3; + + ALERT( at_console, "M_speed = %f\n", m_speed ); + + pev->speed = 0; + pev->velocity = g_vecZero; + pev->avelocity = g_vecZero; + + pev->impulse = (int)m_speed; + m_acceleration = 5; + + m_dir = 1; + m_flTurnStartTime = -1; + + if( FStringNull( pev->target )) + { + ALERT( at_console, "Vehicle with no target" ); + } + + if( pev->spawnflags & SF_TRACKTRAIN_PASSABLE ) + pev->solid = SOLID_NOT; + else + pev->solid = SOLID_BSP; + + pev->movetype = MOVETYPE_PUSH; + + SET_MODEL( ENT( pev ), STRING(pev->model )); + UTIL_SetSize( pev, pev->mins, pev->maxs ); + UTIL_SetOrigin( pev, pev->origin ); + + pev->oldorigin = pev->origin; + + m_controlMins = pev->mins; + m_controlMaxs = pev->maxs; + m_controlMaxs.z += 72; + + NextThink( pev->ltime + 0.1f, FALSE ); + SetThink( &CFuncVehicle::Find ); + Precache(); +} + +void CFuncVehicle::Restart() +{ + ALERT( at_console, "M_speed = %f\n", m_speed ); + + pev->speed = 0; + pev->velocity = g_vecZero; + pev->avelocity = g_vecZero; + + pev->impulse = (int)m_speed; + m_flTurnStartTime = -1; + m_flUpdateSound = -1; + m_dir = 1; + m_pDriver = NULL; + + if( FStringNull( pev->target )) + { + ALERT( at_console, "Vehicle with no target" ); + } + + UTIL_SetOrigin( pev, pev->oldorigin ); + STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise )); + + NextThink( pev->ltime + 0.1f, FALSE ); + SetThink( &CFuncVehicle::Find ); +} + +void CFuncVehicle::Precache() +{ + if( m_flVolume == 0.0f ) + m_flVolume = 1.0f; + + switch( m_sounds ) + { + case 1: PRECACHE_SOUND( "plats/vehicle1.wav" );pev->noise = MAKE_STRING( "plats/vehicle1.wav" ); break; + case 2: PRECACHE_SOUND( "plats/vehicle2.wav" );pev->noise = MAKE_STRING( "plats/vehicle2.wav" ); break; + case 3: PRECACHE_SOUND( "plats/vehicle3.wav" );pev->noise = MAKE_STRING( "plats/vehicle3.wav" ); break; + case 4: PRECACHE_SOUND( "plats/vehicle4.wav" );pev->noise = MAKE_STRING( "plats/vehicle4.wav" ); break; + case 5: PRECACHE_SOUND( "plats/vehicle6.wav" );pev->noise = MAKE_STRING( "plats/vehicle6.wav" ); break; + case 6: PRECACHE_SOUND( "plats/vehicle7.wav" );pev->noise = MAKE_STRING( "plats/vehicle7.wav" ); break; + } + + PRECACHE_SOUND( "plats/vehicle_brake1.wav" ); + PRECACHE_SOUND( "plats/vehicle_start1.wav" ); + + m_usAdjustPitch = PRECACHE_EVENT( 1, "events/vehicle.sc" ); +} + +LINK_ENTITY_TO_CLASS( func_vehiclecontrols, CFuncVehicleControls ); + +void CFuncVehicleControls::Find() +{ + edict_t *pTarget = NULL; + + do + { + pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING( pev->target )); + } + while( !FNullEnt( pTarget ) && !FClassnameIs( pTarget, "func_vehicle" )); + + if( FNullEnt( pTarget )) + { + ALERT( at_console, "No vehicle %s\n", STRING( pev->target )); + return; + } + + CFuncVehicle *pvehicle = CFuncVehicle::Instance( pTarget ); + + pvehicle->SetControls( pev ); + UTIL_Remove( this ); +} + +void CFuncVehicleControls::Spawn() +{ + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_NONE; + SET_MODEL( ENT( pev ), STRING( pev->model )); + + UTIL_SetSize( pev, pev->mins, pev->maxs ); + UTIL_SetOrigin( pev, pev->origin ); + + SetThink( &CFuncVehicleControls::Find ); + pev->nextthink = gpGlobals->time; +} From d020f6d474684756c30854107597da68236f86c0 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:15:15 +0000 Subject: [PATCH 12/42] HL 25th anniversary update satchel changes. (#429) --- dlls/game.cpp | 2 +- dlls/satchel.cpp | 86 ++++++++++++++++++++++++++++++++++++++++-------- mod_options.txt | 1 + 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/dlls/game.cpp b/dlls/game.cpp index f2c74d6b..26a4d481 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -34,7 +34,7 @@ cvar_t falldamage = { "mp_falldamage","0", FCVAR_SERVER }; cvar_t weaponstay = { "mp_weaponstay","0", FCVAR_SERVER }; cvar_t selfgauss = { "selfgauss", "1", FCVAR_SERVER }; cvar_t chargerfix = { "chargerfix", "0", FCVAR_SERVER }; -cvar_t satchelfix = { "satchelfix", "0", FCVAR_SERVER }; +cvar_t satchelfix = { "satchelfix", "1", FCVAR_SERVER }; cvar_t explosionfix = { "explosionfix", "0", FCVAR_SERVER }; cvar_t monsteryawspeedfix = { "monsteryawspeedfix", "1", FCVAR_SERVER }; cvar_t corpsephysics = { "corpsephysics", "0", FCVAR_SERVER }; diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 38ebec08..f5fa886b 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -22,6 +22,7 @@ #include "nodes.h" #include "player.h" #include "gamerules.h" +#include "game.h" enum satchel_state { @@ -191,23 +192,39 @@ LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel ) //========================================================= int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) { +#if !CLIENT_DLL CSatchel *pSatchel; + int nNumSatchels, nSatchelsInPocket; + CBaseEntity *ent; -#if CLIENT_DLL - if( bIsMultiplayer() ) -#else if( g_pGameRules->IsMultiplayer() ) -#endif { + if( satchelfix.value ) + { + if( !pOriginal->m_pPlayer ) + return TRUE; + + nNumSatchels = 0; + nSatchelsInPocket = pOriginal->m_pPlayer->m_rgAmmo[pOriginal->PrimaryAmmoIndex()]; + ent = NULL; + + while( ( ent = UTIL_FindEntityInSphere( ent, pOriginal->m_pPlayer->pev->origin, 4096 )) != NULL ) + { + if( FClassnameIs( ent->pev, "monster_satchel" )) + nNumSatchels += ent->pev->owner == pOriginal->m_pPlayer->edict(); + } + } + pSatchel = (CSatchel *)pOriginal; - if( pSatchel->m_chargeReady != SATCHEL_IDLE ) + if( pSatchel->m_chargeReady != SATCHEL_IDLE + && ( satchelfix.value && nSatchelsInPocket + nNumSatchels > SATCHEL_MAX_CARRY - 1 )) { // player has some satchels deployed. Refuse to add more. return FALSE; } } - +#endif return CBasePlayerWeapon::AddDuplicate( pOriginal ); } @@ -330,8 +347,9 @@ void CSatchel::Holster( int skiplocal /* = 0 */ ) } } -void CSatchel::PrimaryAttack() +void CSatchel::PrimaryAttack( void ) { +#if SATCHEL_OLD_BEHAVIOUR switch( m_chargeReady ) { case SATCHEL_IDLE: @@ -347,9 +365,9 @@ void CSatchel::PrimaryAttack() CBaseEntity *pSatchel = NULL; - while( ( pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 ) ) != NULL ) + while( ( pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 )) != NULL ) { - if( FClassnameIs( pSatchel->pev, "monster_satchel" ) ) + if( FClassnameIs( pSatchel->pev, "monster_satchel" )) { if( pSatchel->pev->owner == pPlayer ) { @@ -368,14 +386,56 @@ void CSatchel::PrimaryAttack() // we're reloading, don't allow fire break; } -} - -void CSatchel::SecondaryAttack( void ) -{ +#else if( m_chargeReady != SATCHEL_RELOAD ) { Throw(); } +#endif +} + +void CSatchel::SecondaryAttack( void ) +{ +#if SATCHEL_OLD_BEHAVIOUR + if( m_chargeReady != SATCHEL_RELOAD ) + { + Throw(); + } +#else + switch( m_chargeReady ) + { + case SATCHEL_IDLE: + break; + case SATCHEL_READY: + { + SendWeaponAnim( SATCHEL_RADIO_FIRE ); + + edict_t *pPlayer = m_pPlayer->edict(); + + CBaseEntity *pSatchel = NULL; + + while( ( pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 )) != NULL ) + { + if( FClassnameIs( pSatchel->pev, "monster_satchel" )) + { + if( pSatchel->pev->owner == pPlayer ) + { + pSatchel->Use( m_pPlayer, m_pPlayer, USE_ON, 0 ); + } + } + } + + m_chargeReady = SATCHEL_RELOAD; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5f ); + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5f; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5f; + break; + } + case SATCHEL_RELOAD: + // we're reloading, don't allow fire + break; + } +#endif } void CSatchel::Throw( void ) diff --git a/mod_options.txt b/mod_options.txt index ec7d0844..8cba4164 100644 --- a/mod_options.txt +++ b/mod_options.txt @@ -7,6 +7,7 @@ GAUSS_OVERCHARGE_FIX=OFF # Gauss overcharge fix TRIPMINE_BEAM_DUPLICATION_FIX=OFF # Fix of tripmine beam duplication on level transition HANDGRENADE_DEPLOY_FIX=OFF # Handgrenade deploy animation fix after finishing a throw WEAPONS_ANIMATION_TIMES_FIX=OFF # Animation times fix for some weapons +SATCHEL_OLD_BEHAVIOUR=OFF # Old pre-HL 25th satchel's behaviour OEM_BUILD=OFF # OEM Build HLDEMO_BUILD=OFF # Demo Build From 41ee8a8746c019379568311810d5ed136e6c4e1c Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:16:06 +0000 Subject: [PATCH 13/42] HL 25th anniversary update snark changes. (#430) --- dlls/squeakgrenade.cpp | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index f332a5a8..f9e77472 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -339,7 +339,8 @@ void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) // higher pitch as squeeker gets closer to detonation time flpitch = 155.0f - 60.0f * ( ( m_flDie - gpGlobals->time ) / SQUEEK_DETONATE_DELAY ); - if( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) + if( !FBitSet( pOther->pev->flags, FL_WORLDBRUSH ) + && pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) { // attack! @@ -494,20 +495,35 @@ void CSqueak::PrimaryAttack() { if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) { - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); TraceResult tr; - Vector trace_origin; + Vector trace_origin, forward; + float flVel; + + UTIL_MakeVectors( Vector( 0, m_pPlayer->pev->v_angle.y, m_pPlayer->pev->v_angle.z )); + forward = gpGlobals->v_forward; + UTIL_MakeVectors( m_pPlayer->pev->v_angle ); + + if( m_pPlayer->pev->v_angle.x <= 0 ) + { + flVel = 1; + } + else + { + flVel = m_pPlayer->pev->v_angle.x / 90.0f; + } // HACK HACK: Ugly hacks to handle change in origin based on new physics code for players // Move origin up if crouched and start trace a bit outside of body ( 20 units instead of 16 ) trace_origin = m_pPlayer->pev->origin; if( m_pPlayer->pev->flags & FL_DUCKING ) { - trace_origin = trace_origin - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); + trace_origin = trace_origin - Vector( 0, 0, 1 ) * ( flVel + 1.0f ) * -18; } + forward = forward * flVel + gpGlobals->v_forward * ( 1 - flVel ); + // find place to toss monster - UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20.0f, trace_origin + gpGlobals->v_forward * 64.0f, dont_ignore_monsters, NULL, &tr ); + UTIL_TraceLine( trace_origin + forward * 24.0f, trace_origin + gpGlobals->v_forward * 60.0f, dont_ignore_monsters, NULL, &tr ); int flags; #if CLIENT_WEAPONS @@ -517,13 +533,13 @@ void CSqueak::PrimaryAttack() #endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSnarkFire, 0.0f, g_vecZero, g_vecZero, 0.0f, 0.0f, 0, 0, 0, 0 ); - if( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25f ) + if( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0 ) { // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); #if !CLIENT_DLL CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pSqueak->pev->velocity = gpGlobals->v_forward * 200.0f + m_pPlayer->pev->velocity; + pSqueak->pev->velocity = forward * 200.0f + m_pPlayer->pev->velocity; #endif // play hunt sound float flRndSound = RANDOM_FLOAT( 0.0f, 1.0f ); From 938a6e23618bcba537eee97bd60d51b55f2400cc Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:16:25 +0000 Subject: [PATCH 14/42] HL 25th anniversary update rpg rocket changes. (#431) --- dlls/rpg.cpp | 42 ++++++++++++++++++++++++++++++++++-------- dlls/weapons.h | 4 +++- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index c81e6246..271a9d7c 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -116,6 +116,25 @@ CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBa return pRocket; } +void CRpgRocket::Explode( TraceResult *pTrace, int bitsDamageType ) +{ + if( CRpg *pLauncher = GetLauncher()) + { + // my launcher is still around, tell it I'm dead. + pLauncher->m_cActiveRockets--; + m_hLauncher = 0; + } + + STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" ); + + CGrenade::Explode( pTrace, bitsDamageType ); +} + +CRpg *CRpgRocket::GetLauncher( void ) +{ + return (CRpg*)( (CBaseEntity*)m_hLauncher ); +} + //========================================================= //========================================================= void CRpgRocket::Spawn( void ) @@ -150,10 +169,11 @@ void CRpgRocket::Spawn( void ) //========================================================= void CRpgRocket::RocketTouch( CBaseEntity *pOther ) { - if( CRpg* pLauncher = (CRpg*)( (CBaseEntity*)( m_hLauncher ) ) ) + if( CRpg *pLauncher = GetLauncher()) { // my launcher is still around, tell it I'm dead. pLauncher->m_cActiveRockets--; + m_hLauncher = 0; } STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" ); @@ -264,17 +284,23 @@ void CRpgRocket::FollowThink( void ) } pev->velocity = pev->velocity * 0.2f + vecTarget * flSpeed * 0.798f; if( pev->waterlevel == 0 && pev->velocity.Length() < 1500.0f ) - { - if( CRpg *pLauncher = (CRpg*)( (CBaseEntity*)( m_hLauncher ) ) ) - { - // my launcher is still around, tell it I'm dead. - pLauncher->m_cActiveRockets--; - } Detonate(); - } } // ALERT( at_console, "%.0f\n", flSpeed ); + if( CRpg *pLauncher = GetLauncher()) + { + if( ( pev->origin - pLauncher->pev->origin ).Length() > 8192 || gpGlobals->time - m_flIgniteTime > 6.0f ) + { + // my launcher is still around, tell it I'm dead. + pLauncher->m_cActiveRockets--; + m_hLauncher = 0; + } + } + + if( UTIL_PointContents( pev->origin ) == CONTENTS_SKY ) + Detonate(); + pev->nextthink = gpGlobals->time + 0.1f; } #endif diff --git a/dlls/weapons.h b/dlls/weapons.h index e4966125..ca1ec3b7 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -37,7 +37,7 @@ public: static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ); void Explode( Vector vecSrc, Vector vecAim ); - void Explode( TraceResult *pTrace, int bitsDamageType ); + virtual void Explode( TraceResult *pTrace, int bitsDamageType ); void EXPORT Smoke( void ); void EXPORT BounceTouch( CBaseEntity *pOther ); @@ -723,6 +723,8 @@ public: void EXPORT IgniteThink( void ); void EXPORT RocketTouch( CBaseEntity *pOther ); static CRpgRocket *CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher ); + void Explode( TraceResult *pTrace, int bitsDamageType ); + inline CRpg *GetLauncher( void ); int m_iTrail; float m_flIgniteTime; From eae53ece365413f4c93da516823a280c44c5ec36 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Wed, 31 Jan 2024 14:01:12 +0300 Subject: [PATCH 15/42] Replace magic numbers related to the max number of sentences with symbolic constants. Change condition from greater-or-equal to just greater. (#432) --- dlls/sound.cpp | 8 ++++---- dlls/util.h | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 992e0ebd..31a36085 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -1341,13 +1341,13 @@ void SENTENCEG_Init() g_engfuncs.pfnFreeFile( pMemFile ); - if( gcallsentences >= 2048 ) + if( gcallsentences > CVOXFILESENTENCEMAX_GOLDSOURCE_ANNIVERSARY_25 ) { - ALERT( at_warning, "NOTE: this mod might not work properly under GoldSource (post-anniversary update) engine: more than 2048 sentences\n" ); + ALERT( at_warning, "NOTE: this mod might not work properly under GoldSource (post-anniversary update) engine: more than %d sentences\n", CVOXFILESENTENCEMAX_GOLDSOURCE_ANNIVERSARY_25 ); } - else if( gcallsentences >= 1536 ) + else if( gcallsentences > CVOXFILESENTENCEMAX_GOLDSOURCE_LEGACY ) { - ALERT( at_warning, "NOTE: this mod might not work properly under GoldSource (pre-anniversary update) engine: more than 1536 sentences\n" ); + ALERT( at_warning, "NOTE: this mod might not work properly under GoldSource (pre-anniversary update) engine: more than %d sentences\n", CVOXFILESENTENCEMAX_GOLDSOURCE_LEGACY ); } fSentencesInit = TRUE; diff --git a/dlls/util.h b/dlls/util.h index bfe0fd32..6ad28546 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -498,7 +498,11 @@ extern DLL_GLOBAL int g_Language; // sentence groups #define CBSENTENCENAME_MAX 16 -#define CVOXFILESENTENCEMAX 4096 // max number of sentences in game. NOTE: this must match + +#define CVOXFILESENTENCEMAX_GOLDSOURCE_LEGACY 1536 +#define CVOXFILESENTENCEMAX_GOLDSOURCE_ANNIVERSARY_25 2048 +#define CVOXFILESENTENCEMAX_XASH3D 4096 +#define CVOXFILESENTENCEMAX CVOXFILESENTENCEMAX_XASH3D // max number of sentences in game. NOTE: this must match // CVOXFILESENTENCEMAX in engine\sound.h!!! extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; From 6787caaf9ebb39ec65870626358f02c05fb9e8be Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Thu, 1 Feb 2024 02:38:59 +0500 Subject: [PATCH 16/42] Read spserver.cfg when load map in singleplayer game mode. --- dlls/singleplay_gamerules.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index ba73747b..59f43fa2 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -35,6 +35,7 @@ extern int gmsgMOTD; //========================================================= CHalfLifeRules::CHalfLifeRules( void ) { + SERVER_COMMAND( "exec spserver.cfg\n" ); RefreshSkillData(); } From 9c247c5bcf6d04fe46214cbf5c114d0f5e99e370 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Fri, 2 Feb 2024 13:02:25 +0000 Subject: [PATCH 17/42] Add new humoristic railgunarena-like multiplayer game mode "GhostBusters" from HL 25th anniversary update. (#433) --- dlls/egon.cpp | 15 ++- dlls/game.cpp | 3 +- dlls/game.h | 1 + dlls/gamerules.cpp | 5 + dlls/gamerules.h | 26 +++++ dlls/multiplay_gamerules.cpp | 216 +++++++++++++++++++++++++++++++++++ dlls/player.cpp | 71 +++++++++--- dlls/player.h | 1 + dlls/weapons.cpp | 15 ++- dlls/weapons.h | 2 +- 10 files changed, 337 insertions(+), 18 deletions(-) diff --git a/dlls/egon.cpp b/dlls/egon.cpp index d315e26f..ab6fe24c 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -291,7 +291,8 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) // multiplayer uses 1 ammo every 1/10th second if( gpGlobals->time >= m_flAmmoUseTime ) { - UseAmmo( 1 ); + if( !g_pGameRules->IsBustingGame()) + UseAmmo( 1 ); m_flAmmoUseTime = gpGlobals->time + 0.1f; } } @@ -336,7 +337,8 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) //multiplayer uses 5 ammo/second if( gpGlobals->time >= m_flAmmoUseTime ) { - UseAmmo( 1 ); + if( !g_pGameRules->IsBustingGame()) + UseAmmo( 1 ); m_flAmmoUseTime = gpGlobals->time + 0.2f; } } @@ -497,6 +499,15 @@ void CEgon::WeaponIdle( void ) m_deployed = TRUE; } +BOOL CEgon::CanHolster( void ) +{ +#if CLIENT_DLL + return TRUE; +#else + return !g_pGameRules->IsBustingGame(); +#endif +} + void CEgon::EndAttack( void ) { bool bMakeNoise = false; diff --git a/dlls/game.cpp b/dlls/game.cpp index 26a4d481..93cc7eb2 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -458,6 +458,7 @@ cvar_t sk_player_leg3 = { "sk_player_leg3","1" }; // END Cvars for Skill Level settings cvar_t sv_pushable_fixed_tick_fudge = { "sv_pushable_fixed_tick_fudge", "15" }; +cvar_t sv_busters = { "sv_busters", "0" }; // Register your console variables here // This gets called one time when the game is initialied @@ -507,7 +508,7 @@ void GameDLLInit( void ) CVAR_REGISTER( &multibyte_only ); CVAR_REGISTER( &mp_chattime ); - + CVAR_REGISTER( &sv_busters ); // REGISTER CVARS FOR SKILL LEVEL STUFF diff --git a/dlls/game.h b/dlls/game.h index 069324bb..8a0f6d34 100644 --- a/dlls/game.h +++ b/dlls/game.h @@ -44,6 +44,7 @@ extern cvar_t defaultteam; extern cvar_t allowmonsters; extern cvar_t bhopcap; extern cvar_t sv_pushable_fixed_tick_fudge; +extern cvar_t sv_busters; // Engine Cvars extern cvar_t *g_psv_gravity; diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index bfbbf59e..2499a67d 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -331,6 +331,11 @@ CGameRules *InstallGameRules( void ) g_teamplay = 1; return new CHalfLifeTeamplay; } + if( sv_busters.value > 0 ) + { + g_teamplay = 0; + return new CMultiplayBusters; + } if( (int)gpGlobals->deathmatch == 1 ) { // vanilla deathmatch diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 781ef447..0d86ce02 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -162,6 +162,7 @@ public: // Immediately end a multiplayer game virtual void EndMultiplayerGame( void ) {} + virtual BOOL IsBustingGame( void ){ return FALSE; }; }; extern CGameRules *InstallGameRules( void ); @@ -362,5 +363,30 @@ protected: void SendMOTDToClient( edict_t *client ); }; +bool IsPlayerBusting( CBaseEntity *pPlayer ); +BOOL BustingCanHaveItem( CBasePlayer *pPlayer, CBaseEntity *pItem ); + +class CMultiplayBusters : public CHalfLifeMultiplay +{ +public: + CMultiplayBusters(); + void Think(); + void PlayerSpawn( CBasePlayer *pPlayer ); + void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); + int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); + BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ); + void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); + BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + void CheckForEgons(); + void SetPlayerModel( CBasePlayer *pPlayer, BOOL bKnownBuster ); + BOOL IsBustingGame( void ){ return TRUE; }; + +protected: + float m_flEgonBustingCheckTime; +}; + extern DLL_GLOBAL CGameRules *g_pGameRules; #endif // GAMERULES_H diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 49e24ab3..1578ec13 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -1723,3 +1723,219 @@ void CHalfLifeMultiplay::SendMOTDToClient( edict_t *client ) FREE_FILE( (void*)aFileList ); } + +int CMultiplayBusters::WeaponShouldRespawn( CBasePlayerItem *pWeapon ) +{ + if( pWeapon->m_iId == WEAPON_EGON ) + return GR_WEAPON_RESPAWN_NO; + + return CHalfLifeMultiplay::WeaponShouldRespawn( pWeapon ); +} + +BOOL CMultiplayBusters::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) +{ + return BustingCanHaveItem( pPlayer, pItem ); +} + +BOOL CMultiplayBusters::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ) +{ + if( !BustingCanHaveItem( pPlayer, pItem )) + return FALSE; + + return CHalfLifeMultiplay::CanHavePlayerItem( pPlayer, pItem ); +} + +int CMultiplayBusters::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) +{ + if( IsPlayerBusting( pAttacker )) + return 1; + + if( IsPlayerBusting( pKilled )) + return 2; + + return 0; +} +void CMultiplayBusters::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) +{ + if( IsPlayerBusting( pVictim ) + || IsPlayerBusting( CBaseEntity::Instance( pKiller ))) + CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor ); +} + +void CMultiplayBusters::PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +{ + if( IsPlayerBusting( pVictim )) + { + UTIL_ClientPrintAll( HUD_PRINTCENTER, "The Buster is dead!!" ); + + m_flEgonBustingCheckTime = -1.0f; + + CBasePlayer *peKiller = NULL; + CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); + if( ktmp && ( ktmp->Classify() == CLASS_PLAYER ) ) + peKiller = (CBasePlayer*)ktmp; + else if( ktmp && ktmp->Classify() == CLASS_VEHICLE ) + { + CBasePlayer *pDriver = (CBasePlayer *)( (CFuncVehicle *)ktmp )->m_pDriver; + + if( pDriver != NULL ) + { + pKiller = pDriver->pev; + peKiller = (CBasePlayer *)pDriver; + } + } + + if( peKiller && peKiller->IsPlayer() ) + { + UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "%s has killed the Buster!", STRING( peKiller->pev->netname ))); + } + + pVictim->pev->renderfx = 0; + pVictim->pev->rendercolor = g_vecZero; + } + + CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); +} + +void CMultiplayBusters::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) +{ + SetPlayerModel( pPlayer, FALSE ); + CHalfLifeMultiplay::ClientUserInfoChanged( pPlayer, infobuffer ); +} + +void CMultiplayBusters::PlayerSpawn( CBasePlayer *pPlayer ) +{ + CHalfLifeMultiplay::PlayerSpawn( pPlayer ); + SetPlayerModel( pPlayer, FALSE ); +} + +bool IsPlayerBusting( CBaseEntity *pPlayer ) +{ + if( g_pGameRules->IsBustingGame() + && pPlayer && pPlayer->IsPlayer() + && ((CBasePlayer*)pPlayer)->HasPlayerItemFromID( WEAPON_EGON )) + return true; + + return false; +} + +BOOL BustingCanHaveItem( CBasePlayer *pPlayer, CBaseEntity *pItem ) +{ + if( IsPlayerBusting( pPlayer ) + && !( strncmp( STRING( pItem->pev->classname ), "weapon_", 7 ) + && strncmp( STRING( pItem->pev->classname ), "ammo_", 5 ))) + return FALSE; + + return TRUE; +} + +CMultiplayBusters::CMultiplayBusters() +{ + CHalfLifeMultiplay(); + + m_flEgonBustingCheckTime = -1.0; +} + +void CMultiplayBusters::CheckForEgons( void ) +{ + CBaseEntity *pPlayer; + CWeaponBox *pWeaponBox = NULL; + CBasePlayerItem *pWeapon; + CBasePlayer *pNewBuster = NULL; + int i, bestfrags = 9999; + + if( m_flEgonBustingCheckTime <= 0.0f ) + { + m_flEgonBustingCheckTime = gpGlobals->time + 10.0f; + return; + } + + if( gpGlobals->time < m_flEgonBustingCheckTime ) + return; + + m_flEgonBustingCheckTime = -1.0f; + + for( i = 1; i <= gpGlobals->maxClients; i++ ) + { + pPlayer = UTIL_PlayerByIndex( i ); + if( IsPlayerBusting( pPlayer )) + return; + } + + for( i = 1; i <= gpGlobals->maxClients; i++ ) + { + pPlayer = UTIL_PlayerByIndex( i ); + + if( pPlayer && pPlayer->pev->frags < bestfrags ) + { + pNewBuster = (CBasePlayer*)pPlayer; + bestfrags = pPlayer->pev->frags; + } + } + + if( !pNewBuster ) + return; + + pNewBuster->GiveNamedItem( "weapon_egon" ); + + while( ( pWeaponBox = (CWeaponBox*)UTIL_FindEntityByClassname( pWeaponBox, "weaponbox" ))) + { + // destroy weaponboxes with egons + for( i = 0; i < MAX_ITEM_TYPES; i++ ) + { + pWeapon = pWeaponBox->m_rgpPlayerItems[i]; + + while( pWeapon ) + { + if( pWeapon->m_iId != WEAPON_EGON ) + { + pWeapon = pWeapon->m_pNext; + continue; + } + + pWeaponBox->Kill(); + pWeapon = 0; + i = MAX_ITEM_TYPES; + } + } + } +} + +void CMultiplayBusters::Think( void ) +{ + CheckForEgons(); + CHalfLifeMultiplay::Think(); +} + +void CMultiplayBusters::SetPlayerModel( CBasePlayer *pPlayer, BOOL bKnownBuster ) +{ + const char *pszModel = NULL; + + if( bKnownBuster || IsPlayerBusting( pPlayer )) + { + pszModel = "ivan"; + } + else + { + pszModel = "skeleton"; + } + + g_engfuncs.pfnSetClientKeyValue( ENTINDEX( pPlayer->edict()), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict()), "model", pszModel ); +} + +void CMultiplayBusters::PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) +{ + if( pWeapon->m_iId != WEAPON_EGON ) + return; + + pPlayer->RemoveAllItems( FALSE ); + UTIL_ClientPrintAll( HUD_PRINTCENTER, "Long live the new Buster!" ); + UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "%s is busting!\n", STRING( pPlayer->pev->netname ))); + SetPlayerModel( pPlayer, TRUE ); + pPlayer->pev->health = pPlayer->pev->max_health; + pPlayer->pev->armorvalue = MAX_NORMAL_BATTERY; + pPlayer->pev->renderfx = kRenderFxGlowShell; + pPlayer->pev->renderamt = 25; + pPlayer->pev->rendercolor = Vector( 0, 75, 250 ); + pPlayer->m_rgAmmo[pWeapon->PrimaryAmmoIndex()] = pPlayer->ammo_uranium = 100; +} diff --git a/dlls/player.cpp b/dlls/player.cpp index 7f5df559..3b1d57af 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -755,24 +755,44 @@ void CBasePlayer::PackDeadPlayerItems( void ) iPA = 0; iPW = 0; - // pack the ammo - while( iPackAmmo[iPA] != -1 ) + if( g_pGameRules->IsBustingGame()) { - pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[iPackAmmo[iPA]].pszName ), m_rgAmmo[iPackAmmo[iPA]] ); - iPA++; + while( rgpPackWeapons[iPW] ) + { + // weapon unhooked from the player. Pack it into der box. + if( FClassnameIs( rgpPackWeapons[iPW]->pev, "weapon_egon" )) + { + pWeaponBox->PackWeapon( rgpPackWeapons[iPW] ); + SET_MODEL( pWeaponBox->edict(), "models/w_egon.mdl" ); + pWeaponBox->pev->velocity = g_vecZero; + pWeaponBox->pev->renderfx = kRenderFxGlowShell; + pWeaponBox->pev->renderamt = 25; + pWeaponBox->pev->rendercolor = Vector( 0, 75, 250 ); + break; + } + iPW++; + } } - - // now pack all of the items in the lists - while( rgpPackWeapons[iPW] ) + else { - // weapon unhooked from the player. Pack it into der box. - pWeaponBox->PackWeapon( rgpPackWeapons[iPW] ); + // pack the ammo + while( iPackAmmo[iPA] != -1 ) + { + pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[iPackAmmo[iPA]].pszName ), m_rgAmmo[iPackAmmo[iPA]] ); + iPA++; + } - iPW++; + // now pack all of the items in the lists + while( rgpPackWeapons[iPW] ) + { + // weapon unhooked from the player. Pack it into der box. + pWeaponBox->PackWeapon( rgpPackWeapons[iPW] ); + + iPW++; + } + + pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. } - - pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. - RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above. } @@ -4635,6 +4655,31 @@ BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) return FALSE; } +//========================================================= +// HasPlayerItemFromID +//========================================================= +BOOL CBasePlayer::HasPlayerItemFromID( int nID ) +{ + CBasePlayerItem *pItem; + int i; + + for( i = 0; i < MAX_ITEM_TYPES; i++ ) + { + pItem = m_rgpPlayerItems[i]; + + while( pItem ) + { + if( nID == pItem->m_iId ) + { + return TRUE; + } + pItem = pItem->m_pNext; + } + } + + return FALSE; +} + //========================================================= // //========================================================= diff --git a/dlls/player.h b/dlls/player.h index f86d25b4..90dd62e1 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -265,6 +265,7 @@ public: void DropPlayerItem ( char *pszItemName ); BOOL HasPlayerItem( CBasePlayerItem *pCheckItem ); BOOL HasNamedPlayerItem( const char *pszItemName ); + BOOL HasPlayerItemFromID( int nID ); BOOL HasWeapons( void );// do I have ANY weapons? void SelectPrevItem( int iItem ); void SelectNextItem( int iItem ); diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 0443d271..3ff1a15f 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -471,6 +471,19 @@ void CBasePlayerItem::FallThink( void ) Materialize(); } + else if( m_pPlayer ) + { + SetThink( NULL ); + } + + if( g_pGameRules->IsBustingGame()) + { + if( !FNullEnt( pev->owner )) + return; + + if( FClassnameIs( pev, "weapon_egon" )) + UTIL_Remove( this ); + } } //========================================================= @@ -1076,7 +1089,7 @@ void CBasePlayerAmmo::Materialize( void ) void CBasePlayerAmmo::DefaultTouch( CBaseEntity *pOther ) { - if( !pOther->IsPlayer() ) + if( !pOther->IsPlayer() || IsPlayerBusting( pOther )) { return; } diff --git a/dlls/weapons.h b/dlls/weapons.h index ca1ec3b7..fae0889d 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -793,13 +793,13 @@ public: int AddToPlayer( CBasePlayer *pPlayer ); BOOL Deploy( void ); + BOOL CanHolster( void ); void Holster( int skiplocal = 0 ); void UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ); void CreateEffect ( void ); void DestroyEffect ( void ); - void EndAttack( void ); void Attack( void ); void PrimaryAttack( void ); From dd1036a5a014971f305a68cb8f5382da6f5f9dc1 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 3 Feb 2024 02:00:18 +0500 Subject: [PATCH 18/42] Change hive hand's weight. --- dlls/weapons.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/weapons.h b/dlls/weapons.h index fae0889d..f0ba783c 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -95,7 +95,7 @@ public: #define RPG_WEIGHT 20 #define GAUSS_WEIGHT 20 #define EGON_WEIGHT 20 -#define HORNETGUN_WEIGHT 10 +#define HORNETGUN_WEIGHT 15 #define HANDGRENADE_WEIGHT 5 #define SNARK_WEIGHT 5 #define SATCHEL_WEIGHT -10 From d438dbfe339d7d82f687a9370cbe811104d6051c Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 3 Feb 2024 22:58:03 +0500 Subject: [PATCH 19/42] Reload dropped weapons. --- dlls/player.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/dlls/player.cpp b/dlls/player.cpp index 3b1d57af..04d161cc 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -661,7 +661,7 @@ void CBasePlayer::PackDeadPlayerItems( void ) { int iWeaponRules; int iAmmoRules; - int i; + int i, j; CBasePlayerWeapon *rgpPackWeapons[MAX_WEAPONS] = {0,}; int iPackAmmo[MAX_AMMO_SLOTS]; int iPW = 0;// index into packweapons array @@ -696,16 +696,26 @@ void CBasePlayer::PackDeadPlayerItems( void ) if( m_pActiveItem && pPlayerItem == m_pActiveItem ) { // this is the active item. Pack it. - rgpPackWeapons[iPW++] = (CBasePlayerWeapon *)pPlayerItem; + rgpPackWeapons[iPW] = (CBasePlayerWeapon *)pPlayerItem; } break; case GR_PLR_DROP_GUN_ALL: - rgpPackWeapons[iPW++] = (CBasePlayerWeapon *)pPlayerItem; + rgpPackWeapons[iPW] = (CBasePlayerWeapon *)pPlayerItem; break; default: break; } + if( rgpPackWeapons[iPW] ) + { + // complete the reload. + j = Q_min( rgpPackWeapons[iPW]->iMaxClip() - rgpPackWeapons[iPW]->m_iClip, m_rgAmmo[rgpPackWeapons[iPW]->m_iPrimaryAmmoType] ); + + // Add them to the clip + rgpPackWeapons[iPW]->m_iClip += j; + m_rgAmmo[rgpPackWeapons[iPW]->m_iPrimaryAmmoType] -= j; + iPW++; + } pPlayerItem = pPlayerItem->m_pNext; } } @@ -790,8 +800,8 @@ void CBasePlayer::PackDeadPlayerItems( void ) iPW++; } - - pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. +end: + pWeaponBox->pev->velocity = pev->velocity * 1.2f;// weaponbox has player's velocity, then some. } RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above. } From b37078f019a83da9dc6e0cc5ef29668725b2f25f Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sun, 4 Feb 2024 01:15:33 +0500 Subject: [PATCH 20/42] Change weapon switch rules. --- dlls/gamerules.h | 2 +- dlls/multiplay_gamerules.cpp | 65 ++----------------------------- dlls/rpg.cpp | 2 +- dlls/singleplay_gamerules.cpp | 73 +++++++++++++++++++++++++++++++++++ dlls/weapons.h | 1 + 5 files changed, 79 insertions(+), 64 deletions(-) diff --git a/dlls/gamerules.h b/dlls/gamerules.h index 0d86ce02..adbbaa31 100644 --- a/dlls/gamerules.h +++ b/dlls/gamerules.h @@ -166,7 +166,7 @@ public: }; extern CGameRules *InstallGameRules( void ); - +BOOL HLGetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); //========================================================= // CHalfLifeRules - rules for the single player Half-Life diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 1578ec13..ef2db2d5 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -345,70 +345,11 @@ BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerI return FALSE; } +//========================================================= +//========================================================= BOOL CHalfLifeMultiplay::GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { - CBasePlayerItem *pCheck; - CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category. - int iBestWeight; - int i; - - iBestWeight = -1;// no weapon lower than -1 can be autoswitched to - pBest = NULL; - - if( !pCurrentWeapon->CanHolster() ) - { - // can't put this gun away right now, so can't switch. - return FALSE; - } - - for( i = 0; i < MAX_ITEM_TYPES; i++ ) - { - pCheck = pPlayer->m_rgpPlayerItems[i]; - - while( pCheck ) - { - if( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) - { - // this weapon is from the same category. - if ( pCheck->CanDeploy() ) - { - if ( pPlayer->SwitchWeapon( pCheck ) ) - { - return TRUE; - } - } - } - else if( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of - { - //ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); - // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight - // that the player was using. This will end up leaving the player with his heaviest-weighted - // weapon. - if( pCheck->CanDeploy() ) - { - // if this weapon is useable, flag it as the best - iBestWeight = pCheck->iWeight(); - pBest = pCheck; - } - } - - pCheck = pCheck->m_pNext; - } - } - - // if we make it here, we've checked all the weapons and found no useable - // weapon in the same catagory as the current weapon. - - // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always - // at least get the crowbar, but ya never know. - if( !pBest ) - { - return FALSE; - } - - pPlayer->SwitchWeapon( pBest ); - - return TRUE; + return HLGetNextBestWeapon( pPlayer, pCurrentWeapon ); } //========================================================= diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 271a9d7c..4e39ec2c 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -400,7 +400,7 @@ int CRpg::GetItemInfo( ItemInfo *p ) p->iSlot = 3; p->iPosition = 0; p->iId = m_iId = WEAPON_RPG; - p->iFlags = 0; + p->iFlags = ITEM_FLAG_NOCHOICE; p->iWeight = RPG_WEIGHT; return 1; diff --git a/dlls/singleplay_gamerules.cpp b/dlls/singleplay_gamerules.cpp index 59f43fa2..06ad417c 100644 --- a/dlls/singleplay_gamerules.cpp +++ b/dlls/singleplay_gamerules.cpp @@ -95,10 +95,83 @@ BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem return TRUE; } +//========================================================= +//========================================================= +BOOL HLGetNextBestWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) +{ + CBasePlayerItem *pCheck; + CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category. + int iBestWeight; + int i; + + iBestWeight = -1;// no weapon lower than -1 can be autoswitched to + pBest = NULL; + + if( !pCurrentWeapon->CanHolster() ) + { + // can't put this gun away right now, so can't switch. + return FALSE; + } + + for( i = 0; i < MAX_ITEM_TYPES; i++ ) + { + pCheck = pPlayer->m_rgpPlayerItems[i]; + + while( pCheck ) + { + if( !FBitSet( pCheck->iFlags(), ITEM_FLAG_NOCHOICE )) + { + if( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) + { + // this weapon is from the same category. + if ( pCheck->CanDeploy() ) + { + if ( pPlayer->SwitchWeapon( pCheck ) ) + { + return TRUE; + } + } + } + else if( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of + { + //ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); + // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight + // that the player was using. This will end up leaving the player with his heaviest-weighted + // weapon. + if( pCheck->CanDeploy() ) + { + // if this weapon is useable, flag it as the best + iBestWeight = pCheck->iWeight(); + pBest = pCheck; + } + } + } + + pCheck = pCheck->m_pNext; + } + } + + // if we make it here, we've checked all the weapons and found no useable + // weapon in the same catagory as the current weapon. + + // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always + // at least get the crowbar, but ya never know. + if( !pBest ) + { + return FALSE; + } + + pPlayer->SwitchWeapon( pBest ); + + return TRUE; +} + //========================================================= //========================================================= BOOL CHalfLifeRules::GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { + if( pCurrentWeapon && FBitSet( pCurrentWeapon->iFlags(), ITEM_FLAG_EXHAUSTIBLE )) + return HLGetNextBestWeapon( pPlayer, pCurrentWeapon ); return FALSE; } diff --git a/dlls/weapons.h b/dlls/weapons.h index f0ba783c..4db8381f 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -183,6 +183,7 @@ typedef enum #define ITEM_FLAG_NOAUTOSWITCHEMPTY 4 #define ITEM_FLAG_LIMITINWORLD 8 #define ITEM_FLAG_EXHAUSTIBLE 16 // A player can totally exhaust their ammo supply and lose this weapon +#define ITEM_FLAG_NOCHOICE 32 #define WEAPON_IS_ONTARGET 0x40 From e552d2cc06d303335def49075e5cf152eaed623b Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 3 Feb 2024 22:33:15 +0000 Subject: [PATCH 21/42] Make cycler and func_button speakable targets for scripted_sentence. (#434) --- cl_dll/hl/hl_baseentity.cpp | 6 +-- dlls/basemonster.h | 7 +--- dlls/cbase.h | 11 ++++- dlls/h_cycler.cpp | 2 + dlls/monsters.cpp | 23 +---------- dlls/scripted.cpp | 80 +++++++++++++++++++++---------------- dlls/subs.cpp | 21 ++++++++++ 7 files changed, 85 insertions(+), 65 deletions(-) diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index 2e2ec2d6..a47078e5 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -207,9 +207,9 @@ BOOL CBaseMonster::FindLateralCover( const Vector &vecThreat, const Vector &vecV Vector CBaseMonster::ShootAtEnemy( const Vector &shootOrigin ) { return g_vecZero; } BOOL CBaseMonster::FacingIdeal( void ) { return FALSE; } BOOL CBaseMonster::FCanActiveIdle( void ) { return FALSE; } -void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { } -void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { } -void CBaseMonster::SentenceStop( void ) { } +void CBaseToggle::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { } +void CBaseToggle::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { } +void CBaseToggle::SentenceStop( void ) { } void CBaseMonster::CorpseFallThink( void ) { } void CBaseMonster::MonsterInitDead( void ) { } BOOL CBaseMonster::BBoxFlat( void ) { return TRUE; } diff --git a/dlls/basemonster.h b/dlls/basemonster.h index ea145a93..dc642a6c 100644 --- a/dlls/basemonster.h +++ b/dlls/basemonster.h @@ -120,6 +120,7 @@ public: virtual int BloodColor( void ) { return m_bloodColor; } virtual CBaseMonster *MyMonsterPointer( void ) { return this; } + virtual BOOL IsAllowedToSpeak( void ) { return IsAlive(); } virtual void Look( int iDistance );// basic sight function for monsters virtual void RunAI( void );// core ai function! void Listen( void ); @@ -186,11 +187,7 @@ public: virtual void ScheduleChange( void ) {} // virtual int CanPlaySequence( void ) { return ((m_pCine == NULL) && (m_MonsterState == MONSTERSTATE_NONE || m_MonsterState == MONSTERSTATE_IDLE || m_IdealMonsterState == MONSTERSTATE_IDLE)); } virtual int CanPlaySequence( BOOL fDisregardState, int interruptLevel ); - virtual int CanPlaySentence( BOOL fDisregardState ) { return IsAlive(); } - virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ); - virtual void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); - - virtual void SentenceStop( void ); + virtual int CanPlaySentence( BOOL fDisregardState ) { return IsAllowedToSpeak(); } Task_t *GetTask( void ); virtual MONSTERSTATE GetIdealState( void ); diff --git a/dlls/cbase.h b/dlls/cbase.h index 88a161e0..caf301d9 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -107,6 +107,7 @@ typedef void(CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCalle #define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures. class CBaseEntity; +class CBaseToggle; class CBaseMonster; class CBasePlayerItem; class CSquadMonster; @@ -173,6 +174,7 @@ public: virtual int BloodColor( void ) { return DONT_BLEED; } virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); virtual BOOL IsTriggered( CBaseEntity *pActivator ) {return TRUE; } + virtual CBaseToggle *MyTogglePointer( void ) { return NULL; } virtual CBaseMonster *MyMonsterPointer( void ) { return NULL; } virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL; } virtual int GetToggleState( void ) { return TS_AT_TOP; } @@ -251,7 +253,6 @@ public: int Intersects( CBaseEntity *pOther ); void MakeDormant( void ); int IsDormant( void ); - BOOL IsLockedByMaster( void ) { return FALSE; } static CBaseEntity *Instance( edict_t *pent ) { @@ -524,9 +525,15 @@ public: static TYPEDESCRIPTION m_SaveData[]; + CBaseToggle *MyTogglePointer( void ) { return this; } virtual int GetToggleState( void ) { return m_toggle_state; } virtual float GetDelay( void ) { return m_flWait; } + virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ); + virtual void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); + virtual void SentenceStop( void ); + virtual BOOL IsAllowedToSpeak( void ) { return FALSE; } + // common member functions void LinearMove( Vector vecDest, float flSpeed ); void EXPORT LinearMoveDone( void ); @@ -693,6 +700,8 @@ public: // Buttons that don't take damage can be IMPULSE used virtual int ObjectCaps( void ) { return (CBaseToggle:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | (pev->takedamage?0:FCAP_IMPULSE_USE); } + BOOL IsAllowedToSpeak( void ) { return TRUE; } + BOOL m_fStayPushed; // button stays pushed in until touched again? BOOL m_fRotating; // a rotating button? default is a sliding button. diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index 49eff1d8..16d15855 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -49,6 +49,8 @@ public: virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; + BOOL IsAllowedToSpeak( void ) { return TRUE; } + int m_animate; }; diff --git a/dlls/monsters.cpp b/dlls/monsters.cpp index 8b8643a6..f995dff5 100644 --- a/dlls/monsters.cpp +++ b/dlls/monsters.cpp @@ -1392,7 +1392,7 @@ float CBaseMonster::OpenDoorAndWait( entvars_t *pevDoor ) //ALERT( at_aiconsole, "A door. " ); CBaseEntity *pcbeDoor = CBaseEntity::Instance( pevDoor ); - if( pcbeDoor && !pcbeDoor->IsLockedByMaster() ) + if( pcbeDoor ) { //ALERT( at_aiconsole, "unlocked! " ); pcbeDoor->Use( this, this, USE_ON, 0.0 ); @@ -3189,27 +3189,6 @@ BOOL CBaseMonster::FCanActiveIdle( void ) return FALSE; } -void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) -{ - if( pszSentence && IsAlive() ) - { - if( pszSentence[0] == '!' ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, PITCH_NORM ); - else - SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, PITCH_NORM ); - } -} - -void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) -{ - PlaySentence( pszSentence, duration, volume, attenuation ); -} - -void CBaseMonster::SentenceStop( void ) -{ - EMIT_SOUND( edict(), CHAN_VOICE, "common/null.wav", 1.0, ATTN_IDLE ); -} - void CBaseMonster::CorpseFallThink( void ) { if( pev->flags & FL_ONGROUND ) diff --git a/dlls/scripted.cpp b/dlls/scripted.cpp index da495f98..bdaa85c0 100644 --- a/dlls/scripted.cpp +++ b/dlls/scripted.cpp @@ -902,9 +902,9 @@ public: static TYPEDESCRIPTION m_SaveData[]; - CBaseMonster *FindEntity( void ); - BOOL AcceptableSpeaker( CBaseMonster *pMonster ); - BOOL StartSentence( CBaseMonster *pTarget ); + CBaseToggle *FindEntity( void ); + BOOL AcceptableSpeaker( CBaseToggle *pTarget ); + BOOL StartSentence( CBaseToggle *pTarget ); private: string_t m_iszSentence; // string index for idle animation @@ -1036,20 +1036,20 @@ void CScriptedSentence::Spawn( void ) void CScriptedSentence::FindThink( void ) { - CBaseMonster *pMonster = FindEntity(); - if( pMonster ) + CBaseToggle *pTarget = FindEntity(); + if( pTarget ) { - StartSentence( pMonster ); + StartSentence( pTarget ); if( pev->spawnflags & SF_SENTENCE_ONCE ) UTIL_Remove( this ); SetThink( &CScriptedSentence::DelayThink ); pev->nextthink = gpGlobals->time + m_flDuration + m_flRepeat; m_active = FALSE; - //ALERT( at_console, "%s: found monster %s\n", STRING( m_iszSentence ), STRING( m_iszEntity ) ); + //ALERT( at_console, "%s: found target %s\n", STRING( m_iszSentence ), STRING( m_iszEntity ) ); } else { - //ALERT( at_console, "%s: can't find monster %s\n", STRING( m_iszSentence ), STRING( m_iszEntity ) ); + //ALERT( at_console, "%s: can't find target %s\n", STRING( m_iszSentence ), STRING( m_iszEntity ) ); pev->nextthink = gpGlobals->time + m_flRepeat + 0.5f; } } @@ -1062,45 +1062,57 @@ void CScriptedSentence::DelayThink( void ) SetThink( &CScriptedSentence::FindThink ); } -BOOL CScriptedSentence::AcceptableSpeaker( CBaseMonster *pMonster ) +BOOL CScriptedSentence::AcceptableSpeaker( CBaseToggle *pTarget ) { - if( pMonster ) + CBaseMonster *pMonster; + EHANDLE hTarget; + + if( pTarget ) { - if( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) + hTarget = pTarget->MyMonsterPointer(); + + if( hTarget != 0 ) { - if( pMonster->m_hTargetEnt == 0 || !pMonster->m_hTargetEnt->IsPlayer() ) - return FALSE; + CBaseMonster *pMonster = (CBaseMonster*)( (CBaseEntity*)hTarget ); + if( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) + { + if( pMonster->m_hTargetEnt == 0 || !pMonster->m_hTargetEnt->IsPlayer() ) + return FALSE; + } + + BOOL override; + + if( pev->spawnflags & SF_SENTENCE_INTERRUPT ) + override = TRUE; + else + override = FALSE; + + if( pMonster->CanPlaySentence( override ) ) + return TRUE; } - - BOOL override; - - if( pev->spawnflags & SF_SENTENCE_INTERRUPT ) - override = TRUE; else - override = FALSE; - - if( pMonster->CanPlaySentence( override ) ) - return TRUE; + return pTarget->IsAllowedToSpeak(); } + return FALSE; } -CBaseMonster *CScriptedSentence::FindEntity( void ) +CBaseToggle *CScriptedSentence::FindEntity( void ) { edict_t *pentTarget; - CBaseMonster *pMonster; + CBaseToggle *pTarget; pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING( m_iszEntity ) ); - pMonster = NULL; + pTarget = NULL; while( !FNullEnt( pentTarget ) ) { - pMonster = GetMonsterPointer( pentTarget ); - if( pMonster != NULL ) + pTarget = (CBaseToggle*)CBaseEntity::Instance( pentTarget ); + if( pTarget != NULL ) { - if( AcceptableSpeaker( pMonster ) ) - return pMonster; - //ALERT( at_console, "%s (%s), not acceptable\n", STRING( pMonster->pev->classname ), STRING( pMonster->pev->targetname ) ); + if( AcceptableSpeaker( pTarget ) ) + return pTarget; + //ALERT( at_console, "%s (%s), not acceptable\n", STRING( pTarget->pev->classname ), STRING( pTarget->pev->targetname ) ); } pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING( m_iszEntity ) ); } @@ -1112,9 +1124,9 @@ CBaseMonster *CScriptedSentence::FindEntity( void ) { if( FBitSet( pEntity->pev->flags, FL_MONSTER ) ) { - pMonster = pEntity->MyMonsterPointer(); - if( AcceptableSpeaker( pMonster ) ) - return pMonster; + pTarget = pEntity->MyTogglePointer(); + if( AcceptableSpeaker( pTarget ) ) + return pTarget; } } } @@ -1122,7 +1134,7 @@ CBaseMonster *CScriptedSentence::FindEntity( void ) return NULL; } -BOOL CScriptedSentence::StartSentence( CBaseMonster *pTarget ) +BOOL CScriptedSentence::StartSentence( CBaseToggle *pTarget ) { if( !pTarget ) { diff --git a/dlls/subs.cpp b/dlls/subs.cpp index 118554d4..9cdb6010 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -520,6 +520,27 @@ float CBaseToggle::AxisDelta( int flags, const Vector &angle1, const Vector &ang return angle1.y - angle2.y; } +void CBaseToggle::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) +{ + if( pszSentence && IsAllowedToSpeak()) + { + if( pszSentence[0] == '!' ) + EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, PITCH_NORM ); + else + SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, PITCH_NORM ); + } +} + +void CBaseToggle::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) +{ + PlaySentence( pszSentence, duration, volume, attenuation ); +} + +void CBaseToggle::SentenceStop( void ) +{ + EMIT_SOUND( edict(), CHAN_VOICE, "common/null.wav", 1.0, ATTN_IDLE ); +} + /* ============= FEntIsVisible From b91043602e8cba48b8743f67ad935e3e59a6767c Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sun, 4 Feb 2024 05:26:45 +0500 Subject: [PATCH 22/42] Don't stuck on level transitions. --- pm_shared/pm_shared.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index 32585d6a..dec69184 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -1699,7 +1699,7 @@ int PM_CheckStuck( void ) // // Deal with precision error in network. // - if( !pmove->server ) + if( !( pmove->server && pmove->multiplayer )) { // World or BSP model if( ( hitent == 0 ) || ( pmove->physents[hitent].model != NULL ) ) From 28112bab77c40bbea88be9f16d13e85a07520230 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:46:45 +0500 Subject: [PATCH 23/42] Fix bullet impact sounds and interpolation artifacts. --- cl_dll/ev_hldm.cpp | 4 +++- common/const.h | 3 ++- dlls/client.cpp | 12 ++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 381ee25b..7ece6ad2 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -99,6 +99,7 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v int cnt; float fattn = ATTN_NORM; int entity; + cl_entity_t *ent; char *pTextureName; char texname[64]; char szbuffer[64]; @@ -110,7 +111,8 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v chTextureType = 0; // Player - if( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) + if( entity >= 1 && entity <= gEngfuncs.GetMaxClients() + || ( ( ent = gEngfuncs.GetEntityByIndex( entity )) && ( ent->curstate.eflags & EFLAG_MONSTER ))) { // hit body chTextureType = CHAR_TEX_FLESH; diff --git a/common/const.h b/common/const.h index 3708371b..5b7e1737 100644 --- a/common/const.h +++ b/common/const.h @@ -127,7 +127,8 @@ // entity flags #define EFLAG_SLERP 1 // do studio interpolation of this entity - +#define EFLAG_MONSTER 2 + // // temp entity events // diff --git a/dlls/client.cpp b/dlls/client.cpp index 3ce82cfb..4e269eae 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -1123,6 +1123,7 @@ we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) { int i; + CBaseEntity *Entity; // don't send if flagged for NODRAW and it's not the host getting the message if( ( ent->v.effects & EF_NODRAW ) && ( ent != host ) ) @@ -1308,6 +1309,17 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h state->health = (int)ent->v.health; } + if( ( Entity = CBaseEntity::Instance( ent )) + && Entity->Classify() != CLASS_NONE + && Entity->Classify() != CLASS_MACHINE ) + { + SetBits( state->eflags, EFLAG_MONSTER ); + } + else + { + ClearBits( state->eflags, EFLAG_SLERP | EFLAG_MONSTER ); + } + return 1; } From 130a6aad6a8ce6986a6c2225314d4735b2033278 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 10 Feb 2024 00:45:10 +0500 Subject: [PATCH 24/42] Fix error message if LTO does not available. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04cf5bce..4396dfec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,7 @@ check_ipo_supported(RESULT HAVE_LTO OUTPUT LTO_ERROR) if(HAVE_LTO) message(STATUS "IPO / LTO enabled") else() - message(STATUS "IPO / LTO not supported: <${LTO_ERROR}>") + message(STATUS "IPO / LTO not supported: ${LTO_ERROR}") endif() check_include_file("tgmath.h" HAVE_TGMATH_H) From b8845fa4c85dd82734cad7a126e767d2b4618d7c Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 10 Feb 2024 04:42:33 +0500 Subject: [PATCH 25/42] Revert "cmake: set -O3 option to android linker." This reverts commit b8e143f5acd5cce9e752b4a620779f8c8aedc398. --- cl_dll/CMakeLists.txt | 1 - dlls/CMakeLists.txt | 1 - 2 files changed, 2 deletions(-) diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index 9375de27..f1dce6bf 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -45,7 +45,6 @@ if(NOT MSVC) add_compile_options(-funsafe-math-optimizations) # GCC/Clang flag if(CMAKE_SYSTEM_NAME STREQUAL "Android") add_compile_options(-O3 -DNDEBUG) # gradle compiles release builds with RelWithDebInfo(-O2 -g) and strips debug symbols. - target_link_options(${CLDLL_LIBRARY} PUBLIC "LINKER:-O3") endif() endif() else() diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index 9c518d39..ca69e13d 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -41,7 +41,6 @@ if(NOT MSVC) add_compile_options(-funsafe-math-optimizations) # GCC/Clang flag if(CMAKE_SYSTEM_NAME STREQUAL "Android") add_compile_options(-O3 -DNDEBUG) # gradle compiles release builds with RelWithDebInfo(-O2 -g) and strips debug symbols. - target_link_options(${SVDLL_LIBRARY} PUBLIC "LINKER:-O3") endif() endif() else() From fd3755e35cfbdb3de8727cf25679396d039a447c Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 10 Feb 2024 04:48:38 +0500 Subject: [PATCH 26/42] Remove additional android compilation flags. --- cl_dll/CMakeLists.txt | 3 --- dlls/CMakeLists.txt | 3 --- 2 files changed, 6 deletions(-) diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index f1dce6bf..37c03d7c 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -43,9 +43,6 @@ if(NOT MSVC) add_compile_options(-fomit-frame-pointer) # GCC/Clang flag add_compile_options(-ftree-vectorize) # GCC/Clang flag add_compile_options(-funsafe-math-optimizations) # GCC/Clang flag - if(CMAKE_SYSTEM_NAME STREQUAL "Android") - add_compile_options(-O3 -DNDEBUG) # gradle compiles release builds with RelWithDebInfo(-O2 -g) and strips debug symbols. - endif() endif() else() add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index ca69e13d..b78706c5 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -39,9 +39,6 @@ if(NOT MSVC) add_compile_options(-fomit-frame-pointer) # GCC/Clang flag add_compile_options(-ftree-vectorize) # GCC/Clang flag add_compile_options(-funsafe-math-optimizations) # GCC/Clang flag - if(CMAKE_SYSTEM_NAME STREQUAL "Android") - add_compile_options(-O3 -DNDEBUG) # gradle compiles release builds with RelWithDebInfo(-O2 -g) and strips debug symbols. - endif() endif() else() add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) From 49edef9257f2239c1fed1dbbbad21aee7ad975fe Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Sat, 10 Feb 2024 04:53:43 +0500 Subject: [PATCH 27/42] Make LTO is optional. --- CMakeLists.txt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4396dfec..19f76e64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ option(USE_NOVGUI_SCOREBOARD "Prefer non-VGUI Scoreboard when USE_VGUI is enable option(USE_VOICEMGR "Enable VOICE MANAGER." OFF) option(BUILD_CLIENT "Build client dll" ON) option(BUILD_SERVER "Build server dll" ON) +option(LTO "Enable interprocedural optimization" OFF) option(POLLY "Enable pollyhedral optimization" OFF) if(CMAKE_SIZEOF_VOID_P EQUAL 4 OR @@ -153,11 +154,13 @@ if(VITA) add_compile_options(-fno-use-cxa-atexit) endif() -check_ipo_supported(RESULT HAVE_LTO OUTPUT LTO_ERROR) -if(HAVE_LTO) - message(STATUS "IPO / LTO enabled") -else() - message(STATUS "IPO / LTO not supported: ${LTO_ERROR}") +if(LTO) + check_ipo_supported(RESULT HAVE_LTO OUTPUT LTO_ERROR) + if(HAVE_LTO) + message(STATUS "IPO / LTO enabled") + else() + message(STATUS "IPO / LTO not supported: ${LTO_ERROR}") + endif() endif() check_include_file("tgmath.h" HAVE_TGMATH_H) From a23889423154cd98fcb6c5fd28a0d8796b5ba61b Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Mon, 5 Feb 2024 03:57:11 +0300 Subject: [PATCH 28/42] Remove linuxunkabi library suffix, as engine doesn't use it anymore --- cmake/LibraryNaming.cmake | 3 --- public/build.h | 8 -------- scripts/waifulib/library_naming.py | 3 --- 3 files changed, 14 deletions(-) diff --git a/cmake/LibraryNaming.cmake b/cmake/LibraryNaming.cmake index 724349bd..d71919fa 100644 --- a/cmake/LibraryNaming.cmake +++ b/cmake/LibraryNaming.cmake @@ -54,7 +54,6 @@ check_group_build_target(XASH_SERENITY XASH_PLATFORM) check_group_build_target(XASH_IRIX XASH_PLATFORM) check_group_build_target(XASH_NSWITCH XASH_PLATFORM) check_group_build_target(XASH_PSVITA XASH_PLATFORM) -check_group_build_target(XASH_LINUX_UNKNOWN XASH_PLATFORM) check_group_build_target(XASH_X86 XASH_ARCHITECTURE) check_group_build_target(XASH_AMD64 XASH_ARCHITECTURE) check_group_build_target(XASH_ARM XASH_ARCHITECTURE) @@ -84,8 +83,6 @@ unset(CMAKE_REQUIRED_INCLUDES) # engine/common/build.c if(XASH_ANDROID) set(BUILDOS "android") -elseif(XASH_LINUX_UNKNOWN) - set(BUILDOS "linuxunkabi") elseif(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE) set(BUILDOS "") # no prefix for default OS elseif(XASH_FREEBSD) diff --git a/public/build.h b/public/build.h index 2f8fffae..851939b5 100644 --- a/public/build.h +++ b/public/build.h @@ -69,7 +69,6 @@ Then you can use another oneliner to query all variables: #undef XASH_IRIX #undef XASH_JS #undef XASH_LINUX -#undef XASH_LINUX_UNKNOWN #undef XASH_LITTLE_ENDIAN #undef XASH_MIPS #undef XASH_MOBILE_PLATFORM @@ -103,13 +102,6 @@ Then you can use another oneliner to query all variables: #if defined __linux__ #if defined __ANDROID__ #define XASH_ANDROID 1 - #else - #include - // if our system libc has features.h header - // try to detect it to not confuse other libcs with built with glibc game libraries - #if !defined __GLIBC__ - #define XASH_LINUX_UNKNOWN 1 - #endif #endif #define XASH_LINUX 1 #elif defined __FreeBSD__ diff --git a/scripts/waifulib/library_naming.py b/scripts/waifulib/library_naming.py index 4369b3b6..ac2faf6f 100644 --- a/scripts/waifulib/library_naming.py +++ b/scripts/waifulib/library_naming.py @@ -44,7 +44,6 @@ DEFINES = [ 'XASH_IRIX', 'XASH_JS', 'XASH_LINUX', -'XASH_LINUX_UNKNOWN', 'XASH_LITTLE_ENDIAN', 'XASH_MIPS', 'XASH_MOBILE_PLATFORM', @@ -76,8 +75,6 @@ def configure(conf): # engine/common/build.c if conf.env.XASH_ANDROID: buildos = "android" - elif conf.env.XASH_LINUX_UNKNOWN: - buildos = "linuxunkabi" elif conf.env.XASH_WIN32 or conf.env.XASH_LINUX or conf.env.XASH_APPLE: buildos = "" # no prefix for default OS elif conf.env.XASH_FREEBSD: From 011f1afeb6a0755aa6d769da3403e2ba87b2275d Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Sat, 10 Feb 2024 04:08:13 +0300 Subject: [PATCH 29/42] client: fix -Wparentheses --- cl_dll/ev_hldm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 7ece6ad2..2e6b4932 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -111,7 +111,7 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v chTextureType = 0; // Player - if( entity >= 1 && entity <= gEngfuncs.GetMaxClients() + if( ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() ) || ( ( ent = gEngfuncs.GetEntityByIndex( entity )) && ( ent->curstate.eflags & EFLAG_MONSTER ))) { // hit body From 955f7ad4367c32eb6f2985daeccef08577d54822 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Tue, 13 Feb 2024 03:41:13 +0500 Subject: [PATCH 30/42] Port spectator changes from HLSDK 2.4. --- cl_dll/Android.mk | 1 + cl_dll/CMakeLists.txt | 1 + cl_dll/compile.bat | 1 + cl_dll/hud_redraw.cpp | 5 + cl_dll/hud_spectator.cpp | 371 ++++++++++++++++++++++++++++++++---- cl_dll/hud_spectator.h | 30 ++- cl_dll/interpolation.cpp | 217 +++++++++++++++++++++ cl_dll/interpolation.h | 52 +++++ cl_dll/view.cpp | 2 + common/hltv.h | 17 +- contrib/iZarif/premake5.lua | 1 + 11 files changed, 657 insertions(+), 41 deletions(-) create mode 100644 cl_dll/interpolation.cpp create mode 100644 cl_dll/interpolation.h diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index 9cb79970..9b4974ce 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -70,6 +70,7 @@ SRCS+=./in_camera.cpp SRCS+=./input.cpp SRCS+=./input_goldsource.cpp SRCS+=./input_mouse.cpp +SRCS+=./interpolation.cpp #SRCS+=./inputw32.cpp SRCS+=./menu.cpp SRCS+=./message.cpp diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index 37c03d7c..f6ecbb9f 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -107,6 +107,7 @@ set (CLDLL_SOURCES input_goldsource.cpp input_mouse.cpp input_xash3d.cpp + interpolation.cpp menu.cpp message.cpp parsemsg.cpp diff --git a/cl_dll/compile.bat b/cl_dll/compile.bat index 720d1e3f..b7085545 100644 --- a/cl_dll/compile.bat +++ b/cl_dll/compile.bat @@ -52,6 +52,7 @@ set SOURCES=../dlls/crossbow.cpp ^ input_goldsource.cpp ^ input_mouse.cpp ^ input_xash3d.cpp ^ + interpolation.cpp ^ menu.cpp ^ message.cpp ^ parsemsg.cpp ^ diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp index 64e24e1c..59366208 100644 --- a/cl_dll/hud_redraw.cpp +++ b/cl_dll/hud_redraw.cpp @@ -87,6 +87,11 @@ void CHud::Think( void ) // only let players adjust up in fov, and only if they are not overriden by something else m_iFOV = Q_max( default_fov->value, 90 ); } + + if( gEngfuncs.IsSpectateOnly() ) + { + m_iFOV = gHUD.m_Spectator.GetFOV(); // default_fov->value; + } } // Redraw diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp index 7e115f51..8e03579b 100644 --- a/cl_dll/hud_spectator.cpp +++ b/cl_dll/hud_spectator.cpp @@ -37,8 +37,6 @@ extern "C" float vJumpAngles[3]; extern void V_GetInEyePos( int entity, float * origin, float * angles ); extern void V_ResetChaseCam(); extern void V_GetChasePos( int target, float * cl_angles, float * origin, float * angles ); -extern void VectorAngles( const float *forward, float *angles ); -extern "C" void NormalizeAngles( float *angles ); extern float * GetClientColor( int clientIndex ); extern vec3_t v_origin; // last view origin @@ -46,6 +44,37 @@ extern vec3_t v_angles; // last view angle extern vec3_t v_cl_angles; // last client/mouse angle extern vec3_t v_sim_org; // last sim origin +#if 0 +const char *GetSpectatorLabel( int iMode ) +{ + switch( iMode ) + { + case OBS_CHASE_LOCKED: + return "#OBS_CHASE_LOCKED"; + + case OBS_CHASE_FREE: + return "#OBS_CHASE_FREE"; + + case OBS_ROAMING: + return "#OBS_ROAMING"; + + case OBS_IN_EYE: + return "#OBS_IN_EYE"; + + case OBS_MAP_FREE: + return "#OBS_MAP_FREE"; + + case OBS_MAP_CHASE: + return "#OBS_MAP_CHASE"; + + case OBS_NONE: + default: + return "#OBS_NONE"; + } +} + +#endif + void SpectatorMode( void ) { if( gEngfuncs.Cmd_Argc() <= 1 ) @@ -152,6 +181,7 @@ int CHudSpectator::Init() m_flNextObserverInput = 0.0f; m_zoomDelta = 0.0f; m_moveDelta = 0.0f; + m_FOV = 90.0f; m_chatEnabled = ( gHUD.m_SayText.m_HUD_saytext->value != 0 ); iJumpSpectator = 0; @@ -363,6 +393,178 @@ void CHudSpectator::SetSpectatorStartPosition() iJumpSpectator = 1; // jump anyway } +void CHudSpectator::SetCameraView( vec3_t pos, vec3_t angle, float fov ) +{ + m_FOV = fov; + VectorCopy( pos, vJumpOrigin ); + VectorCopy( angle, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; // jump anyway +} + +void CHudSpectator::AddWaypoint( float time, vec3_t pos, vec3_t angle, float fov, int flags ) +{ + if( flags == 0 && time == 0.0f ) + { + // switch instantly to this camera view + SetCameraView( pos, angle, fov ); + return; + } + + if( m_NumWayPoints >= MAX_CAM_WAYPOINTS ) + { + gEngfuncs.Con_Printf( "Too many camera waypoints!\n" ); + return; + } + + VectorCopy( angle, m_CamPath[m_NumWayPoints].angle ); + VectorCopy( pos, m_CamPath[m_NumWayPoints].position ); + m_CamPath[m_NumWayPoints].flags = flags; + m_CamPath[m_NumWayPoints].fov = fov; + m_CamPath[m_NumWayPoints].time = time; + + gEngfuncs.Con_DPrintf( "Added waypoint %i\n", m_NumWayPoints ); + + m_NumWayPoints++; +} + +void CHudSpectator::SetWayInterpolation( cameraWayPoint_t *prev, cameraWayPoint_t *start, cameraWayPoint_t *end, cameraWayPoint_t *next ) +{ + m_WayInterpolation.SetViewAngles( start->angle, end->angle ); + + m_WayInterpolation.SetFOVs( start->fov, end->fov ); + + m_WayInterpolation.SetSmoothing( ( start->flags & DRC_FLAG_SLOWSTART ) != 0, + ( start->flags & DRC_FLAG_SLOWEND ) != 0 ); + + if( prev && next ) + { + m_WayInterpolation.SetWaypoints( &prev->position, start->position, end->position, &next->position ); + } + else if( prev ) + { + m_WayInterpolation.SetWaypoints( &prev->position, start->position, end->position, NULL ); + } + else if( next ) + { + m_WayInterpolation.SetWaypoints( NULL, start->position, end->position, &next->position ); + } + else + { + m_WayInterpolation.SetWaypoints( NULL, start->position, end->position, NULL ); + } +} + +bool CHudSpectator::GetDirectorCamera( vec3_t &position, vec3_t &angle ) +{ + float now = gHUD.m_flTime; + float fov = 90.0f; + + if( m_ChaseEntity ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_ChaseEntity ); + + if( ent ) + { + vec3_t vt = ent->curstate.origin; + + if( m_ChaseEntity <= gEngfuncs.GetMaxClients()) + { + if( ent->curstate.solid == SOLID_NOT ) + { + vt[2]+= -8 ; // PM_DEAD_VIEWHEIGHT + } + else if( ent->curstate.usehull == 1 ) + { + vt[2]+= 12; // VEC_DUCK_VIEW; + } + else + { + vt[2]+= 28; // DEFAULT_VIEWHEIGHT + } + } + + vt = vt - position; + VectorAngles( vt, angle ); + angle[0] = -angle[0]; + return true; + } + else + { + return false; + } + } + + if( !m_IsInterpolating ) + return false; + + if( m_WayPoint < 0 || m_WayPoint >= ( m_NumWayPoints - 1 )) + return false; + + cameraWayPoint_t *wp1 = &m_CamPath[m_WayPoint]; + cameraWayPoint_t *wp2 = &m_CamPath[m_WayPoint+1]; + + if( now < wp1->time ) + return false; + + while( now > wp2->time ) + { + // go to next waypoint, if possible + m_WayPoint++; + + if( m_WayPoint >= ( m_NumWayPoints - 1 )) + { + m_IsInterpolating = false; + return false; // there is no following waypoint + } + + wp1 = wp2; + wp2 = &m_CamPath[m_WayPoint + 1]; + + if( m_WayPoint > 0 ) + { + // we have a predecessor + + if( m_WayPoint < ( m_NumWayPoints - 1 )) + { + // we have also a successor + SetWayInterpolation( &m_CamPath[m_WayPoint - 1], wp1, wp2, &m_CamPath[m_WayPoint + 2] ); + } + else + { + SetWayInterpolation( &m_CamPath[m_WayPoint - 1], wp1, wp2, NULL ); + } + } + else if( m_WayPoint < ( m_NumWayPoints - 1 )) + { + // we only have a successor + SetWayInterpolation( NULL, wp1, wp2, &m_CamPath[m_WayPoint + 2] ); + } + else + { + // we have only two waypoints + SetWayInterpolation( NULL, wp1, wp2, NULL ); + } + } + + if( wp2->time <= wp1->time ) + return false; + + float fraction = ( now - wp1->time ) / ( wp2->time - wp1->time ); + + if( fraction < 0.0f ) + fraction = 0.0f; + else if( fraction > 1.0f ) + fraction = 1.0f; + + m_WayInterpolation.Interpolate( fraction, position, angle, &fov ); + + // gEngfuncs.Con_Printf( "Interpolate time: %.2f, fraction %.2f, point : %.2f,%.2f,%.2f\n", now, fraction, position[0], position[1], position[2] ); + + SetCameraView( position, angle, fov ); + + return true; +} //----------------------------------------------------------------------------- // Purpose: Loads new icons //----------------------------------------------------------------------------- @@ -377,9 +579,21 @@ int CHudSpectator::VidInit() m_hsprCamera = SPR_Load( "sprites/camera.spr" ); m_hCrosshair = SPR_Load( "sprites/crosshairs.spr" ); + m_lastPrimaryObject = m_lastSecondaryObject = 0; + m_flNextObserverInput = 0.0f; + m_lastHudMessage = 0; + m_iSpectatorNumber = 0; + iJumpSpectator = 0; + g_iUser1 = g_iUser2 = 0; + return 1; } +float CHudSpectator::GetFOV( void ) +{ + return m_FOV; +} + //----------------------------------------------------------------------------- // Purpose: // Input : flTime - @@ -427,8 +641,11 @@ int CHudSpectator::Draw( float flTime ) return 1; // make sure we have player info +#if USE_VGUI + gViewPort->GetAllPlayersInfo(); +#else gHUD.GetAllPlayersInfo(); - +#endif // loop through all the players and draw additional infos to their sprites on the map for( int i = 0; i < MAX_PLAYERS; i++ ) { @@ -461,8 +678,10 @@ int CHudSpectator::Draw( float flTime ) void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) { - float value; + float f1, f2; char *string; + vec3_t v1, v2; + int i1, i2, i3; BEGIN_READ( pbuf, iSize ); @@ -479,7 +698,7 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) gHUD.MsgFunc_InitHUD( NULL, 0, NULL ); gHUD.MsgFunc_ResetHUD( NULL, 0, NULL ); break; - case DRC_CMD_EVENT: + case DRC_CMD_EVENT: // old director style message m_lastPrimaryObject = READ_WORD(); m_lastSecondaryObject = READ_WORD(); m_iObserverFlags = READ_LONG(); @@ -502,19 +721,22 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) } break; case DRC_CMD_CAMERA: + v1[0] = READ_COORD(); // position + v1[1] = READ_COORD(); + v1[2] = READ_COORD(); // vJumpOrigin + + v1[0] = READ_COORD(); // view angle + v1[1] = READ_COORD(); // vJumpAngles + v1[2] = READ_COORD(); + + f1 = READ_BYTE(); // fov + i1 = READ_WORD(); // target + if( m_autoDirector->value ) { - vJumpOrigin[0] = READ_COORD(); // position - vJumpOrigin[1] = READ_COORD(); - vJumpOrigin[2] = READ_COORD(); - - vJumpAngles[0] = READ_COORD(); // view angle - vJumpAngles[1] = READ_COORD(); - vJumpAngles[2] = READ_COORD(); - - gEngfuncs.SetViewAngles( vJumpAngles ); - - iJumpSpectator = 1; + SetModes( OBS_ROAMING, -1 ); + SetCameraView( v1, v2, f1 ); + m_ChaseEntity = i1; } break; case DRC_CMD_MESSAGE: @@ -551,13 +773,13 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) break; case DRC_CMD_SOUND: string = READ_STRING(); - value = READ_FLOAT(); + f1 = READ_FLOAT(); - // gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, value ); - gEngfuncs.pEventAPI->EV_PlaySound( 0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); + // gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, f1 ); + gEngfuncs.pEventAPI->EV_PlaySound( 0, v_origin, CHAN_BODY, string, f1, ATTN_NORM, 0, PITCH_NORM ); break; case DRC_CMD_TIMESCALE: - value = READ_FLOAT(); + f1 = READ_FLOAT(); break; case DRC_CMD_STATUS: READ_LONG(); // total number of spectator slots @@ -574,13 +796,71 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) gViewPort->UpdateSpectatorPanel(); #endif break; - case DRC_CMD_FADE: - break; case DRC_CMD_STUFFTEXT: gEngfuncs.pfnFilteredClientCmd( READ_STRING() ); break; + case DRC_CMD_CAMPATH: + v1[0] = READ_COORD(); // position + v1[1] = READ_COORD(); + v1[2] = READ_COORD(); // vJumpOrigin + + v2[0] = READ_COORD(); // view angle + v2[1] = READ_COORD(); // vJumpAngles + v2[2] = READ_COORD(); + f1 = READ_BYTE(); // FOV + i1 = READ_BYTE(); // flags + + if( m_autoDirector->value ) + { + SetModes( OBS_ROAMING, -1 ); + SetCameraView( v1, v2, f1 ); + } + break; + case DRC_CMD_WAYPOINTS: + i1 = READ_BYTE(); + m_NumWayPoints = 0; + m_WayPoint = 0; + for( i2 = 0; i2 < i1; i2++ ) + { + f1 = gHUD.m_flTime + (float)( READ_SHORT()) / 100.0f; + + v1[0] = READ_COORD(); // position + v1[1] = READ_COORD(); + v1[2] = READ_COORD(); // vJumpOrigin + + v2[0] = READ_COORD(); // view angle + v2[1] = READ_COORD(); // vJumpAngles + v2[2] = READ_COORD(); + f2 = READ_BYTE(); // fov + i3 = READ_BYTE(); // flags + + AddWaypoint( f1, v1, v2, f2, i3 ); + } + + // gEngfuncs.Con_Printf( "CHudSpectator::DirectorMessage: waypoints %i.\n", m_NumWayPoints ); + if( !m_autoDirector->value ) + { + // ignore waypoints + m_NumWayPoints = 0; + break; + } + + SetModes( OBS_ROAMING, -1 ); + + m_IsInterpolating = true; + + if( m_NumWayPoints > 2 ) + { + SetWayInterpolation( NULL, &m_CamPath[0], &m_CamPath[1], &m_CamPath[2] ); + } + else + { + SetWayInterpolation( NULL, &m_CamPath[0], &m_CamPath[1], NULL ); + } + break; default: gEngfuncs.Con_DPrintf( "CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); + break; } } @@ -595,9 +875,10 @@ void CHudSpectator::FindNextPlayer( bool bReverse ) // if we are NOT in HLTV mode, spectator targets are set on server if( !gEngfuncs.IsSpectateOnly() ) { - char cmdstring[32]; + char cmdstring[256]; // forward command to server - sprintf( cmdstring, "follownext %i", bReverse ? 1 : 0 ); + _snprintf( cmdstring, sizeof( cmdstring ) - 1,"follownext %i", bReverse ? 1 : 0 ); + cmdstring[sizeof( cmdstring ) - 1] = '\0'; gEngfuncs.pfnServerCmd( cmdstring ); return; } @@ -614,8 +895,11 @@ void CHudSpectator::FindNextPlayer( bool bReverse ) int iDir = bReverse ? -1 : 1; // make sure we have player info +#if USE_VGUI + gViewPort->GetAllPlayersInfo(); +#else gHUD.GetAllPlayersInfo(); - +#endif do { iCurrent += iDir; @@ -656,7 +940,7 @@ void CHudSpectator::FindNextPlayer( bool bReverse ) #endif } -void CHudSpectator::FindPlayer(const char *name) +void CHudSpectator::FindPlayer( const char *name ) { // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching // only a subset of the players. e.g. Make it check the target's team. @@ -664,18 +948,22 @@ void CHudSpectator::FindPlayer(const char *name) // if we are NOT in HLTV mode, spectator targets are set on server if ( !gEngfuncs.IsSpectateOnly() ) { - char cmdstring[32]; + char cmdstring[256]; // forward command to server - sprintf(cmdstring,"follow %s",name); - gEngfuncs.pfnServerCmd(cmdstring); + _snprintf( cmdstring, sizeof( cmdstring ) - 1, "follow %s", name ); + cmdstring[sizeof( cmdstring ) - 1] = '\0'; + gEngfuncs.pfnServerCmd( cmdstring ); return; } g_iUser2 = 0; // make sure we have player info +#if USE_VGUI + gViewPort->GetAllPlayersInfo(); +#else gHUD.GetAllPlayersInfo(); - +#endif cl_entity_t * pEnt = NULL; for (int i = 1; i < MAX_PLAYERS; i++ ) @@ -847,12 +1135,20 @@ void CHudSpectator::SetModes( int iNewMainMode, int iNewInsetMode ) return; } - // main modes ettings will override inset window settings + m_IsInterpolating = false; + m_ChaseEntity = 0; + + // main modes settings will override inset window settings if( iNewMainMode != g_iUser1 ) { // if we are NOT in HLTV mode, main spectator mode is set on server if( !gEngfuncs.IsSpectateOnly() ) { + char cmdstring[256]; + // forward command to server + _snprintf( cmdstring, sizeof( cmdstring ) - 1,"specmode %i", iNewMainMode ); + cmdstring[sizeof( cmdstring ) - 1] = '\0'; + gEngfuncs.pfnServerCmd( cmdstring ); return; } @@ -1548,8 +1844,9 @@ void CHudSpectator::CheckSettings() if( gEngfuncs.IsSpectateOnly() ) { // tell proxy our new chat mode - char chatcmd[32]; - sprintf( chatcmd, "ignoremsg %i", m_chatEnabled ? 0 : 1 ); + char chatcmd[256]; + _snprintf( chatcmd, sizeof( chatcmd ) - 1, "ignoremsg %i", m_chatEnabled ? 0 : 1 ); + chatcmd[sizeof( chatcmd ) - 1] = '\0'; gEngfuncs.pfnServerCmd( chatcmd ); } } @@ -1626,6 +1923,12 @@ void CHudSpectator::Reset() memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities) ); + m_FOV = 90.0f; + + m_IsInterpolating = false; + + m_ChaseEntity = 0; + SetSpectatorStartPosition(); } @@ -1648,7 +1951,7 @@ void CHudSpectator::InitHUDData() Reset(); - SetModes( OBS_CHASE_FREE, INSET_OFF ); + SetModes( OBS_CHASE_LOCKED, INSET_OFF ); g_iUser2 = 0; // fake not target until first camera command diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h index 800928e0..dc192141 100644 --- a/cl_dll/hud_spectator.h +++ b/cl_dll/hud_spectator.h @@ -10,6 +10,7 @@ #define HUD_SPECTATOR_H #include "cl_entity.h" +#include "interpolation.h" #define INSET_OFF 0 #define INSET_CHASE_FREE 1 @@ -22,6 +23,9 @@ #define OVERVIEW_TILE_SIZE 128 // don't change this #define OVERVIEW_MAX_LAYERS 1 +extern void VectorAngles( const float *forward, float *angles ); +extern "C" void NormalizeAngles( float *angles ); + //----------------------------------------------------------------------------- // Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it ) //----------------------------------------------------------------------------- @@ -49,7 +53,17 @@ typedef struct overviewEntity_s double killTime; } overviewEntity_t; +typedef struct cameraWayPoint_s +{ + float time; + vec3_t position; + vec3_t angle; + float fov; + int flags; +} cameraWayPoint_t; + #define MAX_OVERVIEW_ENTITIES 128 +#define MAX_CAM_WAYPOINTS 32 class CHudSpectator : public CHudBase { @@ -73,7 +87,7 @@ public: void HandleButtonsDown( int ButtonPressed ); void HandleButtonsUp( int ButtonPressed ); void FindNextPlayer( bool bReverse ); - void FindPlayer(const char *name); + void FindPlayer( const char *name ); void DirectorMessage( int iSize, void *pbuf ); void SetSpectatorStartPosition(); int Init(); @@ -81,6 +95,13 @@ public: int Draw( float flTime ); + void AddWaypoint( float time, vec3_t pos, vec3_t angle, float fov, int flags ); + void SetCameraView( vec3_t pos, vec3_t angle, float fov ); + float GetFOV(); + bool GetDirectorCamera( vec3_t &position, vec3_t &angle ); + void SetWayInterpolation( cameraWayPoint_t *prev, cameraWayPoint_t *start, cameraWayPoint_t *end, cameraWayPoint_t *next ); + + int m_iDrawCycle; client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; @@ -100,8 +121,13 @@ public: qboolean m_chatEnabled; + qboolean m_IsInterpolating; + int m_ChaseEntity; // if != 0, follow this entity with viewangles + int m_WayPoint; // current waypoint 1 + int m_NumWayPoints; // current number of waypoints vec3_t m_cameraOrigin; // a help camera vec3_t m_cameraAngles; // and it's angles + CInterpolation m_WayInterpolation; private: vec3_t m_vPlayerPos[MAX_PLAYERS]; @@ -119,9 +145,11 @@ private: struct model_s *m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame float m_flNextObserverInput; + float m_FOV; float m_zoomDelta; float m_moveDelta; int m_lastPrimaryObject; int m_lastSecondaryObject; + cameraWayPoint_t m_CamPath[MAX_CAM_WAYPOINTS]; }; #endif // SPECTATOR_H diff --git a/cl_dll/interpolation.cpp b/cl_dll/interpolation.cpp new file mode 100644 index 00000000..a06f7e29 --- /dev/null +++ b/cl_dll/interpolation.cpp @@ -0,0 +1,217 @@ +/************ (C) Copyright 2003 Valve, L.L.C. All rights reserved. *********** +** +** The copyright to the contents herein is the property of Valve, L.L.C. +** The contents may be used and/or copied only with the written permission of +** Valve, L.L.C., or in accordance with the terms and conditions stipulated in +** the agreement/contract under which the contents have been supplied. +** +******************************************************************************* +** +** Contents: +** +** interpolation.cpp: implementation of the interpolation class +** +******************************************************************************/ + +#include "hud.h" +#include "cl_util.h" +#include "interpolation.h" + +// = determinant of matrix a,b,c +#define Determinant( a, b, c ) ( (a)[2] * ( (b)[0]*(c)[1] - (b)[1]*(c)[0] ) + \ + (a)[1] * ( (b)[2]*(c)[0] - (b)[0]*(c)[2] ) + \ + (a)[0] * ( (b)[1]*(c)[2] - (b)[2]*(c)[1] ) ) + +// solve 3 vector linear system of equations v0 = x*v1 + y*v2 + z*v3 (if possible) +bool SolveLSE( vec3_t v0, vec3_t v1, vec3_t v2, vec3_t v3, float * x, float * y, float * z ) +{ + float d = Determinant( v1, v2, v3 ); + + if( d == 0.0f ) + return false; + + if( x ) + *x = Determinant( v0, v2, v3 ) / d; + + if( y ) + *y= Determinant( v1, v0, v3 ) / d; + + if( z ) + *z= Determinant( v1, v2, v0 ) / d; + + return true; +} + +// p = closest point between vector lines a1+x*m1 and a2+x*m2 +bool GetPointBetweenLines( vec3_t &p, vec3_t a1, vec3_t m1, vec3_t a2, vec3_t m2 ) +{ + float x, z; + + vec3_t t1 = CrossProduct( m1, m2 ); + vec3_t t2 = a2 - a1; + + if( !SolveLSE( t2, m1, t1, m2, &x , NULL, &z ) ) + return false; + + t1 = a1 + x * m1; + t2 = a2 + ( -z ) * m2; + + p = ( t1 + t2 ) / 2.0f; + + return true; +} + +// Bernstein Poynom B(u) with n = 2, i = 0 +#define BernsteinPolynom20(u) ( ( 1.0f - u ) * ( 1.0f - u )) +#define BernsteinPolynom21(u) ( 2.0f * u * ( 1.0f - u ) ) +#define BernsteinPolynom22(u) ( u * u ) + +CInterpolation::CInterpolation() +{ +} + +CInterpolation::~CInterpolation() +{ + m_SmoothStart = m_SmoothEnd = false; +} + +void CInterpolation::SetViewAngles( vec3_t start, vec3_t end ) +{ + m_StartAngle = start; + m_EndAngle = end; + NormalizeAngles( m_StartAngle ); + NormalizeAngles( m_EndAngle ); +} + +void CInterpolation::SetFOVs( float start, float end ) +{ + m_StartFov = start; + m_EndFov = end; +} + +void CInterpolation::SetWaypoints( vec3_t *prev, vec3_t start, vec3_t end, vec3_t *next ) +{ + m_StartPoint = start; + m_EndPoint = end; + + + vec3_t a, b, c, d; + + if( !prev && !next ) + { + // no direction given, straight linear interpolation + m_Center = ( m_StartPoint + m_EndPoint ) / 2.0f; + } + else if( !prev ) + { + a = start - end; + float dist = a.Length() / 2.0f; + a = a.Normalize(); + b = *next - end; + b = b.Normalize(); + c = a - b; + c = c.Normalize(); + m_Center = end + c * dist; + } + else if( !next ) + { + a = *prev - start; + a = a.Normalize(); + b = end - start; + float dist = b.Length() / 2.0f; + b = b.Normalize(); + c = b - a; + c = c.Normalize(); + m_Center = start + c * dist; + } + else + { + // we have a previous and a next point, great! + a = *prev - start; + a = a.Normalize(); + b = end - start; + b = b.Normalize(); + c = b - a; + + a = start - end; + a = a.Normalize(); + b = *next - end; + b = b.Normalize(); + d = a - b; + + GetPointBetweenLines( m_Center, start, c, end, d ); + } +} + +void CInterpolation::Interpolate( float t, vec3_t &point, vec3_t &angle, float *fov ) +{ + if( m_SmoothStart && m_SmoothEnd ) + { + t = ( 1.0f - t ) * ( t * t ) + t * ( 1.0f - ( ( t - 1.0f ) * ( t - 1.0f ))); + } + else if( m_SmoothStart ) + { + t = t * t; + } + else if( m_SmoothEnd ) + { + t = t - 1.0f; + t = -( t * t ) + 1; + } + + if( point ) + { + BezierInterpolatePoint( t, point ); + } + + if( angle ) + { + InterpolateAngle( t, angle ); + } + + if( fov ) + { + *fov = m_StartFov + ( t * ( m_EndFov - m_StartFov )); + } +} + +void CInterpolation::BezierInterpolatePoint( float t, vec3_t &point ) +{ + point = m_StartPoint * BernsteinPolynom20( t ); + point = point + m_Center * BernsteinPolynom21( t ); + point = point + m_EndPoint * BernsteinPolynom22( t ); +} + +void CInterpolation::SetSmoothing( bool start, bool end ) +{ + m_SmoothStart = start; + m_SmoothEnd = end; +} + +void CInterpolation::InterpolateAngle( float t, vec3_t &angle ) +{ + int i; + float ang1, ang2; + float d; + + for( i = 0; i < 3; i++ ) + { + ang1 = m_StartAngle[i]; + ang2 = m_EndAngle[i]; + + d = ang2 - ang1; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + angle[i] = ang1 + d * t; + } + + NormalizeAngles( angle ); +} + diff --git a/cl_dll/interpolation.h b/cl_dll/interpolation.h new file mode 100644 index 00000000..a0a3cd1b --- /dev/null +++ b/cl_dll/interpolation.h @@ -0,0 +1,52 @@ +/************ (C) Copyright 2003 Valve, L.L.C. All rights reserved. *********** +** +** The copyright to the contents herein is the property of Valve, L.L.C. +** The contents may be used and/or copied only with the written permission of +** Valve, L.L.C., or in accordance with the terms and conditions stipulated in +** the agreement/contract under which the contents have been supplied. +** +******************************************************************************* +** +** Contents: +** +** interpolation.h: Bezier inpolation classes +** +******************************************************************************/ + +#pragma once +#if !defined(INTERPOLATION_H) +#define INTERPOLATION_H + + +// interpolation class +class CInterpolation +{ +public: + CInterpolation(); + virtual ~CInterpolation(); + + void SetWaypoints( vec3_t *prev, vec3_t start, vec3_t end, vec3_t *next ); + void SetViewAngles( vec3_t start, vec3_t end ); + void SetFOVs( float start, float end ); + void SetSmoothing( bool start, bool end ); + + // get interpolated point 0 =< t =< 1, 0 = start, 1 = end + void Interpolate( float t, vec3_t &point, vec3_t &angle, float * fov ); + +protected: + void BezierInterpolatePoint( float t, vec3_t &point ); + void InterpolateAngle( float t, vec3_t &angle ); + + vec3_t m_StartPoint; + vec3_t m_EndPoint; + vec3_t m_StartAngle; + vec3_t m_EndAngle; + vec3_t m_Center; + float m_StartFov; + float m_EndFov; + + bool m_SmoothStart; + bool m_SmoothEnd; +}; + +#endif // INTERPOLATION_H diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index 4c93fb87..d9d61205 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -1462,6 +1462,8 @@ void V_CalcSpectatorRefdef( struct ref_params_s * pparams ) case OBS_ROAMING: VectorCopy( v_cl_angles, v_angles ); VectorCopy( v_sim_org, v_origin ); + // override values if director is active + gHUD.m_Spectator.GetDirectorCamera(v_origin, v_angles); break; case OBS_IN_EYE: V_CalcNormalRefdef( pparams ); diff --git a/common/hltv.h b/common/hltv.h index 970c4861..63393a18 100644 --- a/common/hltv.h +++ b/common/hltv.h @@ -37,11 +37,14 @@ #define DRC_CMD_SOUND 7 // plays a particular sound #define DRC_CMD_STATUS 8 // status info about broadcast #define DRC_CMD_BANNER 9 // banner file name for HLTV gui -#define DRC_CMD_FADE 10 // send screen fade command -#define DRC_CMD_SHAKE 11 // send screen shake command -#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command +#define DRC_CMD_STUFFTEXT 10 // like the normal svc_stufftext but as director command +#define DRC_CMD_CHASE 11 // chase a certain player +#define DRC_CMD_INEYE 12 // view player through own eyes +#define DRC_CMD_MAP 13 // show overview map +#define DRC_CMD_CAMPATH 14 // define camera waypoint +#define DRC_CMD_WAYPOINTS 15 // start moving camera, inetranl message -#define DRC_CMD_LAST 12 +#define DRC_CMD_LAST 15 // HLTV_EVENT event flags #define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) @@ -53,7 +56,9 @@ #define DRC_FLAG_FINAL (1<<9) // is a final scene #define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data -#define MAX_DIRECTOR_CMD_PARAMETERS 4 -#define MAX_DIRECTOR_CMD_STRING 128 +// DRC_CMD_WAYPOINT flags +#define DRC_FLAG_STARTPATH 1 // end with speed 0.0 +#define DRC_FLAG_SLOWSTART 2 // start with speed 0.0 +#define DRC_FLAG_SLOWEND 4 // end with speed 0.0 #endif//HLTV_H diff --git a/contrib/iZarif/premake5.lua b/contrib/iZarif/premake5.lua index d959d9ad..7ad931dd 100644 --- a/contrib/iZarif/premake5.lua +++ b/contrib/iZarif/premake5.lua @@ -270,6 +270,7 @@ files{"cl_dll/hl/hl_baseentity.cpp", "cl_dll/input_goldsource.cpp", "cl_dll/input_mouse.cpp", "cl_dll/input_xash3d.cpp", +"cl_dll/interpolation.cpp", "cl_dll/menu.cpp", "cl_dll/message.cpp", "cl_dll/overview.cpp", From 7bbc2cf4d72deb7ede395816910bc7de7f03f13d Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Tue, 13 Feb 2024 05:30:42 +0500 Subject: [PATCH 31/42] Update weapon bobbing code. --- cl_dll/view.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp index d9d61205..41389296 100644 --- a/cl_dll/view.cpp +++ b/cl_dll/view.cpp @@ -295,8 +295,11 @@ void V_CalcGunAngle( struct ref_params_s *pparams ) viewent->angles[PITCH] -= v_idlescale * sin( pparams->time * v_ipitch_cycle.value ) * ( v_ipitch_level.value * 0.5f ); viewent->angles[YAW] -= v_idlescale * sin( pparams->time * v_iyaw_cycle.value ) * v_iyaw_level.value; - VectorCopy( viewent->angles, viewent->curstate.angles ); - VectorCopy( viewent->angles, viewent->latched.prevangles ); + if( !( cl_viewbob && cl_viewbob->value )) + { + VectorCopy( viewent->angles, viewent->curstate.angles ); + VectorCopy( viewent->angles, viewent->latched.prevangles ); + } } /* @@ -575,6 +578,7 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams ) { VectorCopy( pparams->cl_viewangles, view->angles ); } + // set up gun position V_CalcGunAngle( pparams ); @@ -597,9 +601,6 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams ) view->angles[ROLL] -= bob * 1.0f; view->angles[PITCH] -= bob * 0.3f; - if( cl_viewbob && cl_viewbob->value ) - VectorCopy( view->angles, view->curstate.angles ); - // pushing the view origin down off of the same X/Z plane as the ent's origin will give the // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem // with view model distortion, this may be a cause. (SJB). @@ -768,6 +769,14 @@ void V_CalcNormalRefdef( struct ref_params_s *pparams ) } } + if( cl_viewbob && cl_viewbob->value ) + { + VectorCopy( view->origin, view->curstate.origin ); + VectorCopy( view->origin, view->latched.prevorigin ); + VectorCopy( view->angles, view->curstate.angles ); + VectorCopy( view->angles, view->latched.prevangles ); + } + lasttime = pparams->time; v_origin = pparams->vieworg; From c949e02e4eca3c30ca8536c5b3d2e5e6f9b838bd Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:42:37 +0500 Subject: [PATCH 32/42] Fix death animation loop. --- dlls/player.cpp | 14 +++++++------- dlls/world.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/player.cpp b/dlls/player.cpp index 04d161cc..2911363f 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -1296,7 +1296,7 @@ void CBasePlayer::PlayerDeathThink( void ) PackDeadPlayerItems(); } - if( pev->modelindex && ( !m_fSequenceFinished ) && ( pev->deadflag == DEAD_DYING ) ) + if( pev->modelindex && ( !m_fSequenceFinished ) && ( pev->deadflag == DEAD_DYING )) { StudioFrameAdvance(); @@ -1305,14 +1305,9 @@ void CBasePlayer::PlayerDeathThink( void ) return; } - // once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore - // this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn - if( pev->movetype != MOVETYPE_NONE && FBitSet( pev->flags, FL_ONGROUND ) ) - pev->movetype = MOVETYPE_NONE; - if( pev->deadflag == DEAD_DYING ) { - if( g_pGameRules->IsMultiplayer() && pev->movetype == MOVETYPE_NONE ) + if( g_pGameRules->IsMultiplayer() && m_fSequenceFinished && pev->movetype == MOVETYPE_NONE ) { CopyToBodyQue( pev ); pev->modelindex = 0; @@ -1320,6 +1315,11 @@ void CBasePlayer::PlayerDeathThink( void ) pev->deadflag = DEAD_DEAD; } + // once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore + // this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn + if( pev->movetype != MOVETYPE_NONE && FBitSet( pev->flags, FL_ONGROUND ) ) + pev->movetype = MOVETYPE_NONE; + StopAnimation(); pev->effects |= EF_NOINTERP; diff --git a/dlls/world.cpp b/dlls/world.cpp index 3f4bda0b..d96c10aa 100644 --- a/dlls/world.cpp +++ b/dlls/world.cpp @@ -226,7 +226,7 @@ static void InitBodyQue( void ) // void CopyToBodyQue( entvars_t *pev ) { - if( pev->effects & EF_NODRAW ) + if( ( pev->effects & EF_NODRAW ) || !pev->modelindex ) return; entvars_t *pevHead = VARS( g_pBodyQueueHead ); From d5a8a0d3a36144af8d5cd5bb5bb3d02c3f9e01bd Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Tue, 13 Feb 2024 20:44:58 +0500 Subject: [PATCH 33/42] Clear hitgroup for reflected gauss shots. --- dlls/gauss.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index a997c804..734950f4 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -430,6 +430,8 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) if( pEntity->pev->takedamage ) { ClearMultiDamage(); + if( pEntity->pev == m_pPlayer->pev ) + tr.iHitgroup = 0; pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); } From 835ce1df212f16ec57e2d37e90a70eedad7aab2b Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:57:13 +0500 Subject: [PATCH 34/42] cmake: add more checks for x86 CPU. --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 19f76e64..84897728 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,10 @@ if((WIN32 OR ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") OR CMAKE_SYSTEM_PROCESSOR STREQUAL "EM64T") AND NOT 64BIT) OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "X86" - OR CMAKE_SYSTEM_PROCESSOR STREQUAL "i386")) + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "i386" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "i486" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "i586" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "i686")) option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" ON) else() option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" OFF) From 1f458edb0be871e729a475228ba025583bd4ee52 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Tue, 13 Feb 2024 23:03:14 +0500 Subject: [PATCH 35/42] Turn on weapon bobbing by default. --- cl_dll/hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index f16e30b9..e82679bf 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -380,7 +380,7 @@ void CHud::Init( void ) m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); - cl_viewbob = CVAR_CREATE( "cl_viewbob", "0", FCVAR_ARCHIVE ); + cl_viewbob = CVAR_CREATE( "cl_viewbob", "1", FCVAR_ARCHIVE ); m_pSpriteList = NULL; From 738890287bb9e363631313fddb04403c8e675087 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Wed, 14 Feb 2024 04:14:02 +0500 Subject: [PATCH 36/42] Add kludge for Uplink's scientist model. --- dlls/scientist.cpp | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index 15acf989..7fb7bab5 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -29,6 +29,8 @@ #define NUM_SCIENTIST_HEADS 4 // four heads available for scientist model +static cvar_t *g_psv_override_scientist_mdl; + enum { HEAD_GLASSES = 0, @@ -113,6 +115,8 @@ public: CUSTOM_SCHEDULES private: + const char *GetScientistModel( void ); + float m_painTime; float m_healTime; float m_fearTime; @@ -422,6 +426,20 @@ void CScientist::DeclineFollowing( void ) PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); } +const char *CScientist::GetScientistModel( void ) +{ + if( !g_psv_override_scientist_mdl ) + g_psv_override_scientist_mdl = CVAR_GET_POINTER( "_sv_override_scientist_mdl" ); + + if( !( g_psv_override_scientist_mdl && g_psv_override_scientist_mdl->string )) + return "models/scientist.mdl"; + + if( strlen( g_psv_override_scientist_mdl->string ) < sizeof( "01.mdl" ) - 1 ) + return "models/scientist.mdl"; + + return g_psv_override_scientist_mdl->string; +} + void CScientist::Scream( void ) { if( FOkToSpeak() ) @@ -648,7 +666,7 @@ void CScientist::Spawn( void ) Precache(); - SET_MODEL( ENT( pev ), "models/scientist.mdl" ); + SET_MODEL( ENT( pev ), GetScientistModel()); UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); pev->solid = SOLID_SLIDEBOX; @@ -679,7 +697,7 @@ void CScientist::Spawn( void ) //========================================================= void CScientist::Precache( void ) { - PRECACHE_MODEL( "models/scientist.mdl" ); + PRECACHE_MODEL( GetScientistModel()); PRECACHE_SOUND( "scientist/sci_pain1.wav" ); PRECACHE_SOUND( "scientist/sci_pain2.wav" ); PRECACHE_SOUND( "scientist/sci_pain3.wav" ); @@ -1097,6 +1115,9 @@ public: void KeyValue( KeyValueData *pkvd ); int m_iPose;// which sequence to display static const char *m_szPoses[7]; + +private: + const char *GetScientistModel( void ); }; const char *CDeadScientist::m_szPoses[] = @@ -1127,8 +1148,10 @@ LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist ) // void CDeadScientist::Spawn() { - PRECACHE_MODEL( "models/scientist.mdl" ); - SET_MODEL( ENT( pev ), "models/scientist.mdl" ); + const char *pszModel = GetScientistModel(); + + PRECACHE_MODEL( pszModel ); + SET_MODEL( ENT( pev ), pszModel ); pev->effects = 0; pev->sequence = 0; @@ -1160,6 +1183,20 @@ void CDeadScientist::Spawn() MonsterInitDead(); } +const char *CDeadScientist::GetScientistModel( void ) +{ + if( !g_psv_override_scientist_mdl ) + g_psv_override_scientist_mdl = CVAR_GET_POINTER( "_sv_override_scientist_mdl" ); + + if( !( g_psv_override_scientist_mdl && g_psv_override_scientist_mdl->string )) + return "models/scientist.mdl"; + + if( strlen( g_psv_override_scientist_mdl->string ) < sizeof( "01.mdl" ) - 1 ) + return "models/scientist.mdl"; + + return g_psv_override_scientist_mdl->string; +} + //========================================================= // Sitting Scientist PROP //========================================================= From e0cdfe9ae869fd4b53d97eedd4ea338ebf3214c7 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Wed, 14 Feb 2024 04:33:36 +0500 Subject: [PATCH 37/42] Add Steam Friends Rich Presence cmd calls. --- cl_dll/hud.cpp | 2 ++ cl_dll/hud_msg.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index e82679bf..86f0f6cd 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -428,6 +428,8 @@ void CHud::Init( void ) m_Menu.Init(); MsgFunc_ResetHUD( 0, 0, NULL ); + ClientCmd( "richpresence_gamemode\n" ); + ClientCmd( "richpresence_update\n" ); } // CHud destructor diff --git a/cl_dll/hud_msg.cpp b/cl_dll/hud_msg.cpp index 7cc2fbad..3c3b6f52 100644 --- a/cl_dll/hud_msg.cpp +++ b/cl_dll/hud_msg.cpp @@ -87,6 +87,11 @@ int CHud::MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ) BEGIN_READ( pbuf, iSize ); m_Teamplay = READ_BYTE(); + if( m_Teamplay ) + ClientCmd( "richpresence_gamemode Teamplay\n" ); + else + ClientCmd( "richpresence_gamemode\n" ); + ClientCmd( "richpresence_update\n" ); return 1; } From 7223e0d6c15cede7fd1e93e57d8f0f25a5e7c678 Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Mon, 19 Feb 2024 01:46:19 +0500 Subject: [PATCH 38/42] Fix C functions declarations. --- pm_shared/pm_shared.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index dec69184..b8112d7e 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -167,7 +167,7 @@ void PM_SortTextures( void ) } } -void PM_InitTextureTypes() +void PM_InitTextureTypes( void ) { char buffer[512]; int i, j; @@ -718,7 +718,7 @@ PM_CheckVelocity See if the player has a bogus velocity value. ================ */ -void PM_CheckVelocity() +void PM_CheckVelocity( void ) { int i; @@ -795,7 +795,7 @@ int PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) return blocked; } -void PM_AddCorrectGravity() +void PM_AddCorrectGravity( void ) { float ent_gravity; @@ -816,7 +816,7 @@ void PM_AddCorrectGravity() PM_CheckVelocity(); } -void PM_FixupGravityVelocity() +void PM_FixupGravityVelocity( void ) { float ent_gravity; @@ -1070,7 +1070,7 @@ PM_WalkMove Only used by players. Moves along the ground when player is a MOVETYPE_WALK. ====================== */ -void PM_WalkMove() +void PM_WalkMove( void ) { //int clip; int oldonground; @@ -1511,7 +1511,7 @@ PM_CheckWater Sets pmove->waterlevel and pmove->watertype values. ============= */ -qboolean PM_CheckWater() +qboolean PM_CheckWater( void ) { vec3_t point; int cont; @@ -2259,7 +2259,7 @@ PM_AddGravity ============ */ -void PM_AddGravity() +void PM_AddGravity( void ) { float ent_gravity; @@ -2309,7 +2309,7 @@ PM_Physics_Toss() Dead player flying through air., e.g. ============ */ -void PM_Physics_Toss() +void PM_Physics_Toss( void ) { pmtrace_t trace; vec3_t move; @@ -2410,7 +2410,7 @@ PM_NoClip ==================== */ -void PM_NoClip() +void PM_NoClip( void ) { int i; vec3_t wishvel; From c7b141d67d9bfb443dae23f4a98f0bf68e73967d Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Mon, 19 Feb 2024 01:54:43 +0500 Subject: [PATCH 39/42] Fix alien slave beams staying forever if they exist during a level change. Same as https://github.com/twhl-community/halflife-updated/commit/ac808a876977f780e3753a520d227172fad866c2. --- dlls/islave.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/islave.cpp b/dlls/islave.cpp index 577eda24..ba194cea 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -732,6 +732,7 @@ void CISlave::ArmBeam( int side ) m_pBeam[m_iBeams]->SetColor( 96, 128, 16 ); m_pBeam[m_iBeams]->SetBrightness( 64 ); m_pBeam[m_iBeams]->SetNoise( 80 ); + m_pBeam[m_iBeams]->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition m_iBeams++; } @@ -776,6 +777,7 @@ void CISlave::WackBeam( int side, CBaseEntity *pEntity ) m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); m_pBeam[m_iBeams]->SetBrightness( 255 ); m_pBeam[m_iBeams]->SetNoise( 80 ); + m_pBeam[m_iBeams]->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition m_iBeams++; } @@ -806,6 +808,7 @@ void CISlave::ZapBeam( int side ) m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); m_pBeam[m_iBeams]->SetBrightness( 255 ); m_pBeam[m_iBeams]->SetNoise( 20 ); + m_pBeam[m_iBeams]->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition m_iBeams++; pEntity = CBaseEntity::Instance( tr.pHit ); From f58544a1568f6abbbe28bf3c5c94b5b967e4f69c Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Mon, 19 Feb 2024 02:07:20 +0500 Subject: [PATCH 40/42] Fix save game system not saving arrays of EHANDLEs if the first half of the array contains null handles. Same as https://github.com/twhl-community/halflife-updated/commit/d5d96d38830be1f9d41427c89d5a600fc778ff30. --- dlls/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/util.cpp b/dlls/util.cpp index 6cfebc10..56819f44 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -2223,7 +2223,7 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou break; case FIELD_EHANDLE: // Input and Output sizes are different! - pOutputData = (char *)pOutputData + j * ( sizeof(EHANDLE) - gSizes[pTest->fieldType] ); + pInputData = (char*)pData + j * gSizes[pTest->fieldType]; entityIndex = *(int *)pInputData; pent = EntityFromIndex( entityIndex ); if( pent ) From da9ce1e9c3bd3d26e2fd091cef7ea3800cfdd51b Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Mon, 19 Feb 2024 02:23:22 +0500 Subject: [PATCH 41/42] Disable jump sounds while player is frozen. Same as https://github.com/twhl-community/halflife-updated/commit/f3810c7107c9ea686a043c28a7a4ceb2e6fb92f7. --- pm_shared/pm_shared.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index b8112d7e..922c7ca6 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -2570,13 +2570,17 @@ void PM_Jump( void ) if( !bunnyjump ) PM_PreventMegaBunnyJumping(); - if( tfc ) + // Don't play jump sounds while frozen. + if( !( pmove->flags & FL_FROZEN )) { - pmove->PM_PlaySound( CHAN_BODY, "player/plyrjmp8.wav", 0.5, ATTN_NORM, 0, PITCH_NORM ); - } - else - { - PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), 1.0f ); + if( tfc ) + { + pmove->PM_PlaySound( CHAN_BODY, "player/plyrjmp8.wav", 0.5, ATTN_NORM, 0, PITCH_NORM ); + } + else + { + PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), 1.0f ); + } } // See if user can super long jump? From c3d9f27bcf736a1b0494e66779e0e99e5a25c9cb Mon Sep 17 00:00:00 2001 From: Andrey Akhmichin <15944199+nekonomicon@users.noreply.github.com> Date: Mon, 19 Feb 2024 03:33:51 +0500 Subject: [PATCH 42/42] Properly set up hand grenade sequence. Same as https://github.com/twhl-community/halflife-updated/commit/2ee36b472fcb43b18fb34fe56125e9fcac74704c. --- dlls/ggrenade.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index 5995fe53..a4552d36 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -267,6 +267,7 @@ void CGrenade::BounceTouch( CBaseEntity *pOther ) pev->velocity = pev->velocity * 0.8f; pev->sequence = RANDOM_LONG( 1, 1 ); + ResetSequenceInfo(); } else { @@ -410,7 +411,9 @@ CGrenade *CGrenade::ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vec pGrenade->pev->velocity = Vector( 0, 0, 0 ); } + SET_MODEL( ENT( pGrenade->pev ), "models/w_grenade.mdl" ); pGrenade->pev->sequence = RANDOM_LONG( 3, 6 ); + pGrenade->ResetSequenceInfo(); pGrenade->pev->framerate = 1.0f; // Tumble through the air @@ -419,7 +422,6 @@ CGrenade *CGrenade::ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vec pGrenade->pev->gravity = 0.5f; pGrenade->pev->friction = 0.8f; - SET_MODEL( ENT( pGrenade->pev ), "models/w_grenade.mdl" ); pGrenade->pev->dmg = 100; return pGrenade;