From 4cc9a092fb9e09e4c06a0478052ad512e2aea47b Mon Sep 17 00:00:00 2001 From: Alejo Date: Wed, 14 Feb 2024 19:22:43 -0300 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d48fd3e551bc88d5271197c21c1c627316b4ce45 Merge: 5268e6b 5d2174f Author: Alejo Date: Wed Feb 14 19:17:25 2024 -0300 Merge remote-tracking branch 'upstream/master' commit 5d2174fbbf546f033118bc6d65d55d2166f66980 Author: s1lentq Date: Mon Feb 5 02:21:49 2024 +0700 CWeaponBox::Touch: Reworked dropped grenade pickup commit 4d90a5f4faabd1d220f7bbd0bfc7c246c3896717 Author: s1lentq Date: Thu Feb 1 18:20:11 2024 +0700 CWeaponBox::Touch: Fix grenade pickup (Resolves #923, Closes #931) commit f4c4e891ac094937cc56c26a17d0b2416d92b0c2 Author: s1lentq Date: Thu Feb 1 16:38:16 2024 +0700 CBasePlayerWeapon::ExtractAmmo: Fixed reverse-engineering mistake commit 2489213127db3b73cb2946ce8fe076053dbb9880 Author: s1lentq Date: Thu Feb 1 12:21:23 2024 +0700 Resetable g_weaponSlotInfo commit fb9eb0db55f6c24a333569eda1640360bdc8b0b3 Author: Francisco Muñoz Date: Wed Jan 31 09:38:35 2024 -0300 Fix excessive punchangle when getting shield shot (#919) commit 0bc4ff1d405000d8bebb5141bbc1f748f69c0d1e Author: Rafflesian <56321479+Rafflesian@users.noreply.github.com> Date: Wed Jan 31 09:35:26 2024 -0300 Support for secondary ammo and extra EF_ flags (#934) Support for secondary ammo and extra EF_ flags commit 5287f2a4150ed128e7951fc02ba32a184ed6684b Author: s1lentq Date: Wed Jan 31 19:16:37 2024 +0700 Do not reduce points for bot suicide due bot_kill command commit 0bbc4bd55d437a7097ba969b0922b1bd14a4380c Author: s1lentq Date: Wed Jan 31 18:38:47 2024 +0700 Do not reduce points for suicide due to a fatal fall commit aec3ba2579b0ef50157b9f4a2bf6643b3f8a80b0 Author: s1lentq Date: Wed Jan 31 18:33:34 2024 +0700 Fixed m_looseBombArea assertion commit b34d564e3cd9a4283de6c59ea36783714f2f18e3 Author: s1lentq Date: Wed Jan 31 17:52:38 2024 +0700 PM_CheckWater: Fix for uninitialized waterlevel value for dead players (incorrect waterlevel values from another player movements persisting) commit a1af7ca4260f6f6f5a8d795d654efe91d7603ff5 Author: s1lentq Date: Wed Jan 31 17:40:47 2024 +0700 CBasePlayer::WaterMove: No water sound playback occurs when clients emerge from network lag or was using noclip commit bde6aa07bcd1c359e38eaf5e908886d4d8762b20 Author: s1lentq Date: Wed Jan 31 15:51:44 2024 +0700 Disable door asserts (Resolves #926) commit 2d957a79152eda0ed85ee7f5e725d093ac2f8836 Author: s1lentq Date: Wed Jan 31 15:10:08 2024 +0700 utlvector.h fix assert commit 4b49f630da970cc62bb3cd7ecd65710dd7d87122 Author: s1lentq Date: Fri Jan 19 20:33:01 2024 +0700 Fix mismatched damage glock18 in burst mode 18 against 25 (GLOCK18_DAMAGE) commit 051dc0751afdf86d79660bc85c6d7ecbe1e25587 Author: Sergey Shorokhov Date: Fri Jan 12 11:55:00 2024 +0300 New ConVar: `mp_defuser_allocation` (#908) commit 89dda43b216bb771a6a1dd6960dbfa0aea603e25 Author: s1lentq Date: Fri Jan 12 13:30:01 2024 +0700 fix test demo commit 02a0516c2f257fc3e1b1bcd6408e37143944cc14 Author: s1lentq Date: Fri Jan 12 13:19:01 2024 +0700 Reset damage stats on Putin Server commit c0f47949ec8893f0f41c7d647fcdbde4d6279c99 Author: s1lentq Date: Fri Jan 12 09:27:40 2024 +0700 PM_CategorizePosition: Do not stick to the ground of an OBSERVER or NOCLIP mode commit e636cbc8f582508c0233b23de616e96998560b77 Author: s1lentq Date: Fri Jan 12 09:16:20 2024 +0700 PlayerRelationship: GR_TEAMMATE on checking itself commit 5268e6b8826317d5a4e1d3ddd2543bba3dc1e514 Merge: 9f54246 15df1a9 Author: Alejo <53284952+aleeperezz16@users.noreply.github.com> Date: Tue Jan 2 12:55:47 2024 -0300 Merge branch 's1lentq:master' into master --- README.md | 1 + dist/game.cfg | 8 ++ regamedll/common/const.h | 5 + regamedll/dlls/API/CSPlayer.cpp | 3 + regamedll/dlls/bot/cs_bot.cpp | 14 ++ regamedll/dlls/bot/cs_bot.h | 4 + regamedll/dlls/bot/cs_bot_manager.cpp | 7 +- regamedll/dlls/buttons.cpp | 7 + regamedll/dlls/cbase.cpp | 4 + regamedll/dlls/client.cpp | 28 +++- regamedll/dlls/doors.cpp | 10 +- regamedll/dlls/game.cpp | 2 + regamedll/dlls/game.h | 1 + regamedll/dlls/gamerules.h | 9 ++ regamedll/dlls/multiplay_gamerules.cpp | 72 ++++++++++ regamedll/dlls/player.cpp | 104 +++++++++++--- regamedll/dlls/player.h | 1 + regamedll/dlls/weapons.cpp | 191 ++++++++++++++++++++----- regamedll/dlls/weapons.h | 21 ++- regamedll/dlls/weapontype.cpp | 5 +- regamedll/game_shared/bot/nav_area.cpp | 5 + regamedll/game_shared/bot/nav_area.h | 1 + regamedll/pm_shared/pm_shared.cpp | 31 ++-- regamedll/public/utlvector.h | 20 +-- 24 files changed, 461 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index a2419da2f..fb9088f09 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_assist_damage_threshold | 40 | 0 | 100 | Sets the percentage of damage needed to score an assist. | | 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. | ## How to install zBot for CS 1.6? diff --git a/dist/game.cfg b/dist/game.cfg index 97fdb1fc4..d41e685b2 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -588,3 +588,11 @@ mp_freezetime_duck "1" // // Default value: "1" mp_freezetime_jump "1" + +// Give defuser on player spawn +// 0 - No free defusers (default behavior) +// 1 - Random players +// 2 - All players +// +// Default value: "0" +mp_defuser_allocation "0" diff --git a/regamedll/common/const.h b/regamedll/common/const.h index 024a2a3d5..f6ec01c48 100644 --- a/regamedll/common/const.h +++ b/regamedll/common/const.h @@ -158,6 +158,11 @@ #define EF_FORCEVISIBILITY BIT(11) // force visibility #define EF_OWNER_VISIBILITY BIT(12) // visibility for owner #define EF_OWNER_NO_VISIBILITY BIT(13) // no visibility for owner +#define EF_NOSLERP BIT(14) // no slerp flag for this entity (addtofullpack) +#define EF_FOLLOWKEEPRENDER BIT(15) // the entity following will not copy the render (like it follows nothing) + +// Custom flags that aren't handled by the client +#define EF_CUSTOM_BITS (EF_FORCEVISIBILITY | EF_OWNER_VISIBILITY | EF_OWNER_NO_VISIBILITY | EF_NOSLERP | EF_FOLLOWKEEPRENDER) // state->eflags values #define EFLAG_SLERP 1 // do studio interpolation of this entity diff --git a/regamedll/dlls/API/CSPlayer.cpp b/regamedll/dlls/API/CSPlayer.cpp index ad368bbb9..23c94ec21 100644 --- a/regamedll/dlls/API/CSPlayer.cpp +++ b/regamedll/dlls/API/CSPlayer.cpp @@ -557,6 +557,8 @@ void CCSPlayer::ResetAllStats() m_iNumKilledByUnanswered[i] = 0; m_bPlayerDominated[i] = false; } + + m_DamageList.Clear(); } void CCSPlayer::OnSpawn() @@ -586,6 +588,7 @@ void CCSPlayer::OnKilled() void CCSPlayer::OnConnect() { ResetVars(); + ResetAllStats(); m_iUserID = GETPLAYERUSERID(BasePlayer()->edict()); } diff --git a/regamedll/dlls/bot/cs_bot.cpp b/regamedll/dlls/bot/cs_bot.cpp index b0a484724..838387a95 100644 --- a/regamedll/dlls/bot/cs_bot.cpp +++ b/regamedll/dlls/bot/cs_bot.cpp @@ -429,6 +429,20 @@ bool CCSBot::StayOnNavMesh() return false; } +#ifdef REGAMEDLL_FIXES +void CCSBot::Kill() +{ + m_LastHitGroup = HITGROUP_GENERIC; + + // have the player kill himself + pev->health = 0.0f; + Killed(VARS(eoNullEntity), GIB_NEVER); + + if (CSGameRules()->m_pVIP == this) + CSGameRules()->m_iConsecutiveVIP = 10; +} +#endif + void CCSBot::Panic(CBasePlayer *pEnemy) { if (IsSurprised()) diff --git a/regamedll/dlls/bot/cs_bot.h b/regamedll/dlls/bot/cs_bot.h index 345e11fbd..9670744f9 100644 --- a/regamedll/dlls/bot/cs_bot.h +++ b/regamedll/dlls/bot/cs_bot.h @@ -375,6 +375,10 @@ class CCSBot: public CBot bool IsBuying() const; +#ifdef REGAMEDLL_FIXES + void Kill(); +#endif + void Panic(CBasePlayer *pEnemy); // look around in panic void Follow(CBasePlayer *pPlayer); // begin following given Player void ContinueFollowing(); // continue following our leader after finishing what we were doing diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp index 6324ceeb7..78ce0cf5d 100644 --- a/regamedll/dlls/bot/cs_bot_manager.cpp +++ b/regamedll/dlls/bot/cs_bot_manager.cpp @@ -408,10 +408,9 @@ void CCSBotManager::ServerCommand(const char *pcmd) if (pPlayer->IsBot()) { + CCSBot *pBot = static_cast(pPlayer); if (killThemAll || FStrEq(name, msg)) - { - pPlayer->Kill(); - } + pBot->Kill(); } } } @@ -1452,7 +1451,7 @@ void CCSBotManager::SetLooseBomb(CBaseEntity *bomb) if (bomb) { m_looseBombArea = TheNavAreaGrid.GetNearestNavArea(&bomb->pev->origin); - DbgAssert(m_looseBombArea); // TODO: Need investigation and find out why it cannot find nearest area for a lost bomb, just catch it + DbgAssert(!TheNavAreaGrid.IsValid() || m_looseBombArea); // TODO: Need investigation and find out why it cannot find nearest area for a lost bomb, just catch it } else { diff --git a/regamedll/dlls/buttons.cpp b/regamedll/dlls/buttons.cpp index 8e38b369f..8ad08fe71 100644 --- a/regamedll/dlls/buttons.cpp +++ b/regamedll/dlls/buttons.cpp @@ -1,5 +1,12 @@ #include "precompiled.h" +#if !defined(DOOR_ASSERT) +#undef DbgAssert +#undef DbgAssertMsg +#define DbgAssert(_exp) ((void)0) +#define DbgAssertMsg(_exp, _msg) ((void)0) +#endif + TYPEDESCRIPTION CEnvGlobal::m_SaveData[] = { DEFINE_FIELD(CEnvGlobal, m_globalstate, FIELD_STRING), diff --git a/regamedll/dlls/cbase.cpp b/regamedll/dlls/cbase.cpp index 1d706299b..ebfd2fdc2 100644 --- a/regamedll/dlls/cbase.cpp +++ b/regamedll/dlls/cbase.cpp @@ -1449,7 +1449,11 @@ VectorRef CBaseEntity::__API_HOOK(FireBullets3)(VectorRef vecSrc, VectorRef vecD pEntity->pev->punchangle.x = iCurrentDamage * RANDOM_FLOAT(-0.15, 0.15); pEntity->pev->punchangle.z = iCurrentDamage * RANDOM_FLOAT(-0.15, 0.15); +#ifndef REGAMEDLL_FIXES if (pEntity->pev->punchangle.x < 4) +#else + if (pEntity->pev->punchangle.x < -4) +#endif { pEntity->pev->punchangle.x = -4; } diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index 2cf9dbd63..7aa20ebee 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -249,7 +249,7 @@ void WriteSigonMessages() #ifdef PLAY_GAMEDLL // TODO: fix test demo - iFlags &= ~ITEM_FLAG_NOFIREUNDERWATER; + iFlags &= ~ITEM_FLAG_CUSTOM; #endif MESSAGE_BEGIN(MSG_INIT, gmsgWeaponList); @@ -4494,7 +4494,7 @@ BOOL EXT_FUNC AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, e #ifdef REGAMEDLL_ADD // don't send unhandled custom bits to client - state->effects &= ~(EF_FORCEVISIBILITY | EF_OWNER_VISIBILITY | EF_OWNER_NO_VISIBILITY); + state->effects &= ~EF_CUSTOM_BITS; if (ent->v.skin == CONTENTS_LADDER && (host->v.iuser3 & PLAYER_PREVENT_CLIMB) == PLAYER_PREVENT_CLIMB) { @@ -4502,7 +4502,13 @@ BOOL EXT_FUNC AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, e } #endif - if (!player && ent->v.animtime && !ent->v.velocity.x && !ent->v.velocity.y && !ent->v.velocity.z) + // add studio interpolation if non-player entity is moving (why?) + if (!player && +#ifdef REGAMEDLL_ADD + // adds slerp (studio interpolation) if not set + !(ent->v.effects & EF_NOSLERP) && +#endif + ent->v.animtime && !ent->v.velocity.x && !ent->v.velocity.y && !ent->v.velocity.z) state->eflags |= EFLAG_SLERP; state->scale = ent->v.scale; @@ -4528,8 +4534,22 @@ BOOL EXT_FUNC AddToFullPack(struct entity_state_s *state, int e, edict_t *ent, e state->aiment = 0; + // following something if (ent->v.aiment) - state->aiment = ENTINDEX(ent->v.aiment); + { +#ifdef REGAMEDLL_ADD + // if set, it will still follow the player with a bit of "delay", still looks fine (experimental) + if (ent->v.effects & EF_FOLLOWKEEPRENDER) + { + // will keep the current render entity values if it's set + state->movetype = MOVETYPE_NONE; + } + else +#endif + { + state->aiment = ENTINDEX(ent->v.aiment); + } + } state->owner = 0; if (ent->v.owner) diff --git a/regamedll/dlls/doors.cpp b/regamedll/dlls/doors.cpp index ada7e6a82..a6b252bc0 100644 --- a/regamedll/dlls/doors.cpp +++ b/regamedll/dlls/doors.cpp @@ -1,5 +1,12 @@ #include "precompiled.h" +#if !defined(DOOR_ASSERT) +#undef DbgAssert +#undef DbgAssertMsg +#define DbgAssert(_exp) ((void)0) +#define DbgAssertMsg(_exp, _msg) ((void)0) +#endif + TYPEDESCRIPTION CBaseDoor::m_SaveData[] = { DEFINE_FIELD(CBaseDoor, m_bHealthValue, FIELD_CHARACTER), @@ -695,10 +702,7 @@ void CBaseDoor::DoorGoDown() } } -#ifdef DOOR_ASSERT DbgAssert(m_toggle_state == TS_AT_TOP); -#endif - m_toggle_state = TS_GOING_DOWN; SetMoveDone(&CBaseDoor::DoorHitBottom); diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 37b6db4f0..22dbfb715 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -180,6 +180,7 @@ cvar_t sv_block_vote_commands = { "sv_block_vote_commands", "0", 0, 0 cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr }; cvar_t dying_time = { "mp_dying_time", "3.0", 0, 3.0f, nullptr }; +cvar_t defuser_allocation = { "mp_defuser_allocation", "0", 0, 0.0f, nullptr }; void GameDLL_Version_f() { @@ -440,6 +441,7 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&freezetime_duck); CVAR_REGISTER(&freezetime_jump); + CVAR_REGISTER(&defuser_allocation); CVAR_REGISTER(&max_alive_name_changes); CVAR_REGISTER(&legacy_restart_entities); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index 270ee8019..d48850108 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -200,6 +200,7 @@ extern cvar_t deathmsg_flags; extern cvar_t assist_damage_threshold; extern cvar_t freezetime_duck; extern cvar_t freezetime_jump; +extern cvar_t defuser_allocation; extern cvar_t max_alive_name_changes; extern cvar_t legacy_restart_entities; diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h index e29aaba88..e7dc35085 100644 --- a/regamedll/dlls/gamerules.h +++ b/regamedll/dlls/gamerules.h @@ -255,6 +255,13 @@ enum KillRarity KILLRARITY_REVENGE = 0x100 // Revenge by the killer }; +enum +{ + DEFUSERALLOCATION_NONE = 0, + DEFUSERALLOCATION_RANDOM = 1, + DEFUSERALLOCATION_ALL = 2, +}; + class CItem; class CGameRules @@ -738,6 +745,8 @@ class CHalfLifeMultiplay: public CGameRules int GetRarityOfKill(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, const char *killerWeaponName, bool bFlashAssist); CBasePlayer *CheckAssistsToKill(CBaseEntity *pKiller, CBasePlayer *pVictim, bool &bFlashAssist); + void GiveDefuserToRandomPlayer(); + private: void MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound(int iTeam); diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index d16a53970..398b4b1b0 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -2078,6 +2078,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)() GiveC4(); } +#ifdef REGAMEDLL_ADD + if (m_bMapHasBombTarget && (int)defuser_allocation.value == DEFUSERALLOCATION_RANDOM) + GiveDefuserToRandomPlayer(); +#endif + if (TheBots) { TheBots->OnEvent(EVENT_BUY_TIME_START); @@ -3852,6 +3857,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerSpawn)(CBasePlayer *pPlayer) #ifdef REGAMEDLL_ADD if (respawn_immunitytime.value > 0) pPlayer->SetSpawnProtection(respawn_immunitytime.value); + + // remove any defusers left over from previous random if there is just one random one + if (m_bMapHasBombTarget && (int)defuser_allocation.value == DEFUSERALLOCATION_RANDOM) + pPlayer->RemoveDefuser(); #endif } @@ -3970,6 +3979,15 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, } FireTargets("game_playerdie", pVictim, pVictim, USE_TOGGLE, 0); + +#ifdef REGAMEDLL_FIXES + // Did the player die from a fall? + if (pVictim->m_bitsDamageType & DMG_FALL) + { + // do nothing + } + else +#endif // Did the player kill himself? if (pVictim->pev == pKiller) { @@ -4378,6 +4396,9 @@ edict_t *EXT_FUNC CHalfLifeMultiplay::__API_HOOK(GetPlayerSpawnSpot)(CBasePlayer int CHalfLifeMultiplay::PlayerRelationship(CBasePlayer *pPlayer, CBaseEntity *pTarget) { + if (pPlayer == pTarget) + return GR_TEAMMATE; + #ifdef REGAMEDLL_ADD if (IsFreeForAll()) { @@ -5414,3 +5435,54 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(SendDeathMessage)(CBaseEntity *pKil MESSAGE_END(); } + +void CHalfLifeMultiplay::GiveDefuserToRandomPlayer() +{ + int iDefusersToGive = 2; + CUtlVector candidates; + candidates.EnsureCapacity(MAX_CLIENTS); + + // add all CT candidates to a list + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); + if (!pPlayer || FNullEnt(pPlayer->edict())) + continue; + + if (!pPlayer->IsAlive() || pPlayer->m_iTeam != CT) + continue; + + candidates.AddToTail(pPlayer); + } + + // randomly shuffle the list; this will keep the selection random in case of ties + for (int i = 0; i < candidates.Count(); i++) { + SWAP(candidates[i], candidates[RANDOM_LONG(0, candidates.Count() - 1)]); + } + + // now sort the shuffled list into subgroups + candidates.Sort([](CBasePlayer *const *left, CBasePlayer *const *right) -> int { + // should we prioritize humans over bots? + if (cv_bot_defer_to_human.value != 0.0f) + { + if ((*left)->IsBot() && !(*right)->IsBot()) + return 1; + + if (!(*left)->IsBot() && (*right)->IsBot()) + return -1; + } + + return 0; + } + ); + + // give defusers to the first N candidates + for (int i = 0; i < iDefusersToGive && i < candidates.Count(); ++i) + { + CBasePlayer *pPlayer = candidates[i]; + assert(pPlayer && pPlayer->m_iTeam == CT && pPlayer->IsAlive()); + + pPlayer->GiveDefuser(); + ClientPrint(pPlayer->pev, HUD_PRINTCENTER, "#Got_defuser"); + } +} diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 3b6671e6e..5df67f700 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -1319,26 +1319,52 @@ CWeaponBox *EXT_FUNC __API_HOOK(CreateWeaponBox)(CBasePlayerItem *pItem, CBasePl pWeaponBox->pev->nextthink = gpGlobals->time + lifeTime; pWeaponBox->PackWeapon(pItem); // now pack all of the items in the lists - // pack the ammo - bool exhaustibleAmmo = (pItem->iFlags() & ITEM_FLAG_EXHAUSTIBLE) == ITEM_FLAG_EXHAUSTIBLE; - if ((exhaustibleAmmo || packAmmo) && pPlayerOwner) + // player is the ammo source + if (pPlayerOwner) { -#ifndef REGAMEDLL_ADD - pWeaponBox->PackAmmo(MAKE_STRING(pItem->pszAmmo1()), pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()]); -#else - pWeaponBox->GiveAmmo(pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()], (char *)pItem->pszAmmo1(), pItem->iMaxAmmo1()); -#endif -#ifndef REGAMEDLL_FIXES // by removing ammo ONLY on exhaustible weapons (slot 4 and 5) // you are allowing to duplicate ammo whenever: // (1) you have 2 weapons sharing the same ammo type (e.g. mp5navy and glock) // (2) you are dropping a weapon alive and pickup another (with same ammo type) without ammo // and, logically, you throw your ammo with your gun with packing enabled - if (exhaustibleAmmo) + bool exhaustibleAmmo = (pItem->iFlags() & ITEM_FLAG_EXHAUSTIBLE) == ITEM_FLAG_EXHAUSTIBLE; + + // pack the primary ammo + if (exhaustibleAmmo || packAmmo) + { +#ifndef REGAMEDLL_ADD + pWeaponBox->PackAmmo(MAKE_STRING(pItem->pszAmmo1()), pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()]); +#else + pWeaponBox->GiveAmmo(pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()], (char *)pItem->pszAmmo1(), pItem->iMaxAmmo1()); +#endif + +#ifndef REGAMEDLL_FIXES + if (exhaustibleAmmo) #endif + { + pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()] = 0; + } + } + + // (3rd party support) now that reapi can register custom ammo +#ifdef REGAMEDLL_ADD + // use this flag if you don't want the player harvesting this kind of ammo from dropped weapons + bool exhaustSecondaryAmmo = (pItem->iFlags() & ITEM_FLAG_EXHAUST_SECONDARYAMMO) == ITEM_FLAG_EXHAUST_SECONDARYAMMO; + int iSecondaryAmmoIndex = pItem->SecondaryAmmoIndex(); + + // pack secondary ammo now (must be valid too) + if ((exhaustibleAmmo || exhaustSecondaryAmmo || packAmmo) && iSecondaryAmmoIndex != -1) { - pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()] = 0; + pWeaponBox->GiveAmmo(pPlayerOwner->m_rgAmmo[iSecondaryAmmoIndex], (char *)pItem->pszAmmo2(), pItem->iMaxAmmo2()); + +#ifndef REGAMEDLL_FIXES + if (exhaustibleAmmo) +#endif + { + pPlayerOwner->m_rgAmmo[iSecondaryAmmoIndex] = 0; + } } +#endif } pWeaponBox->SetModel(modelName); @@ -3098,11 +3124,16 @@ void CBasePlayer::WaterMove() // not underwater // play 'up for air' sound - if (pev->air_finished < gpGlobals->time) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade1.wav", VOL_NORM, ATTN_NORM); +#ifdef REGAMEDLL_FIXES + if (pev->flags & FL_INWATER) +#endif + { + if (pev->air_finished < gpGlobals->time) + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade1.wav", VOL_NORM, ATTN_NORM); - else if (pev->air_finished < gpGlobals->time + 9) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade2.wav", VOL_NORM, ATTN_NORM); + else if (pev->air_finished < gpGlobals->time + 9) + EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade2.wav", VOL_NORM, ATTN_NORM); + } pev->air_finished = gpGlobals->time + AIRTIME; pev->dmg = 2; @@ -3679,7 +3710,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(JoiningThink)() } if (m_pIntroCamera && gpGlobals->time >= m_fIntroCamTime -#ifdef REGAMEDLL_FIXES +#ifdef REGAMEDLL_FIXES && m_fIntroCamTime > 0.0 // update only if cameras are available #endif ) @@ -6336,6 +6367,44 @@ CBaseEntity *CBasePlayer::GiveNamedItemEx(const char *pszName) return pEntity; } +// Creates a copy of the specified entity (pEntitySource) and gives it to the player +// The cloned entity inherits base properties (entvars) of the original entity +// Returns Pointer to the cloned entity, or NULL if the entity cannot be created +CBaseEntity *CBasePlayer::GiveCopyItem(CBaseEntity *pEntitySource) +{ + edict_t *pEdict = CREATE_NAMED_ENTITY(pEntitySource->pev->classname); + if (FNullEnt(pEdict)) + { + ALERT(at_console, "NULL Ent in GiveCloneItem classname `%s`!\n", STRING(pEntitySource->pev->classname)); + return nullptr; + } + + // copy entity properties + Q_memcpy(&pEdict->v, pEntitySource->pev, sizeof(pEdict->v)); + + pEdict->v.pContainingEntity = pEdict; + pEdict->v.origin = pev->origin; + pEdict->v.spawnflags |= SF_NORESPAWN; + pEdict->v.owner = NULL; // will re-link owner after touching + pEdict->v.chain = ENT(pEntitySource->pev); // refer to source copy entity + + DispatchSpawn(pEdict); + DispatchTouch(pEdict, ENT(pev)); + pEdict->v.chain = NULL; + + CBaseEntity *pEntity = GET_PRIVATE(pEdict); + + // not allow the item to fall to the ground. + if (FNullEnt(pEdict->v.owner) || pEdict->v.owner != edict()) + { + pEdict->v.flags |= FL_KILLME; + UTIL_Remove(pEntity); + return nullptr; + } + + return pEntity; +} + CBaseEntity *FindEntityForward(CBaseEntity *pEntity) { TraceResult tr; @@ -10330,6 +10399,9 @@ void EXT_FUNC CBasePlayer::__API_HOOK(OnSpawnEquip)(bool addDefault, bool equipG case ARMOR_VESTHELM: GiveNamedItemEx("item_assaultsuit"); break; } } + + if (NeedsDefuseKit() && (int)defuser_allocation.value == DEFUSERALLOCATION_ALL) + GiveNamedItemEx("item_thighpack"); #endif } diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h index 4595bf226..8908e44c9 100644 --- a/regamedll/dlls/player.h +++ b/regamedll/dlls/player.h @@ -536,6 +536,7 @@ class CBasePlayer: public CBaseMonster { void ItemPostFrame(); CBaseEntity *GiveNamedItem(const char *pszName); CBaseEntity *GiveNamedItemEx(const char *pszName); + CBaseEntity *GiveCopyItem(CBaseEntity *pEntityBase); void EnableControl(BOOL fControl); bool HintMessage(const char *pMessage, BOOL bDisplayIfPlayerDead = FALSE, BOOL bOverride = FALSE); bool HintMessageEx(const char *pMessage, float duration = 6.0f, bool bDisplayIfPlayerDead = false, bool bOverride = false); diff --git a/regamedll/dlls/weapons.cpp b/regamedll/dlls/weapons.cpp index b43b05473..3f441975e 100644 --- a/regamedll/dlls/weapons.cpp +++ b/regamedll/dlls/weapons.cpp @@ -816,9 +816,15 @@ void CBasePlayerWeapon::FireRemaining(int &shotsFired, float &shootTime, BOOL bI flag = 0; #endif +#ifdef REGAMEDLL_API + float flBaseDamage = CSPlayerWeapon()->m_flBaseDamage; +#else + float flBaseDamage = bIsGlock ? GLOCK18_DAMAGE : FAMAS_DAMAGE; +#endif + if (bIsGlock) { - vecDir = m_pPlayer->FireBullets3(vecSrc, gpGlobals->v_forward, 0.05, 8192, 1, BULLET_PLAYER_9MM, 18, 0.9, m_pPlayer->pev, true, m_pPlayer->random_seed); + vecDir = m_pPlayer->FireBullets3(vecSrc, gpGlobals->v_forward, 0.05, 8192, 1, BULLET_PLAYER_9MM, flBaseDamage, 0.9, m_pPlayer->pev, true, m_pPlayer->random_seed); #ifndef REGAMEDLL_FIXES --m_pPlayer->ammo_9mm; #endif @@ -827,8 +833,7 @@ void CBasePlayerWeapon::FireRemaining(int &shotsFired, float &shootTime, BOOL bI } else { - - vecDir = m_pPlayer->FireBullets3(vecSrc, gpGlobals->v_forward, m_fBurstSpread, 8192, 2, BULLET_PLAYER_556MM, 30, 0.96, m_pPlayer->pev, false, m_pPlayer->random_seed); + vecDir = m_pPlayer->FireBullets3(vecSrc, gpGlobals->v_forward, m_fBurstSpread, 8192, 2, BULLET_PLAYER_556MM, flBaseDamage, 0.96, m_pPlayer->pev, false, m_pPlayer->random_seed); #ifndef REGAMEDLL_FIXES --m_pPlayer->ammo_556nato; #endif @@ -1302,9 +1307,19 @@ int CBasePlayerWeapon::AddToPlayer(CBasePlayer *pPlayer) if (!m_iPrimaryAmmoType) { m_iPrimaryAmmoType = pPlayer->GetAmmoIndex(pszAmmo1()); +#ifndef REGAMEDLL_FIXES m_iSecondaryAmmoType = pPlayer->GetAmmoIndex(pszAmmo2()); +#endif } +#ifdef REGAMEDLL_FIXES + // (3rd party support) if someone updates (or screws) the secondary ammo type later + if (!m_iSecondaryAmmoType) + { + m_iSecondaryAmmoType = pPlayer->GetAmmoIndex(pszAmmo2()); + } +#endif + if (AddWeapon()) { return CBasePlayerItem::AddToPlayer(pPlayer); @@ -1630,7 +1645,11 @@ int CBasePlayerWeapon::PrimaryAmmoIndex() int CBasePlayerWeapon::SecondaryAmmoIndex() { +#ifdef REGAMEDLL_ADD + return m_iSecondaryAmmoType; +#else return -1; +#endif } void CBasePlayerWeapon::Holster(int skiplocal) @@ -1660,7 +1679,7 @@ int CBasePlayerWeapon::ExtractAmmo(CBasePlayerWeapon *pWeapon) if (pszAmmo2()) { - res = AddSecondaryAmmo(0, (char *)pszAmmo2(), iMaxAmmo2()); + res = pWeapon->AddSecondaryAmmo(0, (char *)pszAmmo2(), iMaxAmmo2()); } return res; @@ -1875,6 +1894,91 @@ void CWeaponBox::Kill() UTIL_Remove(this); } +bool CWeaponBox::GiveAmmoToPlayer(CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon, int iCurrentAmmo, const char *pszAmmo, int iMaxAmmo, CBasePlayerItem **pGivenItem) +{ + if (iCurrentAmmo >= iMaxAmmo) + return false; // can't pickup more, these ammo are full in backpack + + // If already have a weapon in backpack, just refill ammo for it + int iAmmoIndex = GetAmmoIndex(pszAmmo); + if (iAmmoIndex > 0) + { + // How many weapon ammo can pick up? + int iAmmoPickup = min(m_rgAmmo[iAmmoIndex], iMaxAmmo - iCurrentAmmo); + if (iAmmoPickup > 0) + { + if (iCurrentAmmo == 0 && !(pPlayer->pev->weapons & (1<m_iId)) && (pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE)) + { + if (m_rgAmmo[iAmmoIndex] > iMaxAmmo) + { + // If ammo capacity of the dropped weapon exceeds the player's backpack capacity, + // make a copy of dropped weapon and give it to the player + CBasePlayerItem *copyItem = (CBasePlayerItem *)pPlayer->GiveCopyItem(pWeapon); + if (copyItem) + { + // The cloned weapon must inherit properties from a dropped weapon, such as Item Info +#ifdef REGAMEDLL_API + ItemInfo info; + if (pWeapon->CSPlayerItem()->GetItemInfo(&info)) + copyItem->CSPlayerItem()->SetItemInfo(&info); +#endif + m_rgAmmo[iAmmoIndex]--; + iAmmoPickup--; + } + } + else + { + // If no weapon in backpack, then issue weapon + if (pPlayer->AddPlayerItem(pWeapon)) + { + pWeapon->AttachToPlayer(pPlayer); + if (pGivenItem) *pGivenItem = pWeapon; + } + + // unlink this weapon from the box + return true; + } + } + + Assert(iAmmoPickup != 0); + Assert(m_rgAmmo[iAmmoIndex] != 0); + + if (!FStringNull(m_rgiszAmmo[iAmmoIndex]) && + pPlayer->GiveAmmo(iAmmoPickup, STRING(m_rgiszAmmo[iAmmoIndex]), iMaxAmmo) != -1) + { + m_rgAmmo[iAmmoIndex] -= iAmmoPickup; + + if (m_rgAmmo[iAmmoIndex] < 0) + m_rgAmmo[iAmmoIndex] = 0; + + EMIT_SOUND(pPlayer->edict(), CHAN_ITEM, "items/9mmclip1.wav", VOL_NORM, ATTN_NORM); + } + } + + // ammo exhausted, remove this weapon + if (m_rgAmmo[iAmmoIndex] <= 0) + { + pWeapon->Kill(); + + // unlink this weapon from the box + return true; + } + + // ammo has not been exhausted yet, keep this weapon in weaponbox + return false; + } + + // If no weapon in backpack, then issue weapon + if (pPlayer->AddPlayerItem(pWeapon)) + { + pWeapon->AttachToPlayer(pPlayer); + if (pGivenItem) *pGivenItem = pWeapon; + } + + // unlink this weapon from the box + return true; +} + // Try to add my contents to the toucher if the toucher is a player. void CWeaponBox::Touch(CBaseEntity *pOther) { @@ -2020,38 +2124,28 @@ void CWeaponBox::Touch(CBaseEntity *pOther) int playerGrenades = pPlayer->m_rgAmmo[pGrenade->m_iPrimaryAmmoType]; #ifdef REGAMEDLL_FIXES - // sorry for hardcode :( - const int boxAmmoSlot = 1; - - if (playerGrenades < pGrenade->iMaxAmmo1()) + CBasePlayerItem *pNext = m_rgpPlayerItems[i]->m_pNext; + + // Determine the max ammo capacity for the picked-up grenade + int iMaxPickupAmmo = pGrenade->iMaxAmmo1(); + + // If the player already has the same weapon in inventory, + // prioritize the max ammo capacity value over the one from the dropped weapon + // When the pickup occurs, ammo will be granted up to + // the max ammo capacity of the weapon currently held by the player + CBasePlayerItem *pInventoryItem = (CBasePlayerItem *)pPlayer->GetItemById((WeaponIdType)pGrenade->m_iId); + if (pInventoryItem && !Q_stricmp(pInventoryItem->pszAmmo1(), pGrenade->pszAmmo1())) + iMaxPickupAmmo = pInventoryItem->iMaxAmmo1(); + + // Pickup grenade item or refill ammo + if (GiveAmmoToPlayer(pPlayer, pGrenade, + playerGrenades, pGrenade->pszAmmo1(), iMaxPickupAmmo, &givenItem)) { - if (m_rgAmmo[boxAmmoSlot] > 1 && playerGrenades > 0) - { - if (!FStringNull(m_rgiszAmmo[boxAmmoSlot]) - && pPlayer->GiveAmmo(1, STRING(m_rgiszAmmo[boxAmmoSlot]), pGrenade->iMaxAmmo1()) != -1) - { - m_rgAmmo[boxAmmoSlot]--; - - EMIT_SOUND(pPlayer->edict(), CHAN_ITEM, "items/9mmclip1.wav", VOL_NORM, ATTN_NORM); - } - } - else - { - auto pNext = m_rgpPlayerItems[i]->m_pNext; - - if (pPlayer->AddPlayerItem(pItem)) - { - pItem->AttachToPlayer(pPlayer); - givenItem = pItem; - } - - // unlink this weapon from the box - m_rgpPlayerItems[i] = pItem = pNext; - continue; - } + // unlink this weapon from the box + m_rgpPlayerItems[i] = pItem = pNext; + continue; } #else - int maxGrenades = 0; const char *grenadeName = nullptr; @@ -2125,13 +2219,18 @@ void CWeaponBox::Touch(CBaseEntity *pOther) { if (!FStringNull(m_rgiszAmmo[n])) { - // there's some ammo of this type. -#ifndef REGAMEDLL_ADD - pPlayer->GiveAmmo(m_rgAmmo[n], (char *)STRING(m_rgiszAmmo[n]), MaxAmmoCarry(m_rgiszAmmo[n])); + // there's some ammo of this type + if (m_rgAmmo[n] > 0) + { +#ifdef REGAMEDLL_ADD + int iMaxAmmo = m_rgAmmo[n]; #else - pPlayer->GiveAmmo(m_rgAmmo[n], STRING(m_rgiszAmmo[n]), m_rgAmmo[n]); + int iMaxAmmo = MaxAmmoCarry(m_rgiszAmmo[n]); #endif + pPlayer->GiveAmmo(m_rgAmmo[n], STRING(m_rgiszAmmo[n]), iMaxAmmo); + } + // now empty the ammo from the weaponbox since we just gave it to the player m_rgiszAmmo[n] = iStringNull; m_rgAmmo[n] = 0; @@ -2271,6 +2370,24 @@ int CWeaponBox::GiveAmmo(int iCount, char *szName, int iMax, int *pIndex) return i; } +int CWeaponBox::GetAmmoIndex(const char *psz) const +{ + if (!psz) + return -1; + + int i; + for (i = 1; i < MAX_AMMO_SLOTS; i++) + { + if (FStringNull(m_rgiszAmmo[i])) + continue; + + if (!Q_stricmp(STRING(m_rgiszAmmo[i]), psz)) + return i; + } + + return -1; +} + // Is a weapon of this type already packed in this box? BOOL CWeaponBox::HasWeapon(CBasePlayerItem *pCheckItem) { diff --git a/regamedll/dlls/weapons.h b/regamedll/dlls/weapons.h index 0e865fa70..a52a1c1b7 100644 --- a/regamedll/dlls/weapons.h +++ b/regamedll/dlls/weapons.h @@ -35,12 +35,16 @@ const float MAX_DIST_RELOAD_SOUND = 512.0f; #define MAX_WEAPONS 32 -#define ITEM_FLAG_SELECTONEMPTY BIT(0) -#define ITEM_FLAG_NOAUTORELOAD BIT(1) -#define ITEM_FLAG_NOAUTOSWITCHEMPTY BIT(2) -#define ITEM_FLAG_LIMITINWORLD BIT(3) -#define ITEM_FLAG_EXHAUSTIBLE BIT(4) // A player can totally exhaust their ammo supply and lose this weapon -#define ITEM_FLAG_NOFIREUNDERWATER BIT(5) +#define ITEM_FLAG_SELECTONEMPTY BIT(0) +#define ITEM_FLAG_NOAUTORELOAD BIT(1) +#define ITEM_FLAG_NOAUTOSWITCHEMPTY BIT(2) +#define ITEM_FLAG_LIMITINWORLD BIT(3) +#define ITEM_FLAG_EXHAUSTIBLE BIT(4) // A player can totally exhaust their ammo supply and lose this weapon +#define ITEM_FLAG_NOFIREUNDERWATER BIT(5) +#define ITEM_FLAG_EXHAUST_SECONDARYAMMO BIT(6) // A player will exhaust weapon's secondary ammo supply if dropped (ITEM_FLAG_EXHAUSTIBLE does both) + +// if someone has an idea for another flag pack it here, so client prediction will not be screwed (or something) if PLAY_GAMEDLL is defined +#define ITEM_FLAG_CUSTOM (ITEM_FLAG_NOFIREUNDERWATER | ITEM_FLAG_EXHAUST_SECONDARYAMMO) #define WEAPON_IS_ONTARGET 0x40 @@ -473,6 +477,9 @@ class CWeaponBox: public CBaseEntity public: BOOL IsEmpty(); int GiveAmmo(int iCount, char *szName, int iMax, int *pIndex = nullptr); + int GetAmmoIndex(const char *psz) const; + bool GiveAmmoToPlayer(CBasePlayer *pPlayer, CBasePlayerWeapon *pWeapon, + int iCurrentAmmo, const char *pszAmmo, int iMaxAmmo, CBasePlayerItem **pGivenItem = NULL); void EXPORT Kill(); void EXPORT BombThink(); @@ -1265,7 +1272,7 @@ inline float CKnife::KnifeSwingDamage(bool fast) const { return fast ? m_flSwing inline float CKnife::KnifeStabDistance() const { return m_flStabDistance; } inline float CKnife::KnifeSwingDistance() const { return m_flSwingDistance; } inline float CKnife::KnifeBackStabMultiplier() const { return m_flBackStabMultiplier; } -#else +#else inline float CKnife::KnifeStabDamage() const { return KNIFE_STAB_DAMAGE; } inline float CKnife::KnifeSwingDamage(bool fast) const { return fast ? KNIFE_SWING_DAMAGE_FAST : KNIFE_SWING_DAMAGE; } inline float CKnife::KnifeStabDistance() const { return KNIFE_STAB_DISTANCE; } diff --git a/regamedll/dlls/weapontype.cpp b/regamedll/dlls/weapontype.cpp index 2b8ae4458..dd7dc0f82 100644 --- a/regamedll/dlls/weapontype.cpp +++ b/regamedll/dlls/weapontype.cpp @@ -290,7 +290,7 @@ AmmoInfoStruct g_ammoInfo_default[] = AmmoInfoStruct g_ammoInfo[ARRAYSIZE(g_ammoInfo_default)]; -WeaponSlotInfo g_weaponSlotInfo[] = { +WeaponSlotInfo g_weaponSlotInfo_default[] = { { WEAPON_C4, C4_SLOT, "weapon_c4" }, { WEAPON_KNIFE, KNIFE_SLOT, "weapon_knife" }, { WEAPON_P228, PISTOL_SLOT, "weapon_p228" }, @@ -324,6 +324,8 @@ WeaponSlotInfo g_weaponSlotInfo[] = { { WEAPON_SHIELDGUN, NONE_SLOT, "weapon_shield" }, }; +WeaponSlotInfo g_weaponSlotInfo[ARRAYSIZE(g_weaponSlotInfo_default)]; + // Given an alias, return the associated weapon ID WeaponIdType AliasToWeaponID(const char *alias) { @@ -566,6 +568,7 @@ void WeaponInfoReset() { Q_memcpy(g_weaponInfo, g_weaponInfo_default, sizeof(g_weaponInfo)); Q_memcpy(g_ammoInfo, g_ammoInfo_default, sizeof(g_ammoInfo)); + Q_memcpy(g_weaponSlotInfo, g_weaponSlotInfo_default, sizeof(g_weaponSlotInfo)); } WeaponSlotInfo *GetWeaponSlot(WeaponIdType weaponID) diff --git a/regamedll/game_shared/bot/nav_area.cpp b/regamedll/game_shared/bot/nav_area.cpp index 4e4bb309d..1ff3ef8c5 100644 --- a/regamedll/game_shared/bot/nav_area.cpp +++ b/regamedll/game_shared/bot/nav_area.cpp @@ -4674,6 +4674,11 @@ void CNavAreaGrid::RemoveNavArea(CNavArea *area) m_areaCount--; } +bool CNavAreaGrid::IsValid() const +{ + return m_grid && m_areaCount > 0; +} + // Given a position, return the nav area that IsOverlapping and is *immediately* beneath it CNavArea *CNavAreaGrid::GetNavArea(const Vector *pos, float beneathLimit) const { diff --git a/regamedll/game_shared/bot/nav_area.h b/regamedll/game_shared/bot/nav_area.h index 434424a1c..d1ed024ec 100644 --- a/regamedll/game_shared/bot/nav_area.h +++ b/regamedll/game_shared/bot/nav_area.h @@ -503,6 +503,7 @@ class CNavAreaGrid CNavArea *GetNavAreaByID(unsigned int id) const; CNavArea *GetNearestNavArea(const Vector *pos, bool anyZ = false) const; + bool IsValid() const; Place GetPlace(const Vector *pos) const; // return radio chatter place for given coordinate private: diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp index b41a23927..ed6819769 100644 --- a/regamedll/pm_shared/pm_shared.cpp +++ b/regamedll/pm_shared/pm_shared.cpp @@ -1345,27 +1345,27 @@ qboolean PM_InWater() // Sets pmove->waterlevel and pmove->watertype values. qboolean PM_CheckWater() { -#ifdef REGAMEDLL_FIXES - // do not check for dead - if (pmove->dead || pmove->deadflag != DEAD_NO) - return FALSE; -#endif - vec3_t point; int cont; int truecont; float height; float heightover2; + // Assume that we are not in water at all. + pmove->waterlevel = 0; + pmove->watertype = CONTENTS_EMPTY; + +#ifdef REGAMEDLL_FIXES + // do not check for dead + if (pmove->dead || pmove->deadflag != DEAD_NO) + return FALSE; +#endif + // Pick a spot just above the players feet. point[0] = pmove->origin[0] + (pmove->player_mins[pmove->usehull][0] + pmove->player_maxs[pmove->usehull][0]) * 0.5f; point[1] = pmove->origin[1] + (pmove->player_mins[pmove->usehull][1] + pmove->player_maxs[pmove->usehull][1]) * 0.5f; point[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2] + 1; - // Assume that we are not in water at all. - pmove->waterlevel = 0; - pmove->watertype = CONTENTS_EMPTY; - // Grab point contents. cont = pmove->PM_PointContents(point, &truecont); @@ -1436,6 +1436,15 @@ void PM_CategorizePosition() // water on each call, and the converse case will correct itself if called twice. PM_CheckWater(); + // Do not stick to the ground of an OBSERVER or NOCLIP mode +#ifdef REGAMEDLL_FIXES + if (pmove->movetype == MOVETYPE_NOCLIP || pmove->movetype == MOVETYPE_NONE) + { + pmove->onground = -1; + return; + } +#endif + point[0] = pmove->origin[0]; point[1] = pmove->origin[1]; point[2] = pmove->origin[2] - 2; @@ -3275,7 +3284,7 @@ void EXT_FUNC __API_HOOK(PM_Move)(struct playermove_s *ppmove, int server) DbgAssert(pm_shared_initialized); pmove = ppmove; - + #ifdef REGAMEDLL_API pmoveplayer = UTIL_PlayerByIndex(pmove->player_index + 1)->CSPlayer(); #endif diff --git a/regamedll/public/utlvector.h b/regamedll/public/utlvector.h index e3f34e585..8c0b20d3e 100644 --- a/regamedll/public/utlvector.h +++ b/regamedll/public/utlvector.h @@ -43,13 +43,6 @@ class CUtlVector CUtlVector(T *pMemory, int numElements); ~CUtlVector(); - // features C++11 ranged based for - T *begin() { return &m_Memory[0]; } - T *end() { return &m_Memory[m_Size]; } - - T const *begin() const { return &m_Memory[0]; } - T const *end() const { return &m_Memory[m_Size]; } - // Copy the array. CUtlVector &operator=(const CUtlVector &other); @@ -59,6 +52,13 @@ class CUtlVector T &Element(int i); T const &Element(int i) const; + // STL compatible member functions. These allow easier use of std::sort + // and they are forward compatible with the C++ 11 range-based for loops + T *begin() { return Base(); } + const T *begin() const { return Base(); } + T *end() { return Base() + Count(); } + const T *end() const { return Base() + Count(); } + // Gets the base address (can change when adding elements!) T *Base(); T const *Base() const; @@ -583,13 +583,13 @@ void CUtlVector::SetGrowSize(int size) template void CUtlVector::Sort() { - std::sort(Base(), Base() + Count()); + std::sort(begin(), end()); } template void CUtlVector::Sort(bool (*pfnLessFunc)(const T &src1, const T &src2)) { - std::sort(Base(), Base() + Count(), + std::sort(begin(), end(), [pfnLessFunc](const T &a, const T &b) -> bool { if (&a == &b) @@ -628,5 +628,5 @@ template template void CUtlVector::SortPredicate(F &&predicate) { - std::sort(Base(), Base() + Count(), predicate); + std::sort(begin(), end(), predicate); }