diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f8547b3b6..b4e807929 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -25,20 +25,12 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
- - name: Setup Nuget
- uses: nuget/setup-nuget@v1
- with:
- nuget-api-key: ${{ secrets.NuGetAPIKey }}
- nuget-version: '5.x'
-
- - run: nuget restore '${{ env.solution }}'
-
- name: Setup MSBuild
- uses: microsoft/setup-msbuild@v1.1.3
+ uses: microsoft/setup-msbuild@v2
with:
vs-version: '16.8'
@@ -80,6 +72,7 @@ jobs:
env:
WINEDEBUG: -all
WINEDLLOVERRIDES: mshtml=
+ ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
defaults:
run:
@@ -141,18 +134,23 @@ jobs:
linux:
name: 'Linux'
runs-on: ubuntu-20.04
- container: s1lentq/linux86buildtools:latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: true
+ - name: Check dependencies
+ run: |
+ sudo dpkg --add-architecture i386
+ sudo apt-get update
+ sudo apt-get install -y gcc-multilib g++-multilib
+
- name: Build and Run unittests
run: |
- rm -rf build && CC=icc CXX=icpc cmake -DCMAKE_BUILD_TYPE=Unittests -B build && cmake --build build -j8
+ rm -rf build && CC=gcc CXX=g++ cmake -DCMAKE_BUILD_TYPE=Unittests -B build && cmake --build build -j8
retVal=0
./build/regamedll/cs 2> /dev/null > result.log || retVal=$?
while read line; do
@@ -173,17 +171,9 @@ jobs:
fi
shell: bash
- - name: Build using Intel C++ Compiler 19.0 (only for release)
- if: |
- github.event_name == 'release' &&
- github.event.action == 'published' &&
- startsWith(github.ref, 'refs/tags/')
- run: |
- rm -rf build-icc && CC=icc CXX=icpc cmake -B build-icc && cmake --build build-icc -j8
-
- - name: Build using GCC Compiler 9.3
+ - name: Build
run: |
- rm -rf build-gcc && CC=gcc CXX=g++ cmake -B build-gcc && cmake --build build-gcc -j8
+ rm -rf build && CC=gcc CXX=g++ cmake -B build && cmake --build build -j8
- name: Prepare CSSDK
run: |
@@ -193,8 +183,7 @@ jobs:
- name: Move files
run: |
mkdir -p publish/bin/linux32/cstrike/dlls
- mv build-icc/regamedll/cs.so publish/bin/linux32/cstrike/dlls/cs.so 2>/dev/null || true
- mv build-gcc/regamedll/cs.so publish/cs-gcc.so
+ mv build/regamedll/cs.so publish/bin/linux32/cstrike/dlls/cs.so 2>/dev/null || true
mv regamedll/version/appversion.h publish/appversion.h
mv dist/ publish/
@@ -202,7 +191,6 @@ jobs:
run: |
binaries=(
"publish/bin/linux32/cstrike/dlls/cs.so"
- "publish/cs-gcc.so"
)
bash ./regamedll/version/glibc_test.sh ${binaries[@]}
if [[ $? -ne 0 ]]; then
@@ -225,7 +213,7 @@ jobs:
publish:
name: 'Publish'
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
needs: [windows, testdemos, linux]
steps:
@@ -265,7 +253,7 @@ jobs:
7z a -tzip regamedll-bin-${{ env.APP_VERSION }}.zip bin/ cssdk/
- name: Publish artifacts
- uses: softprops/action-gh-release@v1
+ uses: softprops/action-gh-release@v2
id: publish-job
if: |
startsWith(github.ref, 'refs/tags/') &&
diff --git a/README.md b/README.md
index 93cd795d2..90f58990d 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,13 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
| mp_freezetime_duck | 1 | 0 | 1 | Allow players to duck during freezetime.
`0` disabled
`1` enabled |
| mp_freezetime_jump | 1 | 0 | 1 | Allow players to jump during freezetime.
`0` disabled
`1` enabled |
| mp_defuser_allocation | 0 | 0 | 2 | Give defuser on player spawn.
`0` disabled
`1` Random players.
`2` All players. |
+| mp_location_area_info | 0 | 0 | 3 | Enable location area info.
`0` disabled
`1` show location below HUD radar.
`2` show location in HUD chat. `NOT RECOMMENDED!` [:speech_balloon:](## "Not all client builds are compatible")
`3` both displayed. `NOT RECOMMENDED!` [:speech_balloon:](## "Not all client builds are compatible")
`NOTE`: Navigation `maps/.nav` file required and should contain place names
`NOTE`: If option `2` or `3` is enabled, be sure to enable `mp_chat_loc_fallback 1` |
+| mp_item_respawn_time | 30 | 0.0 | - | The respawn time for items (such as health packs, armor, etc.). |
+| mp_weapon_respawn_time | 20 | 0.0 | - | The respawn time for weapons. |
+| mp_ammo_respawn_time | 20 | 0.0 | - | The respawn time for ammunition. |
+| mp_vote_flags | km | 0 | - | Vote systems enabled in server.
`0` voting disabled
`k` votekick enabled via `vote` command
`m` votemap enabled via `votemap` command |
+| mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. |
+
## How to install zBot for CS 1.6?
diff --git a/dist/game.cfg b/dist/game.cfg
index 91009dd00..c5dad01c9 100644
--- a/dist/game.cfg
+++ b/dist/game.cfg
@@ -575,3 +575,48 @@ mp_freezetime_jump "1"
//
// Default value: "0"
mp_defuser_allocation "0"
+
+// Enable location area info
+// 0 - disabled (default behavior)
+// 1 - show location below HUD radar
+// 2 - show location in HUD chat (NOT RECOMMENDED! Not all client builds are compatible)
+// 3 - both displayed (NOT RECOMMENDED! Not all client builds are compatible)
+//
+// NOTE: Navigation maps/.nav file required and should contain place names
+// NOTE: If option 2 or 3 is enabled, be sure to enable mp_chat_loc_fallback 1
+//
+// Default value: "0"
+mp_location_area_info "0"
+
+// The respawn time for items (such as health packs, armor, etc.).
+// 0 - disable delay
+//
+// Default value: "30"
+mp_item_respawn_time "30"
+
+// The respawn time for weapons.
+// 0 - disable delay
+//
+// Default value: "20"
+mp_weapon_respawn_time "20"
+
+// The respawn time for ammunition.
+// 0 - disable delay
+//
+// Default value: "20"
+mp_ammo_respawn_time "20"
+
+// Vote systems enabled in server
+//
+// k - votekick enabled via vote command
+// m - votemap enabled via votemap command
+//
+// Set to "0" to disable voting systems
+//
+// Default value: "km"
+mp_vote_flags "km"
+
+// Minimum seconds that must elapse on map before votemap command can be used
+//
+// Default value: "180"
+mp_votemap_min_time "180"
diff --git a/regamedll/CMakeLists.txt b/regamedll/CMakeLists.txt
index 69f710b31..bc0a990e9 100644
--- a/regamedll/CMakeLists.txt
+++ b/regamedll/CMakeLists.txt
@@ -22,6 +22,7 @@ project(regamedll CXX)
option(DEBUG "Build with debug information." OFF)
option(USE_STATIC_LIBSTDC "Enables static linking libstdc++." OFF)
+option(USE_LEGACY_LIBC "Enables linking against legacy libc (<= 2.15) for compat with older distros (Debian 8/Ubuntu 16.04/Centos 7)." OFF)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -32,6 +33,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
set(COMPILE_FLAGS "-m32 -U_FORTIFY_SOURCE")
set(LINK_FLAGS "-m32 -s")
+set(LINK_LIBS dl aelf32)
set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wall -fno-exceptions -fno-builtin -Wno-unknown-pragmas")
@@ -346,6 +348,7 @@ target_compile_definitions(regamedll PRIVATE
_strnicmp=strncasecmp
_strdup=strdup
_unlink=unlink
+ _snprintf=snprintf
_vsnprintf=vsnprintf
_write=write
_close=close
@@ -362,12 +365,13 @@ target_sources(regamedll PRIVATE
${UNITTESTS_SRCS}>
)
-target_link_libraries(regamedll PRIVATE
- dl
- aelf32
+if (CMAKE_BUILD_TYPE MATCHES Unittests)
+ list(APPEND LINK_LIBS cppunitlite)
+elseif (USE_LEGACY_LIBC)
+ list(APPEND LINK_LIBS libc-2.15.so)
+endif()
- $<$:cppunitlite>
-)
+target_link_libraries(regamedll PRIVATE ${LINK_LIBS})
if (USE_STATIC_LIBSTDC)
target_compile_definitions(regamedll PRIVATE BUILD_STATIC_LIBSTDC)
diff --git a/regamedll/dlls/API/CAPI_Impl.cpp b/regamedll/dlls/API/CAPI_Impl.cpp
index 5bb6b3940..41175c838 100644
--- a/regamedll/dlls/API/CAPI_Impl.cpp
+++ b/regamedll/dlls/API/CAPI_Impl.cpp
@@ -335,6 +335,7 @@ GAMEHOOK_REGISTRY(CSGameRules_SendDeathMessage);
GAMEHOOK_REGISTRY(CBasePlayer_PlayerDeathThink);
GAMEHOOK_REGISTRY(CBasePlayer_Observer_Think);
+GAMEHOOK_REGISTRY(CBasePlayer_RemoveAllItems);
int CReGameApi::GetMajorVersion() {
return REGAMEDLL_API_VERSION_MAJOR;
diff --git a/regamedll/dlls/API/CAPI_Impl.h b/regamedll/dlls/API/CAPI_Impl.h
index 0548a841f..2635be5b9 100644
--- a/regamedll/dlls/API/CAPI_Impl.h
+++ b/regamedll/dlls/API/CAPI_Impl.h
@@ -745,6 +745,10 @@ typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBase
typedef IHookChainClassImpl CReGameHook_CBasePlayer_Observer_Think;
typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_Observer_Think;
+// CBasePlayer::RemoveAllItems hook
+typedef IHookChainClassImpl CReGameHook_CBasePlayer_RemoveAllItems;
+typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_RemoveAllItems;
+
class CReGameHookchains: public IReGameHookchains {
public:
// CBasePlayer virtual
@@ -905,6 +909,7 @@ class CReGameHookchains: public IReGameHookchains {
CReGameHookRegistry_CBasePlayer_PlayerDeathThink m_CBasePlayer_PlayerDeathThink;
CReGameHookRegistry_CBasePlayer_Observer_Think m_CBasePlayer_Observer_Think;
+ CReGameHookRegistry_CBasePlayer_RemoveAllItems m_CBasePlayer_RemoveAllItems;
public:
virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn();
@@ -1064,6 +1069,7 @@ class CReGameHookchains: public IReGameHookchains {
virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink();
virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think();
+ virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems();
};
extern CReGameHookchains g_ReGameHookchains;
diff --git a/regamedll/dlls/ammo.cpp b/regamedll/dlls/ammo.cpp
index bfef8749e..1df3622cc 100644
--- a/regamedll/dlls/ammo.cpp
+++ b/regamedll/dlls/ammo.cpp
@@ -10,7 +10,11 @@ void CBasePlayerAmmo::Spawn()
SetTouch(&CBasePlayerAmmo::DefaultTouch);
- if (g_pGameRules->IsMultiplayer())
+ if (g_pGameRules->IsMultiplayer()
+#ifdef REGAMEDLL_FIXES
+ && g_pGameRules->AmmoShouldRespawn(this) == GR_AMMO_RESPAWN_NO
+#endif
+ )
{
SetThink(&CBaseEntity::SUB_Remove);
pev->nextthink = gpGlobals->time + 2.0f;
diff --git a/regamedll/dlls/bot/cs_bot.cpp b/regamedll/dlls/bot/cs_bot.cpp
index 838387a95..dd85448c6 100644
--- a/regamedll/dlls/bot/cs_bot.cpp
+++ b/regamedll/dlls/bot/cs_bot.cpp
@@ -43,10 +43,7 @@ int GetBotFollowCount(CBasePlayer *pLeader)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -685,10 +682,7 @@ CBasePlayer *CCSBot::GetImportantEnemy(bool checkVisibility) const
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
diff --git a/regamedll/dlls/bot/cs_bot_chatter.cpp b/regamedll/dlls/bot/cs_bot_chatter.cpp
index 31bd03bbd..1476d8d58 100644
--- a/regamedll/dlls/bot/cs_bot_chatter.cpp
+++ b/regamedll/dlls/bot/cs_bot_chatter.cpp
@@ -65,10 +65,7 @@ void BotMeme::Transmit(CCSBot *pSender) const
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -540,8 +537,13 @@ bool BotPhraseManager::Initialize(const char *filename, int bankIndex)
else if (!Q_stricmp("UNDEFINED", token))
placeCriteria = UNDEFINED_PLACE;
else
+ {
placeCriteria = TheBotPhrases->NameToID(token);
+ if (!TheBotPhrases->IsValid() && placeCriteria == UNDEFINED_PLACE)
+ placeCriteria = TheNavAreaGrid.NameToID(token);
+ }
+
continue;
}
@@ -1520,10 +1522,7 @@ BotStatement *BotChatterInterface::GetActiveStatement()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
diff --git a/regamedll/dlls/bot/cs_bot_chatter.h b/regamedll/dlls/bot/cs_bot_chatter.h
index f8d7f45b2..4a4591cf6 100644
--- a/regamedll/dlls/bot/cs_bot_chatter.h
+++ b/regamedll/dlls/bot/cs_bot_chatter.h
@@ -255,6 +255,8 @@ class BotPhraseManager
Place NameToID(const char *name) const;
const char *IDToName(Place id) const;
+ bool IsValid() const { return !m_placeList.empty(); }
+
// given a name, return the associated phrase collection
const BotPhrase *GetPhrase(const char *name) const;
diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp
index 4ed27ac55..1bf7aec00 100644
--- a/regamedll/dlls/bot/cs_bot_init.cpp
+++ b/regamedll/dlls/bot/cs_bot_init.cpp
@@ -62,6 +62,8 @@ cvar_t cv_bot_deathmatch = { "bot_deathmatch", "0", FCVAR_SERVER, 0.
cvar_t cv_bot_quota_mode = { "bot_quota_mode", "normal", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_join_delay = { "bot_join_delay", "0", FCVAR_SERVER, 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_yaw_offset = { "bot_mimic_yaw_offset", "0", 0, 0.0f, nullptr };
#else
// Migrated to bot_quota_mode, use "match"
cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr };
@@ -131,6 +133,8 @@ void Bot_RegisterCVars()
CVAR_REGISTER(&cv_bot_quota_mode);
CVAR_REGISTER(&cv_bot_join_delay);
CVAR_REGISTER(&cv_bot_freeze);
+ CVAR_REGISTER(&cv_bot_mimic);
+ CVAR_REGISTER(&cv_bot_mimic_yaw_offset);
#endif
}
@@ -328,7 +332,7 @@ void CCSBot::SpawnBot()
TheCSBots()->ValidateMapData();
ResetValues();
- Q_strcpy(m_name, STRING(pev->netname));
+ Q_strlcpy(m_name, STRING(pev->netname));
SetState(&m_buyState);
SetTouch(&CCSBot::BotTouch);
diff --git a/regamedll/dlls/bot/cs_bot_init.h b/regamedll/dlls/bot/cs_bot_init.h
index 4f62b511b..8687e3f7f 100644
--- a/regamedll/dlls/bot/cs_bot_init.h
+++ b/regamedll/dlls/bot/cs_bot_init.h
@@ -62,6 +62,8 @@ extern cvar_t cv_bot_deathmatch;
extern cvar_t cv_bot_quota_mode;
extern cvar_t cv_bot_join_delay;
extern cvar_t cv_bot_freeze;
+extern cvar_t cv_bot_mimic;
+extern cvar_t cv_bot_mimic_yaw_offset;
#else
extern cvar_t cv_bot_quota_match;
#endif
diff --git a/regamedll/dlls/bot/cs_bot_learn.cpp b/regamedll/dlls/bot/cs_bot_learn.cpp
index 76edded7a..3cf041e31 100644
--- a/regamedll/dlls/bot/cs_bot_learn.cpp
+++ b/regamedll/dlls/bot/cs_bot_learn.cpp
@@ -477,14 +477,14 @@ void CCSBot::StartSaveProcess()
void CCSBot::UpdateSaveProcess()
{
- char filename[256];
char msg[256];
char cmd[128];
- GET_GAME_DIR(filename);
+ char gd[64]{};
+ GET_GAME_DIR(gd);
- Q_strcat(filename, "\\");
- Q_strcat(filename, TheBots->GetNavMapFilename());
+ char filename[MAX_OSPATH];
+ Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, TheBots->GetNavMapFilename());
HintMessageToAllPlayers("Saving...");
SaveNavigationMap(filename);
diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp
index 024a4718e..730805bbf 100644
--- a/regamedll/dlls/bot/cs_bot_manager.cpp
+++ b/regamedll/dlls/bot/cs_bot_manager.cpp
@@ -337,6 +337,10 @@ void CCSBotManager::ClientDisconnect(CBasePlayer *pPlayer)
pPlayer = GetClassPtr((CBasePlayer *)pevTemp);
AddEntityHashValue(pPlayer->pev, STRING(pPlayer->pev->classname), CLASSNAME);
pPlayer->pev->flags = FL_DORMANT;
+
+#ifdef REGAMEDLL_FIXES
+ pPlayer->has_disconnected = true;
+#endif
}
void PrintAllEntities()
@@ -396,16 +400,19 @@ void CCSBotManager::ServerCommand(const char *pcmd)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
const char *name = STRING(pPlayer->pev->netname);
if (FStrEq(name, ""))
continue;
+#ifdef REGAMEDLL_FIXES
+ if (pPlayer->pev->deadflag != DEAD_NO)
+ continue;
+#endif
+
if (pPlayer->IsBot())
{
CCSBot *pBot = static_cast(pPlayer);
@@ -422,13 +429,17 @@ void CCSBotManager::ServerCommand(const char *pcmd)
else
kickThemAll = false;
+#ifdef REGAMEDLL_ADD
+ bool fillMode = FStrEq(cv_bot_quota_mode.string, "fill");
+#else
+ bool fillMode = false;
+#endif
+
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
const char *name = STRING(pPlayer->pev->netname);
@@ -443,7 +454,11 @@ void CCSBotManager::ServerCommand(const char *pcmd)
// adjust bot quota so kicked bot is not immediately added back in
int newQuota = cv_bot_quota.value - 1;
SERVER_COMMAND(UTIL_VarArgs("kick \"%s\"\n", name));
- CVAR_SET_FLOAT("bot_quota", clamp(newQuota, 0, int(cv_bot_quota.value)));
+
+ if (kickThemAll || !fillMode)
+ {
+ CVAR_SET_FLOAT("bot_quota", clamp(newQuota, 0, int(cv_bot_quota.value)));
+ }
}
}
}
@@ -563,14 +578,16 @@ void CCSBotManager::ServerCommand(const char *pcmd)
}
else if (FStrEq(pcmd, "bot_nav_save"))
{
- GET_GAME_DIR(buffer);
- Q_strcat(buffer, "\\");
- Q_strcat(buffer, CBotManager::GetNavMapFilename());
+ char gd[64]{};
+ GET_GAME_DIR(gd);
+
+ char filename[MAX_OSPATH];
+ Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, CBotManager::GetNavMapFilename());
- if (SaveNavigationMap(buffer))
- CONSOLE_ECHO("Navigation map '%s' saved.\n", buffer);
+ if (SaveNavigationMap(filename))
+ CONSOLE_ECHO("Navigation map '%s' saved.\n", filename);
else
- CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", buffer);
+ CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", filename);
}
else if (FStrEq(pcmd, "bot_nav_load"))
{
@@ -665,6 +682,9 @@ void CCSBotManager::ServerCommand(const char *pcmd)
CBaseEntity *pEntity = nullptr;
while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player")))
{
+ if (FNullEnt(pEntity->edict()))
+ break;
+
if (!pEntity->IsPlayer())
continue;
@@ -745,6 +765,23 @@ void CCSBotManager::ServerCommand(const char *pcmd)
BOOL CCSBotManager::ClientCommand(CBasePlayer *pPlayer, const char *pcmd)
{
+#ifdef REGAMEDLL_ADD
+ if (pPlayer->IsBot())
+ return FALSE;
+
+ if (cv_bot_mimic.value == pPlayer->entindex())
+ {
+ // Bots mimic our client commands
+ ForEachPlayer([pPlayer, pcmd](CBasePlayer *bot)
+ {
+ if (pPlayer != bot && bot->IsBot())
+ bot->ClientCommand(pcmd, CMD_ARGV_(1));
+
+ return true;
+ });
+ }
+#endif
+
return FALSE;
}
@@ -787,7 +824,8 @@ bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromConsole)
// decrease the bot quota
if (!isFromConsole)
{
- CVAR_SET_FLOAT("bot_quota", cv_bot_quota.value - 1);
+ int newQuota = cv_bot_quota.value - 1;
+ CVAR_SET_FLOAT("bot_quota", clamp(newQuota, 0, (int)cv_bot_quota.value));
}
#endif
@@ -821,7 +859,8 @@ bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromConsole)
if (isFromConsole)
{
// increase the bot quota to account for manually added bot
- CVAR_SET_FLOAT("bot_quota", cv_bot_quota.value + 1);
+ int newQuota = cv_bot_quota.value + 1;
+ CVAR_SET_FLOAT("bot_quota", clamp(newQuota, 0, gpGlobals->maxClients));
}
}
#ifdef REGAMEDLL_FIXES
@@ -830,7 +869,8 @@ bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromConsole)
// decrease the bot quota
if (!isFromConsole)
{
- CVAR_SET_FLOAT("bot_quota", cv_bot_quota.value - 1);
+ int newQuota = cv_bot_quota.value - 1;
+ CVAR_SET_FLOAT("bot_quota", clamp(newQuota, 0, (int)cv_bot_quota.value));
}
}
#endif
@@ -860,10 +900,17 @@ void CCSBotManager::MaintainBotQuota()
int desiredBotCount = int(cv_bot_quota.value);
int occupiedBotSlots = UTIL_BotsInGame();
+ bool isRoundInDeathmatch = false;
+
+#ifdef REGAMEDLL_ADD
+ if (round_infinite.value > 0)
+ isRoundInDeathmatch = true; // is no round end gameplay
+#endif
+
// isRoundInProgress is true if the round has progressed far enough that new players will join as dead.
bool isRoundInProgress = CSGameRules()->IsGameStarted() &&
!TheCSBots()->IsRoundOver() &&
- (CSGameRules()->GetRoundElapsedTime() >= CSGameRules()->GetRoundRespawnTime());
+ (CSGameRules()->GetRoundRespawnTime() != -1 && CSGameRules()->GetRoundElapsedTime() >= CSGameRules()->GetRoundRespawnTime()) && !isRoundInDeathmatch;
#ifdef REGAMEDLL_ADD
if (FStrEq(cv_bot_quota_mode.string, "fill"))
@@ -872,7 +919,7 @@ void CCSBotManager::MaintainBotQuota()
// unless the round is already in progress, in which case we play with what we've been dealt
if (!isRoundInProgress)
{
- desiredBotCount = Q_max(0, desiredBotCount - humanPlayersInGame + spectatorPlayersInGame);
+ desiredBotCount = Q_max(0, desiredBotCount - humanPlayersInGame);
}
else
{
@@ -919,13 +966,15 @@ void CCSBotManager::MaintainBotQuota()
if (cv_bot_auto_vacate.value > 0.0)
desiredBotCount = Q_min(desiredBotCount, gpGlobals->maxClients - (humanPlayersInGame + 1));
else
- desiredBotCount = Q_min(desiredBotCount, gpGlobals->maxClients - humanPlayersInGame + spectatorPlayersInGame);
+ desiredBotCount = Q_min(desiredBotCount, gpGlobals->maxClients - humanPlayersInGame);
#ifdef REGAMEDLL_FIXES
// Try to balance teams, if we are in the first specified seconds of a round and bots can join either team.
- if (occupiedBotSlots > 0 && desiredBotCount == occupiedBotSlots && CSGameRules()->IsGameStarted())
+ if (occupiedBotSlots > 0 && desiredBotCount == occupiedBotSlots && (CSGameRules()->IsGameStarted() || isRoundInDeathmatch))
{
- if (CSGameRules()->GetRoundElapsedTime() < CSGameRules()->GetRoundRespawnTime()) // new bots can still spawn during this time
+ if (isRoundInDeathmatch ||
+ (CSGameRules()->GetRoundRespawnTime() == -1 || // means no time limit
+ CSGameRules()->GetRoundElapsedTime() < CSGameRules()->GetRoundRespawnTime())) // new bots can still spawn during this time
{
if (autoteambalance.value > 0.0f)
{
@@ -1042,7 +1091,8 @@ void CCSBotManager::MaintainBotQuota()
UTIL_KickBotFromTeam(TERRORIST);
}
- CVAR_SET_FLOAT("bot_quota", cv_bot_quota.value - 1.0f);
+ int newQuota = cv_bot_quota.value - 1;
+ CVAR_SET_FLOAT("bot_quota", clamp(newQuota, 0, (int)cv_bot_quota.value));
}
}
@@ -1587,7 +1637,8 @@ void CCSBotManager::OnFreeEntPrivateData(CBaseEntity *pEntity)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || pPlayer->IsDormant())
+
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->IsBot())
diff --git a/regamedll/dlls/bot/cs_bot_pathfind.cpp b/regamedll/dlls/bot/cs_bot_pathfind.cpp
index 00386be7b..f418b56cb 100644
--- a/regamedll/dlls/bot/cs_bot_pathfind.cpp
+++ b/regamedll/dlls/bot/cs_bot_pathfind.cpp
@@ -1118,10 +1118,7 @@ bool CCSBot::IsFriendInTheWay(const Vector *goalPos) const
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (!pPlayer->IsAlive())
diff --git a/regamedll/dlls/bot/cs_bot_statemachine.cpp b/regamedll/dlls/bot/cs_bot_statemachine.cpp
index 325252641..7bb31eddc 100644
--- a/regamedll/dlls/bot/cs_bot_statemachine.cpp
+++ b/regamedll/dlls/bot/cs_bot_statemachine.cpp
@@ -299,6 +299,12 @@ void CCSBot::Attack(CBasePlayer *victim)
if (cv_bot_zombie.value != 0.0f)
return;
+#ifdef REGAMEDLL_ADD
+ // If mimicing the player, don't attack state
+ if (cv_bot_mimic.value)
+ return;
+#endif
+
// cannot attack if we are reloading
if (IsActiveWeaponReloading())
return;
diff --git a/regamedll/dlls/bot/cs_bot_vision.cpp b/regamedll/dlls/bot/cs_bot_vision.cpp
index 8fc811ed2..f7b16acc5 100644
--- a/regamedll/dlls/bot/cs_bot_vision.cpp
+++ b/regamedll/dlls/bot/cs_bot_vision.cpp
@@ -61,6 +61,12 @@ void CCSBot::UpdateLookAngles()
float stiffness;
float damping;
+#ifdef REGAMEDLL_ADD
+ // If mimicing the player, don't modify the view angles
+ if (cv_bot_mimic.value > 0)
+ return;
+#endif
+
// springs are stiffer when attacking, so we can track and move between targets better
if (IsAttacking())
{
@@ -253,7 +259,7 @@ bool CCSBot::IsVisible(CBasePlayer *pPlayer, bool testFOV, unsigned char *visPar
if ((pPlayer->pev->flags & FL_NOTARGET) || (pPlayer->pev->effects & EF_NODRAW))
return false;
#endif
-
+
Vector spot = pPlayer->pev->origin;
unsigned char testVisParts = NONE;
@@ -701,10 +707,7 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
// is it a player?
diff --git a/regamedll/dlls/career_tasks.cpp b/regamedll/dlls/career_tasks.cpp
index 200c67558..972ccca9b 100644
--- a/regamedll/dlls/career_tasks.cpp
+++ b/regamedll/dlls/career_tasks.cpp
@@ -545,7 +545,11 @@ void CCareerTaskManager::HandleDeath(int team, CBasePlayer *pAttacker)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer && pPlayer->m_iTeam == enemyTeam && pPlayer->IsAlive())
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (pPlayer->m_iTeam == enemyTeam && pPlayer->IsAlive())
numEnemies++;
}
diff --git a/regamedll/dlls/cbase.cpp b/regamedll/dlls/cbase.cpp
index ebfd2fdc2..5be847bdc 100644
--- a/regamedll/dlls/cbase.cpp
+++ b/regamedll/dlls/cbase.cpp
@@ -1598,6 +1598,30 @@ void OnFreeEntPrivateData(edict_t *pEnt)
if (!pEntity)
return;
+#ifdef REGAMEDLL_FIXES
+ // FIXED: Ensure this item will be removed from the owner player's inventory 'm_rgpPlayerItems[]'
+ // to avoid dangling pointers
+ CBasePlayerItem *pItem = dynamic_cast(pEntity);
+ if (pItem)
+ {
+ CBasePlayer *pOwner = GET_PRIVATE(pItem->pev->owner);
+ if (pOwner && pOwner->IsPlayer())
+ {
+ if (pOwner->m_pActiveItem == pItem && pItem->IsWeapon())
+ ((CBasePlayerWeapon *)pItem)->RetireWeapon();
+
+ if (pOwner->RemovePlayerItem(pItem))
+ {
+ // Ammo must be dropped, otherwise grenades cannot be buy or picked up
+ if (IsGrenadeWeapon(pItem->m_iId) || pItem->m_iId == WEAPON_C4)
+ pOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()] = 0;
+
+ pOwner->pev->weapons &= ~(1 << pItem->m_iId);
+ }
+ }
+ }
+#endif
+
#ifdef REGAMEDLL_API
pEntity->OnDestroy();
#endif
diff --git a/regamedll/dlls/cdll_dll.h b/regamedll/dlls/cdll_dll.h
index da6cd36df..6e495368d 100644
--- a/regamedll/dlls/cdll_dll.h
+++ b/regamedll/dlls/cdll_dll.h
@@ -74,6 +74,7 @@ const int DEFAULT_FOV = 90; // the default field of view
#define PLAYER_PREVENT_DUCK BIT(4)
#define PLAYER_PREVENT_CLIMB BIT(5) // The player can't climb ladder
#define PLAYER_PREVENT_JUMP BIT(6)
+#define PLAYER_PREVENT_DDUCK BIT(7)
#define MENU_KEY_1 BIT(0)
#define MENU_KEY_2 BIT(1)
diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp
index 2a58443d7..bc223ed7d 100644
--- a/regamedll/dlls/client.cpp
+++ b/regamedll/dlls/client.cpp
@@ -133,6 +133,7 @@ static entity_field_alias_t custom_entity_field_alias[] =
{ "animtime", 0 },
};
+edict_t *g_pEdicts = nullptr;
bool g_bServerActive = false;
bool g_bItemCreatedByBuying = false;
PLAYERPVSSTATUS g_PVSStatus[MAX_CLIENTS];
@@ -438,6 +439,9 @@ NOXREF int CountTeams()
if (FNullEnt(pEntity->edict()))
break;
+ if (pEntity->IsDormant())
+ continue;
+
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
if (pPlayer->m_iTeam == UNASSIGNED)
@@ -461,7 +465,7 @@ NOXREF int CountTeams()
void ListPlayers(CBasePlayer *current)
{
- char message[120] = "", cNumber[12];
+ char message[120]{};
CBaseEntity *pEntity = nullptr;
while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player")))
@@ -475,12 +479,7 @@ void ListPlayers(CBasePlayer *current)
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
int iUserID = GETPLAYERUSERID(ENT(pPlayer->pev));
- Q_sprintf(cNumber, "%d", iUserID);
- Q_strcpy(message, "\n");
- Q_strcat(message, cNumber);
- Q_strcat(message, " : ");
- Q_strcat(message, STRING(pPlayer->pev->netname));
-
+ Q_snprintf(message, sizeof(message), "\n%d : %s", iUserID, STRING(pPlayer->pev->netname));
ClientPrint(current->pev, HUD_PRINTCONSOLE, message);
}
@@ -499,7 +498,8 @@ int CountTeamPlayers(int iTeam)
if (pEntity->IsDormant())
continue;
- if (GetClassPtr((CBasePlayer *)pEntity->pev)->m_iTeam == iTeam)
+ CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
+ if (pPlayer->m_iTeam == iTeam)
{
nCount++;
}
@@ -534,6 +534,9 @@ void ProcessKickVote(CBasePlayer *pVotingPlayer, CBasePlayer *pKickPlayer)
if (FNullEnt(pTempEntity->edict()))
break;
+ if (pTempEntity->IsDormant())
+ continue;
+
pTempPlayer = GetClassPtr((CBasePlayer *)pTempEntity->pev);
if (!pTempPlayer || pTempPlayer->m_iTeam == UNASSIGNED)
@@ -571,6 +574,9 @@ void ProcessKickVote(CBasePlayer *pVotingPlayer, CBasePlayer *pKickPlayer)
if (FNullEnt(pTempEntity->edict()))
break;
+ if (pTempEntity->IsDormant())
+ continue;
+
pTempPlayer = GetClassPtr((CBasePlayer *)pTempEntity->pev);
if (!pTempPlayer || pTempPlayer->m_iTeam == UNASSIGNED)
@@ -727,8 +733,8 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity)
pPlayer->m_iJoiningState = SHOWLTEXT;
- static char sName[128];
- Q_strcpy(sName, STRING(pPlayer->pev->netname));
+ char sName[128];
+ Q_strlcpy(sName, STRING(pPlayer->pev->netname));
for (char *pApersand = sName; pApersand && *pApersand != '\0'; pApersand++)
{
@@ -786,12 +792,12 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
{
if (CMD_ARGC_() >= 2)
{
- Q_sprintf(szTemp, "%s %s", pcmd, CMD_ARGS());
+ Q_snprintf(szTemp, sizeof(szTemp), "%s %s", pcmd, CMD_ARGS());
}
else
{
// Just a one word command, use the first word...sigh
- Q_sprintf(szTemp, "%s", pcmd);
+ Q_snprintf(szTemp, sizeof(szTemp), "%s", pcmd);
}
p = szTemp;
@@ -829,14 +835,18 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
return;
const char *placeName = nullptr;
- char *pszFormat = nullptr;
+ const char *pszFormat = nullptr;
char *pszConsoleFormat = nullptr;
bool consoleUsesPlaceName = false;
// team only
if (teamonly)
{
- if (AreRunningCZero() && (pPlayer->m_iTeam == CT || pPlayer->m_iTeam == TERRORIST))
+ if ((
+#ifdef REGAMEDLL_ADD
+ location_area_info.value >= 2 ||
+#endif
+ AreRunningCZero()) && (pPlayer->m_iTeam == CT || pPlayer->m_iTeam == TERRORIST))
{
// search the place name where is located the player
Place playerPlace = TheNavAreaGrid.GetPlace(&pPlayer->pev->origin);
@@ -850,8 +860,17 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
break;
}
}
+
+ if (!placeName)
+ placeName = TheNavAreaGrid.IDToName(playerPlace);
}
+ bool bUseLocFallback = false;
+#ifdef REGAMEDLL_ADD
+ if (chat_loc_fallback.value)
+ bUseLocFallback = true;
+#endif
+
if (pPlayer->m_iTeam == CT)
{
if (bSenderDead)
@@ -861,7 +880,7 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
}
else if (placeName)
{
- pszFormat = "#Cstrike_Chat_CT_Loc";
+ pszFormat = bUseLocFallback ? "\x1(Counter-Terrorist) \x3%s1\x1 @ \x4%s3\x1 : %s2" : "#Cstrike_Chat_CT_Loc";
pszConsoleFormat = "*(Counter-Terrorist) %s @ %s : %s";
consoleUsesPlaceName = true;
}
@@ -880,7 +899,7 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
}
else if (placeName)
{
- pszFormat = "#Cstrike_Chat_T_Loc";
+ pszFormat = bUseLocFallback ? "\x1(Terrorist) \x3%s1\x1 @ \x4%s3\x1 : %s2" : "#Cstrike_Chat_T_Loc";
pszConsoleFormat = "(Terrorist) %s @ %s : %s";
consoleUsesPlaceName = true;
}
@@ -943,8 +962,8 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
}
}
- Q_strcat(text, p);
- Q_strcat(text, "\n");
+ Q_strlcat(text, p);
+ Q_strlcat(text, "\n");
// loop through all players
// Start with the first player.
@@ -963,6 +982,9 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
if (pReceiver->edict() == pEntity)
continue;
+ if (pReceiver->IsDormant())
+ continue;
+
// Not a client ? (should never be true)
if (!pReceiver->IsNetClient())
continue;
@@ -2330,6 +2352,9 @@ CBaseEntity *EntityFromUserID(int userID)
if (FNullEnt(pTempEntity->edict()))
break;
+ if (pTempEntity->IsDormant())
+ continue;
+
CBasePlayer *pTempPlayer = GetClassPtr((CBasePlayer *)pTempEntity->pev);
if (pTempPlayer->m_iTeam != UNASSIGNED && userID == GETPLAYERUSERID(pTempEntity->edict()))
@@ -2350,6 +2375,9 @@ NOXREF int CountPlayersInServer()
if (FNullEnt(pTempEntity->edict()))
break;
+ if (pTempEntity->IsDormant())
+ continue;
+
CBasePlayer *pTempPlayer = GetClassPtr((CBasePlayer *)pTempEntity->pev);
if (pTempPlayer->m_iTeam != UNASSIGNED)
@@ -2595,6 +2623,15 @@ void EXT_FUNC InternalCommand(edict_t *pEntity, const char *pcmd, const char *pa
return;
}
+#ifdef REGAMEDLL_ADD
+ static const int flagKick = UTIL_ReadFlags("k");
+ if ((flagKick & UTIL_ReadFlags(vote_flags.string)) == 0)
+ {
+ ClientPrint(pPlayer->pev, HUD_PRINTCENTER, "#Command_Not_Available");
+ return;
+ }
+#endif
+
pPlayer->m_flNextVoteTime = gpGlobals->time + 3;
if (pPlayer->m_iTeam != UNASSIGNED)
@@ -2676,11 +2713,20 @@ void EXT_FUNC InternalCommand(edict_t *pEntity, const char *pcmd, const char *pa
return;
}
+#ifdef REGAMEDLL_ADD
+ static const int flagMap = UTIL_ReadFlags("m");
+ if ((flagMap & UTIL_ReadFlags(vote_flags.string)) == 0)
+ {
+ ClientPrint(pPlayer->pev, HUD_PRINTCENTER, "#Command_Not_Available");
+ return;
+ }
+#endif
+
pPlayer->m_flNextVoteTime = gpGlobals->time + 3;
if (pPlayer->m_iTeam != UNASSIGNED)
{
- if (gpGlobals->time < 180)
+ if (gpGlobals->time < CGameRules::GetVotemapMinElapsedTime())
{
ClientPrint(pPlayer->pev, HUD_PRINTCONSOLE, "#Cannot_Vote_Map");
return;
@@ -3249,6 +3295,26 @@ void EXT_FUNC InternalCommand(edict_t *pEntity, const char *pcmd, const char *pa
}
}
#endif
+
+#ifdef REGAMEDLL_ADD
+ // Request from client for the given version of player movement control, if any
+ else if (FStrEq(pcmd, "cl_pmove_version"))
+ {
+ // cl_pmove_version
+ if (CMD_ARGC_() < 2)
+ return; // invalid
+
+ PlayerMovementVersion &playerMovementVersion = pPlayer->CSPlayer()->m_MovementVersion;
+ playerMovementVersion.Set(parg1);
+
+ // If the client's requested movement version is newer, enforce it to the available one
+ if (playerMovementVersion.IsGreaterThan(PM_VERSION))
+ {
+ playerMovementVersion.Set(PM_VERSION); // reset to available version
+ CLIENT_COMMAND(pEntity, "cl_pmove_version %s\n", playerMovementVersion.ToString());
+ }
+ }
+#endif
else
{
if (g_pGameRules->ClientCommand_DeadOrAlive(GetClassPtr((CBasePlayer *)pev), pcmd))
@@ -3330,7 +3396,11 @@ void EXT_FUNC InternalCommand(edict_t *pEntity, const char *pcmd, const char *pa
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pObserver = UTIL_PlayerByIndex(i);
- if (pObserver && pObserver->IsObservingPlayer(pPlayer))
+
+ if (!UTIL_IsValidPlayer(pObserver))
+ continue;
+
+ if (pObserver->IsObservingPlayer(pPlayer))
{
EMIT_SOUND(ENT(pObserver->pev), CHAN_ITEM, "items/nvg_off.wav", RANDOM_FLOAT(0.92, 1), ATTN_NORM);
@@ -3355,7 +3425,11 @@ void EXT_FUNC InternalCommand(edict_t *pEntity, const char *pcmd, const char *pa
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pObserver = UTIL_PlayerByIndex(i);
- if (pObserver && pObserver->IsObservingPlayer(pPlayer))
+
+ if (!UTIL_IsValidPlayer(pObserver))
+ continue;
+
+ if (pObserver->IsObservingPlayer(pPlayer))
{
EMIT_SOUND(ENT(pObserver->pev), CHAN_ITEM, "items/nvg_on.wav", RANDOM_FLOAT(0.92, 1), ATTN_NORM);
@@ -3669,6 +3743,22 @@ void EXT_FUNC ServerDeactivate()
void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
{
+ g_pEdicts = pEdictList;
+
+#ifdef REGAMEDLL_ADD
+ //
+ // Tells clients which version of player movement (pmove) the server is using
+ //
+ // In GoldSrc, both the server and clients handle player movement using shared code.
+ // If the server changes how movement works, due to improvements or bugfixes, it can mess up
+ // the client's movement prediction, causing desync. To avoid this, the server can tell clients what
+ // version of the movement code it's using. Clients that don't recognize or respond to this version
+ // will be treated as using the previous behavior, and the server will handle them accordingly.
+ // Clients that do recognize it will let the server know, so everything stays in sync.
+ //
+ SET_KEY_VALUE(GET_INFO_BUFFER(pEdictList), "pmove", PM_ServerVersion());
+#endif
+
int i;
CBaseEntity *pClass;
@@ -3723,6 +3813,9 @@ void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
#ifdef REGAMEDLL_ADD
CSGameRules()->ServerActivate();
+
+ if (location_area_info.value)
+ LoadNavigationMap();
#endif
}
@@ -4895,7 +4988,7 @@ void EXT_FUNC UpdateClientData(const edict_t *ent, int sendweapons, struct clien
cd->flSwimTime = pev->flSwimTime;
cd->waterjumptime = int(pev->teleport_time);
- Q_strcpy(cd->physinfo, ENGINE_GETPHYSINFO(ent));
+ Q_strlcpy(cd->physinfo, ENGINE_GETPHYSINFO(ent));
cd->maxspeed = pev->maxspeed;
cd->fov = pev->fov;
@@ -5106,8 +5199,10 @@ int EXT_FUNC InconsistentFile(const edict_t *pEdict, const char *filename, char
if (!CVAR_GET_FLOAT("mp_consistency"))
return 0;
+ const int BufferLen = 256;
+
// Default behavior is to kick the player
- Q_sprintf(disconnect_message, "Server is enforcing file consistency for %s\n", filename);
+ Q_snprintf(disconnect_message, BufferLen, "Server is enforcing file consistency for %s\n", filename);
// Kick now with specified disconnect message.
return 1;
diff --git a/regamedll/dlls/cmdhandler.cpp b/regamedll/dlls/cmdhandler.cpp
index d715de641..73bfe7cfd 100644
--- a/regamedll/dlls/cmdhandler.cpp
+++ b/regamedll/dlls/cmdhandler.cpp
@@ -37,7 +37,10 @@ void SV_Continue_f()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer && !pPlayer->IsBot())
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!pPlayer->IsBot())
{
// at the end of the round is showed window with the proposal surrender or continue
// now of this time HUD is completely hidden
@@ -96,7 +99,7 @@ void SV_Career_EndRound_f()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->IsBot() && pPlayer->m_iTeam == pLocalPlayer->m_iTeam)
diff --git a/regamedll/dlls/combat.cpp b/regamedll/dlls/combat.cpp
index 4cbc485dc..17fe84e27 100644
--- a/regamedll/dlls/combat.cpp
+++ b/regamedll/dlls/combat.cpp
@@ -9,7 +9,11 @@ void PlayerBlind(CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAt
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pObserver = UTIL_PlayerByIndex(i);
- if (pObserver && pObserver->IsObservingPlayer(pPlayer))
+
+ if (!UTIL_IsValidPlayer(pObserver))
+ continue;
+
+ if (pObserver->IsObservingPlayer(pPlayer))
{
UTIL_ScreenFade(pObserver, color, fadeTime, fadeHold, alpha, 0);
}
diff --git a/regamedll/dlls/debug.cpp b/regamedll/dlls/debug.cpp
index 82d50d71d..81605143d 100644
--- a/regamedll/dlls/debug.cpp
+++ b/regamedll/dlls/debug.cpp
@@ -27,7 +27,7 @@ NOXREF void UTIL_DPrintf(DebugOutputType outputType, char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -41,7 +41,7 @@ void UTIL_DPrintf(char *pszMsg, ...)
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -130,7 +130,7 @@ NOXREF void UTIL_BotDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -146,7 +146,7 @@ void UTIL_CareerDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -162,7 +162,7 @@ NOXREF void UTIL_TutorDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -178,7 +178,7 @@ NOXREF void UTIL_StatsDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
@@ -194,7 +194,7 @@ NOXREF void UTIL_HostageDPrintf(char *pszMsg, ...)
{
va_list argptr;
va_start(argptr, pszMsg);
- vsprintf(theDebugBuffer, pszMsg, argptr);
+ Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(theDebugBuffer);
diff --git a/regamedll/dlls/explode.cpp b/regamedll/dlls/explode.cpp
index 104d84720..6d1c7ccd4 100644
--- a/regamedll/dlls/explode.cpp
+++ b/regamedll/dlls/explode.cpp
@@ -201,7 +201,7 @@ void ExplosionCreate(const Vector ¢er, Vector &angles, edict_t *pOwner, int
CBaseEntity *pExplosion = CBaseEntity::Create("env_explosion", center, angles, pOwner);
- Q_sprintf(buf, "%3d", magnitude);
+ Q_snprintf(buf, sizeof(buf), "%3d", magnitude);
kvd.szKeyName = "iMagnitude";
kvd.szValue = buf;
diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp
index 4ab375d8b..789435938 100644
--- a/regamedll/dlls/game.cpp
+++ b/regamedll/dlls/game.cpp
@@ -178,6 +178,15 @@ cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0,
cvar_t dying_time = { "mp_dying_time", "3.0", 0, 3.0f, nullptr };
cvar_t defuser_allocation = { "mp_defuser_allocation", "0", 0, 0.0f, nullptr };
+cvar_t location_area_info = { "mp_location_area_info", "0", 0, 0.0f, nullptr };
+cvar_t chat_loc_fallback = { "mp_chat_loc_fallback", "1", 1, 0.0f, nullptr };
+
+cvar_t item_respawn_time = { "mp_item_respawn_time", "30", FCVAR_SERVER, 30.0f, nullptr };
+cvar_t weapon_respawn_time = { "mp_weapon_respawn_time", "20", FCVAR_SERVER, 20.0f, nullptr };
+cvar_t ammo_respawn_time = { "mp_ammo_respawn_time", "20", FCVAR_SERVER, 20.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 };
void GameDLL_Version_f()
{
@@ -441,6 +450,15 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&freezetime_duck);
CVAR_REGISTER(&freezetime_jump);
CVAR_REGISTER(&defuser_allocation);
+ CVAR_REGISTER(&location_area_info);
+ CVAR_REGISTER(&chat_loc_fallback);
+
+ CVAR_REGISTER(&item_respawn_time);
+ CVAR_REGISTER(&weapon_respawn_time);
+ CVAR_REGISTER(&ammo_respawn_time);
+
+ CVAR_REGISTER(&vote_flags);
+ CVAR_REGISTER(&votemap_min_time);
// print version
CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n");
diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h
index 706e1c2af..09da5305a 100644
--- a/regamedll/dlls/game.h
+++ b/regamedll/dlls/game.h
@@ -201,6 +201,13 @@ extern cvar_t assist_damage_threshold;
extern cvar_t freezetime_duck;
extern cvar_t freezetime_jump;
extern cvar_t defuser_allocation;
+extern cvar_t location_area_info;
+extern cvar_t chat_loc_fallback;
+extern cvar_t item_respawn_time;
+extern cvar_t weapon_respawn_time;
+extern cvar_t ammo_respawn_time;
+extern cvar_t vote_flags;
+extern cvar_t votemap_min_time;
#endif
diff --git a/regamedll/dlls/gamerules.cpp b/regamedll/dlls/gamerules.cpp
index 45210e212..3d9f14182 100644
--- a/regamedll/dlls/gamerules.cpp
+++ b/regamedll/dlls/gamerules.cpp
@@ -8,8 +8,8 @@ CGameRules::CGameRules()
m_bBombDropped = FALSE;
m_bGameOver = false;
- m_GameDesc = new char[sizeof("Counter-Strike")];
- Q_strcpy(m_GameDesc, AreRunningCZero() ? "Condition Zero" : "Counter-Strike");
+ const char *pszGameDesc = AreRunningCZero() ? "Condition Zero" : "Counter-Strike";
+ m_GameDesc = CloneString(pszGameDesc);
}
CGameRules::~CGameRules()
diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h
index e7dc35085..220e09556 100644
--- a/regamedll/dlls/gamerules.h
+++ b/regamedll/dlls/gamerules.h
@@ -31,28 +31,29 @@
#include "game_shared/voice_gamemgr.h"
#include "cmdhandler.h"
-const int MAX_RULE_BUFFER = 1024;
-const int MAX_VOTE_MAPS = 100;
-const int MAX_VIP_QUEUES = 5;
-const int MAX_MONEY_THRESHOLD = 999999; // allowable money limit in the game that can be drawn on the HUD
-
-const int MAX_MOTD_CHUNK = 60;
-const int MAX_MOTD_LENGTH = 1536; // (MAX_MOTD_CHUNK * 4)
-
-const float ITEM_RESPAWN_TIME = 30.0f;
-const float WEAPON_RESPAWN_TIME = 20.0f;
-const float AMMO_RESPAWN_TIME = 20.0f;
-const float ROUND_RESPAWN_TIME = 20.0f;
-const float ROUND_BEGIN_DELAY = 5.0f; // delay before beginning new round
-const float ITEM_KILL_DELAY = 300.0f;
-const float RADIO_TIMEOUT = 1.5f;
+const int MAX_RULE_BUFFER = 1024;
+const int MAX_VOTE_MAPS = 100;
+const int MAX_VIP_QUEUES = 5;
+const int MAX_MONEY_THRESHOLD = 999999; // allowable money limit in the game that can be drawn on the HUD
+
+const int MAX_MOTD_CHUNK = 60;
+const int MAX_MOTD_LENGTH = 1536; // (MAX_MOTD_CHUNK * 4)
+
+const float ITEM_RESPAWN_TIME = 30.0f;
+const float WEAPON_RESPAWN_TIME = 20.0f;
+const float AMMO_RESPAWN_TIME = 20.0f;
+const float ROUND_RESPAWN_TIME = 20.0f;
+const float ROUND_BEGIN_DELAY = 5.0f; // delay before beginning new round
+const float ITEM_KILL_DELAY = 300.0f;
+const float RADIO_TIMEOUT = 1.5f;
const float DEATH_ANIMATION_TIME = 3.0f;
+const float VOTEMAP_MIN_TIME = 180.0f;
-const int MAX_INTERMISSION_TIME = 120; // longest the intermission can last, in seconds
+const int MAX_INTERMISSION_TIME = 120; // longest the intermission can last, in seconds
// when we are within this close to running out of entities, items
// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn
-const int ENTITY_INTOLERANCE = 100;
+const int ENTITY_INTOLERANCE = 100;
enum
{
@@ -252,7 +253,8 @@ enum KillRarity
KILLRARITY_ASSISTEDFLASH = 0x020, // Assister helped with a flash
KILLRARITY_DOMINATION_BEGAN = 0x040, // Killer player began dominating the victim (NOTE: this flag is set once)
KILLRARITY_DOMINATION = 0x080, // Continues domination by the killer
- KILLRARITY_REVENGE = 0x100 // Revenge by the killer
+ KILLRARITY_REVENGE = 0x100, // Revenge by the killer
+ KILLRARITY_INAIR = 0x200 // Killer was in the air (skill to deal with high inaccuracy)
};
enum
@@ -380,6 +382,7 @@ class CGameRules
static float GetItemKillDelay();
static float GetRadioTimeout();
static float GetDyingTime();
+ static float GetVotemapMinElapsedTime();
public:
BOOL m_bFreezePeriod; // TRUE at beginning of round, set to FALSE when the period expires
@@ -741,7 +744,7 @@ class CHalfLifeMultiplay: public CGameRules
VFUNC bool HasRoundTimeExpired();
VFUNC bool IsBombPlanted();
- void SendDeathMessage(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, entvars_t *pevInflictor, const char *killerWeaponName, int iDeathMessageFlags, int iRarityOfKill);
+ VFUNC void SendDeathMessage(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, entvars_t *pevInflictor, const char *killerWeaponName, int iDeathMessageFlags, int iRarityOfKill);
int GetRarityOfKill(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, const char *killerWeaponName, bool bFlashAssist);
CBasePlayer *CheckAssistsToKill(CBaseEntity *pKiller, CBasePlayer *pVictim, bool &bFlashAssist);
@@ -985,6 +988,15 @@ inline float CGameRules::GetDyingTime()
#endif
}
+inline float CGameRules::GetVotemapMinElapsedTime()
+{
+#ifdef REGAMEDLL_ADD
+ return votemap_min_time.value;
+#else
+ return VOTEMAP_MIN_TIME;
+#endif
+}
+
bool IsBotSpeaking();
void SV_Continue_f();
void SV_Tutor_Toggle_f();
@@ -997,5 +1009,4 @@ char *GetTeam(int team);
void DestroyMapCycle(mapcycle_t *cycle);
int ReloadMapCycleFile(char *filename, mapcycle_t *cycle);
int CountPlayers();
-void ExtractCommandString(char *s, char *szCommand);
int GetMapCount();
diff --git a/regamedll/dlls/hostage/hostage.cpp b/regamedll/dlls/hostage/hostage.cpp
index c9ff79725..7ef34b222 100644
--- a/regamedll/dlls/hostage/hostage.cpp
+++ b/regamedll/dlls/hostage/hostage.cpp
@@ -1242,7 +1242,7 @@ void CHostage::SendHostagePositionMsg()
if (!pEntity->IsPlayer())
continue;
- if (pEntity->pev->flags == FL_DORMANT)
+ if (pEntity->IsDormant())
continue;
CBasePlayer *pTempPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
@@ -1271,7 +1271,7 @@ void CHostage::SendHostageEventMsg()
if (!pEntity->IsPlayer())
continue;
- if (pEntity->pev->flags == FL_DORMANT)
+ if (pEntity->IsDormant())
continue;
CBasePlayer *pTempPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
diff --git a/regamedll/dlls/hostage/hostage_improv.cpp b/regamedll/dlls/hostage/hostage_improv.cpp
index a70d2c76a..6932d2185 100644
--- a/regamedll/dlls/hostage/hostage_improv.cpp
+++ b/regamedll/dlls/hostage/hostage_improv.cpp
@@ -358,10 +358,7 @@ bool CHostageImprov::IsFriendInTheWay(const Vector &goalPos) const
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (!pPlayer->IsAlive() || pPlayer->m_iTeam == TERRORIST)
@@ -675,10 +672,7 @@ void CHostageImprov::UpdateVision()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -1611,9 +1605,9 @@ void CHostageImprov::Afraid()
int which = RANDOM_LONG(0, 100) % 3 + 1;
- Q_sprintf(animInto, "cower_into_%d", which);
- Q_sprintf(animLoop, "cower_loop_%d", which);
- Q_sprintf(animExit, "cower_exit_%d", which);
+ Q_snprintf(animInto, sizeof(animInto), "cower_into_%d", which);
+ Q_snprintf(animLoop, sizeof(animLoop), "cower_loop_%d", which);
+ Q_snprintf(animExit, sizeof(animExit), "cower_exit_%d", which);
m_animateState.AddSequence(this, animInto);
m_animateState.AddSequence(this, animLoop, RANDOM_FLOAT(3, 10));
diff --git a/regamedll/dlls/items.cpp b/regamedll/dlls/items.cpp
index 03620e362..ba138e044 100644
--- a/regamedll/dlls/items.cpp
+++ b/regamedll/dlls/items.cpp
@@ -237,7 +237,7 @@ BOOL CItemBattery::MyTouch(CBasePlayer *pPlayer)
pct--;
char szcharge[64];
- Q_sprintf(szcharge, "!HEV_%1dP", pct);
+ Q_snprintf(szcharge, sizeof(szcharge), "!HEV_%1dP", pct);
pPlayer->SetSuitUpdate(szcharge, SUIT_SENTENCE, SUIT_NEXT_IN_30SEC);
return TRUE;
diff --git a/regamedll/dlls/lights.cpp b/regamedll/dlls/lights.cpp
index d44cddcc1..aa8629ea0 100644
--- a/regamedll/dlls/lights.cpp
+++ b/regamedll/dlls/lights.cpp
@@ -129,11 +129,11 @@ void CEnvLight::KeyValue(KeyValueData *pkvd)
pkvd->fHandled = TRUE;
char szColor[64];
- Q_sprintf(szColor, "%d", r);
+ Q_snprintf(szColor, sizeof(szColor), "%d", r);
CVAR_SET_STRING("sv_skycolor_r", szColor);
- Q_sprintf(szColor, "%d", g);
+ Q_snprintf(szColor, sizeof(szColor), "%d", g);
CVAR_SET_STRING("sv_skycolor_g", szColor);
- Q_sprintf(szColor, "%d", b);
+ Q_snprintf(szColor, sizeof(szColor), "%d", b);
CVAR_SET_STRING("sv_skycolor_b", szColor);
}
else
@@ -147,13 +147,13 @@ void CEnvLight::Spawn()
char szVector[64];
UTIL_MakeAimVectors(pev->angles);
- Q_sprintf(szVector, "%f", gpGlobals->v_forward.x);
+ Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.x);
CVAR_SET_STRING("sv_skyvec_x", szVector);
- Q_sprintf(szVector, "%f", gpGlobals->v_forward.y);
+ Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.y);
CVAR_SET_STRING("sv_skyvec_y", szVector);
- Q_sprintf(szVector, "%f", gpGlobals->v_forward.z);
+ Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.z);
CVAR_SET_STRING("sv_skyvec_z", szVector);
CLight::Spawn();
diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp
index e0d27dfb2..7a84afd46 100644
--- a/regamedll/dlls/multiplay_gamerules.cpp
+++ b/regamedll/dlls/multiplay_gamerules.cpp
@@ -34,7 +34,10 @@ bool IsBotSpeaking()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || !pPlayer->IsBot())
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!pPlayer->IsBot())
continue;
CCSBot *pBot = static_cast(pPlayer);
@@ -175,15 +178,12 @@ bool CCStrikeGameMgrHelper::GetCanHearPlayer(CBasePlayer* pListener, CBasePlayer
void Broadcast(const char *sentence)
{
- char text[32];
+ char text[128];
if (!sentence)
- {
return;
- }
- Q_strcpy(text, "%!MRAD_");
- Q_strcat(text, UTIL_VarArgs("%s", sentence));
+ Q_snprintf(text, sizeof(text), "%%!MRAD_%s", sentence);
MESSAGE_BEGIN(MSG_BROADCAST, gmsgSendAudio);
WRITE_BYTE(0);
@@ -267,6 +267,10 @@ void CHalfLifeMultiplay::EndRoundMessage(const char *sentence, ScenarioEventEndR
}
UTIL_LogPrintf("World triggered \"Round_End\"\n");
+
+#ifdef REGAMEDLL_ADD
+ FireTargets("game_round_end", nullptr, nullptr, USE_TOGGLE, 0.0);
+#endif
}
void CHalfLifeMultiplay::ReadMultiplayCvars()
@@ -500,7 +504,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay()
char szCommand[256];
ALERT(at_console, "Executing listen server config file\n");
- Q_sprintf(szCommand, "exec %s\n", lservercfgfile);
+ Q_snprintf(szCommand, sizeof(szCommand), "exec %s\n", lservercfgfile);
SERVER_COMMAND(szCommand);
}
}
@@ -648,6 +652,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(CleanUpMap)()
UTIL_RestartOther("env_beam");
UTIL_RestartOther("env_laser");
UTIL_RestartOther("trigger_auto");
+ UTIL_RestartOther("trigger_multiple");
#endif
// Remove grenades and C4
@@ -699,7 +704,7 @@ CBasePlayer *EXT_FUNC CHalfLifeMultiplay::__API_HOOK(GiveC4)()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || FNullEnt(pPlayer->edict()))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->pev->deadflag != DEAD_NO || pPlayer->m_iTeam != TERRORIST)
@@ -1074,10 +1079,8 @@ bool EXT_FUNC CHalfLifeMultiplay::NeededPlayersCheck()
if (IsCareer())
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(gpGlobals->maxClients);
- if (!pPlayer || !pPlayer->IsBot())
- {
+ if (!UTIL_IsValidPlayer(pPlayer) || !pPlayer->IsBot())
return true;
- }
}
return OnRoundEnd_Intercept(WINSTATUS_DRAW, ROUND_GAME_COMMENCE, IsCareer() ? 0 : 3);
@@ -1810,10 +1813,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)()
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer && !FNullEnt(pPlayer->pev))
- {
- pPlayer->Reset();
- }
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ pPlayer->Reset();
}
if (TheBots)
@@ -1981,7 +1985,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)()
if (FNullEnt(pEntity->edict()))
break;
- if (pEntity->pev->flags == FL_DORMANT)
+ if (pEntity->IsDormant())
continue;
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
@@ -2092,12 +2096,17 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)()
BOOL CHalfLifeMultiplay::IsThereABomber()
{
- CBasePlayer *pPlayer = nullptr;
- while ((pPlayer = UTIL_FindEntityByClassname(pPlayer, "player")))
+ CBaseEntity *pEntity = nullptr;
+ while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player")))
{
- if (FNullEnt(pPlayer->edict()))
+ if (FNullEnt(pEntity->edict()))
break;
+ if (pEntity->IsDormant())
+ continue;
+
+ CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
+
if (pPlayer->m_iTeam != CT && pPlayer->IsBombGuy())
{
// There you are.
@@ -2512,7 +2521,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(Think)()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer && !pPlayer->IsBot())
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!pPlayer->IsBot())
{
MESSAGE_BEGIN(MSG_ONE, gmsgCZCareerHUD, nullptr, pPlayer->pev);
WRITE_STRING("ROUND");
@@ -2722,9 +2734,9 @@ bool CHalfLifeMultiplay::CheckFragLimit()
// check if any player is over the frag limit
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
- auto pPlayer = UTIL_PlayerByIndex(i);
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || pPlayer->has_disconnected)
+ if (!UTIL_IsValidPlayer(pPlayer) || pPlayer->has_disconnected)
continue;
if (pPlayer->pev->frags >= fraglimit.value)
@@ -2817,9 +2829,15 @@ void EXT_FUNC CHalfLifeMultiplay::OnRoundFreezeEnd()
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *plr = UTIL_PlayerByIndex(i);
- if (!plr || plr->pev->flags == FL_DORMANT)
+
+ if (!UTIL_IsValidPlayer(plr))
continue;
+#ifndef REGAMEDLL_FIXES
+ if (plr->pev->flags == FL_DORMANT)
+ continue;
+#endif
+
if (plr->m_iJoiningState == JOINED)
{
if (plr->m_iTeam == CT && !bCTPlayed)
@@ -2852,6 +2870,10 @@ void EXT_FUNC CHalfLifeMultiplay::OnRoundFreezeEnd()
{
TheCareerTasks->HandleEvent(EVENT_ROUND_START);
}
+
+#ifdef REGAMEDLL_ADD
+ FireTargets("game_round_freeze_end", nullptr, nullptr, USE_TOGGLE, 0.0);
+#endif
}
void CHalfLifeMultiplay::CheckFreezePeriodExpired()
@@ -3191,7 +3213,7 @@ void CHalfLifeMultiplay::MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound(int
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->m_iTeam == iTeam)
@@ -3229,7 +3251,7 @@ void CHalfLifeMultiplay::CareerRestart()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (!pPlayer->IsBot())
@@ -3430,13 +3452,9 @@ void CHalfLifeMultiplay::InitHUD(CBasePlayer *pl)
{
// FIXME: Probably don't need to cast this just to read m_iDeaths
CBasePlayer *plr = UTIL_PlayerByIndex(i);
- if (!plr)
+ if (!UTIL_IsValidPlayer(plr))
continue;
-#ifdef REGAMEDLL_FIXES
- if (plr->IsDormant())
- continue;
-#endif
MESSAGE_BEGIN(MSG_ONE, gmsgScoreInfo, nullptr, pl->edict());
WRITE_BYTE(i); // client number
WRITE_SHORT(int(plr->pev->frags));
@@ -3475,13 +3493,9 @@ void CHalfLifeMultiplay::InitHUD(CBasePlayer *pl)
for (i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *plr = UTIL_PlayerByIndex(i);
- if (!plr)
- continue;
-#ifdef REGAMEDLL_FIXES
- if (plr->IsDormant())
+ if (!UTIL_IsValidPlayer(plr))
continue;
-#endif
MESSAGE_BEGIN(MSG_ONE, gmsgTeamInfo, nullptr, pl->edict());
WRITE_BYTE(plr->entindex());
@@ -3493,7 +3507,7 @@ void CHalfLifeMultiplay::InitHUD(CBasePlayer *pl)
if (pl->entindex() != i)
{
#ifndef REGAMEDLL_FIXES
- if (plr->pev->flags == FL_DORMANT)
+ if (plr->IsDormant())
continue;
#endif
if (plr->pev->deadflag == DEAD_NO
@@ -3654,6 +3668,9 @@ void CHalfLifeMultiplay::ClientDisconnected(edict_t *pClient)
if (!pObserver->pev || pObserver == pPlayer)
continue;
+ if (pObserver->IsDormant())
+ continue;
+
// If a spectator was chasing this player, move him/her onto the next player
if (pObserver->m_hObserverTarget == pPlayer)
{
@@ -4121,6 +4138,16 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim,
iDeathMessageFlags |= PLAYERDEATH_KILLRARITY;
}
+#ifdef REGAMEDLL_ADD
+ iDeathMessageFlags &= UTIL_ReadFlags(deathmsg_flags.string); // leave only allowed bitsums for extra info
+
+ // Send the victim's death position only
+ // 1. if it is not a free for all mode
+ // 2. if the attacker is a player and they are not teammates
+ if (IsFreeForAll() || !pKiller || PlayerRelationship(pKiller, pVictim) == GR_TEAMMATE)
+ iDeathMessageFlags &= ~PLAYERDEATH_POSITION; // do not send a position
+#endif
+
SendDeathMessage(pKiller, pVictim, pAssister, pevInflictor, killer_weapon_name, iDeathMessageFlags, iRarityOfKill);
// Updates the stats of who has killed whom
@@ -4191,7 +4218,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerGotWeapon)(CBasePlayer *pPlay
// What is the time in the future at which this weapon may spawn?
float CHalfLifeMultiplay::FlWeaponRespawnTime(CBasePlayerItem *pWeapon)
{
+#ifdef REGAMEDLL_ADD
+ return gpGlobals->time + weapon_respawn_time.value;
+#else
return gpGlobals->time + WEAPON_RESPAWN_TIME;
+#endif
}
// Returns 0 if the weapon can respawn now,
@@ -4259,7 +4290,11 @@ int CHalfLifeMultiplay::ItemShouldRespawn(CItem *pItem)
// At what time in the future may this Item respawn?
float CHalfLifeMultiplay::FlItemRespawnTime(CItem *pItem)
{
+#ifdef REGAMEDLL_ADD
+ return gpGlobals->time + item_respawn_time.value;
+#else
return gpGlobals->time + ITEM_RESPAWN_TIME;
+#endif
}
// Where should this item respawn?
@@ -4291,7 +4326,11 @@ int CHalfLifeMultiplay::AmmoShouldRespawn(CBasePlayerAmmo *pAmmo)
float CHalfLifeMultiplay::FlAmmoRespawnTime(CBasePlayerAmmo *pAmmo)
{
- return gpGlobals->time + 20.0f;
+#ifdef REGAMEDLL_ADD
+ return gpGlobals->time + ammo_respawn_time.value;
+#else
+ return gpGlobals->time + AMMO_RESPAWN_TIME;
+#endif
}
Vector CHalfLifeMultiplay::VecAmmoRespawnSpot(CBasePlayerAmmo *pAmmo)
@@ -4512,12 +4551,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle)
if (Q_strlen(pToken) <= 0)
break;
-#ifdef REGAMEDLL_FIXES
- Q_strncpy(szMap, pToken, sizeof(szMap) - 1);
- szMap[sizeof(szMap) - 1] = '\0';
-#else
- Q_strcpy(szMap, pToken);
-#endif
+ Q_strlcpy(szMap, pToken);
// Any more tokens on this line?
if (SharedTokenWaiting(pFileList))
@@ -4526,7 +4560,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle)
if (Q_strlen(pToken) > 0)
{
hasBuffer = true;
- Q_strcpy(szBuffer, pToken);
+ Q_strlcpy(szBuffer, pToken);
}
}
@@ -4538,7 +4572,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle)
item = new mapcycle_item_s;
- Q_strcpy(item->mapname, szMap);
+ Q_strlcpy(item->mapname, szMap);
item->minplayers = 0;
item->maxplayers = 0;
@@ -4568,7 +4602,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle)
REMOVE_KEY_VALUE(szBuffer, "minplayers");
REMOVE_KEY_VALUE(szBuffer, "maxplayers");
- Q_strcpy(item->rulebuffer, szBuffer);
+ Q_strlcpy(item->rulebuffer, szBuffer);
}
item->next = cycle->items;
@@ -4622,17 +4656,18 @@ int CountPlayers()
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer)
- {
- nCount++;
- }
+
+ if (!UTIL_IsValidPlayer(pPlayer) || pPlayer->IsBot())
+ continue;
+
+ nCount++;
}
return nCount;
}
// Parse commands/key value pairs to issue right after map xxx command is issued on server level transition
-void ExtractCommandString(char *s, char *szCommand)
+void ExtractCommandString(char *s, char *szCommand, size_t len)
{
// Now make rules happen
char pkey[512];
@@ -4701,13 +4736,13 @@ void ExtractCommandString(char *s, char *szCommand)
*c = '\0';
- Q_strcat(szCommand, pkey);
+ Q_strlcat(szCommand, pkey, len);
if (Q_strlen(value) > 0)
{
- Q_strcat(szCommand, " ");
- Q_strcat(szCommand, value);
+ Q_strlcat(szCommand, " ", len);
+ Q_strlcat(szCommand, value, len);
}
- Q_strcat(szCommand, "\n");
+ Q_strlcat(szCommand, "\n", len);
/*if (!*s)
{
@@ -4727,6 +4762,9 @@ void CHalfLifeMultiplay::ResetAllMapVotes()
if (FNullEnt(pEntity->edict()))
break;
+ if (pEntity->IsDormant())
+ continue;
+
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
if (pPlayer->m_iTeam != UNASSIGNED)
{
@@ -4830,6 +4868,9 @@ void CHalfLifeMultiplay::ProcessMapVote(CBasePlayer *pPlayer, int iVote)
if (FNullEnt(pEntity->edict()))
break;
+ if (pEntity->IsDormant())
+ continue;
+
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
if (pPlayer->m_iTeam != UNASSIGNED)
@@ -4888,10 +4929,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)()
#ifdef REGAMEDLL_FIXES
// the absolute default level is de_dust
- Q_strcpy(szFirstMapInList, "de_dust");
+ Q_strlcpy(szFirstMapInList, "de_dust");
#else
// the absolute default level is hldm1
- Q_strcpy(szFirstMapInList, "hldm1");
+ Q_strlcpy(szFirstMapInList, "hldm1");
#endif
int curplayers;
@@ -4909,7 +4950,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)()
// Has the map cycle filename changed?
if (Q_stricmp(mapcfile, szPreviousMapCycleFile) != 0)
{
- Q_strcpy(szPreviousMapCycleFile, mapcfile);
+ Q_strlcpy(szPreviousMapCycleFile, mapcfile);
DestroyMapCycle(&mapcycle);
@@ -4927,8 +4968,8 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)()
mapcycle_item_s *item;
// Assume current map
- Q_strcpy(szNextMap, STRING(gpGlobals->mapname));
- Q_strcpy(szFirstMapInList, STRING(gpGlobals->mapname));
+ Q_strlcpy(szNextMap, STRING(gpGlobals->mapname));
+ Q_strlcpy(szFirstMapInList, STRING(gpGlobals->mapname));
// Traverse list
for (item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next)
@@ -4981,14 +5022,14 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)()
mapcycle.next_item = item->next;
// Perform logic on current item
- Q_strcpy(szNextMap, item->mapname);
- ExtractCommandString(item->rulebuffer, szCommands);
- Q_strcpy(szRules, item->rulebuffer);
+ Q_strlcpy(szNextMap, item->mapname);
+ ExtractCommandString(item->rulebuffer, szCommands, sizeof(szCommands));
+ Q_strlcpy(szRules, item->rulebuffer);
}
if (!IS_MAP_VALID(szNextMap))
{
- Q_strcpy(szNextMap, szFirstMapInList);
+ Q_strlcpy(szNextMap, szFirstMapInList);
}
m_bGameOver = true;
@@ -5028,17 +5069,7 @@ void CHalfLifeMultiplay::SendMOTDToClient(edict_t *client)
while (pFileList && *pFileList && char_count < MAX_MOTD_LENGTH)
{
char chunk[MAX_MOTD_CHUNK + 1];
-
- if (Q_strlen(pFileList) < sizeof(chunk))
- {
- Q_strcpy(chunk, pFileList);
- }
- else
- {
- Q_strncpy(chunk, pFileList, sizeof(chunk) - 1);
- // Q_strncpy doesn't always append the null terminator
- chunk[sizeof(chunk) - 1] = '\0';
- }
+ Q_strlcpy(chunk, pFileList);
char_count += Q_strlen(chunk);
@@ -5209,7 +5240,7 @@ CBasePlayer *CHalfLifeMultiplay::CheckAssistsToKill(CBaseEntity *pKiller, CBaseP
continue; // dealt no damage
CBasePlayer *pAttackerPlayer = UTIL_PlayerByIndex(i);
- if (!pAttackerPlayer || pAttackerPlayer->IsDormant())
+ if (!UTIL_IsValidPlayer(pAttackerPlayer))
continue; // ignore idle clients
CCSPlayer *pCSAttackerPlayer = pAttackerPlayer->CSPlayer();
@@ -5271,20 +5302,19 @@ int CHalfLifeMultiplay::GetRarityOfKill(CBaseEntity *pKiller, CBasePlayer *pVict
if (pVictim->m_bHeadshotKilled)
iRarity |= KILLRARITY_HEADSHOT;
- // The killer player was blind
CBasePlayer *pKillerPlayer = static_cast(pKiller);
- if (pKillerPlayer && pKillerPlayer->IsPlayer())
+ if (pKillerPlayer && pKillerPlayer->IsPlayer() && pKillerPlayer != pVictim)
{
WeaponClassType weaponClass = AliasToWeaponClass(killerWeaponName);
- if (pKillerPlayer != pVictim
- && weaponClass != WEAPONCLASS_NONE
- && weaponClass != WEAPONCLASS_KNIFE
- && weaponClass != WEAPONCLASS_GRENADE)
+ if (weaponClass != WEAPONCLASS_NONE &&
+ weaponClass != WEAPONCLASS_KNIFE &&
+ weaponClass != WEAPONCLASS_GRENADE)
{
// The killer player kills the victim through the walls
if (pVictim->GetDmgPenetrationLevel() > 0)
iRarity |= KILLRARITY_PENETRATED;
+ // The killer player was blind
if (pKillerPlayer->IsFullyBlind())
iRarity |= KILLRARITY_KILLER_BLIND;
@@ -5296,6 +5326,10 @@ int CHalfLifeMultiplay::GetRarityOfKill(CBaseEntity *pKiller, CBasePlayer *pVict
const Vector inEyePos = pKillerPlayer->EyePosition();
if (TheCSBots()->IsLineBlockedBySmoke(&inEyePos, &pVictim->pev->origin))
iRarity |= KILLRARITY_THRUSMOKE;
+
+ // The killer player kills the victim while in air
+ if (!(pKillerPlayer->pev->flags & FL_ONGROUND))
+ iRarity |= KILLRARITY_INAIR;
}
// Calculate # of unanswered kills between killer & victim
@@ -5308,6 +5342,10 @@ int CHalfLifeMultiplay::GetRarityOfKill(CBaseEntity *pKiller, CBasePlayer *pVict
int iKillsUnanswered = pVictim->CSPlayer()->m_iNumKilledByUnanswered[iAttackerEntityIndex - 1] + 1;
if (iKillsUnanswered == CS_KILLS_FOR_DOMINATION || pKillerPlayer->CSPlayer()->IsPlayerDominated(pVictim->entindex() - 1))
{
+ // Sets the beginning of domination over the victim until he takes revenge
+ if (iKillsUnanswered == CS_KILLS_FOR_DOMINATION)
+ iRarity |= KILLRARITY_DOMINATION_BEGAN;
+
// this is the Nth unanswered kill between killer and victim, killer is now dominating victim
iRarity |= KILLRARITY_DOMINATION;
@@ -5343,32 +5381,13 @@ LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN(CHalfLifeMultiplay, CSGameRules, SendDeathMess
//
void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(SendDeathMessage)(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, entvars_t *pevInflictor, const char *killerWeaponName, int iDeathMessageFlags, int iRarityOfKill)
{
- CBasePlayer *pKillerPlayer = (pKiller && pKiller->IsPlayer()) ? static_cast(pKiller) : nullptr;
-
- // Only the player can dominate the victim
- if ((iRarityOfKill & KILLRARITY_DOMINATION) && pKillerPlayer && pVictim != pKillerPlayer)
- {
- // Sets the beginning of domination over the victim until he takes revenge
- int iKillsUnanswered = pVictim->CSPlayer()->m_iNumKilledByUnanswered[pKillerPlayer->entindex() - 1] + 1;
- if (iKillsUnanswered == CS_KILLS_FOR_DOMINATION)
- iRarityOfKill |= KILLRARITY_DOMINATION_BEGAN;
- }
-
MESSAGE_BEGIN(MSG_ALL, gmsgDeathMsg);
WRITE_BYTE((pKiller && pKiller->IsPlayer()) ? pKiller->entindex() : 0); // the killer
WRITE_BYTE(pVictim->entindex()); // the victim
- WRITE_BYTE(pVictim->m_bHeadshotKilled); // is killed headshot
+ WRITE_BYTE((iRarityOfKill & KILLRARITY_HEADSHOT)); // is killed headshot
WRITE_STRING(killerWeaponName); // what they were killed by (should this be a string?)
#ifdef REGAMEDLL_ADD
- iDeathMessageFlags &= UTIL_ReadFlags(deathmsg_flags.string); // leave only allowed bitsums for extra info
-
- // Send the victim's death position only
- // 1. if it is not a free for all mode
- // 2. if the attacker is a player and they are not teammates
- if (IsFreeForAll() || !pKillerPlayer || PlayerRelationship(pKillerPlayer, pVictim) == GR_TEAMMATE)
- iDeathMessageFlags &= ~PLAYERDEATH_POSITION; // do not send a position
-
if (iDeathMessageFlags > 0)
{
WRITE_LONG(iDeathMessageFlags);
@@ -5384,7 +5403,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(SendDeathMessage)(CBaseEntity *pKil
// Writes the index of the teammate who assisted in the kill
if (iDeathMessageFlags & PLAYERDEATH_ASSISTANT)
- WRITE_BYTE(pAssister->entindex());
+ WRITE_BYTE((pAssister && pAssister->IsPlayer()) ? pAssister->entindex() : 0);
// Writes the rarity classification of the kill
if (iDeathMessageFlags & PLAYERDEATH_KILLRARITY)
@@ -5405,7 +5424,7 @@ void CHalfLifeMultiplay::GiveDefuserToRandomPlayer()
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || FNullEnt(pPlayer->edict()))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (!pPlayer->IsAlive() || pPlayer->m_iTeam != CT)
@@ -5439,9 +5458,9 @@ void CHalfLifeMultiplay::GiveDefuserToRandomPlayer()
for (int i = 0; i < iDefusersToGive && i < candidates.Count(); ++i)
{
CBasePlayer *pPlayer = candidates[i];
- assert(pPlayer && pPlayer->m_iTeam == CT && pPlayer->IsAlive());
+ DbgAssert(pPlayer && pPlayer->m_iTeam == CT && pPlayer->IsAlive());
pPlayer->GiveDefuser();
- ClientPrint(pPlayer->pev, HUD_PRINTCENTER, "#Got_defuser");
+ pPlayer->HintMessage("#Got_defuser", FALSE, TRUE);
}
}
diff --git a/regamedll/dlls/observer.cpp b/regamedll/dlls/observer.cpp
index 4b3521a6c..3ccefc433 100644
--- a/regamedll/dlls/observer.cpp
+++ b/regamedll/dlls/observer.cpp
@@ -480,14 +480,14 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_SetMode)(int iMode)
{
#ifdef REGAMEDLL_FIXES
m_hObserverTarget = Observer_IsValidTarget( ENTINDEX(m_hObserverTarget->edict()), forcecamera != CAMERA_MODE_SPEC_ANYONE );
-#else
+#else
CBasePlayer *pTarget = m_hObserverTarget;
- if (pTarget == this
- || !pTarget
- || pTarget->has_disconnected
- || pTarget->GetObserverMode() != OBS_NONE
- || (pTarget->pev->effects & EF_NODRAW)
+ if (pTarget == this
+ || !pTarget
+ || pTarget->has_disconnected
+ || pTarget->GetObserverMode() != OBS_NONE
+ || (pTarget->pev->effects & EF_NODRAW)
|| (forcecamera != CAMERA_MODE_SPEC_ANYONE && pTarget->m_iTeam != m_iTeam))
m_hObserverTarget = nullptr;
#endif
@@ -534,7 +534,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_SetMode)(int iMode)
// print spepctaor mode on client screen
char modemsg[16];
- Q_sprintf(modemsg, "#Spec_Mode%i", pev->iuser1);
+ Q_snprintf(modemsg, sizeof(modemsg), "#Spec_Mode%i", pev->iuser1);
ClientPrint(pev, HUD_PRINTCENTER, modemsg);
m_iObserverLastMode = iMode;
@@ -548,4 +548,4 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_Think)()
Observer_HandleButtons();
Observer_CheckTarget();
Observer_CheckProperties();
-}
\ No newline at end of file
+}
diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp
index 06c550890..8ece842e2 100644
--- a/regamedll/dlls/player.cpp
+++ b/regamedll/dlls/player.cpp
@@ -332,7 +332,10 @@ CBasePlayer *CBasePlayer::GetNextRadioRecipient(CBasePlayer *pStartPlayer)
continue;
CBasePlayer *pTarget = CBasePlayer::Instance(pPlayer->m_hObserverTarget->pev);
- if (pTarget && pTarget->m_iTeam == m_iTeam)
+ if (!pTarget || pTarget->IsDormant())
+ continue;
+
+ if (pTarget->m_iTeam == m_iTeam)
{
bSend = true;
}
@@ -365,6 +368,9 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Radio)(const char *msg_id, const char *msg
if (FNullEnt(pEntity->edict()))
break;
+ if (pEntity->IsDormant())
+ continue;
+
bool bSend = false;
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
@@ -382,7 +388,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Radio)(const char *msg_id, const char *msg
continue;
// is this player on our team? (even dead players hear our radio calls)
- if (pPlayer->m_iTeam == m_iTeam)
+ if (g_pGameRules->PlayerRelationship(this, pPlayer) == GR_TEAMMATE)
bSend = true;
}
// this means we're a spectator
@@ -396,7 +402,11 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Radio)(const char *msg_id, const char *msg
if (FNullEnt(pPlayer->m_hObserverTarget))
continue;
- if (pPlayer->m_hObserverTarget && pPlayer->m_hObserverTarget->m_iTeam == m_iTeam)
+ CBasePlayer *pTarget = CBasePlayer::Instance(pPlayer->m_hObserverTarget->pev);
+ if (!pTarget || pTarget->IsDormant())
+ continue;
+
+ if (g_pGameRules->PlayerRelationship(this, pTarget) == GR_TEAMMATE)
{
bSend = true;
}
@@ -411,11 +421,15 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Radio)(const char *msg_id, const char *msg
MESSAGE_END();
// radio message icon
- if (msg_verbose)
+ if (msg_verbose && msg_verbose[0] != 0)
{
// search the place name where is located the player
const char *placeName = nullptr;
- if (AreRunningCZero() && TheBotPhrases)
+ if ((
+#ifdef REGAMEDLL_ADD
+ location_area_info.value >= 2 ||
+#endif
+ AreRunningCZero()) && TheBotPhrases)
{
Place playerPlace = TheNavAreaGrid.GetPlace(&pev->origin);
const BotPhraseList *placeList = TheBotPhrases->GetPlaceList();
@@ -427,11 +441,25 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Radio)(const char *msg_id, const char *msg
break;
}
}
+
+ if (!placeName)
+ placeName = TheNavAreaGrid.IDToName(playerPlace);
+ }
+
+ if (placeName && placeName[0])
+ {
+ bool bUseLocFallback = false;
+#ifdef REGAMEDLL_ADD
+ if (chat_loc_fallback.value)
+ bUseLocFallback = true;
+#endif
+
+ ClientPrint(pEntity->pev, HUD_PRINTRADIO, NumAsString(entindex()), bUseLocFallback ? "\x3%s1\x1 @ \x4%s2\x1 (RADIO): %s3" : "#Game_radio_location", STRING(pev->netname), placeName, msg_verbose);
}
- if (placeName)
- ClientPrint(pEntity->pev, HUD_PRINTRADIO, NumAsString(entindex()), "#Game_radio_location", STRING(pev->netname), placeName, msg_verbose);
else
+ {
ClientPrint(pEntity->pev, HUD_PRINTRADIO, NumAsString(entindex()), "#Game_radio", STRING(pev->netname), msg_verbose);
+ }
}
// icon over the head for teammates
@@ -1011,7 +1039,10 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || pPlayer->m_hObserverTarget != this)
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (pPlayer->m_hObserverTarget != this)
continue;
MESSAGE_BEGIN(MSG_ONE, gmsgSpecHealth, nullptr, pPlayer->edict());
@@ -1074,6 +1105,9 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva
if (FNullEnt(pEntity->edict()))
break;
+ if (pEntity->IsDormant())
+ continue;
+
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
if (pPlayer->m_iTeam == m_iTeam)
@@ -1260,7 +1294,7 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->m_hObserverTarget == this)
@@ -1715,7 +1749,9 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)()
#endif
}
-void CBasePlayer::RemoveAllItems(BOOL removeSuit)
+LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayer, RemoveAllItems, (BOOL removeSuit), removeSuit)
+
+void EXT_FUNC CBasePlayer::__API_HOOK(RemoveAllItems)(BOOL removeSuit)
{
int i;
@@ -1856,6 +1892,9 @@ void CBasePlayer::SetProgressBarTime(int time)
if (FNullEnt(pEntity->edict()))
break;
+ if (pEntity->IsDormant())
+ continue;
+
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
if (pPlayer->GetObserverMode() == OBS_IN_EYE && pPlayer->pev->iuser2 == playerIndex)
@@ -1896,6 +1935,9 @@ void CBasePlayer::SetProgressBarTime2(int time, float timeElapsed)
if (FNullEnt(pEntity->edict()))
break;
+ if (pEntity->IsDormant())
+ continue;
+
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
if (pPlayer->GetObserverMode() == OBS_IN_EYE && pPlayer->pev->iuser2 == playerIndex)
@@ -2168,7 +2210,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
bool killedByHumanPlayer = (!pPlayer->IsBot() && pPlayer->pev == pevAttacker && pPlayer->m_iTeam != m_iTeam);
@@ -2199,7 +2241,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib)
{
CBasePlayer *pObserver = UTIL_PlayerByIndex(i);
- if (!pObserver)
+ if (!UTIL_IsValidPlayer(pObserver))
continue;
if (pObserver->IsObservingPlayer(this))
@@ -2514,11 +2556,19 @@ BOOL CBasePlayer::IsBombGuy()
LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayer, SetAnimation, (PLAYER_ANIM playerAnim), playerAnim)
+int CBasePlayer::GetAnimDesired(const char *szAnim, AnimationType type)
+{
+ const char *refAnim = (type == ANIM_CROUCH && (pev->flags & FL_DUCKING)) ? "crouch_" : "ref_";
+
+ char szAnimConstruct[128];
+ Q_snprintf(szAnimConstruct, sizeof(szAnimConstruct), "%s%s_%s", refAnim, szAnim, m_szAnimExtention);
+ return LookupSequence(szAnimConstruct);
+}
+
void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
int animDesired;
float speed;
- char szAnim[64];
int hopSeq;
int leapSeq;
@@ -2654,16 +2704,17 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
if (m_Activity == m_IdealActivity)
return;
+ const char *refAnim;
+
switch (m_Activity)
{
- case ACT_RANGE_ATTACK1: Q_strcpy(szAnim, "ref_shoot_"); break;
- case ACT_RANGE_ATTACK2: Q_strcpy(szAnim, "ref_shoot2_"); break;
- case ACT_RELOAD: Q_strcpy(szAnim, "ref_reload_"); break;
- default: Q_strcpy(szAnim, "ref_aim_"); break;
+ case ACT_RANGE_ATTACK1: refAnim = "shoot"; break;
+ case ACT_RANGE_ATTACK2: refAnim = "shoot2"; break;
+ case ACT_RELOAD: refAnim = "reload"; break;
+ default: refAnim = "aim"; break;
}
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired(refAnim, ANIM_NORMAL);
if (animDesired == -1)
animDesired = 0;
@@ -2685,13 +2736,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
m_flLastFired = gpGlobals->time;
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_shoot_");
- else
- Q_strcpy(szAnim, "ref_shoot_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("shoot", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2706,13 +2751,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
m_flLastFired = gpGlobals->time;
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_shoot2_");
- else
- Q_strcpy(szAnim, "ref_shoot2_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("shoot2", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2725,13 +2764,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
}
case ACT_RELOAD:
{
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_reload_");
- else
- Q_strcpy(szAnim, "ref_reload_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("reload", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2746,13 +2779,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
}
case ACT_HOLDBOMB:
{
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_aim_");
- else
- Q_strcpy(szAnim, "ref_aim_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("aim", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2769,13 +2796,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
if (speed <= 135.0f || m_flLastFired + 4.0 >= gpGlobals->time)
{
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_aim_");
- else
- Q_strcpy(szAnim, "ref_aim_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("aim", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -2783,18 +2804,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
}
else
{
- Q_strcpy(szAnim, "run_");
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("run", ANIM_NORMAL);
if (animDesired == -1)
{
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_aim_");
- else
- Q_strcpy(szAnim, "ref_aim_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("aim", ANIM_CROUCH);
if (animDesired == -1)
animDesired = 0;
@@ -3044,20 +3057,9 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim)
{
if (m_Activity != ACT_FLINCH && m_Activity != ACT_LARGE_FLINCH)
{
- Q_strcpy(szAnim, "run_");
- Q_strcat(szAnim, m_szAnimExtention);
-
- animDesired = LookupSequence(szAnim);
+ animDesired = GetAnimDesired("run", ANIM_NORMAL);
if (animDesired == -1)
- {
- if (pev->flags & FL_DUCKING)
- Q_strcpy(szAnim, "crouch_aim_");
- else
- Q_strcpy(szAnim, "ref_aim_");
-
- Q_strcat(szAnim, m_szAnimExtention);
- animDesired = LookupSequence(szAnim);
- }
+ animDesired = GetAnimDesired("aim", ANIM_CROUCH);
else
pev->gaitsequence = animDesired;
@@ -4206,11 +4208,15 @@ void CBasePlayer::PlayerUse()
}
}
+ int caps;
+ int iClosestCaps = 0;
+
if (!pClosest)
{
while ((pObject = UTIL_FindEntityInSphere(pObject, pev->origin, MAX_PLAYER_USE_RADIUS)))
{
- if (pObject->ObjectCaps() & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE))
+ caps = pObject->ObjectCaps();
+ if (caps & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE))
{
// TODO: PERFORMANCE- should this check be done on a per case basis AFTER we've determined that
// this object is actually usable? This dot is being done for every object within PLAYER_SEARCH_RADIUS
@@ -4225,11 +4231,21 @@ void CBasePlayer::PlayerUse()
{
flMaxDot = flDot;
pClosest = pObject;
+#ifdef REGAMEDLL_FIXES
+ iClosestCaps = caps;
+#endif
}
}
}
}
+#ifdef REGAMEDLL_FIXES
+ else // catch new hostages caps
+ {
+ iClosestCaps = pClosest->ObjectCaps();
+ }
+ caps = iClosestCaps;
+#endif
pObject = pClosest;
// Found an object
@@ -4238,8 +4254,9 @@ void CBasePlayer::PlayerUse()
if (!useNewHostages || CanSeeUseable(this, pObject))
{
// TODO: traceline here to prevent +USEing buttons through walls
+#ifndef REGAMEDLL_FIXES
int caps = pObject->ObjectCaps();
-
+#endif
if (m_afButtonPressed & IN_USE)
EMIT_SOUND(ENT(pev), CHAN_ITEM, "common/wpn_select.wav", 0.4, ATTN_NORM);
@@ -4253,7 +4270,12 @@ void CBasePlayer::PlayerUse()
}
// UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away
// BUGBUG This is an "off" use
- else if ((m_afButtonReleased & IN_USE) && (pObject->ObjectCaps() & FCAP_ONOFF_USE))
+ else if ((m_afButtonReleased & IN_USE)
+#ifdef REGAMEDLL_FIXES
+ && (caps & FCAP_ONOFF_USE))
+#else
+ && (pObject->ObjectCaps() & FCAP_ONOFF_USE))
+#endif
{
pObject->Use(this, this, USE_SET, 0);
}
@@ -4423,7 +4445,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(AddPointsToTeam)(int score, BOOL bAllowNeg
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer && i != index)
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (i != index)
{
if (g_pGameRules->PlayerRelationship(this, pPlayer) == GR_TEAMMATE)
{
@@ -4982,8 +5007,7 @@ void CBasePlayer::CheckSuitUpdate()
{
// play sentence number
char sentence[MAX_SENTENCE_NAME + 1];
- Q_strcpy(sentence, "!");
- Q_strcat(sentence, gszallsentencenames[isentence]);
+ Q_snprintf(sentence, sizeof(sentence), "!%s", gszallsentencenames[isentence]);
EMIT_SOUND_SUIT(ENT(pev), sentence);
}
else
@@ -5309,11 +5333,6 @@ BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot)
if (!pSpot->IsTriggered(pPlayer))
return FALSE;
-#ifdef REGAMEDLL_ADD
- if (!kill_filled_spawn.value)
- return TRUE;
-#endif
-
CBaseEntity *pEntity = nullptr;
while ((pEntity = UTIL_FindEntityInSphere(pEntity, pSpot->pev->origin, MAX_PLAYER_USE_RADIUS)))
{
@@ -5810,7 +5829,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Spawn)()
{
CBasePlayer *pObserver = UTIL_PlayerByIndex(i);
- if (pObserver && pObserver->IsObservingPlayer(this))
+ if (!UTIL_IsValidPlayer(pObserver))
+ continue;
+
+ if (pObserver->IsObservingPlayer(this))
{
MESSAGE_BEGIN(MSG_ONE, gmsgNVGToggle, nullptr, pObserver->pev);
WRITE_BYTE(0);
@@ -5939,8 +5961,10 @@ void CBasePlayer::SetScoreboardAttributes(CBasePlayer *destination)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer && !FNullEnt(pPlayer->edict()))
- SetScoreboardAttributes(pPlayer);
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ SetScoreboardAttributes(pPlayer);
}
}
@@ -6489,10 +6513,8 @@ void CBasePlayer::ForceClientDllUpdate()
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || FNullEnt(pPlayer->edict()))
- continue;
- if (pPlayer->IsDormant())
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pev->deadflag == DEAD_NO)
@@ -6720,6 +6742,26 @@ void CBasePlayer::CheatImpulseCommands(int iImpulse)
break;
}
+#ifdef REGAMEDLL_ADD
+ // noclip with air acceleration
+ case 200:
+ {
+ if (pev->movetype == MOVETYPE_WALK)
+ {
+ pev->movetype = MOVETYPE_NOCLIP;
+ pev->fuser3 = MAX_PLAYER_RUN_MODIFIER_SPEED; // air acceleration increases xN times
+ ALERT(at_console, "noclip ON\n");
+ }
+ else
+ {
+ pev->movetype = MOVETYPE_WALK;
+ pev->fuser3 = 0;
+ ALERT(at_console, "noclip OFF\n");
+ }
+
+ break;
+ }
+#endif
case 202:
{
// Random blood splatter
@@ -7643,14 +7685,14 @@ void EXT_FUNC CBasePlayer::__API_HOOK(UpdateClientData)()
{
CBaseEntity *pEntity = UTIL_PlayerByIndex(i);
- if (!pEntity || i == entindex())
+ if (!UTIL_IsValidPlayer(pEntity))
continue;
- CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
-
- if (pPlayer->pev->flags == FL_DORMANT)
+ if (i == entindex())
continue;
+ CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
+
if (pPlayer->pev->deadflag != DEAD_NO)
continue;
@@ -7684,16 +7726,11 @@ void EXT_FUNC CBasePlayer::__API_HOOK(UpdateClientData)()
{
CBaseEntity *pEntity = UTIL_PlayerByIndex(playerIndex);
- if (!pEntity)
+ if (!UTIL_IsValidPlayer(pEntity))
continue;
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
-#ifdef REGAMEDLL_FIXES
- if (pPlayer->IsDormant())
- continue;
-#endif // REGAMEDLL_FIXES
-
#ifdef REGAMEDLL_FIXES
if (scoreboard_showhealth.value != -1.0f)
#endif
@@ -7996,7 +8033,7 @@ void CBasePlayer::UpdateStatusBar()
char sbuf0[MAX_SBAR_STRING];
Q_memset(newSBarState, 0, sizeof(newSBarState));
- Q_strcpy(sbuf0, m_SbarString0);
+ Q_strlcpy(sbuf0, m_SbarString0);
// Find an ID Target
TraceResult tr;
@@ -8026,9 +8063,9 @@ void CBasePlayer::UpdateStatusBar()
if (sameTeam || GetObserverMode() != OBS_NONE)
{
if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE)
- Q_strcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%");
+ Q_strlcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%");
else
- Q_strcpy(sbuf0, " ");
+ Q_strlcpy(sbuf0, " ");
newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100);
@@ -8041,9 +8078,9 @@ void CBasePlayer::UpdateStatusBar()
else if (GetObserverMode() == OBS_NONE)
{
if (playerid.value != PLAYERID_MODE_TEAMONLY && playerid.value != PLAYERID_MODE_OFF)
- Q_strcpy(sbuf0, "1 %c1: %p2");
+ Q_strlcpy(sbuf0, "1 %c1: %p2");
else
- Q_strcpy(sbuf0, " ");
+ Q_strlcpy(sbuf0, " ");
if (!(m_flDisplayHistory & DHF_ENEMY_SEEN))
{
@@ -8057,9 +8094,9 @@ void CBasePlayer::UpdateStatusBar()
else if (pEntity->Classify() == CLASS_HUMAN_PASSIVE)
{
if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE)
- Q_strcpy(sbuf0, "1 %c1 %h: %i3%%");
+ Q_strlcpy(sbuf0, "1 %c1 %h: %i3%%");
else
- Q_strcpy(sbuf0, " ");
+ Q_strlcpy(sbuf0, " ");
newSBarState[SBAR_ID_TARGETTYPE] = SBAR_TARGETTYPE_HOSTAGE;
newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100);
@@ -8101,7 +8138,7 @@ void CBasePlayer::UpdateStatusBar()
WRITE_STRING(sbuf0);
MESSAGE_END();
- Q_strcpy(m_SbarString0, sbuf0);
+ Q_strlcpy(m_SbarString0, sbuf0);
// make sure everything's resent
bForceResend = true;
@@ -8217,24 +8254,21 @@ CBaseEntity *EXT_FUNC CBasePlayer::__API_HOOK(DropPlayerItem)(const char *pszIte
if (FNullEnt(pEntity->edict()))
break;
- if (!pEntity->IsPlayer())
+ if (!pEntity->IsPlayer() || pEntity->IsDormant())
continue;
- if (pEntity->pev->flags != FL_DORMANT)
- {
- CBasePlayer *pOther = GetClassPtr((CBasePlayer *)pEntity->pev);
+ CBasePlayer *pOther = GetClassPtr((CBasePlayer *)pEntity->pev);
- if (pOther->pev->deadflag == DEAD_NO && pOther->m_iTeam == TERRORIST)
- {
- ClientPrint(pOther->pev, HUD_PRINTCENTER, "#Game_bomb_drop", STRING(pev->netname));
-
- MESSAGE_BEGIN(MSG_ONE, gmsgBombDrop, nullptr, pOther->pev);
- WRITE_COORD(pev->origin.x);
- WRITE_COORD(pev->origin.y);
- WRITE_COORD(pev->origin.z);
- WRITE_BYTE(BOMB_FLAG_DROPPED);
- MESSAGE_END();
- }
+ if (pOther->pev->deadflag == DEAD_NO && pOther->m_iTeam == TERRORIST)
+ {
+ ClientPrint(pOther->pev, HUD_PRINTCENTER, "#Game_bomb_drop", STRING(pev->netname));
+
+ MESSAGE_BEGIN(MSG_ONE, gmsgBombDrop, nullptr, pOther->pev);
+ WRITE_COORD(pev->origin.x);
+ WRITE_COORD(pev->origin.y);
+ WRITE_COORD(pev->origin.z);
+ WRITE_BYTE(BOMB_FLAG_DROPPED);
+ MESSAGE_END();
}
}
}
@@ -9295,14 +9329,10 @@ void CBasePlayer::AddAutoBuyData(const char *str)
{
if (len > 0)
{
- Q_strncat(m_autoBuyString, " ", len);
+ Q_strlcat(m_autoBuyString, " ");
}
-#ifndef REGAMEDLL_FIXES
- Q_strncat(m_autoBuyString, str, sizeof(m_autoBuyString) - Q_strlen(m_autoBuyString));
-#else
- Q_strncat(m_autoBuyString, str, sizeof(m_autoBuyString) - Q_strlen(m_autoBuyString) - 1);
-#endif
+ Q_strlcat(m_autoBuyString, str);
}
}
@@ -9319,9 +9349,7 @@ void CBasePlayer::InitRebuyData(const char *str)
m_rebuyString = nullptr;
}
- m_rebuyString = new char[Q_strlen(str) + 1];
- Q_strcpy(m_rebuyString, str);
- m_rebuyString[Q_strlen(str)] = '\0';
+ m_rebuyString = CloneString(str);
}
void CBasePlayer::AutoBuy()
@@ -9349,7 +9377,7 @@ void CBasePlayer::AutoBuy()
if (c)
{
- Q_strcpy(prioritizedString, c);
+ Q_strlcpy(prioritizedString, c);
PrioritizeAutoBuyString(prioritizedString, m_autoBuyString);
ParseAutoBuyString(prioritizedString, boughtPrimary, boughtSecondary);
@@ -9359,7 +9387,7 @@ void CBasePlayer::AutoBuy()
if (c)
{
- Q_strcpy(prioritizedString, c);
+ Q_strlcpy(prioritizedString, c);
PrioritizeAutoBuyString(prioritizedString, m_autoBuyString);
ParseAutoBuyString(prioritizedString, boughtPrimary, boughtSecondary);
@@ -9507,11 +9535,11 @@ const char *CBasePlayer::PickPrimaryCareerTaskWeapon()
CCareerTask *pTask = taskVector[i];
if (IsPrimaryWeaponId(pTask->GetWeaponId()))
- Q_strncat(buf, WeaponIDToAlias(pTask->GetWeaponId()), sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, WeaponIDToAlias(pTask->GetWeaponId()));
else
- Q_strncat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()), sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()));
- Q_strncat(buf, " ", sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, " ");
}
return buf;
@@ -9582,11 +9610,11 @@ const char *CBasePlayer::PickSecondaryCareerTaskWeapon()
CCareerTask *pTask = taskVector[i];
if (IsSecondaryWeaponId(pTask->GetWeaponId()))
- Q_strncat(buf, WeaponIDToAlias(pTask->GetWeaponId()), sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, WeaponIDToAlias(pTask->GetWeaponId()));
else
- Q_strncat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()), sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()));
- Q_strncat(buf, " ", sizeof(buf) - Q_strlen(buf) - 1);
+ Q_strlcat(buf, " ");
}
return buf;
@@ -9635,7 +9663,7 @@ const char *CBasePlayer::PickGrenadeKillWeaponString()
}
// PostAutoBuyCommandProcessing - reorders the tokens in autobuyString based on the order of tokens in the priorityString.
-void CBasePlayer::PrioritizeAutoBuyString(char *autobuyString, const char *priorityString)
+void CBasePlayer::PrioritizeAutoBuyString(char (&autobuyString)[MAX_AUTOBUY_LENGTH], const char *priorityString)
{
char newString[MAX_AUTOBUY_LENGTH];
int newStringPos = 0;
@@ -9708,7 +9736,7 @@ void CBasePlayer::PrioritizeAutoBuyString(char *autobuyString, const char *prior
// terminate the string. Trailing spaces shouldn't matter.
newString[newStringPos] = '\0';
- Q_sprintf(autobuyString, "%s", newString);
+ Q_snprintf(autobuyString, sizeof(autobuyString), "%s", newString);
}
void CBasePlayer::ParseAutoBuyString(const char *string, bool &boughtPrimary, bool &boughtSecondary)
@@ -10081,9 +10109,13 @@ void CBasePlayer::UpdateLocation(bool forceUpdate)
if (!forceUpdate && m_flLastUpdateTime >= gpGlobals->time + 2.0f)
return;
- const char *placeName = "";
+ const char *placeName = nullptr;
- if (pev->deadflag == DEAD_NO && AreBotsAllowed())
+ if (pev->deadflag == DEAD_NO && (
+#ifdef REGAMEDLL_ADD
+ (location_area_info.value == 1 || location_area_info.value == 3) ||
+#endif
+ AreBotsAllowed()))
{
// search the place name where is located the player
Place playerPlace = TheNavAreaGrid.GetPlace(&pev->origin);
@@ -10096,9 +10128,12 @@ void CBasePlayer::UpdateLocation(bool forceUpdate)
break;
}
}
+
+ if (!placeName)
+ placeName = TheNavAreaGrid.IDToName(playerPlace);
}
- if (!placeName[0] || (m_lastLocation[0] && !Q_strcmp(placeName, &m_lastLocation[1])))
+ if (!placeName || !placeName[0] || (m_lastLocation[0] && !Q_strcmp(placeName, &m_lastLocation[1])))
{
return;
}
@@ -10110,7 +10145,7 @@ void CBasePlayer::UpdateLocation(bool forceUpdate)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->m_iTeam == m_iTeam || pPlayer->m_iTeam == SPECTATOR)
@@ -10658,6 +10693,11 @@ bool CBasePlayer::Kill()
// have the player kill himself
pev->health = 0.0f;
+
+#ifdef REGAMEDLL_API
+ CSPlayer()->ResetAllStats(); // reset damage stats on killed himself or team change
+#endif
+
Killed(pev, GIB_NEVER);
if (CSGameRules()->m_pVIP == this)
@@ -10665,3 +10705,12 @@ bool CBasePlayer::Kill()
return true;
}
+
+const usercmd_t *CBasePlayer::GetLastUserCommand() const
+{
+#ifdef REGAMEDLL_API
+ return CSPlayer()->GetLastUserCommand();
+#else
+ return nullptr;
+#endif
+}
diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h
index 8908e44c9..b13c2c820 100644
--- a/regamedll/dlls/player.h
+++ b/regamedll/dlls/player.h
@@ -58,9 +58,10 @@ const int MAX_BUFFER_MENU_BRIEFING = 50;
const float SUIT_UPDATE_TIME = 3.5f;
const float SUIT_FIRST_UPDATE_TIME = 0.1f;
-const float MAX_PLAYER_FATAL_FALL_SPEED = 1100.0f;
-const float MAX_PLAYER_SAFE_FALL_SPEED = 500.0f;
-const float MAX_PLAYER_USE_RADIUS = 64.0f;
+const float MAX_PLAYER_FATAL_FALL_SPEED = 1100.0f;
+const float MAX_PLAYER_SAFE_FALL_SPEED = 500.0f;
+const float MAX_PLAYER_USE_RADIUS = 64.0f;
+const float MAX_PLAYER_RUN_MODIFIER_SPEED = 10.0f; // x10 speed run when IN_RUN button is pressed
const float ARMOR_RATIO = 0.5f; // Armor Takes 50% of the damage
const float ARMOR_BONUS = 0.5f; // Each Point of Armor is work 1/x points of health
@@ -448,6 +449,7 @@ class CBasePlayer: public CBaseMonster {
edict_t *EntSelectSpawnPoint_OrigFunc();
void PlayerDeathThink_OrigFunc();
void Observer_Think_OrigFunc();
+ void RemoveAllItems_OrigFunc(BOOL removeSuit);
CCSPlayer *CSPlayer() const;
#endif // REGAMEDLL_API
@@ -499,6 +501,7 @@ class CBasePlayer: public CBaseMonster {
void SetClientUserInfoModel(char *infobuffer, char *szNewModel);
void SetClientUserInfoModel_api(char *infobuffer, char *szNewModel);
void SetNewPlayerModel(const char *modelName);
+ const usercmd_t *GetLastUserCommand() const;
BOOL SwitchWeapon(CBasePlayerItem *pWeapon);
void CheckPowerups();
bool CanAffordPrimary();
@@ -519,7 +522,9 @@ class CBasePlayer: public CBaseMonster {
void UpdatePlayerSound();
void DeathSound();
void SetAnimation(PLAYER_ANIM playerAnim);
- void SetWeaponAnimType(const char *szExtention) { Q_strcpy(m_szAnimExtention, szExtention); }
+ enum AnimationType { ANIM_NORMAL, ANIM_CROUCH };
+ int GetAnimDesired(const char *szAnim, AnimationType type);
+ void SetWeaponAnimType(const char *szExtention) { Q_strlcpy(m_szAnimExtention, szExtention); }
void CheatImpulseCommands(int iImpulse);
void StartDeathCam();
void StartObserver(Vector &vecPosition, Vector &vecViewAngle);
@@ -599,7 +604,7 @@ class CBasePlayer: public CBaseMonster {
void AddAutoBuyData(const char *str);
void AutoBuy();
void ClientCommand(const char *cmd, const char *arg1 = nullptr, const char *arg2 = nullptr, const char *arg3 = nullptr);
- void PrioritizeAutoBuyString(char *autobuyString, const char *priorityString);
+ void PrioritizeAutoBuyString(char (&autobuyString)[MAX_AUTOBUY_LENGTH], const char *priorityString);
const char *PickPrimaryCareerTaskWeapon();
const char *PickSecondaryCareerTaskWeapon();
const char *PickFlashKillWeaponString();
@@ -985,6 +990,19 @@ inline CBasePlayer *UTIL_PlayerByIndex(int playerIndex)
return GET_PRIVATE(INDEXENT(playerIndex));
}
+// return true if the given player is valid
+inline bool UTIL_IsValidPlayer(CBaseEntity *pPlayer)
+{
+ return pPlayer && !FNullEnt(pPlayer->pev) && !pPlayer->IsDormant();
+}
+
+#else
+
+inline bool UTIL_IsValidPlayer(CBaseEntity *pPlayer)
+{
+ return pPlayer && !FNullEnt(pPlayer->pev);
+}
+
#endif
inline CBasePlayer *UTIL_PlayerByIndexSafe(int playerIndex)
diff --git a/regamedll/dlls/saverestore.cpp b/regamedll/dlls/saverestore.cpp
index a3a55c7f6..897452c4f 100644
--- a/regamedll/dlls/saverestore.cpp
+++ b/regamedll/dlls/saverestore.cpp
@@ -962,8 +962,8 @@ void CGlobalState::EntityAdd(string_t globalname, string_t mapName, GLOBALESTATE
pNewEntity->pNext = m_pList;
m_pList = pNewEntity;
- Q_strcpy(pNewEntity->name, STRING(globalname));
- Q_strcpy(pNewEntity->levelName, STRING(mapName));
+ Q_strlcpy(pNewEntity->name, STRING(globalname));
+ Q_strlcpy(pNewEntity->levelName, STRING(mapName));
pNewEntity->state = state;
m_listCount++;
@@ -1068,7 +1068,7 @@ void CGlobalState::EntityUpdate(string_t globalname, string_t mapname)
globalentity_t *pEnt = Find(globalname);
if (pEnt)
{
- Q_strcpy(pEnt->levelName, STRING(mapname));
+ Q_strlcpy(pEnt->levelName, STRING(mapname));
}
}
diff --git a/regamedll/dlls/skill.cpp b/regamedll/dlls/skill.cpp
index 87fd4468f..3c0bfe0d3 100644
--- a/regamedll/dlls/skill.cpp
+++ b/regamedll/dlls/skill.cpp
@@ -10,7 +10,7 @@ NOXREF float GetSkillCvar(char *pName)
float flValue;
char szBuffer[64];
- iCount = Q_sprintf(szBuffer, "%s%d", pName, gSkillData.iSkillLevel);
+ iCount = Q_snprintf(szBuffer, sizeof(szBuffer), "%s%d", pName, gSkillData.iSkillLevel);
flValue = CVAR_GET_FLOAT(szBuffer);
if (flValue <= 0.0f)
diff --git a/regamedll/dlls/sound.cpp b/regamedll/dlls/sound.cpp
index baf5353cc..a4dc0a7d6 100644
--- a/regamedll/dlls/sound.cpp
+++ b/regamedll/dlls/sound.cpp
@@ -1040,11 +1040,10 @@ void USENTENCEG_InitLRU(unsigned char *plru, int count)
// ipick is passed in as the requested sentence ordinal.
// ipick 'next' is returned.
// return of -1 indicates an error.
-int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset)
+int USENTENCEG_PickSequential(int isentenceg, char (&szfound)[64], int ipick, int freset)
{
char *szgroupname;
unsigned char count;
- char sznum[12];
if (!fSentencesInit)
return -1;
@@ -1061,10 +1060,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres
if (ipick >= count)
ipick = count - 1;
- Q_strcpy(szfound, "!");
- Q_strcat(szfound, szgroupname);
- Q_snprintf(sznum, sizeof(sznum), "%d", ipick);
- Q_strcat(szfound, sznum);
+ Q_snprintf(szfound, sizeof(szfound), "!%s%d", szgroupname, ipick);
if (ipick >= count)
{
@@ -1084,13 +1080,12 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres
// rest of the lru filled with -1. The first integer in the lru is
// actually the size of the list. Returns ipick, the ordinal
// of the picked sentence within the group.
-int USENTENCEG_Pick(int isentenceg, char *szfound)
+int USENTENCEG_Pick(int isentenceg, char (&szfound)[64])
{
char *szgroupname;
unsigned char *plru;
unsigned char i;
unsigned char count;
- char sznum[12];
unsigned char ipick = 0xFF;
BOOL ffound = FALSE;
@@ -1119,11 +1114,7 @@ int USENTENCEG_Pick(int isentenceg, char *szfound)
if (ffound)
{
- Q_strcpy(szfound, "!");
- Q_strcat(szfound, szgroupname);
- Q_snprintf(sznum, sizeof(sznum), "%d", ipick);
- Q_strcat(szfound, sznum);
-
+ Q_snprintf(szfound, sizeof(szfound), "!%s%d", szgroupname, ipick);
return ipick;
}
else
@@ -1168,8 +1159,6 @@ int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float atte
if (!fSentencesInit)
return -1;
- name[0] = '\0';
-
ipick = USENTENCEG_Pick(isentenceg, name);
#ifndef REGAMEDLL_FIXES
@@ -1194,8 +1183,6 @@ int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, float volume,
if (!fSentencesInit)
return -1;
- name[0] = '\0';
-
isentenceg = SENTENCEG_GetIndex(szgroupname);
if (isentenceg < 0)
{
@@ -1223,8 +1210,6 @@ int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, float v
if (!fSentencesInit)
return -1;
- name[0] = '\0';
-
isentenceg = SENTENCEG_GetIndex(szgroupname);
if (isentenceg < 0)
return -1;
@@ -1323,7 +1308,7 @@ void SENTENCEG_Init()
ALERT(at_warning, "Sentence %s longer than %d letters\n", pString, MAX_SENTENCE_NAME - 1);
}
- Q_strcpy(gszallsentencenames[gcallsentences++], pString);
+ Q_strlcpy(gszallsentencenames[gcallsentences++], pString);
if (--j <= i)
continue;
@@ -1354,10 +1339,10 @@ void SENTENCEG_Init()
break;
}
- Q_strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i]));
+ Q_strlcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i]));
rgsentenceg[isentencegs].count = 1;
- Q_strcpy(szgroup, &(buffer[i]));
+ Q_strlcpy(szgroup, &(buffer[i]));
continue;
}
@@ -1385,9 +1370,8 @@ void SENTENCEG_Init()
}
// convert sentence (sample) name to !sentencenum, return !sentencenum
-int SENTENCEG_Lookup(const char *sample, char *sentencenum)
+int SENTENCEG_Lookup(const char *sample, char (&sentencenum)[32])
{
- char sznum[12];
int i;
// this is a sentence name; lookup sentence number
@@ -1398,9 +1382,7 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum)
{
if (sentencenum)
{
- Q_strcpy(sentencenum, "!");
- Q_snprintf(sznum, sizeof(sznum), "%d", i);
- Q_strcat(sentencenum, sznum);
+ Q_snprintf(sentencenum, sizeof(sentencenum), "!%d", i);
}
return i;
@@ -1580,7 +1562,7 @@ void TEXTURETYPE_Init()
j = Q_min(j, MAX_TEXTURENAME_LENGHT - 1 + i);
buffer[j] = '\0';
- Q_strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i]));
+ Q_strlcpy(grgszTextureName[gcTextures++], &(buffer[i]));
}
FREE_FILE(pMemFile);
@@ -1616,7 +1598,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
char chTextureType;
float fvol;
float fvolbar;
- char szBuffer[64];
+ char szBuffer[MAX_TEXTURENAME_LENGHT];
const char *pTextureName;
float rgfl1[3];
float rgfl2[3];
@@ -1666,8 +1648,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
pTextureName++;
// '}}'
- Q_strcpy(szBuffer, pTextureName);
- szBuffer[MAX_TEXTURENAME_LENGHT - 1] = '\0';
+ Q_strlcpy(szBuffer, pTextureName);
// get texture type
chTextureType = TEXTURETYPE_Find(szBuffer);
diff --git a/regamedll/dlls/sound.h b/regamedll/dlls/sound.h
index d2f0b41a7..b4e716fbc 100644
--- a/regamedll/dlls/sound.h
+++ b/regamedll/dlls/sound.h
@@ -170,15 +170,13 @@ class CSpeaker: public CBaseEntity
BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange);
void USENTENCEG_InitLRU(unsigned char *plru, int count);
-int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset);
-int USENTENCEG_Pick(int isentenceg, char *szfound);
int SENTENCEG_GetIndex(const char *szgroupname);
int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch);
int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, float volume, float attenuation, int flags, int pitch);
int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, float volume, float attenuation, int flags, int pitch, int ipick, int freset);
void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick);
void SENTENCEG_Init();
-int SENTENCEG_Lookup(const char *sample, char *sentencenum);
+int SENTENCEG_Lookup(const char *sample, char (&sentencenum)[32]);
void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch);
void EMIT_SOUND_SUIT(edict_t *entity, const char *sample);
void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg);
diff --git a/regamedll/dlls/triggers.cpp b/regamedll/dlls/triggers.cpp
index c4af258c4..1bfd85b94 100644
--- a/regamedll/dlls/triggers.cpp
+++ b/regamedll/dlls/triggers.cpp
@@ -645,7 +645,7 @@ void PlayCDTrack(edict_t *pClient, int iTrack)
CLIENT_COMMAND(pClient, UTIL_VarArgs("mp3 play %s\n", g_szMP3trackFileMap[iTrack]));
#else
char string[64];
- Q_sprintf(string, "cd play %3d\n", iTrack);
+ Q_snprintf(string, sizeof(string), "cd play %3d\n", iTrack);
CLIENT_COMMAND(pClient, string);
#endif
}
@@ -996,6 +996,14 @@ void CTriggerMultiple::Spawn()
}
}
+#ifdef REGAMEDLL_FIXES
+void CTriggerMultiple::Restart()
+{
+ pev->nextthink = -1;
+ Spawn();
+}
+#endif
+
LINK_ENTITY_TO_CLASS(trigger_once, CTriggerOnce, CCSTriggerOnce)
void CTriggerOnce::Spawn()
@@ -1206,7 +1214,7 @@ void CChangeLevel::KeyValue(KeyValueData *pkvd)
ALERT(at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue);
}
- Q_strcpy(m_szMapName, pkvd->szValue);
+ Q_strlcpy(m_szMapName, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "landmark"))
@@ -1216,7 +1224,7 @@ void CChangeLevel::KeyValue(KeyValueData *pkvd)
ALERT(at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue);
}
- Q_strcpy(m_szLandmarkName, pkvd->szValue);
+ Q_strlcpy(m_szLandmarkName, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "changetarget"))
@@ -1348,7 +1356,7 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator)
}
// This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory
- Q_strcpy(st_szNextMap, m_szMapName);
+ Q_strlcpy(st_szNextMap, m_szMapName);
m_hActivator = pActivator;
SUB_UseTargets(pActivator, USE_TOGGLE, 0);
@@ -1361,7 +1369,7 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator)
if (!FNullEnt(pentLandmark))
{
- Q_strcpy(st_szNextSpot, m_szLandmarkName);
+ Q_strlcpy(st_szNextSpot, m_szLandmarkName);
gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin;
}
@@ -1407,8 +1415,8 @@ int CChangeLevel::AddTransitionToList(LEVELLIST *pLevelList, int listCount, cons
}
}
- Q_strcpy(pLevelList[listCount].mapName, pMapName);
- Q_strcpy(pLevelList[listCount].landmarkName, pLandmarkName);
+ Q_strlcpy(pLevelList[listCount].mapName, pMapName);
+ Q_strlcpy(pLevelList[listCount].landmarkName, pLandmarkName);
pLevelList[listCount].pentLandmark = pentLandmark;
pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin;
@@ -1583,12 +1591,12 @@ NOXREF void NextLevel()
{
gpGlobals->mapname = ALLOC_STRING("start");
pChange = GetClassPtr((CChangeLevel *)nullptr);
- Q_strcpy(pChange->m_szMapName, "start");
+ Q_strlcpy(pChange->m_szMapName, "start");
}
else
pChange = GetClassPtr((CChangeLevel *)VARS(pent));
- Q_strcpy(st_szNextMap, pChange->m_szMapName);
+ Q_strlcpy(st_szNextMap, pChange->m_szMapName);
g_pGameRules->SetGameOver();
if (pChange->pev->nextthink < gpGlobals->time)
@@ -1763,8 +1771,30 @@ void CBaseTrigger::TeleportTouch(CBaseEntity *pOther)
if (pOther->IsPlayer())
{
+#ifdef REGAMEDLL_ADD
+ // If a landmark was specified, offset the player relative to the landmark
+ if (m_iszLandmarkName)
+ {
+ edict_t *pentLandmark = FIND_ENTITY_BY_TARGETNAME(nullptr, STRING(m_iszLandmarkName));
+
+ if (!FNullEnt(pentLandmark))
+ {
+ Vector diff = pevToucher->origin - VARS(pentLandmark)->origin;
+ tmp += diff;
+ tmp.z--; // offset by +1 because -1 will run out of this scope.
+ }
+ else
+ {
+ // fallback, shouldn't happen but anyway.
+ tmp.z -= pOther->pev->mins.z;
+ }
+ }
+ else
+#endif
// make origin adjustments in case the teleportee is a player. (origin in center, not at feet)
- tmp.z -= pOther->pev->mins.z;
+ {
+ tmp.z -= pOther->pev->mins.z;
+ }
}
tmp.z++;
@@ -1817,6 +1847,26 @@ void CTriggerTeleport::Spawn()
SetTouch(&CTriggerTeleport::TeleportTouch);
}
+void CTriggerTeleport::KeyValue(KeyValueData *pkvd)
+{
+#ifdef REGAMEDLL_ADD
+ if (FStrEq(pkvd->szKeyName, "landmark"))
+ {
+ if (Q_strlen(pkvd->szValue) > 0)
+ {
+ m_iszLandmarkName = ALLOC_STRING(pkvd->szValue);
+ }
+
+ // If empty, handle it in the teleport touch instead
+ pkvd->fHandled = TRUE;
+ }
+ else
+#endif
+ {
+ CBaseTrigger::KeyValue(pkvd);
+ }
+}
+
LINK_ENTITY_TO_CLASS(info_teleport_destination, CPointEntity, CCSPointEntity)
LINK_ENTITY_TO_CLASS(func_buyzone, CBuyZone, CCSBuyZone)
@@ -1979,7 +2029,7 @@ void CEscapeZone::EscapeTouch(CBaseEntity *pOther)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->m_iTeam == pEscapee->m_iTeam)
diff --git a/regamedll/dlls/triggers.h b/regamedll/dlls/triggers.h
index c16f969c8..90a7daef3 100644
--- a/regamedll/dlls/triggers.h
+++ b/regamedll/dlls/triggers.h
@@ -204,6 +204,11 @@ class CBaseTrigger: public CBaseToggle
void EXPORT CounterUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void EXPORT ToggleUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void InitTrigger();
+
+#ifdef REGAMEDLL_ADD
+ // For trigger_teleport TriggerTouch
+ int m_iszLandmarkName = 0;
+#endif
};
#define SF_TRIGGER_HURT_TARGETONCE BIT(0) // Only fire hurt target once
@@ -278,6 +283,10 @@ class CTriggerMultiple: public CBaseTrigger
{
public:
virtual void Spawn();
+
+#ifdef REGAMEDLL_FIXES
+ virtual void Restart();
+#endif
};
// Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
@@ -393,6 +402,7 @@ class CTriggerTeleport: public CBaseTrigger
{
public:
virtual void Spawn();
+ virtual void KeyValue(KeyValueData *pkvd);
};
class CBuyZone: public CBaseTrigger
diff --git a/regamedll/dlls/tutor.cpp b/regamedll/dlls/tutor.cpp
index 5f2dbeca0..0f83d4812 100644
--- a/regamedll/dlls/tutor.cpp
+++ b/regamedll/dlls/tutor.cpp
@@ -75,7 +75,10 @@ void MonitorTutorStatus()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer && !pPlayer->IsBot())
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!pPlayer->IsBot())
numHumans++;
}
diff --git a/regamedll/dlls/tutor_base_tutor.cpp b/regamedll/dlls/tutor_base_tutor.cpp
index 2268d18b7..a44ef4728 100644
--- a/regamedll/dlls/tutor_base_tutor.cpp
+++ b/regamedll/dlls/tutor_base_tutor.cpp
@@ -68,12 +68,10 @@ void TutorMessageEvent::AddParameter(char *str)
TutorMessageEventParam *param = new TutorMessageEventParam;
param->m_next = nullptr;
- param->m_data = new char[Q_strlen(str) + 1];
+ param->m_data = CloneString(str);
if (param->m_data)
{
- Q_strcpy(param->m_data, str);
- param->m_data[Q_strlen(str)] = '\0';
m_numParameters++;
if (m_paramList)
@@ -101,11 +99,7 @@ char *TutorMessageEvent::GetNextParameter(char *buf, int buflen)
m_numParameters--;
m_paramList = param->m_next;
- Q_strncpy(buf, param->m_data, buflen);
-
-#ifdef REGAMEDLL_FIXES
- buf[buflen - 1] = '\0';
-#endif
+ Q_strlcpy(buf, param->m_data, buflen);
delete param;
return buf;
diff --git a/regamedll/dlls/tutor_cs_tutor.cpp b/regamedll/dlls/tutor_cs_tutor.cpp
index f8ca0aef7..aa6bdd4bc 100644
--- a/regamedll/dlls/tutor_cs_tutor.cpp
+++ b/regamedll/dlls/tutor_cs_tutor.cpp
@@ -213,7 +213,7 @@ void ParseMessageParameters(char *&messageData, TutorMessage *ret)
if (!Q_stricmp(token, "String"))
{
messageData = SharedParse((char *)messageData);
- ret->m_text = Q_strdup(SharedGetToken());
+ ret->m_text = CloneString(SharedGetToken());
}
else if (!Q_stricmp(token, "Duration"))
{
@@ -832,7 +832,7 @@ TutorMessageEvent *CCSTutor::CreateTutorMessageEvent(TutorMessageID mid, CBaseEn
{
numtasks = TheCareerTasks->GetNumRemainingTasks();
}
- Q_sprintf(numLeftStr, "%d", numtasks);
+ Q_snprintf(numLeftStr, sizeof(numLeftStr), "%d", numtasks);
event->AddParameter(numLeftStr);
break;
}
@@ -2040,7 +2040,11 @@ void CCSTutor::GetNumPlayersAliveOnTeams(int &numT, int &numCT)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || !pPlayer->IsAlive())
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!pPlayer->IsAlive())
continue;
switch (pPlayer->m_iTeam)
@@ -2132,7 +2136,11 @@ void CCSTutor::CheckForBombViewable()
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer && pPlayer->m_bHasC4)
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (pPlayer->m_bHasC4)
{
pBombCarrier = pPlayer;
break;
@@ -2812,14 +2820,13 @@ void CCSTutor::ConstructRecentDeathsList(TeamName team, char *buf, int buflen, T
if (!buf || !buflen)
return;
- char scratch[32];
- buf[0] = '\0';
+ int len = 0;
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
// ignore alive players
@@ -2829,10 +2836,7 @@ void CCSTutor::ConstructRecentDeathsList(TeamName team, char *buf, int buflen, T
if (pPlayer->m_iTeam != team)
continue;
- Q_strcat(buf, " %n");
- Q_sprintf(scratch, "%d\n", i);
- Q_strcat(buf, scratch);
-
+ len += Q_snprintf(&buf[len], buflen - len, " %%n%d\n", i);
m_playerDeathInfo[i].m_event = event;
}
}
diff --git a/regamedll/dlls/util.cpp b/regamedll/dlls/util.cpp
index 7c3c3db6c..de6159469 100644
--- a/regamedll/dlls/util.cpp
+++ b/regamedll/dlls/util.cpp
@@ -506,7 +506,11 @@ void UTIL_ScreenShake(const Vector ¢er, float amplitude, float frequency, fl
for (i = 1; i <= gpGlobals->maxClients; i++)
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || !(pPlayer->pev->flags & FL_ONGROUND))
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!(pPlayer->pev->flags & FL_ONGROUND))
continue;
localAmplitude = 0;
@@ -552,7 +556,10 @@ void UTIL_ScreenFadeBuild(ScreenFade &fade, const Vector &color, float fadeTime,
void UTIL_ScreenFadeWrite(const ScreenFade &fade, CBaseEntity *pEntity)
{
- if (!pEntity || !pEntity->IsNetClient())
+ if (!UTIL_IsValidPlayer(pEntity))
+ return;
+
+ if (!pEntity->IsNetClient())
return;
MESSAGE_BEGIN(MSG_ONE, gmsgFade, nullptr, pEntity->edict());
@@ -634,10 +641,11 @@ void UTIL_HudMessageAll(const hudtextparms_t &textparms, const char *pMessage)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer)
- {
- UTIL_HudMessage(pPlayer, textparms, pMessage);
- }
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ UTIL_HudMessage(pPlayer, textparms, pMessage);
}
}
@@ -682,10 +690,7 @@ void UTIL_Log(const char *fmt, ...)
Q_vsnprintf(string, sizeof(string), fmt, ap);
va_end(ap);
- if (Q_strlen(string) < sizeof(string) - 2)
- Q_strcat(string, "\n");
- else
- string[Q_strlen(string) - 1] = '\n';
+ Q_strlcat(string, "\n");
FILE *fp = fopen("regamedll.log", "at");
if (fp)
@@ -709,10 +714,7 @@ void UTIL_ServerPrint(const char *fmt, ...)
Q_vsnprintf(string, sizeof(string), fmt, ap);
va_end(ap);
- if (Q_strlen(string) < sizeof(string) - 2)
- Q_strcat(string, "\n");
- else
- string[Q_strlen(string) - 1] = '\n';
+ Q_strlcat(string, "\n");
SERVER_PRINT(string);
}
@@ -730,10 +732,7 @@ void UTIL_PrintConsole(edict_t *pEdict, const char *fmt, ...)
Q_vsnprintf(string, sizeof(string), fmt, ap);
va_end(ap);
- if (Q_strlen(string) < sizeof(string) - 2)
- Q_strcat(string, "\n");
- else
- string[Q_strlen(string) - 1] = '\n';
+ Q_strlcat(string, "\n");
ClientPrint(pEntity->pev, HUD_PRINTCONSOLE, string);
}
@@ -751,10 +750,7 @@ void UTIL_SayText(edict_t *pEdict, const char *fmt, ...)
Q_vsnprintf(string, sizeof(string), fmt, ap);
va_end(ap);
- if (Q_strlen(string) < sizeof(string) - 2)
- Q_strcat(string, "\n");
- else
- string[Q_strlen(string) - 1] = '\n';
+ Q_strlcat(string, "\n");
MESSAGE_BEGIN(MSG_ONE, gmsgSayText, nullptr, pEntity->edict());
WRITE_BYTE(pEntity->entindex());
@@ -773,28 +769,28 @@ void UTIL_SayTextAll(const char *pText, CBaseEntity *pEntity)
char *UTIL_dtos1(int d)
{
static char buf[12];
- Q_sprintf(buf, "%d", d);
+ Q_snprintf(buf, sizeof(buf), "%d", d);
return buf;
}
char *UTIL_dtos2(int d)
{
static char buf[12];
- Q_sprintf(buf, "%d", d);
+ Q_snprintf(buf, sizeof(buf), "%d", d);
return buf;
}
NOXREF char *UTIL_dtos3(int d)
{
static char buf[12];
- Q_sprintf(buf, "%d", d);
+ Q_snprintf(buf, sizeof(buf), "%d", d);
return buf;
}
NOXREF char *UTIL_dtos4(int d)
{
static char buf[12];
- Q_sprintf(buf, "%d", d);
+ Q_snprintf(buf, sizeof(buf), "%d", d);
return buf;
}
@@ -843,8 +839,11 @@ void UTIL_ShowMessageAll(const char *pString, bool isHint)
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer)
- UTIL_ShowMessage(pString, pPlayer, isHint);
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ UTIL_ShowMessage(pString, pPlayer, isHint);
}
}
@@ -980,7 +979,7 @@ char *UTIL_VarArgs(char *format, ...)
static char string[1024];
va_start(argptr, format);
- vsprintf(string, format, argptr);
+ Q_vsnprintf(string, sizeof(string), format, argptr);
va_end(argptr);
return string;
@@ -1550,7 +1549,7 @@ void UTIL_LogPrintf(const char *fmt, ...)
static char string[1024];
va_start(argptr, fmt);
- vsprintf(string, fmt, argptr);
+ Q_vsnprintf(string, sizeof(string), fmt, argptr);
va_end(argptr);
ALERT(at_logged, "%s", string);
@@ -1569,7 +1568,7 @@ char UTIL_TextureHit(TraceResult *ptr, Vector vecSrc, Vector vecEnd)
float rgfl1[3];
float rgfl2[3];
const char *pTextureName;
- char szbuffer[64];
+ char szbuffer[MAX_TEXTURENAME_LENGHT];
CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit);
#ifdef REGAMEDLL_FIXES
@@ -1595,8 +1594,8 @@ char UTIL_TextureHit(TraceResult *ptr, Vector vecSrc, Vector vecEnd)
if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ')
pTextureName++;
- Q_strcpy(szbuffer, pTextureName);
- szbuffer[16] = '\0';
+ Q_strlcpy(szbuffer, pTextureName);
+
chTextureType = TEXTURETYPE_Find(szbuffer);
}
else
@@ -1749,10 +1748,11 @@ int UTIL_GetNumPlayers()
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (pPlayer)
- {
- nNumPlayers++;
- }
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ nNumPlayers++;
}
return nNumPlayers;
@@ -1837,7 +1837,10 @@ int UTIL_CountPlayersInBrushVolume(bool bOnlyAlive, CBaseEntity *pBrushEntity, i
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer || !pPlayer->IsInWorld())
+ if (!UTIL_IsValidPlayer(pPlayer))
+ continue;
+
+ if (!pPlayer->IsInWorld())
continue;
if (bOnlyAlive && !pPlayer->IsAlive())
diff --git a/regamedll/dlls/weapons.cpp b/regamedll/dlls/weapons.cpp
index 2c035c746..47a77c6fc 100644
--- a/regamedll/dlls/weapons.cpp
+++ b/regamedll/dlls/weapons.cpp
@@ -79,7 +79,7 @@ LINK_HOOK_VOID_CHAIN2(ClearMultiDamage)
// Resets the global multi damage accumulator
void EXT_FUNC __API_HOOK(ClearMultiDamage)()
{
- gMultiDamage.pEntity = nullptr;
+ gMultiDamage.hEntity = nullptr;
gMultiDamage.amount = 0;
gMultiDamage.type = 0;
}
@@ -89,11 +89,15 @@ LINK_HOOK_VOID_CHAIN(ApplyMultiDamage, (entvars_t *pevInflictor, entvars_t *pevA
// Inflicts contents of global multi damage register on gMultiDamage.pEntity
void EXT_FUNC __API_HOOK(ApplyMultiDamage)(entvars_t *pevInflictor, entvars_t *pevAttacker)
{
- if (!gMultiDamage.pEntity)
+ EntityHandle hEnt = gMultiDamage.hEntity;
+ if (!hEnt)
return;
- gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type);
- gMultiDamage.pEntity->ResetDmgPenetrationLevel();
+ hEnt->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type);
+
+ // check again, the entity may be removed after taking damage
+ if (hEnt)
+ hEnt->ResetDmgPenetrationLevel();
}
LINK_HOOK_VOID_CHAIN(AddMultiDamage, (entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType), pevInflictor, pEntity, flDamage, bitsDamageType)
@@ -105,11 +109,17 @@ void EXT_FUNC __API_HOOK(AddMultiDamage)(entvars_t *pevInflictor, CBaseEntity *p
gMultiDamage.type |= bitsDamageType;
- if (pEntity != gMultiDamage.pEntity)
+ if (pEntity != gMultiDamage.hEntity)
{
- // UNDONE: wrong attacker!
- ApplyMultiDamage(pevInflictor, pevInflictor);
- gMultiDamage.pEntity = pEntity;
+#ifdef REGAMEDLL_FIXES
+ if (gMultiDamage.hEntity) // avoid api calls with null default pEntity
+#endif
+ {
+ // UNDONE: wrong attacker!
+ ApplyMultiDamage(pevInflictor, pevInflictor);
+ }
+
+ gMultiDamage.hEntity = pEntity;
gMultiDamage.amount = 0;
}
@@ -508,7 +518,11 @@ void CBasePlayerItem::Materialize()
UTIL_SetOrigin(pev, pev->origin);
SetTouch(&CBasePlayerItem::DefaultTouch);
- if (g_pGameRules->IsMultiplayer())
+ if (g_pGameRules->IsMultiplayer()
+#ifdef REGAMEDLL_FIXES
+ && g_pGameRules->WeaponShouldRespawn(this) == GR_WEAPON_RESPAWN_NO
+#endif
+ )
{
if (!CanDrop())
{
@@ -545,8 +559,12 @@ void CBasePlayerItem::CheckRespawn()
{
switch (g_pGameRules->WeaponShouldRespawn(this))
{
- case GR_WEAPON_RESPAWN_YES:
+ case GR_WEAPON_RESPAWN_YES: {
+#ifdef REGAMEDLL_FIXES
+ Respawn();
+#endif
return;
+ }
case GR_WEAPON_RESPAWN_NO:
return;
}
@@ -565,6 +583,10 @@ CBaseEntity *CBasePlayerItem::Respawn()
// invisible for now
pNewWeapon->pev->effects |= EF_NODRAW;
+#ifdef REGAMEDLL_ADD
+ pNewWeapon->pev->spawnflags &= ~SF_NORESPAWN;
+#endif
+
// no touch
pNewWeapon->SetTouch(nullptr);
pNewWeapon->SetThink(&CBasePlayerItem::AttemptToMaterialize);
@@ -630,11 +652,11 @@ void CBasePlayerWeapon::SetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
}
else
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
}
}
@@ -644,7 +666,7 @@ void CBasePlayerWeapon::ResetPlayerShieldAnim()
{
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
}
}
}
@@ -675,7 +697,7 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
m_fMaxSpeed = 250.0f;
m_pPlayer->m_bShieldDrawn = false;
}
@@ -683,7 +705,7 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = 180.0f;
m_pPlayer->m_bShieldDrawn = true;
}
@@ -702,6 +724,41 @@ LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayerWeapon, KickBack, (float up_base, float la
void EXT_FUNC CBasePlayerWeapon::__API_HOOK(KickBack)(float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change)
{
+#ifdef REGAMEDLL_ADD
+ real_t flKickUp = up_base;
+ float flKickLateral = lateral_base;
+
+ if (m_iShotsFired > 1) // consider == 0 case
+ {
+ flKickUp += m_iShotsFired * up_modifier;
+ flKickLateral += m_iShotsFired * lateral_modifier;
+ }
+
+ if (up_max == 0.0f) // boundaryless vertical kick
+ {
+ m_pPlayer->pev->punchangle.x -= flKickUp;
+ }
+ else if (m_pPlayer->pev->punchangle.x > -up_max) // do not kick when already out of boundaries
+ {
+ m_pPlayer->pev->punchangle.x = Q_max(m_pPlayer->pev->punchangle.x - flKickUp, -up_max);
+ }
+
+ if (lateral_max == 0.0f) // boundaryless horizontal kick
+ {
+ m_pPlayer->pev->punchangle.y += flKickLateral * (m_iDirection * 2 - 1);
+ }
+ else if (Q_fabs(m_pPlayer->pev->punchangle.y) < lateral_max) // do not kick when already out of boundaries
+ {
+ m_pPlayer->pev->punchangle.y = (m_iDirection == 1) ?
+ Q_min(m_pPlayer->pev->punchangle.y + flKickLateral, lateral_max) :
+ Q_max(m_pPlayer->pev->punchangle.y - flKickLateral, -lateral_max);
+ }
+
+ if (direction_change > 0 && !RANDOM_LONG(0, direction_change)) // be sure to not waste RNG consumption
+ {
+ m_iDirection = !m_iDirection;
+ }
+#else
real_t flKickUp;
float flKickLateral;
@@ -742,6 +799,7 @@ void EXT_FUNC CBasePlayerWeapon::__API_HOOK(KickBack)(float up_base, float later
{
m_iDirection = !m_iDirection;
}
+#endif
}
void CBasePlayerWeapon::FireRemaining(int &shotsFired, float &shootTime, BOOL bIsGlock)
@@ -1433,7 +1491,7 @@ BOOL EXT_FUNC CBasePlayerWeapon::__API_HOOK(DefaultDeploy)(char *szViewModel, ch
m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel);
#endif
model_name = m_pPlayer->pev->viewmodel;
- Q_strcpy(m_pPlayer->m_szAnimExtention, szAnimExt);
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, szAnimExt);
SendWeaponAnim(iAnim, skiplocal);
m_pPlayer->m_flNextAttack = 0.75f;
@@ -1454,9 +1512,12 @@ void CBasePlayerWeapon::ReloadSound()
CBasePlayer *pPlayer = nullptr;
while ((pPlayer = UTIL_FindEntityByClassname(pPlayer, "player")))
{
- if (pPlayer->IsDormant())
+ if (FNullEnt(pPlayer->edict()))
break;
+ if (pPlayer->IsDormant())
+ continue;
+
if (pPlayer == m_pPlayer)
continue;
@@ -1610,6 +1671,10 @@ void CBasePlayerWeapon::Holster(int skiplocal)
m_fInReload = FALSE;
m_pPlayer->pev->viewmodel = 0;
m_pPlayer->pev->weaponmodel = 0;
+
+#ifdef REGAMEDLL_FIXES
+ m_fInSpecialReload = 0;
+#endif
}
// called by the new item with the existing item as parameter
@@ -1974,6 +2039,7 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
if (!m_rgpPlayerItems[i])
continue;
+ CBasePlayerItem *pPrev = NULL;
CBasePlayerItem *pItem = m_rgpPlayerItems[i];
// have at least one weapon in this slot
@@ -2036,7 +2102,7 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
if (!pEntity->IsPlayer())
continue;
- if (pEntity->pev->flags == FL_DORMANT)
+ if (pEntity->IsDormant())
continue;
CBasePlayer *pTempPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
@@ -2070,13 +2136,13 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
}
else if (i == GRENADE_SLOT)
{
- CBasePlayerWeapon *pGrenade = static_cast(m_rgpPlayerItems[i]);
+ CBasePlayerWeapon *pGrenade = static_cast(pItem);
if (pGrenade && pGrenade->IsWeapon())
{
int playerGrenades = pPlayer->m_rgAmmo[pGrenade->m_iPrimaryAmmoType];
#ifdef REGAMEDLL_FIXES
- CBasePlayerItem *pNext = m_rgpPlayerItems[i]->m_pNext;
+ CBasePlayerItem *pNext = pItem->m_pNext;
// Determine the max ammo capacity for the picked-up grenade
int iMaxPickupAmmo = pGrenade->iMaxAmmo1();
@@ -2094,7 +2160,11 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
playerGrenades, pGrenade->pszAmmo1(), iMaxPickupAmmo, &givenItem))
{
// unlink this weapon from the box
- m_rgpPlayerItems[i] = pItem = pNext;
+ if (pPrev)
+ pPrev->m_pNext = pItem = pNext;
+ else
+ m_rgpPlayerItems[i] = pItem = pNext;
+
continue;
}
#else
@@ -2143,7 +2213,8 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
}
else
{
- auto pNext = m_rgpPlayerItems[i]->m_pNext;
+ CBasePlayerItem *pNext = pItem->m_pNext;
+
if (pPlayer->AddPlayerItem(pItem))
{
pItem->AttachToPlayer(pPlayer);
@@ -2155,12 +2226,17 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
}
// unlink this weapon from the box
- m_rgpPlayerItems[i] = pItem = pNext;
+ if (pPrev)
+ pPrev->m_pNext = pNext;
+ else
+ m_rgpPlayerItems[i] = pItem = pNext;
+
continue;
}
bRemove = false;
- pItem = m_rgpPlayerItems[i]->m_pNext;
+ pPrev = pItem;
+ pItem = pItem->m_pNext;
}
}
diff --git a/regamedll/dlls/weapons.h b/regamedll/dlls/weapons.h
index c9cd58c36..9266d8434 100644
--- a/regamedll/dlls/weapons.h
+++ b/regamedll/dlls/weapons.h
@@ -133,7 +133,7 @@ struct AmmoInfo
struct MULTIDAMAGE
{
- CBaseEntity *pEntity;
+ EntityHandle hEntity;
float amount;
int type;
};
diff --git a/regamedll/dlls/world.cpp b/regamedll/dlls/world.cpp
index 55147af09..cc4a3de55 100644
--- a/regamedll/dlls/world.cpp
+++ b/regamedll/dlls/world.cpp
@@ -216,7 +216,7 @@ void CWorld::Spawn()
Precache();
g_szMapBriefingText[0] = '\0';
- Q_sprintf(szMapBriefingFile, "maps/%s.txt", STRING(gpGlobals->mapname));
+ Q_snprintf(szMapBriefingFile, sizeof(szMapBriefingFile), "maps/%s.txt", STRING(gpGlobals->mapname));
int flength = 0;
char *pFile = (char *)LOAD_FILE_FOR_ME(szMapBriefingFile, &flength);
diff --git a/regamedll/dlls/wpn_shared/wpn_awp.cpp b/regamedll/dlls/wpn_shared/wpn_awp.cpp
index 0e31bd548..3cf4e437e 100644
--- a/regamedll/dlls/wpn_shared/wpn_awp.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_awp.cpp
@@ -189,7 +189,11 @@ void CAWP::AWPFire(float flSpread, float flCycleTime, BOOL fUseAutoAim)
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
+#ifdef REGAMEDLL_ADD
+ KickBack(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= 2.0f;
+#endif
}
void CAWP::Reload()
diff --git a/regamedll/dlls/wpn_shared/wpn_deagle.cpp b/regamedll/dlls/wpn_shared/wpn_deagle.cpp
index 7dbed0c6b..f04ab55d6 100644
--- a/regamedll/dlls/wpn_shared/wpn_deagle.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_deagle.cpp
@@ -177,7 +177,11 @@ void CDEAGLE::DEAGLEFire(float flSpread, float flCycleTime, BOOL fUseSemi)
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.8f;
+#ifdef REGAMEDLL_ADD
+ KickBack(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= 2;
+#endif
ResetPlayerShieldAnim();
}
@@ -200,11 +204,23 @@ void CDEAGLE::WeaponIdle()
if (m_flTimeWeaponIdle <= UTIL_WeaponTimeBase())
{
- m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 20.0f;
+#ifdef REGAMEDLL_FIXES
+ if (m_pPlayer->HasShield())
+#endif
+ {
+ m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 20.0f;
- if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
+ if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
+ {
+ SendWeaponAnim(DEAGLE_SHIELD_IDLE_UP, UseDecrement() != FALSE);
+ }
+ }
+#ifdef REGAMEDLL_FIXES
+ else if (m_iClip)
{
- SendWeaponAnim(DEAGLE_SHIELD_IDLE_UP, UseDecrement() != FALSE);
+ m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0625f;
+ SendWeaponAnim(DEAGLE_IDLE1, UseDecrement() != FALSE);
}
+#endif
}
}
diff --git a/regamedll/dlls/wpn_shared/wpn_elite.cpp b/regamedll/dlls/wpn_shared/wpn_elite.cpp
index 05428d8ed..845b5f278 100644
--- a/regamedll/dlls/wpn_shared/wpn_elite.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_elite.cpp
@@ -200,7 +200,11 @@ void CELITE::ELITEFire(float flSpread, float flCycleTime, BOOL fUseSemi)
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
+#ifdef REGAMEDLL_ADD
+ KickBack(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= 2.0f;
+#endif
}
void CELITE::Reload()
diff --git a/regamedll/dlls/wpn_shared/wpn_fiveseven.cpp b/regamedll/dlls/wpn_shared/wpn_fiveseven.cpp
index 31f211f08..4f07b840e 100644
--- a/regamedll/dlls/wpn_shared/wpn_fiveseven.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_fiveseven.cpp
@@ -176,7 +176,11 @@ void CFiveSeven::FiveSevenFire(float flSpread, float flCycleTime, BOOL fUseSemi)
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
+#ifdef REGAMEDLL_ADD
+ KickBack(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= 2.0f;
+#endif
ResetPlayerShieldAnim();
}
diff --git a/regamedll/dlls/wpn_shared/wpn_flashbang.cpp b/regamedll/dlls/wpn_shared/wpn_flashbang.cpp
index 0443353e8..bbebb8ebf 100644
--- a/regamedll/dlls/wpn_shared/wpn_flashbang.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_flashbang.cpp
@@ -114,7 +114,7 @@ bool CFlashbang::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
m_fMaxSpeed = FLASHBANG_MAX_SPEED;
m_pPlayer->m_bShieldDrawn = false;
@@ -124,7 +124,7 @@ bool CFlashbang::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = FLASHBANG_MAX_SPEED_SHIELD;
m_pPlayer->m_bShieldDrawn = true;
@@ -151,9 +151,9 @@ void CFlashbang::SetPlayerShieldAnim()
return;
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
else
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
void CFlashbang::ResetPlayerShieldAnim()
@@ -163,7 +163,7 @@ void CFlashbang::ResetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
}
diff --git a/regamedll/dlls/wpn_shared/wpn_g3sg1.cpp b/regamedll/dlls/wpn_shared/wpn_g3sg1.cpp
index 5351d0f78..b7e36b09f 100644
--- a/regamedll/dlls/wpn_shared/wpn_g3sg1.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_g3sg1.cpp
@@ -185,8 +185,15 @@ void CG3SG1::G3SG1Fire(float flSpread, float flCycleTime, BOOL fUseAutoAim)
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.8f;
+#ifdef REGAMEDLL_ADD
+ m_iDirection = 1; // force positive Y addition
+ KickBack(UTIL_SharedRandomFloat(m_pPlayer->random_seed + 4, 0.75, 1.75) + m_pPlayer->pev->punchangle.x * 0.25f,
+ UTIL_SharedRandomFloat(m_pPlayer->random_seed + 5, -0.75, 0.75),
+ 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= UTIL_SharedRandomFloat(m_pPlayer->random_seed + 4, 0.75, 1.75) + m_pPlayer->pev->punchangle.x * 0.25f;
m_pPlayer->pev->punchangle.y += UTIL_SharedRandomFloat(m_pPlayer->random_seed + 5, -0.75, 0.75);
+#endif
}
void CG3SG1::Reload()
diff --git a/regamedll/dlls/wpn_shared/wpn_glock18.cpp b/regamedll/dlls/wpn_shared/wpn_glock18.cpp
index c2f5399d5..b879ef858 100644
--- a/regamedll/dlls/wpn_shared/wpn_glock18.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_glock18.cpp
@@ -253,6 +253,9 @@ void CGLOCK18::GLOCK18Fire(float flSpread, float flCycleTime, BOOL bFireBurst)
m_flGlock18Shoot = gpGlobals->time + 0.1f;
}
+#ifdef REGAMEDLL_ADD
+ KickBack(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0); // dummy call, API useful
+#endif
ResetPlayerShieldAnim();
}
diff --git a/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp b/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp
index 49d8eb7a8..ca2c63adb 100644
--- a/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp
@@ -117,7 +117,7 @@ bool CHEGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
m_fMaxSpeed = HEGRENADE_MAX_SPEED;
m_pPlayer->m_bShieldDrawn = false;
@@ -126,7 +126,7 @@ bool CHEGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = HEGRENADE_MAX_SPEED_SHIELD;
m_pPlayer->m_bShieldDrawn = true;
@@ -153,9 +153,9 @@ void CHEGrenade::SetPlayerShieldAnim()
return;
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
else
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
void CHEGrenade::ResetPlayerShieldAnim()
@@ -165,7 +165,7 @@ void CHEGrenade::ResetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
}
diff --git a/regamedll/dlls/wpn_shared/wpn_knife.cpp b/regamedll/dlls/wpn_shared/wpn_knife.cpp
index fcbf2d949..43a2f28f2 100644
--- a/regamedll/dlls/wpn_shared/wpn_knife.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_knife.cpp
@@ -180,7 +180,7 @@ void CKnife::SetPlayerShieldAnim()
if (!m_pPlayer->HasShield())
return;
- Q_strcpy(m_pPlayer->m_szAnimExtention, (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) != 0 ? "shield" : "shieldknife");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) != 0 ? "shield" : "shieldknife");
}
void CKnife::ResetPlayerShieldAnim()
@@ -190,7 +190,7 @@ void CKnife::ResetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldknife");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldknife");
}
}
@@ -207,7 +207,7 @@ bool CKnife::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldknife");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldknife");
m_fMaxSpeed = KNIFE_MAX_SPEED;
m_pPlayer->m_bShieldDrawn = false;
@@ -217,7 +217,7 @@ bool CKnife::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = KNIFE_MAX_SPEED_SHIELD;
m_pPlayer->m_bShieldDrawn = true;
@@ -339,14 +339,14 @@ BOOL CKnife::Swing(BOOL fFirst)
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
// play wiff or swish sound
- EMIT_SOUND_DYN(m_pPlayer->edict(),
- CHAN_WEAPON,
- RANDOM_LONG(0, 1) ?
+ EMIT_SOUND_DYN(m_pPlayer->edict(),
+ CHAN_WEAPON,
+ RANDOM_LONG(0, 1) ?
"weapons/knife_slash1.wav" :
- "weapons/knife_slash2.wav",
- VOL_NORM,
- ATTN_NORM,
- 0,
+ "weapons/knife_slash2.wav",
+ VOL_NORM,
+ ATTN_NORM,
+ 0,
94);
// player "shoot" animation
@@ -390,10 +390,10 @@ BOOL CKnife::Swing(BOOL fFirst)
m_pPlayer->SetAnimation(PLAYER_ATTACK1);
ClearMultiDamage();
- pEntity->TraceAttack(m_pPlayer->pev,
+ pEntity->TraceAttack(m_pPlayer->pev,
KnifeSwingDamage(m_flNextPrimaryAttack + 0.4f < UTIL_WeaponTimeBase()),
- gpGlobals->v_forward,
- &tr,
+ gpGlobals->v_forward,
+ &tr,
(DMG_NEVERGIB | DMG_BULLET));
ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev);
@@ -402,7 +402,7 @@ BOOL CKnife::Swing(BOOL fFirst)
if (pEntity) // -V595
#endif
{
- if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
+ if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
#ifdef REGAMEDLL_FIXES
&& pEntity->Classify() != CLASS_VEHICLE
#endif
@@ -518,14 +518,14 @@ BOOL CKnife::Stab(BOOL fFirst)
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0f;
// play wiff or swish sound
- EMIT_SOUND_DYN(m_pPlayer->edict(),
- CHAN_WEAPON,
- RANDOM_LONG(0, 1) ?
- "weapons/knife_slash1.wav" :
- "weapons/knife_slash2.wav",
- VOL_NORM,
- ATTN_NORM,
- 0,
+ EMIT_SOUND_DYN(m_pPlayer->edict(),
+ CHAN_WEAPON,
+ RANDOM_LONG(0, 1) ?
+ "weapons/knife_slash1.wav" :
+ "weapons/knife_slash2.wav",
+ VOL_NORM,
+ ATTN_NORM,
+ 0,
94);
// player "shoot" animation
@@ -586,7 +586,7 @@ BOOL CKnife::Stab(BOOL fFirst)
if (pEntity) // -V595
#endif
{
- if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
+ if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
#ifdef REGAMEDLL_FIXES
&& pEntity->Classify() != CLASS_VEHICLE
#endif
diff --git a/regamedll/dlls/wpn_shared/wpn_m3.cpp b/regamedll/dlls/wpn_shared/wpn_m3.cpp
index 3251ae9a1..64ad7c5f0 100644
--- a/regamedll/dlls/wpn_shared/wpn_m3.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_m3.cpp
@@ -167,10 +167,17 @@ void CM3::PrimaryAttack()
m_fInSpecialReload = 0;
+#ifdef REGAMEDLL_ADD
+ if (m_pPlayer->pev->flags & FL_ONGROUND)
+ KickBack(UTIL_SharedRandomLong(m_pPlayer->random_seed + 1, 4, 6), 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+ else
+ KickBack(UTIL_SharedRandomLong(m_pPlayer->random_seed + 1, 8, 11), 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
if (m_pPlayer->pev->flags & FL_ONGROUND)
m_pPlayer->pev->punchangle.x -= UTIL_SharedRandomLong(m_pPlayer->random_seed + 1, 4, 6);
else
m_pPlayer->pev->punchangle.x -= UTIL_SharedRandomLong(m_pPlayer->random_seed + 1, 8, 11);
+#endif
m_pPlayer->m_flEjectBrass = gpGlobals->time + 0.45f;
}
diff --git a/regamedll/dlls/wpn_shared/wpn_m4a1.cpp b/regamedll/dlls/wpn_shared/wpn_m4a1.cpp
index 89ea81b5b..e9bb062e2 100644
--- a/regamedll/dlls/wpn_shared/wpn_m4a1.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_m4a1.cpp
@@ -82,13 +82,13 @@ void CM4A1::SecondaryAttack()
{
m_iWeaponState &= ~WPNSTATE_M4A1_SILENCED;
SendWeaponAnim(M4A1_DETACH_SILENCER, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "rifle");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "rifle");
}
else
{
m_iWeaponState |= WPNSTATE_M4A1_SILENCED;
SendWeaponAnim(M4A1_ATTACH_SILENCER, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "rifle");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "rifle");
}
m_flTimeWeaponIdle = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.0f;
diff --git a/regamedll/dlls/wpn_shared/wpn_p228.cpp b/regamedll/dlls/wpn_shared/wpn_p228.cpp
index b64f5fcf3..1343671cb 100644
--- a/regamedll/dlls/wpn_shared/wpn_p228.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_p228.cpp
@@ -176,7 +176,11 @@ void CP228::P228Fire(float flSpread, float flCycleTime, BOOL fUseSemi)
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
+#ifdef REGAMEDLL_ADD
+ KickBack(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= 2;
+#endif
ResetPlayerShieldAnim();
}
diff --git a/regamedll/dlls/wpn_shared/wpn_scout.cpp b/regamedll/dlls/wpn_shared/wpn_scout.cpp
index fd9456624..ec7c1a196 100644
--- a/regamedll/dlls/wpn_shared/wpn_scout.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_scout.cpp
@@ -181,7 +181,11 @@ void CSCOUT::SCOUTFire(float flSpread, float flCycleTime, BOOL fUseAutoAim)
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.8f;
+#ifdef REGAMEDLL_ADD
+ KickBack(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= 2.0f;
+#endif
}
void CSCOUT::Reload()
diff --git a/regamedll/dlls/wpn_shared/wpn_sg550.cpp b/regamedll/dlls/wpn_shared/wpn_sg550.cpp
index 8263e98a8..efad9e082 100644
--- a/regamedll/dlls/wpn_shared/wpn_sg550.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_sg550.cpp
@@ -188,8 +188,15 @@ void CSG550::SG550Fire(float flSpread, float flCycleTime, BOOL fUseAutoAim)
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.8f;
+#ifdef REGAMEDLL_ADD
+ m_iDirection = 1; // force positive Y addition
+ KickBack(UTIL_SharedRandomFloat(m_pPlayer->random_seed + 4, 0.75, 1.75) + m_pPlayer->pev->punchangle.x * 0.25,
+ UTIL_SharedRandomFloat(m_pPlayer->random_seed + 5, -0.75, 0.75),
+ 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= UTIL_SharedRandomFloat(m_pPlayer->random_seed + 4, 0.75, 1.25) + m_pPlayer->pev->punchangle.x * 0.25;
m_pPlayer->pev->punchangle.y += UTIL_SharedRandomFloat(m_pPlayer->random_seed + 5, -0.75, 0.75);
+#endif
}
void CSG550::Reload()
diff --git a/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp b/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp
index ae13158b4..56c5e27bc 100644
--- a/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp
@@ -117,7 +117,7 @@ bool CSmokeGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
m_fMaxSpeed = SMOKEGRENADE_MAX_SPEED;
m_pPlayer->m_bShieldDrawn = false;
@@ -127,7 +127,7 @@ bool CSmokeGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = SMOKEGRENADE_MAX_SPEED_SHIELD;
m_pPlayer->m_bShieldDrawn = true;
@@ -154,9 +154,9 @@ void CSmokeGrenade::SetPlayerShieldAnim()
return;
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
else
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
void CSmokeGrenade::ResetPlayerShieldAnim()
@@ -166,7 +166,7 @@ void CSmokeGrenade::ResetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
- Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren");
}
}
diff --git a/regamedll/dlls/wpn_shared/wpn_usp.cpp b/regamedll/dlls/wpn_shared/wpn_usp.cpp
index 0d830d690..de823f30e 100644
--- a/regamedll/dlls/wpn_shared/wpn_usp.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_usp.cpp
@@ -98,14 +98,14 @@ void CUSP::SecondaryAttack()
m_iWeaponState &= ~WPNSTATE_USP_SILENCED;
SendWeaponAnim(USP_DETACH_SILENCER, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "onehanded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "onehanded");
}
else
{
m_iWeaponState |= WPNSTATE_USP_SILENCED;
SendWeaponAnim(USP_ATTACH_SILENCER, UseDecrement() != FALSE);
- Q_strcpy(m_pPlayer->m_szAnimExtention, "onehanded");
+ Q_strlcpy(m_pPlayer->m_szAnimExtention, "onehanded");
}
m_flNextSecondaryAttack = m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + USP_ADJUST_SIL_TIME;
@@ -239,7 +239,11 @@ void CUSP::USPFire(float flSpread, float flCycleTime, BOOL fUseSemi)
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
+#ifdef REGAMEDLL_ADD
+ KickBack(2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
m_pPlayer->pev->punchangle.x -= 2.0f;
+#endif
ResetPlayerShieldAnim();
}
diff --git a/regamedll/dlls/wpn_shared/wpn_xm1014.cpp b/regamedll/dlls/wpn_shared/wpn_xm1014.cpp
index ec7a01dee..a4e4304eb 100644
--- a/regamedll/dlls/wpn_shared/wpn_xm1014.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_xm1014.cpp
@@ -166,10 +166,17 @@ void CXM1014::PrimaryAttack()
m_fInSpecialReload = 0;
+#ifdef REGAMEDLL_ADD
+ if (m_pPlayer->pev->flags & FL_ONGROUND)
+ KickBack(UTIL_SharedRandomLong(m_pPlayer->random_seed + 1, 3, 5), 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+ else
+ KickBack(UTIL_SharedRandomLong(m_pPlayer->random_seed + 1, 7, 10), 0.0, 0.0, 0.0, 0.0, 0.0, 0);
+#else
if (m_pPlayer->pev->flags & FL_ONGROUND)
m_pPlayer->pev->punchangle.x -= UTIL_SharedRandomLong(m_pPlayer->random_seed + 1, 3, 5);
else
m_pPlayer->pev->punchangle.x -= UTIL_SharedRandomLong(m_pPlayer->random_seed + 1, 7, 10);
+#endif
}
void CXM1014::Reload()
diff --git a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd
index 0e6838732..79fe8333a 100644
--- a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd
+++ b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd
@@ -1934,6 +1934,7 @@
bombradius(integer) : "Bomb Radius" : 500
]
+@PointClass base(Targetname) iconsprite("sprites/CS/info_target.spr") = info_landmark : "Transition/Relative teleport Landmark" []
@PointClass base(Targetname) iconsprite("sprites/CS/info_target.spr") = info_null : "info_null (spotlight target)" []
@PointClass iconsprite("sprites/CS/info_player_deathmatch.spr") base(PlayerClass) = info_player_deathmatch : "Terrorist start" []
@PointClass iconsprite("sprites/CS/info_player_start.spr") base(PlayerClass) = info_player_start : "Counter-terrorist start" []
@@ -2264,6 +2265,7 @@
@SolidClass base(Trigger) = trigger_teleport : "Trigger teleport"
[
+ landmark(string) : "Landmark name"
spawnflags(flags) =
[
256: "Keep angles" : 0
diff --git a/regamedll/game_shared/bot/bot.cpp b/regamedll/game_shared/bot/bot.cpp
index e5849b9b4..52d1f4db7 100644
--- a/regamedll/game_shared/bot/bot.cpp
+++ b/regamedll/game_shared/bot/bot.cpp
@@ -261,13 +261,6 @@ void CBot::ExecuteCommand()
// Adjust msec to command time interval
adjustedMSec = ThrottledMsec();
- // player model is "munged"
- pev->angles = pev->v_angle;
- pev->angles.x /= -3.0f;
-
- // save the command time
- m_flPreviousCommandTime = gpGlobals->time;
-
if (IsCrouching())
{
m_buttonFlags |= IN_DUCK;
@@ -282,8 +275,69 @@ void CBot::ExecuteCommand()
}
#endif
+ // Run mimic command
+ usercmd_t botCmd;
+ if (!RunMimicCommand(botCmd))
+ {
+ botCmd.forwardmove = m_forwardSpeed;
+ botCmd.sidemove = m_strafeSpeed;
+ botCmd.upmove = m_verticalSpeed;
+ botCmd.buttons = m_buttonFlags;
+ botCmd.impulse = 0;
+ botCmd.viewangles = pev->v_angle;
+ }
+
+ // player model is "munged"
+ pev->angles = pev->v_angle;
+ pev->angles.x /= -3.0f;
+
+ // save the command time
+ m_flPreviousCommandTime = gpGlobals->time;
+
// Run the command
- PLAYER_RUN_MOVE(edict(), pev->v_angle, m_forwardSpeed, m_strafeSpeed, m_verticalSpeed, m_buttonFlags, 0, adjustedMSec);
+ PLAYER_RUN_MOVE(edict(), botCmd.viewangles, botCmd.forwardmove, botCmd.sidemove, botCmd.upmove, botCmd.buttons, 0, adjustedMSec);
+}
+
+bool CBot::RunMimicCommand(usercmd_t &botCmd)
+{
+#ifdef REGAMEDLL_ADD
+ if (cv_bot_mimic.value <= 0)
+ return false;
+
+ if (cv_bot_mimic.value > gpGlobals->maxClients)
+ return false;
+
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex(cv_bot_mimic.value);
+ if (!pPlayer)
+ return false;
+
+ if (!UTIL_IsValidPlayer(pPlayer))
+ return false;
+
+ if (!pPlayer->IsAlive())
+ return false;
+
+ if (pPlayer->IsBot())
+ return false;
+
+ const usercmd_t *ucmd = pPlayer->GetLastUserCommand();
+ if (!ucmd)
+ return false;
+
+ botCmd = *ucmd;
+ botCmd.viewangles[YAW] += cv_bot_mimic_yaw_offset.value;
+
+ float mult = 8.0f;
+ botCmd.forwardmove *= mult;
+ botCmd.sidemove *= mult;
+ botCmd.upmove *= mult;
+
+ pev->fixangle = 0;
+
+ return true;
+#else
+ return false;
+#endif
}
void CBot::ResetCommand()
@@ -352,10 +406,8 @@ int CBot::GetEnemiesRemaining() const
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -380,10 +432,8 @@ int CBot::GetFriendsRemaining() const
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -436,11 +486,11 @@ NOXREF void CBot::Print(char *format, ...) const
char buffer[1024];
// prefix the message with the bot's name
- Q_sprintf(buffer, "%s: ", STRING(pev->netname));
+ Q_snprintf(buffer, sizeof(buffer), "%s: ", STRING(pev->netname));
SERVER_PRINT(buffer);
va_start(varg, format);
- vsprintf(buffer, format, varg);
+ Q_vsnprintf(buffer, sizeof(buffer), format, varg);
va_end(varg);
SERVER_PRINT(buffer);
@@ -459,12 +509,12 @@ void CBot::PrintIfWatched(char *format, ...) const
// prefix the message with the bot's name (this can be NULL if bot was just added)
const char *name = pev ? STRING(pev->netname) : "(NULL pev)";
- Q_sprintf(buffer, "%s: ", name ? name : "(NULL netname)");
+ Q_snprintf(buffer, sizeof(buffer), "%s: ", name ? name : "(NULL netname)");
SERVER_PRINT(buffer);
va_start(varg, format);
- vsprintf(buffer, format, varg);
+ Q_vsnprintf(buffer, sizeof(buffer), format, varg);
va_end(varg);
SERVER_PRINT(buffer);
@@ -491,9 +541,15 @@ void ActiveGrenade::OnEntityGone()
m_entity = nullptr;
}
+void ActiveGrenade::CheckOnEntityGone()
+{
+ if (m_dieTimestamp == 0 && !m_entity.IsValid())
+ OnEntityGone();
+}
+
bool ActiveGrenade::IsValid() const
{
- if (!m_entity)
+ if (!m_entity.IsValid())
{
if (gpGlobals->time > m_dieTimestamp)
return false;
@@ -502,7 +558,7 @@ bool ActiveGrenade::IsValid() const
return true;
}
-const Vector *ActiveGrenade::GetPosition() const
+const Vector *ActiveGrenade::GetPosition()
{
return &m_entity->pev->origin;
}
diff --git a/regamedll/game_shared/bot/bot.h b/regamedll/game_shared/bot/bot.h
index 6ad3cda11..17cec5a98 100644
--- a/regamedll/game_shared/bot/bot.h
+++ b/regamedll/game_shared/bot/bot.h
@@ -259,6 +259,8 @@ class CBot: public CBasePlayer
void ResetCommand();
byte ThrottledMsec() const;
+ bool RunMimicCommand(usercmd_t &botCmd);
+
// returns current movement speed (for walk/run)
float GetMoveSpeed();
diff --git a/regamedll/game_shared/bot/bot_manager.cpp b/regamedll/game_shared/bot/bot_manager.cpp
index 285a26a36..3fa121ba7 100644
--- a/regamedll/game_shared/bot/bot_manager.cpp
+++ b/regamedll/game_shared/bot/bot_manager.cpp
@@ -147,6 +147,8 @@ void CBotManager::StartFrame()
ActiveGrenade *ag = (*iter);
// lazy validation
+ ag->CheckOnEntityGone();
+
if (!ag->IsValid())
{
delete ag;
@@ -194,7 +196,7 @@ void CBotManager::StartFrame()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->IsBot() && IsEntityValid(pPlayer))
@@ -203,13 +205,15 @@ void CBotManager::StartFrame()
pBot->BotThink();
}
}
+
+ ValidateActiveGrenades();
}
// Return the filename for this map's "nav map" file
const char *CBotManager::GetNavMapFilename() const
{
static char filename[256];
- Q_sprintf(filename, "maps\\%s.nav", STRING(gpGlobals->mapname));
+ Q_snprintf(filename, sizeof(filename), "maps\\%s.nav", STRING(gpGlobals->mapname));
return filename;
}
@@ -225,10 +229,7 @@ void CBotManager::__API_HOOK(OnEvent)(GameEventType event, CBaseEntity* pEntity,
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -278,13 +279,16 @@ void CBotManager::RemoveGrenade(CGrenade *grenade)
}
// Destroy any invalid active grenades
-NOXREF void CBotManager::ValidateActiveGrenades()
+void CBotManager::ValidateActiveGrenades()
{
auto iter = m_activeGrenadeList.begin();
while (iter != m_activeGrenadeList.end())
{
ActiveGrenade *ag = (*iter);
+ // lazy validation
+ ag->CheckOnEntityGone();
+
if (!ag->IsValid())
{
delete ag;
@@ -314,6 +318,8 @@ bool CBotManager::IsInsideSmokeCloud(const Vector *pos)
ActiveGrenade *ag = (*iter);
// lazy validation
+ ag->CheckOnEntityGone();
+
if (!ag->IsValid())
{
delete ag;
@@ -358,6 +364,8 @@ bool CBotManager::IsLineBlockedBySmoke(const Vector *from, const Vector *to)
ActiveGrenade *ag = (*iter);
// lazy validation
+ ag->CheckOnEntityGone();
+
if (!ag->IsValid())
{
delete ag;
diff --git a/regamedll/game_shared/bot/bot_manager.h b/regamedll/game_shared/bot/bot_manager.h
index dfcfd8edc..a985fc1d7 100644
--- a/regamedll/game_shared/bot/bot_manager.h
+++ b/regamedll/game_shared/bot/bot_manager.h
@@ -42,16 +42,17 @@ class ActiveGrenade
ActiveGrenade(int weaponID, CGrenade *grenadeEntity);
void OnEntityGone();
+ void CheckOnEntityGone();
bool IsValid() const;
- bool IsEntity(CGrenade *grenade) const { return (grenade == m_entity) ? true : false; }
+ bool IsEntity(CGrenade *grenade) const { return grenade == m_entity; }
int GetID() const { return m_id; }
const Vector *GetDetonationPosition() const { return &m_detonationPosition; }
- const Vector *GetPosition() const;
+ const Vector *GetPosition();
private:
int m_id;
- CGrenade *m_entity;
+ EntityHandle m_entity;
Vector m_detonationPosition;
float m_dieTimestamp;
};
diff --git a/regamedll/game_shared/bot/bot_profile.cpp b/regamedll/game_shared/bot/bot_profile.cpp
index c025f903b..76cb37a10 100644
--- a/regamedll/game_shared/bot/bot_profile.cpp
+++ b/regamedll/game_shared/bot/bot_profile.cpp
@@ -178,9 +178,10 @@ void BotProfileManager::Init(const char *filename, unsigned int *checksum)
m_skins[m_nextSkin] = CloneString(decoratedName);
// construct the model filename
+ int SkinLen = Q_strlen(token) * 2 + Q_strlen("models/player//.mdl");
m_skinModelnames[m_nextSkin] = CloneString(token);
- m_skinFilenames[m_nextSkin] = new char[Q_strlen(token) * 2 + Q_strlen("models/player//.mdl") + 1];
- Q_sprintf(m_skinFilenames[m_nextSkin], "models/player/%s/%s.mdl", token, token);
+ m_skinFilenames[m_nextSkin] = new char[SkinLen + 1];
+ Q_snprintf(m_skinFilenames[m_nextSkin], SkinLen + 1, "models/player/%s/%s.mdl", token, token);
m_nextSkin++;
}
@@ -304,7 +305,7 @@ void BotProfileManager::Init(const char *filename, unsigned int *checksum)
// found attribute name - keep it
char attributeName[64];
- Q_strcpy(attributeName, token);
+ Q_strlcpy(attributeName, token);
// eat '='
dataFile = SharedParse(dataFile);
diff --git a/regamedll/game_shared/bot/bot_util.cpp b/regamedll/game_shared/bot/bot_util.cpp
index 9b5e2013e..4d694b318 100644
--- a/regamedll/game_shared/bot/bot_util.cpp
+++ b/regamedll/game_shared/bot/bot_util.cpp
@@ -11,10 +11,7 @@ bool UTIL_IsNameTaken(const char *name, bool ignoreHumans)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -46,14 +43,12 @@ bool UTIL_IsNameTaken(const char *name, bool ignoreHumans)
int UTIL_ClientsInGame()
{
int iCount = 0;
+
for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++)
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex(iIndex);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -68,14 +63,12 @@ int UTIL_ClientsInGame()
int UTIL_ActivePlayersInGame()
{
int iCount = 0;
+
for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(iIndex);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -102,10 +95,7 @@ int UTIL_HumansInGame(bool ignoreSpectators)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(iIndex);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -138,12 +128,9 @@ int UTIL_SpectatorsInGame()
for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++)
{
- CBasePlayer* pPlayer = UTIL_PlayerByIndex(iIndex);
-
- if (!pPlayer)
- continue;
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex(iIndex);
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -167,14 +154,12 @@ int UTIL_SpectatorsInGame()
int UTIL_HumansOnTeam(int teamID, bool isAlive)
{
int iCount = 0;
+
for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(iIndex);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -203,10 +188,7 @@ int UTIL_BotsInGame()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(iIndex);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -230,10 +212,7 @@ bool UTIL_KickBotFromTeam(TeamName kickTeam)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
const char *name = STRING(pPlayer->pev->netname);
@@ -256,10 +235,7 @@ bool UTIL_KickBotFromTeam(TeamName kickTeam)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
const char *name = STRING(pPlayer->pev->netname);
@@ -283,19 +259,17 @@ bool UTIL_KickBotFromTeam(TeamName kickTeam)
bool UTIL_IsTeamAllBots(int team)
{
int botCount = 0;
+
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (pPlayer->m_iTeam != team)
continue;
- if (FNullEnt(pPlayer->pev))
- continue;
-
if (FStrEq(STRING(pPlayer->pev->netname), ""))
continue;
@@ -403,10 +377,7 @@ bool UTIL_IsVisibleToTeam(const Vector &spot, int team, float maxRange)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -443,10 +414,7 @@ CBasePlayer *UTIL_GetLocalPlayer()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(iIndex);
- if (!pPlayer)
- continue;
-
- if (FNullEnt(pPlayer->pev))
+ if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (FStrEq(STRING(pPlayer->pev->netname), ""))
@@ -592,7 +560,7 @@ void CONSOLE_ECHO(const char *pszMsg, ...)
static char szStr[1024];
va_start(argptr, pszMsg);
- vsprintf(szStr, pszMsg, argptr);
+ Q_vsnprintf(szStr, sizeof(szStr), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(szStr);
@@ -604,7 +572,7 @@ void CONSOLE_ECHO_LOGGED(const char *pszMsg, ...)
static char szStr[1024];
va_start(argptr, pszMsg);
- vsprintf(szStr, pszMsg, argptr);
+ Q_vsnprintf(szStr, sizeof(szStr), pszMsg, argptr);
va_end(argptr);
SERVER_PRINT(szStr);
diff --git a/regamedll/game_shared/bot/bot_util.h b/regamedll/game_shared/bot/bot_util.h
index e7fbd71b0..8dfa352de 100644
--- a/regamedll/game_shared/bot/bot_util.h
+++ b/regamedll/game_shared/bot/bot_util.h
@@ -141,7 +141,7 @@ inline bool IsIntersecting2D(const Vector &startA, const Vector &endA, const Vec
// Iterate over all active players in the game, invoking functor on each.
// If functor returns false, stop iteration and return false.
template
-bool ForEachPlayer(Functor &func)
+bool ForEachPlayer(Functor func)
{
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
diff --git a/regamedll/game_shared/bot/nav_area.cpp b/regamedll/game_shared/bot/nav_area.cpp
index 1ff3ef8c5..6c5960517 100644
--- a/regamedll/game_shared/bot/nav_area.cpp
+++ b/regamedll/game_shared/bot/nav_area.cpp
@@ -3815,10 +3815,13 @@ void EditNavAreas(NavEditCmdType cmd)
if (area->GetPlace())
{
const char *name = TheBotPhrases->IDToName(area->GetPlace());
+ if (!TheBotPhrases->IsValid() && !name)
+ name = TheNavAreaGrid.IDToName(area->GetPlace());
+
if (name)
- Q_strcpy(locName, name);
+ Q_strlcpy(locName, name);
else
- Q_strcpy(locName, "ERROR");
+ Q_strlcpy(locName, "ERROR");
}
else
{
@@ -4428,6 +4431,7 @@ inline bool IsAreaVisible(const Vector *pos, const CNavArea *area)
// Determine the set of "approach areas".
// An approach area is an area representing a place where players
// move into/out of our local neighborhood of areas.
+// @todo Optimize by search from eye outward and modifying pathfinder to treat all links as bi-directional
void CNavArea::ComputeApproachAreas()
{
m_approachCount = 0;
@@ -4449,95 +4453,132 @@ void CNavArea::ComputeApproachAreas()
enum { MAX_PATH_LENGTH = 256 };
CNavArea *path[MAX_PATH_LENGTH];
- // In order to enumerate all of the approach areas, we need to
- // run the algorithm many times, once for each "far away" area
- // and keep the union of the approach area sets
- for (auto farArea : goodSizedAreaList)
+ enum SearchType
{
- BlockedIDCount = 0;
+ FROM_EYE, ///< start search from our eyepoint outward to farArea
+ TO_EYE, ///< start search from farArea beack towards our eye
+ SEARCH_FINISHED
+ };
- // if we can see 'farArea', try again - the whole point is to go "around the bend", so to speak
- if (IsAreaVisible(&eye, farArea))
- continue;
+ // In order to *completely* enumerate all of the approach areas, we
+ // need to search from our eyepoint outward, as well as from outwards
+ // towards our eyepoint
+ for (int searchType = FROM_EYE; searchType != SEARCH_FINISHED; searchType++)
+ {
+ // In order to enumerate all of the approach areas, we need to
+ // run the algorithm many times, once for each "far away" area
+ // and keep the union of the approach area sets
+ for (auto farArea : goodSizedAreaList)
+ {
+ BlockedIDCount = 0;
- // make first path to far away area
- ApproachAreaCost cost;
- if (NavAreaBuildPath(this, farArea, nullptr, cost) == false)
- continue;
+ // if we can see 'farArea', try again - the whole point is to go "around the bend", so to speak
+ if (IsAreaVisible(&eye, farArea))
+ continue;
- //
- // Keep building paths to farArea and blocking them off until we
- // cant path there any more.
- // As areas are blocked off, all exits will be enumerated.
- //
- while (m_approachCount < MAX_APPROACH_AREAS)
- {
- // find number of areas on path
- int count = 0;
- CNavArea *area;
- for (area = farArea; area; area = area->GetParent())
- count++;
-
- if (count > MAX_PATH_LENGTH)
- count = MAX_PATH_LENGTH;
-
- // build path in correct order - from eye outwards
- int i = count;
- for (area = farArea; i && area; area = area->GetParent())
- {
- path[--i] = area;
- }
+ ApproachAreaCost cost;
- // traverse path to find first area we cannot see (skip the first area)
- for (i = 1; i < count; i++)
+ //
+ // Keep building paths to farArea and blocking them off until we
+ // cant path there any more.
+ // As areas are blocked off, all exits will be enumerated.
+ //
+ while (m_approachCount < MAX_APPROACH_AREAS)
{
- // if we see this area, continue on
- if (IsAreaVisible(&eye, path[i]))
- continue;
+ CNavArea *from, *to;
- // we can't see this area.
- // mark this area as "blocked" and unusable by subsequent approach paths
- if (BlockedIDCount == MAX_BLOCKED_AREAS)
+ if (searchType == FROM_EYE)
{
- CONSOLE_ECHO("Overflow computing approach areas for area #%d.\n", m_id);
- return;
+ // find another path *to* 'farArea'
+ // we must pathfind from us in order to pick up one-way paths OUT OF our area
+ from = this;
+ to = farArea;
+ }
+ else // TO_EYE
+ {
+ // find another path *from* 'farArea'
+ // we must pathfind to us in order to pick up one-way paths INTO our area
+ from = farArea;
+ to = this;
}
- // if the area to be blocked is actually farArea, block the one just prior
- // (blocking farArea will cause all subsequent pathfinds to fail)
- int block = (path[i] == farArea) ? i - 1 : i;
+ // build the actual path
+ if (NavAreaBuildPath(from, to, NULL, cost) == false)
+ break;
- BlockedID[BlockedIDCount++] = path[block]->GetID();
+ // find number of areas on path
+ int count = 0;
+ CNavArea *area;
+ for (area = to; area; area = area->GetParent())
+ count++;
- if (block == 0)
+ if (count > MAX_PATH_LENGTH)
+ count = MAX_PATH_LENGTH;
+
+ // if the path is only two areas long, there can be no approach points
+ if (count <= 2)
break;
- // store new approach area if not already in set
- int a;
- for (a = 0; a < m_approachCount; a++)
- if (m_approach[a].here.area == path[block - 1])
- break;
+ // build path starting from eye
+ int i = 0;
- if (a == m_approachCount)
+ if (searchType == FROM_EYE)
{
- m_approach[m_approachCount].prev.area = (block >= 2) ? path[block-2] : nullptr;
- m_approach[m_approachCount].here.area = path[block - 1];
- m_approach[m_approachCount].prevToHereHow = path[block - 1]->GetParentHow();
- m_approach[m_approachCount].next.area = path[block];
- m_approach[m_approachCount].hereToNextHow = path[block]->GetParentHow();
- m_approachCount++;
+ for(area = to; i < count && area; area = area->GetParent())
+ {
+ path[count - i - 1] = area;
+ ++i;
+ }
+ }
+ else // TO_EYE
+ {
+ for(area = to; i < count && area; area = area->GetParent())
+ path[i++] = area;
}
- // we are done with this path
- break;
- }
+ // traverse path to find first area we cannot see (skip the first area)
+ for (i = 1; i < count; i++)
+ {
+ // if we see this area, continue on
+ if (IsAreaVisible(&eye, path[i]))
+ continue;
- // find another path to 'farArea'
- ApproachAreaCost cost;
- if (NavAreaBuildPath(this, farArea, nullptr, cost) == false)
- {
- // can't find a path to 'farArea' means all exits have been already tested and blocked
- break;
+ // we can't see this area.
+ // mark this area as "blocked" and unusable by subsequent approach paths
+ if (BlockedIDCount == MAX_BLOCKED_AREAS)
+ {
+ CONSOLE_ECHO("Overflow computing approach areas for area #%d.\n", m_id);
+ return;
+ }
+
+ // if the area to be blocked is actually farArea, block the one just prior
+ // (blocking farArea will cause all subsequent pathfinds to fail)
+ int block = (path[i] == farArea) ? i - 1 : i;
+
+ if (block == 0)
+ continue;
+
+ BlockedID[BlockedIDCount++] = path[block]->GetID();
+
+ // store new approach area if not already in set
+ int a;
+ for (a = 0; a < m_approachCount; a++)
+ if (m_approach[a].here.area == path[block-1])
+ break;
+
+ if (a == m_approachCount)
+ {
+ m_approach[m_approachCount].prev.area = (block >= 2) ? path[block-2] : nullptr;
+ m_approach[m_approachCount].here.area = path[block - 1];
+ m_approach[m_approachCount].prevToHereHow = path[block - 1]->GetParentHow();
+ m_approach[m_approachCount].next.area = path[block];
+ m_approach[m_approachCount].hereToNextHow = path[block]->GetParentHow();
+ m_approachCount++;
+ }
+
+ // we are done with this path
+ break;
+ }
}
}
}
@@ -4810,3 +4851,133 @@ Place CNavAreaGrid::GetPlace(const Vector *pos) const
return UNDEFINED_PLACE;
}
+
+static const char *g_pszDefaultPlaceNames[] =
+{
+ "BombsiteA",
+ "BombsiteB",
+ "BombsiteC",
+ "Hostages",
+ "HostageRescueZone",
+ "VipRescueZone",
+ "CTSpawn",
+ "TSpawn",
+ "Bridge",
+ "Middle",
+ "House",
+ "Apartment",
+ "Apartments",
+ "Market",
+ "Sewers",
+ "Tunnel",
+ "Ducts",
+ "Village",
+ "Roof",
+ "Upstairs",
+ "Downstairs",
+ "Basement",
+ "Crawlspace",
+ "Kitchen",
+ "Inside",
+ "Outside",
+ "Tower",
+ "WineCellar",
+ "Garage",
+ "Courtyard",
+ "Water",
+ "FrontDoor",
+ "BackDoor",
+ "SideDoor",
+ "BackWay",
+ "FrontYard",
+ "BackYard",
+ "SideYard",
+ "Lobby",
+ "Vault",
+ "Elevator",
+ "DoubleDoors",
+ "SecurityDoors",
+ "LongHall",
+ "SideHall",
+ "FrontHall",
+ "BackHall",
+ "MainHall",
+ "FarSide",
+ "Windows",
+ "Window",
+ "Attic",
+ "StorageRoom",
+ "ProjectorRoom",
+ "MeetingRoom",
+ "ConferenceRoom",
+ "ComputerRoom",
+ "BigOffice",
+ "LittleOffice",
+ "Dumpster",
+ "Airplane",
+ "Underground",
+ "Bunker",
+ "Mines",
+ "Front",
+ "Back",
+ "Rear",
+ "Side",
+ "Ramp",
+ "Underpass",
+ "Overpass",
+ "Stairs",
+ "Ladder",
+ "Gate",
+ "GateHouse",
+ "LoadingDock",
+ "GuardHouse",
+ "Entrance",
+ "VendingMachines",
+ "Loft",
+ "Balcony",
+ "Alley",
+ "BackAlley",
+ "SideAlley",
+ "FrontRoom",
+ "BackRoom",
+ "SideRoom",
+ "Crates",
+ "Truck",
+ "Bedroom",
+ "FamilyRoom",
+ "Bathroom",
+ "LivingRoom",
+ "Den",
+ "Office",
+ "Atrium",
+ "Entryway",
+ "Foyer",
+ "Stairwell",
+ "Fence",
+ "Deck",
+ "Porch",
+ "Patio",
+ "Wall"
+};
+
+// Return fallback place name for given place id
+const char *CNavAreaGrid::IDToName(Place place) const
+{
+ if (place <= 0 || place > ARRAYSIZE(g_pszDefaultPlaceNames))
+ return nullptr;
+
+ return g_pszDefaultPlaceNames[place - 1];
+}
+
+// Return place id for given place name
+Place CNavAreaGrid::NameToID(const char *name) const
+{
+ for (unsigned int place = 0; place < ARRAYSIZE(g_pszDefaultPlaceNames); place++)
+ {
+ const char *placeName = g_pszDefaultPlaceNames[place];
+ if (!Q_stricmp(placeName, name))
+ return place + 1;
+ }
+
+ return UNDEFINED_PLACE;
+}
diff --git a/regamedll/game_shared/bot/nav_area.h b/regamedll/game_shared/bot/nav_area.h
index d1ed024ec..c4cf8a1ff 100644
--- a/regamedll/game_shared/bot/nav_area.h
+++ b/regamedll/game_shared/bot/nav_area.h
@@ -505,6 +505,8 @@ class CNavAreaGrid
bool IsValid() const;
Place GetPlace(const Vector *pos) const; // return radio chatter place for given coordinate
+ Place NameToID(const char *name) const;
+ const char *IDToName(Place id) const;
private:
const float m_cellSize;
diff --git a/regamedll/game_shared/bot/nav_file.cpp b/regamedll/game_shared/bot/nav_file.cpp
index ad04f52c9..5c6d65c38 100644
--- a/regamedll/game_shared/bot/nav_file.cpp
+++ b/regamedll/game_shared/bot/nav_file.cpp
@@ -85,7 +85,10 @@ void PlaceDirectory::Save(int fd)
// store entries
for (auto &id : m_directory)
{
- auto placeName = TheBotPhrases->IDToName(id);
+ const char *placeName = TheBotPhrases->IDToName(id);
+
+ if (!TheBotPhrases->IsValid() && !placeName)
+ placeName = TheNavAreaGrid.IDToName(id);
// store string length followed by string itself
unsigned short len = (unsigned short)Q_strlen(placeName) + 1;
@@ -110,7 +113,11 @@ void PlaceDirectory::Load(SteamFile *file)
file->Read(&len, sizeof(unsigned short));
file->Read(placeName, len);
- AddPlace(TheBotPhrases->NameToID(placeName));
+ Place place = TheBotPhrases->NameToID(placeName);
+ if (!TheBotPhrases->IsValid() && place == UNDEFINED_PLACE)
+ place = TheNavAreaGrid.NameToID(placeName);
+
+ AddPlace(place);
}
}
@@ -625,12 +632,15 @@ bool SaveNavigationMap(const char *filename)
void LoadLocationFile(const char *filename)
{
char locFilename[256];
- Q_strcpy(locFilename, filename);
+ Q_strlcpy(locFilename, filename);
- char *dot = Q_strchr(locFilename, '.');
+ char *dot = Q_strrchr(locFilename, '.');
if (dot)
{
- Q_strcpy(dot, ".loc");
+ int dotlen = dot - locFilename;
+ size_t remaining_size = sizeof(locFilename) - dotlen;
+ if (remaining_size > 0)
+ Q_snprintf(dot, remaining_size, ".loc");
int locDataLength;
char *locDataFile = (char *)LOAD_FILE_FOR_ME(const_cast(locFilename), &locDataLength);
@@ -652,7 +662,12 @@ void LoadLocationFile(const char *filename)
for (int i = 0; i < dirSize; i++)
{
locData = SharedParse(locData);
- directory.push_back(TheBotPhrases->NameToID(SharedGetToken()));
+
+ Place place = TheBotPhrases->NameToID(SharedGetToken());
+ if (!TheBotPhrases->IsValid() && place == UNDEFINED_PLACE)
+ place = TheNavAreaGrid.NameToID(SharedGetToken());
+
+ directory.push_back(place);
}
// read places for each nav area
@@ -759,7 +774,7 @@ NavErrorType LoadNavigationMap()
// nav filename is derived from map filename
char filename[256];
- Q_sprintf(filename, "maps\\%s.nav", STRING(gpGlobals->mapname));
+ Q_snprintf(filename, sizeof(filename), "maps\\%s.nav", STRING(gpGlobals->mapname));
// free previous navigation map data
DestroyNavigationMap();
diff --git a/regamedll/lib/linux32/libc-2.15.so b/regamedll/lib/linux32/libc-2.15.so
new file mode 100644
index 000000000..8c11121eb
Binary files /dev/null and b/regamedll/lib/linux32/libc-2.15.so differ
diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj
index 57e09e917..f33cfa3dc 100644
--- a/regamedll/msvc/ReGameDLL.vcxproj
+++ b/regamedll/msvc/ReGameDLL.vcxproj
@@ -809,6 +809,9 @@
+
+
+
{70A2B904-B7DB-4C48-8DE0-AF567360D572}
ReGameDLL
diff --git a/regamedll/msvc/ReGameDLL.vcxproj.filters b/regamedll/msvc/ReGameDLL.vcxproj.filters
index ef2017ae4..bfc6d6256 100644
--- a/regamedll/msvc/ReGameDLL.vcxproj.filters
+++ b/regamedll/msvc/ReGameDLL.vcxproj.filters
@@ -1070,4 +1070,9 @@
public\tier0
+
+
+ regamedll
+
+
\ No newline at end of file
diff --git a/regamedll/pm_shared/pm_defs.h b/regamedll/pm_shared/pm_defs.h
index 8606c587d..75fba5076 100644
--- a/regamedll/pm_shared/pm_defs.h
+++ b/regamedll/pm_shared/pm_defs.h
@@ -91,6 +91,74 @@ typedef struct physent_s
} physent_t;
+#define PM_VERSION_MAJOR 1
+#define PM_VERSION_MINOR 0
+#define PM_VERSION_PATCH 0
+#define PM_VERSION PM_VERSION_MAJOR, PM_VERSION_MINOR, PM_VERSION_PATCH
+
+#define PM_VERSION_STRINGIZE(x) #x
+#define PM_VERSION_STRING(major,minor,patch) \
+ (patch == 0 ?\
+ PM_VERSION_STRINGIZE(major) "." PM_VERSION_STRINGIZE(minor) :\
+ PM_VERSION_STRINGIZE(major) "." PM_VERSION_STRINGIZE(minor) "." PM_VERSION_STRINGIZE(patch))
+
+// Control version of the player movement system
+struct PlayerMovementVersion {
+ uint8_t major, minor, patch;
+ uint32_t u32;
+
+ PlayerMovementVersion() {
+ Set(0, 0, 0);
+ }
+
+ PlayerMovementVersion(uint32_t majorVersion, uint32_t minorVersion, uint32_t patchVersion = 0) {
+ Set(majorVersion, minorVersion, patchVersion);
+ }
+
+ inline void Set(uint32_t majorVersion, uint32_t minorVersion, uint32_t patchVersion = 0)
+ {
+ major = majorVersion;
+ minor = minorVersion;
+ patch = patchVersion;
+ u32 = (major << 16) | (minor << 8) | patch;
+ }
+
+ inline void Set(const char *version)
+ {
+ if (!version)
+ return;
+
+ major = minor = patch = u32 = 0;
+ int result = sscanf(version, "%hhu.%hhu.%hhu", &major, &minor, &patch);
+ if (result < 1)
+ return; // major invalid
+
+ u32 = (major << 16) | (minor << 8) | patch;
+ }
+
+ // Compares if the current version is less than the given version
+ inline bool IsLessThan(uint32_t major, uint32_t minor, uint32_t patch = 0) const {
+ return u32 < ((major << 16) | (minor << 8) | patch);
+ }
+
+ // Compares if the current version is greater than the given version
+ inline bool IsGreaterThan(uint32_t major, uint32_t minor, uint32_t patch = 0) const {
+ return u32 > ((major << 16) | (minor << 8) | patch);
+ }
+
+ // Compares if the current version is greater than or equal to the given version
+ inline bool IsAtLeast(uint32_t major, uint32_t minor, uint32_t patch = 0) const {
+ return !IsLessThan(major, minor, patch);
+ }
+
+ const char *ToString() const {
+ static char string[14];
+ int len = Q_snprintf(string, sizeof(string), "%u.%u.%u", major, minor, patch);
+ if (patch == 0 && len > 2) string[len - 2] = '\0';
+ return string;
+ }
+};
+
typedef struct playermove_s
{
int player_index; // So we don't try to run the PM_CheckStuck nudging too quickly.
@@ -111,7 +179,7 @@ typedef struct playermove_s
qboolean bInDuck; // In process of ducking or ducked already?
int flTimeStepSound; // For walking/falling
// Next time we can play a step sound
- int iStepLeft;
+ qboolean iStepLeft;
float flFallVelocity;
vec3_t punchangle;
float flSwimTime;
diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp
index ed6819769..e9efb3763 100644
--- a/regamedll/pm_shared/pm_shared.cpp
+++ b/regamedll/pm_shared/pm_shared.cpp
@@ -123,7 +123,7 @@ void PM_InitTextureTypes()
j = Q_min(j, MAX_TEXTURENAME_LENGHT - 1 + i);
buffer[j] = '\0';
- Q_strcpy(&(pm_grgszTextureName[pm_gcTextures++][0]), &(buffer[i]));
+ Q_strlcpy(pm_grgszTextureName[pm_gcTextures++], &(buffer[i]));
}
// Must use engine to free since we are in a .dll
@@ -364,8 +364,7 @@ void PM_CatagorizeTextureType()
if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ')
pTextureName++;
- Q_strcpy(pmove->sztexturename, pTextureName);
- pmove->sztexturename[MAX_TEXTURENAME_LENGHT - 1] = '\0';
+ Q_strlcpy(pmove->sztexturename, pTextureName, MAX_TEXTURENAME_LENGHT);
// get texture type
pmove->chtexturetype = PM_FindTextureType(pmove->sztexturename);
@@ -870,7 +869,7 @@ void PM_WalkMove()
vec3_t wishvel;
real_t spd;
- float fmove, smove;
+ float fmove, smove, maxspeed;
vec3_t wishdir;
real_t wishspeed;
@@ -882,6 +881,7 @@ void PM_WalkMove()
pmtrace_t trace;
+ // jump penalty
if (pmove->fuser2 > 0.0)
{
real_t flRatio = (100 - pmove->fuser2 * 0.001 * 19) * 0.01;
@@ -893,6 +893,17 @@ void PM_WalkMove()
// Copy movement amounts
fmove = pmove->cmd.forwardmove;
smove = pmove->cmd.sidemove;
+ maxspeed = pmove->maxspeed;
+
+#ifdef REGAMEDLL_ADD
+ // Player can speed up the run if '+speed' button is pressed
+ if ((pmove->cmd.buttons & IN_RUN) && pmove->fuser3 > 0)
+ {
+ fmove *= pmove->fuser3;
+ smove *= pmove->fuser3;
+ maxspeed *= 2.0f; // increase speed cap to x2 when running
+ }
+#endif
// Zero out z components of movement vectors
pmove->forward[2] = 0;
@@ -916,10 +927,10 @@ void PM_WalkMove()
wishspeed = VectorNormalize(wishdir);
// Clamp to server defined max speed
- if (wishspeed > pmove->maxspeed)
+ if (wishspeed > maxspeed)
{
- VectorScale(wishvel, pmove->maxspeed / wishspeed, wishvel);
- wishspeed = pmove->maxspeed;
+ VectorScale(wishvel, maxspeed / wishspeed, wishvel);
+ wishspeed = maxspeed;
}
// Set pmove velocity
@@ -1438,7 +1449,7 @@ void PM_CategorizePosition()
// Do not stick to the ground of an OBSERVER or NOCLIP mode
#ifdef REGAMEDLL_FIXES
- if (pmove->movetype == MOVETYPE_NOCLIP || pmove->movetype == MOVETYPE_NONE)
+ if (pmoveplayer->m_MovementVersion.IsAtLeast(1, 0) && (pmove->movetype == MOVETYPE_NOCLIP || pmove->movetype == MOVETYPE_NONE))
{
pmove->onground = -1;
return;
@@ -1636,7 +1647,7 @@ void PM_SpectatorMove()
real_t accelspeed;
int i;
vec3_t wishvel;
- float fmove, smove;
+ float fmove, smove, spectatormaxspeed;
vec3_t wishdir;
real_t wishspeed;
@@ -1688,6 +1699,19 @@ void PM_SpectatorMove()
fmove = pmove->cmd.forwardmove;
smove = pmove->cmd.sidemove;
+ spectatormaxspeed = pmove->movevars->spectatormaxspeed;
+
+#ifdef REGAMEDLL_ADD
+ // Observer can accelerate in air if '+speed' button is pressed
+ if (pmove->cmd.buttons & IN_RUN)
+ {
+ float flAirAccelerate = (pmove->fuser3 > 0.0f) ? pmove->fuser3 : max(pmove->movevars->airaccelerate / 100.0f, 7.0f);
+ fmove *= flAirAccelerate;
+ smove *= flAirAccelerate;
+ spectatormaxspeed *= 2.0f; // increase speed cap to x2 when accelerating
+ }
+#endif
+
VectorNormalize(pmove->forward);
VectorNormalize(pmove->right);
@@ -1702,29 +1726,36 @@ void PM_SpectatorMove()
wishspeed = VectorNormalize(wishdir);
// clamp to server defined max speed
- if (wishspeed > pmove->movevars->spectatormaxspeed)
+ if (wishspeed > spectatormaxspeed)
{
- VectorScale(wishvel, pmove->movevars->spectatormaxspeed / wishspeed, wishvel);
- wishspeed = pmove->movevars->spectatormaxspeed;
+ VectorScale(wishvel, spectatormaxspeed / wishspeed, wishvel);
+ wishspeed = spectatormaxspeed;
}
currentspeed = DotProduct(pmove->velocity, wishdir);
addspeed = wishspeed - currentspeed;
+
if (addspeed <= 0)
{
- return;
+#ifdef REGAMEDLL_FIXES
+ if (pmoveplayer->m_MovementVersion.IsLessThan(1, 0))
+#endif
+ return;
}
- accelspeed = pmove->movevars->accelerate * pmove->frametime * wishspeed;
- if (accelspeed > addspeed)
+ if (addspeed > 0)
{
- accelspeed = addspeed;
- }
+ accelspeed = pmove->movevars->accelerate * pmove->frametime * wishspeed;
+ if (accelspeed > addspeed)
+ {
+ accelspeed = addspeed;
+ }
- for (i = 0; i < 3; i++)
- {
- pmove->velocity[i] += accelspeed * wishdir[i];
+ for (i = 0; i < 3; i++)
+ {
+ pmove->velocity[i] += accelspeed * wishdir[i];
+ }
}
// move
@@ -1815,7 +1846,7 @@ LINK_HOOK_VOID_CHAIN2(PM_UnDuck)
void EXT_FUNC __API_HOOK(PM_UnDuck)()
{
#ifdef REGAMEDLL_ADD
- if (unduck_method.value)
+ if (unduck_method.value || (pmove->iuser3 & PLAYER_PREVENT_DDUCK))
#endif
{
#ifdef REGAMEDLL_FIXES
@@ -1902,8 +1933,8 @@ void EXT_FUNC __API_HOOK(PM_Duck)()
}
#ifdef REGAMEDLL_ADD
- if ((pmove->iuser3 & PLAYER_PREVENT_DUCK) == PLAYER_PREVENT_DUCK // Prevent ducking if the iuser3 variable is contain PLAYER_PREVENT_DUCK
- || freezetime_duck.value == 0.0f && CSGameRules()->IsFreezePeriod()) // Prevent ducking during freezetime if the freezetime_duck cvar is 0
+ if ((pmove->iuser3 & PLAYER_PREVENT_DUCK) == PLAYER_PREVENT_DUCK // Prevent ducking if the iuser3 variable is contain PLAYER_PREVENT_DUCK
+ || (freezetime_duck.value == 0.0f && CSGameRules()->IsFreezePeriod())) // Prevent ducking during freezetime if the freezetime_duck cvar is 0
{
// Try to unduck
if (pmove->flags & FL_DUCKING)
@@ -2334,6 +2365,16 @@ void PM_NoClip()
fmove = pmove->cmd.forwardmove;
smove = pmove->cmd.sidemove;
+#ifdef REGAMEDLL_ADD
+ // Player with noclip can accelerate in air if '+speed' button is pressed
+ if ((pmove->cmd.buttons & IN_RUN) && pmove->fuser3 > 0)
+ {
+ float flAirAccelerate = pmove->fuser3;
+ fmove *= flAirAccelerate;
+ smove *= flAirAccelerate;
+ }
+#endif
+
VectorNormalize(pmove->forward);
VectorNormalize(pmove->right);
@@ -2458,8 +2499,8 @@ void EXT_FUNC __API_HOOK(PM_Jump)()
}
#ifdef REGAMEDLL_ADD
- if ((pmove->iuser3 & PLAYER_PREVENT_JUMP) == PLAYER_PREVENT_JUMP // Prevent jumping if the iuser3 variable is contain PLAYER_PREVENT_JUMP
- || freezetime_jump.value == 0.0f && CSGameRules()->IsFreezePeriod()) // Prevent jumping during freezetime if the freezetime_jump cvar is 0
+ if ((pmove->iuser3 & PLAYER_PREVENT_JUMP) == PLAYER_PREVENT_JUMP // Prevent jumping if the iuser3 variable is contain PLAYER_PREVENT_JUMP
+ || (freezetime_jump.value == 0.0f && CSGameRules()->IsFreezePeriod())) // Prevent jumping during freezetime if the freezetime_jump cvar is 0
{
return;
}
@@ -3300,6 +3341,11 @@ void EXT_FUNC __API_HOOK(PM_Move)(struct playermove_s *ppmove, int server)
{
pmove->friction = 1.0f;
}
+
+#ifdef REGAMEDLL_API
+ // save the last usercmd
+ pmoveplayer->SetLastUserCommand(pmove->cmd);
+#endif
}
NOXREF int PM_GetVisEntInfo(int ent)
@@ -3335,3 +3381,8 @@ void EXT_FUNC __API_HOOK(PM_Init)(struct playermove_s *ppmove)
pm_shared_initialized = TRUE;
}
+
+const char *PM_ServerVersion()
+{
+ return PM_VERSION_STRING(PM_VERSION_MAJOR, PM_VERSION_MINOR, PM_VERSION_PATCH);
+}
diff --git a/regamedll/pm_shared/pm_shared.h b/regamedll/pm_shared/pm_shared.h
index 2c0385f40..50550c696 100644
--- a/regamedll/pm_shared/pm_shared.h
+++ b/regamedll/pm_shared/pm_shared.h
@@ -96,4 +96,6 @@ void PM_AirAccelerate_OrigFunc(vec_t *wishdir, float wishspeed, float accel);
void PM_AirMove(int playerIndex = 0);
#endif
+const char *PM_ServerVersion();
+
extern struct playermove_s *pmove;
diff --git a/regamedll/public/regamedll/API/CSPlayer.h b/regamedll/public/regamedll/API/CSPlayer.h
index 0b8672332..05b81b704 100644
--- a/regamedll/public/regamedll/API/CSPlayer.h
+++ b/regamedll/public/regamedll/API/CSPlayer.h
@@ -141,6 +141,16 @@ class CCSPlayer: public CCSMonster {
EProtectionState GetProtectionState() const;
bool CheckActivityInGame();
+ const usercmd_t *GetLastUserCommand() const
+ {
+ return &m_LastCmd;
+ }
+
+ void SetLastUserCommand(const usercmd_t &ucmd)
+ {
+ m_LastCmd = ucmd;
+ }
+
public:
char m_szModel[32];
bool m_bForceShowMenu;
@@ -175,6 +185,10 @@ class CCSPlayer: public CCSMonster {
bool m_bPlayerDominated[MAX_CLIENTS]; // [0-31] array of state per other player whether player is dominating other players
int m_iGibDamageThreshold; // negative health to reach to gib player
+ usercmd_t m_LastCmd;
+
+ // Player movement version control
+ PlayerMovementVersion m_MovementVersion;
};
// Inlines
diff --git a/regamedll/public/regamedll/regamedll_api.h b/regamedll/public/regamedll/regamedll_api.h
index 4aeb12545..74879aa42 100644
--- a/regamedll/public/regamedll/regamedll_api.h
+++ b/regamedll/public/regamedll/regamedll_api.h
@@ -38,7 +38,7 @@
#include
#define REGAMEDLL_API_VERSION_MAJOR 5
-#define REGAMEDLL_API_VERSION_MINOR 26
+#define REGAMEDLL_API_VERSION_MINOR 28
// CBasePlayer::Spawn hook
typedef IHookChainClass IReGameHook_CBasePlayer_Spawn;
@@ -624,6 +624,10 @@ typedef IHookChainRegistryClass IReGameHookRegistry_CBa
typedef IHookChainClass IReGameHook_CBasePlayer_Observer_Think;
typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Observer_Think;
+// CBasePlayer::RemoveAllItems hook
+typedef IHookChainClass IReGameHook_CBasePlayer_RemoveAllItems;
+typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_RemoveAllItems;
+
class IReGameHookchains {
public:
virtual ~IReGameHookchains() {}
@@ -785,6 +789,7 @@ class IReGameHookchains {
virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0;
virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0;
+ virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems() = 0;
};
struct ReGameFuncs_t {
diff --git a/regamedll/public/strtools.h b/regamedll/public/strtools.h
index 5cdf8c41d..11279c76e 100644
--- a/regamedll/public/strtools.h
+++ b/regamedll/public/strtools.h
@@ -156,40 +156,48 @@ inline char *Q_strlcpy(char *dest, const char *src, size_t size) {
// a safe variant of strcpy that truncates the result to fit in the destination buffer
template
char *Q_strlcpy(char (&dest)[size], const char *src) {
- return Q_strlcpy(dest, src, size);
+ return Q_strlcpy(static_cast(dest), src, size);
}
// safely concatenate two strings.
// a variant of strcat that truncates the result to fit in the destination buffer
-template
-size_t Q_strlcat(char (&dest)[size], const char *src)
+inline size_t Q_strlcat(char *dest, const char *src, size_t maxDestSize)
{
size_t srclen; // Length of source string
size_t dstlen; // Length of destination string
// Figure out how much room is left
- dstlen = Q_strlen(dest);
- size_t length = size - dstlen + 1;
+ dstlen = strlen(dest);
+ size_t unRemainingSize = maxDestSize - dstlen - 1;
+
+ // Sanity check in case dest doesn't contain a null termination
+ if (dstlen > (maxDestSize - 1))
+ dstlen = maxDestSize - 1;
- if (!length) {
- // No room, return immediately
- return dstlen;
+ if (unRemainingSize <= 0 || unRemainingSize > maxDestSize)
+ {
+ dest[dstlen] = '\0';
+ return dstlen; // No room, return immediately
}
// Figure out how much room is needed
- srclen = Q_strlen(src);
+ srclen = strlen(src);
// Copy the appropriate amount
- if (srclen > length) {
- srclen = length;
- }
+ if (srclen > unRemainingSize)
+ srclen = unRemainingSize;
Q_memcpy(dest + dstlen, src, srclen);
dest[dstlen + srclen] = '\0';
-
return dstlen + srclen;
}
+template
+inline size_t Q_strlcat(char (&dest)[size], const char *src)
+{
+ return Q_strlcat(static_cast(dest), src, size);
+}
+
// Force slashes of either type to be = separator character
inline void Q_FixSlashes(char *pname, char separator = CORRECT_PATH_SEPARATOR)
{
diff --git a/regamedll/public/tier0/dbg.cpp b/regamedll/public/tier0/dbg.cpp
index 35c99fe38..b9bade819 100644
--- a/regamedll/public/tier0/dbg.cpp
+++ b/regamedll/public/tier0/dbg.cpp
@@ -141,7 +141,7 @@ SpewRetval_t _SpewMessageV(SpewType_t spewType, int level, const char *pMsgForma
assert(len < sizeof(szTempBuffer));
// Add \n for warning and assert
- if ((spewType == SPEW_ASSERT))
+ if (spewType == SPEW_ASSERT)
{
len += Q_snprintf(&szTempBuffer[len], sizeof(szTempBuffer) - len, "\n");
Plat_OutputDebugString(szTempBuffer);
diff --git a/regamedll/public/tier0/platform.h b/regamedll/public/tier0/platform.h
index 5703cf53b..96a208dc3 100644
--- a/regamedll/public/tier0/platform.h
+++ b/regamedll/public/tier0/platform.h
@@ -41,7 +41,7 @@
#endif
// Used to step into the debugger
-#if defined(__GNUC__) && !defined(__clang__)
+#if defined(__GNUC__) || defined(__clang__)
#define DebuggerBreak() __asm__ __volatile__("int3;")
#else
#define DebuggerBreak() __asm { int 3 }
diff --git a/regamedll/regamedll/types.natvis b/regamedll/regamedll/types.natvis
new file mode 100644
index 000000000..4dc313c65
--- /dev/null
+++ b/regamedll/regamedll/types.natvis
@@ -0,0 +1,107 @@
+
+
+
+
+
+ {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname }, { pev->health }, { m_iTeam }, { m_iModelName } }}
+
+
+
+
+
+ { *m_pContainingEntity }
+
+
+
+
+ {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname } }}
+
+
+ m_pNext
+ m_pNext
+ (*this)
+
+
+
+
+
+
+ {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname }, { pev->model } }}
+
+
+
+
+ {{ {this - g_pEdicts}, { v.classname }, { v.model } }}
+
+
+
+
+ {{ { pContainingEntity - g_pEdicts }, { classname }, { model } }}
+
+
+
+
+ { &gpGlobals->pStringBase[m_string],s }
+
+
+
+
+ allocator
+
+ - ($T1 *)m_pMemory
+ - m_nAllocationCount
+ - m_nGrowSize
+
+
+
+
+
+ {{ size = { m_Size } }}
+
+
+ m_Size
+ (ElemType_t *)m_Memory.m_pMemory
+
+
+
+
+
+
+ {{ size = { m_Tree.m_NumElements } }}
+
+ - m_Tree.m_NumElements
+ - m_Tree.m_Elements
+
+
+
+ - ((CTree::Node_t *)m_Tree.m_Elements.m_pMemory)[iMap].m_Data.elem
+ iMap++
+
+
+
+
+
+
+
+ {{ size = { $T2 } }}
+
+
+ $T2
+ ($T1 *)&m_Memory[0]
+
+
+
+
+
+
+
+ - m_NumElements
+ - m_Elements
+
+ m_NumElements
+ ((Node_t *)m_Elements.m_pMemory)[$i].m_Data
+
+
+
+
+
diff --git a/regamedll/unittests/mathfun_tests.cpp b/regamedll/unittests/mathfun_tests.cpp
index 6cb36eca5..7d39cb3b7 100644
--- a/regamedll/unittests/mathfun_tests.cpp
+++ b/regamedll/unittests/mathfun_tests.cpp
@@ -32,10 +32,10 @@ TEST(SinCosPrecision, SseMathFun, 10000)
double sse_sin = _mm_cvtss_f32(s);
double sse_cos = _mm_cvtss_f32(c);
- sprintf(localbuf, "sin precision failure for angle=%f", i);
+ Q_snprintf(localbuf, sizeof(localbuf), "sin precision failure for angle=%f", i);
DOUBLES_EQUAL(localbuf, x87_sin, sse_sin, 0.000001);
- sprintf(localbuf, "cos precision failure for angle=%f", i);
+ Q_snprintf(localbuf, sizeof(localbuf), "cos precision failure for angle=%f", i);
DOUBLES_EQUAL(localbuf, x87_cos, sse_cos, 0.000001);
}
}
diff --git a/regamedll/version/version.h b/regamedll/version/version.h
index 0f32ed96e..62c33001b 100644
--- a/regamedll/version/version.h
+++ b/regamedll/version/version.h
@@ -6,5 +6,5 @@
#pragma once
#define VERSION_MAJOR 5
-#define VERSION_MINOR 26
+#define VERSION_MINOR 28
#define VERSION_MAINTENANCE 0