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