diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b4e807929..8217211ff 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -24,6 +24,9 @@ jobs:
buildTests: 'Tests'
steps:
+ - name: Configure
+ run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
+
- name: Checkout
uses: actions/checkout@v4
with:
@@ -32,7 +35,7 @@ jobs:
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
with:
- vs-version: '16.8'
+ vs-version: '16'
- name: Build and Run unittests
run: |
@@ -58,95 +61,72 @@ jobs:
move msvc\${{ env.buildRelease }}\mp.pdb publish\debug\mp.pdb
- name: Deploy artifacts
- uses: actions/upload-artifact@v3.1.1
+ uses: actions/upload-artifact@v4
with:
name: win32
path: publish/*
testdemos:
name: 'Test demos'
- runs-on: ubuntu-20.04
- container: s1lentq/testdemos:latest
+ runs-on: ubuntu-latest
+ container: rehldsorg/testdemos:latest
needs: [windows]
- env:
- WINEDEBUG: -all
- WINEDLLOVERRIDES: mshtml=
- ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
-
defaults:
run:
shell: bash
- working-directory: ../../../opt/HLDS
+ working-directory: /opt/HLDS
+
+ strategy:
+ fail-fast: false
+ matrix:
+ test: [
+ { file: 'cstrike-basic-1', desc: 'CS: Testing jumping, scenarios, shooting etc' },
+ ]
steps:
- name: Deploying windows artifacts
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: win32
- - name: Play demos
+ - name: Setup dependencies
run: |
chown root ~
rsync -a deps/regamedll/* .
mv $GITHUB_WORKSPACE/tests/mp.dll cstrike/dlls/mp.dll
- descs=(
- "CS: Testing jumping, scenarios, shooting etc"
- )
-
- demos=(
- "cstrike-basic-1"
- )
-
- retVal=0
- for i in "${!demos[@]}"; do
- params=$(cat "testdemos/${demos[i]}.params")
-
- echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[0m"
- echo -e " - \e[0;33mParameters $params\e[0m"
-
- wine hlds.exe --rehlds-enable-all-hooks --rehlds-test-play "testdemos/${demos[i]}.bin" $params &> result.log || retVal=$?
-
- if [ $retVal -ne 777 ] && [ $retVal -ne 9 ]; then
- # Print with catchy messages
- while read line; do
- echo -e " \e[0;33m$line"
- done <<< $(cat result.log | sed '0,/demo failed/I!d;/wine:/d;/./,$!d')
-
- echo " 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸"
- while read line; do
- echo -e " \e[1;31m$line";
- done < rehlds_demo_error.txt
- echo -e " \e[30;41mExit code: $retVal\e[0m"
- echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[1;31m Failed ❌"
- exit 6 # Test demo failed
- else
- # Print result HLDS console
- while read line; do
- echo -e " \e[0;33m$line"
- done <<< $(cat result.log | sed '/wine:/d;/./,$!d')
- echo -e " \e[30;43mExit code: $retVal\e[0m"
- echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[1;32m Succeed ✔"
- fi
- done
+ - name: Play test
+ env:
+ demo: ${{ matrix.test.file }}
+ desc: ${{ matrix.test.desc }}
+ run: ./runTest.sh
linux:
name: 'Linux'
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
+ container: debian:11-slim
steps:
+ - name: Install dependencies
+ run: |
+ dpkg --add-architecture i386
+ apt-get update
+ apt-get install -y \
+ gcc-multilib g++-multilib \
+ build-essential \
+ libc6-dev libc6-dev-i386 \
+ git cmake rsync \
+ g++ gcc
+
+ - name: Configure
+ run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
+
- name: Checkout
uses: actions/checkout@v4
with:
+ submodules: recursive
fetch-depth: 0
- submodules: true
-
- - name: Check dependencies
- run: |
- sudo dpkg --add-architecture i386
- sudo apt-get update
- sudo apt-get install -y gcc-multilib g++-multilib
- name: Build and Run unittests
run: |
@@ -171,7 +151,7 @@ jobs:
fi
shell: bash
- - name: Build
+ - name: Build using GCC Compiler
run: |
rm -rf build && CC=gcc CXX=g++ cmake -B build && cmake --build build -j8
@@ -199,18 +179,12 @@ jobs:
shell: bash
- name: Deploy artifacts
- uses: actions/upload-artifact@v3.1.1
+ uses: actions/upload-artifact@v4
id: upload-job
with:
name: linux32
path: publish/*
- - name: Cleanup temporary artifacts
- if: success() && steps.upload-job.outcome == 'success'
- run: |
- rm -rf cssdk
- rm -f appversion.h
-
publish:
name: 'Publish'
runs-on: ubuntu-latest
@@ -218,12 +192,12 @@ jobs:
steps:
- name: Deploying linux artifacts
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: linux32
- name: Deploying windows artifacts
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: win32
@@ -264,8 +238,3 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.API_TOKEN }}
- - name: Cleanup temporary artifacts
- if: success() && steps.publish-job.outcome == 'success'
- run: |
- rm -rf bin dist debug cssdk
- rm -f *.zip appversion.h
diff --git a/README.md b/README.md
index 90f58990d..a1198f080 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
| swapteams | Swap the teams and restart the game (1 sec delay to restart by default).
Args:
`0` - swap teams without restart.
`>0.001` - time delay in seconds to restart the round after swap. |
| give | Give weapon command.
Args:
Usage:
`give weapon_ak47`
`give weapon_usp`
NOTE: `sv_cheats 1` required. |
| impulse 255 | Give all weapons.
NOTE: `sv_cheats 1` required. |
+| impulse 200 | Noclip with air acceleration.
NOTE: `sv_cheats 1` required. |
## Configuration (cvars)
@@ -97,6 +98,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
| mp_ct_give_player_knife | 1 | 0 | 1 | Whether Counter-Terrorist player spawn with knife. |
| mp_ct_default_weapons_primary | "" | "" | - | The default primary (rifle) weapon that the CTs will spawn with. |
| mp_ct_default_weapons_secondary | "usp" | "" | - | The default secondary (pistol) weapon that the CTs will spawn with. |
+| mp_default_weapons_random | 0 | 0 | 1 | Randomize default weapons (if there are multiple).
`0` disabled
`1` enabled |
| mp_give_player_c4 | 1 | 0 | 1 | Whether this map should spawn a C4 bomb for a player or not.
`0` disabled
`1` enabled |
| mp_weapons_allow_map_placed | 1 | 0 | 1 | When set, map weapons (located on the floor by map) will be shown.
`0` hide all map weapons.
`1` enabled
`NOTE`: Effect will work after round restart. |
| mp_free_armor | 0 | 0 | 2 | Give free armor on player spawn.
`0` disabled
`1` Give Kevlar
`2` Give Kevlar + Helmet |
@@ -122,16 +124,25 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
| mp_ammo_respawn_time | 20 | 0.0 | - | The respawn time for ammunition. |
| mp_vote_flags | km | 0 | - | Vote systems enabled in server.
`0` voting disabled
`k` votekick enabled via `vote` command
`m` votemap enabled via `votemap` command |
| mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. |
+| mp_flymove_method | 0 | 0 | 1 | Set the method used for flymove calculations.
`0` default method
`1` alternative method (more accurate) |
+| 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. |
+| 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 |
+| mp_playerid_field | 3 | 0 | 3 | Player ID field display mode.
`0` don't show additional information
`1` show team name
`2` show health percentage
`3` show both team name and health percentage |
+| mp_knockback | 170 | - | - | Knockback force applied to the victim when damaged by strong weapons (e.g. `AWP`, `AK47`).
Works only if not crouching, and not hit in the legs.
Set to `0` to disable. |
## How to install zBot for CS 1.6?
* Extract all the files from an [archive](regamedll/extra/zBot/bot_profiles.zip?raw=true)
-* Enter `-bots` option at the command line HLDS
+* Enable CVar `bot_enable 1` in `cstrike/game_init.cfg` (if this config file does not exist, create it)
-## How to install CSCZ hostage AI for CS 1.6?
+## How to install CS:CZ hostage AI for CS 1.6?
* Extract all the files from an [archive](regamedll/extra/HostageImprov/host_improv.zip?raw=true)
-* Enter `-host-improv` option at the command line HLDS
+* Enable CVar `hostage_ai_enable 1` in `cstrike/game_init.cfg` (if this config file does not exist, create it)
## Build instructions
### Checking requirements
diff --git a/build.sh b/build.sh
index 876b458da..6dbfad242 100755
--- a/build.sh
+++ b/build.sh
@@ -33,7 +33,7 @@ main()
case "$C" in
("intel"|"icc") CC=icc CXX=icpc ;;
("gcc"|"g++") CC=gcc CXX=g++ ;;
- ("clang|llvm") CC=clang CXX=clang++ ;;
+ ("clang"|"llvm") CC=clang CXX=clang++ ;;
*)
;;
esac
diff --git a/dist/game.cfg b/dist/game.cfg
index c5dad01c9..f566ee9ba 100644
--- a/dist/game.cfg
+++ b/dist/game.cfg
@@ -466,6 +466,13 @@ mp_ct_default_weapons_primary ""
// Default value: "usp"
mp_ct_default_weapons_secondary "usp"
+// Randomize default weapons (if there are multiple)
+// 0 - disabled (default behaviour)
+// 1 - enabled
+//
+// Default value: "0"
+mp_default_weapons_random "0"
+
// Give the player free armor on player spawn
// 0 - No armor (default behavior)
// 1 - Give Kevlar
@@ -521,7 +528,7 @@ mp_give_c4_frags "3"
// Default value: "1.0"
mp_hostages_rescued_ratio "1.0"
-// Legacy func_vehicle behavior when blocked by another entity.
+// Legacy func_vehicle behavior when blocked by another entity.
// New one is more useful for playing multiplayer.
//
// 0 - New behavior
@@ -620,3 +627,63 @@ mp_vote_flags "km"
//
// Default value: "180"
mp_votemap_min_time "180"
+
+// Set the method used for flymove calculations.
+// 0 - default method
+// 1 - alternative method (more accurate)
+//
+// Default value: "0"
+mp_flymove_method "0"
+
+// Framerate (FPS), that is used as a reference when restoring stamina (fuser2) after a jump.
+// 0 - disabled
+//
+// Default value: "0"
+mp_stamina_restore_rate "0"
+
+// Player jump height
+//
+// Default value: "45"
+mp_jump_height "45"
+
+// Bots always have great morale regardless of defeat or victory.
+// 0 - disabled (default behaviour)
+// 1 - enabled
+//
+// Default value: "0"
+bot_excellent_morale "0"
+
+// Random player spawns
+// 0 - disabled (default behaviour)
+// 1 - enabled
+//
+// NOTE: Navigation "maps/.nav" file required
+//
+// Default value: "0"
+mp_randomspawn "0"
+
+// Player ID display mode
+//
+// 0 - don't show health (default behaviour)
+// 1 - show health for teammates only (default CS behaviour)
+// 2 - show health for all players
+//
+// Default value: "1"
+mp_playerid_showhealth "1"
+
+// Player ID field display mode
+//
+// 0 - don't show additional information
+// 1 - show team name
+// 2 - show health percentage
+// 3 - show both team name and health percentage
+//
+// Default value: "3"
+mp_playerid_field "3"
+
+// Knockback force applied to the victim when damaged by strong weapons (e.g. AWP, AK47).
+// Works only if not crouching, and not hit in the legs.
+// Set to "0" to disable.
+//
+// Default: "170"
+mp_knockback "170"
diff --git a/dist/game_init.cfg b/dist/game_init.cfg
index 90e31b2d5..de6cb5326 100644
--- a/dist/game_init.cfg
+++ b/dist/game_init.cfg
@@ -1,3 +1,18 @@
+// Enables ZBots for the server
+// NOTE: ZBots are always enabled on a listen server, regardless of this cvar
+// 0 - disabled
+// 1 - enabled
+//
+// Default value: "0"
+bot_enable "0"
+
+// Enables the improve AI for hostages from CS:CZ
+// 0 - disabled (classic hostage)
+// 1 - enabled (improved hostage)
+//
+// Default value: "0"
+hostage_ai_enable "0"
+
// Sets mins/maxs hull bounds for the player.
// 0 - disabled (default behaviour, sets engine)
// 1 - enabled (sets gamedll)
diff --git a/regamedll/CMakeLists.txt b/regamedll/CMakeLists.txt
index bc0a990e9..c1a13f9bd 100644
--- a/regamedll/CMakeLists.txt
+++ b/regamedll/CMakeLists.txt
@@ -20,20 +20,47 @@
cmake_minimum_required(VERSION 3.1)
project(regamedll CXX)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
option(DEBUG "Build with debug information." OFF)
option(USE_STATIC_LIBSTDC "Enables static linking libstdc++." OFF)
option(USE_LEGACY_LIBC "Enables linking against legacy libc (<= 2.15) for compat with older distros (Debian 8/Ubuntu 16.04/Centos 7)." OFF)
+option(XASH_COMPAT "Enable Xash3D FWGS compatiblity (support for it's 64-bit ABI support and crossplatform library suffix)")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Avoid -rdynamic -fPIC options
-set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "")
-set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
+if (NOT XASH_COMPAT)
+ set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "")
+ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
+endif()
-set(COMPILE_FLAGS "-m32 -U_FORTIFY_SOURCE")
-set(LINK_FLAGS "-m32 -s")
-set(LINK_LIBS dl aelf32)
+set(COMPILE_FLAGS "-U_FORTIFY_SOURCE")
+set(LINK_LIBS dl)
+
+# do not strip debuginfo during link
+if (NOT DEBUG)
+ set(LINK_FLAGS "-s")
+endif()
+
+# add -m32 flag only on 64-bit systems, if building for 64-bit wasn't enabled with XASH_COMPAT
+if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ if (XASH_COMPAT)
+ set(COMPILE_FLAGS "${COMPILE_FLAGS} -DXASH_64BIT")
+ else()
+ set(COMPILE_FLAGS "${COMPILE_FLAGS} -m32")
+ set(LINK_FLAGS "${LINK_FLAGS} -m32")
+ list(APPEND LINK_LIBS aelf32)
+ set(CMAKE_SIZEOF_VOID_P 4)
+ endif()
+endif()
+
+if(XASH_COMPAT)
+ # Xash3D FWGS Library Naming Scheme compliance
+ # see documentation: https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/extensions/library-naming.md
+ include(LibraryNaming)
+endif()
set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wall -fno-exceptions -fno-builtin -Wno-unknown-pragmas")
@@ -47,7 +74,7 @@ else()
endif()
# Check Intel C++ compiler
-if ("$ENV{CXX}" MATCHES "icpc")
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
#
# -fp-model=precise
# ICC uses -fp-model fast=1 by default for more aggressive optimizations on floating-point calculations
@@ -75,11 +102,15 @@ if ("$ENV{CXX}" MATCHES "icpc")
set(COMPILE_FLAGS "${COMPILE_FLAGS} -ipo")
set(LINK_FLAGS "${LINK_FLAGS} -ipo")
endif()
-else()
- # Produce code optimized for the most common IA32/AMD64/EM64T processors.
- # As new processors are deployed in the marketplace, the behavior of this option will change.
+elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ if (NOT XASH_COMPAT OR XASH_AMD64 OR XASH_X86)
+ # Produce code optimized for the most common IA32/AMD64/EM64T processors.
+ # As new processors are deployed in the marketplace, the behavior of this option will change.
+ set(COMPILE_FLAGS "${COMPILE_FLAGS} \
+ -mtune=generic -msse3")
+ endif()
+
set(COMPILE_FLAGS "${COMPILE_FLAGS} \
- -mtune=generic -msse3\
-fpermissive -fno-sized-deallocation\
-Wno-delete-non-virtual-dtor -Wno-invalid-offsetof\
-Wno-unused-variable -Wno-unused-value -Wno-unused-result -Wno-unused-function\
@@ -87,7 +118,7 @@ else()
-Wno-sign-compare -Wno-format -Wno-ignored-attributes -Wno-strict-aliasing")
# Check Clang compiler
- if ("$ENV{CXX}" MATCHES "clang")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(COMPILE_FLAGS "${COMPILE_FLAGS} \
-Wno-unused-local-typedef\
-Wno-unused-private-field\
@@ -102,16 +133,11 @@ else()
# GCC >= 8.3
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
- set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-stringop-truncation -Wno-format-truncation -Wno-class-memaccess")
+ set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-stringop-truncation -Wno-format-truncation -Wno-class-memaccess -fcf-protection=none")
endif()
endif()
endif()
-# GCC >= 8.3
-if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
- set(COMPILE_FLAGS "${COMPILE_FLAGS} -fcf-protection=none")
-endif()
-
if (NOT DEBUG)
set(LINK_FLAGS "${LINK_FLAGS} \
-Wl,-gc-sections -Wl,--version-script=\"${PROJECT_SOURCE_DIR}/../version_script.lds\"")
@@ -378,14 +404,36 @@ if (USE_STATIC_LIBSTDC)
set(LINK_FLAGS "${LINK_FLAGS} -static-libgcc -static-libstdc++")
endif()
-set(LINK_FLAGS "${LINK_FLAGS} \
- -Wl,-rpath,'$ORIGIN/.' \
- -L${PROJECT_SOURCE_DIR}/lib/linux32")
+set(LINK_FLAGS "${LINK_FLAGS} -Wl,-rpath,'$ORIGIN/.'")
+
+if (CMAKE_SIZEOF_VOID_P EQUAL 4)
+ set(LINK_FLAGS "${LINK_FLAGS} -L${PROJECT_SOURCE_DIR}/lib/linux32")
+endif()
set_target_properties(regamedll PROPERTIES
- OUTPUT_NAME cs
- PREFIX ""
COMPILE_FLAGS ${COMPILE_FLAGS}
LINK_FLAGS ${LINK_FLAGS}
- POSITION_INDEPENDENT_CODE OFF
)
+
+if (XASH_COMPAT)
+ if (CMAKE_SYSTEM_NAME STREQUAL "Android")
+ set_target_properties(regamedll PROPERTIES
+ OUTPUT_NAME server)
+ else()
+ set_target_properties(regamedll PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME cs${POSTFIX})
+ endif()
+else()
+ set_target_properties(regamedll PROPERTIES
+ OUTPUT_NAME cs
+ PREFIX ""
+ POSITION_INDEPENDENT_CODE OFF)
+endif()
+
+install(TARGETS regamedll
+ RUNTIME DESTINATION "cstrike/dlls/"
+ LIBRARY DESTINATION "cstrike/dlls/"
+ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE)
diff --git a/regamedll/cmake/LibraryNaming.cmake b/regamedll/cmake/LibraryNaming.cmake
new file mode 100644
index 000000000..a20529aed
--- /dev/null
+++ b/regamedll/cmake/LibraryNaming.cmake
@@ -0,0 +1,198 @@
+include(CheckSymbolExists)
+
+macro(check_build_target symbol)
+ check_symbol_exists(${symbol} "build.h" ${symbol})
+endmacro()
+
+macro(check_group_build_target symbol group)
+ if(NOT ${group})
+ check_build_target(${symbol})
+ if(${symbol})
+ set(${group} TRUE)
+ endif()
+ else()
+ set(${symbol} FALSE)
+ endif()
+endmacro()
+
+# So there is a problem:
+# 1. Number of these symbols only grows, as we support more and more ports
+# 2. CMake was written by morons and can't check these symbols in parallel
+# 3. MSVC is very slow at everything (startup, parsing, generating error)
+
+# Solution: group these symbols and set variable if one of them was found
+# this way we can reorder to reorder them by most common configurations
+# but we can't generate this list anymore! ... OR IS IT ???
+
+# Well, after reordering positions in engine's buildenums.h, we can partially autogenerate this list!
+# echo "check_build_target(XASH_64BIT)"
+# grep "#define PLATFORM" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 " XASH_PLATFORM)" }'
+# grep "#define ARCHITECTURE" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 " XASH_ARCHITECTURE)"
+# grep "#define ENDIAN" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 "_ENDIAN XASH_ENDIANNESS)"}'
+# echo "if(XASH_ARM)"
+# grep '^#undef XASH' build.h | grep "XASH_ARM[v_]" | awk '{ print "check_build_target(" $2 ")"}'
+# echo "endif()"
+# echo "if(XASH_RISCV)"
+# grep '^#undef XASH' build.h | grep "XASH_RISCV_" | awk '{ print "check_build_target(" $2 ")"}'
+# echo "endif()"
+
+# NOTE: Android must have priority over Linux to work correctly!
+
+set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}/public/")
+check_build_target(XASH_64BIT)
+check_group_build_target(XASH_WIN32 XASH_PLATFORM)
+check_group_build_target(XASH_ANDROID XASH_PLATFORM)
+check_group_build_target(XASH_LINUX XASH_PLATFORM)
+check_group_build_target(XASH_FREEBSD XASH_PLATFORM)
+check_group_build_target(XASH_APPLE XASH_PLATFORM)
+check_group_build_target(XASH_NETBSD XASH_PLATFORM)
+check_group_build_target(XASH_OPENBSD XASH_PLATFORM)
+check_group_build_target(XASH_EMSCRIPTEN XASH_PLATFORM)
+check_group_build_target(XASH_DOS4GW XASH_PLATFORM)
+check_group_build_target(XASH_HAIKU XASH_PLATFORM)
+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_WASI XASH_PLATFORM)
+check_group_build_target(XASH_SUNOS 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)
+check_group_build_target(XASH_MIPS XASH_ARCHITECTURE)
+check_group_build_target(XASH_PPC XASH_ARCHITECTURE)
+check_group_build_target(XASH_JS XASH_ARCHITECTURE)
+check_group_build_target(XASH_E2K XASH_ARCHITECTURE)
+check_group_build_target(XASH_RISCV XASH_ARCHITECTURE)
+check_group_build_target(XASH_LITTLE_ENDIAN XASH_ENDIANNESS)
+check_group_build_target(XASH_BIG_ENDIAN XASH_ENDIANNESS)
+if(XASH_ARM)
+check_build_target(XASH_ARM_HARDFP)
+check_build_target(XASH_ARM_SOFTFP)
+check_build_target(XASH_ARMv4)
+check_build_target(XASH_ARMv5)
+check_build_target(XASH_ARMv6)
+check_build_target(XASH_ARMv7)
+check_build_target(XASH_ARMv8)
+endif()
+if(XASH_RISCV)
+check_build_target(XASH_RISCV_DOUBLEFP)
+check_build_target(XASH_RISCV_SINGLEFP)
+check_build_target(XASH_RISCV_SOFTFP)
+endif()
+unset(CMAKE_REQUIRED_INCLUDES)
+
+# engine/common/build.c
+if(XASH_ANDROID)
+ set(BUILDOS "android")
+elseif(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE)
+ set(BUILDOS "") # no prefix for default OS
+elseif(XASH_FREEBSD)
+ set(BUILDOS "freebsd")
+elseif(XASH_NETBSD)
+ set(BUILDOS "netbsd")
+elseif(XASH_OPENBSD)
+ set(BUILDOS "openbsd")
+elseif(XASH_EMSCRIPTEN)
+ set(BUILDOS "emscripten")
+elseif(XASH_DOS4GW)
+ set(BUILDOS "DOS4GW")
+elseif(XASH_HAIKU)
+ set(BUILDOS "haiku")
+elseif(XASH_SERENITY)
+ set(BUILDOS "serenityos")
+elseif(XASH_NSWITCH)
+ set(BUILDOS "nswitch")
+elseif(XASH_PSVITA)
+ set(BUILDOS "psvita")
+elseif(XASH_IRIX)
+ set(BUILDOS "irix")
+elseif(XASH_WASI)
+ set(BUILDOS "wasi")
+elseif(XASH_SUNOS)
+ set(BUILDOS "sunos")
+else()
+ message(SEND_ERROR "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug")
+endif()
+
+if(XASH_AMD64)
+ set(BUILDARCH "amd64")
+elseif(XASH_X86)
+ if(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE)
+ set(BUILDARCH "") # no prefix for default OS
+ else()
+ set(BUILDARCH "i386")
+ endif()
+elseif(XASH_ARM AND XASH_64BIT)
+ set(BUILDARCH "arm64")
+elseif(XASH_ARM)
+ set(BUILDARCH "armv")
+ if(XASH_ARMv8)
+ set(BUILDARCH "${BUILDARCH}8_32")
+ elseif(XASH_ARMv7)
+ set(BUILDARCH "${BUILDARCH}7")
+ elseif(XASH_ARMv6)
+ set(BUILDARCH "${BUILDARCH}6")
+ elseif(XASH_ARMv5)
+ set(BUILDARCH "${BUILDARCH}5")
+ elseif(XASH_ARMv4)
+ set(BUILDARCH "${BUILDARCH}4")
+ else()
+ message(SEND_ERROR "Unknown ARM")
+ endif()
+
+ if(XASH_ARM_HARDFP)
+ set(BUILDARCH "${BUILDARCH}hf")
+ else()
+ set(BUILDARCH "${BUILDARCH}l")
+ endif()
+elseif(XASH_MIPS)
+ set(BUILDARCH "mips")
+ if(XASH_64BIT)
+ set(BUILDARCH "${BUILDARCH}64")
+ endif()
+
+ if(XASH_LITTLE_ENDIAN)
+ set(BUILDARCH "${BUILDARCH}el")
+ endif()
+elseif(XASH_RISCV)
+ set(BUILDARCH "riscv")
+ if(XASH_64BIT)
+ set(BUILDARCH "${BUILDARCH}64")
+ else()
+ set(BUILDARCH "${BUILDARCH}32")
+ endif()
+
+ if(XASH_RISCV_DOUBLEFP)
+ set(BUILDARCH "${BUILDARCH}d")
+ elseif(XASH_RISCV_SINGLEFP)
+ set(BUILDARCH "${BUILDARCH}f")
+ endif()
+elseif(XASH_JS)
+ set(BUILDARCH "javascript")
+elseif(XASH_E2K)
+ set(BUILDARCH "e2k")
+elseif(XASH_PPC)
+ set(BUILDARCH "ppc")
+ if(XASH_64BIT)
+ set(BUILDARCH "${BUILDARCH}64")
+ endif()
+
+ if(XASH_LITTLE_ENDIAN)
+ set(BUILDARCH "${BUILDARCH}el")
+ endif()
+else()
+ message(SEND_ERROR "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug")
+endif()
+
+if(BUILDOS STREQUAL "android")
+ set(POSTFIX "") # force disable for Android, as Android ports aren't distributed in normal way and doesn't follow library naming
+elseif(BUILDOS AND BUILDARCH)
+ set(POSTFIX "_${BUILDOS}_${BUILDARCH}")
+elseif(BUILDARCH)
+ set(POSTFIX "_${BUILDARCH}")
+else()
+ set(POSTFIX "")
+endif()
+
+message(STATUS "Library postfix: " ${POSTFIX})
diff --git a/regamedll/dlls/API/CAPI_Impl.cpp b/regamedll/dlls/API/CAPI_Impl.cpp
index 41175c838..ba40f1908 100644
--- a/regamedll/dlls/API/CAPI_Impl.cpp
+++ b/regamedll/dlls/API/CAPI_Impl.cpp
@@ -143,6 +143,66 @@ CGrenade *EXT_FUNC SpawnGrenade_api(WeaponIdType weaponId, entvars_t *pevOwner,
return nullptr;
}
+int EXT_FUNC UTIL_SharedRandomLong_api(unsigned int seed, int low, int high)
+{
+ return UTIL_SharedRandomLong(seed, low, high);
+}
+
+float EXT_FUNC UTIL_SharedRandomFloat_api(unsigned int seed, float low, float high)
+{
+ return UTIL_SharedRandomFloat(seed, low, high);
+}
+
+void EXT_FUNC UTIL_SetGroupTrace_api(int groupmask, int op)
+{
+ UTIL_SetGroupTrace(groupmask, op);
+}
+
+void EXT_FUNC UTIL_UnsetGroupTrace_api()
+{
+ UTIL_UnsetGroupTrace();
+}
+
+int EXT_FUNC UTIL_EntitiesInBox_api(CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask)
+{
+ return UTIL_EntitiesInBox(pList, listMax, mins, maxs, flagMask);
+}
+
+void EXT_FUNC UTIL_ScreenShake_api(const Vector ¢er, float amplitude, float frequency, float duration, float radius)
+{
+ UTIL_ScreenShake(center, amplitude, frequency, duration, radius);
+}
+
+void EXT_FUNC UTIL_ScreenFadeAll_api(const Vector &color, float fadeTime, float fadeHold, int alpha, int flags)
+{
+ UTIL_ScreenFadeAll(color, fadeTime, fadeHold, alpha, flags);
+}
+
+void EXT_FUNC UTIL_ScreenFade_api(CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags)
+{
+ UTIL_ScreenFade(pEntity, color, fadeTime, fadeHold, alpha, flags);
+}
+
+float EXT_FUNC UTIL_WaterLevel_api(const Vector &position, float minz, float maxz)
+{
+ return UTIL_WaterLevel(position, minz, maxz);
+}
+
+void EXT_FUNC UTIL_Bubbles_api(Vector mins, Vector maxs, int count)
+{
+ UTIL_Bubbles(mins, maxs, count);
+}
+
+void EXT_FUNC UTIL_BubbleTrail_api(Vector from, Vector to, int count)
+{
+ UTIL_BubbleTrail(from, to, count);
+}
+
+char EXT_FUNC UTIL_TextureHit_api(TraceResult *ptr, Vector vecSrc, Vector vecEnd)
+{
+ return UTIL_TextureHit(ptr, vecSrc, vecEnd);
+}
+
ReGameFuncs_t g_ReGameApiFuncs = {
CREATE_NAMED_ENTITY,
@@ -176,6 +236,19 @@ ReGameFuncs_t g_ReGameApiFuncs = {
TextureTypePlaySound_api,
CreateWeaponBox_api,
SpawnGrenade_api,
+
+ UTIL_SharedRandomLong_api,
+ UTIL_SharedRandomFloat_api,
+ UTIL_SetGroupTrace_api,
+ UTIL_UnsetGroupTrace_api,
+ UTIL_EntitiesInBox_api,
+ UTIL_ScreenShake_api,
+ UTIL_ScreenFadeAll_api,
+ UTIL_ScreenFade_api,
+ UTIL_WaterLevel_api,
+ UTIL_Bubbles_api,
+ UTIL_BubbleTrail_api,
+ UTIL_TextureHit_api,
};
GAMEHOOK_REGISTRY(CBasePlayer_Spawn);
@@ -336,6 +409,8 @@ GAMEHOOK_REGISTRY(CSGameRules_SendDeathMessage);
GAMEHOOK_REGISTRY(CBasePlayer_PlayerDeathThink);
GAMEHOOK_REGISTRY(CBasePlayer_Observer_Think);
GAMEHOOK_REGISTRY(CBasePlayer_RemoveAllItems);
+GAMEHOOK_REGISTRY(CBasePlayer_UpdateStatusBar);
+GAMEHOOK_REGISTRY(CBasePlayer_TakeDamageImpulse);
int CReGameApi::GetMajorVersion() {
return REGAMEDLL_API_VERSION_MAJOR;
diff --git a/regamedll/dlls/API/CAPI_Impl.h b/regamedll/dlls/API/CAPI_Impl.h
index 2635be5b9..727fdf9e4 100644
--- a/regamedll/dlls/API/CAPI_Impl.h
+++ b/regamedll/dlls/API/CAPI_Impl.h
@@ -749,6 +749,14 @@ typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBase
typedef IHookChainClassImpl CReGameHook_CBasePlayer_RemoveAllItems;
typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_RemoveAllItems;
+// CBasePlayer::UpdateStatusBar hook
+typedef IHookChainClassImpl CReGameHook_CBasePlayer_UpdateStatusBar;
+typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_UpdateStatusBar;
+
+// CBasePlayer::TakeDamageImpulse hook
+typedef IHookChainClassImpl CReGameHook_CBasePlayer_TakeDamageImpulse;
+typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_TakeDamageImpulse;
+
class CReGameHookchains: public IReGameHookchains {
public:
// CBasePlayer virtual
@@ -910,6 +918,8 @@ class CReGameHookchains: public IReGameHookchains {
CReGameHookRegistry_CBasePlayer_PlayerDeathThink m_CBasePlayer_PlayerDeathThink;
CReGameHookRegistry_CBasePlayer_Observer_Think m_CBasePlayer_Observer_Think;
CReGameHookRegistry_CBasePlayer_RemoveAllItems m_CBasePlayer_RemoveAllItems;
+ CReGameHookRegistry_CBasePlayer_UpdateStatusBar m_CBasePlayer_UpdateStatusBar;
+ CReGameHookRegistry_CBasePlayer_TakeDamageImpulse m_CBasePlayer_TakeDamageImpulse;
public:
virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn();
@@ -1070,6 +1080,8 @@ class CReGameHookchains: public IReGameHookchains {
virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink();
virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think();
virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems();
+ virtual IReGameHookRegistry_CBasePlayer_UpdateStatusBar *CBasePlayer_UpdateStatusBar();
+ virtual IReGameHookRegistry_CBasePlayer_TakeDamageImpulse *CBasePlayer_TakeDamageImpulse();
};
extern CReGameHookchains g_ReGameHookchains;
diff --git a/regamedll/dlls/API/CSPlayer.cpp b/regamedll/dlls/API/CSPlayer.cpp
index 8ebf79306..cab27a473 100644
--- a/regamedll/dlls/API/CSPlayer.cpp
+++ b/regamedll/dlls/API/CSPlayer.cpp
@@ -412,6 +412,11 @@ EXT_FUNC void CCSPlayer::Observer_SetMode(int iMode)
BasePlayer()->Observer_SetMode(iMode);
}
+EXT_FUNC void CCSPlayer::Observer_FindNextPlayer(bool bReverse, const char *name)
+{
+ BasePlayer()->Observer_FindNextPlayer(bReverse, name);
+}
+
EXT_FUNC bool CCSPlayer::SelectSpawnSpot(const char *pEntClassName, CBaseEntity *&pSpot)
{
return BasePlayer()->SelectSpawnSpot(pEntClassName, pSpot);
@@ -534,6 +539,11 @@ EXT_FUNC bool CCSPlayer::CheckActivityInGame()
return (fabs(deltaYaw) >= 0.1f && fabs(deltaPitch) >= 0.1f);
}
+EXT_FUNC void CCSPlayer::TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier)
+{
+ BasePlayer()->TakeDamageImpulse(pAttacker, flKnockbackForce, flVelModifier);
+}
+
void CCSPlayer::ResetVars()
{
m_szModel[0] = '\0';
diff --git a/regamedll/dlls/ammo.cpp b/regamedll/dlls/ammo.cpp
index 1df3622cc..8c264ac78 100644
--- a/regamedll/dlls/ammo.cpp
+++ b/regamedll/dlls/ammo.cpp
@@ -24,7 +24,7 @@ void CBasePlayerAmmo::Spawn()
BOOL CBasePlayerAmmo::AddAmmo(CBaseEntity *pOther)
{
auto ammoInfo = GetAmmoInfo(pev->classname);
- if (pOther->GiveAmmo(ammoInfo->buyClipSize, ammoInfo->ammoName2) == -1)
+ if (!ammoInfo || pOther->GiveAmmo(ammoInfo->buyClipSize, ammoInfo->ammoName2) == -1)
{
return FALSE;
}
diff --git a/regamedll/dlls/animation.cpp b/regamedll/dlls/animation.cpp
index 7d5df6f07..fbf6a1bb6 100644
--- a/regamedll/dlls/animation.cpp
+++ b/regamedll/dlls/animation.cpp
@@ -547,7 +547,9 @@ void AngleQuaternion(vec_t *angles, vec_t *quaternion)
{
static const ALIGN16_BEG size_t ps_signmask[4] ALIGN16_END = { 0x80000000, 0, 0x80000000, 0 };
- __m128 a = _mm_loadu_ps(angles);
+ vec4_t _ps_angles = { angles[0], angles[1], angles[2], 0.0f };
+
+ __m128 a = _mm_loadu_ps(_ps_angles);
a = _mm_mul_ps(a, _mm_load_ps(_ps_0p5)); //a *= 0.5
__m128 s, c;
sincos_ps(a, &s, &c);
diff --git a/regamedll/dlls/bot/cs_bot.cpp b/regamedll/dlls/bot/cs_bot.cpp
index dd85448c6..2302e4611 100644
--- a/regamedll/dlls/bot/cs_bot.cpp
+++ b/regamedll/dlls/bot/cs_bot.cpp
@@ -900,3 +900,129 @@ float CCSBot::GetRangeToFarthestEscortedHostage() const
return away.m_farRange;
}
+
+// Remove all occurrences of a given area from the path list
+void CCSBot::RemovePath(CNavArea *area)
+{
+ int i = 0;
+ while (i < m_pathLength)
+ {
+ if (m_path[i].area == area)
+ {
+ // If this area is linked to a ladder, clear the reference
+ if (m_path[i].ladder == m_pathLadder)
+ m_pathLadder = nullptr;
+
+ m_pathLength--;
+
+ // adjust the current path index if the removed element is being used
+ if (i == m_pathIndex)
+ {
+ if (i > 0)
+ m_pathIndex = i - 1;
+ else
+ m_pathIndex = 0;
+ }
+
+ if (m_pathLength != i)
+ Q_memmove(&m_path[i], &m_path[i + 1], (m_pathLength - i) * sizeof(m_path[0]));
+
+ // clear the slot
+ Q_memset(&m_path[m_pathLength], 0, sizeof(m_path[m_pathLength]));
+ }
+ else
+ {
+ i++;
+ }
+ }
+}
+
+// Remove a hiding spot from the checked spots list
+void CCSBot::RemoveHidingSpot(HidingSpot *spot)
+{
+ int i = 0;
+ while (i < m_checkedHidingSpotCount)
+ {
+ if (m_checkedHidingSpot[i].spot == spot)
+ {
+ m_checkedHidingSpotCount--;
+
+ if (m_checkedHidingSpotCount != i)
+ Q_memmove(&m_checkedHidingSpot[i], &m_checkedHidingSpot[i + 1], (m_checkedHidingSpotCount - i) * sizeof(m_checkedHidingSpot[0]));
+
+ // clear the slot
+ Q_memset(&m_checkedHidingSpot[m_checkedHidingSpotCount], 0, sizeof(m_checkedHidingSpot[m_checkedHidingSpotCount]));
+ }
+ else
+ {
+ i++;
+ }
+ }
+}
+
+// Handle navigation-related cleanup when a nav area, spot, or encounter is destroyed
+void CCSBot::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead)
+{
+ switch (navNotifyType)
+ {
+ case NAV_NOTIFY_DESTROY_AREA:
+ {
+ CNavArea *area = static_cast(dead);
+
+ // If the destroyed area was linked to a spot encounter, clear it
+ if (m_spotEncounter)
+ {
+ if (m_spotEncounter->from.area == area || m_spotEncounter->to.area == area)
+ m_spotEncounter = nullptr;
+ }
+
+ RemovePath(area);
+
+ // Invalidate any references to the destroyed area
+
+ if (m_noiseArea == area)
+ m_noiseArea = nullptr;
+
+ if (m_currentArea == area)
+ m_currentArea = nullptr;
+
+ if (m_lastKnownArea == area)
+ m_lastKnownArea = nullptr;
+
+ if (m_hideState.GetSearchArea() == area)
+ m_hideState.SetSearchArea(nullptr);
+
+ if (m_huntState.GetHuntArea() == area)
+ m_huntState.ClearHuntArea();
+
+ break;
+ }
+ case NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER:
+ {
+ CNavArea *area = static_cast(dead);
+
+ // Remove the encounter if it references the destroyed area
+ if (m_spotEncounter && area->HasSpotEncounter(m_spotEncounter))
+ m_spotEncounter = nullptr;
+
+ break;
+ }
+ case NAV_NOTIFY_DESTROY_SPOT:
+ {
+ HidingSpot *spot = static_cast(dead);
+
+ // Remove the destroyed hiding spot from the spot order list
+ if (m_spotEncounter)
+ {
+ SpotOrderList &spotOrderList = m_spotEncounter->spotList;
+ spotOrderList.erase(std::remove_if(spotOrderList.begin(), spotOrderList.end(), [&](SpotOrder &spotOrder) {
+ return spotOrder.spot == spot;
+ }
+ ), spotOrderList.end());
+ }
+
+ RemoveHidingSpot(spot);
+ break;
+ }
+ }
+}
diff --git a/regamedll/dlls/bot/cs_bot.h b/regamedll/dlls/bot/cs_bot.h
index 9670744f9..0ba299857 100644
--- a/regamedll/dlls/bot/cs_bot.h
+++ b/regamedll/dlls/bot/cs_bot.h
@@ -71,6 +71,7 @@ class HuntState: public BotState
virtual const char *GetName() const { return "Hunt"; }
void ClearHuntArea() { m_huntArea = nullptr; }
+ CNavArea *GetHuntArea() { return m_huntArea; }
private:
CNavArea *m_huntArea;
@@ -204,6 +205,7 @@ class HideState: public BotState
const Vector &GetHidingSpot() const { return m_hidingSpot; }
void SetSearchArea(CNavArea *area) { m_searchFromArea = area; }
+ CNavArea *GetSearchArea() { return m_searchFromArea; }
void SetSearchRange(float range) { m_range = range; }
void SetDuration(float time) { m_duration = time; }
@@ -533,12 +535,21 @@ class CCSBot: public CBot
bool IsAwareOfEnemyDeath() const; // return true if we *noticed* that our enemy died
int GetLastVictimID() const; // return the ID (entindex) of the last victim we killed, or zero
+#ifdef REGAMEDLL_ADD
+ bool CanSeeSniper(void) const; ///< return true if we can see an enemy sniper
+ bool HasSeenSniperRecently(void) const; ///< return true if we have seen a sniper recently
+#endif
+
// navigation
bool HasPath() const;
void DestroyPath();
float GetFeetZ() const; // return Z of bottom of feet
+ void OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead);
+ void RemovePath(CNavArea *area);
+ void RemoveHidingSpot(HidingSpot *spot);
+
enum PathResult
{
PROGRESSING, // we are moving along the path
@@ -921,6 +932,11 @@ class CCSBot: public CBot
float m_fireWeaponTimestamp;
+#ifdef REGAMEDLL_ADD
+ bool m_isEnemySniperVisible; ///< do we see an enemy sniper right now
+ CountdownTimer m_sawEnemySniperTimer; ///< tracking time since saw enemy sniper
+#endif
+
// reaction time system
enum { MAX_ENEMY_QUEUE = 20 };
struct ReactionState
@@ -1109,6 +1125,11 @@ inline bool CCSBot::IsAtBombsite()
inline CCSBot::MoraleType CCSBot::GetMorale() const
{
+#ifdef REGAMEDLL_ADD
+ if (cv_bot_excellent_morale.value != 0.0f)
+ return EXCELLENT;
+#endif
+
return m_morale;
}
@@ -1250,6 +1271,18 @@ inline int CCSBot::GetLastVictimID() const
return m_lastVictimID;
}
+#ifdef REGAMEDLL_ADD
+inline bool CCSBot::CanSeeSniper(void) const
+{
+ return m_isEnemySniperVisible;
+}
+
+inline bool CCSBot::HasSeenSniperRecently(void) const
+{
+ return !m_sawEnemySniperTimer.IsElapsed();
+}
+#endif
+
inline bool CCSBot::HasPath() const
{
return m_pathLength != 0;
diff --git a/regamedll/dlls/bot/cs_bot_chatter.cpp b/regamedll/dlls/bot/cs_bot_chatter.cpp
index 1476d8d58..d48898ae7 100644
--- a/regamedll/dlls/bot/cs_bot_chatter.cpp
+++ b/regamedll/dlls/bot/cs_bot_chatter.cpp
@@ -246,6 +246,17 @@ void BotHostageBeingTakenMeme::Interpret(CCSBot *pSender, CCSBot *pReceiver) con
pReceiver->GetChatter()->Say("Affirmative");
}
+#ifdef REGAMEDLL_ADD
+//---------------------------------------------------------------------------------------------------------------
+/**
+ * A teammate warned about snipers, so we shouldn't warn again for awhile
+ */
+void BotWarnSniperMeme::Interpret(CCSBot* sender, CCSBot* receiver) const
+{
+ receiver->GetChatter()->FriendSpottedSniper();
+}
+#endif
+
BotSpeakable::BotSpeakable()
{
m_phrase = nullptr;
@@ -464,6 +475,7 @@ bool BotPhraseManager::Initialize(const char *filename, int bankIndex)
phraseData = SharedParse(phraseData);
if (!phraseData)
{
+ if (phrase) delete phrase;
CONSOLE_ECHO("Error parsing '%s' - expected identifier\n", filename);
FREE_FILE(phraseDataFile);
return false;
@@ -1269,6 +1281,9 @@ void BotChatterInterface::Reset()
m_planInterval.Invalidate();
m_encourageTimer.Invalidate();
m_escortingHostageTimer.Invalidate();
+#ifdef REGAMEDLL_ADD
+ m_warnSniperTimer.Invalidate();
+#endif
}
// Register a statement for speaking
@@ -1625,6 +1640,42 @@ void BotChatterInterface::EnemySpotted()
AddStatement(say);
}
+#ifdef REGAMEDLL_ADD
+//---------------------------------------------------------------------------------------------------------------
+/**
+ * If a friend warned of snipers, don't warn again for awhile
+ */
+void BotChatterInterface::FriendSpottedSniper(void)
+{
+ m_warnSniperTimer.Start(60.0f);
+}
+
+//---------------------------------------------------------------------------------------------------------------
+/**
+ * Warn of an enemy sniper
+ */
+void BotChatterInterface::SpottedSniper(void)
+{
+ if (!m_warnSniperTimer.IsElapsed())
+ {
+ return;
+ }
+
+ if (m_me->GetFriendsRemaining() == 0)
+ {
+ // no-one to warn
+ return;
+ }
+
+ BotStatement* say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("SniperWarning"));
+ say->AttachMeme(new BotWarnSniperMeme());
+
+ AddStatement(say);
+}
+#endif
+
NOXREF void BotChatterInterface::Clear(Place place)
{
BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
diff --git a/regamedll/dlls/bot/cs_bot_chatter.h b/regamedll/dlls/bot/cs_bot_chatter.h
index 4a4591cf6..8d3a5baa0 100644
--- a/regamedll/dlls/bot/cs_bot_chatter.h
+++ b/regamedll/dlls/bot/cs_bot_chatter.h
@@ -140,6 +140,14 @@ class BotRequestReportMeme: public BotMeme
virtual void Interpret(CCSBot *pSender, CCSBot *pReceiver) const; // cause the given bot to act on this meme
};
+#ifdef REGAMEDLL_ADD
+class BotWarnSniperMeme : public BotMeme
+{
+public:
+ virtual void Interpret(CCSBot* sender, CCSBot* receiver) const; ///< cause the given bot to act on this meme
+};
+#endif
+
enum BotStatementType
{
REPORT_VISIBLE_ENEMIES,
@@ -531,6 +539,10 @@ class BotChatterInterface
void KilledFriend();
void FriendlyFire();
+#ifdef REGAMEDLL_ADD
+ void SpottedSniper(void);
+ void FriendSpottedSniper(void);
+#endif
bool SeesAtLeastOneEnemy() const { return m_seeAtLeastOneEnemy; }
private:
@@ -557,6 +569,9 @@ class BotChatterInterface
CountdownTimer m_spottedLooseBombTimer;
CountdownTimer m_heardNoiseTimer;
CountdownTimer m_escortingHostageTimer;
+#ifdef REGAMEDLL_ADD
+ CountdownTimer m_warnSniperTimer;
+#endif
};
inline BotChatterInterface::VerbosityType BotChatterInterface::GetVerbosity() const
diff --git a/regamedll/dlls/bot/cs_bot_event.cpp b/regamedll/dlls/bot/cs_bot_event.cpp
index 199616659..70411c8e5 100644
--- a/regamedll/dlls/bot/cs_bot_event.cpp
+++ b/regamedll/dlls/bot/cs_bot_event.cpp
@@ -56,6 +56,11 @@ void CCSBot::OnEvent(GameEventType event, CBaseEntity *pEntity, CBaseEntity *pOt
DecreaseMorale();
}
break;
+#ifdef REGAMEDLL_FIXES
+ case EVENT_NEW_MATCH:
+ m_morale = POSITIVE; // starting a new round makes everyone a little happy
+ break;
+#endif
}
if (!IsAlive())
diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp
index a6503e901..2db6b02d5 100644
--- a/regamedll/dlls/bot/cs_bot_init.cpp
+++ b/regamedll/dlls/bot/cs_bot_init.cpp
@@ -28,6 +28,7 @@
#include "precompiled.h"
+cvar_t cv_bot_enable = { "bot_enable", "0", 0, 0.0f, nullptr };
cvar_t cv_bot_traceview = { "bot_traceview", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_stop = { "bot_stop", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_show_nav = { "bot_show_nav", "0", FCVAR_SERVER, 0.0f, nullptr };
@@ -64,6 +65,7 @@ cvar_t cv_bot_join_delay = { "bot_join_delay", "0", FCVAR_SERVER, 0.
cvar_t cv_bot_freeze = { "bot_freeze", "0", 0, 0.0f, nullptr };
cvar_t cv_bot_mimic = { "bot_mimic", "0", 0, 0.0f, nullptr };
cvar_t cv_bot_mimic_yaw_offset = { "bot_mimic_yaw_offset", "0", 0, 0.0f, nullptr };
+cvar_t cv_bot_excellent_morale = { "bot_excellent_morale", "0", 0, 0.0f, nullptr };
#else
// Migrated to bot_quota_mode, use "match"
cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr };
@@ -135,6 +137,7 @@ void Bot_RegisterCVars()
CVAR_REGISTER(&cv_bot_freeze);
CVAR_REGISTER(&cv_bot_mimic);
CVAR_REGISTER(&cv_bot_mimic_yaw_offset);
+ CVAR_REGISTER(&cv_bot_excellent_morale);
#endif
}
@@ -193,6 +196,11 @@ void CCSBot::ResetValues()
m_currentArea = nullptr;
m_lastKnownArea = nullptr;
+#ifdef REGAMEDLL_ADD
+ m_isEnemySniperVisible = false;
+ m_sawEnemySniperTimer.Invalidate();
+#endif
+
m_avoidFriendTimer.Invalidate();
m_isFriendInTheWay = false;
m_isWaitingBehindFriend = false;
@@ -329,10 +337,10 @@ void CCSBot::ResetValues()
// NOTE: For some reason, this can be called twice when a bot is added.
void CCSBot::SpawnBot()
{
- TheCSBots()->ValidateMapData();
+ TheCSBots()->LoadNavigationMap();
ResetValues();
- Q_strcpy(m_name, STRING(pev->netname));
+ Q_strlcpy(m_name, STRING(pev->netname));
SetState(&m_buyState);
SetTouch(&CCSBot::BotTouch);
diff --git a/regamedll/dlls/bot/cs_bot_init.h b/regamedll/dlls/bot/cs_bot_init.h
index 8687e3f7f..691c518f2 100644
--- a/regamedll/dlls/bot/cs_bot_init.h
+++ b/regamedll/dlls/bot/cs_bot_init.h
@@ -28,6 +28,7 @@
#pragma once
+extern cvar_t cv_bot_enable;
extern cvar_t cv_bot_traceview;
extern cvar_t cv_bot_stop;
extern cvar_t cv_bot_show_nav;
@@ -64,6 +65,7 @@ extern cvar_t cv_bot_join_delay;
extern cvar_t cv_bot_freeze;
extern cvar_t cv_bot_mimic;
extern cvar_t cv_bot_mimic_yaw_offset;
+extern cvar_t cv_bot_excellent_morale;
#else
extern cvar_t cv_bot_quota_match;
#endif
diff --git a/regamedll/dlls/bot/cs_bot_learn.cpp b/regamedll/dlls/bot/cs_bot_learn.cpp
index 76edded7a..e68a77a5e 100644
--- a/regamedll/dlls/bot/cs_bot_learn.cpp
+++ b/regamedll/dlls/bot/cs_bot_learn.cpp
@@ -477,31 +477,24 @@ void CCSBot::StartSaveProcess()
void CCSBot::UpdateSaveProcess()
{
- char filename[256];
- char msg[256];
- char cmd[128];
+ char gd[64]{};
+ GET_GAME_DIR(gd);
- GET_GAME_DIR(filename);
-
- Q_strcat(filename, "\\");
- Q_strcat(filename, TheBots->GetNavMapFilename());
-
- HintMessageToAllPlayers("Saving...");
+ char filename[MAX_OSPATH];
+ Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, TheBots->GetNavMapFilename());
SaveNavigationMap(filename);
+ char msg[256]{};
Q_snprintf(msg, sizeof(msg), "Navigation file '%s' saved.", filename);
HintMessageToAllPlayers(msg);
+ CONSOLE_ECHO("%s\n", msg);
hideProgressMeter();
StartNormalProcess();
-#ifndef REGAMEDLL_FIXES
- Q_snprintf(cmd, sizeof(cmd), "map %s\n", STRING(gpGlobals->mapname));
-#else
- Q_snprintf(cmd, sizeof(cmd), "changelevel %s\n", STRING(gpGlobals->mapname));
-#endif
-
- SERVER_COMMAND(cmd);
+ // tell bot manager that the analysis is completed
+ if (TheCSBots())
+ TheCSBots()->AnalysisCompleted();
}
void CCSBot::StartNormalProcess()
diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp
index b4391be7f..8c7c7a1fc 100644
--- a/regamedll/dlls/bot/cs_bot_manager.cpp
+++ b/regamedll/dlls/bot/cs_bot_manager.cpp
@@ -231,13 +231,12 @@ bool CCSBotManager::IsOnOffense(CBasePlayer *pPlayer) const
// Invoked when a map has just been loaded
void CCSBotManager::ServerActivate()
{
- DestroyNavigationMap();
m_isMapDataLoaded = false;
m_zoneCount = 0;
m_gameScenario = SCENARIO_DEATHMATCH;
- ValidateMapData();
+ LoadNavigationMap();
RestartRound();
m_isLearningMap = false;
@@ -578,18 +577,21 @@ void CCSBotManager::ServerCommand(const char *pcmd)
}
else if (FStrEq(pcmd, "bot_nav_save"))
{
- GET_GAME_DIR(buffer);
- Q_strcat(buffer, "\\");
- Q_strcat(buffer, CBotManager::GetNavMapFilename());
+ char gd[64]{};
+ GET_GAME_DIR(gd);
+
+ char filename[MAX_OSPATH];
+ Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, CBotManager::GetNavMapFilename());
- if (SaveNavigationMap(buffer))
- CONSOLE_ECHO("Navigation map '%s' saved.\n", buffer);
+ if (SaveNavigationMap(filename))
+ CONSOLE_ECHO("Navigation map '%s' saved.\n", filename);
else
- CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", buffer);
+ CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", filename);
}
else if (FStrEq(pcmd, "bot_nav_load"))
{
- ValidateMapData();
+ m_isMapDataLoaded = false; // force nav reload
+ LoadNavigationMap();
}
else if (FStrEq(pcmd, "bot_nav_use_place"))
{
@@ -887,12 +889,10 @@ void CCSBotManager::MaintainBotQuota()
if (m_isLearningMap)
return;
- int totalHumansInGame = UTIL_HumansInGame();
- int humanPlayersInGame = UTIL_HumansInGame(IGNORE_SPECTATORS);
- int spectatorPlayersInGame = UTIL_SpectatorsInGame();
+ int humanPlayersInGame = UTIL_HumansInGame();
// don't add bots until local player has been registered, to make sure he's player ID #1
- if (!IS_DEDICATED_SERVER() && totalHumansInGame == 0)
+ if (!IS_DEDICATED_SERVER() && humanPlayersInGame == 0)
return;
int desiredBotCount = int(cv_bot_quota.value);
@@ -947,7 +947,7 @@ void CCSBotManager::MaintainBotQuota()
// wait for a player to join, if necessary
if (cv_bot_join_after_player.value > 0.0)
{
- if (humanPlayersInGame == 0 && spectatorPlayersInGame == 0)
+ if (humanPlayersInGame == 0)
desiredBotCount = 0;
}
@@ -1144,22 +1144,232 @@ class CollectOverlappingAreas
CCSBotManager::Zone *m_zone;
};
-// Search the map entities to determine the game scenario and define important zones.
-void CCSBotManager::ValidateMapData()
+LINK_ENTITY_TO_CLASS(info_spawn_point, CPointEntity, CCSPointEntity)
+
+inline bool IsFreeSpace(Vector vecOrigin, int iHullNumber, edict_t *pSkipEnt = nullptr)
+{
+ if (UTIL_PointContents(vecOrigin) != CONTENTS_EMPTY)
+ return false;
+
+ TraceResult trace;
+ UTIL_TraceHull(vecOrigin, vecOrigin, dont_ignore_monsters, iHullNumber, pSkipEnt, &trace);
+
+ return (!trace.fStartSolid && !trace.fAllSolid && trace.fInOpen);
+}
+
+inline bool pointInRadius(Vector vecOrigin, float radius)
+{
+ CBaseEntity *pEntity = nullptr;
+ while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecOrigin, radius)))
+ {
+ if (!UTIL_IsValidEntity(pEntity->edict()))
+ continue; // ignore the entity marked for deletion
+
+ if (FClassnameIs(pEntity->edict(), "info_spawn_point"))
+ return true;
+ }
+
+ return false;
+}
+
+// a simple algorithm that searches for the farthest point (so that the player does not look at the wall)
+inline bool GetIdealLookYawForSpawnPoint(const Vector &vecStart, float &flIdealLookYaw)
+{
+ const float ANGLE_STEP = 30.0f;
+ float bestDistance = 0.0f;
+
+ for (float angleYaw = 0.0f; angleYaw <= 360.0f; angleYaw += ANGLE_STEP)
+ {
+ TraceResult tr;
+ UTIL_MakeVectors(Vector(0, angleYaw, 0));
+
+ Vector vecEnd(vecStart + gpGlobals->v_forward * 8192);
+ UTIL_TraceLine(vecStart, vecEnd, ignore_monsters, nullptr, &tr);
+
+ float distance = (vecStart - tr.vecEndPos).Length();
+ if (distance > bestDistance)
+ {
+ bestDistance = distance;
+ flIdealLookYaw = angleYaw;
+ }
+ }
+
+ return bestDistance > 0.0f;
+}
+
+// this function from leaked csgo sources 2020y
+inline bool IsValidArea(CNavArea *area)
+{
+ ShortestPathCost cost;
+ bool bNotOrphaned;
+
+ // check that we can path from the nav area to a ct spawner to confirm it isn't orphaned.
+ CBaseEntity *CTSpawn = UTIL_FindEntityByClassname(nullptr, "info_player_start");
+
+ if (CTSpawn)
+ {
+ CNavArea *CTSpawnArea = TheNavAreaGrid.GetNearestNavArea(&CTSpawn->pev->origin);
+ bNotOrphaned = NavAreaBuildPath(area, CTSpawnArea, nullptr, cost);
+
+ if (bNotOrphaned)
+ return true;
+ }
+
+ // double check that we can path from the nav area to a t spawner to confirm it isn't orphaned.
+ CBaseEntity *TSpawn = UTIL_FindEntityByClassname(nullptr, "info_player_deathmatch");
+
+ if (TSpawn)
+ {
+ CNavArea *TSpawnArea = TheNavAreaGrid.GetNearestNavArea(&TSpawn->pev->origin);
+ bNotOrphaned = NavAreaBuildPath(area, TSpawnArea, nullptr, cost);
+
+ if (bNotOrphaned)
+ return true;
+ }
+
+ return false;
+}
+
+#ifdef REGAMEDLL_ADD
+
+// Generates spawn points (info_spawn_point entities) for players and bots based on the navigation map data
+// It uses the navigation areas to find valid spots for spawn points considering factors like area size, slope,
+// available free space, and distance from other spawn points.
+void GenerateSpawnPointsFromNavData()
{
+ // Remove any existing spawn points
+ UTIL_RemoveOther("info_spawn_point");
+
+ const int MAX_SPAWNS_POINTS = 128; // Max allowed spawn points
+
+ const float MAX_SLOPE = 0.85f; // Maximum slope allowed for a spawn point
+ const float MIN_AREA_SIZE = 32.0f; // Minimum area size for a valid spawn point
+ const float MIN_NEARBY_SPAWNPOINT = 128.0f; // Minimum distance between spawn point
+
+ // Total number of spawn points generated
+ int totalSpawns = 0;
+
+ for (CNavArea *area : TheNavAreaList)
+ {
+ if (totalSpawns >= MAX_SPAWNS_POINTS)
+ break;
+
+ if (!area)
+ continue;
+
+ // Skip areas that are too small
+ if (area->GetSizeX() < MIN_AREA_SIZE || area->GetSizeY() < MIN_AREA_SIZE)
+ continue;
+
+ // Skip areas with unwanted attributes (jump, crouch, etc.)
+ if (area->GetAttributes() != 0)
+ continue;
+
+ // Skip areas with steep slopes
+ if (area->GetAreaSlope() < MAX_SLOPE)
+ {
+ //CONSOLE_ECHO("Skip area slope: %0.3f\n", area->GetAreaSlope());
+ continue;
+ }
+
+ // Calculate the spawn point position above the area center
+ Vector vecOrigin = *area->GetCenter() + Vector(0, 0, HalfHumanHeight + 5);
+
+ // Ensure there is free space at the calculated position
+ if (!IsFreeSpace(vecOrigin, human_hull))
+ {
+ //CONSOLE_ECHO("No free space!\n");
+ continue;
+ }
+
+ if (pointInRadius(vecOrigin, MIN_NEARBY_SPAWNPOINT))
+ continue; // spawn point is too close to others
+
+ if (!IsValidArea(area))
+ continue;
+
+ // Calculate ideal spawn point yaw angle
+ float flIdealSpawnPointYaw = 0.0f;
+ if (GetIdealLookYawForSpawnPoint(vecOrigin, flIdealSpawnPointYaw))
+ {
+ CBaseEntity *pPoint = CBaseEntity::Create("info_spawn_point", vecOrigin, Vector(0, flIdealSpawnPointYaw, 0), nullptr);
+ if (pPoint)
+ {
+ totalSpawns++;
+ //CONSOLE_ECHO("Add spawn at x:%f y:%f z:%f with angle %0.1f slope %0.3f \n", vecOrigin.x, vecOrigin.y, vecOrigin.z, bestAngle.y, area->GetAreaSlope());
+
+ // use only for debugging
+ if (randomspawn.value > 1.0f)
+ {
+ SET_MODEL(ENT(pPoint->pev), "models/player.mdl");
+ pPoint->pev->sequence = ACT_IDLE;
+ pPoint->pev->rendermode = kRenderTransAdd;
+ pPoint->pev->renderamt = 150.0f;
+ }
+ }
+ }
+ }
+
+ CONSOLE_ECHO("Total spawns points: %i\n", totalSpawns);
+}
+
+#endif
+
+// Load the map's navigation data
+bool CCSBotManager::LoadNavigationMap()
+{
+ // check if the map data is already loaded or if bots are not allowed
if (m_isMapDataLoaded || !AreBotsAllowed())
- return;
+ return false;
m_isMapDataLoaded = true;
- if (LoadNavigationMap())
+ // Clear navigation map data from previous map
+ DestroyNavigationMap();
+
+ // Try to load the map's navigation file
+ NavErrorType navStatus = ::LoadNavigationMap();
+ if (navStatus != NAV_OK)
{
- CONSOLE_ECHO("Failed to load navigation map.\n");
- return;
+ CONSOLE_ECHO("ERROR: Failed to load 'maps/%s.nav' file navigation map!\n", STRING(gpGlobals->mapname));
+
+ switch (navStatus)
+ {
+ case NAV_CANT_ACCESS_FILE:
+ CONSOLE_ECHO("\tNavigation file not found or access denied.\n");
+ break;
+ case NAV_INVALID_FILE:
+ CONSOLE_ECHO("\tInvalid navigation file format.\n");
+ break;
+ case NAV_BAD_FILE_VERSION:
+ CONSOLE_ECHO("\tBad navigation file version.\n");
+ break;
+ case NAV_CORRUPT_DATA:
+ CONSOLE_ECHO("\tCorrupted navigation data detected.\n");
+ break;
+ default:
+ break;
+ }
+
+ if (navStatus != NAV_CANT_ACCESS_FILE)
+ CONSOLE_ECHO("\tTry regenerating it using the command: bot_nav_analyze\n");
+
+ return false;
}
- CONSOLE_ECHO("Navigation map loaded.\n");
+ // Determine the scenario for the current map (e.g., bomb defuse, hostage rescue etc)
+ DetermineMapScenario();
+
+#ifdef REGAMEDLL_ADD
+ GenerateSpawnPointsFromNavData();
+#endif
+
+ return true;
+}
+// Search the map entities to determine the game scenario and define important zones.
+void CCSBotManager::DetermineMapScenario()
+{
m_zoneCount = 0;
m_gameScenario = SCENARIO_DEATHMATCH;
@@ -1211,6 +1421,13 @@ void CCSBotManager::ValidateMapData()
found = true;
isLegacy = false;
}
+ else if (FClassnameIs(pEntity->pev, "func_escapezone"))
+ {
+ m_gameScenario = SCENARIO_ESCAPE;
+ found = true;
+ isLegacy = false;
+ }
+
if (found)
{
@@ -1292,6 +1509,59 @@ void CCSBotManager::ValidateMapData()
}
}
+// Tell all bots that the given nav data no longer exists
+// This function is called when a part of the map or the nav data is destroyed
+void CCSBotManager::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead)
+{
+ for (int i = 1; i <= gpGlobals->maxClients; i++)
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!pPlayer->IsBot())
+ continue;
+
+ // Notify the bot about the destroyed nav data
+ CCSBot *pBot = static_cast(pPlayer);
+ pBot->OnDestroyNavDataNotify(navNotifyType, dead);
+ }
+}
+
+// Called when the map analysis process has completed
+// This function makes sure all bots are removed from the map analysis process
+// and are reset to normal bot behavior. It also reloads the navigation map
+// and triggers a game restart after the analysis is completed
+void CCSBotManager::AnalysisCompleted()
+{
+ // Ensure that all bots are no longer involved in map analysis and start their normal process
+ for (int i = 1; i <= gpGlobals->maxClients; i++)
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!pPlayer->IsBot())
+ continue;
+
+ CCSBot *pBot = static_cast(pPlayer);
+ pBot->StartNormalProcess();
+ }
+
+ m_isLearningMap = false;
+ m_isMapDataLoaded = false;
+ m_isAnalysisRequested = false;
+
+ // Try to reload the navigation map from the file
+ if (LoadNavigationMap())
+ {
+ // Initiate a game restart in 3 seconds
+ CVAR_SET_FLOAT("sv_restart", 3);
+ }
+}
+
bool CCSBotManager::AddBot(const BotProfile *profile, BotProfileTeamType team)
{
if (!AreBotsAllowed())
diff --git a/regamedll/dlls/bot/cs_bot_manager.h b/regamedll/dlls/bot/cs_bot_manager.h
index 1faea5461..6f3b0e689 100644
--- a/regamedll/dlls/bot/cs_bot_manager.h
+++ b/regamedll/dlls/bot/cs_bot_manager.h
@@ -56,13 +56,16 @@ class CCSBotManager: public CBotManager
virtual bool IsImportantPlayer(CBasePlayer *pPlayer) const; // return true if pPlayer is important to scenario (VIP, bomb carrier, etc)
public:
- void ValidateMapData();
+ bool LoadNavigationMap();
+ void DetermineMapScenario();
void OnFreeEntPrivateData(CBaseEntity *pEntity);
+ void OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead);
bool IsLearningMap() const { return m_isLearningMap; }
void SetLearningMapFlag() { m_isLearningMap = true; }
bool IsAnalysisRequested() const { return m_isAnalysisRequested; }
void RequestAnalysis() { m_isAnalysisRequested = true; }
void AckAnalysisRequest() { m_isAnalysisRequested = false; }
+ void AnalysisCompleted();
// difficulty levels
static BotDifficultyType GetDifficultyLevel()
@@ -85,7 +88,8 @@ class CCSBotManager: public CBotManager
SCENARIO_DEATHMATCH,
SCENARIO_DEFUSE_BOMB,
SCENARIO_RESCUE_HOSTAGES,
- SCENARIO_ESCORT_VIP
+ SCENARIO_ESCORT_VIP,
+ SCENARIO_ESCAPE
};
GameScenarioType GetScenario() const
@@ -268,3 +272,4 @@ inline bool AreBotsAllowed()
}
void PrintAllEntities();
+void GenerateSpawnPointsFromNavData();
diff --git a/regamedll/dlls/bot/cs_bot_update.cpp b/regamedll/dlls/bot/cs_bot_update.cpp
index 37d496659..de75bf6aa 100644
--- a/regamedll/dlls/bot/cs_bot_update.cpp
+++ b/regamedll/dlls/bot/cs_bot_update.cpp
@@ -255,7 +255,7 @@ void CCSBot::Update()
Vector dir = m_spotEncounter->path.to - m_spotEncounter->path.from;
float length = dir.NormalizeInPlace();
- for (auto &order : m_spotEncounter->spotList) {
+ for (auto& order : m_spotEncounter->spotList) {
UTIL_DrawBeamPoints(m_spotEncounter->path.from + order.t * length * dir, *order.spot->GetPosition(), 3, 0, 255, 255);
}
}
@@ -339,7 +339,7 @@ void CCSBot::Update()
UpdateReactionQueue();
// "threat" may be the same as our current enemy
- CBasePlayer *threat = GetRecognizedEnemy();
+ CBasePlayer* threat = GetRecognizedEnemy();
if (threat)
{
// adjust our personal "safe" time
@@ -592,6 +592,10 @@ void CCSBot::Update()
SecondaryAttack();
}
+#ifdef REGAMEDLL_ADD
+ if (!IsBlind())
+ {
+#endif
// check encounter spots
UpdatePeripheralVision();
@@ -601,11 +605,24 @@ void CCSBot::Update()
GetChatter()->SpottedBomber(GetBomber());
}
+#ifdef REGAMEDLL_ADD
+ // watch for snipers
+ if (CanSeeSniper() && !HasSeenSniperRecently())
+ {
+ GetChatter()->SpottedSniper();
+
+ const float sniperRecentInterval = 20.0f;
+ m_sawEnemySniperTimer.Start(sniperRecentInterval);
+ }
+#endif
+
if (CanSeeLooseBomb())
{
GetChatter()->SpottedLooseBomb(TheCSBots()->GetLooseBomb());
}
-
+#ifdef REGAMEDLL_ADD
+}
+#endif
// Scenario interrupts
switch (TheCSBots()->GetScenario())
{
diff --git a/regamedll/dlls/bot/cs_bot_vision.cpp b/regamedll/dlls/bot/cs_bot_vision.cpp
index f7b16acc5..5e4e30264 100644
--- a/regamedll/dlls/bot/cs_bot_vision.cpp
+++ b/regamedll/dlls/bot/cs_bot_vision.cpp
@@ -697,6 +697,13 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
m_closestVisibleFriend = nullptr;
m_closestVisibleHumanFriend = nullptr;
+#ifdef REGAMEDLL_ADD
+ m_isEnemySniperVisible = false;
+ CBasePlayer* sniperThreat = NULL;
+ float sniperThreatRange = 99999999999.9f;
+ bool sniperThreatIsFacingMe = false;
+#endif
+
float closeFriendRange = 99999999999.9f;
float closeHumanFriendRange = 99999999999.9f;
@@ -789,6 +796,53 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
Vector d = pev->origin - pPlayer->pev->origin;
float distSq = d.LengthSquared();
+#ifdef REGAMEDLL_ADD
+ CBasePlayerWeapon *pCurrentWeapon = static_cast(pPlayer->m_pActiveItem);
+ if (pCurrentWeapon && isSniperRifle(pCurrentWeapon))
+ {
+ m_isEnemySniperVisible = true;
+ if (sniperThreat)
+ {
+ if (IsPlayerLookingAtMe(pPlayer))
+ {
+ if (sniperThreatIsFacingMe)
+ {
+ // several snipers are facing us - keep closest
+ if (distSq < sniperThreatRange)
+ {
+ sniperThreat = pPlayer;
+ sniperThreatRange = distSq;
+ sniperThreatIsFacingMe = true;
+ }
+ }
+ else
+ {
+ // even if this sniper is farther away, keep it because he's aiming at us
+ sniperThreat = pPlayer;
+ sniperThreatRange = distSq;
+ sniperThreatIsFacingMe = true;
+ }
+ }
+ else
+ {
+ // this sniper is not looking at us, only consider it if we dont have a sniper facing us
+ if (!sniperThreatIsFacingMe && distSq < sniperThreatRange)
+ {
+ sniperThreat = pPlayer;
+ sniperThreatRange = distSq;
+ }
+ }
+ }
+ else
+ {
+ // first sniper we see
+ sniperThreat = pPlayer;
+ sniperThreatRange = distSq;
+ sniperThreatIsFacingMe = IsPlayerLookingAtMe(pPlayer);
+ }
+ }
+#endif
+
// maintain set of visible threats, sorted by increasing distance
if (threatCount == 0)
{
@@ -950,6 +1004,23 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
{
return currentThreat;
}
+
+ // if we are a sniper and we see a sniper threat, attack it unless
+ // there are other close enemies facing me
+ if (IsSniper() && sniperThreat)
+ {
+ const float closeCombatRange = 500.0f;
+
+ for (t = 0; t < threatCount; ++t)
+ {
+ if (threat[t].range < closeCombatRange && IsPlayerLookingAtMe(threat[t].enemy))
+ {
+ return threat[t].enemy;
+ }
+ }
+
+ return sniperThreat;
+ }
#endif
// otherwise, find the closest threat that without using shield
diff --git a/regamedll/dlls/bot/states/cs_bot_buy.cpp b/regamedll/dlls/bot/states/cs_bot_buy.cpp
index f210423e9..c34351f07 100644
--- a/regamedll/dlls/bot/states/cs_bot_buy.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_buy.cpp
@@ -462,17 +462,26 @@ void BuyState::OnUpdate(CCSBot *me)
me->ClientCommand("vesthelm");
me->ClientCommand("vest");
- // pistols - if we have no preferred pistol, buy at random
- if (TheCSBots()->AllowPistols() && !me->GetProfile()->HasPistolPreference())
+ if (TheCSBots()->AllowPistols()
+#ifndef REGAMEDLL_FIXES
+ && !me->GetProfile()->HasPistolPreference()
+#endif
+ )
{
if (m_buyPistol)
{
- int which = RANDOM_LONG(0, MAX_BUY_WEAPON_SECONDARY - 1);
+#ifdef REGAMEDLL_FIXES
+ // pistols - if we have no preferred pistol, buy at random
+ if (!me->GetProfile()->HasPistolPreference())
+#endif
+ {
+ int which = RANDOM_LONG(0, MAX_BUY_WEAPON_SECONDARY - 1);
- if (me->m_iTeam == TERRORIST)
- me->ClientCommand(secondaryWeaponBuyInfoT[which].buyAlias);
- else
- me->ClientCommand(secondaryWeaponBuyInfoCT[which].buyAlias);
+ if (me->m_iTeam == TERRORIST)
+ me->ClientCommand(secondaryWeaponBuyInfoT[which].buyAlias);
+ else
+ me->ClientCommand(secondaryWeaponBuyInfoCT[which].buyAlias);
+ }
// only buy one pistol
m_buyPistol = false;
diff --git a/regamedll/dlls/bot/states/cs_bot_idle.cpp b/regamedll/dlls/bot/states/cs_bot_idle.cpp
index e38bde885..4bfcd7cc0 100644
--- a/regamedll/dlls/bot/states/cs_bot_idle.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_idle.cpp
@@ -773,6 +773,93 @@ void IdleState::OnUpdate(CCSBot *me)
}
break;
}
+ case CCSBotManager::SCENARIO_ESCAPE:
+ {
+ if (me->m_iTeam == TERRORIST)
+ {
+ // if early in round, pick a random zone, otherwise pick closest zone
+ const float earlyTime = 20.0f;
+ const CCSBotManager::Zone *zone = nullptr;
+
+ if (TheCSBots()->GetElapsedRoundTime() < earlyTime)
+ {
+ // pick random zone
+ zone = TheCSBots()->GetRandomZone();
+ }
+ else
+ {
+ // pick closest zone
+ zone = TheCSBots()->GetClosestZone(me->GetLastKnownArea(), PathCost(me));
+ }
+
+ if (zone)
+ {
+ // pick a random spot within the escape zone
+ const Vector *pos = TheCSBots()->GetRandomPositionInZone(zone);
+ if (pos)
+ {
+ // move to escape zone
+ // me->SetTask(CCSBot::VIP_ESCAPE);
+ me->Run();
+ me->MoveTo(pos);
+ return;
+ }
+ }
+ }
+ // CT
+ else
+ {
+ if (me->IsSniper())
+ {
+ if (RANDOM_FLOAT(0, 100) <= defenseSniperCampChance)
+ {
+ // snipe escape zone(s)
+ const CCSBotManager::Zone *zone = TheCSBots()->GetRandomZone();
+ if (zone)
+ {
+ CNavArea *area = TheCSBots()->GetRandomAreaInZone(zone);
+ if (area)
+ {
+ me->SetTask(CCSBot::MOVE_TO_SNIPER_SPOT);
+ me->Hide(area, -1.0, sniperHideRange);
+ me->SetDisposition(CCSBot::OPPORTUNITY_FIRE);
+ me->PrintIfWatched("Sniping near escape zone\n");
+ return;
+ }
+ }
+ }
+ }
+
+ // rogues just hunt, unless they want to snipe
+ // if the whole team has decided to rush, hunt
+ if (me->IsRogue() || TheCSBots()->IsDefenseRushing())
+ break;
+
+ // the lower our morale gets, the more we want to camp the escape zone(s)
+ float guardEscapeZoneChance = -34.0f * me->GetMorale();
+
+ if (RANDOM_FLOAT(0.0f, 100.0f) < guardEscapeZoneChance)
+ {
+ // guard escape zone(s)
+ const CCSBotManager::Zone *zone = TheCSBots()->GetRandomZone();
+ if (zone)
+ {
+ CNavArea *area = TheCSBots()->GetRandomAreaInZone(zone);
+ if (area)
+ {
+ // guard the escape zone - stay closer if our morale is low
+ //me->SetTask(CCSBot::GUARD_VIP_ESCAPE_ZONE);
+ me->PrintIfWatched("I'm guarding an escape zone\n");
+
+ float escapeGuardRange = 750.0f + 250.0f * (me->GetMorale() + 3);
+ me->Hide(area, -1.0, escapeGuardRange);
+ me->SetDisposition(CCSBot::OPPORTUNITY_FIRE);
+ return;
+ }
+ }
+ }
+ }
+ }
// deathmatch
default:
{
diff --git a/regamedll/dlls/career_tasks.cpp b/regamedll/dlls/career_tasks.cpp
index 972ccca9b..050a9aab0 100644
--- a/regamedll/dlls/career_tasks.cpp
+++ b/regamedll/dlls/career_tasks.cpp
@@ -260,7 +260,7 @@ void CCareerTask::OnEvent(GameEventType event, CBasePlayer *pVictim, CBasePlayer
while ((pHostage = UTIL_FindEntityByClassname(pHostage, "hostage_entity")))
{
- if (pHostage && pHostage->IsDead())
+ if (pHostage->IsDead())
hostagesCount++;
}
@@ -389,7 +389,6 @@ void CCareerTaskManager::Reset(bool deleteTasks)
delete task;
m_tasks.clear();
- m_nextId = 0;
}
else
{
@@ -397,6 +396,7 @@ void CCareerTaskManager::Reset(bool deleteTasks)
task->Reset();
}
+ m_nextId = 0;
m_finishedTaskTime = 0;
m_finishedTaskRound = 0;
m_shouldLatchRoundEndMessage = false;
diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp
index e1b4d3221..b802a2e31 100644
--- a/regamedll/dlls/client.cpp
+++ b/regamedll/dlls/client.cpp
@@ -133,6 +133,7 @@ static entity_field_alias_t custom_entity_field_alias[] =
{ "animtime", 0 },
};
+edict_t *g_pEdicts = nullptr;
bool g_bServerActive = false;
bool g_bItemCreatedByBuying = false;
PLAYERPVSSTATUS g_PVSStatus[MAX_CLIENTS];
@@ -464,7 +465,7 @@ NOXREF int CountTeams()
void ListPlayers(CBasePlayer *current)
{
- char message[120] = "", cNumber[12];
+ char message[120]{};
CBaseEntity *pEntity = nullptr;
while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player")))
@@ -478,12 +479,7 @@ void ListPlayers(CBasePlayer *current)
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
int iUserID = GETPLAYERUSERID(ENT(pPlayer->pev));
- Q_sprintf(cNumber, "%d", iUserID);
- Q_strcpy(message, "\n");
- Q_strcat(message, cNumber);
- Q_strcat(message, " : ");
- Q_strcat(message, STRING(pPlayer->pev->netname));
-
+ Q_snprintf(message, sizeof(message), "\n%d : %s", iUserID, STRING(pPlayer->pev->netname));
ClientPrint(current->pev, HUD_PRINTCONSOLE, message);
}
@@ -737,8 +733,8 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity)
pPlayer->m_iJoiningState = SHOWLTEXT;
- static char sName[128];
- Q_strcpy(sName, STRING(pPlayer->pev->netname));
+ char sName[128];
+ Q_strlcpy(sName, STRING(pPlayer->pev->netname));
for (char *pApersand = sName; pApersand && *pApersand != '\0'; pApersand++)
{
@@ -796,12 +792,12 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
{
if (CMD_ARGC_() >= 2)
{
- Q_sprintf(szTemp, "%s %s", pcmd, CMD_ARGS());
+ Q_snprintf(szTemp, sizeof(szTemp), "%s %s", pcmd, CMD_ARGS());
}
else
{
// Just a one word command, use the first word...sigh
- Q_sprintf(szTemp, "%s", pcmd);
+ Q_snprintf(szTemp, sizeof(szTemp), "%s", pcmd);
}
p = szTemp;
@@ -815,7 +811,9 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
if (*p == '"')
{
p++;
- p[Q_strlen(p) - 1] = '\0';
+ size_t len = Q_strlen(p);
+ if (len > 0)
+ p[len - 1] = '\0';
}
// Check if buffer contains an invalid unicode sequence
@@ -843,6 +841,12 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
char *pszConsoleFormat = nullptr;
bool consoleUsesPlaceName = false;
+#ifdef REGAMEDLL_ADD
+ // there's no team on FFA mode
+ if (teamonly && CSGameRules()->IsFreeForAll() && (pPlayer->m_iTeam == CT || pPlayer->m_iTeam == TERRORIST))
+ teamonly = FALSE;
+#endif
+
// team only
if (teamonly)
{
@@ -966,8 +970,8 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
}
}
- Q_strcat(text, p);
- Q_strcat(text, "\n");
+ Q_strlcat(text, p);
+ Q_strlcat(text, "\n");
// loop through all players
// Start with the first player.
@@ -997,7 +1001,13 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
if (gpGlobals->deathmatch != 0.0f && CSGameRules()->m_VoiceGameMgr.PlayerHasBlockedPlayer(pReceiver, pPlayer))
continue;
- if (teamonly && pReceiver->m_iTeam != pPlayer->m_iTeam)
+ if (teamonly
+#ifdef REGAMEDLL_FIXES
+ && CSGameRules()->PlayerRelationship(pPlayer, pReceiver) != GR_TEAMMATE
+#else
+ && pReceiver->m_iTeam != pPlayer->m_iTeam
+#endif
+ )
continue;
if (
@@ -1010,7 +1020,13 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
continue;
}
- if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY && pReceiver->m_iTeam == pPlayer->m_iTeam)
+ if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY
+#ifdef REGAMEDLL_FIXES
+ && CSGameRules()->PlayerRelationship(pPlayer, pReceiver) == GR_TEAMMATE
+#else
+ && pReceiver->m_iTeam == pPlayer->m_iTeam
+#endif
+ )
|| pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_NONE)
{
MESSAGE_BEGIN(MSG_ONE, gmsgSayText, nullptr, pReceiver->pev);
@@ -3747,6 +3763,8 @@ void EXT_FUNC ServerDeactivate()
void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
{
+ g_pEdicts = pEdictList;
+
#ifdef REGAMEDLL_ADD
//
// Tells clients which version of player movement (pmove) the server is using
@@ -3815,9 +3833,6 @@ void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
#ifdef REGAMEDLL_ADD
CSGameRules()->ServerActivate();
-
- if (location_area_info.value)
- LoadNavigationMap();
#endif
}
@@ -4298,7 +4313,7 @@ void ClientPrecache()
PRECACHE_GENERIC("sprites/scope_arc_ne.tga");
PRECACHE_GENERIC("sprites/scope_arc_sw.tga");
- m_usResetDecals = g_engfuncs.pfnPrecacheEvent(1, "events/decal_reset.sc");
+ m_usResetDecals = PRECACHE_EVENT(1, "events/decal_reset.sc");
}
const char *EXT_FUNC GetGameDescription()
@@ -4990,7 +5005,7 @@ void EXT_FUNC UpdateClientData(const edict_t *ent, int sendweapons, struct clien
cd->flSwimTime = pev->flSwimTime;
cd->waterjumptime = int(pev->teleport_time);
- Q_strcpy(cd->physinfo, ENGINE_GETPHYSINFO(ent));
+ Q_strlcpy(cd->physinfo, ENGINE_GETPHYSINFO(ent));
cd->maxspeed = pev->maxspeed;
cd->fov = pev->fov;
@@ -5201,8 +5216,10 @@ int EXT_FUNC InconsistentFile(const edict_t *pEdict, const char *filename, char
if (!CVAR_GET_FLOAT("mp_consistency"))
return 0;
+ const int BufferLen = 256;
+
// Default behavior is to kick the player
- Q_sprintf(disconnect_message, "Server is enforcing file consistency for %s\n", filename);
+ Q_snprintf(disconnect_message, BufferLen, "Server is enforcing file consistency for %s\n", filename);
// Kick now with specified disconnect message.
return 1;
diff --git a/regamedll/dlls/combat.cpp b/regamedll/dlls/combat.cpp
index 17fe84e27..8c66a4754 100644
--- a/regamedll/dlls/combat.cpp
+++ b/regamedll/dlls/combat.cpp
@@ -285,8 +285,6 @@ void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker
damageRatio = GetAmountOfPlayerVisible(vecSrc, pEntity);
}
- damageRatio = GetAmountOfPlayerVisible(vecSrc, pEntity);
-
float length;
#ifdef REGAMEDLL_ADD
// allow to damage breakable objects
diff --git a/regamedll/dlls/debug.cpp b/regamedll/dlls/debug.cpp
index 82d50d71d..81605143d 100644
--- a/regamedll/dlls/debug.cpp
+++ b/regamedll/dlls/debug.cpp
@@ -27,7 +27,7 @@ NOXREF void UTIL_DPrintf(DebugOutputType outputType, char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -41,7 +41,7 @@ void UTIL_DPrintf(char *pszMsg, ...)
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -130,7 +130,7 @@ NOXREF void UTIL_BotDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -146,7 +146,7 @@ void UTIL_CareerDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -162,7 +162,7 @@ NOXREF void UTIL_TutorDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -178,7 +178,7 @@ NOXREF void UTIL_StatsDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -194,7 +194,7 @@ NOXREF void UTIL_HostageDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
diff --git a/regamedll/dlls/ehandle.h b/regamedll/dlls/ehandle.h
index 9a8717826..61d22a5cc 100644
--- a/regamedll/dlls/ehandle.h
+++ b/regamedll/dlls/ehandle.h
@@ -130,6 +130,10 @@ inline edict_t *EntityHandle::Set(edict_t *pEdict)
{
m_serialnumber = pEdict->serialnumber;
}
+ else
+ {
+ m_serialnumber = 0;
+ }
return pEdict;
}
diff --git a/regamedll/dlls/explode.cpp b/regamedll/dlls/explode.cpp
index 104d84720..6d1c7ccd4 100644
--- a/regamedll/dlls/explode.cpp
+++ b/regamedll/dlls/explode.cpp
@@ -201,7 +201,7 @@ void ExplosionCreate(const Vector ¢er, Vector &angles, edict_t *pOwner, int
CBaseEntity *pExplosion = CBaseEntity::Create("env_explosion", center, angles, pOwner);
- Q_sprintf(buf, "%3d", magnitude);
+ Q_snprintf(buf, sizeof(buf), "%3d", magnitude);
kvd.szKeyName = "iMagnitude";
kvd.szValue = buf;
diff --git a/regamedll/dlls/func_tank.cpp b/regamedll/dlls/func_tank.cpp
index e12c90768..14c2ef6fc 100644
--- a/regamedll/dlls/func_tank.cpp
+++ b/regamedll/dlls/func_tank.cpp
@@ -302,7 +302,7 @@ void CFuncTank::ControllerPostFrame()
Assert(m_pController != nullptr);
- if (m_pController->pev->button & IN_ATTACK)
+ if (m_pController && m_pController->pev->button & IN_ATTACK)
{
Vector vecForward;
UTIL_MakeVectorsPrivate(pev->angles, vecForward, nullptr, nullptr);
diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp
index 789435938..2c6d9fbff 100644
--- a/regamedll/dlls/game.cpp
+++ b/regamedll/dlls/game.cpp
@@ -160,6 +160,7 @@ cvar_t t_default_grenades = { "mp_t_default_grenades", "", 0, 0.0
cvar_t t_give_player_knife = { "mp_t_give_player_knife", "1", 0, 1.0f, nullptr };
cvar_t t_default_weapons_secondary = { "mp_t_default_weapons_secondary", "glock18", 0, 0.0f, nullptr };
cvar_t t_default_weapons_primary = { "mp_t_default_weapons_primary", "", 0, 0.0f, nullptr };
+cvar_t default_weapons_random = { "mp_default_weapons_random", "", 0, 0.0f, nullptr };
cvar_t free_armor = { "mp_free_armor", "0", 0, 0.0f, nullptr };
cvar_t teamflash = { "mp_team_flash", "1", 0, 1.0f, nullptr };
cvar_t allchat = { "sv_allchat", "0", 0, 0.0f, nullptr };
@@ -171,15 +172,16 @@ cvar_t deathmsg_flags = { "mp_deathmsg_flags", "abc", 0, 0.0f
cvar_t assist_damage_threshold = { "mp_assist_damage_threshold", "40", 0, 40.0f, nullptr };
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 hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr };
+cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr };
-cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr };
+cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr };
cvar_t dying_time = { "mp_dying_time", "3.0", 0, 3.0f, nullptr };
cvar_t defuser_allocation = { "mp_defuser_allocation", "0", 0, 0.0f, nullptr };
cvar_t location_area_info = { "mp_location_area_info", "0", 0, 0.0f, nullptr };
-cvar_t chat_loc_fallback = { "mp_chat_loc_fallback", "1", 1, 0.0f, nullptr };
+cvar_t chat_loc_fallback = { "mp_chat_loc_fallback", "1", 0, 1.0f, nullptr };
cvar_t item_respawn_time = { "mp_item_respawn_time", "30", FCVAR_SERVER, 30.0f, nullptr };
cvar_t weapon_respawn_time = { "mp_weapon_respawn_time", "20", FCVAR_SERVER, 20.0f, nullptr };
@@ -188,6 +190,17 @@ cvar_t ammo_respawn_time = { "mp_ammo_respawn_time", "20", FCVAR_SERVER, 2
cvar_t vote_flags = { "mp_vote_flags", "km", 0, 0.0f, nullptr };
cvar_t votemap_min_time = { "mp_votemap_min_time", "180", 0, 180.0f, nullptr };
+cvar_t flymove_method = { "mp_flymove_method", "0", 0, 0.0f, nullptr };
+cvar_t stamina_restore_rate = { "mp_stamina_restore_rate", "0", 0, 0.f, nullptr };
+
+cvar_t logkills = { "mp_logkills", "1", FCVAR_SERVER, 0.0f, nullptr };
+cvar_t randomspawn = { "mp_randomspawn", "0", FCVAR_SERVER, 0.0f, nullptr };
+
+cvar_t playerid_showhealth = { "mp_playerid_showhealth", "1", 0, 1.0f, nullptr };
+cvar_t playerid_field = { "mp_playerid_field", "3", 0, 3.0f, nullptr };
+
+cvar_t knockback = { "mp_knockback", "170", 0, 170.0f, nullptr };
+
void GameDLL_Version_f()
{
if (Q_stricmp(CMD_ARGV(1), "version") != 0)
@@ -431,6 +444,7 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&t_give_player_knife);
CVAR_REGISTER(&t_default_weapons_secondary);
CVAR_REGISTER(&t_default_weapons_primary);
+ CVAR_REGISTER(&default_weapons_random);
CVAR_REGISTER(&free_armor);
CVAR_REGISTER(&teamflash);
CVAR_REGISTER(&allchat);
@@ -449,6 +463,7 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&freezetime_duck);
CVAR_REGISTER(&freezetime_jump);
+ CVAR_REGISTER(&jump_height);
CVAR_REGISTER(&defuser_allocation);
CVAR_REGISTER(&location_area_info);
CVAR_REGISTER(&chat_loc_fallback);
@@ -459,12 +474,32 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&vote_flags);
CVAR_REGISTER(&votemap_min_time);
+ CVAR_REGISTER(&randomspawn);
+
+ CVAR_REGISTER(&cv_bot_enable);
+ CVAR_REGISTER(&cv_hostage_ai_enable);
+ CVAR_REGISTER(&logkills);
+
+ CVAR_REGISTER(&playerid_showhealth);
+ CVAR_REGISTER(&playerid_field);
+
+ CVAR_REGISTER(&stamina_restore_rate);
+
+ CVAR_REGISTER(&flymove_method);
+
+ CVAR_REGISTER(&knockback);
// print version
CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n");
+ // execute initial pre-configurations
+ SERVER_COMMAND("exec game_init.cfg\n");
+ SERVER_EXECUTE();
+
#endif // REGAMEDLL_ADD
+ Regamedll_Game_Init();
+
Bot_RegisterCVars();
Tutor_RegisterCVars();
Hostage_RegisterCVars();
@@ -473,12 +508,6 @@ void EXT_FUNC GameDLLInit()
VoiceGameMgr_RegisterCVars();
#endif
-#ifdef REGAMEDLL_ADD
- // execute initial pre-configurations
- SERVER_COMMAND("exec game_init.cfg\n");
- SERVER_EXECUTE();
-#endif
-
}
SpewRetval_t GameDLL_SpewHandler(SpewType_t spewType, int level, const char *pMsg)
diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h
index 09da5305a..ecf1001c8 100644
--- a/regamedll/dlls/game.h
+++ b/regamedll/dlls/game.h
@@ -186,6 +186,7 @@ extern cvar_t t_default_grenades;
extern cvar_t t_give_player_knife;
extern cvar_t t_default_weapons_secondary;
extern cvar_t t_default_weapons_primary;
+extern cvar_t default_weapons_random;
extern cvar_t free_armor;
extern cvar_t teamflash;
extern cvar_t allchat;
@@ -200,6 +201,7 @@ extern cvar_t deathmsg_flags;
extern cvar_t assist_damage_threshold;
extern cvar_t freezetime_duck;
extern cvar_t freezetime_jump;
+extern cvar_t jump_height;
extern cvar_t defuser_allocation;
extern cvar_t location_area_info;
extern cvar_t chat_loc_fallback;
@@ -208,6 +210,13 @@ extern cvar_t weapon_respawn_time;
extern cvar_t ammo_respawn_time;
extern cvar_t vote_flags;
extern cvar_t votemap_min_time;
+extern cvar_t flymove_method;
+extern cvar_t stamina_restore_rate;
+extern cvar_t logkills;
+extern cvar_t randomspawn;
+extern cvar_t playerid_showhealth;
+extern cvar_t playerid_field;
+extern cvar_t knockback;
#endif
@@ -215,4 +224,6 @@ extern cvar_t scoreboard_showmoney;
extern cvar_t scoreboard_showhealth;
extern cvar_t scoreboard_showdefkit;
+
+
void GameDLLInit();
diff --git a/regamedll/dlls/gamerules.cpp b/regamedll/dlls/gamerules.cpp
index 45210e212..3d9f14182 100644
--- a/regamedll/dlls/gamerules.cpp
+++ b/regamedll/dlls/gamerules.cpp
@@ -8,8 +8,8 @@ CGameRules::CGameRules()
m_bBombDropped = FALSE;
m_bGameOver = false;
- m_GameDesc = new char[sizeof("Counter-Strike")];
- Q_strcpy(m_GameDesc, AreRunningCZero() ? "Condition Zero" : "Counter-Strike");
+ const char *pszGameDesc = AreRunningCZero() ? "Condition Zero" : "Counter-Strike";
+ m_GameDesc = CloneString(pszGameDesc);
}
CGameRules::~CGameRules()
diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h
index a4f556ab9..220e09556 100644
--- a/regamedll/dlls/gamerules.h
+++ b/regamedll/dlls/gamerules.h
@@ -1009,5 +1009,4 @@ char *GetTeam(int team);
void DestroyMapCycle(mapcycle_t *cycle);
int ReloadMapCycleFile(char *filename, mapcycle_t *cycle);
int CountPlayers();
-void ExtractCommandString(char *s, char *szCommand);
int GetMapCount();
diff --git a/regamedll/dlls/ggrenade.cpp b/regamedll/dlls/ggrenade.cpp
index 41e92f27d..878355658 100644
--- a/regamedll/dlls/ggrenade.cpp
+++ b/regamedll/dlls/ggrenade.cpp
@@ -1170,6 +1170,12 @@ void CGrenade::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTy
if (!m_bIsC4)
return;
+#ifdef REGAMEDLL_FIXES
+ // block the start of defuse if the bomb timer has expired
+ if (m_flC4Blow > 0 && gpGlobals->time >= m_flC4Blow)
+ return;
+#endif
+
// TODO: We must be sure that the activator is a player.
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pActivator->pev);
@@ -1503,6 +1509,13 @@ void CGrenade::C4Think()
{
DefuseBombEnd(pPlayer, false);
}
+#ifdef REGAMEDLL_FIXES
+ // if the bomb timer has expired and defuse is still ongoing, stop the defuse
+ else if (gpGlobals->time >= m_flC4Blow)
+ {
+ DefuseBombEnd(pPlayer, false);
+ }
+#endif
}
else
{
diff --git a/regamedll/dlls/globals.cpp b/regamedll/dlls/globals.cpp
index 3f698d59f..d02c8fee9 100644
--- a/regamedll/dlls/globals.cpp
+++ b/regamedll/dlls/globals.cpp
@@ -11,4 +11,3 @@ BOOL gDisplayTitle;
bool g_bIsBeta = false;
bool g_bIsCzeroGame = false;
bool g_bAllowedCSBot = false;
-bool g_bHostageImprov = false;
diff --git a/regamedll/dlls/globals.h b/regamedll/dlls/globals.h
index 020242918..805fd12ad 100644
--- a/regamedll/dlls/globals.h
+++ b/regamedll/dlls/globals.h
@@ -38,4 +38,3 @@ extern BOOL gDisplayTitle;
extern bool g_bIsBeta;
extern bool g_bIsCzeroGame;
extern bool g_bAllowedCSBot;
-extern bool g_bHostageImprov;
diff --git a/regamedll/dlls/h_export.cpp b/regamedll/dlls/h_export.cpp
index 486a3eedf..544a92ffb 100644
--- a/regamedll/dlls/h_export.cpp
+++ b/regamedll/dlls/h_export.cpp
@@ -13,7 +13,6 @@ C_DLLEXPORT void WINAPI GiveFnptrsToDll(enginefuncs_t *pEnginefuncsTable, global
gpGlobals = pGlobals;
FileSystem_Init();
- Regamedll_Game_Init();
}
#if defined(_LINUX)
diff --git a/regamedll/dlls/hostage/hostage.cpp b/regamedll/dlls/hostage/hostage.cpp
index 7ef34b222..c6f57091c 100644
--- a/regamedll/dlls/hostage/hostage.cpp
+++ b/regamedll/dlls/hostage/hostage.cpp
@@ -28,6 +28,7 @@
#include "precompiled.h"
+cvar_t cv_hostage_ai_enable = { "hostage_ai_enable", "0", 0, 0.0f, nullptr };
cvar_t cv_hostage_debug = { "hostage_debug", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_hostage_stop = { "hostage_stop", "0", FCVAR_SERVER, 0.0f, nullptr };
@@ -268,39 +269,48 @@ void CHostage::Spawn()
void CHostage::Precache()
{
- if (AreImprovAllowed())
+ if (cv_hostage_ai_enable.value)
{
+ string_t model = iStringNull;
+
static int which = 0;
switch (which)
{
+ default:
case REGULAR_GUY:
- pev->model = MAKE_STRING("models/hostageA.mdl");
+ model = MAKE_STRING("models/hostageA.mdl");
break;
case OLD_GUY:
- pev->model = MAKE_STRING("models/hostageB.mdl");
+ model = MAKE_STRING("models/hostageB.mdl");
break;
case BLACK_GUY:
- pev->model = MAKE_STRING("models/hostageC.mdl");
+ model = MAKE_STRING("models/hostageC.mdl");
break;
case GOOFY_GUY:
- pev->model = MAKE_STRING("models/hostageD.mdl");
- break;
- default:
+ model = MAKE_STRING("models/hostageD.mdl");
break;
}
m_whichModel = static_cast(which);
- if (++which > 3)
- which = 0;
+ if (++which > GOOFY_GUY)
+ which = REGULAR_GUY;
+
+ if (g_pFileSystem->FileExists(model))
+ {
+ pev->model = model;
+ }
+ else
+ {
+ // It seems that the model is missing, so use classic hostages
+ CVAR_SET_FLOAT("hostage_ai_enable", 0);
+ }
}
- else
+
+ if (pev->model.IsNull())
{
m_whichModel = REGULAR_GUY;
- if (pev->model.IsNull())
- {
- pev->model = MAKE_STRING("models/scientist.mdl");
- }
+ pev->model = MAKE_STRING("models/scientist.mdl");
}
PRECACHE_MODEL(pev->model);
@@ -342,7 +352,7 @@ void CHostage::IdleThink()
const float giveUpTime = (1 / 30.0f);
float const updateRate = 0.1f;
- if (AreImprovAllowed() && !TheNavAreaList.empty())
+ if (cv_hostage_ai_enable.value && !TheNavAreaList.empty())
{
if (!m_improv)
{
@@ -619,7 +629,7 @@ void CHostage::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir
BOOL CHostage::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
{
#ifdef REGAMEDLL_ADD
- if (!CanTakeDamage(pevAttacker))
+ if (pevAttacker && !CanTakeDamage(pevAttacker))
return FALSE;
#endif
@@ -771,7 +781,7 @@ void CHostage::SetDeathActivity()
return;
}
- if (AreImprovAllowed())
+ if (cv_hostage_ai_enable.value)
{
switch (m_LastHitGroup)
{
@@ -1397,7 +1407,7 @@ void Hostage_RegisterCVars()
{
// These cvars are only used in czero
#ifdef REGAMEDLL_FIXES
- if (!AreImprovAllowed())
+ if (!cv_hostage_ai_enable.value)
return;
#endif
@@ -1432,7 +1442,7 @@ void CHostageManager::ServerActivate()
AddHostage(pHostage);
}
- if (AreImprovAllowed())
+ if (cv_hostage_ai_enable.value)
{
for (auto& snd : hostageSoundStruct) {
m_chatter.AddSound(snd.type, snd.fileName);
@@ -1568,6 +1578,9 @@ void SimpleChatter::AddSound(HostageChatterType type, char *filename)
Q_snprintf(actualFilename, sizeof(actualFilename), "sound\\%s", filename);
+ if (!g_pFileSystem->FileExists(actualFilename))
+ return;
+
chatter->file[chatter->count].filename = CloneString(filename);
chatter->file[chatter->count].duration = (double)GET_APPROX_WAVE_PLAY_LEN(actualFilename) / 1000.0;
@@ -1605,6 +1618,9 @@ void SimpleChatter::Shuffle(ChatterSet *chatter)
char *SimpleChatter::GetSound(HostageChatterType type, float *duration)
{
ChatterSet *chatter = &m_chatter[type];
+ if (chatter->count == 0)
+ return nullptr;
+
char *sound;
Shuffle(chatter);
diff --git a/regamedll/dlls/hostage/hostage.h b/regamedll/dlls/hostage/hostage.h
index 44a501235..f869cacfb 100644
--- a/regamedll/dlls/hostage/hostage.h
+++ b/regamedll/dlls/hostage/hostage.h
@@ -77,6 +77,7 @@ enum HostageChatterType
extern CHostageManager *g_pHostages;
extern int g_iHostageNumber;
+extern cvar_t cv_hostage_ai_enable;
extern cvar_t cv_hostage_debug;
extern cvar_t cv_hostage_stop;
@@ -284,11 +285,5 @@ class CHostageManager
SimpleChatter m_chatter;
};
-// Determine whether hostage improv can be used or not
-inline bool AreImprovAllowed()
-{
- return g_bHostageImprov;
-}
-
void Hostage_RegisterCVars();
void InstallHostageManager();
diff --git a/regamedll/dlls/hostage/hostage_improv.cpp b/regamedll/dlls/hostage/hostage_improv.cpp
index 9cdba7777..6932d2185 100644
--- a/regamedll/dlls/hostage/hostage_improv.cpp
+++ b/regamedll/dlls/hostage/hostage_improv.cpp
@@ -1605,9 +1605,9 @@ void CHostageImprov::Afraid()
int which = RANDOM_LONG(0, 100) % 3 + 1;
- Q_sprintf(animInto, "cower_into_%d", which);
- Q_sprintf(animLoop, "cower_loop_%d", which);
- Q_sprintf(animExit, "cower_exit_%d", which);
+ Q_snprintf(animInto, sizeof(animInto), "cower_into_%d", which);
+ Q_snprintf(animLoop, sizeof(animLoop), "cower_loop_%d", which);
+ Q_snprintf(animExit, sizeof(animExit), "cower_exit_%d", which);
m_animateState.AddSequence(this, animInto);
m_animateState.AddSequence(this, animLoop, RANDOM_FLOAT(3, 10));
diff --git a/regamedll/dlls/hostage/states/hostage_idle.cpp b/regamedll/dlls/hostage/states/hostage_idle.cpp
index c2c311a15..618848fc8 100644
--- a/regamedll/dlls/hostage/states/hostage_idle.cpp
+++ b/regamedll/dlls/hostage/states/hostage_idle.cpp
@@ -78,7 +78,7 @@ void HostageIdleState::OnUpdate(CHostageImprov *improv)
}
}
- if (m_moveState && improv->IsAtMoveGoal())
+ if (m_moveState != NotMoving && improv->IsAtMoveGoal())
{
m_moveState = NotMoving;
diff --git a/regamedll/dlls/items.cpp b/regamedll/dlls/items.cpp
index 03620e362..ba138e044 100644
--- a/regamedll/dlls/items.cpp
+++ b/regamedll/dlls/items.cpp
@@ -237,7 +237,7 @@ BOOL CItemBattery::MyTouch(CBasePlayer *pPlayer)
pct--;
char szcharge[64];
- Q_sprintf(szcharge, "!HEV_%1dP", pct);
+ Q_snprintf(szcharge, sizeof(szcharge), "!HEV_%1dP", pct);
pPlayer->SetSuitUpdate(szcharge, SUIT_SENTENCE, SUIT_NEXT_IN_30SEC);
return TRUE;
diff --git a/regamedll/dlls/lights.cpp b/regamedll/dlls/lights.cpp
index d44cddcc1..aa8629ea0 100644
--- a/regamedll/dlls/lights.cpp
+++ b/regamedll/dlls/lights.cpp
@@ -129,11 +129,11 @@ void CEnvLight::KeyValue(KeyValueData *pkvd)
pkvd->fHandled = TRUE;
char szColor[64];
- Q_sprintf(szColor, "%d", r);
+ Q_snprintf(szColor, sizeof(szColor), "%d", r);
CVAR_SET_STRING("sv_skycolor_r", szColor);
- Q_sprintf(szColor, "%d", g);
+ Q_snprintf(szColor, sizeof(szColor), "%d", g);
CVAR_SET_STRING("sv_skycolor_g", szColor);
- Q_sprintf(szColor, "%d", b);
+ Q_snprintf(szColor, sizeof(szColor), "%d", b);
CVAR_SET_STRING("sv_skycolor_b", szColor);
}
else
@@ -147,13 +147,13 @@ void CEnvLight::Spawn()
char szVector[64];
UTIL_MakeAimVectors(pev->angles);
- Q_sprintf(szVector, "%f", gpGlobals->v_forward.x);
+ Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.x);
CVAR_SET_STRING("sv_skyvec_x", szVector);
- Q_sprintf(szVector, "%f", gpGlobals->v_forward.y);
+ Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.y);
CVAR_SET_STRING("sv_skyvec_y", szVector);
- Q_sprintf(szVector, "%f", gpGlobals->v_forward.z);
+ Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.z);
CVAR_SET_STRING("sv_skyvec_z", szVector);
CLight::Spawn();
diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp
index 8ba46556d..2b91a50f5 100644
--- a/regamedll/dlls/multiplay_gamerules.cpp
+++ b/regamedll/dlls/multiplay_gamerules.cpp
@@ -178,15 +178,12 @@ bool CCStrikeGameMgrHelper::GetCanHearPlayer(CBasePlayer* pListener, CBasePlayer
void Broadcast(const char *sentence)
{
- char text[32];
+ char text[128];
if (!sentence)
- {
return;
- }
- Q_strcpy(text, "%!MRAD_");
- Q_strcat(text, UTIL_VarArgs("%s", sentence));
+ Q_snprintf(text, sizeof(text), "%%!MRAD_%s", sentence);
MESSAGE_BEGIN(MSG_BROADCAST, gmsgSendAudio);
WRITE_BYTE(0);
@@ -507,7 +504,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay()
char szCommand[256];
ALERT(at_console, "Executing listen server config file\n");
- Q_sprintf(szCommand, "exec %s\n", lservercfgfile);
+ Q_snprintf(szCommand, sizeof(szCommand), "exec %s\n", lservercfgfile);
SERVER_COMMAND(szCommand);
}
}
@@ -659,8 +656,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(CleanUpMap)()
#endif
// Remove grenades and C4
- const int grenadesRemoveCount = 20;
- UTIL_RemoveOther("grenade", grenadesRemoveCount);
+ UTIL_RemoveOther("grenade");
#ifndef REGAMEDLL_FIXES
// Remove defuse kit
@@ -1820,6 +1816,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)()
if (!UTIL_IsValidPlayer(pPlayer))
continue;
+#ifdef REGAMEDLL_FIXES
+ if (!pPlayer->IsBot())
+ pPlayer->ForceClientDllUpdate();
+#endif
+
pPlayer->Reset();
}
@@ -3249,19 +3250,6 @@ void CHalfLifeMultiplay::CareerRestart()
}
m_bSkipSpawn = false;
-
- for (int i = 1; i <= gpGlobals->maxClients; i++)
- {
- CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
-
- if (!UTIL_IsValidPlayer(pPlayer))
- continue;
-
- if (!pPlayer->IsBot())
- {
- pPlayer->ForceClientDllUpdate();
- }
- }
}
BOOL CHalfLifeMultiplay::IsMultiplayer()
@@ -4163,29 +4151,33 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim,
pVictim->CSPlayer()->m_iNumKilledByUnanswered[iPlayerIndexKiller - 1]++;
}
}
-
- // Did he kill himself?
- if (pVictim->pev == pevKiller)
- {
- // killed self
- char *team = GetTeam(pVictim->m_iTeam);
- UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()),
- GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name);
- }
- else if (pevKiller->flags & FL_CLIENT)
+#ifdef REGAMEDLL_ADD
+ if (static_cast(logkills.value))
+#endif
{
- const char *VictimTeam = GetTeam(pVictim->m_iTeam);
- const char *KillerTeam = (pKiller && pKiller->IsPlayer()) ? GetTeam(pKiller->m_iTeam) : "";
+ // Did he kill himself?
+ if (pVictim->pev == pevKiller)
+ {
+ // killed self
+ char *team = GetTeam(pVictim->m_iTeam);
+ UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()),
+ GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name);
+ }
+ else if (pevKiller->flags & FL_CLIENT)
+ {
+ const char *VictimTeam = GetTeam(pVictim->m_iTeam);
+ const char *KillerTeam = (pKiller && pKiller->IsPlayer()) ? GetTeam(pKiller->m_iTeam) : "";
- UTIL_LogPrintf("\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", STRING(pevKiller->netname), GETPLAYERUSERID(ENT(pevKiller)), GETPLAYERAUTHID(ENT(pevKiller)),
- KillerTeam, STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), GETPLAYERAUTHID(pVictim->edict()), VictimTeam, killer_weapon_name);
- }
- else
- {
- // killed by the world
- char *team = GetTeam(pVictim->m_iTeam);
- UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()),
- GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name);
+ UTIL_LogPrintf("\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", STRING(pevKiller->netname), GETPLAYERUSERID(ENT(pevKiller)), GETPLAYERAUTHID(ENT(pevKiller)),
+ KillerTeam, STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), GETPLAYERAUTHID(pVictim->edict()), VictimTeam, killer_weapon_name);
+ }
+ else
+ {
+ // killed by the world
+ char *team = GetTeam(pVictim->m_iTeam);
+ UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()),
+ GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name);
+ }
}
// TODO: It is called in CBasePlayer::Killed too, most likely,
@@ -4554,12 +4546,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle)
if (Q_strlen(pToken) <= 0)
break;
-#ifdef REGAMEDLL_FIXES
- Q_strncpy(szMap, pToken, sizeof(szMap) - 1);
- szMap[sizeof(szMap) - 1] = '\0';
-#else
- Q_strcpy(szMap, pToken);
-#endif
+ Q_strlcpy(szMap, pToken);
// Any more tokens on this line?
if (SharedTokenWaiting(pFileList))
@@ -4568,7 +4555,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle)
if (Q_strlen(pToken) > 0)
{
hasBuffer = true;
- Q_strcpy(szBuffer, pToken);
+ Q_strlcpy(szBuffer, pToken);
}
}
@@ -4580,7 +4567,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle)
item = new mapcycle_item_s;
- Q_strcpy(item->mapname, szMap);
+ Q_strlcpy(item->mapname, szMap);
item->minplayers = 0;
item->maxplayers = 0;
@@ -4610,7 +4597,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle)
REMOVE_KEY_VALUE(szBuffer, "minplayers");
REMOVE_KEY_VALUE(szBuffer, "maxplayers");
- Q_strcpy(item->rulebuffer, szBuffer);
+ Q_strlcpy(item->rulebuffer, szBuffer);
}
item->next = cycle->items;
@@ -4675,7 +4662,7 @@ int CountPlayers()
}
// Parse commands/key value pairs to issue right after map xxx command is issued on server level transition
-void ExtractCommandString(char *s, char *szCommand)
+void ExtractCommandString(char *s, char *szCommand, size_t len)
{
// Now make rules happen
char pkey[512];
@@ -4744,13 +4731,13 @@ void ExtractCommandString(char *s, char *szCommand)
*c = '\0';
- Q_strcat(szCommand, pkey);
+ Q_strlcat(szCommand, pkey, len);
if (Q_strlen(value) > 0)
{
- Q_strcat(szCommand, " ");
- Q_strcat(szCommand, value);
+ Q_strlcat(szCommand, " ", len);
+ Q_strlcat(szCommand, value, len);
}
- Q_strcat(szCommand, "\n");
+ Q_strlcat(szCommand, "\n", len);
/*if (!*s)
{
@@ -4937,10 +4924,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)()
#ifdef REGAMEDLL_FIXES
// the absolute default level is de_dust
- Q_strcpy(szFirstMapInList, "de_dust");
+ Q_strlcpy(szFirstMapInList, "de_dust");
#else
// the absolute default level is hldm1
- Q_strcpy(szFirstMapInList, "hldm1");
+ Q_strlcpy(szFirstMapInList, "hldm1");
#endif
int curplayers;
@@ -4958,7 +4945,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)()
// Has the map cycle filename changed?
if (Q_stricmp(mapcfile, szPreviousMapCycleFile) != 0)
{
- Q_strcpy(szPreviousMapCycleFile, mapcfile);
+ Q_strlcpy(szPreviousMapCycleFile, mapcfile);
DestroyMapCycle(&mapcycle);
@@ -4976,8 +4963,8 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)()
mapcycle_item_s *item;
// Assume current map
- Q_strcpy(szNextMap, STRING(gpGlobals->mapname));
- Q_strcpy(szFirstMapInList, STRING(gpGlobals->mapname));
+ Q_strlcpy(szNextMap, STRING(gpGlobals->mapname));
+ Q_strlcpy(szFirstMapInList, STRING(gpGlobals->mapname));
// Traverse list
for (item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next)
@@ -5030,14 +5017,14 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)()
mapcycle.next_item = item->next;
// Perform logic on current item
- Q_strcpy(szNextMap, item->mapname);
- ExtractCommandString(item->rulebuffer, szCommands);
- Q_strcpy(szRules, item->rulebuffer);
+ Q_strlcpy(szNextMap, item->mapname);
+ ExtractCommandString(item->rulebuffer, szCommands, sizeof(szCommands));
+ Q_strlcpy(szRules, item->rulebuffer);
}
if (!IS_MAP_VALID(szNextMap))
{
- Q_strcpy(szNextMap, szFirstMapInList);
+ Q_strlcpy(szNextMap, szFirstMapInList);
}
m_bGameOver = true;
@@ -5077,17 +5064,7 @@ void CHalfLifeMultiplay::SendMOTDToClient(edict_t *client)
while (pFileList && *pFileList && char_count < MAX_MOTD_LENGTH)
{
char chunk[MAX_MOTD_CHUNK + 1];
-
- if (Q_strlen(pFileList) < sizeof(chunk))
- {
- Q_strcpy(chunk, pFileList);
- }
- else
- {
- Q_strncpy(chunk, pFileList, sizeof(chunk) - 1);
- // Q_strncpy doesn't always append the null terminator
- chunk[sizeof(chunk) - 1] = '\0';
- }
+ Q_strlcpy(chunk, pFileList);
char_count += Q_strlen(chunk);
diff --git a/regamedll/dlls/observer.cpp b/regamedll/dlls/observer.cpp
index 4b3521a6c..3ccefc433 100644
--- a/regamedll/dlls/observer.cpp
+++ b/regamedll/dlls/observer.cpp
@@ -480,14 +480,14 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_SetMode)(int iMode)
{
#ifdef REGAMEDLL_FIXES
m_hObserverTarget = Observer_IsValidTarget( ENTINDEX(m_hObserverTarget->edict()), forcecamera != CAMERA_MODE_SPEC_ANYONE );
-#else
+#else
CBasePlayer *pTarget = m_hObserverTarget;
- if (pTarget == this
- || !pTarget
- || pTarget->has_disconnected
- || pTarget->GetObserverMode() != OBS_NONE
- || (pTarget->pev->effects & EF_NODRAW)
+ if (pTarget == this
+ || !pTarget
+ || pTarget->has_disconnected
+ || pTarget->GetObserverMode() != OBS_NONE
+ || (pTarget->pev->effects & EF_NODRAW)
|| (forcecamera != CAMERA_MODE_SPEC_ANYONE && pTarget->m_iTeam != m_iTeam))
m_hObserverTarget = nullptr;
#endif
@@ -534,7 +534,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_SetMode)(int iMode)
// print spepctaor mode on client screen
char modemsg[16];
- Q_sprintf(modemsg, "#Spec_Mode%i", pev->iuser1);
+ Q_snprintf(modemsg, sizeof(modemsg), "#Spec_Mode%i", pev->iuser1);
ClientPrint(pev, HUD_PRINTCENTER, modemsg);
m_iObserverLastMode = iMode;
@@ -548,4 +548,4 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_Think)()
Observer_HandleButtons();
Observer_CheckTarget();
Observer_CheckProperties();
-}
\ No newline at end of file
+}
diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp
index 1a895df62..67aa43e47 100644
--- a/regamedll/dlls/player.cpp
+++ b/regamedll/dlls/player.cpp
@@ -115,6 +115,57 @@ void CBasePlayer::SendItemStatus()
MESSAGE_END();
}
+#ifdef REGAMEDLL_ADD
+
+enum PlayerIdShowHealth
+{
+ PLAYERID_HIDE = 0, // Don't show health
+ PLAYERID_TEAMMATES = 1, // Show health for teammates only (default CS)
+ PLAYERID_ALL = 2 // Show health for all players
+};
+
+enum PlayerIdField
+{
+ PLAYERID_FIELD_NONE = 0, // No extra info
+ PLAYERID_FIELD_TEAM = 1, // Show team name
+ PLAYERID_FIELD_HEALTH = 2, // Show health percentage
+ PLAYERID_FIELD_BOTH = 3 // Show both team name and health
+};
+
+inline const char *GetPlayerIdString(bool sameTeam)
+{
+ int showHealth = static_cast(playerid_showhealth.value);
+ int fieldType = static_cast(playerid_field.value);
+
+ // Don't show health
+ if (showHealth == PLAYERID_HIDE)
+ {
+ return (fieldType == PLAYERID_FIELD_NONE) ? "1 %p2" : "1 %c1: %p2";
+ }
+
+ // Health only for teammates
+ if (showHealth == PLAYERID_TEAMMATES && !sameTeam)
+ {
+ switch (fieldType)
+ {
+ case PLAYERID_FIELD_TEAM: return "1 %c1: %p2";
+ case PLAYERID_FIELD_HEALTH: return "1 %p2";
+ case PLAYERID_FIELD_BOTH: return "1 %c1: %p2";
+ default: return "1 %p2";
+ }
+ }
+
+ // Show health to everyone
+ switch (fieldType)
+ {
+ case PLAYERID_FIELD_TEAM: return "1 %c1: %p2\n2 : %i3%%";
+ case PLAYERID_FIELD_HEALTH: return "1 %p2\n2 %h: %i3%%";
+ case PLAYERID_FIELD_BOTH: return "1 %c1: %p2\n2 %h: %i3%%";
+ default: return "1 %p2\n2 : %i3%%";
+ }
+}
+#endif
+
const char *GetCSModelName(int item_id)
{
const char *modelName = nullptr;
@@ -569,13 +620,20 @@ LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, DeathSound)
void EXT_FUNC CBasePlayer::__API_HOOK(DeathSound)()
{
+#if REGAMEDLL_FIXES
+ // FIXED: Don't interrupt pain sounds with death sound, use any available channel instead
+ const int channel = CHAN_AUTO;
+#else
+ const int channel = CHAN_VOICE;
+#endif
+
// temporarily using pain sounds for death sounds
switch (RANDOM_LONG(1, 4))
{
- case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/die1.wav", VOL_NORM, ATTN_NORM); break;
- case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/die2.wav", VOL_NORM, ATTN_NORM); break;
- case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/die3.wav", VOL_NORM, ATTN_NORM); break;
- case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/death6.wav", VOL_NORM, ATTN_NORM); break;
+ case 1: EMIT_SOUND(ENT(pev), channel, "player/die1.wav", VOL_NORM, ATTN_NORM); break;
+ case 2: EMIT_SOUND(ENT(pev), channel, "player/die2.wav", VOL_NORM, ATTN_NORM); break;
+ case 3: EMIT_SOUND(ENT(pev), channel, "player/die3.wav", VOL_NORM, ATTN_NORM); break;
+ case 4: EMIT_SOUND(ENT(pev), channel, "player/death6.wav", VOL_NORM, ATTN_NORM); break;
}
}
@@ -1175,7 +1233,7 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva
if (!ShouldDoLargeFlinch(m_LastHitGroup, iGunType))
{
- m_flVelocityModifier = 0.5f;
+ TakeDamageImpulse(pAttack, 0.0f, 0.5f);
if (m_LastHitGroup == HITGROUP_HEAD)
m_bHighDamage = (flDamage > 60);
@@ -1188,10 +1246,13 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva
{
if (pev->velocity.Length() < 300)
{
- Vector attack_velocity = (pev->origin - pAttack->pev->origin).Normalize() * 170;
- pev->velocity = pev->velocity + attack_velocity;
+#ifdef REGAMEDLL_ADD
+ float knockbackValue = knockback.value;
+#else
+ float knockbackValue = 170;
+#endif
- m_flVelocityModifier = 0.65f;
+ TakeDamageImpulse(pAttack, knockbackValue, 0.65f);
}
SetAnimation(PLAYER_LARGE_FLINCH);
@@ -1480,7 +1541,7 @@ void CBasePlayer::PackDeadPlayerItems()
{
DropShield();
#ifdef REGAMEDLL_ADD
- if(iPackGun != GR_PLR_DROP_GUN_ALL)
+ if (iPackGun != GR_PLR_DROP_GUN_ALL)
#endif
{
bSkipPrimSec = true;
@@ -1637,6 +1698,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)()
// Give default secondary equipment
{
char *secondaryString = NULL;
+ int secondaryCount = 0;
+ const int MAX_SECONDARY = 13; // x2 + 1
+ WeaponInfoStruct *secondaryWeaponInfoArray[MAX_SECONDARY];
+
if (m_iTeam == CT)
secondaryString = ct_default_weapons_secondary.string;
else if (m_iTeam == TERRORIST)
@@ -1658,18 +1723,34 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)()
if (weaponInfo) {
const auto iItemID = GetItemIdByWeaponId(weaponInfo->id);
if (iItemID != ITEM_NONE && !HasRestrictItem(iItemID, ITEM_TYPE_EQUIPPED) && IsSecondaryWeapon(iItemID)) {
- GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName);
+ if (default_weapons_random.value != 0.0f) {
+ if (secondaryCount < MAX_SECONDARY) {
+ secondaryWeaponInfoArray[secondaryCount++] = weaponInfo;
+ }
+ }
+ else {
+ GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName);
+ }
}
}
secondaryString = SharedParse(secondaryString);
}
+
+ if (default_weapons_random.value != 0.0f) {
+ WeaponInfoStruct *weaponInfo = secondaryWeaponInfoArray[RANDOM_LONG(0, secondaryCount - 1)];
+ if (weaponInfo)
+ GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName);
+ }
}
}
// Give default primary equipment
{
char *primaryString = NULL;
+ int primaryCount = 0;
+ const int MAX_PRIMARY = 39; // x2 + 1
+ WeaponInfoStruct *primaryWeaponInfoArray[MAX_PRIMARY];
if (m_iTeam == CT)
primaryString = ct_default_weapons_primary.string;
@@ -1692,12 +1773,25 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)()
if (weaponInfo) {
const auto iItemID = GetItemIdByWeaponId(weaponInfo->id);
if (iItemID != ITEM_NONE && !HasRestrictItem(iItemID, ITEM_TYPE_EQUIPPED) && IsPrimaryWeapon(iItemID)) {
- GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName);
+ if (default_weapons_random.value != 0.0f) {
+ if (primaryCount < MAX_PRIMARY) {
+ primaryWeaponInfoArray[primaryCount++] = weaponInfo;
+ }
+ }
+ else {
+ GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName);
+ }
}
}
primaryString = SharedParse(primaryString);
}
+
+ if (default_weapons_random.value != 0.0f) {
+ WeaponInfoStruct *weaponInfo = primaryWeaponInfoArray[RANDOM_LONG(0, primaryCount - 1)];
+ if (weaponInfo)
+ GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName);
+ }
}
}
@@ -2179,7 +2273,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib)
{
CBasePlayer *pAttacker = CBasePlayer::Instance(pevAttacker);
- if(pAttacker /*safety*/ && !pAttacker->IsBot() && pAttacker->m_iTeam != m_iTeam)
+ if (pAttacker /*safety*/ && !pAttacker->IsBot() && pAttacker->m_iTeam != m_iTeam)
{
if (pAttacker->HasShield())
killerHasShield = true;
@@ -2455,8 +2549,16 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib)
break;
}
+ // UNDO: This code was intended to set the victim's angle with the throw direction
+ // For bots, it works correctly because they do not send angle updates to the server,
+ // However, for players, the client overrides the angle with its own view direction in the next frame,
+ // causing a visual glitch where the model rotates excessively
+ // The issue is more noticeable with high cmdrate values (e.g., cl_cmdrate >100)
+ // Disabled to avoid this artifact
+#ifndef REGAMEDLL_FIXES
pev->angles.y = UTIL_VecToAngles(-pev->velocity).y;
pev->v_angle.y = pev->angles.y;
+#endif
m_iThrowDirection = THROW_NONE;
}
@@ -2556,11 +2658,19 @@ BOOL CBasePlayer::IsBombGuy()
LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayer, SetAnimation, (PLAYER_ANIM playerAnim), playerAnim)
+int CBasePlayer::GetAnimDesired(const char *szAnim, AnimationType type)
+{
+ const char *refAnim = (type == ANIM_CROUCH && (pev->flags & FL_DUCKING)) ? "crouch_" : "ref_";
+
+ char szAnimConstruct[128];
+ Q_snprintf(szAnimConstruct, sizeof(szAnimConstruct), "%s%s_%s", refAnim, szAnim, m_szAnimExtention);
+ return LookupSequence(szAnimConstruct);
+}
+
void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
int animDesired;
float speed;
- char szAnim[64];
int hopSeq;
int leapSeq;
@@ -2696,16 +2806,17 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
if (m_Activity == m_IdealActivity)
return;
+ const char *refAnim;
+
switch (m_Activity)
{
- case ACT_RANGE_ATTACK1: Q_strcpy(szAnim, "ref_shoot_"); break;
- case ACT_RANGE_ATTACK2: Q_strcpy(szAnim, "ref_shoot2_"); break;
- case ACT_RELOAD: Q_strcpy(szAnim, "ref_reload_"); break;
- default: Q_strcpy(szAnim, "ref_aim_"); break;
+ case ACT_RANGE_ATTACK1: refAnim = "shoot"; break;
+ case ACT_RANGE_ATTACK2: refAnim = "shoot2"; break;
+ case ACT_RELOAD: refAnim = "reload"; break;
+ default: refAnim = "aim"; break;
}
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired(refAnim, ANIM_NORMAL);
if (animDesired == -1)
animDesired = 0;
@@ -2727,13 +2838,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
m_flLastFired = gpGlobals->time;
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_shoot_");
- else
- Q_strcpy(szAnim, "ref_shoot_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("shoot", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2748,13 +2853,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
m_flLastFired = gpGlobals->time;
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_shoot2_");
- else
- Q_strcpy(szAnim, "ref_shoot2_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("shoot2", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2767,13 +2866,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
}
case ACT_RELOAD:
{
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_reload_");
- else
- Q_strcpy(szAnim, "ref_reload_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("reload", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2788,13 +2881,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
}
case ACT_HOLDBOMB:
{
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_aim_");
- else
- Q_strcpy(szAnim, "ref_aim_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("aim", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2811,13 +2898,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
if (speed <= 135.0f || m_flLastFired + 4.0 >= gpGlobals->time)
{
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_aim_");
- else
- Q_strcpy(szAnim, "ref_aim_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("aim", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2825,18 +2906,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
}
else
{
- Q_strcpy(szAnim, "run_");
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("run", ANIM_NORMAL);
if (animDesired == -1)
{
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_aim_");
- else
- Q_strcpy(szAnim, "ref_aim_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("aim", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2974,10 +3047,8 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
break;
case 3:
case 4:
-#ifndef REGAMEDLL_FIXES
m_iThrowDirection = THROW_FORWARD;
break;
-#endif
case 5:
case 6:
m_iThrowDirection = THROW_HITVEL;
@@ -3086,20 +3157,9 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
if (m_Activity != ACT_FLINCH && m_Activity != ACT_LARGE_FLINCH)
{
- Q_strcpy(szAnim, "run_");
- Q_strcat(szAnim, m_szAnimExtention);
-
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("run", ANIM_NORMAL);
if (animDesired == -1)
- {
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_aim_");
- else
- Q_strcpy(szAnim, "ref_aim_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
- }
+ animDesired = GetAnimDesired("aim", ANIM_CROUCH);
else
pev->gaitsequence = animDesired;
@@ -4200,7 +4260,7 @@ void CBasePlayer::PlayerUse()
}
}
- bool useNewHostages = !TheNavAreaList.empty() && AreImprovAllowed();
+ bool useNewHostages = !TheNavAreaList.empty() && cv_hostage_ai_enable.value;
CBaseEntity *pObject = nullptr;
CBaseEntity *pClosest = nullptr;
Vector vecLOS;
@@ -4310,10 +4370,10 @@ void CBasePlayer::PlayerUse()
}
// UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
// BUGBUG This is an "off" use
- else if ((m_afButtonReleased & IN_USE)
+ else if ((m_afButtonReleased & IN_USE)
#ifdef REGAMEDLL_FIXES
&& (caps & FCAP_ONOFF_USE))
-#else
+#else
&& (pObject->ObjectCaps() & FCAP_ONOFF_USE))
#endif
{
@@ -5047,8 +5107,7 @@ void CBasePlayer::CheckSuitUpdate()
{
// play sentence number
char sentence[MAX_SENTENCE_NAME + 1];
- Q_strcpy(sentence, "!");
- Q_strcat(sentence, gszallsentencenames[isentence]);
+ Q_snprintf(sentence, sizeof(sentence), "!%s", gszallsentencenames[isentence]);
EMIT_SOUND_SUIT(ENT(pev), sentence);
}
else
@@ -5186,12 +5245,9 @@ void CBasePlayer::UpdatePlayerSound()
m_iExtraSoundTypes = 0;
}
- if (pSound)
- {
- pSound->m_vecOrigin = pev->origin;
- pSound->m_iVolume = iVolume;
- pSound->m_iType |= (bits_SOUND_PLAYER | m_iExtraSoundTypes);
- }
+ pSound->m_vecOrigin = pev->origin;
+ pSound->m_iVolume = iVolume;
+ pSound->m_iType |= (bits_SOUND_PLAYER | m_iExtraSoundTypes);
// keep track of virtual muzzle flash
m_iWeaponFlash -= 256 * gpGlobals->frametime;
@@ -5369,22 +5425,24 @@ void EXT_FUNC CBasePlayer::__API_HOOK(PostThink)()
}
// checks if the spot is clear of players
-BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot)
+BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot, float fRadius)
{
if (!pSpot->IsTriggered(pPlayer))
return FALSE;
-#ifdef REGAMEDLL_ADD
- if (!kill_filled_spawn.value)
- return TRUE;
-#endif
-
CBaseEntity *pEntity = nullptr;
- while ((pEntity = UTIL_FindEntityInSphere(pEntity, pSpot->pev->origin, MAX_PLAYER_USE_RADIUS)))
+
+ while ((pEntity = UTIL_FindEntityInSphere(pEntity, pSpot->pev->origin, fRadius)))
{
// if ent is a client, don't spawn on 'em
- if (pEntity->IsPlayer() && pEntity != pPlayer)
+ if (pEntity->IsPlayer() && pEntity != pPlayer
+#ifdef REGAMEDLL_FIXES
+ && pEntity->IsAlive()
+#endif
+ )
+ {
return FALSE;
+ }
}
return TRUE;
@@ -5409,17 +5467,34 @@ bool CBasePlayer::SelectSpawnSpot(const char *pEntClassName, CBaseEntity *&pSpot
{
if (pSpot)
{
- // check if pSpot is valid
- if (IsSpawnPointValid(this, pSpot))
+#ifdef REGAMEDLL_ADD
+ if (FClassnameIs(pSpot->edict(), "info_spawn_point"))
{
- if (pSpot->pev->origin == Vector(0, 0, 0))
+ if (!IsSpawnPointValid(this, pSpot, 512.0f) || pSpot->pev->origin == Vector(0, 0, 0))
{
pSpot = UTIL_FindEntityByClassname(pSpot, pEntClassName);
continue;
}
+ else
+ {
+ return true;
+ }
+ }
+ else
+#endif
+ {
+ // check if pSpot is valid
+ if (IsSpawnPointValid(this, pSpot, MAX_PLAYER_USE_RADIUS))
+ {
+ if (pSpot->pev->origin == Vector(0, 0, 0))
+ {
+ pSpot = UTIL_FindEntityByClassname(pSpot, pEntClassName);
+ continue;
+ }
- // if so, go to pSpot
- return true;
+ // if so, go to pSpot
+ return true;
+ }
}
}
@@ -5477,6 +5552,24 @@ edict_t *EXT_FUNC CBasePlayer::__API_HOOK(EntSelectSpawnPoint)()
if (!FNullEnt(pSpot))
goto ReturnSpot;
}
+#ifdef REGAMEDLL_ADD
+ else if (randomspawn.value > 0)
+ {
+ pSpot = g_pLastSpawn;
+
+ if (SelectSpawnSpot("info_spawn_point", pSpot))
+ {
+ g_pLastSpawn = pSpot;
+
+ return pSpot->edict();
+ }
+
+ if (m_iTeam == CT)
+ goto CTSpawn;
+ else if (m_iTeam == TERRORIST)
+ goto TSpawn;
+ }
+#endif
// VIP spawn point
else if (g_pGameRules->IsDeathmatch() && m_bIsVIP)
{
@@ -5504,6 +5597,9 @@ edict_t *EXT_FUNC CBasePlayer::__API_HOOK(EntSelectSpawnPoint)()
// The terrorist spawn points
else if (g_pGameRules->IsDeathmatch() && m_iTeam == TERRORIST)
{
+#ifdef REGAMEDLL_ADD
+TSpawn:
+#endif
pSpot = g_pLastTerroristSpawn;
if (SelectSpawnSpot("info_player_deathmatch", pSpot))
@@ -5946,7 +6042,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Spawn)()
TheBots->OnEvent(EVENT_PLAYER_SPAWNED, this);
}
- m_allowAutoFollowTime = false;
+ m_allowAutoFollowTime = 0.0f;
for (i = 0; i < COMMANDS_TO_TRACK; i++)
m_flLastCommandTime[i] = -1;
@@ -8073,13 +8169,15 @@ void CBasePlayer::InitStatusBar()
m_SbarString0[0] = '\0';
}
-void CBasePlayer::UpdateStatusBar()
+LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, UpdateStatusBar)
+
+void EXT_FUNC CBasePlayer::__API_HOOK(UpdateStatusBar)()
{
int newSBarState[SBAR_END];
char sbuf0[MAX_SBAR_STRING];
Q_memset(newSBarState, 0, sizeof(newSBarState));
- Q_strcpy(sbuf0, m_SbarString0);
+ Q_strlcpy(sbuf0, m_SbarString0);
// Find an ID Target
TraceResult tr;
@@ -8109,11 +8207,19 @@ void CBasePlayer::UpdateStatusBar()
if (sameTeam || GetObserverMode() != OBS_NONE)
{
if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE)
- Q_strcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%");
+#ifndef REGAMEDLL_ADD
+ Q_strlcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%");
+#else
+ Q_strlcpy(sbuf0, GetPlayerIdString(sameTeam));
+#endif
else
- Q_strcpy(sbuf0, " ");
-
- newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100);
+ Q_strlcpy(sbuf0, " ");
+#ifdef REGAMEDLL_ADD
+ if (static_cast(playerid_showhealth.value) != PLAYERID_FIELD_NONE)
+#endif
+ {
+ newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100);
+ }
if (!(m_flDisplayHistory & DHF_FRIEND_SEEN) && !(pev->flags & FL_SPECTATOR))
{
@@ -8124,10 +8230,18 @@ void CBasePlayer::UpdateStatusBar()
else if (GetObserverMode() == OBS_NONE)
{
if (playerid.value != PLAYERID_MODE_TEAMONLY && playerid.value != PLAYERID_MODE_OFF)
- Q_strcpy(sbuf0, "1 %c1: %p2");
+#ifndef REGAMEDLL_ADD
+ Q_strlcpy(sbuf0, "1 %c1: %p2");
+#else
+ Q_strlcpy(sbuf0, GetPlayerIdString(sameTeam));
+#endif
else
- Q_strcpy(sbuf0, " ");
+ Q_strlcpy(sbuf0, " ");
+#ifdef REGAMEDLL_ADD
+ if (static_cast(playerid_showhealth.value) == PLAYERID_ALL)
+ newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100);
+#endif
if (!(m_flDisplayHistory & DHF_ENEMY_SEEN))
{
m_flDisplayHistory |= DHF_ENEMY_SEEN;
@@ -8140,9 +8254,9 @@ void CBasePlayer::UpdateStatusBar()
else if (pEntity->Classify() == CLASS_HUMAN_PASSIVE)
{
if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE)
- Q_strcpy(sbuf0, "1 %c1 %h: %i3%%");
+ Q_strlcpy(sbuf0, "1 %c1 %h: %i3%%");
else
- Q_strcpy(sbuf0, " ");
+ Q_strlcpy(sbuf0, " ");
newSBarState[SBAR_ID_TARGETTYPE] = SBAR_TARGETTYPE_HOSTAGE;
newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100);
@@ -8184,7 +8298,7 @@ void CBasePlayer::UpdateStatusBar()
WRITE_STRING(sbuf0);
MESSAGE_END();
- Q_strcpy(m_SbarString0, sbuf0);
+ Q_strlcpy(m_SbarString0, sbuf0);
// make sure everything's resent
bForceResend = true;
@@ -8503,7 +8617,7 @@ void CBasePlayer::__API_HOOK(SwitchTeam)()
UpdateLocation(true);
- if (m_iTeam)
+ if (m_iTeam != UNASSIGNED)
{
SetScoreboardAttributes();
}
@@ -9375,14 +9489,10 @@ void CBasePlayer::AddAutoBuyData(const char *str)
{
if (len > 0)
{
- Q_strncat(m_autoBuyString, " ", len);
+ Q_strlcat(m_autoBuyString, " ");
}
-#ifndef REGAMEDLL_FIXES
- Q_strncat(m_autoBuyString, str, sizeof(m_autoBuyString) - Q_strlen(m_autoBuyString));
-#else
- Q_strncat(m_autoBuyString, str, sizeof(m_autoBuyString) - Q_strlen(m_autoBuyString) - 1);
-#endif
+ Q_strlcat(m_autoBuyString, str);
}
}
@@ -9399,9 +9509,7 @@ void CBasePlayer::InitRebuyData(const char *str)
m_rebuyString = nullptr;
}
- m_rebuyString = new char[Q_strlen(str) + 1];
- Q_strcpy(m_rebuyString, str);
- m_rebuyString[Q_strlen(str)] = '\0';
+ m_rebuyString = CloneString(str);
}
void CBasePlayer::AutoBuy()
@@ -9429,7 +9537,7 @@ void CBasePlayer::AutoBuy()
if (c)
{
- Q_strcpy(prioritizedString, c);
+ Q_strlcpy(prioritizedString, c);
PrioritizeAutoBuyString(prioritizedString, m_autoBuyString);
ParseAutoBuyString(prioritizedString, boughtPrimary, boughtSecondary);
@@ -9439,7 +9547,7 @@ void CBasePlayer::AutoBuy()
if (c)
{
- Q_strcpy(prioritizedString, c);
+ Q_strlcpy(prioritizedString, c);
PrioritizeAutoBuyString(prioritizedString, m_autoBuyString);
ParseAutoBuyString(prioritizedString, boughtPrimary, boughtSecondary);
@@ -9587,11 +9695,11 @@ const char *CBasePlayer::PickPrimaryCareerTaskWeapon()
CCareerTask *pTask = taskVector[i];
if (IsPrimaryWeaponId(pTask->GetWeaponId()))
- Q_strncat(buf, WeaponIDToAlias(pTask->GetWeaponId()), sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, WeaponIDToAlias(pTask->GetWeaponId()));
else
- Q_strncat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()), sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()));
- Q_strncat(buf, " ", sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, " ");
}
return buf;
@@ -9662,11 +9770,11 @@ const char *CBasePlayer::PickSecondaryCareerTaskWeapon()
CCareerTask *pTask = taskVector[i];
if (IsSecondaryWeaponId(pTask->GetWeaponId()))
- Q_strncat(buf, WeaponIDToAlias(pTask->GetWeaponId()), sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, WeaponIDToAlias(pTask->GetWeaponId()));
else
- Q_strncat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()), sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()));
- Q_strncat(buf, " ", sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, " ");
}
return buf;
@@ -9715,13 +9823,13 @@ const char *CBasePlayer::PickGrenadeKillWeaponString()
}
// PostAutoBuyCommandProcessing - reorders the tokens in autobuyString based on the order of tokens in the priorityString.
-void CBasePlayer::PrioritizeAutoBuyString(char *autobuyString, const char *priorityString)
+void CBasePlayer::PrioritizeAutoBuyString(char (&autobuyString)[MAX_AUTOBUY_LENGTH], const char *priorityString)
{
char newString[MAX_AUTOBUY_LENGTH];
int newStringPos = 0;
char priorityToken[32];
- if (!priorityString || !autobuyString)
+ if (!priorityString)
return;
const char *priorityChar = priorityString;
@@ -9788,7 +9896,7 @@ void CBasePlayer::PrioritizeAutoBuyString(char *autobuyString, const char *prior
// terminate the string. Trailing spaces shouldn't matter.
newString[newStringPos] = '\0';
- Q_sprintf(autobuyString, "%s", newString);
+ Q_snprintf(autobuyString, sizeof(autobuyString), "%s", newString);
}
void CBasePlayer::ParseAutoBuyString(const char *string, bool &boughtPrimary, bool &boughtSecondary)
@@ -10158,7 +10266,11 @@ bool CBasePlayer::IsObservingPlayer(CBasePlayer *pPlayer)
void CBasePlayer::UpdateLocation(bool forceUpdate)
{
+#ifdef REGAMEDLL_FIXES
+ if (!forceUpdate && m_flLastUpdateTime > gpGlobals->time - 2.0f)
+#else
if (!forceUpdate && m_flLastUpdateTime >= gpGlobals->time + 2.0f)
+#endif
return;
const char *placeName = nullptr;
@@ -10758,6 +10870,17 @@ bool CBasePlayer::Kill()
return true;
}
+LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayer, TakeDamageImpulse, (CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier), pAttacker, flKnockbackForce, flVelModifier)
+
+void EXT_FUNC CBasePlayer::__API_HOOK(TakeDamageImpulse)(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier)
+{
+ if (flKnockbackForce != 0.0f)
+ pev->velocity += (pev->origin - pAttacker->pev->origin).Normalize() * flKnockbackForce;
+
+ if (flVelModifier != 0.0f)
+ m_flVelocityModifier = flVelModifier;
+}
+
const usercmd_t *CBasePlayer::GetLastUserCommand() const
{
#ifdef REGAMEDLL_API
diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h
index 182c4a379..f3ec649c3 100644
--- a/regamedll/dlls/player.h
+++ b/regamedll/dlls/player.h
@@ -450,6 +450,8 @@ class CBasePlayer: public CBaseMonster {
void PlayerDeathThink_OrigFunc();
void Observer_Think_OrigFunc();
void RemoveAllItems_OrigFunc(BOOL removeSuit);
+ void UpdateStatusBar_OrigFunc();
+ void TakeDamageImpulse_OrigFunc(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier);
CCSPlayer *CSPlayer() const;
#endif // REGAMEDLL_API
@@ -522,7 +524,9 @@ class CBasePlayer: public CBaseMonster {
void UpdatePlayerSound();
void DeathSound();
void SetAnimation(PLAYER_ANIM playerAnim);
- void SetWeaponAnimType(const char *szExtention) { Q_strcpy(m_szAnimExtention, szExtention); }
+ enum AnimationType { ANIM_NORMAL, ANIM_CROUCH };
+ int GetAnimDesired(const char *szAnim, AnimationType type);
+ void SetWeaponAnimType(const char *szExtention) { Q_strlcpy(m_szAnimExtention, szExtention); }
void CheatImpulseCommands(int iImpulse);
void StartDeathCam();
void StartObserver(Vector &vecPosition, Vector &vecViewAngle);
@@ -602,7 +606,7 @@ class CBasePlayer: public CBaseMonster {
void AddAutoBuyData(const char *str);
void AutoBuy();
void ClientCommand(const char *cmd, const char *arg1 = nullptr, const char *arg2 = nullptr, const char *arg3 = nullptr);
- void PrioritizeAutoBuyString(char *autobuyString, const char *priorityString);
+ void PrioritizeAutoBuyString(char (&autobuyString)[MAX_AUTOBUY_LENGTH], const char *priorityString);
const char *PickPrimaryCareerTaskWeapon();
const char *PickSecondaryCareerTaskWeapon();
const char *PickFlashKillWeaponString();
@@ -656,6 +660,7 @@ class CBasePlayer: public CBaseMonster {
void UseEmpty();
void DropIdlePlayer(const char *reason);
bool Kill();
+ void TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier);
// templates
template
@@ -1042,7 +1047,7 @@ int TrainSpeed(int iSpeed, int iMax);
void LogAttack(CBasePlayer *pAttacker, CBasePlayer *pVictim, int teamAttack, int healthHit, int armorHit, int newHealth, int newArmor, const char *killer_weapon_name);
bool CanSeeUseable(CBasePlayer *me, CBaseEntity *pEntity);
void FixPlayerCrouchStuck(edict_t *pPlayer);
-BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot);
+BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot, float fRadius);
CBaseEntity *FindEntityForward(CBaseEntity *pMe);
real_t GetPlayerPitch(const edict_t *pEdict);
real_t GetPlayerYaw(const edict_t *pEdict);
diff --git a/regamedll/dlls/qstring.h b/regamedll/dlls/qstring.h
index 0b158292b..1f5d679dd 100644
--- a/regamedll/dlls/qstring.h
+++ b/regamedll/dlls/qstring.h
@@ -30,16 +30,18 @@
#define QSTRING_DEFINE
-constexpr unsigned int iStringNull = {0};
-
// Quake string (helper class)
class QString final
{
public:
+#if XASH_64BIT
+ using qstring_t = int;
+#else
using qstring_t = unsigned int;
+#endif
- QString(): m_string(iStringNull) {};
- QString(qstring_t string): m_string(string) {};
+ QString();
+ QString(qstring_t string);
bool IsNull() const;
bool IsNullOrEmpty() const;
@@ -52,13 +54,15 @@ class QString final
bool operator==(const char *pszString) const;
operator const char *() const;
- operator unsigned int() const;
+ operator qstring_t() const;
const char *str() const;
private:
qstring_t m_string;
};
+constexpr QString::qstring_t iStringNull = {0};
+
#ifdef USE_QSTRING
#define string_t QString
#endif
@@ -70,10 +74,25 @@ class QString final
extern globalvars_t *gpGlobals;
-#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (unsigned int)(offset)))
-#define MAKE_STRING(str) ((unsigned int)(str) - (unsigned int)(STRING(0)))
+#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (QString::qstring_t)(offset)))
+#if XASH_64BIT
+// Xash3D FWGS in 64-bit mode has internal string pool which allows mods to continue use 32-bit string_t
+inline int MAKE_STRING(const char *str)
+{
+ ptrdiff_t diff = str - STRING(0);
+ if (diff >= INT_MIN && diff <= INT_MAX)
+ return (int)diff;
+
+ return ALLOC_STRING(str);
+}
+#else
+#define MAKE_STRING(str) ((QString::qstring_t)(str) - (QString::qstring_t)(STRING(0)))
+#endif
// Inlines
+inline QString::QString(): m_string(iStringNull) {}
+inline QString::QString(qstring_t string): m_string(string) {}
+
inline bool QString::IsNull() const
{
return m_string == iStringNull;
@@ -115,7 +134,7 @@ inline QString::operator const char *() const
return str();
}
-inline QString::operator unsigned int() const
+inline QString::operator qstring_t() const
{
return m_string;
}
diff --git a/regamedll/dlls/saverestore.cpp b/regamedll/dlls/saverestore.cpp
index a3a55c7f6..514ca64b8 100644
--- a/regamedll/dlls/saverestore.cpp
+++ b/regamedll/dlls/saverestore.cpp
@@ -250,10 +250,10 @@ edict_t *CSaveRestoreBuffer::EntityFromIndex(int entityIndex)
int CSaveRestoreBuffer::EntityFlagsSet(int entityIndex, int flags)
{
- if (!m_pData || entityIndex < 0)
+ if (!m_pData)
return 0;
- if (!m_pData || entityIndex < 0 || entityIndex > m_pData->tableCount)
+ if (entityIndex < 0 || entityIndex > m_pData->tableCount)
return 0;
m_pData->pTable[entityIndex].flags |= flags;
@@ -962,8 +962,8 @@ void CGlobalState::EntityAdd(string_t globalname, string_t mapName, GLOBALESTATE
pNewEntity->pNext = m_pList;
m_pList = pNewEntity;
- Q_strcpy(pNewEntity->name, STRING(globalname));
- Q_strcpy(pNewEntity->levelName, STRING(mapName));
+ Q_strlcpy(pNewEntity->name, STRING(globalname));
+ Q_strlcpy(pNewEntity->levelName, STRING(mapName));
pNewEntity->state = state;
m_listCount++;
@@ -1068,7 +1068,7 @@ void CGlobalState::EntityUpdate(string_t globalname, string_t mapname)
globalentity_t *pEnt = Find(globalname);
if (pEnt)
{
- Q_strcpy(pEnt->levelName, STRING(mapname));
+ Q_strlcpy(pEnt->levelName, STRING(mapname));
}
}
diff --git a/regamedll/dlls/skill.cpp b/regamedll/dlls/skill.cpp
index 87fd4468f..3c0bfe0d3 100644
--- a/regamedll/dlls/skill.cpp
+++ b/regamedll/dlls/skill.cpp
@@ -10,7 +10,7 @@ NOXREF float GetSkillCvar(char *pName)
float flValue;
char szBuffer[64];
- iCount = Q_sprintf(szBuffer, "%s%d", pName, gSkillData.iSkillLevel);
+ iCount = Q_snprintf(szBuffer, sizeof(szBuffer), "%s%d", pName, gSkillData.iSkillLevel);
flValue = CVAR_GET_FLOAT(szBuffer);
if (flValue <= 0.0f)
diff --git a/regamedll/dlls/sound.cpp b/regamedll/dlls/sound.cpp
index baf5353cc..25e930e3d 100644
--- a/regamedll/dlls/sound.cpp
+++ b/regamedll/dlls/sound.cpp
@@ -1040,11 +1040,10 @@ void USENTENCEG_InitLRU(unsigned char *plru, int count)
// ipick is passed in as the requested sentence ordinal.
// ipick 'next' is returned.
// return of -1 indicates an error.
-int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset)
+int USENTENCEG_PickSequential(int isentenceg, char (&szfound)[64], int ipick, int freset)
{
char *szgroupname;
unsigned char count;
- char sznum[12];
if (!fSentencesInit)
return -1;
@@ -1061,10 +1060,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres
if (ipick >= count)
ipick = count - 1;
- Q_strcpy(szfound, "!");
- Q_strcat(szfound, szgroupname);
- Q_snprintf(sznum, sizeof(sznum), "%d", ipick);
- Q_strcat(szfound, sznum);
+ Q_snprintf(szfound, sizeof(szfound), "!%s%d", szgroupname, ipick);
if (ipick >= count)
{
@@ -1084,13 +1080,12 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres
// rest of the lru filled with -1. The first integer in the lru is
// actually the size of the list. Returns ipick, the ordinal
// of the picked sentence within the group.
-int USENTENCEG_Pick(int isentenceg, char *szfound)
+int USENTENCEG_Pick(int isentenceg, char (&szfound)[64])
{
char *szgroupname;
unsigned char *plru;
unsigned char i;
unsigned char count;
- char sznum[12];
unsigned char ipick = 0xFF;
BOOL ffound = FALSE;
@@ -1119,11 +1114,7 @@ int USENTENCEG_Pick(int isentenceg, char *szfound)
if (ffound)
{
- Q_strcpy(szfound, "!");
- Q_strcat(szfound, szgroupname);
- Q_snprintf(sznum, sizeof(sznum), "%d", ipick);
- Q_strcat(szfound, sznum);
-
+ Q_snprintf(szfound, sizeof(szfound), "!%s%d", szgroupname, ipick);
return ipick;
}
else
@@ -1168,8 +1159,6 @@ int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float atte
if (!fSentencesInit)
return -1;
- name[0] = '\0';
-
ipick = USENTENCEG_Pick(isentenceg, name);
#ifndef REGAMEDLL_FIXES
@@ -1194,8 +1183,6 @@ int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, float volume,
if (!fSentencesInit)
return -1;
- name[0] = '\0';
-
isentenceg = SENTENCEG_GetIndex(szgroupname);
if (isentenceg < 0)
{
@@ -1223,8 +1210,6 @@ int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, float v
if (!fSentencesInit)
return -1;
- name[0] = '\0';
-
isentenceg = SENTENCEG_GetIndex(szgroupname);
if (isentenceg < 0)
return -1;
@@ -1323,7 +1308,7 @@ void SENTENCEG_Init()
ALERT(at_warning, "Sentence %s longer than %d letters\n", pString, MAX_SENTENCE_NAME - 1);
}
- Q_strcpy(gszallsentencenames[gcallsentences++], pString);
+ Q_strlcpy(gszallsentencenames[gcallsentences++], pString);
if (--j <= i)
continue;
@@ -1354,10 +1339,10 @@ void SENTENCEG_Init()
break;
}
- Q_strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i]));
+ Q_strlcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i]));
rgsentenceg[isentencegs].count = 1;
- Q_strcpy(szgroup, &(buffer[i]));
+ Q_strlcpy(szgroup, &(buffer[i]));
continue;
}
@@ -1377,7 +1362,7 @@ void SENTENCEG_Init()
i = 0;
- while (rgsentenceg[i].count && i < MAX_SENTENCE_GROUPS)
+ while (i < MAX_SENTENCE_GROUPS && rgsentenceg[i].count)
{
USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count);
i++;
@@ -1385,9 +1370,8 @@ void SENTENCEG_Init()
}
// convert sentence (sample) name to !sentencenum, return !sentencenum
-int SENTENCEG_Lookup(const char *sample, char *sentencenum)
+int SENTENCEG_Lookup(const char *sample, char (&sentencenum)[32])
{
- char sznum[12];
int i;
// this is a sentence name; lookup sentence number
@@ -1396,13 +1380,7 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum)
{
if (!Q_stricmp(gszallsentencenames[i], sample + 1))
{
- if (sentencenum)
- {
- Q_strcpy(sentencenum, "!");
- Q_snprintf(sznum, sizeof(sznum), "%d", i);
- Q_strcat(sentencenum, sznum);
- }
-
+ Q_snprintf(sentencenum, sizeof(sentencenum), "!%d", i);
return i;
}
}
@@ -1580,7 +1558,7 @@ void TEXTURETYPE_Init()
j = Q_min(j, MAX_TEXTURENAME_LENGHT - 1 + i);
buffer[j] = '\0';
- Q_strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i]));
+ Q_strlcpy(grgszTextureName[gcTextures++], &(buffer[i]));
}
FREE_FILE(pMemFile);
@@ -1616,7 +1594,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
char chTextureType;
float fvol;
float fvolbar;
- char szBuffer[64];
+ char szBuffer[MAX_TEXTURENAME_LENGHT];
const char *pTextureName;
float rgfl1[3];
float rgfl2[3];
@@ -1666,8 +1644,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
pTextureName++;
// '}}'
- Q_strcpy(szBuffer, pTextureName);
- szBuffer[MAX_TEXTURENAME_LENGHT - 1] = '\0';
+ Q_strlcpy(szBuffer, pTextureName);
// get texture type
chTextureType = TEXTURETYPE_Find(szBuffer);
diff --git a/regamedll/dlls/sound.h b/regamedll/dlls/sound.h
index d2f0b41a7..b4e716fbc 100644
--- a/regamedll/dlls/sound.h
+++ b/regamedll/dlls/sound.h
@@ -170,15 +170,13 @@ class CSpeaker: public CBaseEntity
BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange);
void USENTENCEG_InitLRU(unsigned char *plru, int count);
-int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset);
-int USENTENCEG_Pick(int isentenceg, char *szfound);
int SENTENCEG_GetIndex(const char *szgroupname);
int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch);
int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, float volume, float attenuation, int flags, int pitch);
int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, float volume, float attenuation, int flags, int pitch, int ipick, int freset);
void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick);
void SENTENCEG_Init();
-int SENTENCEG_Lookup(const char *sample, char *sentencenum);
+int SENTENCEG_Lookup(const char *sample, char (&sentencenum)[32]);
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch);
void EMIT_SOUND_SUIT(edict_t *entity, const char *sample);
void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg);
diff --git a/regamedll/dlls/triggers.cpp b/regamedll/dlls/triggers.cpp
index 82bf6907a..63282c06e 100644
--- a/regamedll/dlls/triggers.cpp
+++ b/regamedll/dlls/triggers.cpp
@@ -585,7 +585,6 @@ void CTriggerCDAudio::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP
PlayTrack(pCaller->edict());
}
-#ifdef REGAMEDLL_FIXES
const char *g_szMP3trackFileMap[] =
{
"", "",
@@ -617,7 +616,6 @@ const char *g_szMP3trackFileMap[] =
"media/Suspense05.mp3",
"media/Suspense07.mp3"
};
-#endif
void PlayCDTrack(edict_t *pClient, int iTrack)
{
@@ -625,7 +623,7 @@ void PlayCDTrack(edict_t *pClient, int iTrack)
if (!pClient)
return;
- if (iTrack < -1 || iTrack > 30)
+ if (iTrack < -1 || iTrack >= (int)ARRAYSIZE(g_szMP3trackFileMap))
{
ALERT(at_console, "TriggerCDAudio - Track %d out of range\n", iTrack);
return;
@@ -645,7 +643,7 @@ void PlayCDTrack(edict_t *pClient, int iTrack)
CLIENT_COMMAND(pClient, UTIL_VarArgs("mp3 play %s\n", g_szMP3trackFileMap[iTrack]));
#else
char string[64];
- Q_sprintf(string, "cd play %3d\n", iTrack);
+ Q_snprintf(string, sizeof(string), "cd play %3d\n", iTrack);
CLIENT_COMMAND(pClient, string);
#endif
}
@@ -1214,7 +1212,7 @@ void CChangeLevel::KeyValue(KeyValueData *pkvd)
ALERT(at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue);
}
- Q_strcpy(m_szMapName, pkvd->szValue);
+ Q_strlcpy(m_szMapName, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "landmark"))
@@ -1224,7 +1222,7 @@ void CChangeLevel::KeyValue(KeyValueData *pkvd)
ALERT(at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue);
}
- Q_strcpy(m_szLandmarkName, pkvd->szValue);
+ Q_strlcpy(m_szLandmarkName, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "changetarget"))
@@ -1356,7 +1354,7 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator)
}
// This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory
- Q_strcpy(st_szNextMap, m_szMapName);
+ Q_strlcpy(st_szNextMap, m_szMapName);
m_hActivator = pActivator;
SUB_UseTargets(pActivator, USE_TOGGLE, 0);
@@ -1369,7 +1367,7 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator)
if (!FNullEnt(pentLandmark))
{
- Q_strcpy(st_szNextSpot, m_szLandmarkName);
+ Q_strlcpy(st_szNextSpot, m_szLandmarkName);
gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin;
}
@@ -1415,8 +1413,8 @@ int CChangeLevel::AddTransitionToList(LEVELLIST *pLevelList, int listCount, cons
}
}
- Q_strcpy(pLevelList[listCount].mapName, pMapName);
- Q_strcpy(pLevelList[listCount].landmarkName, pLandmarkName);
+ Q_strlcpy(pLevelList[listCount].mapName, pMapName);
+ Q_strlcpy(pLevelList[listCount].landmarkName, pLandmarkName);
pLevelList[listCount].pentLandmark = pentLandmark;
pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin;
@@ -1591,12 +1589,12 @@ NOXREF void NextLevel()
{
gpGlobals->mapname = ALLOC_STRING("start");
pChange = GetClassPtr((CChangeLevel *)nullptr);
- Q_strcpy(pChange->m_szMapName, "start");
+ Q_strlcpy(pChange->m_szMapName, "start");
}
else
pChange = GetClassPtr((CChangeLevel *)VARS(pent));
- Q_strcpy(st_szNextMap, pChange->m_szMapName);
+ Q_strlcpy(st_szNextMap, pChange->m_szMapName);
g_pGameRules->SetGameOver();
if (pChange->pev->nextthink < gpGlobals->time)
diff --git a/regamedll/dlls/tutor_base_tutor.cpp b/regamedll/dlls/tutor_base_tutor.cpp
index 2268d18b7..a44ef4728 100644
--- a/regamedll/dlls/tutor_base_tutor.cpp
+++ b/regamedll/dlls/tutor_base_tutor.cpp
@@ -68,12 +68,10 @@ void TutorMessageEvent::AddParameter(char *str)
TutorMessageEventParam *param = new TutorMessageEventParam;
param->m_next = nullptr;
- param->m_data = new char[Q_strlen(str) + 1];
+ param->m_data = CloneString(str);
if (param->m_data)
{
- Q_strcpy(param->m_data, str);
- param->m_data[Q_strlen(str)] = '\0';
m_numParameters++;
if (m_paramList)
@@ -101,11 +99,7 @@ char *TutorMessageEvent::GetNextParameter(char *buf, int buflen)
m_numParameters--;
m_paramList = param->m_next;
- Q_strncpy(buf, param->m_data, buflen);
-
-#ifdef REGAMEDLL_FIXES
- buf[buflen - 1] = '\0';
-#endif
+ Q_strlcpy(buf, param->m_data, buflen);
delete param;
return buf;
diff --git a/regamedll/dlls/tutor_cs_tutor.cpp b/regamedll/dlls/tutor_cs_tutor.cpp
index 18e5d2b67..aa6bdd4bc 100644
--- a/regamedll/dlls/tutor_cs_tutor.cpp
+++ b/regamedll/dlls/tutor_cs_tutor.cpp
@@ -213,7 +213,7 @@ void ParseMessageParameters(char *&messageData, TutorMessage *ret)
if (!Q_stricmp(token, "String"))
{
messageData = SharedParse((char *)messageData);
- ret->m_text = Q_strdup(SharedGetToken());
+ ret->m_text = CloneString(SharedGetToken());
}
else if (!Q_stricmp(token, "Duration"))
{
@@ -832,7 +832,7 @@ TutorMessageEvent *CCSTutor::CreateTutorMessageEvent(TutorMessageID mid, CBaseEn
{
numtasks = TheCareerTasks->GetNumRemainingTasks();
}
- Q_sprintf(numLeftStr, "%d", numtasks);
+ Q_snprintf(numLeftStr, sizeof(numLeftStr), "%d", numtasks);
event->AddParameter(numLeftStr);
break;
}
@@ -2820,8 +2820,7 @@ void CCSTutor::ConstructRecentDeathsList(TeamName team, char *buf, int buflen, T
if (!buf || !buflen)
return;
- char scratch[32];
- buf[0] = '\0';
+ int len = 0;
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
@@ -2837,10 +2836,7 @@ void CCSTutor::ConstructRecentDeathsList(TeamName team, char *buf, int buflen, T
if (pPlayer->m_iTeam != team)
continue;
- Q_strcat(buf, " %n");
- Q_sprintf(scratch, "%d\n", i);
- Q_strcat(buf, scratch);
-
+ len += Q_snprintf(&buf[len], buflen - len, " %%n%d\n", i);
m_playerDeathInfo[i].m_event = event;
}
}
diff --git a/regamedll/dlls/util.cpp b/regamedll/dlls/util.cpp
index 7841b006b..e0ffed532 100644
--- a/regamedll/dlls/util.cpp
+++ b/regamedll/dlls/util.cpp
@@ -690,10 +690,7 @@ void UTIL_Log(const char *fmt, ...)
Q_vsnprintf(string, sizeof(string), fmt, ap);
va_end(ap);
- if (Q_strlen(string) < sizeof(string) - 2)
- Q_strcat(string, "\n");
- else
- string[Q_strlen(string) - 1] = '\n';
+ Q_strlcat(string, "\n");
FILE *fp = fopen("regamedll.log", "at");
if (fp)
@@ -717,10 +714,7 @@ void UTIL_ServerPrint(const char *fmt, ...)
Q_vsnprintf(string, sizeof(string), fmt, ap);
va_end(ap);
- if (Q_strlen(string) < sizeof(string) - 2)
- Q_strcat(string, "\n");
- else
- string[Q_strlen(string) - 1] = '\n';
+ Q_strlcat(string, "\n");
SERVER_PRINT(string);
}
@@ -738,10 +732,7 @@ void UTIL_PrintConsole(edict_t *pEdict, const char *fmt, ...)
Q_vsnprintf(string, sizeof(string), fmt, ap);
va_end(ap);
- if (Q_strlen(string) < sizeof(string) - 2)
- Q_strcat(string, "\n");
- else
- string[Q_strlen(string) - 1] = '\n';
+ Q_strlcat(string, "\n");
ClientPrint(pEntity->pev, HUD_PRINTCONSOLE, string);
}
@@ -759,10 +750,7 @@ void UTIL_SayText(edict_t *pEdict, const char *fmt, ...)
Q_vsnprintf(string, sizeof(string), fmt, ap);
va_end(ap);
- if (Q_strlen(string) < sizeof(string) - 2)
- Q_strcat(string, "\n");
- else
- string[Q_strlen(string) - 1] = '\n';
+ Q_strlcat(string, "\n");
MESSAGE_BEGIN(MSG_ONE, gmsgSayText, nullptr, pEntity->edict());
WRITE_BYTE(pEntity->entindex());
@@ -781,28 +769,28 @@ void UTIL_SayTextAll(const char *pText, CBaseEntity *pEntity)
char *UTIL_dtos1(int d)
{
static char buf[12];
- Q_sprintf(buf, "%d", d);
+ Q_snprintf(buf, sizeof(buf), "%d", d);
return buf;
}
char *UTIL_dtos2(int d)
{
static char buf[12];
- Q_sprintf(buf, "%d", d);
+ Q_snprintf(buf, sizeof(buf), "%d", d);
return buf;
}
NOXREF char *UTIL_dtos3(int d)
{
static char buf[12];
- Q_sprintf(buf, "%d", d);
+ Q_snprintf(buf, sizeof(buf), "%d", d);
return buf;
}
NOXREF char *UTIL_dtos4(int d)
{
static char buf[12];
- Q_sprintf(buf, "%d", d);
+ Q_snprintf(buf, sizeof(buf), "%d", d);
return buf;
}
@@ -991,7 +979,7 @@ char *UTIL_VarArgs(char *format, ...)
static char string[1024];
va_start(argptr, format);
- vsprintf(string, format, argptr);
+ Q_vsnprintf(string, sizeof(string), format, argptr);
va_end(argptr);
return string;
@@ -1476,7 +1464,7 @@ void UTIL_Remove(CBaseEntity *pEntity)
pEntity->pev->targetname = 0;
}
-NOXREF BOOL UTIL_IsValidEntity(edict_t *pent)
+BOOL UTIL_IsValidEntity(edict_t *pent)
{
if (!pent || pent->free || (pent->v.flags & FL_KILLME))
return FALSE;
@@ -1561,7 +1549,7 @@ void UTIL_LogPrintf(const char *fmt, ...)
static char string[1024];
va_start(argptr, fmt);
- vsprintf(string, fmt, argptr);
+ Q_vsnprintf(string, sizeof(string), fmt, argptr);
va_end(argptr);
ALERT(at_logged, "%s", string);
@@ -1580,7 +1568,7 @@ char UTIL_TextureHit(TraceResult *ptr, Vector vecSrc, Vector vecEnd)
float rgfl1[3];
float rgfl2[3];
const char *pTextureName;
- char szbuffer[64];
+ char szbuffer[MAX_TEXTURENAME_LENGHT];
CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit);
#ifdef REGAMEDLL_FIXES
@@ -1606,8 +1594,8 @@ char UTIL_TextureHit(TraceResult *ptr, Vector vecSrc, Vector vecEnd)
if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ')
pTextureName++;
- Q_strcpy(szbuffer, pTextureName);
- szbuffer[16] = '\0';
+ Q_strlcpy(szbuffer, pTextureName);
+
chTextureType = TEXTURETYPE_Find(szbuffer);
}
else
@@ -1672,14 +1660,12 @@ int UTIL_ReadFlags(const char *c)
// Determine whether bots can be used or not
bool UTIL_AreBotsAllowed()
{
-#ifdef REGAMEDLL_ADD
- if (g_engfuncs.pfnEngCheckParm == nullptr)
- return false;
-#endif
-
if (AreRunningCZero())
{
#ifdef REGAMEDLL_ADD
+ if (g_engfuncs.pfnEngCheckParm == nullptr)
+ return false;
+
// If they pass in -nobots, don't allow bots. This is for people who host servers, to
// allow them to disallow bots to enforce CPU limits.
int nobots = ENG_CHECK_PARM("-nobots", nullptr);
@@ -1699,15 +1685,10 @@ bool UTIL_AreBotsAllowed()
return true;
}
- // allow the using of bots for CS 1.6
- int bots = ENG_CHECK_PARM("-bots", nullptr);
- if (bots)
- {
- return true;
- }
-#endif
-
+ return cv_bot_enable.value > 0;
+#else
return false;
+#endif
}
bool UTIL_IsBeta()
@@ -1740,18 +1721,10 @@ bool UTIL_AreHostagesImprov()
}
#ifdef REGAMEDLL_ADD
- if (g_engfuncs.pfnEngCheckParm == nullptr)
- return false;
-
- // someday in CS 1.6
- int improv = ENG_CHECK_PARM("-host-improv", nullptr);
- if (improv)
- {
- return true;
- }
-#endif
-
+ return cv_hostage_ai_enable.value > 0;
+#else
return false;
+#endif
}
int UTIL_GetNumPlayers()
diff --git a/regamedll/dlls/vehicle.cpp b/regamedll/dlls/vehicle.cpp
index 3ff84b941..7bf2d4184 100644
--- a/regamedll/dlls/vehicle.cpp
+++ b/regamedll/dlls/vehicle.cpp
@@ -126,7 +126,7 @@ void CFuncVehicle::Blocked(CBaseEntity *pOther)
float minz = pev->origin.z;
#ifdef REGAMEDLL_FIXES
- float maxz = pev->origin.z + (2 * Q_abs(pev->mins.z - pev->maxs.z));
+ float maxz = pev->origin.z + (2 * Q_abs(pev->mins.z - pev->maxs.z));
#else
float maxz = pev->origin.z + (2 * Q_abs(int(pev->mins.z - pev->maxs.z)));
#endif
@@ -343,15 +343,20 @@ void CFuncVehicle::CheckTurning()
if (pev->speed > 0)
{
UTIL_TraceLine(m_vFrontRight, m_vFrontRight - (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
+
+ if (tr.flFraction != 1.0f)
+ {
+ m_iTurnAngle = 1;
+ }
}
else if (pev->speed < 0)
{
UTIL_TraceLine(m_vBackLeft, m_vBackLeft + (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
- }
- if (tr.flFraction != 1.0f)
- {
- m_iTurnAngle = 1;
+ if (tr.flFraction != 1.0f)
+ {
+ m_iTurnAngle = 1;
+ }
}
}
else if (m_iTurnAngle > 0)
@@ -359,15 +364,20 @@ void CFuncVehicle::CheckTurning()
if (pev->speed > 0)
{
UTIL_TraceLine(m_vFrontLeft, m_vFrontLeft + (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
+
+ if (tr.flFraction != 1.0f)
+ {
+ m_iTurnAngle = -1;
+ }
}
else if (pev->speed < 0)
{
UTIL_TraceLine(m_vBackRight, m_vBackRight - (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
- }
- if (tr.flFraction != 1.0f)
- {
- m_iTurnAngle = -1;
+ if (tr.flFraction != 1.0f)
+ {
+ m_iTurnAngle = -1;
+ }
}
}
diff --git a/regamedll/dlls/weapons.cpp b/regamedll/dlls/weapons.cpp
index 087f45eee..b98749cb6 100644
--- a/regamedll/dlls/weapons.cpp
+++ b/regamedll/dlls/weapons.cpp
@@ -618,11 +618,17 @@ void CBasePlayerItem::DefaultTouch(CBaseEntity *pOther)
CBasePlayer *pPlayer = static_cast(pOther);
if (pPlayer->m_bIsVIP
- && m_iId != WEAPON_USP
+ &&
+#ifndef REGAMEDLL_FIXES
+ m_iId != WEAPON_USP
&& m_iId != WEAPON_GLOCK18
&& m_iId != WEAPON_P228
&& m_iId != WEAPON_DEAGLE
- && m_iId != WEAPON_KNIFE)
+ && m_iId != WEAPON_KNIFE
+#else
+ !IsSecondaryWeapon(m_iId)
+#endif
+ )
{
return;
}
@@ -652,11 +658,11 @@ void CBasePlayerWeapon::SetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
}
else
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
}
}
@@ -666,7 +672,7 @@ void CBasePlayerWeapon::ResetPlayerShieldAnim()
{
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
}
}
}
@@ -697,7 +703,7 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
m_fMaxSpeed = 250.0f;
m_pPlayer->m_bShieldDrawn = false;
}
@@ -705,7 +711,7 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = 180.0f;
m_pPlayer->m_bShieldDrawn = true;
}
@@ -728,7 +734,7 @@ void EXT_FUNC CBasePlayerWeapon::__API_HOOK(KickBack)(float up_base, float later
real_t flKickUp = up_base;
float flKickLateral = lateral_base;
- if (m_iShotsFired > 1) // consider == 0 case
+ if (m_iShotsFired > 1) // consider == 0 case
{
flKickUp += m_iShotsFired * up_modifier;
flKickLateral += m_iShotsFired * lateral_modifier;
@@ -1491,7 +1497,7 @@ BOOL EXT_FUNC CBasePlayerWeapon::__API_HOOK(DefaultDeploy)(char *szViewModel, ch
m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel);
#endif
model_name = m_pPlayer->pev->viewmodel;
- Q_strcpy(m_pPlayer->m_szAnimExtention, szAnimExt);
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, szAnimExt);
SendWeaponAnim(iAnim, skiplocal);
m_pPlayer->m_flNextAttack = 0.75f;
@@ -1671,7 +1677,7 @@ void CBasePlayerWeapon::Holster(int skiplocal)
m_fInReload = FALSE;
m_pPlayer->pev->viewmodel = 0;
m_pPlayer->pev->weaponmodel = 0;
-
+
#ifdef REGAMEDLL_FIXES
m_fInSpecialReload = 0;
#endif
diff --git a/regamedll/dlls/weapons.h b/regamedll/dlls/weapons.h
index 9266d8434..252c4c5f1 100644
--- a/regamedll/dlls/weapons.h
+++ b/regamedll/dlls/weapons.h
@@ -1333,7 +1333,6 @@ class CM249: public CBasePlayerWeapon
const float M3_MAX_SPEED = 230.0f;
const float M3_DAMAGE = 20.0f;
-const Vector M3_CONE_VECTOR = Vector(0.0675, 0.0675, 0.0); // special shotgun spreads
enum m3_e
{
@@ -1764,7 +1763,6 @@ class CTMP: public CBasePlayerWeapon
const float XM1014_MAX_SPEED = 240.0f;
const float XM1014_DAMAGE = 20.0f;
-const Vector XM1014_CONE_VECTOR = Vector(0.0725, 0.0725, 0.0); // special shotgun spreads
enum xm1014_e
{
diff --git a/regamedll/dlls/weapontype.cpp b/regamedll/dlls/weapontype.cpp
index dd7dc0f82..cc341d7c9 100644
--- a/regamedll/dlls/weapontype.cpp
+++ b/regamedll/dlls/weapontype.cpp
@@ -545,7 +545,7 @@ WeaponInfoStruct *GetDefaultWeaponInfo(int weaponID)
AmmoInfoStruct *GetAmmoInfo(const char *ammoName)
{
for (auto& info : g_ammoInfo) {
- if (!Q_stricmp(info.ammoName1, ammoName)) {
+ if (info.ammoName1 && !Q_stricmp(info.ammoName1, ammoName)) {
return &info;
}
}
diff --git a/regamedll/dlls/world.cpp b/regamedll/dlls/world.cpp
index 55147af09..cc4a3de55 100644
--- a/regamedll/dlls/world.cpp
+++ b/regamedll/dlls/world.cpp
@@ -216,7 +216,7 @@ void CWorld::Spawn()
Precache();
g_szMapBriefingText[0] = '\0';
- Q_sprintf(szMapBriefingFile, "maps/%s.txt", STRING(gpGlobals->mapname));
+ Q_snprintf(szMapBriefingFile, sizeof(szMapBriefingFile), "maps/%s.txt", STRING(gpGlobals->mapname));
int flength = 0;
char *pFile = (char *)LOAD_FILE_FOR_ME(szMapBriefingFile, &flength);
diff --git a/regamedll/dlls/wpn_shared/wpn_aug.cpp b/regamedll/dlls/wpn_shared/wpn_aug.cpp
index 988c74808..dfba3fdf9 100644
--- a/regamedll/dlls/wpn_shared/wpn_aug.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_aug.cpp
@@ -73,6 +73,15 @@ void CAUG::SecondaryAttack()
else
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 90;
+#ifdef REGAMEDLL_FIXES
+ if (TheBots)
+ {
+ TheBots->OnEvent(EVENT_WEAPON_ZOOMED, m_pPlayer);
+ }
+
+ m_pPlayer->ResetMaxSpeed();
+#endif
+
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.3f;
}
diff --git a/regamedll/dlls/wpn_shared/wpn_flashbang.cpp b/regamedll/dlls/wpn_shared/wpn_flashbang.cpp
index 0443353e8..bbebb8ebf 100644
--- a/regamedll/dlls/wpn_shared/wpn_flashbang.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_flashbang.cpp
@@ -114,7 +114,7 @@ bool CFlashbang::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
m_fMaxSpeed = FLASHBANG_MAX_SPEED;
m_pPlayer->m_bShieldDrawn = false;
@@ -124,7 +124,7 @@ bool CFlashbang::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = FLASHBANG_MAX_SPEED_SHIELD;
m_pPlayer->m_bShieldDrawn = true;
@@ -151,9 +151,9 @@ void CFlashbang::SetPlayerShieldAnim()
return;
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
else
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
void CFlashbang::ResetPlayerShieldAnim()
@@ -163,7 +163,7 @@ void CFlashbang::ResetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
}
diff --git a/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp b/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp
index 49d8eb7a8..ca2c63adb 100644
--- a/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp
@@ -117,7 +117,7 @@ bool CHEGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
m_fMaxSpeed = HEGRENADE_MAX_SPEED;
m_pPlayer->m_bShieldDrawn = false;
@@ -126,7 +126,7 @@ bool CHEGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = HEGRENADE_MAX_SPEED_SHIELD;
m_pPlayer->m_bShieldDrawn = true;
@@ -153,9 +153,9 @@ void CHEGrenade::SetPlayerShieldAnim()
return;
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
else
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
void CHEGrenade::ResetPlayerShieldAnim()
@@ -165,7 +165,7 @@ void CHEGrenade::ResetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
}
diff --git a/regamedll/dlls/wpn_shared/wpn_knife.cpp b/regamedll/dlls/wpn_shared/wpn_knife.cpp
index fcbf2d949..43a2f28f2 100644
--- a/regamedll/dlls/wpn_shared/wpn_knife.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_knife.cpp
@@ -180,7 +180,7 @@ void CKnife::SetPlayerShieldAnim()
if (!m_pPlayer->HasShield())
return;
- Q_strcpy(m_pPlayer->m_szAnimExtention, (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) != 0 ? "shield" : "shieldknife");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) != 0 ? "shield" : "shieldknife");
}
void CKnife::ResetPlayerShieldAnim()
@@ -190,7 +190,7 @@ void CKnife::ResetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldknife");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldknife");
}
}
@@ -207,7 +207,7 @@ bool CKnife::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldknife");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldknife");
m_fMaxSpeed = KNIFE_MAX_SPEED;
m_pPlayer->m_bShieldDrawn = false;
@@ -217,7 +217,7 @@ bool CKnife::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = KNIFE_MAX_SPEED_SHIELD;
m_pPlayer->m_bShieldDrawn = true;
@@ -339,14 +339,14 @@ BOOL CKnife::Swing(BOOL fFirst)
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
// play wiff or swish sound
- EMIT_SOUND_DYN(m_pPlayer->edict(),
- CHAN_WEAPON,
- RANDOM_LONG(0, 1) ?
+ EMIT_SOUND_DYN(m_pPlayer->edict(),
+ CHAN_WEAPON,
+ RANDOM_LONG(0, 1) ?
"weapons/knife_slash1.wav" :
- "weapons/knife_slash2.wav",
- VOL_NORM,
- ATTN_NORM,
- 0,
+ "weapons/knife_slash2.wav",
+ VOL_NORM,
+ ATTN_NORM,
+ 0,
94);
// player "shoot" animation
@@ -390,10 +390,10 @@ BOOL CKnife::Swing(BOOL fFirst)
m_pPlayer->SetAnimation(PLAYER_ATTACK1);
ClearMultiDamage();
- pEntity->TraceAttack(m_pPlayer->pev,
+ pEntity->TraceAttack(m_pPlayer->pev,
KnifeSwingDamage(m_flNextPrimaryAttack + 0.4f < UTIL_WeaponTimeBase()),
- gpGlobals->v_forward,
- &tr,
+ gpGlobals->v_forward,
+ &tr,
(DMG_NEVERGIB | DMG_BULLET));
ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev);
@@ -402,7 +402,7 @@ BOOL CKnife::Swing(BOOL fFirst)
if (pEntity) // -V595
#endif
{
- if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
+ if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
#ifdef REGAMEDLL_FIXES
&& pEntity->Classify() != CLASS_VEHICLE
#endif
@@ -518,14 +518,14 @@ BOOL CKnife::Stab(BOOL fFirst)
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0f;
// play wiff or swish sound
- EMIT_SOUND_DYN(m_pPlayer->edict(),
- CHAN_WEAPON,
- RANDOM_LONG(0, 1) ?
- "weapons/knife_slash1.wav" :
- "weapons/knife_slash2.wav",
- VOL_NORM,
- ATTN_NORM,
- 0,
+ EMIT_SOUND_DYN(m_pPlayer->edict(),
+ CHAN_WEAPON,
+ RANDOM_LONG(0, 1) ?
+ "weapons/knife_slash1.wav" :
+ "weapons/knife_slash2.wav",
+ VOL_NORM,
+ ATTN_NORM,
+ 0,
94);
// player "shoot" animation
@@ -586,7 +586,7 @@ BOOL CKnife::Stab(BOOL fFirst)
if (pEntity) // -V595
#endif
{
- if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
+ if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
#ifdef REGAMEDLL_FIXES
&& pEntity->Classify() != CLASS_VEHICLE
#endif
diff --git a/regamedll/dlls/wpn_shared/wpn_m3.cpp b/regamedll/dlls/wpn_shared/wpn_m3.cpp
index 64ad7c5f0..2f341c951 100644
--- a/regamedll/dlls/wpn_shared/wpn_m3.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_m3.cpp
@@ -1,5 +1,7 @@
#include "precompiled.h"
+const Vector M3_CONE_VECTOR = Vector(0.0675, 0.0675, 0.0); // special shotgun spreads
+
LINK_ENTITY_TO_CLASS(weapon_m3, CM3, CCSM3)
void CM3::Spawn()
diff --git a/regamedll/dlls/wpn_shared/wpn_m4a1.cpp b/regamedll/dlls/wpn_shared/wpn_m4a1.cpp
index 89ea81b5b..e9bb062e2 100644
--- a/regamedll/dlls/wpn_shared/wpn_m4a1.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_m4a1.cpp
@@ -82,13 +82,13 @@ void CM4A1::SecondaryAttack()
{
m_iWeaponState &= ~WPNSTATE_M4A1_SILENCED;
SendWeaponAnim(M4A1_DETACH_SILENCER, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "rifle");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "rifle");
}
else
{
m_iWeaponState |= WPNSTATE_M4A1_SILENCED;
SendWeaponAnim(M4A1_ATTACH_SILENCER, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "rifle");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "rifle");
}
m_flTimeWeaponIdle = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.0f;
diff --git a/regamedll/dlls/wpn_shared/wpn_sg552.cpp b/regamedll/dlls/wpn_shared/wpn_sg552.cpp
index e86eec412..f9eb61f5f 100644
--- a/regamedll/dlls/wpn_shared/wpn_sg552.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_sg552.cpp
@@ -72,6 +72,15 @@ void CSG552::SecondaryAttack()
else
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 90;
+#ifdef REGAMEDLL_FIXES
+ if (TheBots)
+ {
+ TheBots->OnEvent(EVENT_WEAPON_ZOOMED, m_pPlayer);
+ }
+
+ m_pPlayer->ResetMaxSpeed();
+#endif
+
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.3f;
}
diff --git a/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp b/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp
index ae13158b4..56c5e27bc 100644
--- a/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp
@@ -117,7 +117,7 @@ bool CSmokeGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
m_fMaxSpeed = SMOKEGRENADE_MAX_SPEED;
m_pPlayer->m_bShieldDrawn = false;
@@ -127,7 +127,7 @@ bool CSmokeGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = SMOKEGRENADE_MAX_SPEED_SHIELD;
m_pPlayer->m_bShieldDrawn = true;
@@ -154,9 +154,9 @@ void CSmokeGrenade::SetPlayerShieldAnim()
return;
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
else
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
void CSmokeGrenade::ResetPlayerShieldAnim()
@@ -166,7 +166,7 @@ void CSmokeGrenade::ResetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
}
diff --git a/regamedll/dlls/wpn_shared/wpn_usp.cpp b/regamedll/dlls/wpn_shared/wpn_usp.cpp
index 5a474f652..de823f30e 100644
--- a/regamedll/dlls/wpn_shared/wpn_usp.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_usp.cpp
@@ -98,14 +98,14 @@ void CUSP::SecondaryAttack()
m_iWeaponState &= ~WPNSTATE_USP_SILENCED;
SendWeaponAnim(USP_DETACH_SILENCER, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "onehanded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "onehanded");
}
else
{
m_iWeaponState |= WPNSTATE_USP_SILENCED;
SendWeaponAnim(USP_ATTACH_SILENCER, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "onehanded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "onehanded");
}
m_flNextSecondaryAttack = m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + USP_ADJUST_SIL_TIME;
diff --git a/regamedll/dlls/wpn_shared/wpn_xm1014.cpp b/regamedll/dlls/wpn_shared/wpn_xm1014.cpp
index a4e4304eb..c664fe597 100644
--- a/regamedll/dlls/wpn_shared/wpn_xm1014.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_xm1014.cpp
@@ -1,5 +1,7 @@
#include "precompiled.h"
+const Vector XM1014_CONE_VECTOR = Vector(0.0725, 0.0725, 0.0); // special shotgun spreads
+
LINK_ENTITY_TO_CLASS(weapon_xm1014, CXM1014, CCSXM1014)
void CXM1014::Spawn()
diff --git a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd
index 79fe8333a..cab21059a 100644
--- a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd
+++ b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd
@@ -1,12 +1,17 @@
// -----------------------------------------------------------------------
// Counter-Strike game definition file (.fgd)
-// Version 0.9.0.0
+// Version 0.9.5.0
// Valve Hammer Editor >= 3.5
// Last update: September 25th, 2016
// -----------------------------------------------------------------------
// Based on FGD 0.8.0.0 by Dmitrich!
//
-// Full compatibility with https://github.com/s1lentq/ReGameDLL_CS
+// Full compatibility with https://github.com/rehlds/ReGameDLL_CS
+// -----------------------------------------------------------------------
+// December 12th, 2024 (0.9.5.0)
+// - Added target_cdaudio
+// -----------------------------------------------------------------------
+//
// -----------------------------------------------------------------------
// September 25th, 2016 - s1lent (0.9.0.0)
// - Removed xen entities.
@@ -2323,6 +2328,46 @@
]
]
+// This entity allows to play a specific CD track when the player is within the specified radius around the entity or when triggered
+// A brush entity equivalent is available as trigger_cdaudio
+@PointClass base(Targetname) color(255 240 128) = target_cdaudio : "CD Audio Target"
+[
+ health(choices) : "Track #" : -1 =
+ [
+ -1 : "Stop"
+// 1 : "None"
+ 2 : "Track 1"
+ 3 : "Track 2"
+ 4 : "Track 3"
+ 5 : "Track 4"
+ 6 : "Track 5"
+ 7 : "Track 6"
+ 8 : "Track 7"
+ 9 : "Track 8"
+ 10 : "Track 9"
+ 11 : "Track 10"
+ 12 : "Track 11"
+ 13 : "Track 12"
+ 14 : "Track 13"
+ 15 : "Track 14"
+ 16 : "Track 15"
+ 17 : "Track 16"
+ 18 : "Track 17"
+ 19 : "Track 18"
+ 20 : "Track 19"
+ 21 : "Track 20"
+ 22 : "Track 21"
+ 23 : "Track 22"
+ 24 : "Track 23"
+ 25 : "Track 24"
+ 26 : "Track 25"
+ 27 : "Track 26"
+ 28 : "Track 27"
+ 29 : "Track 28"
+ ]
+ scale(string) : "Player Radius" : "128.0" // The player must come within this radius for the track to start playing
+]
+
@SolidClass base(Targetname) = trigger_changelevel : "Trigger Change level"
[
map(string) : "New map name"
@@ -3098,3 +3143,7 @@
@PointClass base(BaseCommand) size(-8 -8 -8, 8 8 8) = point_clientcommand : "It issues commands to the client console"
[
]
+
+@PointClass iconsprite("sprites/CS/info_player_start.spr") base(PlayerClass) = info_spawn_point : "Random spawn start"
+[
+]
\ No newline at end of file
diff --git a/regamedll/game_shared/bot/bot.cpp b/regamedll/game_shared/bot/bot.cpp
index 0f19e81f4..52d1f4db7 100644
--- a/regamedll/game_shared/bot/bot.cpp
+++ b/regamedll/game_shared/bot/bot.cpp
@@ -486,11 +486,11 @@ NOXREF void CBot::Print(char *format, ...) const
char buffer[1024];
// prefix the message with the bot's name
- Q_sprintf(buffer, "%s: ", STRING(pev->netname));
+ Q_snprintf(buffer, sizeof(buffer), "%s: ", STRING(pev->netname));
SERVER_PRINT(buffer);
va_start(varg, format);
- vsprintf(buffer, format, varg);
+ Q_vsnprintf(buffer, sizeof(buffer), format, varg);
va_end(varg);
SERVER_PRINT(buffer);
@@ -509,12 +509,12 @@ void CBot::PrintIfWatched(char *format, ...) const
// prefix the message with the bot's name (this can be NULL if bot was just added)
const char *name = pev ? STRING(pev->netname) : "(NULL pev)";
- Q_sprintf(buffer, "%s: ", name ? name : "(NULL netname)");
+ Q_snprintf(buffer, sizeof(buffer), "%s: ", name ? name : "(NULL netname)");
SERVER_PRINT(buffer);
va_start(varg, format);
- vsprintf(buffer, format, varg);
+ Q_vsnprintf(buffer, sizeof(buffer), format, varg);
va_end(varg);
SERVER_PRINT(buffer);
diff --git a/regamedll/game_shared/bot/bot_manager.cpp b/regamedll/game_shared/bot/bot_manager.cpp
index 7ccd32814..3fa121ba7 100644
--- a/regamedll/game_shared/bot/bot_manager.cpp
+++ b/regamedll/game_shared/bot/bot_manager.cpp
@@ -213,7 +213,7 @@ void CBotManager::StartFrame()
const char *CBotManager::GetNavMapFilename() const
{
static char filename[256];
- Q_sprintf(filename, "maps\\%s.nav", STRING(gpGlobals->mapname));
+ Q_snprintf(filename, sizeof(filename), "maps\\%s.nav", STRING(gpGlobals->mapname));
return filename;
}
diff --git a/regamedll/game_shared/bot/bot_profile.cpp b/regamedll/game_shared/bot/bot_profile.cpp
index c025f903b..76cb37a10 100644
--- a/regamedll/game_shared/bot/bot_profile.cpp
+++ b/regamedll/game_shared/bot/bot_profile.cpp
@@ -178,9 +178,10 @@ void BotProfileManager::Init(const char *filename, unsigned int *checksum)
m_skins[m_nextSkin] = CloneString(decoratedName);
// construct the model filename
+ int SkinLen = Q_strlen(token) * 2 + Q_strlen("models/player//.mdl");
m_skinModelnames[m_nextSkin] = CloneString(token);
- m_skinFilenames[m_nextSkin] = new char[Q_strlen(token) * 2 + Q_strlen("models/player//.mdl") + 1];
- Q_sprintf(m_skinFilenames[m_nextSkin], "models/player/%s/%s.mdl", token, token);
+ m_skinFilenames[m_nextSkin] = new char[SkinLen + 1];
+ Q_snprintf(m_skinFilenames[m_nextSkin], SkinLen + 1, "models/player/%s/%s.mdl", token, token);
m_nextSkin++;
}
@@ -304,7 +305,7 @@ void BotProfileManager::Init(const char *filename, unsigned int *checksum)
// found attribute name - keep it
char attributeName[64];
- Q_strcpy(attributeName, token);
+ Q_strlcpy(attributeName, token);
// eat '='
dataFile = SharedParse(dataFile);
diff --git a/regamedll/game_shared/bot/bot_util.cpp b/regamedll/game_shared/bot/bot_util.cpp
index 449b7e373..4d694b318 100644
--- a/regamedll/game_shared/bot/bot_util.cpp
+++ b/regamedll/game_shared/bot/bot_util.cpp
@@ -560,7 +560,7 @@ void CONSOLE_ECHO(const char *pszMsg, ...)
static char szStr[1024];
va_start(argptr, pszMsg);
- vsprintf(szStr, pszMsg, argptr);
+ Q_vsnprintf(szStr, sizeof(szStr), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(szStr);
@@ -572,7 +572,7 @@ void CONSOLE_ECHO_LOGGED(const char *pszMsg, ...)
static char szStr[1024];
va_start(argptr, pszMsg);
- vsprintf(szStr, pszMsg, argptr);
+ Q_vsnprintf(szStr, sizeof(szStr), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(szStr);
diff --git a/regamedll/game_shared/bot/nav.h b/regamedll/game_shared/bot/nav.h
index a917aa993..d23a734e6 100644
--- a/regamedll/game_shared/bot/nav.h
+++ b/regamedll/game_shared/bot/nav.h
@@ -71,6 +71,13 @@ enum NavAttributeType
NAV_NO_JUMP = 0x08, // inhibit discontinuity jumping
};
+enum NavNotifyDestroyType
+{
+ NAV_NOTIFY_DESTROY_AREA,
+ NAV_NOTIFY_DESTROY_SPOT,
+ NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER
+};
+
enum NavDirType
{
NORTH = 0,
diff --git a/regamedll/game_shared/bot/nav_area.cpp b/regamedll/game_shared/bot/nav_area.cpp
index 8e4baf0da..845b2a3fd 100644
--- a/regamedll/game_shared/bot/nav_area.cpp
+++ b/regamedll/game_shared/bot/nav_area.cpp
@@ -72,17 +72,29 @@ NOXREF void buildGoodSizedList()
void DestroyHidingSpots()
{
+ // free all the HidingSpots
+ for (HidingSpot *spot : TheHidingSpotList)
+ {
+ TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_SPOT, spot);
+ delete spot;
+ }
+
+ TheHidingSpotList.clear();
+
// remove all hiding spot references from the nav areas
- for (auto area : TheNavAreaList)
+ for (CNavArea *area : TheNavAreaList)
+ {
area->m_hidingSpotList.clear();
- HidingSpot::m_nextID = 0;
+ // free all the HidingSpots in area
+ for (SpotEncounter &e : area->m_spotEncounterList)
+ e.spotList.clear();
- // free all the HidingSpots
- for (auto spot : TheHidingSpotList)
- delete spot;
+ TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER, area);
+ area->m_spotEncounterList.clear();
+ }
- TheHidingSpotList.clear();
+ HidingSpot::m_nextID = 0;
}
// For use when loading from a file
@@ -249,6 +261,9 @@ CNavArea::CNavArea(CNavNode *nwNode, class CNavNode *neNode, class CNavNode *seN
// Destructor
CNavArea::~CNavArea()
{
+ // tell all bots that this area no longer exists
+ TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this);
+
// if we are resetting the system, don't bother cleaning up - all areas are being destroyed
if (m_isReset)
return;
@@ -344,6 +359,7 @@ void CNavArea::FinishMerge(CNavArea *adjArea)
// remove subsumed adjacent area
TheNavAreaList.remove(adjArea);
+ TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this);
delete adjArea;
}
@@ -536,6 +552,7 @@ bool CNavArea::SplitEdit(bool splitAlongX, float splitEdge, CNavArea **outAlpha,
// remove original area
TheNavAreaList.remove(this);
+ TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this);
delete this;
return true;
@@ -868,6 +885,7 @@ bool CNavArea::MergeEdit(CNavArea *adj)
// remove subsumed adjacent area
TheNavAreaList.remove(adj);
+ TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, adj);
delete adj;
return true;
@@ -900,6 +918,9 @@ void DestroyNavigationMap()
{
CNavArea::m_isReset = true;
+ // destroy all hiding spots
+ DestroyHidingSpots();
+
// remove each element of the list and delete them
while (!TheNavAreaList.empty())
{
@@ -913,8 +934,8 @@ void DestroyNavigationMap()
// destroy ladder representations
DestroyLadders();
- // destroy all hiding spots
- DestroyHidingSpots();
+ // cleanup from previous analysis
+ CleanupApproachAreaAnalysisPrep();
// destroy navigation nodes created during map learning
CNavNode *node, *next;
@@ -1772,6 +1793,13 @@ void GenerateNavigationAreaMesh()
break;
}
+ if (!TheNavAreaList.size())
+ {
+ // If we somehow have no areas, don't try to create an impossibly-large grid
+ TheNavAreaGrid.Initialize(0, 0, 0, 0);
+ return;
+ }
+
Extent extent;
extent.lo.x = 9999999999.9f;
extent.lo.y = 9999999999.9f;
@@ -2828,6 +2856,22 @@ SpotEncounter *CNavArea::GetSpotEncounter(const CNavArea *from, const CNavArea *
return nullptr;
}
+// Checks if a SpotEncounter is present in the list of encounters for the given CNavArea
+bool CNavArea::HasSpotEncounter(const SpotEncounter *encounter)
+{
+ SpotEncounter *e;
+
+ for (SpotEncounterList::iterator iter = m_spotEncounterList.begin(); iter != m_spotEncounterList.end(); iter++)
+ {
+ e = &(*iter);
+
+ if (e == encounter)
+ return true;
+ }
+
+ return false;
+}
+
// Add spot encounter data when moving from area to area
void CNavArea::AddSpotEncounters(const class CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir)
{
@@ -3819,9 +3863,9 @@ void EditNavAreas(NavEditCmdType cmd)
name = TheNavAreaGrid.IDToName(area->GetPlace());
if (name)
- Q_strcpy(locName, name);
+ Q_strlcpy(locName, name);
else
- Q_strcpy(locName, "ERROR");
+ Q_strlcpy(locName, "ERROR");
}
else
{
@@ -3968,6 +4012,7 @@ void EditNavAreas(NavEditCmdType cmd)
case EDIT_DELETE:
EMIT_SOUND_DYN(ENT(pLocalPlayer->pev), CHAN_ITEM, "buttons/blip1.wav", 1, ATTN_NORM, 0, 100);
TheNavAreaList.remove(area);
+ TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, area);
delete area;
return;
case EDIT_ATTRIB_CROUCH:
@@ -4636,6 +4681,12 @@ void CNavAreaGrid::Initialize(float minX, float maxX, float minY, float maxY)
// Add an area to the grid
void CNavAreaGrid::AddNavArea(CNavArea *area)
{
+ if (!m_grid)
+ {
+ // If we somehow have no grid (manually creating a nav area without loading or generating a mesh), don't crash
+ TheNavAreaGrid.Initialize(0, 0, 0, 0);
+ }
+
// add to grid
const Extent *extent = area->GetExtent();
diff --git a/regamedll/game_shared/bot/nav_area.h b/regamedll/game_shared/bot/nav_area.h
index c4cf8a1ff..2792cd3b6 100644
--- a/regamedll/game_shared/bot/nav_area.h
+++ b/regamedll/game_shared/bot/nav_area.h
@@ -273,6 +273,7 @@ class CNavArea
void ComputeHidingSpots(); // analyze local area neighborhood to find "hiding spots" in this area - for map learning
void ComputeSniperSpots(); // analyze local area neighborhood to find "sniper spots" in this area - for map learning
+ bool HasSpotEncounter(const SpotEncounter *encounter);
SpotEncounter *GetSpotEncounter(const CNavArea *from, const CNavArea *to); // given the areas we are moving between, return the spots we will encounter
void ComputeSpotEncounters(); // compute spot encounter data - for map learning
@@ -345,6 +346,25 @@ class CNavArea
void AddLadderUp(CNavLadder *ladder) { m_ladder[LADDER_UP].push_back(ladder); }
void AddLadderDown(CNavLadder *ladder) { m_ladder[LADDER_DOWN].push_back(ladder); }
+ inline float GetAreaSlope()
+ {
+ Vector u, v;
+
+ // compute our unit surface normal
+ u.x = m_extent.hi.x - m_extent.lo.x;
+ u.y = 0.0f;
+ u.z = m_neZ - m_extent.lo.z;
+
+ v.x = 0.0f;
+ v.y = m_extent.hi.y - m_extent.lo.y;
+ v.z = m_swZ - m_extent.lo.z;
+
+ Vector normal = CrossProduct(u, v);
+ normal.NormalizeInPlace();
+
+ return normal.z;
+ }
+
private:
friend void ConnectGeneratedAreas();
friend void MergeGeneratedAreas();
diff --git a/regamedll/game_shared/bot/nav_file.cpp b/regamedll/game_shared/bot/nav_file.cpp
index c9f206fd9..e43a0200e 100644
--- a/regamedll/game_shared/bot/nav_file.cpp
+++ b/regamedll/game_shared/bot/nav_file.cpp
@@ -67,7 +67,7 @@ Place PlaceDirectory::EntryToPlace(EntryType entry) const
return UNDEFINED_PLACE;
unsigned int i = entry - 1;
- if (i > m_directory.size())
+ if (i >= m_directory.size())
{
DbgAssert(false && "PlaceDirectory::EntryToPlace: Invalid entry");
return UNDEFINED_PLACE;
@@ -623,6 +623,13 @@ bool SaveNavigationMap(const char *filename)
area->Save(fd, version);
}
+ // Ensure that all data is flushed to disk
+#ifdef WIN32
+ _commit(fd);
+#else
+ fsync(fd);
+#endif
+
_close(fd);
return true;
}
@@ -632,12 +639,15 @@ bool SaveNavigationMap(const char *filename)
void LoadLocationFile(const char *filename)
{
char locFilename[256];
- Q_strcpy(locFilename, filename);
+ Q_strlcpy(locFilename, filename);
- char *dot = Q_strchr(locFilename, '.');
+ char *dot = Q_strrchr(locFilename, '.');
if (dot)
{
- Q_strcpy(dot, ".loc");
+ int dotlen = dot - locFilename;
+ size_t remaining_size = sizeof(locFilename) - dotlen;
+ if (remaining_size > 0)
+ Q_snprintf(dot, remaining_size, ".loc");
int locDataLength;
char *locDataFile = (char *)LOAD_FILE_FOR_ME(const_cast(locFilename), &locDataLength);
@@ -771,7 +781,7 @@ NavErrorType LoadNavigationMap()
// nav filename is derived from map filename
char filename[256];
- Q_sprintf(filename, "maps\\%s.nav", STRING(gpGlobals->mapname));
+ Q_snprintf(filename, sizeof(filename), "maps\\%s.nav", STRING(gpGlobals->mapname));
// free previous navigation map data
DestroyNavigationMap();
@@ -836,6 +846,11 @@ NavErrorType LoadNavigationMap()
unsigned int count;
result = navFile.Read(&count, sizeof(unsigned int));
+ if (count == 0)
+ {
+ return NAV_INVALID_FILE;
+ }
+
Extent extent;
extent.lo.x = 9999999999.9f;
extent.lo.y = 9999999999.9f;
diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj
index 57e09e917..80e93c922 100644
--- a/regamedll/msvc/ReGameDLL.vcxproj
+++ b/regamedll/msvc/ReGameDLL.vcxproj
@@ -809,6 +809,9 @@
+
+
+
{70A2B904-B7DB-4C48-8DE0-AF567360D572}
ReGameDLL
@@ -929,7 +932,7 @@
Disabled
true
REGAMEDLL_ADD;REGAMEDLL_API;REGAMEDLL_FIXES;REGAMEDLL_SSE;REGAMEDLL_SELF;REGAMEDLL_CHECKS;UNICODE_FIXES;BUILD_LATEST;BUILD_LATEST_FIXES;CLIENT_WEAPONS;USE_QSTRING;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)
- Fast
+ Precise
/arch:IA32 %(AdditionalOptions)
/Zc:threadSafeInit- %(AdditionalOptions)
MultiThreadedDebug
@@ -966,7 +969,7 @@
Full
true
REGAMEDLL_ADD;REGAMEDLL_API;REGAMEDLL_FIXES;REGAMEDLL_SSE;REGAMEDLL_SELF;REGAMEDLL_CHECKS;UNICODE_FIXES;BUILD_LATEST;BUILD_LATEST_FIXES;CLIENT_WEAPONS;USE_QSTRING;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)
- Fast
+ Precise
/arch:IA32 %(AdditionalOptions)
/Zc:threadSafeInit- %(AdditionalOptions)
MultiThreaded
@@ -1099,6 +1102,7 @@
Use
precompiled.h
NoExtensions
+ Precise
true
diff --git a/regamedll/msvc/ReGameDLL.vcxproj.filters b/regamedll/msvc/ReGameDLL.vcxproj.filters
index ef2017ae4..bfc6d6256 100644
--- a/regamedll/msvc/ReGameDLL.vcxproj.filters
+++ b/regamedll/msvc/ReGameDLL.vcxproj.filters
@@ -1070,4 +1070,9 @@
public\tier0
+
+
+ regamedll
+
+
\ No newline at end of file
diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp
index fa106c09b..846b410d0 100644
--- a/regamedll/pm_shared/pm_shared.cpp
+++ b/regamedll/pm_shared/pm_shared.cpp
@@ -123,7 +123,7 @@ void PM_InitTextureTypes()
j = Q_min(j, MAX_TEXTURENAME_LENGHT - 1 + i);
buffer[j] = '\0';
- Q_strcpy(&(pm_grgszTextureName[pm_gcTextures++][0]), &(buffer[i]));
+ Q_strlcpy(pm_grgszTextureName[pm_gcTextures++], &(buffer[i]));
}
// Must use engine to free since we are in a .dll
@@ -364,8 +364,7 @@ void PM_CatagorizeTextureType()
if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ')
pTextureName++;
- Q_strcpy(pmove->sztexturename, pTextureName);
- pmove->sztexturename[MAX_TEXTURENAME_LENGHT - 1] = '\0';
+ Q_strlcpy(pmove->sztexturename, pTextureName, MAX_TEXTURENAME_LENGHT);
// get texture type
pmove->chtexturetype = PM_FindTextureType(pmove->sztexturename);
@@ -642,9 +641,184 @@ void PM_FixupGravityVelocity()
pmove->velocity[2] -= (pmove->movevars->gravity * pmove->frametime * ent_gravity * 0.5);
PM_CheckVelocity();
}
+#ifdef REGAMEDLL_ADD
+int PM_FlyMove_New()
+{
+ int bumpcount, numbumps;
+ vec3_t dir;
+ float d;
+ int numplanes;
+ vec3_t planes[MAX_CLIP_PLANES];
+ vec3_t primal_velocity;
+ vec3_t clipVelocity;
+ int i, j, k;
+ pmtrace_t trace;
+ vec3_t end;
+ float time_left;
+ float into;
+ vec3_t endVelocity;
+ vec3_t endClipVelocity;
+ int blocked;
+
+ numbumps = 4;
+
+ VectorCopy(pmove->velocity, primal_velocity);
+
+
+ time_left = pmove->frametime;
+
+ numplanes = 0;
+ blocked = 0x00; // Assume not blocked
+
+ // never turn against original velocity
+ VectorCopy(pmove->velocity, planes[numplanes]);
+ VectorNormalize(planes[numplanes]);
+ numplanes++;
+
+ for (bumpcount = 0; bumpcount < numbumps; bumpcount++) {
+
+ // calculate position we are trying to move to
+ VectorMA(pmove->origin, time_left, pmove->velocity, end);
+ // see if we can make it there
+ trace = pmove->PM_PlayerTrace(pmove->origin, end, PM_NORMAL, -1);
+
+ if (trace.allsolid) {
+ // entity is completely trapped in another solid
+ pmove->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration
+ return 4;
+ }
+
+ if (trace.fraction > 0) {
+ // actually covered some distance
+ VectorCopy(trace.endpos, pmove->origin);
+ }
+
+ if (trace.fraction == 1) {
+ break; // moved the entire distance
+ }
+
+ // save entity for contact
+ PM_AddToTouched(trace, pmove->velocity);
+
+ // If the plane we hit has a high z component in the normal, then
+ // it's probably a floor
+ if (trace.plane.normal[2] > 0.7f)
+ {
+ // floor
+ blocked |= 0x01;
+ }
+
+ // If the plane has a zero z component in the normal, then it's a
+ // step or wall
+ if (!trace.plane.normal[2])
+ {
+ // step / wall
+ blocked |= 0x02;
+ }
+
+ time_left -= time_left * trace.fraction;
+
+ if (numplanes >= MAX_CLIP_PLANES) {
+ // this shouldn't really happen
+ VectorClear(pmove->velocity);
+ break;
+ }
+
+ //
+ // if this is the same plane we hit before, nudge velocity
+ // out along it, which fixes some epsilon issues with
+ // non-axial planes
+ //
+ for (i = 0; i < numplanes; i++) {
+ if (DotProduct(trace.plane.normal, planes[i]) > 0.99) {
+ VectorAdd(trace.plane.normal, pmove->velocity, pmove->velocity);
+ break;
+ }
+ }
+ if (i < numplanes) {
+ continue;
+ }
+ VectorCopy(trace.plane.normal, planes[numplanes]);
+ numplanes++;
+
+ //
+ // modify velocity so it parallels all of the clip planes
+ //
+
+ // find a plane that it enters
+ for (i = 0; i < numplanes; i++) {
+ into = DotProduct(pmove->velocity, planes[i]);
+ if (into >= 0.1) {
+ continue; // move doesn't interact with the plane
+ }
+
+ // slide along the plane
+ PM_ClipVelocity(pmove->velocity, planes[i], clipVelocity, 1);
+
+ // slide along the plane
+ PM_ClipVelocity(endVelocity, planes[i], endClipVelocity, 1);
+
+ // see if there is a second plane that the new move enters
+ for (j = 0; j < numplanes; j++) {
+ if (j == i) {
+ continue;
+ }
+ if (DotProduct(clipVelocity, planes[j]) >= 0.1) {
+ continue; // move doesn't interact with the plane
+ }
+
+ // try clipping the move to the plane
+ PM_ClipVelocity(clipVelocity, planes[j], clipVelocity, 1);
+ PM_ClipVelocity(endClipVelocity, planes[j], endClipVelocity, 1);
+
+ // see if it goes back into the first clip plane
+ if (DotProduct(clipVelocity, planes[i]) >= 0) {
+ continue;
+ }
+
+ // slide the original velocity along the crease
+ CrossProduct(planes[i], planes[j], dir);
+ VectorNormalize(dir);
+ d = DotProduct(dir, pmove->velocity);
+ VectorScale(dir, d, clipVelocity);
+
+ CrossProduct(planes[i], planes[j], dir);
+ VectorNormalize(dir);
+ d = DotProduct(dir, endVelocity);
+ VectorScale(dir, d, endClipVelocity);
+
+ // see if there is a third plane the the new move enters
+ for (k = 0; k < numplanes; k++) {
+ if (k == i || k == j) {
+ continue;
+ }
+ if (DotProduct(clipVelocity, planes[k]) >= 0.1) {
+ continue; // move doesn't interact with the plane
+ }
+
+ // stop dead at a tripple plane interaction
+ VectorClear(pmove->velocity);
+ return 4;
+ }
+ }
+
+ // if we have fixed all interactions, try another move
+ VectorCopy(clipVelocity, pmove->velocity);
+ VectorCopy(endClipVelocity, endVelocity);
+ break;
+ }
+ }
+
+ return blocked;
+}
+#endif
int PM_FlyMove()
{
+#ifdef REGAMEDLL_ADD
+ if (flymove_method.value)
+ return PM_FlyMove_New();
+#endif
int bumpcount, numbumps;
vec3_t dir;
float d;
@@ -887,6 +1061,18 @@ void PM_WalkMove()
{
real_t flRatio = (100 - pmove->fuser2 * 0.001 * 19) * 0.01;
+#ifdef REGAMEDLL_ADD
+ // change stamina restoration speed by fps reference
+ if (stamina_restore_rate.value > 0.0f)
+ {
+ real_t flReferenceFrametime = 1.0f / stamina_restore_rate.value;
+
+ float flFrametimeRatio = pmove->frametime / flReferenceFrametime;
+
+ flRatio = pow(flRatio, flFrametimeRatio);
+ }
+#endif
+
pmove->velocity[0] *= flRatio;
pmove->velocity[1] *= flRatio;
}
@@ -2430,13 +2616,18 @@ inline real_t PM_JumpHeight(bool longjump)
#ifdef REGAMEDLL_API
if (longjump)
{
- if(pmoveplayer->m_flLongJumpHeight > 0.0)
+ if (pmoveplayer->m_flLongJumpHeight > 0.0)
return pmoveplayer->m_flLongJumpHeight;
}
else if (pmoveplayer->m_flJumpHeight > 0.0)
return pmoveplayer->m_flJumpHeight;
#endif
+
+#ifdef REGAMEDLL_ADD
+ return Q_sqrt(2.0 * 800.0f * (longjump ? 56.0f : Q_max(jump_height.value, 0.0f)));
+#else
return Q_sqrt(2.0 * 800.0f * (longjump ? 56.0f : 45.0f));
+#endif
}
LINK_HOOK_VOID_CHAIN2(PM_Jump)
@@ -2607,6 +2798,7 @@ void EXT_FUNC __API_HOOK(PM_Jump)()
{
// NOTE: don't do it in .f (float)
real_t flRatio = (100.0 - pmove->fuser2 * 0.001 * 19.0) * 0.01;
+
pmove->velocity[2] *= flRatio;
}
diff --git a/regamedll/public/build.h b/regamedll/public/build.h
new file mode 100644
index 000000000..24fd9d5bb
--- /dev/null
+++ b/regamedll/public/build.h
@@ -0,0 +1,269 @@
+/*
+build.h - compile-time build information
+
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to
+*/
+#pragma once
+#ifndef BUILD_H
+#define BUILD_H
+
+/*
+All XASH_* macros set by this header are guaranteed to have positive value
+otherwise not defined.
+
+Every macro is intended to be the unified interface for buildsystems that lack
+platform & CPU detection, and a neat quick way for checks in platform code
+For Q_build* macros, refer to buildenums.h
+
+Any new define must be undefined at first
+You can generate #undef list below with this oneliner:
+ $ sed 's/\t//g' build.h | grep '^#define XASH' | awk '{ print $2 }' | \
+ sort | uniq | awk '{ print "#undef " $1 }'
+
+Then you can use another oneliner to query all variables:
+ $ grep '^#undef XASH' build.h | awk '{ print $2 }'
+*/
+
+#undef XASH_64BIT
+#undef XASH_AMD64
+#undef XASH_ANDROID
+#undef XASH_APPLE
+#undef XASH_ARM
+#undef XASH_ARM_HARDFP
+#undef XASH_ARM_SOFTFP
+#undef XASH_ARMv4
+#undef XASH_ARMv5
+#undef XASH_ARMv6
+#undef XASH_ARMv7
+#undef XASH_ARMv8
+#undef XASH_BIG_ENDIAN
+#undef XASH_DOS4GW
+#undef XASH_E2K
+#undef XASH_EMSCRIPTEN
+#undef XASH_FREEBSD
+#undef XASH_HAIKU
+#undef XASH_IOS
+#undef XASH_IRIX
+#undef XASH_JS
+#undef XASH_LINUX
+#undef XASH_LITTLE_ENDIAN
+#undef XASH_MIPS
+#undef XASH_MOBILE_PLATFORM
+#undef XASH_NETBSD
+#undef XASH_OPENBSD
+#undef XASH_POSIX
+#undef XASH_PPC
+#undef XASH_RISCV
+#undef XASH_RISCV_DOUBLEFP
+#undef XASH_RISCV_SINGLEFP
+#undef XASH_RISCV_SOFTFP
+#undef XASH_SERENITY
+#undef XASH_SUNOS
+#undef XASH_WIN32
+#undef XASH_X86
+#undef XASH_NSWITCH
+#undef XASH_PSVITA
+#undef XASH_WASI
+#undef XASH_WASM
+
+//================================================================
+//
+// PLATFORM DETECTION CODE
+//
+//================================================================
+#if defined _WIN32
+ #define XASH_WIN32 1
+#elif defined __EMSCRIPTEN__
+ #define XASH_EMSCRIPTEN 1
+#elif defined __WATCOMC__ && defined __DOS__
+ #define XASH_DOS4GW 1
+#else // POSIX compatible
+ #define XASH_POSIX 1
+ #if defined __linux__
+ #if defined __ANDROID__
+ #define XASH_ANDROID 1
+ #endif
+ #define XASH_LINUX 1
+ #elif defined __FreeBSD__
+ #define XASH_FREEBSD 1
+ #elif defined __NetBSD__
+ #define XASH_NETBSD 1
+ #elif defined __OpenBSD__
+ #define XASH_OPENBSD 1
+ #elif defined __HAIKU__
+ #define XASH_HAIKU 1
+ #elif defined __serenity__
+ #define XASH_SERENITY 1
+ #elif defined __sgi
+ #define XASH_IRIX 1
+ #elif defined __APPLE__
+ #include
+ #define XASH_APPLE 1
+ #if TARGET_OS_IOS
+ #define XASH_IOS 1
+ #endif // TARGET_OS_IOS
+ #elif defined __SWITCH__
+ #define XASH_NSWITCH 1
+ #elif defined __vita__
+ #define XASH_PSVITA 1
+ #elif defined __wasi__
+ #define XASH_WASI 1
+ #elif defined __sun__
+ #define XASH_SUNOS 1
+ #else
+ #error
+ #endif
+#endif
+
+// XASH_SAILFISH is special: SailfishOS by itself is a normal GNU/Linux platform
+// It doesn't make sense to split it to separate platform
+// but we still need XASH_MOBILE_PLATFORM for the engine.
+// So this macro is defined entirely in build-system: see main wscript
+// HLSDK/PrimeXT/other SDKs users note: you may ignore this macro
+#if XASH_ANDROID || XASH_IOS || XASH_NSWITCH || XASH_PSVITA || XASH_SAILFISH
+ #define XASH_MOBILE_PLATFORM 1
+#endif
+
+//================================================================
+//
+// ENDIANNESS DEFINES
+//
+//================================================================
+
+#if !defined XASH_ENDIANNESS
+ #if defined XASH_WIN32 || __LITTLE_ENDIAN__
+ //!!! Probably all WinNT installations runs in little endian
+ #define XASH_LITTLE_ENDIAN 1
+ #elif __BIG_ENDIAN__
+ #define XASH_BIG_ENDIAN 1
+ #elif defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ && defined __ORDER_LITTLE_ENDIAN__ // some compilers define this
+ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ #define XASH_BIG_ENDIAN 1
+ #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ #define XASH_LITTLE_ENDIAN 1
+ #endif
+ #else
+ #include
+ #if __BYTE_ORDER == __BIG_ENDIAN
+ #define XASH_BIG_ENDIAN 1
+ #elif __BYTE_ORDER == __LITTLE_ENDIAN
+ #define XASH_LITTLE_ENDIAN 1
+ #endif
+ #endif // !XASH_WIN32
+#endif
+
+//================================================================
+//
+// CPU ARCHITECTURE DEFINES
+//
+//================================================================
+#if defined __x86_64__ || defined _M_X64
+ #define XASH_64BIT 1
+ #define XASH_AMD64 1
+#elif defined __i386__ || defined _X86_ || defined _M_IX86
+ #define XASH_X86 1
+#elif defined __aarch64__ || defined _M_ARM64
+ #define XASH_64BIT 1
+ #define XASH_ARM 8
+#elif defined __mips__
+ #define XASH_MIPS 1
+#elif defined __EMSCRIPTEN__
+ #define XASH_JS 1
+#elif defined __e2k__
+ #define XASH_64BIT 1
+ #define XASH_E2K 1
+#elif defined __PPC__ || defined __powerpc__
+ #define XASH_PPC 1
+ #if defined __PPC64__ || defined __powerpc64__
+ #define XASH_64BIT 1
+ #endif
+#elif defined _M_ARM // msvc
+ #define XASH_ARM 7
+ #define XASH_ARM_HARDFP 1
+#elif defined __arm__
+ #if __ARM_ARCH == 8 || __ARM_ARCH_8__
+ #define XASH_ARM 8
+ #elif __ARM_ARCH == 7 || __ARM_ARCH_7__
+ #define XASH_ARM 7
+ #elif __ARM_ARCH == 6 || __ARM_ARCH_6__ || __ARM_ARCH_6J__
+ #define XASH_ARM 6
+ #elif __ARM_ARCH == 5 || __ARM_ARCH_5__
+ #define XASH_ARM 5
+ #elif __ARM_ARCH == 4 || __ARM_ARCH_4__
+ #define XASH_ARM 4
+ #else
+ #error "Unknown ARM"
+ #endif
+
+ #if defined __SOFTFP__ || __ARM_PCS_VFP == 0
+ #define XASH_ARM_SOFTFP 1
+ #else // __SOFTFP__
+ #define XASH_ARM_HARDFP 1
+ #endif // __SOFTFP__
+#elif defined __riscv
+ #define XASH_RISCV 1
+
+ #if __riscv_xlen == 64
+ #define XASH_64BIT 1
+ #elif __riscv_xlen != 32
+ #error "Unknown RISC-V ABI"
+ #endif
+
+ #if defined __riscv_float_abi_soft
+ #define XASH_RISCV_SOFTFP 1
+ #elif defined __riscv_float_abi_single
+ #define XASH_RISCV_SINGLEFP 1
+ #elif defined __riscv_float_abi_double
+ #define XASH_RISCV_DOUBLEFP 1
+ #else
+ #error "Unknown RISC-V float ABI"
+ #endif
+#elif defined __wasm__
+ #if defined __wasm64__
+ #define XASH_64BIT 1
+ #endif
+ #define XASH_WASM 1
+#else
+ #error "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug"
+#endif
+
+#if !XASH_64BIT && ( defined( __LP64__ ) || defined( _LP64 ))
+#define XASH_64BIT 1
+#endif
+
+#if XASH_ARM == 8
+ #define XASH_ARMv8 1
+#elif XASH_ARM == 7
+ #define XASH_ARMv7 1
+#elif XASH_ARM == 6
+ #define XASH_ARMv6 1
+#elif XASH_ARM == 5
+ #define XASH_ARMv5 1
+#elif XASH_ARM == 4
+ #define XASH_ARMv4 1
+#endif
+
+#endif // BUILD_H
diff --git a/regamedll/public/regamedll/API/CSPlayer.h b/regamedll/public/regamedll/API/CSPlayer.h
index 05b81b704..3ead37a22 100644
--- a/regamedll/public/regamedll/API/CSPlayer.h
+++ b/regamedll/public/regamedll/API/CSPlayer.h
@@ -117,6 +117,8 @@ class CCSPlayer: public CCSMonster {
virtual void Reset();
virtual void OnSpawnEquip(bool addDefault = true, bool equipGame = true);
virtual void SetScoreboardAttributes(CBasePlayer *destination = nullptr);
+ virtual void Observer_FindNextPlayer(bool bReverse, const char *name = nullptr);
+ virtual void TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier);
bool IsPlayerDominated(int iPlayerIndex) const;
void SetPlayerDominated(CBasePlayer *pPlayer, bool bDominated);
diff --git a/regamedll/public/regamedll/regamedll_api.h b/regamedll/public/regamedll/regamedll_api.h
index 74879aa42..2e52c0c7c 100644
--- a/regamedll/public/regamedll/regamedll_api.h
+++ b/regamedll/public/regamedll/regamedll_api.h
@@ -38,7 +38,7 @@
#include
#define REGAMEDLL_API_VERSION_MAJOR 5
-#define REGAMEDLL_API_VERSION_MINOR 28
+#define REGAMEDLL_API_VERSION_MINOR 31
// CBasePlayer::Spawn hook
typedef IHookChainClass IReGameHook_CBasePlayer_Spawn;
@@ -628,6 +628,14 @@ typedef IHookChainRegistryClass IReGameHookRegistry_CBa
typedef IHookChainClass IReGameHook_CBasePlayer_RemoveAllItems;
typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_RemoveAllItems;
+// CBasePlayer::UpdateStatusBar hook
+typedef IHookChainClass IReGameHook_CBasePlayer_UpdateStatusBar;
+typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_UpdateStatusBar;
+
+// CBasePlayer::TakeDamageImpulse hook
+typedef IHookChainClass IReGameHook_CBasePlayer_TakeDamageImpulse;
+typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_TakeDamageImpulse;
+
class IReGameHookchains {
public:
virtual ~IReGameHookchains() {}
@@ -790,6 +798,8 @@ class IReGameHookchains {
virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0;
virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0;
virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems() = 0;
+ virtual IReGameHookRegistry_CBasePlayer_UpdateStatusBar *CBasePlayer_UpdateStatusBar() = 0;
+ virtual IReGameHookRegistry_CBasePlayer_TakeDamageImpulse *CBasePlayer_TakeDamageImpulse() = 0;
};
struct ReGameFuncs_t {
@@ -816,6 +826,18 @@ struct ReGameFuncs_t {
void (*TextureTypePlaySound)(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType);
class CWeaponBox *(*CreateWeaponBox)(CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo);
class CGrenade *(*SpawnGrenade)(WeaponIdType weaponId, entvars_t *pevOwner, Vector &vecSrc, Vector &vecThrow, float time, int iTeam, unsigned short usEvent);
+ int (*UTIL_SharedRandomLong)(unsigned int seed, int low, int high);
+ float (*UTIL_SharedRandomFloat)(unsigned int seed, float low, float high);
+ void (*UTIL_SetGroupTrace)(int groupmask, int op);
+ void (*UTIL_UnsetGroupTrace)();
+ int (*UTIL_EntitiesInBox)(CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask);
+ void (*UTIL_ScreenShake)(const Vector ¢er, float amplitude, float frequency, float duration, float radius);
+ void (*UTIL_ScreenFadeAll)(const Vector &color, float fadeTime, float fadeHold, int alpha, int flags);
+ void (*UTIL_ScreenFade)(CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags);
+ float (*UTIL_WaterLevel)(const Vector &position, float minz, float maxz);
+ void (*UTIL_Bubbles)(Vector mins, Vector maxs, int count);
+ void (*UTIL_BubbleTrail)(Vector from, Vector to, int count);
+ char (*UTIL_TextureHit)(TraceResult *ptr, Vector vecSrc, Vector vecEnd);
};
class IReGameApi {
diff --git a/regamedll/public/strtools.h b/regamedll/public/strtools.h
index 5cdf8c41d..11279c76e 100644
--- a/regamedll/public/strtools.h
+++ b/regamedll/public/strtools.h
@@ -156,40 +156,48 @@ inline char *Q_strlcpy(char *dest, const char *src, size_t size) {
// a safe variant of strcpy that truncates the result to fit in the destination buffer
template
char *Q_strlcpy(char (&dest)[size], const char *src) {
- return Q_strlcpy(dest, src, size);
+ return Q_strlcpy(static_cast(dest), src, size);
}
// safely concatenate two strings.
// a variant of strcat that truncates the result to fit in the destination buffer
-template
-size_t Q_strlcat(char (&dest)[size], const char *src)
+inline size_t Q_strlcat(char *dest, const char *src, size_t maxDestSize)
{
size_t srclen; // Length of source string
size_t dstlen; // Length of destination string
// Figure out how much room is left
- dstlen = Q_strlen(dest);
- size_t length = size - dstlen + 1;
+ dstlen = strlen(dest);
+ size_t unRemainingSize = maxDestSize - dstlen - 1;
+
+ // Sanity check in case dest doesn't contain a null termination
+ if (dstlen > (maxDestSize - 1))
+ dstlen = maxDestSize - 1;
- if (!length) {
- // No room, return immediately
- return dstlen;
+ if (unRemainingSize <= 0 || unRemainingSize > maxDestSize)
+ {
+ dest[dstlen] = '\0';
+ return dstlen; // No room, return immediately
}
// Figure out how much room is needed
- srclen = Q_strlen(src);
+ srclen = strlen(src);
// Copy the appropriate amount
- if (srclen > length) {
- srclen = length;
- }
+ if (srclen > unRemainingSize)
+ srclen = unRemainingSize;
Q_memcpy(dest + dstlen, src, srclen);
dest[dstlen + srclen] = '\0';
-
return dstlen + srclen;
}
+template
+inline size_t Q_strlcat(char (&dest)[size], const char *src)
+{
+ return Q_strlcat(static_cast(dest), src, size);
+}
+
// Force slashes of either type to be = separator character
inline void Q_FixSlashes(char *pname, char separator = CORRECT_PATH_SEPARATOR)
{
diff --git a/regamedll/regamedll/regamedll.cpp b/regamedll/regamedll/regamedll.cpp
index 5e6190d15..9602faa17 100644
--- a/regamedll/regamedll/regamedll.cpp
+++ b/regamedll/regamedll/regamedll.cpp
@@ -33,7 +33,6 @@ void Regamedll_Game_Init()
g_bIsBeta = UTIL_IsBeta();
g_bIsCzeroGame = UTIL_IsGame("czero");
g_bAllowedCSBot = UTIL_AreBotsAllowed(); // determine whether bots can be used or not
- g_bHostageImprov = UTIL_AreHostagesImprov(); // determine whether hostage improv can be used or not
WeaponInfoReset();
}
diff --git a/regamedll/regamedll/types.natvis b/regamedll/regamedll/types.natvis
new file mode 100644
index 000000000..4dc313c65
--- /dev/null
+++ b/regamedll/regamedll/types.natvis
@@ -0,0 +1,107 @@
+
+
+
+
+
+ {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname }, { pev->health }, { m_iTeam }, { m_iModelName } }}
+
+
+
+
+
+ { *m_pContainingEntity }
+
+
+
+
+ {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname } }}
+
+
+ m_pNext
+ m_pNext
+ (*this)
+
+
+
+
+
+
+ {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname }, { pev->model } }}
+
+
+
+
+ {{ {this - g_pEdicts}, { v.classname }, { v.model } }}
+
+
+
+
+ {{ { pContainingEntity - g_pEdicts }, { classname }, { model } }}
+
+
+
+
+ { &gpGlobals->pStringBase[m_string],s }
+
+
+
+
+ allocator
+
+ - ($T1 *)m_pMemory
+ - m_nAllocationCount
+ - m_nGrowSize
+
+
+
+
+
+ {{ size = { m_Size } }}
+
+
+ m_Size
+ (ElemType_t *)m_Memory.m_pMemory
+
+
+
+
+
+
+ {{ size = { m_Tree.m_NumElements } }}
+
+ - m_Tree.m_NumElements
+ - m_Tree.m_Elements
+
+
+
+ - ((CTree::Node_t *)m_Tree.m_Elements.m_pMemory)[iMap].m_Data.elem
+ iMap++
+
+
+
+
+
+
+
+ {{ size = { $T2 } }}
+
+
+ $T2
+ ($T1 *)&m_Memory[0]
+
+
+
+
+
+
+
+ - m_NumElements
+ - m_Elements
+
+ m_NumElements
+ ((Node_t *)m_Elements.m_pMemory)[$i].m_Data
+
+
+
+
+
diff --git a/regamedll/unittests/mathfun_tests.cpp b/regamedll/unittests/mathfun_tests.cpp
index 6cb36eca5..7d39cb3b7 100644
--- a/regamedll/unittests/mathfun_tests.cpp
+++ b/regamedll/unittests/mathfun_tests.cpp
@@ -32,10 +32,10 @@ TEST(SinCosPrecision, SseMathFun, 10000)
double sse_sin = _mm_cvtss_f32(s);
double sse_cos = _mm_cvtss_f32(c);
- sprintf(localbuf, "sin precision failure for angle=%f", i);
+ Q_snprintf(localbuf, sizeof(localbuf), "sin precision failure for angle=%f", i);
DOUBLES_EQUAL(localbuf, x87_sin, sse_sin, 0.000001);
- sprintf(localbuf, "cos precision failure for angle=%f", i);
+ Q_snprintf(localbuf, sizeof(localbuf), "cos precision failure for angle=%f", i);
DOUBLES_EQUAL(localbuf, x87_cos, sse_cos, 0.000001);
}
}
diff --git a/regamedll/version/version.h b/regamedll/version/version.h
index 62c33001b..77bdbb482 100644
--- a/regamedll/version/version.h
+++ b/regamedll/version/version.h
@@ -6,5 +6,5 @@
#pragma once
#define VERSION_MAJOR 5
-#define VERSION_MINOR 28
+#define VERSION_MINOR 31
#define VERSION_MAINTENANCE 0