Compare commits

...

26 Commits

Author SHA1 Message Date
GLoOoccK
8d5aa54ceb
API: Knockback (#1069) 2025-04-20 21:32:49 +07:00
GLoOoccK
a4f48f4e42
FIX: Remove grenades and C4 (#1066) 2025-04-20 21:13:08 +07:00
s1lentq
99d93ba8a7 Fix crash nav generation with impossibly-large grid 2025-04-17 04:59:11 +07:00
s1lentq
5bf71bdb18 CCSBot::FindMostDangerousThreat: Fix crash when m_pActiveItem is null Related #1055 2025-04-08 06:59:49 +07:00
Eason
797c265db3
API: Implemented CBasePlayer::Observer_FindNextPlayer() (#1065) 2025-04-07 01:13:23 +07:00
s1lentq
312dc3eb84 Fix defuse behavior when bomb explodes
- Ensure DefuseBombEnd is called when defusing and bomb explodes to properly stop defuse
- Fixes the issue where defuse progress bar continued draw after bomb explosion
2025-04-06 04:01:26 +07:00
GLoOoccK
0fc5213049
Implements UpdateStatusBar Hook (#968) 2025-04-04 22:47:40 +07:00
s1lentq
f3d8d1b5fd fix typo 2025-04-04 08:24:33 +07:00
s1lentq
a4d74392f0 Update player's HUD after round restart time expires, not before it 2025-04-04 02:49:40 +07:00
s1lentq
35082b5f26 fix build.sh for clang compiler 2025-04-04 02:42:29 +07:00
s1lentq
6f70d6dd8e ZBot: Implemented immediate reloading of nav data after bot analysis, without requiring a full map restart
ZBot: Added cleanup for dangling navigation pointers in bots, enabling seamless map reanalysis
Minor refactoring
2025-04-04 02:41:19 +07:00
s1lentq
f5cc6f3a8b AngleQuaternion: fix buffer overflow 2025-04-04 02:19:53 +07:00
Garey
d3fc7ac000
New flymove more accurate method (#1006) 2025-03-28 06:16:07 +07:00
Garey
ce11175e89
Add cvar for stamina restoration speed based on fps reference. (#1005)
* Add variable for framerate (FPS), that used as reference when restoring stamina (fuser2) after jump.
2025-03-28 06:05:43 +07:00
Vaqtincha
b10f23e1e9
Add new CVars mp_playerid_showhealth & mp_playerid_field (#1046)
* Add new CVars playerid_showhealth & mp_playerid_field
2025-03-28 05:59:34 +07:00
golukon
b44b09d07b
feat: add new cvar "mp_logkills" (#1039) 2025-03-28 05:30:32 +07:00
Vaqtincha
d8faea0966
Add new CVar mp_jump_height (#1022) 2025-03-28 05:28:15 +07:00
Vaqtincha
94a7eb4cbb
added forgot pistols fiveseven and dualelite touching for vip (#1045) 2025-03-28 05:21:24 +07:00
Vaqtincha
518f142635
Add new CVar mp_default_weapons_random (#1015) 2025-03-28 05:20:28 +07:00
Vaqtincha
dbec1b589c
Randomspawn (#1013)
add new cvar mp_randomspawn
improved search for the best angle
added mp_randomspawn 2 for debugging
added info_spawn_point entity to .fgd
2025-03-28 05:17:02 +07:00
Vaqtincha
316405b00d
add new cvar "bot_excellent_morale" (#1035) 2025-03-28 05:10:32 +07:00
Vaqtincha
b8e9726347
fix: bots can't buy sec ammo if preferred pistol (ex. "WeaponPreference = deagle" in BotProfile.db) (#1034) 2025-03-28 05:09:56 +07:00
Francisco Muñoz
6adb795fee
Team Say refactory/enhancement (#1042)
Disable say_team when FFA mode is enabled
Only for CT and T, Spectators can still use say_team
2025-03-28 05:09:24 +07:00
golukon
756deb1ea9
fix: calculate UpdateLocation fun not so often (#1040) 2025-03-28 05:08:42 +07:00
Huga
a7395b054d
Bot Chatter: Bots will react to enemy snipers presence (#1055)
Friendly fire fixes
Bot Chatter: Bots will react to enemy snipers presence
previously unused chatter on both 1.6 and czero but is used on cs source
Probably fixed where teammate that use sniperrifles looking at bots that don't use sniperrifles got warned
2025-03-28 05:06:17 +07:00
Alibek Omarov
b59bbb1c83
CMake improvements, add 64-bit support for use in Xash3D FWGS (#1053)
* cmake: do not strip debuginfo during link if DEBUG was enabled
* cmake: use compiler id instead of env checks to determine Intel compiler or Clang
* cmake: introduce XASH_COMPAT option, which will let regamedll to be built for 64-bit and non-x86 targets
* cmake: add LibraryNaming module from hlsdk-portable repository and platform detection header
* cmake: now, integrate LibraryNaming into regamedll CMakeLists file. Disable x86 options on non-x86 platforms
* server: add support for 64-bit ABI used in Xash3D FWGS
2025-03-28 05:03:52 +07:00
42 changed files with 1909 additions and 149 deletions

View File

@ -98,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_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_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_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).<br/> `0` disabled<br/>`1` enabled |
| mp_give_player_c4 | 1 | 0 | 1 | Whether this map should spawn a C4 bomb for a player or not.<br/> `0` disabled<br/>`1` enabled | | mp_give_player_c4 | 1 | 0 | 1 | Whether this map should spawn a C4 bomb for a player or not.<br/> `0` disabled<br/>`1` enabled |
| mp_weapons_allow_map_placed | 1 | 0 | 1 | When set, map weapons (located on the floor by map) will be shown.<br/> `0` hide all map weapons.<br/>`1` enabled<br/>`NOTE`: Effect will work after round restart. | | mp_weapons_allow_map_placed | 1 | 0 | 1 | When set, map weapons (located on the floor by map) will be shown.<br/> `0` hide all map weapons.<br/>`1` enabled<br/>`NOTE`: Effect will work after round restart. |
| mp_free_armor | 0 | 0 | 2 | Give free armor on player spawn.<br/>`0` disabled <br/>`1` Give Kevlar <br/>`2` Give Kevlar + Helmet | | mp_free_armor | 0 | 0 | 2 | Give free armor on player spawn.<br/>`0` disabled <br/>`1` Give Kevlar <br/>`2` Give Kevlar + Helmet |
@ -123,6 +124,15 @@ 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_ammo_respawn_time | 20 | 0.0 | - | The respawn time for ammunition. |
| mp_vote_flags | km | 0 | - | Vote systems enabled in server.<br/>`0` voting disabled<br/>`k` votekick enabled via `vote` command<br/>`m` votemap enabled via `votemap` command | | mp_vote_flags | km | 0 | - | Vote systems enabled in server.<br/>`0` voting disabled<br/>`k` votekick enabled via `vote` command<br/>`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_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.<br/> `0` default method<br/>`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.<br/>`0` disabled <br/>`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<br/>`0` disabled <br/>`1` enabled<br/>`NOTE`: Navigation `maps/.nav` file required |
| mp_playerid_showhealth | 1 | 0 | 2 | Player ID display mode.<br/>`0` don't show health<br/>`1` show health for teammates only (default CS behaviour)<br/>`2` show health for all players |
| mp_playerid_field | 3 | 0 | 3 | Player ID field display mode.<br/>`0` don't show additional information<br/>`1` show team name<br/>`2` show health percentage<br/>`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`).<br/>Works only if not crouching, and not hit in the legs.<br/>Set to `0` to disable. |
</details> </details>

View File

@ -33,7 +33,7 @@ main()
case "$C" in case "$C" in
("intel"|"icc") CC=icc CXX=icpc ;; ("intel"|"icc") CC=icc CXX=icpc ;;
("gcc"|"g++") CC=gcc CXX=g++ ;; ("gcc"|"g++") CC=gcc CXX=g++ ;;
("clang|llvm") CC=clang CXX=clang++ ;; ("clang"|"llvm") CC=clang CXX=clang++ ;;
*) *)
;; ;;
esac esac

67
dist/game.cfg vendored
View File

@ -466,6 +466,13 @@ mp_ct_default_weapons_primary ""
// Default value: "usp" // Default value: "usp"
mp_ct_default_weapons_secondary "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 // Give the player free armor on player spawn
// 0 - No armor (default behavior) // 0 - No armor (default behavior)
// 1 - Give Kevlar // 1 - Give Kevlar
@ -620,3 +627,63 @@ mp_vote_flags "km"
// //
// Default value: "180" // Default value: "180"
mp_votemap_min_time "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"

View File

@ -20,20 +20,47 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.1)
project(regamedll CXX) project(regamedll CXX)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
option(DEBUG "Build with debug information." OFF) option(DEBUG "Build with debug information." OFF)
option(USE_STATIC_LIBSTDC "Enables static linking libstdc++." 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(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 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Avoid -rdynamic -fPIC options # Avoid -rdynamic -fPIC options
set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "") if (NOT XASH_COMPAT)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "")
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
endif()
set(COMPILE_FLAGS "-m32 -U_FORTIFY_SOURCE") set(COMPILE_FLAGS "-U_FORTIFY_SOURCE")
set(LINK_FLAGS "-m32 -s") set(LINK_LIBS dl)
set(LINK_LIBS dl aelf32)
# 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") set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wall -fno-exceptions -fno-builtin -Wno-unknown-pragmas")
@ -47,7 +74,7 @@ else()
endif() endif()
# Check Intel C++ compiler # Check Intel C++ compiler
if ("$ENV{CXX}" MATCHES "icpc") if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
# #
# -fp-model=precise # -fp-model=precise
# ICC uses -fp-model fast=1 by default for more aggressive optimizations on floating-point calculations # 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(COMPILE_FLAGS "${COMPILE_FLAGS} -ipo")
set(LINK_FLAGS "${LINK_FLAGS} -ipo") set(LINK_FLAGS "${LINK_FLAGS} -ipo")
endif() endif()
else() 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. # 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. # As new processors are deployed in the marketplace, the behavior of this option will change.
set(COMPILE_FLAGS "${COMPILE_FLAGS} \ set(COMPILE_FLAGS "${COMPILE_FLAGS} \
-mtune=generic -msse3\ -mtune=generic -msse3")
endif()
set(COMPILE_FLAGS "${COMPILE_FLAGS} \
-fpermissive -fno-sized-deallocation\ -fpermissive -fno-sized-deallocation\
-Wno-delete-non-virtual-dtor -Wno-invalid-offsetof\ -Wno-delete-non-virtual-dtor -Wno-invalid-offsetof\
-Wno-unused-variable -Wno-unused-value -Wno-unused-result -Wno-unused-function\ -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") -Wno-sign-compare -Wno-format -Wno-ignored-attributes -Wno-strict-aliasing")
# Check Clang compiler # Check Clang compiler
if ("$ENV{CXX}" MATCHES "clang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(COMPILE_FLAGS "${COMPILE_FLAGS} \ set(COMPILE_FLAGS "${COMPILE_FLAGS} \
-Wno-unused-local-typedef\ -Wno-unused-local-typedef\
-Wno-unused-private-field\ -Wno-unused-private-field\
@ -102,16 +133,11 @@ else()
# GCC >= 8.3 # GCC >= 8.3
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) 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() 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) if (NOT DEBUG)
set(LINK_FLAGS "${LINK_FLAGS} \ set(LINK_FLAGS "${LINK_FLAGS} \
-Wl,-gc-sections -Wl,--version-script=\"${PROJECT_SOURCE_DIR}/../version_script.lds\"") -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++") set(LINK_FLAGS "${LINK_FLAGS} -static-libgcc -static-libstdc++")
endif() endif()
set(LINK_FLAGS "${LINK_FLAGS} \ set(LINK_FLAGS "${LINK_FLAGS} -Wl,-rpath,'$ORIGIN/.'")
-Wl,-rpath,'$ORIGIN/.' \
-L${PROJECT_SOURCE_DIR}/lib/linux32") if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LINK_FLAGS "${LINK_FLAGS} -L${PROJECT_SOURCE_DIR}/lib/linux32")
endif()
set_target_properties(regamedll PROPERTIES set_target_properties(regamedll PROPERTIES
OUTPUT_NAME cs
PREFIX ""
COMPILE_FLAGS ${COMPILE_FLAGS} COMPILE_FLAGS ${COMPILE_FLAGS}
LINK_FLAGS ${LINK_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)

View File

@ -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})

View File

@ -336,6 +336,8 @@ GAMEHOOK_REGISTRY(CSGameRules_SendDeathMessage);
GAMEHOOK_REGISTRY(CBasePlayer_PlayerDeathThink); GAMEHOOK_REGISTRY(CBasePlayer_PlayerDeathThink);
GAMEHOOK_REGISTRY(CBasePlayer_Observer_Think); GAMEHOOK_REGISTRY(CBasePlayer_Observer_Think);
GAMEHOOK_REGISTRY(CBasePlayer_RemoveAllItems); GAMEHOOK_REGISTRY(CBasePlayer_RemoveAllItems);
GAMEHOOK_REGISTRY(CBasePlayer_UpdateStatusBar);
GAMEHOOK_REGISTRY(CBasePlayer_TakeDamageImpulse);
int CReGameApi::GetMajorVersion() { int CReGameApi::GetMajorVersion() {
return REGAMEDLL_API_VERSION_MAJOR; return REGAMEDLL_API_VERSION_MAJOR;

View File

@ -749,6 +749,14 @@ typedef IHookChainRegistryClassImpl<void, CBasePlayer> CReGameHookRegistry_CBase
typedef IHookChainClassImpl<void, CBasePlayer, BOOL> CReGameHook_CBasePlayer_RemoveAllItems; typedef IHookChainClassImpl<void, CBasePlayer, BOOL> CReGameHook_CBasePlayer_RemoveAllItems;
typedef IHookChainRegistryClassImpl<void, CBasePlayer, BOOL> CReGameHookRegistry_CBasePlayer_RemoveAllItems; typedef IHookChainRegistryClassImpl<void, CBasePlayer, BOOL> CReGameHookRegistry_CBasePlayer_RemoveAllItems;
// CBasePlayer::UpdateStatusBar hook
typedef IHookChainClassImpl<void, CBasePlayer> CReGameHook_CBasePlayer_UpdateStatusBar;
typedef IHookChainRegistryClassImpl<void, CBasePlayer> CReGameHookRegistry_CBasePlayer_UpdateStatusBar;
// CBasePlayer::TakeDamageImpulse hook
typedef IHookChainClassImpl<void, CBasePlayer, CBasePlayer *, float, float> CReGameHook_CBasePlayer_TakeDamageImpulse;
typedef IHookChainRegistryClassImpl<void, CBasePlayer, CBasePlayer *, float, float> CReGameHookRegistry_CBasePlayer_TakeDamageImpulse;
class CReGameHookchains: public IReGameHookchains { class CReGameHookchains: public IReGameHookchains {
public: public:
// CBasePlayer virtual // CBasePlayer virtual
@ -910,6 +918,8 @@ public:
CReGameHookRegistry_CBasePlayer_PlayerDeathThink m_CBasePlayer_PlayerDeathThink; CReGameHookRegistry_CBasePlayer_PlayerDeathThink m_CBasePlayer_PlayerDeathThink;
CReGameHookRegistry_CBasePlayer_Observer_Think m_CBasePlayer_Observer_Think; CReGameHookRegistry_CBasePlayer_Observer_Think m_CBasePlayer_Observer_Think;
CReGameHookRegistry_CBasePlayer_RemoveAllItems m_CBasePlayer_RemoveAllItems; CReGameHookRegistry_CBasePlayer_RemoveAllItems m_CBasePlayer_RemoveAllItems;
CReGameHookRegistry_CBasePlayer_UpdateStatusBar m_CBasePlayer_UpdateStatusBar;
CReGameHookRegistry_CBasePlayer_TakeDamageImpulse m_CBasePlayer_TakeDamageImpulse;
public: public:
virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn(); virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn();
@ -1070,6 +1080,8 @@ public:
virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink(); virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink();
virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think(); virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think();
virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems(); virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems();
virtual IReGameHookRegistry_CBasePlayer_UpdateStatusBar *CBasePlayer_UpdateStatusBar();
virtual IReGameHookRegistry_CBasePlayer_TakeDamageImpulse *CBasePlayer_TakeDamageImpulse();
}; };
extern CReGameHookchains g_ReGameHookchains; extern CReGameHookchains g_ReGameHookchains;

View File

@ -412,6 +412,11 @@ EXT_FUNC void CCSPlayer::Observer_SetMode(int iMode)
BasePlayer()->Observer_SetMode(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) EXT_FUNC bool CCSPlayer::SelectSpawnSpot(const char *pEntClassName, CBaseEntity *&pSpot)
{ {
return BasePlayer()->SelectSpawnSpot(pEntClassName, pSpot); return BasePlayer()->SelectSpawnSpot(pEntClassName, pSpot);
@ -534,6 +539,11 @@ EXT_FUNC bool CCSPlayer::CheckActivityInGame()
return (fabs(deltaYaw) >= 0.1f && fabs(deltaPitch) >= 0.1f); 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() void CCSPlayer::ResetVars()
{ {
m_szModel[0] = '\0'; m_szModel[0] = '\0';

View File

@ -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 }; 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 a = _mm_mul_ps(a, _mm_load_ps(_ps_0p5)); //a *= 0.5
__m128 s, c; __m128 s, c;
sincos_ps(a, &s, &c); sincos_ps(a, &s, &c);

View File

@ -900,3 +900,129 @@ float CCSBot::GetRangeToFarthestEscortedHostage() const
return away.m_farRange; 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<CNavArea *>(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<CNavArea *>(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<HidingSpot *>(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;
}
}
}

View File

@ -71,6 +71,7 @@ public:
virtual const char *GetName() const { return "Hunt"; } virtual const char *GetName() const { return "Hunt"; }
void ClearHuntArea() { m_huntArea = nullptr; } void ClearHuntArea() { m_huntArea = nullptr; }
CNavArea *GetHuntArea() { return m_huntArea; }
private: private:
CNavArea *m_huntArea; CNavArea *m_huntArea;
@ -204,6 +205,7 @@ public:
const Vector &GetHidingSpot() const { return m_hidingSpot; } const Vector &GetHidingSpot() const { return m_hidingSpot; }
void SetSearchArea(CNavArea *area) { m_searchFromArea = area; } void SetSearchArea(CNavArea *area) { m_searchFromArea = area; }
CNavArea *GetSearchArea() { return m_searchFromArea; }
void SetSearchRange(float range) { m_range = range; } void SetSearchRange(float range) { m_range = range; }
void SetDuration(float time) { m_duration = time; } void SetDuration(float time) { m_duration = time; }
@ -533,12 +535,21 @@ public:
bool IsAwareOfEnemyDeath() const; // return true if we *noticed* that our enemy died 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 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 // navigation
bool HasPath() const; bool HasPath() const;
void DestroyPath(); void DestroyPath();
float GetFeetZ() const; // return Z of bottom of feet 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 enum PathResult
{ {
PROGRESSING, // we are moving along the path PROGRESSING, // we are moving along the path
@ -921,6 +932,11 @@ private:
float m_fireWeaponTimestamp; 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 // reaction time system
enum { MAX_ENEMY_QUEUE = 20 }; enum { MAX_ENEMY_QUEUE = 20 };
struct ReactionState struct ReactionState
@ -1109,6 +1125,11 @@ inline bool CCSBot::IsAtBombsite()
inline CCSBot::MoraleType CCSBot::GetMorale() const inline CCSBot::MoraleType CCSBot::GetMorale() const
{ {
#ifdef REGAMEDLL_ADD
if (cv_bot_excellent_morale.value != 0.0f)
return EXCELLENT;
#endif
return m_morale; return m_morale;
} }
@ -1250,6 +1271,18 @@ inline int CCSBot::GetLastVictimID() const
return m_lastVictimID; 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 inline bool CCSBot::HasPath() const
{ {
return m_pathLength != 0; return m_pathLength != 0;

View File

@ -246,6 +246,17 @@ void BotHostageBeingTakenMeme::Interpret(CCSBot *pSender, CCSBot *pReceiver) con
pReceiver->GetChatter()->Say("Affirmative"); 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() BotSpeakable::BotSpeakable()
{ {
m_phrase = nullptr; m_phrase = nullptr;
@ -1270,6 +1281,9 @@ void BotChatterInterface::Reset()
m_planInterval.Invalidate(); m_planInterval.Invalidate();
m_encourageTimer.Invalidate(); m_encourageTimer.Invalidate();
m_escortingHostageTimer.Invalidate(); m_escortingHostageTimer.Invalidate();
#ifdef REGAMEDLL_ADD
m_warnSniperTimer.Invalidate();
#endif
} }
// Register a statement for speaking // Register a statement for speaking
@ -1626,6 +1640,42 @@ void BotChatterInterface::EnemySpotted()
AddStatement(say); 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) NOXREF void BotChatterInterface::Clear(Place place)
{ {
BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f); BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);

View File

@ -140,6 +140,14 @@ public:
virtual void Interpret(CCSBot *pSender, CCSBot *pReceiver) const; // cause the given bot to act on this meme 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 enum BotStatementType
{ {
REPORT_VISIBLE_ENEMIES, REPORT_VISIBLE_ENEMIES,
@ -531,6 +539,10 @@ public:
void KilledFriend(); void KilledFriend();
void FriendlyFire(); void FriendlyFire();
#ifdef REGAMEDLL_ADD
void SpottedSniper(void);
void FriendSpottedSniper(void);
#endif
bool SeesAtLeastOneEnemy() const { return m_seeAtLeastOneEnemy; } bool SeesAtLeastOneEnemy() const { return m_seeAtLeastOneEnemy; }
private: private:
@ -557,6 +569,9 @@ private:
CountdownTimer m_spottedLooseBombTimer; CountdownTimer m_spottedLooseBombTimer;
CountdownTimer m_heardNoiseTimer; CountdownTimer m_heardNoiseTimer;
CountdownTimer m_escortingHostageTimer; CountdownTimer m_escortingHostageTimer;
#ifdef REGAMEDLL_ADD
CountdownTimer m_warnSniperTimer;
#endif
}; };
inline BotChatterInterface::VerbosityType BotChatterInterface::GetVerbosity() const inline BotChatterInterface::VerbosityType BotChatterInterface::GetVerbosity() const

View File

@ -65,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_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 = { "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_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 #else
// Migrated to bot_quota_mode, use "match" // Migrated to bot_quota_mode, use "match"
cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr }; cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr };
@ -136,6 +137,7 @@ void Bot_RegisterCVars()
CVAR_REGISTER(&cv_bot_freeze); CVAR_REGISTER(&cv_bot_freeze);
CVAR_REGISTER(&cv_bot_mimic); CVAR_REGISTER(&cv_bot_mimic);
CVAR_REGISTER(&cv_bot_mimic_yaw_offset); CVAR_REGISTER(&cv_bot_mimic_yaw_offset);
CVAR_REGISTER(&cv_bot_excellent_morale);
#endif #endif
} }
@ -194,6 +196,11 @@ void CCSBot::ResetValues()
m_currentArea = nullptr; m_currentArea = nullptr;
m_lastKnownArea = nullptr; m_lastKnownArea = nullptr;
#ifdef REGAMEDLL_ADD
m_isEnemySniperVisible = false;
m_sawEnemySniperTimer.Invalidate();
#endif
m_avoidFriendTimer.Invalidate(); m_avoidFriendTimer.Invalidate();
m_isFriendInTheWay = false; m_isFriendInTheWay = false;
m_isWaitingBehindFriend = false; m_isWaitingBehindFriend = false;
@ -330,7 +337,7 @@ void CCSBot::ResetValues()
// NOTE: For some reason, this can be called twice when a bot is added. // NOTE: For some reason, this can be called twice when a bot is added.
void CCSBot::SpawnBot() void CCSBot::SpawnBot()
{ {
TheCSBots()->ValidateMapData(); TheCSBots()->LoadNavigationMap();
ResetValues(); ResetValues();
Q_strlcpy(m_name, STRING(pev->netname)); Q_strlcpy(m_name, STRING(pev->netname));

View File

@ -65,6 +65,7 @@ extern cvar_t cv_bot_join_delay;
extern cvar_t cv_bot_freeze; extern cvar_t cv_bot_freeze;
extern cvar_t cv_bot_mimic; extern cvar_t cv_bot_mimic;
extern cvar_t cv_bot_mimic_yaw_offset; extern cvar_t cv_bot_mimic_yaw_offset;
extern cvar_t cv_bot_excellent_morale;
#else #else
extern cvar_t cv_bot_quota_match; extern cvar_t cv_bot_quota_match;
#endif #endif

View File

@ -477,31 +477,24 @@ void CCSBot::StartSaveProcess()
void CCSBot::UpdateSaveProcess() void CCSBot::UpdateSaveProcess()
{ {
char msg[256];
char cmd[128];
char gd[64]{}; char gd[64]{};
GET_GAME_DIR(gd); GET_GAME_DIR(gd);
char filename[MAX_OSPATH]; char filename[MAX_OSPATH];
Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, TheBots->GetNavMapFilename()); Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, TheBots->GetNavMapFilename());
HintMessageToAllPlayers("Saving...");
SaveNavigationMap(filename); SaveNavigationMap(filename);
char msg[256]{};
Q_snprintf(msg, sizeof(msg), "Navigation file '%s' saved.", filename); Q_snprintf(msg, sizeof(msg), "Navigation file '%s' saved.", filename);
HintMessageToAllPlayers(msg); HintMessageToAllPlayers(msg);
CONSOLE_ECHO("%s\n", msg);
hideProgressMeter(); hideProgressMeter();
StartNormalProcess(); StartNormalProcess();
#ifndef REGAMEDLL_FIXES // tell bot manager that the analysis is completed
Q_snprintf(cmd, sizeof(cmd), "map %s\n", STRING(gpGlobals->mapname)); if (TheCSBots())
#else TheCSBots()->AnalysisCompleted();
Q_snprintf(cmd, sizeof(cmd), "changelevel %s\n", STRING(gpGlobals->mapname));
#endif
SERVER_COMMAND(cmd);
} }
void CCSBot::StartNormalProcess() void CCSBot::StartNormalProcess()

View File

@ -231,13 +231,12 @@ bool CCSBotManager::IsOnOffense(CBasePlayer *pPlayer) const
// Invoked when a map has just been loaded // Invoked when a map has just been loaded
void CCSBotManager::ServerActivate() void CCSBotManager::ServerActivate()
{ {
DestroyNavigationMap();
m_isMapDataLoaded = false; m_isMapDataLoaded = false;
m_zoneCount = 0; m_zoneCount = 0;
m_gameScenario = SCENARIO_DEATHMATCH; m_gameScenario = SCENARIO_DEATHMATCH;
ValidateMapData(); LoadNavigationMap();
RestartRound(); RestartRound();
m_isLearningMap = false; m_isLearningMap = false;
@ -591,7 +590,8 @@ void CCSBotManager::ServerCommand(const char *pcmd)
} }
else if (FStrEq(pcmd, "bot_nav_load")) else if (FStrEq(pcmd, "bot_nav_load"))
{ {
ValidateMapData(); m_isMapDataLoaded = false; // force nav reload
LoadNavigationMap();
} }
else if (FStrEq(pcmd, "bot_nav_use_place")) else if (FStrEq(pcmd, "bot_nav_use_place"))
{ {
@ -1144,22 +1144,232 @@ private:
CCSBotManager::Zone *m_zone; CCSBotManager::Zone *m_zone;
}; };
// Search the map entities to determine the game scenario and define important zones. LINK_ENTITY_TO_CLASS(info_spawn_point, CPointEntity, CCSPointEntity)
void CCSBotManager::ValidateMapData()
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()) if (m_isMapDataLoaded || !AreBotsAllowed())
return; return false;
m_isMapDataLoaded = true; 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"); CONSOLE_ECHO("ERROR: Failed to load 'maps/%s.nav' file navigation map!\n", STRING(gpGlobals->mapname));
return;
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;
} }
CONSOLE_ECHO("Navigation map loaded.\n"); if (navStatus != NAV_CANT_ACCESS_FILE)
CONSOLE_ECHO("\tTry regenerating it using the command: bot_nav_analyze\n");
return false;
}
// 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_zoneCount = 0;
m_gameScenario = SCENARIO_DEATHMATCH; m_gameScenario = SCENARIO_DEATHMATCH;
@ -1299,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<CCSBot *>(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<CCSBot *>(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) bool CCSBotManager::AddBot(const BotProfile *profile, BotProfileTeamType team)
{ {
if (!AreBotsAllowed()) if (!AreBotsAllowed())

View File

@ -56,13 +56,16 @@ public:
virtual bool IsImportantPlayer(CBasePlayer *pPlayer) const; // return true if pPlayer is important to scenario (VIP, bomb carrier, etc) virtual bool IsImportantPlayer(CBasePlayer *pPlayer) const; // return true if pPlayer is important to scenario (VIP, bomb carrier, etc)
public: public:
void ValidateMapData(); bool LoadNavigationMap();
void DetermineMapScenario();
void OnFreeEntPrivateData(CBaseEntity *pEntity); void OnFreeEntPrivateData(CBaseEntity *pEntity);
void OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead);
bool IsLearningMap() const { return m_isLearningMap; } bool IsLearningMap() const { return m_isLearningMap; }
void SetLearningMapFlag() { m_isLearningMap = true; } void SetLearningMapFlag() { m_isLearningMap = true; }
bool IsAnalysisRequested() const { return m_isAnalysisRequested; } bool IsAnalysisRequested() const { return m_isAnalysisRequested; }
void RequestAnalysis() { m_isAnalysisRequested = true; } void RequestAnalysis() { m_isAnalysisRequested = true; }
void AckAnalysisRequest() { m_isAnalysisRequested = false; } void AckAnalysisRequest() { m_isAnalysisRequested = false; }
void AnalysisCompleted();
// difficulty levels // difficulty levels
static BotDifficultyType GetDifficultyLevel() static BotDifficultyType GetDifficultyLevel()
@ -269,3 +272,4 @@ inline bool AreBotsAllowed()
} }
void PrintAllEntities(); void PrintAllEntities();
void GenerateSpawnPointsFromNavData();

View File

@ -255,7 +255,7 @@ void CCSBot::Update()
Vector dir = m_spotEncounter->path.to - m_spotEncounter->path.from; Vector dir = m_spotEncounter->path.to - m_spotEncounter->path.from;
float length = dir.NormalizeInPlace(); 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); 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(); UpdateReactionQueue();
// "threat" may be the same as our current enemy // "threat" may be the same as our current enemy
CBasePlayer *threat = GetRecognizedEnemy(); CBasePlayer* threat = GetRecognizedEnemy();
if (threat) if (threat)
{ {
// adjust our personal "safe" time // adjust our personal "safe" time
@ -592,6 +592,10 @@ void CCSBot::Update()
SecondaryAttack(); SecondaryAttack();
} }
#ifdef REGAMEDLL_ADD
if (!IsBlind())
{
#endif
// check encounter spots // check encounter spots
UpdatePeripheralVision(); UpdatePeripheralVision();
@ -601,11 +605,24 @@ void CCSBot::Update()
GetChatter()->SpottedBomber(GetBomber()); 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()) if (CanSeeLooseBomb())
{ {
GetChatter()->SpottedLooseBomb(TheCSBots()->GetLooseBomb()); GetChatter()->SpottedLooseBomb(TheCSBots()->GetLooseBomb());
} }
#ifdef REGAMEDLL_ADD
}
#endif
// Scenario interrupts // Scenario interrupts
switch (TheCSBots()->GetScenario()) switch (TheCSBots()->GetScenario())
{ {

View File

@ -697,6 +697,13 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
m_closestVisibleFriend = nullptr; m_closestVisibleFriend = nullptr;
m_closestVisibleHumanFriend = 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 closeFriendRange = 99999999999.9f;
float closeHumanFriendRange = 99999999999.9f; float closeHumanFriendRange = 99999999999.9f;
@ -789,6 +796,53 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
Vector d = pev->origin - pPlayer->pev->origin; Vector d = pev->origin - pPlayer->pev->origin;
float distSq = d.LengthSquared(); float distSq = d.LengthSquared();
#ifdef REGAMEDLL_ADD
CBasePlayerWeapon *pCurrentWeapon = static_cast<CBasePlayerWeapon *>(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 // maintain set of visible threats, sorted by increasing distance
if (threatCount == 0) if (threatCount == 0)
{ {
@ -950,6 +1004,23 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
{ {
return currentThreat; 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 #endif
// otherwise, find the closest threat that without using shield // otherwise, find the closest threat that without using shield

View File

@ -462,17 +462,26 @@ void BuyState::OnUpdate(CCSBot *me)
me->ClientCommand("vesthelm"); me->ClientCommand("vesthelm");
me->ClientCommand("vest"); me->ClientCommand("vest");
// pistols - if we have no preferred pistol, buy at random if (TheCSBots()->AllowPistols()
if (TheCSBots()->AllowPistols() && !me->GetProfile()->HasPistolPreference()) #ifndef REGAMEDLL_FIXES
&& !me->GetProfile()->HasPistolPreference()
#endif
)
{ {
if (m_buyPistol) if (m_buyPistol)
{ {
#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); int which = RANDOM_LONG(0, MAX_BUY_WEAPON_SECONDARY - 1);
if (me->m_iTeam == TERRORIST) if (me->m_iTeam == TERRORIST)
me->ClientCommand(secondaryWeaponBuyInfoT[which].buyAlias); me->ClientCommand(secondaryWeaponBuyInfoT[which].buyAlias);
else else
me->ClientCommand(secondaryWeaponBuyInfoCT[which].buyAlias); me->ClientCommand(secondaryWeaponBuyInfoCT[which].buyAlias);
}
// only buy one pistol // only buy one pistol
m_buyPistol = false; m_buyPistol = false;

View File

@ -841,6 +841,12 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
char *pszConsoleFormat = nullptr; char *pszConsoleFormat = nullptr;
bool consoleUsesPlaceName = false; 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 // team only
if (teamonly) if (teamonly)
{ {
@ -995,7 +1001,13 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
if (gpGlobals->deathmatch != 0.0f && CSGameRules()->m_VoiceGameMgr.PlayerHasBlockedPlayer(pReceiver, pPlayer)) if (gpGlobals->deathmatch != 0.0f && CSGameRules()->m_VoiceGameMgr.PlayerHasBlockedPlayer(pReceiver, pPlayer))
continue; 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; continue;
if ( if (
@ -1008,7 +1020,13 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
continue; 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) || pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_NONE)
{ {
MESSAGE_BEGIN(MSG_ONE, gmsgSayText, nullptr, pReceiver->pev); MESSAGE_BEGIN(MSG_ONE, gmsgSayText, nullptr, pReceiver->pev);
@ -3815,9 +3833,6 @@ void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
#ifdef REGAMEDLL_ADD #ifdef REGAMEDLL_ADD
CSGameRules()->ServerActivate(); CSGameRules()->ServerActivate();
if (location_area_info.value)
LoadNavigationMap();
#endif #endif
} }

View File

@ -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_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_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 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 free_armor = { "mp_free_armor", "0", 0, 0.0f, nullptr };
cvar_t teamflash = { "mp_team_flash", "1", 0, 1.0f, nullptr }; cvar_t teamflash = { "mp_team_flash", "1", 0, 1.0f, nullptr };
cvar_t allchat = { "sv_allchat", "0", 0, 0.0f, nullptr }; cvar_t allchat = { "sv_allchat", "0", 0, 0.0f, nullptr };
@ -171,6 +172,7 @@ 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 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_duck = { "mp_freezetime_duck", "1", 0, 1.0f, nullptr };
cvar_t freezetime_jump = { "mp_freezetime_jump", "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 };
@ -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 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 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() void GameDLL_Version_f()
{ {
if (Q_stricmp(CMD_ARGV(1), "version") != 0) 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_give_player_knife);
CVAR_REGISTER(&t_default_weapons_secondary); CVAR_REGISTER(&t_default_weapons_secondary);
CVAR_REGISTER(&t_default_weapons_primary); CVAR_REGISTER(&t_default_weapons_primary);
CVAR_REGISTER(&default_weapons_random);
CVAR_REGISTER(&free_armor); CVAR_REGISTER(&free_armor);
CVAR_REGISTER(&teamflash); CVAR_REGISTER(&teamflash);
CVAR_REGISTER(&allchat); CVAR_REGISTER(&allchat);
@ -449,6 +463,7 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&freezetime_duck); CVAR_REGISTER(&freezetime_duck);
CVAR_REGISTER(&freezetime_jump); CVAR_REGISTER(&freezetime_jump);
CVAR_REGISTER(&jump_height);
CVAR_REGISTER(&defuser_allocation); CVAR_REGISTER(&defuser_allocation);
CVAR_REGISTER(&location_area_info); CVAR_REGISTER(&location_area_info);
CVAR_REGISTER(&chat_loc_fallback); CVAR_REGISTER(&chat_loc_fallback);
@ -459,9 +474,20 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&vote_flags); CVAR_REGISTER(&vote_flags);
CVAR_REGISTER(&votemap_min_time); CVAR_REGISTER(&votemap_min_time);
CVAR_REGISTER(&randomspawn);
CVAR_REGISTER(&cv_bot_enable); CVAR_REGISTER(&cv_bot_enable);
CVAR_REGISTER(&cv_hostage_ai_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 // print version
CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n");

View File

@ -186,6 +186,7 @@ extern cvar_t t_default_grenades;
extern cvar_t t_give_player_knife; extern cvar_t t_give_player_knife;
extern cvar_t t_default_weapons_secondary; extern cvar_t t_default_weapons_secondary;
extern cvar_t t_default_weapons_primary; extern cvar_t t_default_weapons_primary;
extern cvar_t default_weapons_random;
extern cvar_t free_armor; extern cvar_t free_armor;
extern cvar_t teamflash; extern cvar_t teamflash;
extern cvar_t allchat; extern cvar_t allchat;
@ -200,6 +201,7 @@ extern cvar_t deathmsg_flags;
extern cvar_t assist_damage_threshold; extern cvar_t assist_damage_threshold;
extern cvar_t freezetime_duck; extern cvar_t freezetime_duck;
extern cvar_t freezetime_jump; extern cvar_t freezetime_jump;
extern cvar_t jump_height;
extern cvar_t defuser_allocation; extern cvar_t defuser_allocation;
extern cvar_t location_area_info; extern cvar_t location_area_info;
extern cvar_t chat_loc_fallback; 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 ammo_respawn_time;
extern cvar_t vote_flags; extern cvar_t vote_flags;
extern cvar_t votemap_min_time; 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 #endif
@ -215,4 +224,6 @@ extern cvar_t scoreboard_showmoney;
extern cvar_t scoreboard_showhealth; extern cvar_t scoreboard_showhealth;
extern cvar_t scoreboard_showdefkit; extern cvar_t scoreboard_showdefkit;
void GameDLLInit(); void GameDLLInit();

View File

@ -1170,6 +1170,12 @@ void CGrenade::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTy
if (!m_bIsC4) if (!m_bIsC4)
return; 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. // TODO: We must be sure that the activator is a player.
CBasePlayer *pPlayer = GetClassPtr<CCSPlayer>((CBasePlayer *)pActivator->pev); CBasePlayer *pPlayer = GetClassPtr<CCSPlayer>((CBasePlayer *)pActivator->pev);
@ -1503,6 +1509,13 @@ void CGrenade::C4Think()
{ {
DefuseBombEnd(pPlayer, false); 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 else
{ {

View File

@ -656,8 +656,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(CleanUpMap)()
#endif #endif
// Remove grenades and C4 // Remove grenades and C4
const int grenadesRemoveCount = 20; UTIL_RemoveOther("grenade");
UTIL_RemoveOther("grenade", grenadesRemoveCount);
#ifndef REGAMEDLL_FIXES #ifndef REGAMEDLL_FIXES
// Remove defuse kit // Remove defuse kit
@ -1817,6 +1816,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)()
if (!UTIL_IsValidPlayer(pPlayer)) if (!UTIL_IsValidPlayer(pPlayer))
continue; continue;
#ifdef REGAMEDLL_FIXES
if (!pPlayer->IsBot())
pPlayer->ForceClientDllUpdate();
#endif
pPlayer->Reset(); pPlayer->Reset();
} }
@ -3246,19 +3250,6 @@ void CHalfLifeMultiplay::CareerRestart()
} }
m_bSkipSpawn = false; 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() BOOL CHalfLifeMultiplay::IsMultiplayer()
@ -4160,7 +4151,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim,
pVictim->CSPlayer()->m_iNumKilledByUnanswered[iPlayerIndexKiller - 1]++; pVictim->CSPlayer()->m_iNumKilledByUnanswered[iPlayerIndexKiller - 1]++;
} }
} }
#ifdef REGAMEDLL_ADD
if (static_cast<int>(logkills.value))
#endif
{
// Did he kill himself? // Did he kill himself?
if (pVictim->pev == pevKiller) if (pVictim->pev == pevKiller)
{ {
@ -4184,6 +4178,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim,
UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), 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); GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name);
} }
}
// TODO: It is called in CBasePlayer::Killed too, most likely, // TODO: It is called in CBasePlayer::Killed too, most likely,
// an unnecessary call. (Need investigate) // an unnecessary call. (Need investigate)

View File

@ -115,6 +115,57 @@ void CBasePlayer::SendItemStatus()
MESSAGE_END(); 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<int>(playerid_showhealth.value);
int fieldType = static_cast<int>(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 *GetCSModelName(int item_id)
{ {
const char *modelName = nullptr; const char *modelName = nullptr;
@ -1182,7 +1233,7 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva
if (!ShouldDoLargeFlinch(m_LastHitGroup, iGunType)) if (!ShouldDoLargeFlinch(m_LastHitGroup, iGunType))
{ {
m_flVelocityModifier = 0.5f; TakeDamageImpulse(pAttack, 0.0f, 0.5f);
if (m_LastHitGroup == HITGROUP_HEAD) if (m_LastHitGroup == HITGROUP_HEAD)
m_bHighDamage = (flDamage > 60); m_bHighDamage = (flDamage > 60);
@ -1195,10 +1246,13 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva
{ {
if (pev->velocity.Length() < 300) if (pev->velocity.Length() < 300)
{ {
Vector attack_velocity = (pev->origin - pAttack->pev->origin).Normalize() * 170; #ifdef REGAMEDLL_ADD
pev->velocity = pev->velocity + attack_velocity; float knockbackValue = knockback.value;
#else
float knockbackValue = 170;
#endif
m_flVelocityModifier = 0.65f; TakeDamageImpulse(pAttack, knockbackValue, 0.65f);
} }
SetAnimation(PLAYER_LARGE_FLINCH); SetAnimation(PLAYER_LARGE_FLINCH);
@ -1487,7 +1541,7 @@ void CBasePlayer::PackDeadPlayerItems()
{ {
DropShield(); DropShield();
#ifdef REGAMEDLL_ADD #ifdef REGAMEDLL_ADD
if(iPackGun != GR_PLR_DROP_GUN_ALL) if (iPackGun != GR_PLR_DROP_GUN_ALL)
#endif #endif
{ {
bSkipPrimSec = true; bSkipPrimSec = true;
@ -1644,6 +1698,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)()
// Give default secondary equipment // Give default secondary equipment
{ {
char *secondaryString = NULL; char *secondaryString = NULL;
int secondaryCount = 0;
const int MAX_SECONDARY = 13; // x2 + 1
WeaponInfoStruct *secondaryWeaponInfoArray[MAX_SECONDARY];
if (m_iTeam == CT) if (m_iTeam == CT)
secondaryString = ct_default_weapons_secondary.string; secondaryString = ct_default_weapons_secondary.string;
else if (m_iTeam == TERRORIST) else if (m_iTeam == TERRORIST)
@ -1665,18 +1723,34 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)()
if (weaponInfo) { if (weaponInfo) {
const auto iItemID = GetItemIdByWeaponId(weaponInfo->id); const auto iItemID = GetItemIdByWeaponId(weaponInfo->id);
if (iItemID != ITEM_NONE && !HasRestrictItem(iItemID, ITEM_TYPE_EQUIPPED) && IsSecondaryWeapon(iItemID)) { if (iItemID != ITEM_NONE && !HasRestrictItem(iItemID, ITEM_TYPE_EQUIPPED) && IsSecondaryWeapon(iItemID)) {
if (default_weapons_random.value != 0.0f) {
if (secondaryCount < MAX_SECONDARY) {
secondaryWeaponInfoArray[secondaryCount++] = weaponInfo;
}
}
else {
GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName); GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName);
} }
} }
}
secondaryString = SharedParse(secondaryString); 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 // Give default primary equipment
{ {
char *primaryString = NULL; char *primaryString = NULL;
int primaryCount = 0;
const int MAX_PRIMARY = 39; // x2 + 1
WeaponInfoStruct *primaryWeaponInfoArray[MAX_PRIMARY];
if (m_iTeam == CT) if (m_iTeam == CT)
primaryString = ct_default_weapons_primary.string; primaryString = ct_default_weapons_primary.string;
@ -1699,12 +1773,25 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)()
if (weaponInfo) { if (weaponInfo) {
const auto iItemID = GetItemIdByWeaponId(weaponInfo->id); const auto iItemID = GetItemIdByWeaponId(weaponInfo->id);
if (iItemID != ITEM_NONE && !HasRestrictItem(iItemID, ITEM_TYPE_EQUIPPED) && IsPrimaryWeapon(iItemID)) { if (iItemID != ITEM_NONE && !HasRestrictItem(iItemID, ITEM_TYPE_EQUIPPED) && IsPrimaryWeapon(iItemID)) {
if (default_weapons_random.value != 0.0f) {
if (primaryCount < MAX_PRIMARY) {
primaryWeaponInfoArray[primaryCount++] = weaponInfo;
}
}
else {
GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName); GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName);
} }
} }
}
primaryString = SharedParse(primaryString); 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);
}
} }
} }
@ -2186,7 +2273,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib)
{ {
CBasePlayer *pAttacker = CBasePlayer::Instance(pevAttacker); 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()) if (pAttacker->HasShield())
killerHasShield = true; killerHasShield = true;
@ -5338,18 +5425,25 @@ pt_end:
} }
// checks if the spot is clear of players // 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)) if (!pSpot->IsTriggered(pPlayer))
return FALSE; return FALSE;
CBaseEntity *pEntity = nullptr; 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 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 FALSE;
} }
}
return TRUE; return TRUE;
} }
@ -5373,8 +5467,24 @@ bool CBasePlayer::SelectSpawnSpot(const char *pEntClassName, CBaseEntity *&pSpot
{ {
if (pSpot) if (pSpot)
{ {
#ifdef REGAMEDLL_ADD
if (FClassnameIs(pSpot->edict(), "info_spawn_point"))
{
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 // check if pSpot is valid
if (IsSpawnPointValid(this, pSpot)) if (IsSpawnPointValid(this, pSpot, MAX_PLAYER_USE_RADIUS))
{ {
if (pSpot->pev->origin == Vector(0, 0, 0)) if (pSpot->pev->origin == Vector(0, 0, 0))
{ {
@ -5386,6 +5496,7 @@ bool CBasePlayer::SelectSpawnSpot(const char *pEntClassName, CBaseEntity *&pSpot
return true; return true;
} }
} }
}
// increment pSpot // increment pSpot
pSpot = UTIL_FindEntityByClassname(pSpot, pEntClassName); pSpot = UTIL_FindEntityByClassname(pSpot, pEntClassName);
@ -5441,6 +5552,24 @@ edict_t *EXT_FUNC CBasePlayer::__API_HOOK(EntSelectSpawnPoint)()
if (!FNullEnt(pSpot)) if (!FNullEnt(pSpot))
goto ReturnSpot; 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 // VIP spawn point
else if (g_pGameRules->IsDeathmatch() && m_bIsVIP) else if (g_pGameRules->IsDeathmatch() && m_bIsVIP)
{ {
@ -5468,6 +5597,9 @@ CTSpawn:
// The terrorist spawn points // The terrorist spawn points
else if (g_pGameRules->IsDeathmatch() && m_iTeam == TERRORIST) else if (g_pGameRules->IsDeathmatch() && m_iTeam == TERRORIST)
{ {
#ifdef REGAMEDLL_ADD
TSpawn:
#endif
pSpot = g_pLastTerroristSpawn; pSpot = g_pLastTerroristSpawn;
if (SelectSpawnSpot("info_player_deathmatch", pSpot)) if (SelectSpawnSpot("info_player_deathmatch", pSpot))
@ -8037,7 +8169,9 @@ void CBasePlayer::InitStatusBar()
m_SbarString0[0] = '\0'; 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]; int newSBarState[SBAR_END];
char sbuf0[MAX_SBAR_STRING]; char sbuf0[MAX_SBAR_STRING];
@ -8073,11 +8207,19 @@ void CBasePlayer::UpdateStatusBar()
if (sameTeam || GetObserverMode() != OBS_NONE) if (sameTeam || GetObserverMode() != OBS_NONE)
{ {
if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE) if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE)
#ifndef REGAMEDLL_ADD
Q_strlcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%"); Q_strlcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%");
#else
Q_strlcpy(sbuf0, GetPlayerIdString(sameTeam));
#endif
else else
Q_strlcpy(sbuf0, " "); Q_strlcpy(sbuf0, " ");
#ifdef REGAMEDLL_ADD
if (static_cast<int>(playerid_showhealth.value) != PLAYERID_FIELD_NONE)
#endif
{
newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100); newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100);
}
if (!(m_flDisplayHistory & DHF_FRIEND_SEEN) && !(pev->flags & FL_SPECTATOR)) if (!(m_flDisplayHistory & DHF_FRIEND_SEEN) && !(pev->flags & FL_SPECTATOR))
{ {
@ -8088,10 +8230,18 @@ void CBasePlayer::UpdateStatusBar()
else if (GetObserverMode() == OBS_NONE) else if (GetObserverMode() == OBS_NONE)
{ {
if (playerid.value != PLAYERID_MODE_TEAMONLY && playerid.value != PLAYERID_MODE_OFF) if (playerid.value != PLAYERID_MODE_TEAMONLY && playerid.value != PLAYERID_MODE_OFF)
#ifndef REGAMEDLL_ADD
Q_strlcpy(sbuf0, "1 %c1: %p2"); Q_strlcpy(sbuf0, "1 %c1: %p2");
#else
Q_strlcpy(sbuf0, GetPlayerIdString(sameTeam));
#endif
else else
Q_strlcpy(sbuf0, " "); Q_strlcpy(sbuf0, " ");
#ifdef REGAMEDLL_ADD
if (static_cast<int>(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)) if (!(m_flDisplayHistory & DHF_ENEMY_SEEN))
{ {
m_flDisplayHistory |= DHF_ENEMY_SEEN; m_flDisplayHistory |= DHF_ENEMY_SEEN;
@ -10116,7 +10266,11 @@ bool CBasePlayer::IsObservingPlayer(CBasePlayer *pPlayer)
void CBasePlayer::UpdateLocation(bool forceUpdate) 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) if (!forceUpdate && m_flLastUpdateTime >= gpGlobals->time + 2.0f)
#endif
return; return;
const char *placeName = nullptr; const char *placeName = nullptr;
@ -10716,6 +10870,17 @@ bool CBasePlayer::Kill()
return true; 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 const usercmd_t *CBasePlayer::GetLastUserCommand() const
{ {
#ifdef REGAMEDLL_API #ifdef REGAMEDLL_API

View File

@ -450,6 +450,8 @@ public:
void PlayerDeathThink_OrigFunc(); void PlayerDeathThink_OrigFunc();
void Observer_Think_OrigFunc(); void Observer_Think_OrigFunc();
void RemoveAllItems_OrigFunc(BOOL removeSuit); void RemoveAllItems_OrigFunc(BOOL removeSuit);
void UpdateStatusBar_OrigFunc();
void TakeDamageImpulse_OrigFunc(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier);
CCSPlayer *CSPlayer() const; CCSPlayer *CSPlayer() const;
#endif // REGAMEDLL_API #endif // REGAMEDLL_API
@ -658,6 +660,7 @@ public:
void UseEmpty(); void UseEmpty();
void DropIdlePlayer(const char *reason); void DropIdlePlayer(const char *reason);
bool Kill(); bool Kill();
void TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier);
// templates // templates
template<typename T = CBasePlayerItem, typename Functor> template<typename T = CBasePlayerItem, typename Functor>
@ -1044,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); 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); bool CanSeeUseable(CBasePlayer *me, CBaseEntity *pEntity);
void FixPlayerCrouchStuck(edict_t *pPlayer); void FixPlayerCrouchStuck(edict_t *pPlayer);
BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot); BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot, float fRadius);
CBaseEntity *FindEntityForward(CBaseEntity *pMe); CBaseEntity *FindEntityForward(CBaseEntity *pMe);
real_t GetPlayerPitch(const edict_t *pEdict); real_t GetPlayerPitch(const edict_t *pEdict);
real_t GetPlayerYaw(const edict_t *pEdict); real_t GetPlayerYaw(const edict_t *pEdict);

View File

@ -30,16 +30,18 @@
#define QSTRING_DEFINE #define QSTRING_DEFINE
constexpr unsigned int iStringNull = {0};
// Quake string (helper class) // Quake string (helper class)
class QString final class QString final
{ {
public: public:
#if XASH_64BIT
using qstring_t = int;
#else
using qstring_t = unsigned int; using qstring_t = unsigned int;
#endif
QString(): m_string(iStringNull) {}; QString();
QString(qstring_t string): m_string(string) {}; QString(qstring_t string);
bool IsNull() const; bool IsNull() const;
bool IsNullOrEmpty() const; bool IsNullOrEmpty() const;
@ -52,13 +54,15 @@ public:
bool operator==(const char *pszString) const; bool operator==(const char *pszString) const;
operator const char *() const; operator const char *() const;
operator unsigned int() const; operator qstring_t() const;
const char *str() const; const char *str() const;
private: private:
qstring_t m_string; qstring_t m_string;
}; };
constexpr QString::qstring_t iStringNull = {0};
#ifdef USE_QSTRING #ifdef USE_QSTRING
#define string_t QString #define string_t QString
#endif #endif
@ -70,10 +74,25 @@ private:
extern globalvars_t *gpGlobals; extern globalvars_t *gpGlobals;
#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (unsigned int)(offset))) #define STRING(offset) ((const char *)(gpGlobals->pStringBase + (QString::qstring_t)(offset)))
#define MAKE_STRING(str) ((unsigned int)(str) - (unsigned int)(STRING(0))) #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 // Inlines
inline QString::QString(): m_string(iStringNull) {}
inline QString::QString(qstring_t string): m_string(string) {}
inline bool QString::IsNull() const inline bool QString::IsNull() const
{ {
return m_string == iStringNull; return m_string == iStringNull;
@ -115,7 +134,7 @@ inline QString::operator const char *() const
return str(); return str();
} }
inline QString::operator unsigned int() const inline QString::operator qstring_t() const
{ {
return m_string; return m_string;
} }

View File

@ -1464,7 +1464,7 @@ void UTIL_Remove(CBaseEntity *pEntity)
pEntity->pev->targetname = 0; 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)) if (!pent || pent->free || (pent->v.flags & FL_KILLME))
return FALSE; return FALSE;

View File

@ -618,11 +618,17 @@ void CBasePlayerItem::DefaultTouch(CBaseEntity *pOther)
CBasePlayer *pPlayer = static_cast<CBasePlayer *>(pOther); CBasePlayer *pPlayer = static_cast<CBasePlayer *>(pOther);
if (pPlayer->m_bIsVIP if (pPlayer->m_bIsVIP
&& m_iId != WEAPON_USP &&
#ifndef REGAMEDLL_FIXES
m_iId != WEAPON_USP
&& m_iId != WEAPON_GLOCK18 && m_iId != WEAPON_GLOCK18
&& m_iId != WEAPON_P228 && m_iId != WEAPON_P228
&& m_iId != WEAPON_DEAGLE && m_iId != WEAPON_DEAGLE
&& m_iId != WEAPON_KNIFE) && m_iId != WEAPON_KNIFE
#else
!IsSecondaryWeapon(m_iId)
#endif
)
{ {
return; return;
} }

View File

@ -3143,3 +3143,7 @@
@PointClass base(BaseCommand) size(-8 -8 -8, 8 8 8) = point_clientcommand : "It issues commands to the client console" @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"
[
]

View File

@ -71,6 +71,13 @@ enum NavAttributeType
NAV_NO_JUMP = 0x08, // inhibit discontinuity jumping NAV_NO_JUMP = 0x08, // inhibit discontinuity jumping
}; };
enum NavNotifyDestroyType
{
NAV_NOTIFY_DESTROY_AREA,
NAV_NOTIFY_DESTROY_SPOT,
NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER
};
enum NavDirType enum NavDirType
{ {
NORTH = 0, NORTH = 0,

View File

@ -72,17 +72,29 @@ NOXREF void buildGoodSizedList()
void DestroyHidingSpots() void DestroyHidingSpots()
{ {
// remove all hiding spot references from the nav areas
for (auto area : TheNavAreaList)
area->m_hidingSpotList.clear();
HidingSpot::m_nextID = 0;
// free all the HidingSpots // free all the HidingSpots
for (auto spot : TheHidingSpotList) for (HidingSpot *spot : TheHidingSpotList)
{
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_SPOT, spot);
delete spot; delete spot;
}
TheHidingSpotList.clear(); TheHidingSpotList.clear();
// remove all hiding spot references from the nav areas
for (CNavArea *area : TheNavAreaList)
{
area->m_hidingSpotList.clear();
// free all the HidingSpots in area
for (SpotEncounter &e : area->m_spotEncounterList)
e.spotList.clear();
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER, area);
area->m_spotEncounterList.clear();
}
HidingSpot::m_nextID = 0;
} }
// For use when loading from a file // For use when loading from a file
@ -249,6 +261,9 @@ CNavArea::CNavArea(CNavNode *nwNode, class CNavNode *neNode, class CNavNode *seN
// Destructor // Destructor
CNavArea::~CNavArea() 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 we are resetting the system, don't bother cleaning up - all areas are being destroyed
if (m_isReset) if (m_isReset)
return; return;
@ -344,6 +359,7 @@ void CNavArea::FinishMerge(CNavArea *adjArea)
// remove subsumed adjacent area // remove subsumed adjacent area
TheNavAreaList.remove(adjArea); TheNavAreaList.remove(adjArea);
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this);
delete adjArea; delete adjArea;
} }
@ -536,6 +552,7 @@ bool CNavArea::SplitEdit(bool splitAlongX, float splitEdge, CNavArea **outAlpha,
// remove original area // remove original area
TheNavAreaList.remove(this); TheNavAreaList.remove(this);
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this);
delete this; delete this;
return true; return true;
@ -868,6 +885,7 @@ bool CNavArea::MergeEdit(CNavArea *adj)
// remove subsumed adjacent area // remove subsumed adjacent area
TheNavAreaList.remove(adj); TheNavAreaList.remove(adj);
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, adj);
delete adj; delete adj;
return true; return true;
@ -900,6 +918,9 @@ void DestroyNavigationMap()
{ {
CNavArea::m_isReset = true; CNavArea::m_isReset = true;
// destroy all hiding spots
DestroyHidingSpots();
// remove each element of the list and delete them // remove each element of the list and delete them
while (!TheNavAreaList.empty()) while (!TheNavAreaList.empty())
{ {
@ -913,8 +934,8 @@ void DestroyNavigationMap()
// destroy ladder representations // destroy ladder representations
DestroyLadders(); DestroyLadders();
// destroy all hiding spots // cleanup from previous analysis
DestroyHidingSpots(); CleanupApproachAreaAnalysisPrep();
// destroy navigation nodes created during map learning // destroy navigation nodes created during map learning
CNavNode *node, *next; CNavNode *node, *next;
@ -1772,6 +1793,13 @@ void GenerateNavigationAreaMesh()
break; 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 extent;
extent.lo.x = 9999999999.9f; extent.lo.x = 9999999999.9f;
extent.lo.y = 9999999999.9f; extent.lo.y = 9999999999.9f;
@ -2828,6 +2856,22 @@ SpotEncounter *CNavArea::GetSpotEncounter(const CNavArea *from, const CNavArea *
return nullptr; 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 // Add spot encounter data when moving from area to area
void CNavArea::AddSpotEncounters(const class CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir) void CNavArea::AddSpotEncounters(const class CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir)
{ {
@ -3968,6 +4012,7 @@ void EditNavAreas(NavEditCmdType cmd)
case EDIT_DELETE: case EDIT_DELETE:
EMIT_SOUND_DYN(ENT(pLocalPlayer->pev), CHAN_ITEM, "buttons/blip1.wav", 1, ATTN_NORM, 0, 100); EMIT_SOUND_DYN(ENT(pLocalPlayer->pev), CHAN_ITEM, "buttons/blip1.wav", 1, ATTN_NORM, 0, 100);
TheNavAreaList.remove(area); TheNavAreaList.remove(area);
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, area);
delete area; delete area;
return; return;
case EDIT_ATTRIB_CROUCH: 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 // Add an area to the grid
void CNavAreaGrid::AddNavArea(CNavArea *area) 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 // add to grid
const Extent *extent = area->GetExtent(); const Extent *extent = area->GetExtent();

View File

@ -273,6 +273,7 @@ public:
void ComputeHidingSpots(); // analyze local area neighborhood to find "hiding spots" in this area - for map learning 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 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 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 void ComputeSpotEncounters(); // compute spot encounter data - for map learning
@ -345,6 +346,25 @@ public:
void AddLadderUp(CNavLadder *ladder) { m_ladder[LADDER_UP].push_back(ladder); } void AddLadderUp(CNavLadder *ladder) { m_ladder[LADDER_UP].push_back(ladder); }
void AddLadderDown(CNavLadder *ladder) { m_ladder[LADDER_DOWN].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: private:
friend void ConnectGeneratedAreas(); friend void ConnectGeneratedAreas();
friend void MergeGeneratedAreas(); friend void MergeGeneratedAreas();

View File

@ -623,6 +623,13 @@ bool SaveNavigationMap(const char *filename)
area->Save(fd, version); area->Save(fd, version);
} }
// Ensure that all data is flushed to disk
#ifdef WIN32
_commit(fd);
#else
fsync(fd);
#endif
_close(fd); _close(fd);
return true; return true;
} }
@ -839,6 +846,11 @@ NavErrorType LoadNavigationMap()
unsigned int count; unsigned int count;
result = navFile.Read(&count, sizeof(unsigned int)); result = navFile.Read(&count, sizeof(unsigned int));
if (count == 0)
{
return NAV_INVALID_FILE;
}
Extent extent; Extent extent;
extent.lo.x = 9999999999.9f; extent.lo.x = 9999999999.9f;
extent.lo.y = 9999999999.9f; extent.lo.y = 9999999999.9f;

View File

@ -932,7 +932,7 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>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)</PreprocessorDefinitions> <PreprocessorDefinitions>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)</PreprocessorDefinitions>
<FloatingPointModel>Fast</FloatingPointModel> <FloatingPointModel>Precise</FloatingPointModel>
<AdditionalOptions>/arch:IA32 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/arch:IA32 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="'$(PlatformToolset)' == 'v140_xp' OR '$(PlatformToolset)' == 'v141_xp'">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions Condition="'$(PlatformToolset)' == 'v140_xp' OR '$(PlatformToolset)' == 'v141_xp'">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -969,7 +969,7 @@
<Optimization>Full</Optimization> <Optimization>Full</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>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)</PreprocessorDefinitions> <PreprocessorDefinitions>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)</PreprocessorDefinitions>
<FloatingPointModel>Fast</FloatingPointModel> <FloatingPointModel>Precise</FloatingPointModel>
<AdditionalOptions>/arch:IA32 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/arch:IA32 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="'$(PlatformToolset)' == 'v140_xp' OR '$(PlatformToolset)' == 'v141_xp'">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions Condition="'$(PlatformToolset)' == 'v140_xp' OR '$(PlatformToolset)' == 'v141_xp'">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -1102,6 +1102,7 @@
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>

View File

@ -641,9 +641,184 @@ void PM_FixupGravityVelocity()
pmove->velocity[2] -= (pmove->movevars->gravity * pmove->frametime * ent_gravity * 0.5); pmove->velocity[2] -= (pmove->movevars->gravity * pmove->frametime * ent_gravity * 0.5);
PM_CheckVelocity(); 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() int PM_FlyMove()
{ {
#ifdef REGAMEDLL_ADD
if (flymove_method.value)
return PM_FlyMove_New();
#endif
int bumpcount, numbumps; int bumpcount, numbumps;
vec3_t dir; vec3_t dir;
float d; float d;
@ -886,6 +1061,18 @@ void PM_WalkMove()
{ {
real_t flRatio = (100 - pmove->fuser2 * 0.001 * 19) * 0.01; 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[0] *= flRatio;
pmove->velocity[1] *= flRatio; pmove->velocity[1] *= flRatio;
} }
@ -2429,13 +2616,18 @@ inline real_t PM_JumpHeight(bool longjump)
#ifdef REGAMEDLL_API #ifdef REGAMEDLL_API
if (longjump) if (longjump)
{ {
if(pmoveplayer->m_flLongJumpHeight > 0.0) if (pmoveplayer->m_flLongJumpHeight > 0.0)
return pmoveplayer->m_flLongJumpHeight; return pmoveplayer->m_flLongJumpHeight;
} }
else if (pmoveplayer->m_flJumpHeight > 0.0) else if (pmoveplayer->m_flJumpHeight > 0.0)
return pmoveplayer->m_flJumpHeight; return pmoveplayer->m_flJumpHeight;
#endif #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)); return Q_sqrt(2.0 * 800.0f * (longjump ? 56.0f : 45.0f));
#endif
} }
LINK_HOOK_VOID_CHAIN2(PM_Jump) LINK_HOOK_VOID_CHAIN2(PM_Jump)
@ -2606,6 +2798,7 @@ void EXT_FUNC __API_HOOK(PM_Jump)()
{ {
// NOTE: don't do it in .f (float) // NOTE: don't do it in .f (float)
real_t flRatio = (100.0 - pmove->fuser2 * 0.001 * 19.0) * 0.01; real_t flRatio = (100.0 - pmove->fuser2 * 0.001 * 19.0) * 0.01;
pmove->velocity[2] *= flRatio; pmove->velocity[2] *= flRatio;
} }

269
regamedll/public/build.h Normal file
View File

@ -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 <http://unlicense.org/>
*/
#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 <TargetConditionals.h>
#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 <sys/param.h>
#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

View File

@ -117,6 +117,8 @@ public:
virtual void Reset(); virtual void Reset();
virtual void OnSpawnEquip(bool addDefault = true, bool equipGame = true); virtual void OnSpawnEquip(bool addDefault = true, bool equipGame = true);
virtual void SetScoreboardAttributes(CBasePlayer *destination = nullptr); 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; bool IsPlayerDominated(int iPlayerIndex) const;
void SetPlayerDominated(CBasePlayer *pPlayer, bool bDominated); void SetPlayerDominated(CBasePlayer *pPlayer, bool bDominated);

View File

@ -38,7 +38,7 @@
#include <API/CSInterfaces.h> #include <API/CSInterfaces.h>
#define REGAMEDLL_API_VERSION_MAJOR 5 #define REGAMEDLL_API_VERSION_MAJOR 5
#define REGAMEDLL_API_VERSION_MINOR 28 #define REGAMEDLL_API_VERSION_MINOR 30
// CBasePlayer::Spawn hook // CBasePlayer::Spawn hook
typedef IHookChainClass<void, class CBasePlayer> IReGameHook_CBasePlayer_Spawn; typedef IHookChainClass<void, class CBasePlayer> IReGameHook_CBasePlayer_Spawn;
@ -628,6 +628,14 @@ typedef IHookChainRegistryClass<void, class CBasePlayer> IReGameHookRegistry_CBa
typedef IHookChainClass<void, class CBasePlayer, BOOL> IReGameHook_CBasePlayer_RemoveAllItems; typedef IHookChainClass<void, class CBasePlayer, BOOL> IReGameHook_CBasePlayer_RemoveAllItems;
typedef IHookChainRegistryClass<void, class CBasePlayer, BOOL> IReGameHookRegistry_CBasePlayer_RemoveAllItems; typedef IHookChainRegistryClass<void, class CBasePlayer, BOOL> IReGameHookRegistry_CBasePlayer_RemoveAllItems;
// CBasePlayer::UpdateStatusBar hook
typedef IHookChainClass<void, class CBasePlayer> IReGameHook_CBasePlayer_UpdateStatusBar;
typedef IHookChainRegistryClass<void, class CBasePlayer> IReGameHookRegistry_CBasePlayer_UpdateStatusBar;
// CBasePlayer::TakeDamageImpulse hook
typedef IHookChainClass<void, class CBasePlayer, class CBasePlayer *, float, float> IReGameHook_CBasePlayer_TakeDamageImpulse;
typedef IHookChainRegistryClass<void, class CBasePlayer, class CBasePlayer *, float, float> IReGameHookRegistry_CBasePlayer_TakeDamageImpulse;
class IReGameHookchains { class IReGameHookchains {
public: public:
virtual ~IReGameHookchains() {} virtual ~IReGameHookchains() {}
@ -790,6 +798,8 @@ public:
virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0; virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0;
virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0; virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0;
virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems() = 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 { struct ReGameFuncs_t {

View File

@ -6,5 +6,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 5 #define VERSION_MAJOR 5
#define VERSION_MINOR 28 #define VERSION_MINOR 30
#define VERSION_MAINTENANCE 0 #define VERSION_MAINTENANCE 0