diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 61c858563..22442c86b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -196,9 +196,23 @@ jobs:
steps:
- name: Install dependencies
run: |
- dpkg --add-architecture i386
- apt-get update
- apt-get install -y \
+ # Debian 11 reached end of LTS on 2026-08-31: the bullseye-security
+ # suite is frozen and its pool is being pruned from deb.debian.org.
+ # Keep the same toolchain, but fetch the base suite from the Debian
+ # archive and pin the security suite to its last complete snapshot.
+ # The security suite is fetched from the cloudflare snapshot mirror:
+ # plain snapshot.debian.org throttles CI bursts with connection
+ # resets, and https needs ca-certificates, which debian:11-slim
+ # does not ship, so bootstrap it from the archive first.
+ cat > /etc/apt/sources.list <<'EOF'
+ deb http://archive.debian.org/debian bullseye main
+ deb http://archive.debian.org/debian bullseye-updates main
+ EOF
+ apt-get -o Acquire::Check-Valid-Until=false update
+ apt-get install -y --no-install-recommends ca-certificates
+ echo 'deb https://snapshot-cloudflare.debian.org/archive/debian-security/20260831T000000Z bullseye-security main' > /etc/apt/sources.list.d/bullseye-security.list
+ apt-get -o Acquire::Check-Valid-Until=false -o Acquire::Retries=5 update
+ apt-get -o Acquire::Retries=5 install -y \
gcc-multilib g++-multilib \
build-essential \
libc6-dev libc6-dev-i386 \
diff --git a/README.md b/README.md
index d224265e1..d16cf5cc8 100644
--- a/README.md
+++ b/README.md
@@ -140,6 +140,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
| mp_stamina_restore_rate | 0 | 0.0 | - | Framerate (FPS), that used as reference when restoring stamina (fuser2) after jump. |
| mp_logkills | 1 | 0 | 1 | Log kills.
`0` disabled
`1` enabled |
| mp_jump_height | 45 | 0.0 | - | Player jump height. |
+| mp_longjump_cooldown | 0.0 | 0.0 | - | Cooldown time (in seconds) between long jumps to prevent abuse.
`0` disabled
`>0` seconds before the player can long jump again. During cooldown, only a regular vertical jump is performed. |
| bot_excellent_morale | 0 | 0 | 1 | Bots always have great morale regardless of defeat or victory. |
| mp_randomspawn | 0 | 0 | 1 | Random player spawns
`0` disabled
`1` enabled
`NOTE`: Navigation `maps/.nav` file required |
| mp_playerid_showhealth | 1 | 0 | 2 | Player ID display mode.
`0` don't show health
`1` show health for teammates only (default CS behaviour)
`2` show health for all players |
diff --git a/dist/game.cfg b/dist/game.cfg
index fc59a237e..14c752a46 100644
--- a/dist/game.cfg
+++ b/dist/game.cfg
@@ -670,6 +670,13 @@ mp_stamina_restore_rate "0"
// Default value: "45"
mp_jump_height "45"
+// Cooldown time (in seconds) between long jumps to prevent abuse.
+// 0 - disabled (default behaviour)
+// >0 - seconds before the player can long jump again
+//
+// Default value: "0.0"
+mp_longjump_cooldown "0.0"
+
// Bots always have great morale regardless of defeat or victory.
// 0 - disabled (default behaviour)
// 1 - enabled
diff --git a/regamedll/CMakeLists.txt b/regamedll/CMakeLists.txt
index b1166d023..c4b22a8e0 100644
--- a/regamedll/CMakeLists.txt
+++ b/regamedll/CMakeLists.txt
@@ -43,7 +43,7 @@ endif()
# do not strip debuginfo during link
if (NOT DEBUG)
- set(LINK_FLAGS "-s")
+ set(LINK_FLAGS "")
endif()
# add -m32 flag only on 64-bit systems, if building for 64-bit wasn't enabled with XASH_COMPAT
@@ -437,6 +437,10 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 4 AND NOT ANDROID)
set(LINK_FLAGS "${LINK_FLAGS} -L${PROJECT_SOURCE_DIR}/lib/linux32")
endif()
+if (UNIX AND NOT APPLE AND NOT ANDROID)
+ set(LINK_FLAGS "${LINK_FLAGS} -Wl,-z,notext")
+endif()
+
if (NOT MSVC)
set_target_properties(regamedll PROPERTIES
COMPILE_FLAGS ${COMPILE_FLAGS}
diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp
index 01e07b92a..7f3e8102f 100644
--- a/regamedll/dlls/game.cpp
+++ b/regamedll/dlls/game.cpp
@@ -10,6 +10,7 @@ cvar_t *g_psv_stopspeed = nullptr;
cvar_t *g_psv_stepsize = nullptr;
cvar_t *g_psv_clienttrace = nullptr;
cvar_t *g_psv_maxvelocity = nullptr;
+cvar_t *g_psv_zmax = nullptr;
cvar_t displaysoundlist = { "displaysoundlist", "0", 0, 0.0f, nullptr };
cvar_t timelimit = { "mp_timelimit", "0", FCVAR_SERVER, 0.0f, nullptr };
@@ -174,6 +175,7 @@ cvar_t assist_damage_threshold = { "mp_assist_damage_threshold", "40",
cvar_t freezetime_duck = { "mp_freezetime_duck", "1", 0, 1.0f, nullptr };
cvar_t freezetime_jump = { "mp_freezetime_jump", "1", 0, 1.0f, nullptr };
cvar_t jump_height = { "mp_jump_height", "45", FCVAR_SERVER, 45.0f, nullptr };
+cvar_t longjump_cooldown = { "mp_longjump_cooldown", "0.0", 0, 0.0f, nullptr };
cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr };
@@ -272,6 +274,7 @@ void EXT_FUNC GameDLLInit()
g_psv_stepsize = CVAR_GET_POINTER("sv_stepsize");
g_psv_clienttrace = CVAR_GET_POINTER("sv_clienttrace");
g_psv_maxvelocity = CVAR_GET_POINTER("sv_maxvelocity");
+ g_psv_zmax = CVAR_GET_POINTER("sv_zmax");
CVAR_REGISTER(&displaysoundlist);
CVAR_REGISTER(&timelimit);
@@ -469,6 +472,7 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&freezetime_duck);
CVAR_REGISTER(&freezetime_jump);
CVAR_REGISTER(&jump_height);
+ CVAR_REGISTER(&longjump_cooldown);
CVAR_REGISTER(&defuser_allocation);
CVAR_REGISTER(&location_area_info);
CVAR_REGISTER(&chat_loc_fallback);
diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h
index 741e0a571..32e6ae015 100644
--- a/regamedll/dlls/game.h
+++ b/regamedll/dlls/game.h
@@ -50,6 +50,7 @@ extern cvar_t *g_psv_stopspeed;
extern cvar_t *g_psv_stepsize;
extern cvar_t *g_psv_clienttrace;
extern cvar_t *g_psv_maxvelocity;
+extern cvar_t *g_psv_zmax;
extern cvar_t displaysoundlist;
extern cvar_t timelimit;
@@ -203,6 +204,7 @@ extern cvar_t assist_damage_threshold;
extern cvar_t freezetime_duck;
extern cvar_t freezetime_jump;
extern cvar_t jump_height;
+extern cvar_t longjump_cooldown;
extern cvar_t defuser_allocation;
extern cvar_t location_area_info;
extern cvar_t chat_loc_fallback;
diff --git a/regamedll/dlls/mapinfo.cpp b/regamedll/dlls/mapinfo.cpp
index 48200b6f6..1c81e45e4 100644
--- a/regamedll/dlls/mapinfo.cpp
+++ b/regamedll/dlls/mapinfo.cpp
@@ -22,7 +22,9 @@ void CMapInfo::OnCreate()
void CMapInfo::OnDestroy()
{
- g_pMapInfo = nullptr;
+ // Only the instance that owns the global may clear it.
+ if (g_pMapInfo == this)
+ g_pMapInfo = nullptr;
}
void CMapInfo::CheckMapInfo()
diff --git a/regamedll/dlls/plats.cpp b/regamedll/dlls/plats.cpp
index f0735053b..4069d521c 100644
--- a/regamedll/dlls/plats.cpp
+++ b/regamedll/dlls/plats.cpp
@@ -1051,12 +1051,19 @@ void CFuncTrackTrain::StopSound()
// if sound playing, stop it
if (m_soundPlaying && pev->noise)
{
+#ifdef REGAMEDLL_FIXES
+ // Stop the sound through the engine sound API: SND_STOP is delivered as a reliable
+ // broadcast, while the event is PVS-filtered and can be missed by distant players,
+ // leaving the engine loop running on their side.
+ EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), 0, 0, SND_STOP, PITCH_NORM);
+#else
unsigned short us_encode;
unsigned short us_sound = ((unsigned short)(m_sounds) & 0x0007) << 12;
us_encode = us_sound;
PLAYBACK_EVENT_FULL(FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0);
+#endif
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100);
}
@@ -1070,19 +1077,40 @@ void CFuncTrackTrain::UpdateSound()
#ifdef REGAMEDLL_FIXES
float flpitch = TRAIN_STARTPITCH + (Q_abs(pev->speed) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED);
+
+ // The engine sound API carries the pitch as a byte, keep it inside the intended range
+ if (flpitch > TRAIN_MAXPITCH)
+ flpitch = TRAIN_MAXPITCH;
+
+ // Never report the engine pitch as exactly PITCH_NORM: a looping sound that is
+ // re-pitched to 100 drops out of the client's pitch-shifting mixer back into the
+ // plain playback path, which then runs past the end of the wave and mixes in
+ // whatever sound follows it in the client's sound cache.
+ // Same guard as CFuncRotating::RampPitchVol() and CAmbientGeneric.
+ int ipitch = int(flpitch);
+ if (ipitch == PITCH_NORM)
+ ipitch = PITCH_NORM - 1;
#else
float flpitch = TRAIN_STARTPITCH + (Q_abs(int(pev->speed)) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED);
+ int ipitch = int(flpitch);
#endif
if (!m_soundPlaying)
{
// play startup sound for train
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100);
- EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, int(flpitch));
+ EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, ipitch);
m_soundPlaying = 1;
}
else
{
+#ifdef REGAMEDLL_FIXES
+ // Update pitch/volume through the engine sound API instead of the client event:
+ // the event packs the pitch as pitch / 10 into 6 bits, so the range is quantized
+ // to steps of 10 and everything in [100, 110) arrives as PITCH_NORM. The event is
+ // also PVS-filtered, while the sound itself is started with a reliable broadcast.
+ EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH | SND_CHANGE_VOL, ipitch);
+#else
// update pitch
// EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, int(flpitch));
@@ -1099,6 +1127,7 @@ void CFuncTrackTrain::UpdateSound()
us_encode = us_sound | us_pitch | us_volume;
PLAYBACK_EVENT_FULL(FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0);
+#endif
}
}
diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp
index 25b538ef2..8a219ead3 100644
--- a/regamedll/dlls/player.cpp
+++ b/regamedll/dlls/player.cpp
@@ -4281,7 +4281,19 @@ void CBasePlayer::PlayerUse()
if (legacy_vehicle_block.value == 0)
return;
#endif
- ((CFuncVehicle *)pTrain)->m_pDriver = nullptr;
+ CFuncVehicle *pVehicle = (CFuncVehicle *)pTrain;
+ pVehicle->m_pDriver = nullptr;
+#ifdef REGAMEDLL_FIXES
+ if (Q_abs(pTrain->pev->speed) < 50)
+ {
+ pVehicle->StopSound();
+ pVehicle->SetThink(nullptr);
+ pTrain->pev->speed = 0;
+ pTrain->pev->velocity = g_vecZero;
+ pTrain->pev->avelocity = g_vecZero;
+ pVehicle->m_fEngineOn = FALSE;
+ }
+#endif
}
return;
}
@@ -4299,8 +4311,18 @@ void CBasePlayer::PlayerUse()
if (pTrain->Classify() == CLASS_VEHICLE)
{
+ CFuncVehicle *pVehicle = (CFuncVehicle *)pTrain;
+#ifdef REGAMEDLL_FIXES
+ if (!pVehicle->m_fEngineOn)
+ {
+ EMIT_SOUND(ENT(pev), CHAN_ITEM, "plats/vehicle_ignition.wav", 0.8, ATTN_NORM);
+ pVehicle->m_fEngineOn = TRUE;
+ pVehicle->UpdateSound();
+ }
+#else
EMIT_SOUND(ENT(pev), CHAN_ITEM, "plats/vehicle_ignition.wav", 0.8, ATTN_NORM);
- ((CFuncVehicle *)pTrain)->m_pDriver = this;
+#endif
+ pVehicle->m_pDriver = this;
}
else
EMIT_SOUND(ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM);
@@ -8252,7 +8274,13 @@ void EXT_FUNC CBasePlayer::__API_HOOK(UpdateStatusBar)()
UTIL_MakeVectors(pev->v_angle + pev->punchangle);
Vector vecSrc = EyePosition();
- Vector vecEnd = vecSrc + (gpGlobals->v_forward * ((pev->flags & FL_SPECTATOR) != 0 ? MAX_SPEC_ID_RANGE : MAX_ID_RANGE));
+ Vector vecEnd = vecSrc + (gpGlobals->v_forward * ((pev->flags & FL_SPECTATOR) != 0 ? MAX_SPEC_ID_RANGE :
+#ifdef REGAMEDLL_ADD
+ (g_psv_zmax ? g_psv_zmax->value : MAX_ID_RANGE)
+#else
+ MAX_ID_RANGE
+#endif
+ ));
UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr);
diff --git a/regamedll/dlls/trains.h b/regamedll/dlls/trains.h
index ebef8bf5f..33de0b548 100644
--- a/regamedll/dlls/trains.h
+++ b/regamedll/dlls/trains.h
@@ -198,6 +198,10 @@ class CFuncVehicle: public CBaseEntity
Vector m_vSurfaceNormal;
Vector m_vVehicleDirection;
CBaseEntity *m_pDriver;
+#ifdef REGAMEDLL_FIXES
+ int m_iCollisionCount;
+ BOOL m_fEngineOn;
+#endif
private:
unsigned short m_usAdjustPitch;
diff --git a/regamedll/dlls/vehicle.cpp b/regamedll/dlls/vehicle.cpp
index 7bf2d4184..fef3f7833 100644
--- a/regamedll/dlls/vehicle.cpp
+++ b/regamedll/dlls/vehicle.cpp
@@ -288,10 +288,17 @@ void CFuncVehicle::StopSound()
{
if (m_soundPlaying && pev->noise)
{
+#ifdef REGAMEDLL_FIXES
+ // Stop the sound through the engine sound API: SND_STOP is delivered as a reliable
+ // broadcast, while the event is PVS-filtered and can be missed by distant players,
+ // leaving the engine loop running on their side.
+ EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), 0, 0, SND_STOP, PITCH_NORM);
+#else
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, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, us_encode, 0, 1, 0);
+#endif
}
m_soundPlaying = 0;
@@ -311,6 +318,19 @@ void CFuncVehicle::UpdateSound()
if (flpitch > 200)
flpitch = 200;
+#ifdef REGAMEDLL_FIXES
+ // Never report the engine pitch as exactly PITCH_NORM: a looping sound that is
+ // re-pitched to 100 drops out of the client's pitch-shifting mixer back into the
+ // plain playback path, which then runs past the end of the wave and mixes in
+ // whatever sound follows it in the client's sound cache.
+ // Same guard as CFuncRotating::RampPitchVol() and CAmbientGeneric.
+ int ipitch = int(flpitch);
+ if (ipitch == PITCH_NORM)
+ ipitch = PITCH_NORM - 1;
+#else
+ int ipitch = int(flpitch);
+#endif
+
if (!m_soundPlaying)
{
if (m_sounds < 5)
@@ -318,17 +338,25 @@ void CFuncVehicle::UpdateSound()
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/vehicle_brake1.wav", m_flVolume, ATTN_NORM, 0, 100);
}
- EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, int(flpitch));
+ EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, ipitch);
m_soundPlaying = 1;
}
else
{
+#ifdef REGAMEDLL_FIXES
+ // Update pitch/volume through the engine sound API instead of the client event:
+ // the event packs the pitch as pitch / 10 into 6 bits, so the range is quantized
+ // to steps of 10 and everything in [100, 110) arrives as PITCH_NORM. The event is
+ // also PVS-filtered, while the sound itself is started with a reliable broadcast.
+ EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH | SND_CHANGE_VOL, ipitch);
+#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, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0);
+#endif
}
}
@@ -441,6 +469,9 @@ void CFuncVehicle::CollisionDetection()
if (tr.flFraction == 1.0f)
{
+#ifdef REGAMEDLL_FIXES
+ m_iCollisionCount = 0;
+#endif
return;
}
}
@@ -454,6 +485,16 @@ void CFuncVehicle::CollisionDetection()
}
else if (tr.vecPlaneNormal.z < 0.65 || tr.fStartSolid)
{
+#ifdef REGAMEDLL_FIXES
+ m_iCollisionCount++;
+ if (m_iCollisionCount >= 3)
+ {
+ pev->speed = 0;
+ pev->velocity = g_vecZero;
+ pev->avelocity = g_vecZero;
+ }
+ else
+#endif
pev->speed *= -1.0;
}
else
@@ -472,6 +513,16 @@ void CFuncVehicle::CollisionDetection()
}
else if (tr.vecPlaneNormal[2] < 0.65f || tr.fStartSolid)
{
+#ifdef REGAMEDLL_FIXES
+ m_iCollisionCount++;
+ if (m_iCollisionCount >= 3)
+ {
+ pev->speed = 0;
+ pev->velocity = g_vecZero;
+ pev->avelocity = g_vecZero;
+ }
+ else
+#endif
pev->speed *= -1.0;
}
else
@@ -502,6 +553,9 @@ void CFuncVehicle::CollisionDetection()
if (tr.flFraction == 1.0f)
{
+#ifdef REGAMEDLL_FIXES
+ m_iCollisionCount = 0;
+#endif
return;
}
}
@@ -516,6 +570,16 @@ void CFuncVehicle::CollisionDetection()
}
else if (tr.vecPlaneNormal.z < 0.65 || tr.fStartSolid)
{
+#ifdef REGAMEDLL_FIXES
+ m_iCollisionCount++;
+ if (m_iCollisionCount >= 3)
+ {
+ pev->speed = 0;
+ pev->velocity = g_vecZero;
+ pev->avelocity = g_vecZero;
+ }
+ else
+#endif
pev->speed *= -1.0;
}
else
@@ -599,6 +663,12 @@ void CFuncVehicle::Next()
pev->avelocity = g_vecZero;
pev->velocity = g_vecZero;
+#ifdef REGAMEDLL_FIXES
+ // Ensure idle sound is playing when vehicle stops
+ if (m_fEngineOn && !m_soundPlaying)
+ UpdateSound();
+#endif
+
SetThink(&CFuncVehicle::Next);
NextThink(pev->ltime + time, TRUE);
return;
@@ -805,8 +875,13 @@ void CFuncVehicle::Find()
UTIL_SetOrigin(pev, nextPos);
NextThink(pev->ltime + 0.1, FALSE);
SetThink(&CFuncVehicle::Next);
+#ifdef REGAMEDLL_FIXES
+ if (m_fEngineOn)
+ pev->speed = m_startSpeed;
+#else
pev->speed = m_startSpeed;
UpdateSound();
+#endif
}
void CFuncVehicle::NearestPath()
@@ -902,6 +977,10 @@ void CFuncVehicle::Spawn()
m_dir = 1;
m_flTurnStartTime = -1;
+#ifdef REGAMEDLL_FIXES
+ m_iCollisionCount = 0;
+ m_fEngineOn = FALSE;
+#endif
if (FStringNull(pev->target))
{
@@ -946,6 +1025,10 @@ void CFuncVehicle::Restart()
m_flTurnStartTime = -1;
m_flUpdateSound = -1;
m_pDriver = nullptr;
+#ifdef REGAMEDLL_FIXES
+ m_iCollisionCount = 0;
+ m_fEngineOn = FALSE;
+#endif
if (FStringNull(pev->target))
{
@@ -954,6 +1037,9 @@ void CFuncVehicle::Restart()
UTIL_SetOrigin(pev, pev->oldorigin);
STOP_SOUND(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noise));
+#ifdef REGAMEDLL_FIXES
+ m_soundPlaying = 0;
+#endif
NextThink(pev->ltime + 0.1f, FALSE);
SetThink(&CFuncVehicle::Find);
diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp
index 846b410d0..b524513e3 100644
--- a/regamedll/pm_shared/pm_shared.cpp
+++ b/regamedll/pm_shared/pm_shared.cpp
@@ -2762,25 +2762,40 @@ void EXT_FUNC __API_HOOK(PM_Jump)()
// UNDONE: note this should be based on forward angles, not current velocity.
if (cansuperjump && (pmove->cmd.buttons & IN_DUCK) && pmove->flDuckTime > 0 && Length(pmove->velocity) > 50)
{
- pmove->punchangle[0] = -5.0f;
-
-#ifdef REGAMEDLL_API
- if (pmoveplayer->m_flLongJumpForce > 0.0)
+#ifdef REGAMEDLL_ADD
+ if (pmove->fuser4 > 0.0f)
{
- fvel = pmoveplayer->m_flLongJumpForce;
+ pmove->velocity[2] = PM_JumpHeight(false);
}
else
#endif
{
- fvel = PLAYER_LONGJUMP_SPEED * 1.6f;
- }
+ pmove->punchangle[0] = -5.0f;
- for (int i = 0; i < 2; i++)
- {
- pmove->velocity[i] = pmove->forward[i] * fvel;
- }
+#ifdef REGAMEDLL_API
+ if (pmoveplayer->m_flLongJumpForce > 0.0)
+ {
+ fvel = pmoveplayer->m_flLongJumpForce;
+ }
+ else
+#endif
+ {
+ fvel = PLAYER_LONGJUMP_SPEED * 1.6f;
+ }
- pmove->velocity[2] = PM_JumpHeight(true);
+ for (int i = 0; i < 2; i++)
+ {
+ pmove->velocity[i] = pmove->forward[i] * fvel;
+ }
+
+ pmove->velocity[2] = PM_JumpHeight(true);
+#ifdef REGAMEDLL_ADD
+ if (longjump_cooldown.value > 0.0f)
+ {
+ pmove->fuser4 = longjump_cooldown.value * 1000.0f;
+ }
+#endif
+ }
}
else
{
@@ -3112,6 +3127,18 @@ void PM_ReduceTimers()
pmove->fuser2 = 0;
}
}
+
+#ifdef REGAMEDLL_ADD
+ if (pmove->fuser4 > 0.0)
+ {
+ pmove->fuser4 -= pmove->cmd.msec;
+
+ if (pmove->fuser4 < 0.0)
+ {
+ pmove->fuser4 = 0;
+ }
+ }
+#endif
}
qboolean PM_ShouldDoSpectMode()