2
0
mirror of https://github.com/s1lentq/ReGameDLL_CS.git synced 2025-05-12 06:49:32 +03:00

Compare commits

...

189 Commits

Author SHA1 Message Date
GLoOoccK
8d5aa54ceb
API: Knockback () 2025-04-20 21:32:49 +07:00
GLoOoccK
a4f48f4e42
FIX: Remove grenades and C4 () 2025-04-20 21:13:08 +07:00
s1lentq
99d93ba8a7 Fix crash nav generation with impossibly-large grid 2025-04-17 04:59:11 +07:00
s1lentq
5bf71bdb18 CCSBot::FindMostDangerousThreat: Fix crash when m_pActiveItem is null Related 2025-04-08 06:59:49 +07:00
Eason
797c265db3
API: Implemented CBasePlayer::Observer_FindNextPlayer() () 2025-04-07 01:13:23 +07:00
s1lentq
312dc3eb84 Fix defuse behavior when bomb explodes
- Ensure DefuseBombEnd is called when defusing and bomb explodes to properly stop defuse
- Fixes the issue where defuse progress bar continued draw after bomb explosion
2025-04-06 04:01:26 +07:00
GLoOoccK
0fc5213049
Implements UpdateStatusBar Hook () 2025-04-04 22:47:40 +07:00
s1lentq
f3d8d1b5fd fix typo 2025-04-04 08:24:33 +07:00
s1lentq
a4d74392f0 Update player's HUD after round restart time expires, not before it 2025-04-04 02:49:40 +07:00
s1lentq
35082b5f26 fix build.sh for clang compiler 2025-04-04 02:42:29 +07:00
s1lentq
6f70d6dd8e ZBot: Implemented immediate reloading of nav data after bot analysis, without requiring a full map restart
ZBot: Added cleanup for dangling navigation pointers in bots, enabling seamless map reanalysis
Minor refactoring
2025-04-04 02:41:19 +07:00
s1lentq
f5cc6f3a8b AngleQuaternion: fix buffer overflow 2025-04-04 02:19:53 +07:00
Garey
d3fc7ac000
New flymove more accurate method () 2025-03-28 06:16:07 +07:00
Garey
ce11175e89
Add cvar for stamina restoration speed based on fps reference. ()
* Add variable for framerate (FPS), that used as reference when restoring stamina (fuser2) after jump.
2025-03-28 06:05:43 +07:00
Vaqtincha
b10f23e1e9
Add new CVars mp_playerid_showhealth & mp_playerid_field ()
* Add new CVars playerid_showhealth & mp_playerid_field
2025-03-28 05:59:34 +07:00
golukon
b44b09d07b
feat: add new cvar "mp_logkills" () 2025-03-28 05:30:32 +07:00
Vaqtincha
d8faea0966
Add new CVar mp_jump_height () 2025-03-28 05:28:15 +07:00
Vaqtincha
94a7eb4cbb
added forgot pistols fiveseven and dualelite touching for vip () 2025-03-28 05:21:24 +07:00
Vaqtincha
518f142635
Add new CVar mp_default_weapons_random () 2025-03-28 05:20:28 +07:00
Vaqtincha
dbec1b589c
Randomspawn ()
add new cvar mp_randomspawn
improved search for the best angle
added mp_randomspawn 2 for debugging
added info_spawn_point entity to .fgd
2025-03-28 05:17:02 +07:00
Vaqtincha
316405b00d
add new cvar "bot_excellent_morale" () 2025-03-28 05:10:32 +07:00
Vaqtincha
b8e9726347
fix: bots can't buy sec ammo if preferred pistol (ex. "WeaponPreference = deagle" in BotProfile.db) () 2025-03-28 05:09:56 +07:00
Francisco Muñoz
6adb795fee
Team Say refactory/enhancement ()
Disable say_team when FFA mode is enabled
Only for CT and T, Spectators can still use say_team
2025-03-28 05:09:24 +07:00
golukon
756deb1ea9
fix: calculate UpdateLocation fun not so often () 2025-03-28 05:08:42 +07:00
Huga
a7395b054d
Bot Chatter: Bots will react to enemy snipers presence ()
Friendly fire fixes
Bot Chatter: Bots will react to enemy snipers presence
previously unused chatter on both 1.6 and czero but is used on cs source
Probably fixed where teammate that use sniperrifles looking at bots that don't use sniperrifles got warned
2025-03-28 05:06:17 +07:00
Alibek Omarov
b59bbb1c83
CMake improvements, add 64-bit support for use in Xash3D FWGS ()
* cmake: do not strip debuginfo during link if DEBUG was enabled
* cmake: use compiler id instead of env checks to determine Intel compiler or Clang
* cmake: introduce XASH_COMPAT option, which will let regamedll to be built for 64-bit and non-x86 targets
* cmake: add LibraryNaming module from hlsdk-portable repository and platform detection header
* cmake: now, integrate LibraryNaming into regamedll CMakeLists file. Disable x86 options on non-x86 platforms
* server: add support for 64-bit ABI used in Xash3D FWGS
2025-03-28 05:03:52 +07:00
s1lentq
96b2ef2727 Update build.yml 2025-03-28 01:44:41 +07:00
s1lentq
f63ad678c2 Hostage minor fixes
Minor cleanup
2024-12-15 05:21:34 +07:00
s1lentq
1579273f62 Add target_cdaudio in fgd (Closes ) 2024-12-12 02:08:00 +07:00
s1lentq
17ae24e012 fix build 2024-12-12 01:31:05 +07:00
Vaqtincha
1a17ef4e45
Reset bot morale on new match(game) () 2024-12-11 23:33:26 +07:00
s1lentq
6f0d17bb74 fixed issues reported by static analyzer 2024-12-11 23:30:27 +07:00
s1lentq
8a77bba94d always consider all human players on the server to use bot_auto_vacate correctly 2024-12-11 03:50:44 +07:00
s1lentq
3efc5ad166 AUG/SG552: Reset maxspeed when zooming 2024-12-11 02:33:12 +07:00
s1lentq
942f2e6637 Removed -bots and -host-improve command line params in favor of using CVars 2024-12-11 02:33:10 +07:00
s1lentq
df7944ab88 Disable broken angle adjustment with throw direction in Killed to avoid player model visual artifacts 2024-12-10 20:46:00 +07:00
s1lentq
476b5f7afd fix typo 2024-12-09 22:10:03 +07:00
Sergey Shorokhov
7738142c69
CI Workflow Refactor and Fixes ()
chore(ci): standardize and update CI workflows for compatibility and consistency

- Updated action versions (`checkout@v4`, `upload-artifact@v4`, `download-artifact@v4`) for enhanced compatibility and security
- Removed unsecure Node.js version allowance to align with *-latest OS requirements
- Migrated test demos to `rehldsorg/testdemos:latest` container with a streamlined testing approach via matrix strategy and `runTest.sh`
- Standardized Linux dependency installation for consistent build environment across jobs
- Unified CI workflow structure with `rehlds` and `regamedll` repositories for better consistency
- Optimized artifact deployment steps and removed unnecessary cleanup operations

Co-authored-by: s1lentq <s1lentsk@yandex.ru>
2024-10-29 09:22:24 +03:00
Nord1cWarr1or
535ea846a9
client.cpp: Use macros for pfnPrecacheEvent () 2024-10-23 23:08:29 +07:00
Vaqtincha
9b626b1d82
add desc to readme () 2024-09-18 07:49:24 +07:00
Vaqtincha
9b7b1695a9
escape feature for bots () 2024-09-17 16:35:21 +07:00
s1lentq
3f628ea970 DeathSound: Don't interrupt pain sounds with death sound, use any available channel instead 2024-09-17 02:49:27 +07:00
s1lentq
19714af6e6 get rid of unsafe string functions
minor refactor
2024-09-13 06:43:27 +07:00
Vaqtincha
3cf66de905
fix mp_kill_filled_spawn () 2024-09-13 04:22:08 +07:00
s1lentq
dc16b12d79 [skip ci] VisualStudio: Add auto visualizer for some structures/classes 2024-08-25 05:45:09 +07:00
s1lentq
12f4e9bc79 remove unnecessary version consistency for some player movement code 2024-08-17 04:55:17 +07:00
s1lentq
a8fd512dad Fix linux build 2024-08-16 10:05:39 +07:00
s1lentq
8b6d659077 Implemented simple player movement version control to avoid desync
Bump minor API version
2024-08-16 09:53:11 +07:00
Vaqtincha
4e1cb1091f fix Deagle animation () 2024-08-14 12:35:00 +03:00
Francisco Muñoz
b6c2c62e8b
Added mp_vote_flags and mp_votemap_min_time cvars ()
* Added mp_vote_flags cvar
* Added mp_votemap_min_time cvar
* Cvars on README
* game.cfg cvars
* Ensure timers check before new restrictions
2024-08-12 13:45:54 +07:00
Francisco Muñoz
c7bd4af9b6
Cache ObjectCaps call inside PlayerUse ()
Not really useful, discovered while testing on 3rd party plugins that ObjectCaps was being called unnecessarily more than once per entity
2024-08-12 13:45:21 +07:00
Francisco Muñoz
fee10d8ba8
Fix Shotguns reload flag not getting reset on weapon changing () 2024-08-12 13:40:09 +07:00
Francisco Muñoz
c48be87474
Extend KickBack functionalities () 2024-08-06 08:11:59 +07:00
s1lentq
77a3f2b25b try fix a crash due to the deletion of an item in an unusual way
related , , , 
2024-08-06 07:19:58 +07:00
s1lentq
279799bff9 Add support IN_RUN key for +speed button in spectator/noclip and walk moves
Add cheat impulse for enable Noclip with air accelerate
2024-08-06 05:03:10 +07:00
s1lentq
17386acac4 Update build.yml 2024-08-06 04:26:00 +07:00
s1lentq
11638cbb21 Fixed a bug in spectator move with no apply friction when stopped 2024-08-06 03:54:56 +07:00
s1lentq
a47d55823f Fix compiler warnings 2024-08-06 03:26:10 +07:00
s1lentq
ff843fe478 Update workflows/build.yml
Fix temporarily testdemos
2024-08-06 03:19:31 +07:00
Sergey Shorokhov
9d9c2de1ff
Feature: ConVars for weapon/item/ammo respawn time ()
* `CBasePlayerAmmo`: check spawnflags on `Spawn()`

* `CBasePlayerItem`: check spawnflags on `Materialize()`

* `CBasePlayerItem`: Add `Respawn()` item when hasn't specific spawnflags

* `CBasePlayerItem`: remove `SF_NORESPAWN` flag on `Respawn()`

* Use forgotten `AMMO_RESPAWN_TIME`

* new ConVars: `mp_item_respawn_time`, `mp_weapon_respawn_time`, `mp_ammo_respawn_time`
2024-08-03 20:17:52 +03:00
Sergey Shorokhov
a202425dd7
Fix: ammo/weapons respawn behavior ()
* `CBasePlayerAmmo`: check spawnflags on `Spawn()`

* `CBasePlayerItem`: check spawnflags on `Materialize()`

* `CBasePlayerItem`: Add `Respawn()` item when hasn't specific spawnflags

* `CBasePlayerItem`: remove `SF_NORESPAWN` flag on `Respawn()`

* Use forgotten `AMMO_RESPAWN_TIME`
2024-08-03 20:11:08 +03:00
s1lentq
576e967cbd Workflows: Downgrade linux distro 2024-07-27 20:35:54 +07:00
s1lentq
1991434301 [skip ci] Fixed typo version 2024-07-15 20:28:49 +07:00
s1lentq
79cfd7103a Linking against legacy libc <= 2.15 2024-07-15 02:18:23 +07:00
s1lentq
30572ef0b6 Change compiler to Clang, instead of ICC 2019 2024-07-14 23:27:44 +07:00
Vaqtincha
8005dd9ca3
Fix bot_kill command (killed already dead bots) () 2024-07-09 00:53:21 +07:00
s1lentq
a94c7bd728 Fix crouch bot 2024-06-09 15:46:50 +07:00
s1lentq
ad1c58cef5 Add bot_mimic 2024-06-03 01:57:21 +07:00
s1lentq
fef9bf3a87 mp_defuser_allocation: Send a message with a hint instead of the text in the center 2024-06-03 00:29:00 +07:00
s1lentq
bdc96d26d9 Minor rework bot_quota_mode fill 2024-06-03 00:28:57 +07:00
s1lentq
c7be8bfe7c MULTIDAMAGE: make check entity safe
ApplyMultiDamage: Fixed potential crash when in TakeDamage hook causes another additional damage
2024-05-31 23:21:37 +07:00
s1lentq
7372573c89 Add UTIL_IsValidPlayer
Ignore dormant players
Minor refactoring
2024-05-29 00:23:28 +07:00
Sergey Shorokhov
c08e6d0180
CNavArea::ComputeApproachAreas(): fix hang on *.nav generating () 2024-05-12 17:17:02 +03:00
s1lentq
9f66264562 KillOfRarity: Add feature in-air kill 2024-05-09 02:38:12 +07:00
s1lentq
8706cc5a10 KillRarity Domination: Don't consider suicides to be unanswered killing 2024-05-09 00:30:57 +07:00
s1lentq
cabdc254c7 ActiveGrenade: Fixed a potential leak by checking entities smokegrens life if RemoveGrenade call is somehow missing or blocked 2024-05-09 00:20:22 +07:00
s1lentq
8ff1bf1232 Fix typo 2024-05-08 23:01:02 +07:00
Federico Matías
8ec5b6cd0f
Fix SendDeathMessage kill rarity flags and transform to VFUNC ()
* implement VFUNC to `SendDeathMessage`
* fix use KILLRARITY_HEADSHOT flag instead of member
* fix rare crash when pAssister is nullptr
* fix KILLRARITY_DOMINATION_BEGAN flag
This flag was never valid in "SendDeathMessage" hook
* set iDeathMessageFlags before call function
2024-05-08 22:59:40 +07:00
Francisco Muñoz
4ecf42799d
Fix ApplyMultiDamage duplicated call on MultiDamage routine () 2024-05-08 22:18:36 +07:00
肯定龙
d7f22ae3ec
Restart trigger_multiple () 2024-05-08 22:18:24 +07:00
Lê Hàn Minh Khang
75f142e18a
Add trigger_teleport landmark ()
* Add trigger_teleport landmark
2024-05-08 21:52:41 +07:00
肯定龙
8cd9086937
Implement game_round_end and game_round_freeze_end triggers ()
* Implement `game_round_end` and `game_round_freeze_end` triggers
2024-05-08 20:59:27 +07:00
s1lentq
2a0e54bbf7 Bump minor version up to 27 2024-05-08 14:55:21 +07:00
Javekson
0626800fbb
Implement RemoveAllItems hook () 2024-05-08 14:50:53 +07:00
Vaqtincha
d5eb9c34d2
don't send radio message to teammate (if freeforall 1) ()
* don't send radio message to teammate (if freeforall 1)
* don't send message zero length
2024-04-15 15:49:44 +07:00
s1lentq
f24cccfe73 Fix linux build 2024-04-08 16:47:02 +07:00
s1lentq
5117374a27 Separate mp_location_area_info from chat and radar
Add fallback location message for chat
2024-04-08 16:42:08 +07:00
s1lentq
279bd6421b Fix crash 2024-04-08 12:41:22 +07:00
s1lentq
8c14d05168 Add fallback place names if BotChatter.db is missing 2024-04-07 18:49:08 +07:00
s1lentq
1ae0091947 Added CVar mp_location_area_info for display location area info in HUDs radio chat and below radar 2024-04-07 16:41:56 +07:00
s1lentq
f711276d8a ignore kill assist when victim killed himself while changing team 2024-04-04 19:31:27 +07:00
s1lentq
a546997723 CWeaponBox::Touch: Fixed a hang when touching a weaponbox if multiple items are packed in a slot 2024-03-31 22:46:06 +07:00
s1lentq
92775824e6 IsWalkableTraceLineClear: Fixed deadlock (mutual collisions in traces leading to hang) 2024-02-29 06:52:48 +07:00
s1lentq
5d2174fbbf CWeaponBox::Touch: Reworked dropped grenade pickup 2024-02-05 02:21:49 +07:00
s1lentq
4d90a5f4fa CWeaponBox::Touch: Fix grenade pickup (Resolves , Closes ) 2024-02-01 18:20:11 +07:00
s1lentq
f4c4e891ac CBasePlayerWeapon::ExtractAmmo: Fixed reverse-engineering mistake 2024-02-01 16:38:16 +07:00
s1lentq
2489213127 Resetable g_weaponSlotInfo 2024-02-01 12:21:23 +07:00
Francisco Muñoz
fb9eb0db55
Fix excessive punchangle when getting shield shot () 2024-01-31 19:38:35 +07:00
Rafflesian
0bc4ff1d40
Support for secondary ammo and extra EF_ flags ()
Support for secondary ammo and extra EF_ flags
2024-01-31 19:35:26 +07:00
s1lentq
5287f2a415 Do not reduce points for bot suicide due bot_kill command 2024-01-31 19:16:37 +07:00
s1lentq
0bbc4bd55d Do not reduce points for suicide due to a fatal fall 2024-01-31 19:14:04 +07:00
s1lentq
aec3ba2579 Fixed m_looseBombArea assertion 2024-01-31 18:33:34 +07:00
s1lentq
b34d564e3c PM_CheckWater: Fix for uninitialized waterlevel value for dead players (incorrect waterlevel values from another player movements persisting) 2024-01-31 17:52:38 +07:00
s1lentq
a1af7ca426 CBasePlayer::WaterMove: No water sound playback occurs when clients emerge from network lag or was using noclip 2024-01-31 17:40:47 +07:00
s1lentq
bde6aa07bc Disable door asserts (Resolves ) 2024-01-31 15:51:44 +07:00
s1lentq
2d957a7915 utlvector.h fix assert 2024-01-31 15:10:08 +07:00
s1lentq
4b49f630da Fix mismatched damage glock18 in burst mode 18 against 25 (GLOCK18_DAMAGE) 2024-01-19 20:33:01 +07:00
Sergey Shorokhov
051dc0751a
New ConVar: mp_defuser_allocation () 2024-01-12 11:55:00 +03:00
s1lentq
89dda43b21 fix test demo 2024-01-12 13:30:01 +07:00
s1lentq
02a0516c2f Reset damage stats on Putin Server 2024-01-12 13:19:01 +07:00
s1lentq
c0f47949ec PM_CategorizePosition: Do not stick to the ground of an OBSERVER or NOCLIP mode 2024-01-12 09:50:41 +07:00
s1lentq
e636cbc8f5 PlayerRelationship: GR_TEAMMATE on checking itself 2024-01-12 09:16:20 +07:00
Shorokhov Sergey
15df1a9cf2 readme: labels fix
[skip ci]
2024-01-02 02:04:40 +03:00
Sergey Shorokhov
71606f8f36
game.cfg: Add forgotten double quotation marks
[skip ci]
2024-01-02 01:45:55 +03:00
s1lentq
d3c0ec8aeb Fixed crash bot when can see a loose bomb but didn't get closest area for bomb 2023-12-31 17:30:29 +07:00
s1lentq
991573f165 Fixed bot navigation route when connected area somehow is null 2023-12-31 07:56:45 +07:00
s1lentq
6c9019bcc8 Set KILLRARITY_KILLER_BLIND flag only when fully blind 2023-12-23 02:51:04 +07:00
s1lentq
0e68bedf24 Fixed rarity of kills suicide, thrusmoke and for some weapons 2023-12-23 02:43:42 +07:00
s1lentq
28e2bc45f6 Fix crash bot_nav_use_place when place name is not exists 2023-12-22 20:25:38 +07:00
s1lentq
b413577428 cleanup 2023-12-14 13:24:49 +07:00
Francisco Muñoz
f63b154637
Add member m_iGibDamageThreshold to control GIB damage threshold ()
* Add member m_iGibDamageThreshold to control GIB damage threshold
2023-12-14 06:01:34 +07:00
s1lentq
8c0b684046 Enable assert mode 2023-12-14 03:18:04 +07:00
s1lentq
abe648b9d6 Use custom assert instead normal 2023-12-14 03:16:27 +07:00
s1lentq
db5cbee2b8 Fix windows build 2023-12-14 03:05:40 +07:00
s1lentq
4928c56f21 Change some Asserts to DbgAssert 2023-12-14 02:54:32 +07:00
s1lentq
f97c9d9f46 Improve dbg code to work Assertion properly 2023-12-14 02:50:32 +07:00
s1lentq
806f5651de Fixed assertion check 2023-12-13 20:01:12 +07:00
s1lentq
85e882f4db utlvector.h add sort methods 2023-12-13 19:19:31 +07:00
s1lentq
8ed193d254 fix linux build 2023-12-13 19:14:01 +07:00
s1lentq
e6d25ba159 utlarray.h add sort methods 2023-12-13 19:01:25 +07:00
s1lentq
34e56f61f2 Minor refactoring API functions 2023-12-12 18:59:13 +07:00
s1lentq
d98e8f8b60 cleanup 2023-12-12 06:43:32 +07:00
s1lentq
a63bcf0a10 delta.lst adjust premultiply for clientdata_t::origin 2023-12-08 00:49:16 +07:00
s1lentq
59362ec8d5 delta.lst maximum entity_state_player_t::effects value raised 2023-12-07 03:52:47 +07:00
s1lentq
4f0818b7bf delta.lst maximum entity_state_t::body value raised 2023-12-07 03:52:47 +07:00
s1lentq
7c9582f44b delta.lst increased float-point accuracy for fields entity_state_player_t::origin 2023-12-07 03:52:46 +07:00
s1lentq
0c29cf36fc UpdateClientData: No send health negative value to draw HUD 2023-12-07 03:52:45 +07:00
s1lentq
5e2aadceac delta.lst maximum health value raised to 131072 from 512 transmitted over network 2023-12-07 03:52:44 +07:00
s1lentq
7ea9beffdf delta.lst increased float-point accuracy for fields clientdata_t::origin, clientdata_t::punchangle 2023-12-07 03:52:39 +07:00
s1lentq
e5f546c453 Added delta.lst file 2023-12-07 03:14:12 +07:00
Francisco Muñoz
6863777b81
Initialize m_pevLastInflictor to nullptr to avoid garbage memory () 2023-12-02 05:51:26 +07:00
Francisco Muñoz
f882e81efe
Update studio.h constants ()
* Update studio.h file, magic number change
- Updated studio.h header, limits increased according to engine ones, added missing structures (in case of)
2023-11-28 19:47:52 +07:00
Francisco Muñoz
d135a67bb7
Allow null player pointer in CreateWeaponBox () 2023-11-27 15:22:33 +07:00
Francisco Muñoz
556406009f
Tiny API code clean () 2023-11-26 12:59:01 +07:00
Ecnologia
15bca2eab9
Implements Observer_Think Hook ()
* Observer Think Hook
* Update CAPI_Impl.cpp
* Update CAPI_Impl.h
* Update regamedll_api.h
2023-11-26 11:27:09 +07:00
Francisco Muñoz
fba9a335da
Avoid intro camera switching when only 1 trigger_camera available ()
* Add UTIL_CountEntities, adjust m_fIntroCamTime assignation
* Moved camera count caching to CheckLevelInitialized
2023-11-26 11:25:08 +07:00
Francisco Muñoz
193c1ed52a
Fixed grenades disappearing when speed exceeds 2000 fixed units ignoring sv_maxvelocity ()
* Fixed grenades disappearing when speed exceeds 2000 fixed units ignoring sv_maxvelocity
* Clamp nades velocity to sv_maxvelocity value when reached
* Make IsInWorld behave like SV_CheckVelocity: less/greater without equal
* Enclose IsInWorld changes with FIXES macro
2023-11-26 11:24:48 +07:00
Javekson
b10489f2e0
Changed the order of setting pev->body for the correct value in SetBombIcon() () 2023-11-26 11:24:29 +07:00
Francisco Muñoz
9ab1589d32
Use CSEntity member to hold last inflictor from TakeDamage () 2023-11-26 11:21:04 +07:00
Federico Matías
e3d70d2b14
New CVars: mp_freezetime_duck and mp_freezetime_jump ()
* new cvars: prevent duck/jump during freezetime
* use CSGameRules() instead of g_pGameRules
* changed name of cvars and default value
* improved cvars description
2023-11-26 11:13:29 +07:00
fl0werD
2d0ac93f63
Implement PlayerDeathThink hook () 2023-11-08 21:18:01 +07:00
Dmitry Novikov
c87761e182
Added updating more game info to the player who started recording the demo () 2023-11-08 21:15:29 +07:00
s1lentq
2857986cc7 Reworked cvar mp_deathmsg_flags (use flags instead of bitsums) 2023-11-08 21:11:27 +07:00
s1lentq
96e2121c45 Improve CBaseTrigger::InitTrigger to allow use custom triggers without bsp model just origin,mins,maxs 2023-10-28 16:40:23 +07:00
Vaqtincha
426c975a88
Ammo type hardcode fix ()
* Useful for custom ammo types.
2023-10-25 11:37:32 +07:00
Francisco Muñoz
7e02dea4a0 Drop defuser on disconnect 2023-10-24 10:48:53 +07:00
Francisco Muñoz
a2678a18ed
Ensure HasPrimary flag assignation on successful weapon removal () 2023-10-11 05:03:48 +07:00
Francisco Muñoz
e422a37d8b
Reduce code redundancy in observer.cpp () 2023-10-11 05:03:11 +07:00
Francisco Muñoz
2f50f5ab9d
Group defuser give code in one function () 2023-10-11 05:02:27 +07:00
Javekson
a9ec63df1b
Updated the GiveC4 to return a player pointer () 2023-10-08 20:59:45 +07:00
Sergey Shorokhov
96ba309e4a
SG_Detonate: make event realible () 2023-10-06 19:18:57 +03:00
s1lentq
3a0970a1cd Fixed typo when checking a teammate 2023-10-05 16:26:03 +07:00
s1lentq
ac07e89269 Back to using MSG_ALL for the DeathMsg event in favor of backward compatibility (issue )
Minor refactoring
2023-10-01 01:30:56 +07:00
s1lentq
b962e0eb8e Fixed 2023-09-30 14:54:32 +07:00
s1lentq
1e49d94792 Fixed no fall damage when ff_damage_reduction_other set 0 (also damage with ITBD_POISON) 2023-09-30 00:18:37 +07:00
s1lentq
71c4e21385 Fixed a crash when killer is worldspawn 2023-09-29 01:19:31 +07:00
Dmitry Novikov
108db28143
Add an extended player's DeathMsg message ()
* Implemented rarity of kill and assist for extended user message DeathMsg
* Add hookchain CGameRules::SendDeathMessage
* Add domination and revenge
2023-09-28 16:18:15 +07:00
Francisco Muñoz
67e7d87423
FIX: Reloading animation bug while holding weapon with altered Maxclip ()
* Add functions for default weaponinfo array
* Whitespace cleaning and pointer safety check
* Added reload condition to enhance conditions
2023-09-28 16:08:35 +07:00
Francisco Muñoz
8a52b7e38d
API: CSPlayer methods enhancement ()
* Adding return type to DropShield and DropPlayerItem
* JoinTeam: force C4 drop when changing to SPEC
2023-09-28 16:06:35 +07:00
Javekson
d7b44099e7
Refactored RemovePlayerItemEx and Extended DestroyItem in CBasePlayerItem () 2023-09-28 16:06:04 +07:00
Alejo
ee34b06605
New CVar: mp_team_flash ()
* Added new CVar `mp_team_flash`
2023-09-05 11:10:38 +07:00
s1lentq
7b7a1b9d94 Bump minor version up to 23 2023-09-05 11:01:46 +07:00
Francisco Muñoz
1aae57fd17
Fix: Grenade weaponbox not deploying on unarmed player () 2023-09-05 10:54:20 +07:00
Javekson
728f1fcc67
Fixed of m_lastDamageAmount recording during armor calculation () 2023-09-05 10:53:22 +07:00
Dmitry Novikov
e8bff71475
Fixed crash sometimes occurring while zbot map analyzing () 2023-09-05 10:53:05 +07:00
Francisco Muñoz
facc2be534
Various defuser fixes and code refactory ()
* Defuser code refactory and fix
2023-09-05 10:52:44 +07:00
Francisco Muñoz
2e6e77906f
Ensure m_pDriver assignation on func_vehicle only () 2023-09-05 10:52:30 +07:00
Francisco Muñoz
f441279294
API: CSPlayer new members (physics related) ()
* CSPlayer new members
* API refactory in pm_shared.cpp
* Cached CSPlayer pointer in a global variable
* Changed PM_JumpHeight from lambda function to an inline function
* Changed m_flDuckSpeedMultiplier data type to double
2023-09-05 10:52:14 +07:00
Francisco Muñoz
696f465977
API: Added new API funcs (6) and new Hookchains (21) ()
* Added few newest API Hookchains
* Added hookchain for PM_CheckWaterJump
* Added hookchain for PM_Jump
* Added hookchain for PM_Duck
* Added hookchain for PM_UnDuck
* Added hookchain for ClearMultiDamage
* Added hookchain for AddMultiDamage
* Added hookchain for ApplyMultiDamage
* Added hookchain for CSGameRules::TeamFull
* Added hookchain for CSGameRules::TeamStacked
* Added hookchain for CSGameRules::PlayerGotWeapon
* Added hookchain for CBotManager::OnEvent
* Added hookchain for CBasePlayer::EntSelectSpawnPoint
* Added hookchain for CBasePlayerWeapon::KickBack
* Added hookchain for CBasePlayerWeapon::SendWeaponAnim
* Added new PM_* Hookchains
* Added PM_WaterJump
* Added PM_PlayStepSound
* Added PM_AirAccelerate
* Added CBasePlayer::CheckTimeBasedDamage
* Added CBasePlayerWeapon::ItemPostFrame
* Added BuyItem and CSGameRules::Think
* AddAmmoNameToAmmoRegistry refactory
* Bump minor version in an API bump up to 23
2023-09-05 10:43:40 +07:00
s1lentq
f3723d7a04 Add reserve members for CCS Entity
Bump interface version up to CSENTITY_API_INTERFACE_VERSION003
2023-08-24 17:09:50 +07:00
s1lentq
02bb06a6ef Fixed bug when restarting a button using multisource (Do not use multisource when restarting a button) 2023-08-23 23:14:31 +07:00
Francisco Muñoz
53d26a7ea5
API: CSPlayerWeapon integration + new members and functions ()
- Member name changed to m_iStateSecondaryAttack
- Member type changed to uint8_t which has same size of bool but allows more values than true or false (this wont break API compatibility)
- Moved logic inside HasSecondaryAttack to correctly alter function return based on m_iStateSecondaryAttack, which can be (0) no value / null (1) set (2) block
-Removed logic in CBasePlayerWeapon::Spawn that caches the return value of HasSecondaryAttack, as this can only be overridden when set, rather than always
* Improve API compatibility
2023-08-23 21:27:35 +07:00
Sergey Shorokhov
942776783b
mp_fadetoblack 2 fade timings now depends from mp_dying_time CVar and code fixes ()
Fix forcing 1-person view for players when `mp_fadetoblack = 2`;
 Fix player blackout on server entry when `mp_fadetoblack = 2`;
 Fix observer not being blinded when `mp_fadetoblack = 2`;
 Fix fadetoblack message timings using new CVar `mp_dying_time`.

fix 
fix 

Co-authored-by: s1lentq <s1lentsk@yandex.ru>
2023-07-16 15:55:58 +03:00
s1lentq
c526fa5885 Enable location feature if bots allowed or listen server is running 2023-07-16 04:17:14 +07:00
s1lentq
ad13545dac TutorMessageEvent::GetNextParameter: Fixed corrupted stack 2023-07-16 04:13:08 +07:00
Adrian Cirstea
718f0330f1
API: Implement PM_LadderMove hook ()
Related to https://github.com/s1lentq/reapi/issues/82
2023-07-16 03:48:44 +07:00
Francisco Muñoz
8a8f348755
Adjust gib's velocity limit according to sv_maxvelocity ()
* Adjust gib's velocity limit according to sv_maxvelocity
* Gib max velocity adjusted to sv_maxvelocity
2023-07-15 04:34:54 +07:00
Francisco Muñoz
11d6b086b4
Shield constants code cleaning ()
* Change constant name (SHIELDREN -> SHIELDGREN)

* Correct and separate constant names
2023-07-13 01:29:56 +03:00
Sergey Shorokhov
8a18969be1
New CVar: mp_dying_time ()
* Add new CVar: mp_dying_time < 0 .. 999>

* Add description

* magic numbers to named const

* magic numbers to named const (№2)

* cvar value handling

* update description

* a better description

* resolve conflicts

* lil order fixes & indent

* remove death animation skip

* DYING_TIME -> DEATH_ANIMATION_TIME

* Fix death animation when mp_dying_time < 3.0 depending on animation

* change desc

* change cvar desc

---------

Co-authored-by: dystopm <fjmunozpena@gmail.com>
2023-07-12 20:43:37 +03:00
160 changed files with 8626 additions and 2533 deletions

@ -24,23 +24,18 @@ jobs:
buildTests: 'Tests'
steps:
- name: Configure
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- 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'
vs-version: '16'
- name: Build and Run unittests
run: |
@ -66,93 +61,76 @@ jobs:
move msvc\${{ env.buildRelease }}\mp.pdb publish\debug\mp.pdb
- name: Deploy artifacts
uses: actions/upload-artifact@v3.1.1
uses: actions/upload-artifact@v4
with:
name: win32
path: publish/*
testdemos:
name: 'Test demos'
runs-on: ubuntu-20.04
container: s1lentq/testdemos:latest
runs-on: ubuntu-latest
container: rehldsorg/testdemos:latest
needs: [windows]
env:
WINEDEBUG: -all
WINEDLLOVERRIDES: mshtml=
defaults:
run:
shell: bash
working-directory: ../../../opt/HLDS
working-directory: /opt/HLDS
strategy:
fail-fast: false
matrix:
test: [
{ file: 'cstrike-basic-1', desc: 'CS: Testing jumping, scenarios, shooting etc' },
]
steps:
- name: Deploying windows artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: win32
- name: Play demos
- name: Setup dependencies
run: |
chown root ~
rsync -a deps/regamedll/* .
mv $GITHUB_WORKSPACE/tests/mp.dll cstrike/dlls/mp.dll
descs=(
"CS: Testing jumping, scenarios, shooting etc"
)
demos=(
"cstrike-basic-1"
)
retVal=0
for i in "${!demos[@]}"; do
params=$(cat "testdemos/${demos[i]}.params")
echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[0m"
echo -e " - \e[0;33mParameters $params\e[0m"
wine hlds.exe --rehlds-enable-all-hooks --rehlds-test-play "testdemos/${demos[i]}.bin" $params &> result.log || retVal=$?
if [ $retVal -ne 777 ] && [ $retVal -ne 9 ]; then
# Print with catchy messages
while read line; do
echo -e " \e[0;33m$line"
done <<< $(cat result.log | sed '0,/demo failed/I!d;/wine:/d;/./,$!d')
echo " 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸"
while read line; do
echo -e " \e[1;31m$line";
done < rehlds_demo_error.txt
echo -e " \e[30;41mExit code: $retVal\e[0m"
echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[1;31m Failed ❌"
exit 6 # Test demo failed
else
# Print result HLDS console
while read line; do
echo -e " \e[0;33m$line"
done <<< $(cat result.log | sed '/wine:/d;/./,$!d')
echo -e " \e[30;43mExit code: $retVal\e[0m"
echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[1;32m Succeed ✔"
fi
done
- name: Play test
env:
demo: ${{ matrix.test.file }}
desc: ${{ matrix.test.desc }}
run: ./runTest.sh
linux:
name: 'Linux'
runs-on: ubuntu-20.04
container: s1lentq/linux86buildtools:latest
runs-on: ubuntu-latest
container: debian:11-slim
steps:
- name: Install dependencies
run: |
dpkg --add-architecture i386
apt-get update
apt-get install -y \
gcc-multilib g++-multilib \
build-essential \
libc6-dev libc6-dev-i386 \
git cmake rsync \
g++ gcc
- name: Configure
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
submodules: true
- 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 +151,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/')
- name: Build using GCC Compiler
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
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 +163,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 +171,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
@ -211,31 +179,25 @@ jobs:
shell: bash
- name: Deploy artifacts
uses: actions/upload-artifact@v3.1.1
uses: actions/upload-artifact@v4
id: upload-job
with:
name: linux32
path: publish/*
- name: Cleanup temporary artifacts
if: success() && steps.upload-job.outcome == 'success'
run: |
rm -rf cssdk
rm -f appversion.h
publish:
name: 'Publish'
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
needs: [windows, testdemos, linux]
steps:
- name: Deploying linux artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: linux32
- name: Deploying windows artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: win32
@ -265,7 +227,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/') &&
@ -276,8 +238,3 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.API_TOKEN }}
- name: Cleanup temporary artifacts
if: success() && steps.publish-job.outcome == 'success'
run: |
rm -rf bin dist debug cssdk
rm -f *.zip appversion.h

1
.gitignore vendored

@ -2,6 +2,7 @@
*.bat
*.log
*.lnk
*.aps
**/msvc/Debug*
**/msvc/Release*
**/msvc/Tests

@ -1,4 +1,4 @@
# ReGameDLL_CS [![Download](https://camo.githubusercontent.com/0c15c5ed5da356288ad4bb69ed24267fb48498f2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f73316c656e74712f526547616d65444c4c5f43532e737667)](https://github.com/s1lentq/ReGameDLL_CS/releases/latest) [![Downloads](https://camo.githubusercontent.com/7eb895bf12d373df1d7c2bd2af3eb7d6328cdf6c02eee380fa93f81365c32d41/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f73316c656e74712f526547616d65444c4c5f43532f746f74616c3f636f6c6f723d696d706f7274616e74)]() [![Percentage of issues still open](http://isitmaintained.com/badge/open/s1lentq/ReGameDLL_CS.svg)](http://isitmaintained.com/project/s1lentq/ReGameDLL_CS "Percentage of issues still open") [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) <img align="right" src="https://cloud.githubusercontent.com/assets/5860435/20008568/b3623150-a2d3-11e6-85f3-0d6571045fc9.png" alt="Counter-Strike 1.6 GameDLL" />
# ReGameDLL_CS [![GitHub release (by tag)](https://img.shields.io/github/downloads/s1lentq/ReGameDLL_CS/latest/total)](https://github.com/s1lentq/ReGameDLL_CS/releases/latest) ![GitHub all releases](https://img.shields.io/github/downloads/s1lentq/ReGameDLL_CS/total) [![Percentage of issues still open](http://isitmaintained.com/badge/open/s1lentq/ReGameDLL_CS.svg)](http://isitmaintained.com/project/s1lentq/ReGameDLL_CS "Percentage of issues still open") [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) <img align="right" src="https://cloud.githubusercontent.com/assets/5860435/20008568/b3623150-a2d3-11e6-85f3-0d6571045fc9.png" alt="Counter-Strike 1.6 GameDLL" />
Reverse-engineered gamedll (mp.dll / Counter-Strike)
## What is this?
@ -29,6 +29,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
| swapteams | Swap the teams and restart the game (1 sec delay to restart by default).<br/> Args: <br/>`0` - swap teams without restart. <br/> `>0.001` - time delay in seconds to restart the round after swap. |
| give | Give weapon command.<br/> Args:<br/><weapon_name><br/>Usage:<br/>`give weapon_ak47`<br/>`give weapon_usp`<br/><br/>NOTE: `sv_cheats 1` required. |
| impulse 255 | Give all weapons.<br/><br/>NOTE: `sv_cheats 1` required. |
| impulse 200 | Noclip with air acceleration.<br/><br/>NOTE: `sv_cheats 1` required. |
## Configuration (cvars)
<details>
@ -97,9 +98,11 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
| mp_ct_give_player_knife | 1 | 0 | 1 | Whether Counter-Terrorist player spawn with knife. |
| mp_ct_default_weapons_primary | "" | "" | - | The default primary (rifle) weapon that the CTs will spawn with. |
| mp_ct_default_weapons_secondary | "usp" | "" | - | The default secondary (pistol) weapon that the CTs will spawn with. |
| mp_default_weapons_random | 0 | 0 | 1 | Randomize default weapons (if there are multiple).<br/> `0` disabled<br/>`1` enabled |
| mp_give_player_c4 | 1 | 0 | 1 | Whether this map should spawn a C4 bomb for a player or not.<br/> `0` disabled<br/>`1` enabled |
| mp_weapons_allow_map_placed | 1 | 0 | 1 | When set, map weapons (located on the floor by map) will be shown.<br/> `0` hide all map weapons.<br/>`1` enabled<br/>`NOTE`: Effect will work after round restart. |
| mp_free_armor | 0 | 0 | 2 | Give free armor on player spawn.<br/>`0` disabled <br/>`1` Give Kevlar <br/>`2` Give Kevlar + Helmet |
| mp_team_flash | 1 | -1 | 1 | Sets the behaviour for Flashbangs on teammates.<br/>`-1` Don't affect teammates neither flash owner <br/>`0` Don't affect teammates <br/>`1` Affects teammates |
| mp_fadetoblack | 0 | 0 | 2 | Observer's screen will fade to black on kill event or permanent.<br/> `0` No fade.<br/>`1` Fade to black and won't be able to watch anybody.<br/>`2` fade to black only on kill moment. |
| mp_falldamage | 1 | 0 | 1 | Damage from falling.<br/>`0` disabled <br/>`1` enabled |
| sv_allchat | 1 | 0 | 1 | Players can receive all other players text chat, team restrictions apply<br/>`0` disabled <br/>`1` enabled |
@ -109,15 +112,37 @@ This means that plugins that do binary code analysis (Orpheu for example) probab
| mp_give_c4_frags | 3 | - | - | How many bonuses (frags) will get the player who defused or exploded the bomb. |
| mp_hostages_rescued_ratio | 1.0 | 0.0 | 1.0 | Ratio of hostages rescued to win the round. |
| mp_legacy_vehicle_block | 1 | 0 | 1 | Legacy func_vehicle behavior when blocked by another entity.<br/>`0` New behavior <br/>`1` Legacy behavior |
| mp_dying_time | 3.0 | 0.0 | - | Time for switch to free observing after death.<br/>`0` - disable spectating around death.<br/>`>0.00001` - time delay to start spectate.<br/>`NOTE`: The countdown starts when the players death animation is finished. |
| mp_deathmsg_flags | abc | 0 | - | Sets a flags for extra information in the player's death message.<br/>`0` disabled<br/>`a` position where the victim died<br/>`b` index of the assistant who helped the attacker kill the victim<br/>`c` rarity classification bits, e.g., `blinkill`, `noscope`, `penetrated`, etc. |
| 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.<br/> `0` disabled<br/>`1` enabled |
| mp_freezetime_jump | 1 | 0 | 1 | Allow players to jump during freezetime.<br/> `0` disabled<br/>`1` enabled |
| mp_defuser_allocation | 0 | 0 | 2 | Give defuser on player spawn.<br/> `0` disabled<br/>`1` Random players. <br/>`2` All players. |
| mp_location_area_info | 0 | 0 | 3 | Enable location area info.<br/> `0` disabled<br/>`1` show location below HUD radar.<br/>`2` show location in HUD chat. `NOT RECOMMENDED!` [:speech_balloon:](## "Not all client builds are compatible")<br/>`3` both displayed. `NOT RECOMMENDED!` [:speech_balloon:](## "Not all client builds are compatible")<br/><br/>`NOTE`: Navigation `maps/.nav` file required and should contain place names<br/>`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.<br/>`0` voting disabled<br/>`k` votekick enabled via `vote` command<br/>`m` votemap enabled via `votemap` command |
| mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. |
| mp_flymove_method | 0 | 0 | 1 | Set the method used for flymove calculations.<br/> `0` default method<br/>`1` alternative method (more accurate) |
| mp_stamina_restore_rate | 0 | 0.0 | - | Framerate (FPS), that used as reference when restoring stamina (fuser2) after jump. |
| mp_logkills | 1 | 0 | 1 | Log kills.<br/>`0` disabled <br/>`1` enabled |
| mp_jump_height | 45 | 0.0 | - | Player jump height. |
| bot_excellent_morale | 0 | 0 | 1 | Bots always have great morale regardless of defeat or victory. |
| mp_randomspawn | 0 | 0 | 1 | Random player spawns<br/>`0` disabled <br/>`1` enabled<br/>`NOTE`: Navigation `maps/.nav` file required |
| mp_playerid_showhealth | 1 | 0 | 2 | Player ID display mode.<br/>`0` don't show health<br/>`1` show health for teammates only (default CS behaviour)<br/>`2` show health for all players |
| mp_playerid_field | 3 | 0 | 3 | Player ID field display mode.<br/>`0` don't show additional information<br/>`1` show team name<br/>`2` show health percentage<br/>`3` show both team name and health percentage |
| mp_knockback | 170 | - | - | Knockback force applied to the victim when damaged by strong weapons (e.g. `AWP`, `AK47`).<br/>Works only if not crouching, and not hit in the legs.<br/>Set to `0` to disable. |
</details>
## How to install zBot for CS 1.6?
* Extract all the files from an [archive](regamedll/extra/zBot/bot_profiles.zip?raw=true)
* Enter `-bots` option at the command line HLDS
* Enable CVar `bot_enable 1` in `cstrike/game_init.cfg` (if this config file does not exist, create it)
## How to install CSCZ hostage AI for CS 1.6?
## How to install CS:CZ hostage AI for CS 1.6?
* Extract all the files from an [archive](regamedll/extra/HostageImprov/host_improv.zip?raw=true)
* Enter `-host-improv` option at the command line HLDS
* Enable CVar `hostage_ai_enable 1` in `cstrike/game_init.cfg` (if this config file does not exist, create it)
## Build instructions
### Checking requirements

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

262
dist/delta.lst vendored Normal file

@ -0,0 +1,262 @@
// structure name
// none == no conditional encode routine
// gamedll routine_name : before transmitting data, invoke the named function from the game .dll to reset fields as needed
// clientdll routine_name : same as above, except the routine is called via the client.dll
clientdata_t none
{
DEFINE_DELTA( flTimeStepSound, DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 24, 1024.0 ),
DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 24, 1024.0 ),
DEFINE_DELTA( velocity[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( velocity[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( m_flNextAttack, DT_FLOAT | DT_SIGNED, 22, 1000.0 ),
DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 24, 1024.0 ),
DEFINE_DELTA( velocity[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( ammo_nails, DT_SIGNED | DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( ammo_shells, DT_SIGNED | DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( ammo_cells, DT_SIGNED | DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( ammo_rockets, DT_SIGNED | DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( m_iId, DT_INTEGER, 5, 1.0 ),
DEFINE_DELTA( punchangle[2], DT_SIGNED | DT_FLOAT, 21, 8.0 ),
DEFINE_DELTA( flags, DT_INTEGER, 32, 1.0 ), // Cut to 3 bits?
DEFINE_DELTA( weaponanim, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( health, DT_FLOAT, 17, 1.0 ), // Cut # of bits?
DEFINE_DELTA( maxspeed, DT_FLOAT, 16, 10.0 ),
DEFINE_DELTA( flDuckTime, DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( view_ofs[2], DT_SIGNED | DT_FLOAT, 10, 4.0 ),
DEFINE_DELTA( punchangle[0], DT_SIGNED | DT_FLOAT, 26, 8192.0 ),
DEFINE_DELTA( punchangle[1], DT_SIGNED | DT_FLOAT, 26, 8192.0 ),
DEFINE_DELTA( viewmodel, DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( weapons, DT_INTEGER, 32, 1.0 ),
DEFINE_DELTA( pushmsec, DT_INTEGER, 11, 1.0 ),
DEFINE_DELTA( deadflag, DT_INTEGER, 3, 1.0 ),
DEFINE_DELTA( fov, DT_FLOAT, 8, 1.0 ),
DEFINE_DELTA( physinfo, DT_STRING, 1, 1.0 ),
DEFINE_DELTA( bInDuck, DT_INTEGER, 1, 1.0 ),
DEFINE_DELTA( flSwimTime, DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( waterjumptime, DT_INTEGER, 15, 1.0 ),
DEFINE_DELTA( waterlevel, DT_INTEGER, 2, 1.0 ),
DEFINE_DELTA( iuser1, DT_INTEGER, 3, 1.0 ),
DEFINE_DELTA( iuser2, DT_INTEGER, 6, 1.0 ),
DEFINE_DELTA( iuser3, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( iuser4, DT_INTEGER, 2, 1.0 ),
DEFINE_DELTA( vuser2[0], DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( vuser2[1], DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( vuser2[2], DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( vuser3[0], DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( vuser3[1], DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( vuser3[2], DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( vuser4[0], DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( vuser4[1], DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( fuser1, DT_FLOAT, 9, 1.0 ),
DEFINE_DELTA( fuser2, DT_FLOAT, 14, 1.0 ),
DEFINE_DELTA( fuser3, DT_FLOAT, 10, 1.0 )
}
entity_state_t gamedll Entity_Encode
{
DEFINE_DELTA( animtime, DT_TIMEWINDOW_8, 8, 1.0 ),
DEFINE_DELTA( frame, DT_FLOAT, 8, 1.0 ),
DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( angles[0], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( angles[1], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( sequence, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( modelindex, DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( movetype, DT_INTEGER, 4, 1.0 ),
DEFINE_DELTA( solid, DT_SHORT, 3, 1.0 ),
DEFINE_DELTA( mins[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( mins[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( mins[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( maxs[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( maxs[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( maxs[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( endpos[0], DT_SIGNED | DT_FLOAT, 13, 1.0 ),
DEFINE_DELTA( endpos[1], DT_SIGNED | DT_FLOAT, 13, 1.0 ),
DEFINE_DELTA( endpos[2], DT_SIGNED | DT_FLOAT, 13, 1.0 ),
DEFINE_DELTA( startpos[0], DT_SIGNED | DT_FLOAT, 13, 1.0 ),
DEFINE_DELTA( startpos[1], DT_SIGNED | DT_FLOAT, 13, 1.0 ),
DEFINE_DELTA( startpos[2], DT_SIGNED | DT_FLOAT, 13, 1.0 ),
DEFINE_DELTA( impacttime, DT_TIMEWINDOW_BIG, 13, 100.0 ),
DEFINE_DELTA( starttime, DT_TIMEWINDOW_BIG, 13, 100.0 ),
DEFINE_DELTA( weaponmodel, DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( owner, DT_INTEGER, 5, 1.0 ),
DEFINE_DELTA( effects, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( eflags, DT_INTEGER, 1, 1.0 ),
DEFINE_DELTA( angles[2], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( colormap, DT_INTEGER, 16, 1.0 ),
DEFINE_DELTA( framerate, DT_SIGNED | DT_FLOAT, 8, 16.0 ),
DEFINE_DELTA( skin, DT_SHORT | DT_SIGNED, 9, 1.0 ),
DEFINE_DELTA( controller[0], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( controller[1], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( controller[2], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( controller[3], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( blending[0], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( blending[1], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( body, DT_INTEGER, 18, 1.0 ),
DEFINE_DELTA( rendermode, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( renderamt, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( renderfx, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( scale, DT_FLOAT, 16, 256.0 ),
DEFINE_DELTA( rendercolor.r, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( rendercolor.g, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( rendercolor.b, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( aiment, DT_INTEGER, 11, 1.0 ),
DEFINE_DELTA( basevelocity[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( basevelocity[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( basevelocity[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( iuser4, DT_INTEGER, 2, 1.0 )
}
entity_state_player_t gamedll Player_Encode
{
DEFINE_DELTA( animtime, DT_TIMEWINDOW_8, 8, 1.0 ),
DEFINE_DELTA( frame, DT_FLOAT, 8, 1.0 ),
DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 24, 32.0 ),
DEFINE_DELTA( angles[0], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( angles[1], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 24, 32.0 ),
DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 24, 32.0 ),
DEFINE_DELTA( gaitsequence, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( sequence, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( modelindex, DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( movetype, DT_INTEGER, 4, 1.0 ),
DEFINE_DELTA( solid, DT_SHORT, 3, 1.0 ),
DEFINE_DELTA( mins[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( mins[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( mins[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( maxs[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( maxs[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( maxs[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( weaponmodel, DT_INTEGER, 10, 1.0 ),
// DEFINE_DELTA( team, DT_INTEGER, 4, 1.0 )
// DEFINE_DELTA( playerclass, DT_INTEGER, 4, 1.0 )
DEFINE_DELTA( owner, DT_INTEGER, 5, 1.0 ),
DEFINE_DELTA( effects, DT_INTEGER, 16, 1.0 ),
DEFINE_DELTA( angles[2], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( colormap, DT_INTEGER, 16, 1.0 ),
DEFINE_DELTA( framerate, DT_SIGNED | DT_FLOAT, 8, 16.0 ),
DEFINE_DELTA( skin, DT_SHORT | DT_SIGNED, 9, 1.0 ),
DEFINE_DELTA( controller[0], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( controller[1], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( controller[2], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( controller[3], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( blending[0], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( blending[1], DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( body, DT_INTEGER, 9, 1.0 ),
DEFINE_DELTA( rendermode, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( renderamt, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( renderfx, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( scale, DT_FLOAT, 16, 256.0 ),
DEFINE_DELTA( rendercolor.r, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( rendercolor.g, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( rendercolor.b, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( friction, DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( usehull, DT_INTEGER, 1, 1.0 ),
DEFINE_DELTA( gravity, DT_SIGNED | DT_FLOAT, 16, 32.0 ),
DEFINE_DELTA( aiment, DT_INTEGER, 11, 1.0 ),
DEFINE_DELTA( basevelocity[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( basevelocity[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( basevelocity[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( spectator, DT_INTEGER, 1, 1.0 )
DEFINE_DELTA( iuser4, DT_INTEGER, 2, 1.0 )
}
custom_entity_state_t gamedll Custom_Encode
{
DEFINE_DELTA( rendermode, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 17, 8.0 ),
DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 17, 8.0 ),
DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 17, 8.0 ),
DEFINE_DELTA( angles[0], DT_SIGNED | DT_FLOAT, 17, 8.0 ),
DEFINE_DELTA( angles[1], DT_SIGNED | DT_FLOAT, 17, 8.0 ),
DEFINE_DELTA( angles[2], DT_SIGNED | DT_FLOAT, 17, 8.0 ),
DEFINE_DELTA( sequence, DT_INTEGER, 16, 1.0 ),
DEFINE_DELTA( skin, DT_INTEGER, 16, 1.0 ),
DEFINE_DELTA( modelindex, DT_INTEGER, 16, 1.0 ),
DEFINE_DELTA_POST( scale, DT_FLOAT, 8, 1.0, 0.1 ),
DEFINE_DELTA( body, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( rendercolor.r, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( rendercolor.g, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( rendercolor.b, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( renderfx, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( renderamt, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( frame, DT_FLOAT, 8, 1.0 ),
DEFINE_DELTA_POST( animtime, DT_FLOAT, 8, 1.0, 0.1 )
}
usercmd_t none
{
DEFINE_DELTA( lerp_msec, DT_SHORT, 9, 1.0 ),
DEFINE_DELTA( msec, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( viewangles[1], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( viewangles[0], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( buttons, DT_SHORT, 16, 1.0 ),
DEFINE_DELTA( forwardmove, DT_SIGNED | DT_FLOAT, 12, 1.0 ),
DEFINE_DELTA( lightlevel, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( sidemove, DT_SIGNED | DT_FLOAT, 12, 1.0 ),
DEFINE_DELTA( upmove, DT_SIGNED | DT_FLOAT, 12, 1.0 ),
DEFINE_DELTA( impulse, DT_BYTE, 8, 1.0 ),
DEFINE_DELTA( viewangles[2], DT_ANGLE, 16, 1.0 ),
DEFINE_DELTA( impact_index, DT_INTEGER, 6, 1.0 ),
DEFINE_DELTA( impact_position[0], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( impact_position[1], DT_SIGNED | DT_FLOAT, 16, 8.0 ),
DEFINE_DELTA( impact_position[2], DT_SIGNED | DT_FLOAT, 16, 8.0 )
}
weapon_data_t none
{
DEFINE_DELTA( m_flTimeWeaponIdle, DT_FLOAT | DT_SIGNED, 22, 1000.0 ),
DEFINE_DELTA( m_flNextPrimaryAttack, DT_FLOAT | DT_SIGNED, 22, 1000.0 ),
DEFINE_DELTA( m_flNextReload, DT_FLOAT | DT_SIGNED, 22, 1000.0 ),
DEFINE_DELTA( m_fNextAimBonus, DT_FLOAT | DT_SIGNED, 22, 1000.0 ),
DEFINE_DELTA( m_flNextSecondaryAttack, DT_FLOAT | DT_SIGNED, 22, 1000.0 ),
DEFINE_DELTA( m_iClip, DT_SIGNED | DT_INTEGER, 10, 1.0 ),
DEFINE_DELTA( m_flPumpTime, DT_FLOAT | DT_SIGNED, 22, 1000.0 ),
DEFINE_DELTA( m_fInSpecialReload, DT_INTEGER, 2, 1.0 ),
DEFINE_DELTA( m_fReloadTime, DT_FLOAT, 16, 100.0 ),
DEFINE_DELTA( m_fInReload, DT_INTEGER, 1, 1.0 ),
DEFINE_DELTA( m_fAimedDamage, DT_FLOAT, 22, 1000.0 ),
DEFINE_DELTA( m_fInZoom, DT_INTEGER, 8, 1.0 ),
DEFINE_DELTA( m_iWeaponState, DT_INTEGER, 7, 1.0 )
DEFINE_DELTA( m_iId, DT_INTEGER, 5, 1.0 )
DEFINE_DELTA( fuser1, DT_SIGNED | DT_FLOAT, 22, 1000.0 ),
DEFINE_DELTA( fuser2, DT_SIGNED | DT_FLOAT, 22, 128.0 ),
DEFINE_DELTA( fuser3, DT_SIGNED | DT_FLOAT, 22, 128.0 ),
DEFINE_DELTA( iuser1, DT_SIGNED | DT_INTEGER, 16, 128.0 )
}
event_t none
{
DEFINE_DELTA( entindex, DT_INTEGER, 11, 1.0 ),
DEFINE_DELTA( bparam1, DT_INTEGER, 1, 1.0 ),
DEFINE_DELTA( bparam2, DT_INTEGER, 1, 1.0 ),
DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 26, 8192.0 ),
DEFINE_DELTA( origin[1], DT_SIGNED | DT_FLOAT, 26, 8192.0 ),
DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 26, 8192.0 ),
DEFINE_DELTA( fparam1, DT_FLOAT | DT_SIGNED, 20, 100.0 ),
DEFINE_DELTA( fparam2, DT_FLOAT | DT_SIGNED, 20, 100.0 ),
DEFINE_DELTA( iparam1, DT_INTEGER | DT_SIGNED, 18, 1.0 ),
DEFINE_DELTA( iparam2, DT_INTEGER | DT_SIGNED, 18, 1.0 ),
DEFINE_DELTA( angles[0], DT_SIGNED | DT_FLOAT, 26, 8192.0 ),
DEFINE_DELTA( angles[1], DT_SIGNED | DT_FLOAT, 26, 8192.0 ),
DEFINE_DELTA( angles[2], DT_SIGNED | DT_FLOAT, 26, 8192.0 ),
DEFINE_DELTA( ducking, DT_INTEGER, 1, 1.0 )
}

168
dist/game.cfg vendored

@ -466,6 +466,13 @@ mp_ct_default_weapons_primary ""
// Default value: "usp"
mp_ct_default_weapons_secondary "usp"
// Randomize default weapons (if there are multiple)
// 0 - disabled (default behaviour)
// 1 - enabled
//
// Default value: "0"
mp_default_weapons_random "0"
// Give the player free armor on player spawn
// 0 - No armor (default behavior)
// 1 - Give Kevlar
@ -474,6 +481,14 @@ mp_ct_default_weapons_secondary "usp"
// Default value: "0"
mp_free_armor "0"
// Sets the behaviour for Flashbangs on teammates.
// -1 - Don't affect teammates neither flash owner
// 0 - Don't affect teammates
// 1 - Affects teammates (default behaviour)
//
// Default value: "1"
mp_team_flash "1"
// Players can receive all other players text chat, team restrictions apply.
// 0 - disabled (default behaviour)
// 1 - enabled
@ -513,7 +528,7 @@ mp_give_c4_frags "3"
// Default value: "1.0"
mp_hostages_rescued_ratio "1.0"
// Legacy func_vehicle behavior when blocked by another entity.
// Legacy func_vehicle behavior when blocked by another entity.
// New one is more useful for playing multiplayer.
//
// 0 - New behavior
@ -521,3 +536,154 @@ mp_hostages_rescued_ratio "1.0"
//
// Default value: "1"
mp_legacy_vehicle_block "1"
// Time for switch to free observing after death.
// NOTE: The countdown starts when the players death animation is finished.
// 0 - disable spectating around death
// >0.00001 - time delay to start spectate
//
// Default value: "3.0"
mp_dying_time "3.0"
// Sets a flags for extra information in the player's death message
//
// a - Position where the victim died
// b - Index of the assistant who helped the attacker kill the victim
// c - Rarity classification bits, e.g., blinkill, noscope, penetrated, etc
//
// Set to "0" to send no extra information about death
//
// Default value: "abc"
mp_deathmsg_flags "abc"
// Sets the percentage of damage needed to score an assist
//
// Default value: "40"
mp_assist_damage_threshold "40"
// Allow players to duck during freezetime
// 0 - disabled
// 1 - enabled (default behaviour)
//
// Default value: "1"
mp_freezetime_duck "1"
// Allow players to jump during freezetime
// 0 - disabled
// 1 - enabled (default behaviour)
//
// 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"
// 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"
// Set the method used for flymove calculations.
// 0 - default method
// 1 - alternative method (more accurate)
//
// Default value: "0"
mp_flymove_method "0"
// Framerate (FPS), that is used as a reference when restoring stamina (fuser2) after a jump.
// 0 - disabled
//
// Default value: "0"
mp_stamina_restore_rate "0"
// Player jump height
//
// Default value: "45"
mp_jump_height "45"
// Bots always have great morale regardless of defeat or victory.
// 0 - disabled (default behaviour)
// 1 - enabled
//
// Default value: "0"
bot_excellent_morale "0"
// Random player spawns
// 0 - disabled (default behaviour)
// 1 - enabled
//
// NOTE: Navigation "maps/.nav" file required
//
// Default value: "0"
mp_randomspawn "0"
// Player ID display mode
//
// 0 - don't show health (default behaviour)
// 1 - show health for teammates only (default CS behaviour)
// 2 - show health for all players
//
// Default value: "1"
mp_playerid_showhealth "1"
// Player ID field display mode
//
// 0 - don't show additional information
// 1 - show team name
// 2 - show health percentage
// 3 - show both team name and health percentage
//
// Default value: "3"
mp_playerid_field "3"
// Knockback force applied to the victim when damaged by strong weapons (e.g. AWP, AK47).
// Works only if not crouching, and not hit in the legs.
// Set to "0" to disable.
//
// Default: "170"
mp_knockback "170"

15
dist/game_init.cfg vendored

@ -1,3 +1,18 @@
// Enables ZBots for the server
// NOTE: ZBots are always enabled on a listen server, regardless of this cvar
// 0 - disabled
// 1 - enabled
//
// Default value: "0"
bot_enable "0"
// Enables the improve AI for hostages from CS:CZ
// 0 - disabled (classic hostage)
// 1 - enabled (improved hostage)
//
// Default value: "0"
hostage_ai_enable "0"
// Sets mins/maxs hull bounds for the player.
// 0 - disabled (default behaviour, sets engine)
// 1 - enabled (sets gamedll)

@ -20,18 +20,47 @@
cmake_minimum_required(VERSION 3.1)
project(regamedll CXX)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
option(DEBUG "Build with debug information." OFF)
option(USE_STATIC_LIBSTDC "Enables static linking libstdc++." OFF)
option(USE_LEGACY_LIBC "Enables linking against legacy libc (<= 2.15) for compat with older distros (Debian 8/Ubuntu 16.04/Centos 7)." OFF)
option(XASH_COMPAT "Enable Xash3D FWGS compatiblity (support for it's 64-bit ABI support and crossplatform library suffix)")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Avoid -rdynamic -fPIC options
set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "")
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
if (NOT XASH_COMPAT)
set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "")
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
endif()
set(COMPILE_FLAGS "-m32 -U_FORTIFY_SOURCE")
set(LINK_FLAGS "-m32 -s")
set(COMPILE_FLAGS "-U_FORTIFY_SOURCE")
set(LINK_LIBS dl)
# do not strip debuginfo during link
if (NOT DEBUG)
set(LINK_FLAGS "-s")
endif()
# add -m32 flag only on 64-bit systems, if building for 64-bit wasn't enabled with XASH_COMPAT
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
if (XASH_COMPAT)
set(COMPILE_FLAGS "${COMPILE_FLAGS} -DXASH_64BIT")
else()
set(COMPILE_FLAGS "${COMPILE_FLAGS} -m32")
set(LINK_FLAGS "${LINK_FLAGS} -m32")
list(APPEND LINK_LIBS aelf32)
set(CMAKE_SIZEOF_VOID_P 4)
endif()
endif()
if(XASH_COMPAT)
# Xash3D FWGS Library Naming Scheme compliance
# see documentation: https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/extensions/library-naming.md
include(LibraryNaming)
endif()
set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wall -fno-exceptions -fno-builtin -Wno-unknown-pragmas")
@ -45,7 +74,7 @@ else()
endif()
# Check Intel C++ compiler
if ("$ENV{CXX}" MATCHES "icpc")
if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
#
# -fp-model=precise
# ICC uses -fp-model fast=1 by default for more aggressive optimizations on floating-point calculations
@ -73,11 +102,15 @@ if ("$ENV{CXX}" MATCHES "icpc")
set(COMPILE_FLAGS "${COMPILE_FLAGS} -ipo")
set(LINK_FLAGS "${LINK_FLAGS} -ipo")
endif()
else()
# Produce code optimized for the most common IA32/AMD64/EM64T processors.
# As new processors are deployed in the marketplace, the behavior of this option will change.
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if (NOT XASH_COMPAT OR XASH_AMD64 OR XASH_X86)
# Produce code optimized for the most common IA32/AMD64/EM64T processors.
# As new processors are deployed in the marketplace, the behavior of this option will change.
set(COMPILE_FLAGS "${COMPILE_FLAGS} \
-mtune=generic -msse3")
endif()
set(COMPILE_FLAGS "${COMPILE_FLAGS} \
-mtune=generic -msse3\
-fpermissive -fno-sized-deallocation\
-Wno-delete-non-virtual-dtor -Wno-invalid-offsetof\
-Wno-unused-variable -Wno-unused-value -Wno-unused-result -Wno-unused-function\
@ -85,7 +118,7 @@ else()
-Wno-sign-compare -Wno-format -Wno-ignored-attributes -Wno-strict-aliasing")
# Check Clang compiler
if ("$ENV{CXX}" MATCHES "clang")
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(COMPILE_FLAGS "${COMPILE_FLAGS} \
-Wno-unused-local-typedef\
-Wno-unused-private-field\
@ -100,16 +133,11 @@ else()
# GCC >= 8.3
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-stringop-truncation -Wno-format-truncation -Wno-class-memaccess")
set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-stringop-truncation -Wno-format-truncation -Wno-class-memaccess -fcf-protection=none")
endif()
endif()
endif()
# GCC >= 8.3
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
set(COMPILE_FLAGS "${COMPILE_FLAGS} -fcf-protection=none")
endif()
if (NOT DEBUG)
set(LINK_FLAGS "${LINK_FLAGS} \
-Wl,-gc-sections -Wl,--version-script=\"${PROJECT_SOURCE_DIR}/../version_script.lds\"")
@ -161,6 +189,9 @@ set(SHARED_SRCS
"public/FileSystem.cpp"
"public/interface.cpp"
"public/MemPool.cpp"
"public/MemPool.cpp"
"public/tier0/dbg.cpp"
"public/tier0/platform_posix.cpp"
)
set(GAMEDLL_SRCS
@ -226,6 +257,7 @@ set(GAMEDLL_SRCS
"dlls/API/CSEntity.cpp"
"dlls/API/CSPlayer.cpp"
"dlls/API/CSPlayerItem.cpp"
"dlls/API/CSPlayerWeapon.cpp"
"dlls/addons/item_airbox.cpp"
"dlls/addons/point_command.cpp"
"dlls/addons/trigger_random.cpp"
@ -342,6 +374,7 @@ target_compile_definitions(regamedll PRIVATE
_strnicmp=strncasecmp
_strdup=strdup
_unlink=unlink
_snprintf=snprintf
_vsnprintf=vsnprintf
_write=write
_close=close
@ -358,26 +391,49 @@ 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()
$<$<CONFIG:Unittests>:cppunitlite>
)
target_link_libraries(regamedll PRIVATE ${LINK_LIBS})
if (USE_STATIC_LIBSTDC)
target_compile_definitions(regamedll PRIVATE BUILD_STATIC_LIBSTDC)
set(LINK_FLAGS "${LINK_FLAGS} -static-libgcc -static-libstdc++")
endif()
set(LINK_FLAGS "${LINK_FLAGS} \
-Wl,-rpath,'$ORIGIN/.' \
-L${PROJECT_SOURCE_DIR}/lib/linux32")
set(LINK_FLAGS "${LINK_FLAGS} -Wl,-rpath,'$ORIGIN/.'")
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set(LINK_FLAGS "${LINK_FLAGS} -L${PROJECT_SOURCE_DIR}/lib/linux32")
endif()
set_target_properties(regamedll PROPERTIES
OUTPUT_NAME cs
PREFIX ""
COMPILE_FLAGS ${COMPILE_FLAGS}
LINK_FLAGS ${LINK_FLAGS}
POSITION_INDEPENDENT_CODE OFF
)
if (XASH_COMPAT)
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
set_target_properties(regamedll PROPERTIES
OUTPUT_NAME server)
else()
set_target_properties(regamedll PROPERTIES
PREFIX ""
OUTPUT_NAME cs${POSTFIX})
endif()
else()
set_target_properties(regamedll PROPERTIES
OUTPUT_NAME cs
PREFIX ""
POSITION_INDEPENDENT_CODE OFF)
endif()
install(TARGETS regamedll
RUNTIME DESTINATION "cstrike/dlls/"
LIBRARY DESTINATION "cstrike/dlls/"
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)

@ -0,0 +1,198 @@
include(CheckSymbolExists)
macro(check_build_target symbol)
check_symbol_exists(${symbol} "build.h" ${symbol})
endmacro()
macro(check_group_build_target symbol group)
if(NOT ${group})
check_build_target(${symbol})
if(${symbol})
set(${group} TRUE)
endif()
else()
set(${symbol} FALSE)
endif()
endmacro()
# So there is a problem:
# 1. Number of these symbols only grows, as we support more and more ports
# 2. CMake was written by morons and can't check these symbols in parallel
# 3. MSVC is very slow at everything (startup, parsing, generating error)
# Solution: group these symbols and set variable if one of them was found
# this way we can reorder to reorder them by most common configurations
# but we can't generate this list anymore! ... OR IS IT ???
# Well, after reordering positions in engine's buildenums.h, we can partially autogenerate this list!
# echo "check_build_target(XASH_64BIT)"
# grep "#define PLATFORM" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 " XASH_PLATFORM)" }'
# grep "#define ARCHITECTURE" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 " XASH_ARCHITECTURE)"
# grep "#define ENDIAN" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 "_ENDIAN XASH_ENDIANNESS)"}'
# echo "if(XASH_ARM)"
# grep '^#undef XASH' build.h | grep "XASH_ARM[v_]" | awk '{ print "check_build_target(" $2 ")"}'
# echo "endif()"
# echo "if(XASH_RISCV)"
# grep '^#undef XASH' build.h | grep "XASH_RISCV_" | awk '{ print "check_build_target(" $2 ")"}'
# echo "endif()"
# NOTE: Android must have priority over Linux to work correctly!
set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}/public/")
check_build_target(XASH_64BIT)
check_group_build_target(XASH_WIN32 XASH_PLATFORM)
check_group_build_target(XASH_ANDROID XASH_PLATFORM)
check_group_build_target(XASH_LINUX XASH_PLATFORM)
check_group_build_target(XASH_FREEBSD XASH_PLATFORM)
check_group_build_target(XASH_APPLE XASH_PLATFORM)
check_group_build_target(XASH_NETBSD XASH_PLATFORM)
check_group_build_target(XASH_OPENBSD XASH_PLATFORM)
check_group_build_target(XASH_EMSCRIPTEN XASH_PLATFORM)
check_group_build_target(XASH_DOS4GW XASH_PLATFORM)
check_group_build_target(XASH_HAIKU XASH_PLATFORM)
check_group_build_target(XASH_SERENITY XASH_PLATFORM)
check_group_build_target(XASH_IRIX XASH_PLATFORM)
check_group_build_target(XASH_NSWITCH XASH_PLATFORM)
check_group_build_target(XASH_PSVITA XASH_PLATFORM)
check_group_build_target(XASH_WASI XASH_PLATFORM)
check_group_build_target(XASH_SUNOS XASH_PLATFORM)
check_group_build_target(XASH_X86 XASH_ARCHITECTURE)
check_group_build_target(XASH_AMD64 XASH_ARCHITECTURE)
check_group_build_target(XASH_ARM XASH_ARCHITECTURE)
check_group_build_target(XASH_MIPS XASH_ARCHITECTURE)
check_group_build_target(XASH_PPC XASH_ARCHITECTURE)
check_group_build_target(XASH_JS XASH_ARCHITECTURE)
check_group_build_target(XASH_E2K XASH_ARCHITECTURE)
check_group_build_target(XASH_RISCV XASH_ARCHITECTURE)
check_group_build_target(XASH_LITTLE_ENDIAN XASH_ENDIANNESS)
check_group_build_target(XASH_BIG_ENDIAN XASH_ENDIANNESS)
if(XASH_ARM)
check_build_target(XASH_ARM_HARDFP)
check_build_target(XASH_ARM_SOFTFP)
check_build_target(XASH_ARMv4)
check_build_target(XASH_ARMv5)
check_build_target(XASH_ARMv6)
check_build_target(XASH_ARMv7)
check_build_target(XASH_ARMv8)
endif()
if(XASH_RISCV)
check_build_target(XASH_RISCV_DOUBLEFP)
check_build_target(XASH_RISCV_SINGLEFP)
check_build_target(XASH_RISCV_SOFTFP)
endif()
unset(CMAKE_REQUIRED_INCLUDES)
# engine/common/build.c
if(XASH_ANDROID)
set(BUILDOS "android")
elseif(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE)
set(BUILDOS "") # no prefix for default OS
elseif(XASH_FREEBSD)
set(BUILDOS "freebsd")
elseif(XASH_NETBSD)
set(BUILDOS "netbsd")
elseif(XASH_OPENBSD)
set(BUILDOS "openbsd")
elseif(XASH_EMSCRIPTEN)
set(BUILDOS "emscripten")
elseif(XASH_DOS4GW)
set(BUILDOS "DOS4GW")
elseif(XASH_HAIKU)
set(BUILDOS "haiku")
elseif(XASH_SERENITY)
set(BUILDOS "serenityos")
elseif(XASH_NSWITCH)
set(BUILDOS "nswitch")
elseif(XASH_PSVITA)
set(BUILDOS "psvita")
elseif(XASH_IRIX)
set(BUILDOS "irix")
elseif(XASH_WASI)
set(BUILDOS "wasi")
elseif(XASH_SUNOS)
set(BUILDOS "sunos")
else()
message(SEND_ERROR "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug")
endif()
if(XASH_AMD64)
set(BUILDARCH "amd64")
elseif(XASH_X86)
if(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE)
set(BUILDARCH "") # no prefix for default OS
else()
set(BUILDARCH "i386")
endif()
elseif(XASH_ARM AND XASH_64BIT)
set(BUILDARCH "arm64")
elseif(XASH_ARM)
set(BUILDARCH "armv")
if(XASH_ARMv8)
set(BUILDARCH "${BUILDARCH}8_32")
elseif(XASH_ARMv7)
set(BUILDARCH "${BUILDARCH}7")
elseif(XASH_ARMv6)
set(BUILDARCH "${BUILDARCH}6")
elseif(XASH_ARMv5)
set(BUILDARCH "${BUILDARCH}5")
elseif(XASH_ARMv4)
set(BUILDARCH "${BUILDARCH}4")
else()
message(SEND_ERROR "Unknown ARM")
endif()
if(XASH_ARM_HARDFP)
set(BUILDARCH "${BUILDARCH}hf")
else()
set(BUILDARCH "${BUILDARCH}l")
endif()
elseif(XASH_MIPS)
set(BUILDARCH "mips")
if(XASH_64BIT)
set(BUILDARCH "${BUILDARCH}64")
endif()
if(XASH_LITTLE_ENDIAN)
set(BUILDARCH "${BUILDARCH}el")
endif()
elseif(XASH_RISCV)
set(BUILDARCH "riscv")
if(XASH_64BIT)
set(BUILDARCH "${BUILDARCH}64")
else()
set(BUILDARCH "${BUILDARCH}32")
endif()
if(XASH_RISCV_DOUBLEFP)
set(BUILDARCH "${BUILDARCH}d")
elseif(XASH_RISCV_SINGLEFP)
set(BUILDARCH "${BUILDARCH}f")
endif()
elseif(XASH_JS)
set(BUILDARCH "javascript")
elseif(XASH_E2K)
set(BUILDARCH "e2k")
elseif(XASH_PPC)
set(BUILDARCH "ppc")
if(XASH_64BIT)
set(BUILDARCH "${BUILDARCH}64")
endif()
if(XASH_LITTLE_ENDIAN)
set(BUILDARCH "${BUILDARCH}el")
endif()
else()
message(SEND_ERROR "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug")
endif()
if(BUILDOS STREQUAL "android")
set(POSTFIX "") # force disable for Android, as Android ports aren't distributed in normal way and doesn't follow library naming
elseif(BUILDOS AND BUILDARCH)
set(POSTFIX "_${BUILDOS}_${BUILDARCH}")
elseif(BUILDARCH)
set(POSTFIX "_${BUILDARCH}")
else()
set(POSTFIX "")
endif()
message(STATUS "Library postfix: " ${POSTFIX})

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

@ -30,40 +30,133 @@
CReGameHookchains g_ReGameHookchains;
int EXT_FUNC Cmd_Argc_api() {
void EXT_FUNC Regamedll_ChangeString_api(char *&dest, const char *source)
{
size_t len = Q_strlen(source);
if (dest == nullptr || Q_strlen(dest) != len) {
delete [] dest;
dest = new char [len + 1];
}
Q_strcpy(dest, source);
}
void EXT_FUNC RadiusDamage_api(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType)
{
RadiusDamage(vecSrc, pevInflictor, pevAttacker, flDamage, flRadius, iClassIgnore, bitsDamageType);
}
void EXT_FUNC ClearMultiDamage_api()
{
ClearMultiDamage();
}
void EXT_FUNC ApplyMultiDamage_api(entvars_t *pevInflictor, entvars_t *pevAttacker)
{
ApplyMultiDamage(pevInflictor, pevAttacker);
}
void EXT_FUNC AddMultiDamage_api(entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType)
{
AddMultiDamage(pevInflictor, pEntity, flDamage, bitsDamageType);
}
int EXT_FUNC Cmd_Argc_api()
{
return CMD_ARGC_();
}
const char *EXT_FUNC Cmd_Argv_api(int i) {
const char *EXT_FUNC Cmd_Argv_api(int i)
{
return CMD_ARGV_(i);
}
CGrenade *PlantBomb_api(entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity) {
CGrenade *EXT_FUNC PlantBomb_api(entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity)
{
return CGrenade::ShootSatchelCharge(pevOwner, vecStart, vecVelocity);
}
CGib *SpawnHeadGib_api(entvars_t *pevVictim) {
CGib *EXT_FUNC SpawnHeadGib_api(entvars_t *pevVictim)
{
return CGib::SpawnHeadGib(pevVictim);
}
void SpawnRandomGibs_api(entvars_t *pevVictim, int cGibs, int human) {
void EXT_FUNC SpawnRandomGibs_api(entvars_t *pevVictim, int cGibs, int human)
{
CGib::SpawnRandomGibs(pevVictim, cGibs, human);
}
void EXT_FUNC UTIL_RestartOther_api(const char *szClassname)
{
UTIL_RestartOther(szClassname);
}
void EXT_FUNC UTIL_ResetEntities_api()
{
UTIL_ResetEntities();
}
void EXT_FUNC UTIL_RemoveOther_api(const char *szClassname, int nCount)
{
UTIL_RemoveOther(szClassname, nCount);
}
void EXT_FUNC UTIL_DecalTrace_api(TraceResult *pTrace, int decalNumber)
{
UTIL_DecalTrace(pTrace, decalNumber);
}
void EXT_FUNC UTIL_Remove_api(CBaseEntity *pEntity)
{
UTIL_Remove(pEntity);
}
int EXT_FUNC AddAmmoNameToAmmoRegistry_api(const char *szAmmoname)
{
return AddAmmoNameToAmmoRegistry(szAmmoname);
}
void EXT_FUNC TextureTypePlaySound_api(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType)
{
TEXTURETYPE_PlaySound(ptr, vecSrc, vecEnd, iBulletType);
}
CWeaponBox *EXT_FUNC CreateWeaponBox_api(CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo)
{
return CreateWeaponBox(pItem, pPlayerOwner, modelName, origin, angles, velocity, lifeTime < 0.0 ? CGameRules::GetItemKillDelay() : lifeTime, packAmmo);
}
CGrenade *EXT_FUNC SpawnGrenade_api(WeaponIdType weaponId, entvars_t *pevOwner, Vector &vecSrc, Vector &vecThrow, float time, int iTeam, unsigned short usEvent)
{
switch (weaponId)
{
case WEAPON_HEGRENADE:
return CGrenade::ShootTimed2(pevOwner, vecSrc, vecThrow, time, iTeam, usEvent);
case WEAPON_FLASHBANG:
return CGrenade::ShootTimed(pevOwner, vecSrc, vecThrow, time);
case WEAPON_SMOKEGRENADE:
return CGrenade::ShootSmokeGrenade(pevOwner, vecSrc, vecThrow, time, usEvent);
case WEAPON_C4:
return CGrenade::ShootSatchelCharge(pevOwner, vecSrc, vecThrow);
}
return nullptr;
}
ReGameFuncs_t g_ReGameApiFuncs = {
&CREATE_NAMED_ENTITY,
CREATE_NAMED_ENTITY,
&Regamedll_ChangeString_api,
Regamedll_ChangeString_api,
&RadiusDamage_api,
&ClearMultiDamage_api,
&ApplyMultiDamage_api,
&AddMultiDamage_api,
RadiusDamage_api,
ClearMultiDamage_api,
ApplyMultiDamage_api,
AddMultiDamage_api,
&UTIL_FindEntityByString,
UTIL_FindEntityByString,
&AddEntityHashValue,
&RemoveEntityHashValue,
AddEntityHashValue,
RemoveEntityHashValue,
Cmd_Argc_api,
Cmd_Argv_api,
@ -76,6 +169,13 @@ ReGameFuncs_t g_ReGameApiFuncs = {
UTIL_RestartOther_api,
UTIL_ResetEntities_api,
UTIL_RemoveOther_api,
UTIL_DecalTrace_api,
UTIL_Remove_api,
AddAmmoNameToAmmoRegistry_api,
TextureTypePlaySound_api,
CreateWeaponBox_api,
SpawnGrenade_api,
};
GAMEHOOK_REGISTRY(CBasePlayer_Spawn);
@ -209,6 +309,35 @@ GAMEHOOK_REGISTRY(CBasePlayer_DeathSound);
GAMEHOOK_REGISTRY(CBasePlayer_JoiningThink);
GAMEHOOK_REGISTRY(FreeGameRules);
GAMEHOOK_REGISTRY(PM_LadderMove);
GAMEHOOK_REGISTRY(PM_WaterJump);
GAMEHOOK_REGISTRY(PM_CheckWaterJump);
GAMEHOOK_REGISTRY(PM_Jump);
GAMEHOOK_REGISTRY(PM_Duck);
GAMEHOOK_REGISTRY(PM_UnDuck);
GAMEHOOK_REGISTRY(PM_PlayStepSound);
GAMEHOOK_REGISTRY(PM_AirAccelerate);
GAMEHOOK_REGISTRY(ClearMultiDamage);
GAMEHOOK_REGISTRY(AddMultiDamage);
GAMEHOOK_REGISTRY(ApplyMultiDamage);
GAMEHOOK_REGISTRY(BuyItem);
GAMEHOOK_REGISTRY(CSGameRules_Think);
GAMEHOOK_REGISTRY(CSGameRules_TeamFull);
GAMEHOOK_REGISTRY(CSGameRules_TeamStacked);
GAMEHOOK_REGISTRY(CSGameRules_PlayerGotWeapon);
GAMEHOOK_REGISTRY(CBotManager_OnEvent);
GAMEHOOK_REGISTRY(CBasePlayer_CheckTimeBasedDamage);
GAMEHOOK_REGISTRY(CBasePlayer_EntSelectSpawnPoint);
GAMEHOOK_REGISTRY(CBasePlayerWeapon_ItemPostFrame);
GAMEHOOK_REGISTRY(CBasePlayerWeapon_KickBack);
GAMEHOOK_REGISTRY(CBasePlayerWeapon_SendWeaponAnim);
GAMEHOOK_REGISTRY(CSGameRules_SendDeathMessage);
GAMEHOOK_REGISTRY(CBasePlayer_PlayerDeathThink);
GAMEHOOK_REGISTRY(CBasePlayer_Observer_Think);
GAMEHOOK_REGISTRY(CBasePlayer_RemoveAllItems);
GAMEHOOK_REGISTRY(CBasePlayer_UpdateStatusBar);
GAMEHOOK_REGISTRY(CBasePlayer_TakeDamageImpulse);
int CReGameApi::GetMajorVersion() {
return REGAMEDLL_API_VERSION_MAJOR;
@ -271,48 +400,4 @@ bool CReGameApi::BGetIGameRules(const char *pchVersion) const
return false;
}
EXT_FUNC void Regamedll_ChangeString_api(char *&dest, const char *source)
{
size_t len = Q_strlen(source);
if (dest == nullptr || Q_strlen(dest) != len) {
delete [] dest;
dest = new char [len + 1];
}
Q_strcpy(dest, source);
}
EXT_FUNC void RadiusDamage_api(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType)
{
RadiusDamage(vecSrc, pevInflictor, pevAttacker, flDamage, flRadius, iClassIgnore, bitsDamageType);
}
EXT_FUNC void ClearMultiDamage_api()
{
ClearMultiDamage();
}
EXT_FUNC void ApplyMultiDamage_api(entvars_t *pevInflictor, entvars_t *pevAttacker)
{
ApplyMultiDamage(pevInflictor, pevAttacker);
}
EXT_FUNC void AddMultiDamage_api(entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType)
{
AddMultiDamage(pevInflictor, pEntity, flDamage, bitsDamageType);
}
EXT_FUNC void UTIL_RestartOther_api(const char *szClassname) {
UTIL_RestartOther(szClassname);
}
EXT_FUNC void UTIL_ResetEntities_api() {
UTIL_ResetEntities();
}
EXT_FUNC void UTIL_RemoveOther_api(const char *szClassname, int nCount)
{
UTIL_RemoveOther(szClassname, nCount);
}
EXPOSE_SINGLE_INTERFACE(CReGameApi, IReGameApi, VRE_GAMEDLL_API_VERSION);

@ -458,8 +458,8 @@ typedef IHookChainClassImpl<void, class CHalfLifeMultiplay> CReGameHook_CSGameRu
typedef IHookChainRegistryClassEmptyImpl<void, class CHalfLifeMultiplay> CReGameHookRegistry_CSGameRules_RemoveGuns;
// CHalfLifeMultiplay::GiveC4 hook
typedef IHookChainClassImpl<void, class CHalfLifeMultiplay> CReGameHook_CSGameRules_GiveC4;
typedef IHookChainRegistryClassEmptyImpl<void, class CHalfLifeMultiplay> CReGameHookRegistry_CSGameRules_GiveC4;
typedef IHookChainClassImpl<CBasePlayer *, class CHalfLifeMultiplay> CReGameHook_CSGameRules_GiveC4;
typedef IHookChainRegistryClassEmptyImpl<CBasePlayer *, class CHalfLifeMultiplay> CReGameHookRegistry_CSGameRules_GiveC4;
// CHalfLifeMultiplay::ChangeLevel hook
typedef IHookChainClassImpl<void, class CHalfLifeMultiplay> CReGameHook_CSGameRules_ChangeLevel;
@ -645,6 +645,118 @@ typedef IHookChainRegistryClassImpl<void, CBasePlayer> CReGameHookRegistry_CBase
typedef IHookChainImpl<void, CGameRules **> CReGameHook_FreeGameRules;
typedef IHookChainRegistryImpl<void, CGameRules **> CReGameHookRegistry_FreeGameRules;
// PM_LadderMove hook
typedef IHookChainImpl<void, struct physent_s *> CReGameHook_PM_LadderMove;
typedef IHookChainRegistryImpl<void, struct physent_s *> CReGameHookRegistry_PM_LadderMove;
// PM_WaterJump hook
typedef IHookChainImpl<void> CReGameHook_PM_WaterJump;
typedef IHookChainRegistryImpl<void> CReGameHookRegistry_PM_WaterJump;
// PM_CheckWaterJump hook
typedef IHookChainImpl<void> CReGameHook_PM_CheckWaterJump;
typedef IHookChainRegistryImpl<void> CReGameHookRegistry_PM_CheckWaterJump;
// PM_Jump hook
typedef IHookChainImpl<void> CReGameHook_PM_Jump;
typedef IHookChainRegistryImpl<void> CReGameHookRegistry_PM_Jump;
// PM_Duck hook
typedef IHookChainImpl<void> CReGameHook_PM_Duck;
typedef IHookChainRegistryImpl<void> CReGameHookRegistry_PM_Duck;
// PM_UnDuck hook
typedef IHookChainImpl<void> CReGameHook_PM_UnDuck;
typedef IHookChainRegistryImpl<void> CReGameHookRegistry_PM_UnDuck;
// PM_PlayStepSound hook
typedef IHookChainImpl<void, int, float> CReGameHook_PM_PlayStepSound;
typedef IHookChainRegistryImpl<void, int, float> CReGameHookRegistry_PM_PlayStepSound;
// PM_AirAccelerate hook
typedef IHookChainImpl<void, vec_t *, float, float> CReGameHook_PM_AirAccelerate;
typedef IHookChainRegistryImpl<void, vec_t *, float, float> CReGameHookRegistry_PM_AirAccelerate;
// ClearMultiDamage hook
typedef IHookChainImpl<void> CReGameHook_ClearMultiDamage;
typedef IHookChainRegistryImpl<void> CReGameHookRegistry_ClearMultiDamage;
// AddMultiDamage hook
typedef IHookChainImpl<void, entvars_t *, CBaseEntity *, float, int> CReGameHook_AddMultiDamage;
typedef IHookChainRegistryImpl<void, entvars_t *, CBaseEntity *, float, int> CReGameHookRegistry_AddMultiDamage;
// ApplyMultiDamage hook
typedef IHookChainImpl<void, entvars_t *, entvars_t *> CReGameHook_ApplyMultiDamage;
typedef IHookChainRegistryImpl<void, entvars_t *, entvars_t *> CReGameHookRegistry_ApplyMultiDamage;
// BuyItem hook
typedef IHookChainImpl<void, CBasePlayer *, int> CReGameHook_BuyItem;
typedef IHookChainRegistryImpl<void, CBasePlayer *, int> CReGameHookRegistry_BuyItem;
// CHalfLifeMultiplay::Think hook
typedef IHookChainClassImpl<void, class CHalfLifeMultiplay> CReGameHook_CSGameRules_Think;
typedef IHookChainRegistryClassEmptyImpl<void, class CHalfLifeMultiplay> CReGameHookRegistry_CSGameRules_Think;
// CHalfLifeMultiplay::TeamFull hook
typedef IHookChainClassImpl<BOOL, class CHalfLifeMultiplay, int> CReGameHook_CSGameRules_TeamFull;
typedef IHookChainRegistryClassEmptyImpl<BOOL, class CHalfLifeMultiplay, int> CReGameHookRegistry_CSGameRules_TeamFull;
// CHalfLifeMultiplay::TeamStacked hook
typedef IHookChainClassImpl<BOOL, class CHalfLifeMultiplay, int, int> CReGameHook_CSGameRules_TeamStacked;
typedef IHookChainRegistryClassEmptyImpl<BOOL, class CHalfLifeMultiplay, int, int> CReGameHookRegistry_CSGameRules_TeamStacked;
// CHalfLifeMultiplay::PlayerGotWeapon hook
typedef IHookChainClassImpl<void, class CHalfLifeMultiplay, CBasePlayer *, CBasePlayerItem *> CReGameHook_CSGameRules_PlayerGotWeapon;
typedef IHookChainRegistryClassEmptyImpl<void, class CHalfLifeMultiplay, CBasePlayer *, CBasePlayerItem *> CReGameHookRegistry_CSGameRules_PlayerGotWeapon;
// CHalfLifeMultiplay::SendDeathMessage hook
typedef IHookChainClassImpl<void, class CHalfLifeMultiplay, CBaseEntity *, CBasePlayer *, CBasePlayer *, entvars_t *, const char *, int, int> CReGameHook_CSGameRules_SendDeathMessage;
typedef IHookChainRegistryClassEmptyImpl<void, class CHalfLifeMultiplay, CBaseEntity *, CBasePlayer *, CBasePlayer *, entvars_t *, const char *, int, int> CReGameHookRegistry_CSGameRules_SendDeathMessage;
// CBotManager::OnEvent hook
typedef IHookChainClassImpl<void, CBotManager, GameEventType, CBaseEntity *, CBaseEntity *> CReGameHook_CBotManager_OnEvent;
typedef IHookChainRegistryClassEmptyImpl<void, CBotManager, GameEventType, CBaseEntity*, CBaseEntity*> CReGameHookRegistry_CBotManager_OnEvent;
// CBasePlayer::CheckTimeBasedDamage hook
typedef IHookChainClassImpl<void, CBasePlayer> CReGameHook_CBasePlayer_CheckTimeBasedDamage;
typedef IHookChainRegistryClassImpl<void, CBasePlayer> CReGameHookRegistry_CBasePlayer_CheckTimeBasedDamage;
// CBasePlayer::EntSelectSpawnPoint hook
typedef IHookChainClassImpl<edict_t *, CBasePlayer> CReGameHook_CBasePlayer_EntSelectSpawnPoint;
typedef IHookChainRegistryClassImpl<edict_t *, CBasePlayer> CReGameHookRegistry_CBasePlayer_EntSelectSpawnPoint;
// CBasePlayerWeapon::ItemPostFrame hook
typedef IHookChainClassImpl<void, CBasePlayerWeapon> CReGameHook_CBasePlayerWeapon_ItemPostFrame;
typedef IHookChainRegistryClassImpl<void, CBasePlayerWeapon> CReGameHookRegistry_CBasePlayerWeapon_ItemPostFrame;
// CBasePlayerWeapon::KickBack hook
typedef IHookChainClassImpl<void, CBasePlayerWeapon, float, float, float, float, float, float, int> CReGameHook_CBasePlayerWeapon_KickBack;
typedef IHookChainRegistryClassImpl<void, CBasePlayerWeapon, float, float, float, float, float, float, int> CReGameHookRegistry_CBasePlayerWeapon_KickBack;
// CBasePlayerWeapon::SendWeaponAnim hook
typedef IHookChainClassImpl<void, CBasePlayerWeapon, int, int> CReGameHook_CBasePlayerWeapon_SendWeaponAnim;
typedef IHookChainRegistryClassImpl<void, CBasePlayerWeapon, int, int> CReGameHookRegistry_CBasePlayerWeapon_SendWeaponAnim;
// CBasePlayer::PlayerDeathThink hook
typedef IHookChainClassImpl<void, CBasePlayer> CReGameHook_CBasePlayer_PlayerDeathThink;
typedef IHookChainRegistryClassImpl<void, CBasePlayer> CReGameHookRegistry_CBasePlayer_PlayerDeathThink;
// CBasePlayer::Observer_Think hook
typedef IHookChainClassImpl<void, CBasePlayer> CReGameHook_CBasePlayer_Observer_Think;
typedef IHookChainRegistryClassImpl<void, CBasePlayer> CReGameHookRegistry_CBasePlayer_Observer_Think;
// CBasePlayer::RemoveAllItems hook
typedef IHookChainClassImpl<void, CBasePlayer, BOOL> CReGameHook_CBasePlayer_RemoveAllItems;
typedef IHookChainRegistryClassImpl<void, CBasePlayer, BOOL> CReGameHookRegistry_CBasePlayer_RemoveAllItems;
// CBasePlayer::UpdateStatusBar hook
typedef IHookChainClassImpl<void, CBasePlayer> CReGameHook_CBasePlayer_UpdateStatusBar;
typedef IHookChainRegistryClassImpl<void, CBasePlayer> CReGameHookRegistry_CBasePlayer_UpdateStatusBar;
// CBasePlayer::TakeDamageImpulse hook
typedef IHookChainClassImpl<void, CBasePlayer, CBasePlayer *, float, float> CReGameHook_CBasePlayer_TakeDamageImpulse;
typedef IHookChainRegistryClassImpl<void, CBasePlayer, CBasePlayer *, float, float> CReGameHookRegistry_CBasePlayer_TakeDamageImpulse;
class CReGameHookchains: public IReGameHookchains {
public:
// CBasePlayer virtual
@ -779,6 +891,35 @@ public:
CReGameHookRegistry_CBasePlayer_JoiningThink m_CBasePlayer_JoiningThink;
CReGameHookRegistry_FreeGameRules m_FreeGameRules;
CReGameHookRegistry_PM_LadderMove m_PM_LadderMove;
CReGameHookRegistry_PM_WaterJump m_PM_WaterJump;
CReGameHookRegistry_PM_CheckWaterJump m_PM_CheckWaterJump;
CReGameHookRegistry_PM_Jump m_PM_Jump;
CReGameHookRegistry_PM_Duck m_PM_Duck;
CReGameHookRegistry_PM_UnDuck m_PM_UnDuck;
CReGameHookRegistry_PM_PlayStepSound m_PM_PlayStepSound;
CReGameHookRegistry_PM_AirAccelerate m_PM_AirAccelerate;
CReGameHookRegistry_ClearMultiDamage m_ClearMultiDamage;
CReGameHookRegistry_AddMultiDamage m_AddMultiDamage;
CReGameHookRegistry_ApplyMultiDamage m_ApplyMultiDamage;
CReGameHookRegistry_BuyItem m_BuyItem;
CReGameHookRegistry_CSGameRules_Think m_CSGameRules_Think;
CReGameHookRegistry_CSGameRules_TeamFull m_CSGameRules_TeamFull;
CReGameHookRegistry_CSGameRules_TeamStacked m_CSGameRules_TeamStacked;
CReGameHookRegistry_CSGameRules_PlayerGotWeapon m_CSGameRules_PlayerGotWeapon;
CReGameHookRegistry_CBotManager_OnEvent m_CBotManager_OnEvent;
CReGameHookRegistry_CBasePlayer_CheckTimeBasedDamage m_CBasePlayer_CheckTimeBasedDamage;
CReGameHookRegistry_CBasePlayer_EntSelectSpawnPoint m_CBasePlayer_EntSelectSpawnPoint;
CReGameHookRegistry_CBasePlayerWeapon_ItemPostFrame m_CBasePlayerWeapon_ItemPostFrame;
CReGameHookRegistry_CBasePlayerWeapon_KickBack m_CBasePlayerWeapon_KickBack;
CReGameHookRegistry_CBasePlayerWeapon_SendWeaponAnim m_CBasePlayerWeapon_SendWeaponAnim;
CReGameHookRegistry_CSGameRules_SendDeathMessage m_CSGameRules_SendDeathMessage;
CReGameHookRegistry_CBasePlayer_PlayerDeathThink m_CBasePlayer_PlayerDeathThink;
CReGameHookRegistry_CBasePlayer_Observer_Think m_CBasePlayer_Observer_Think;
CReGameHookRegistry_CBasePlayer_RemoveAllItems m_CBasePlayer_RemoveAllItems;
CReGameHookRegistry_CBasePlayer_UpdateStatusBar m_CBasePlayer_UpdateStatusBar;
CReGameHookRegistry_CBasePlayer_TakeDamageImpulse m_CBasePlayer_TakeDamageImpulse;
public:
virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn();
@ -912,6 +1053,35 @@ public:
virtual IReGameHookRegistry_CBasePlayer_JoiningThink *CBasePlayer_JoiningThink();
virtual IReGameHookRegistry_FreeGameRules *FreeGameRules();
virtual IReGameHookRegistry_PM_LadderMove *PM_LadderMove();
virtual IReGameHookRegistry_PM_WaterJump *PM_WaterJump();
virtual IReGameHookRegistry_PM_CheckWaterJump *PM_CheckWaterJump();
virtual IReGameHookRegistry_PM_Jump *PM_Jump();
virtual IReGameHookRegistry_PM_Duck *PM_Duck();
virtual IReGameHookRegistry_PM_UnDuck *PM_UnDuck();
virtual IReGameHookRegistry_PM_PlayStepSound *PM_PlayStepSound();
virtual IReGameHookRegistry_PM_AirAccelerate *PM_AirAccelerate();
virtual IReGameHookRegistry_ClearMultiDamage *ClearMultiDamage();
virtual IReGameHookRegistry_AddMultiDamage *AddMultiDamage();
virtual IReGameHookRegistry_ApplyMultiDamage *ApplyMultiDamage();
virtual IReGameHookRegistry_BuyItem *BuyItem();
virtual IReGameHookRegistry_CSGameRules_Think *CSGameRules_Think();
virtual IReGameHookRegistry_CSGameRules_TeamFull *CSGameRules_TeamFull();
virtual IReGameHookRegistry_CSGameRules_TeamStacked *CSGameRules_TeamStacked();
virtual IReGameHookRegistry_CSGameRules_PlayerGotWeapon *CSGameRules_PlayerGotWeapon();
virtual IReGameHookRegistry_CBotManager_OnEvent *CBotManager_OnEvent();
virtual IReGameHookRegistry_CBasePlayer_CheckTimeBasedDamage *CBasePlayer_CheckTimeBasedDamage();
virtual IReGameHookRegistry_CBasePlayer_EntSelectSpawnPoint *CBasePlayer_EntSelectSpawnPoint();
virtual IReGameHookRegistry_CBasePlayerWeapon_ItemPostFrame *CBasePlayerWeapon_ItemPostFrame();
virtual IReGameHookRegistry_CBasePlayerWeapon_KickBack *CBasePlayerWeapon_KickBack();
virtual IReGameHookRegistry_CBasePlayerWeapon_SendWeaponAnim *CBasePlayerWeapon_SendWeaponAnim();
virtual IReGameHookRegistry_CSGameRules_SendDeathMessage *CSGameRules_SendDeathMessage();
virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink();
virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think();
virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems();
virtual IReGameHookRegistry_CBasePlayer_UpdateStatusBar *CBasePlayer_UpdateStatusBar();
virtual IReGameHookRegistry_CBasePlayer_TakeDamageImpulse *CBasePlayer_TakeDamageImpulse();
};
extern CReGameHookchains g_ReGameHookchains;
@ -938,14 +1108,3 @@ public:
EXT_FUNC virtual bool BGetICSEntity(const char *pchVersion) const;
EXT_FUNC virtual bool BGetIGameRules(const char *pchVersion) const;
};
void Regamedll_ChangeString_api(char *&dest, const char *source);
void RadiusDamage_api(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType);
void ClearMultiDamage_api();
void ApplyMultiDamage_api(entvars_t *pevInflictor, entvars_t *pevAttacker);
void AddMultiDamage_api(entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType);
void UTIL_RestartOther_api(const char *szClassname);
void UTIL_ResetEntities_api();
void UTIL_RemoveOther_api(const char *szClassname, int nCount = 0);

@ -30,15 +30,15 @@
void CCSEntity::FireBullets(int iShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker)
{
m_pContainingEntity->FireBullets(iShots, vecSrc, vecDirShooting, vecSpread, flDistance, iBulletType, iTracerFreq, iDamage, pevAttacker);
BaseEntity()->FireBullets(iShots, vecSrc, vecDirShooting, vecSpread, flDistance, iBulletType, iTracerFreq, iDamage, pevAttacker);
}
void CCSEntity::FireBuckshots(ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iTracerFreq, int iDamage, entvars_t *pevAttacker)
{
m_pContainingEntity->FireBuckshots(cShots, vecSrc, vecDirShooting, vecSpread, flDistance, iTracerFreq, iDamage, pevAttacker);
BaseEntity()->FireBuckshots(cShots, vecSrc, vecDirShooting, vecSpread, flDistance, iTracerFreq, iDamage, pevAttacker);
}
Vector CCSEntity::FireBullets3(Vector &vecSrc, Vector &vecDirShooting, float vecSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand)
{
return m_pContainingEntity->FireBullets3(vecSrc, vecDirShooting, vecSpread, flDistance, iPenetration, iBulletType, iDamage, flRangeModifier, pevAttacker, bPistol, shared_rand);
return BaseEntity()->FireBullets3(vecSrc, vecDirShooting, vecSpread, flDistance, iPenetration, iBulletType, iDamage, flRangeModifier, pevAttacker, bPistol, shared_rand);
}

@ -43,8 +43,10 @@ EXT_FUNC bool CCSPlayer::JoinTeam(TeamName team)
pPlayer->pev->deadflag = DEAD_DEAD;
pPlayer->pev->health = 0;
if (pPlayer->m_bHasC4)
pPlayer->DropPlayerItem("weapon_c4");
pPlayer->RemoveAllItems(TRUE);
pPlayer->m_bHasC4 = false;
pPlayer->m_iTeam = SPECTATOR;
pPlayer->m_iJoiningState = JOINED;
@ -58,7 +60,7 @@ EXT_FUNC bool CCSPlayer::JoinTeam(TeamName team)
pPlayer->StartObserver(pentSpawnSpot->v.origin, pentSpawnSpot->v.angles);
// do we have fadetoblack on? (need to fade their screen back in)
if (fadetoblack.value)
if (fadetoblack.value == FADETOBLACK_STAY)
{
UTIL_ScreenFade(pPlayer, Vector(0, 0, 0), 0.001, 0, 0, FFADE_IN);
}
@ -153,15 +155,7 @@ EXT_FUNC bool CCSPlayer::RemovePlayerItemEx(const char* pszItemName, bool bRemov
if (!pPlayer->m_bHasDefuser)
return false;
pPlayer->m_bHasDefuser = false;
pPlayer->pev->body = 0;
MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pPlayer->pev);
WRITE_BYTE(STATUSICON_HIDE);
WRITE_STRING("defuser");
MESSAGE_END();
pPlayer->SendItemStatus();
pPlayer->RemoveDefuser();
}
// item_longjump
else if (FStrEq(pszItemName, "longjump"))
@ -225,38 +219,20 @@ EXT_FUNC bool CCSPlayer::RemovePlayerItemEx(const char* pszItemName, bool bRemov
return true; // ammo was reduced, this will be considered a successful result
}
if (bRemoveAmmo) {
pPlayer->m_rgAmmo[pItem->PrimaryAmmoIndex()] = 0;
}
if (pItem == pPlayer->m_pActiveItem) {
((CBasePlayerWeapon *)pItem)->RetireWeapon();
}
if (bRemoveAmmo) {
pPlayer->m_rgAmmo[ pItem->PrimaryAmmoIndex() ] = 0;
if (pItem->CanHolster() && pItem != pPlayer->m_pActiveItem && !(pPlayer->pev->weapons &(1 << pItem->m_iId))) {
return true;
}
}
}
if (pPlayer->RemovePlayerItem(pItem))
{
if (FClassnameIs(pItem->pev, "weapon_c4")) {
pPlayer->m_bHasC4 = false;
pPlayer->pev->body = 0;
pPlayer->SetBombIcon(FALSE);
pPlayer->SetProgressBarTime(0);
}
pPlayer->pev->weapons &= ~(1 << pItem->m_iId);
// No more weapon
if ((pPlayer->pev->weapons & ~(1 << WEAPON_SUIT)) == 0) {
pPlayer->m_iHideHUD |= HIDEHUD_WEAPONS;
}
pItem->Kill();
if (!pPlayer->m_rgpPlayerItems[PRIMARY_WEAPON_SLOT]) {
pPlayer->m_bHasPrimary = false;
}
return true;
}
return pItem->DestroyItem();
}
return false;
@ -273,11 +249,13 @@ EXT_FUNC CBaseEntity *CCSPlayer::GiveNamedItemEx(const char *pszName)
if (FStrEq(pszName, "weapon_c4")) {
pPlayer->m_bHasC4 = true;
pPlayer->SetBombIcon();
if (pPlayer->m_iTeam == TERRORIST) {
pPlayer->pev->body = 1;
}
pPlayer->SetBombIcon();
} else if (FStrEq(pszName, "weapon_shield")) {
pPlayer->DropPrimary();
pPlayer->DropPlayerItem("weapon_elite");
@ -290,7 +268,7 @@ EXT_FUNC CBaseEntity *CCSPlayer::GiveNamedItemEx(const char *pszName)
EXT_FUNC bool CCSPlayer::IsConnected() const
{
return m_pContainingEntity->has_disconnected == false;
return BaseEntity()->has_disconnected == false;
}
EXT_FUNC void CCSPlayer::SetAnimation(PLAYER_ANIM playerAnim)
@ -318,14 +296,14 @@ EXT_FUNC void CCSPlayer::GiveShield(bool bDeploy)
BasePlayer()->GiveShield(bDeploy);
}
EXT_FUNC void CCSPlayer::DropShield(bool bDeploy)
EXT_FUNC CBaseEntity *CCSPlayer::DropShield(bool bDeploy)
{
BasePlayer()->DropShield(bDeploy);
return BasePlayer()->DropShield(bDeploy);
}
EXT_FUNC void CCSPlayer::DropPlayerItem(const char *pszItemName)
EXT_FUNC CBaseEntity *CCSPlayer::DropPlayerItem(const char *pszItemName)
{
BasePlayer()->DropPlayerItem(pszItemName);
return BasePlayer()->DropPlayerItem(pszItemName);
}
EXT_FUNC bool CCSPlayer::RemoveShield()
@ -434,6 +412,11 @@ EXT_FUNC void CCSPlayer::Observer_SetMode(int iMode)
BasePlayer()->Observer_SetMode(iMode);
}
EXT_FUNC void CCSPlayer::Observer_FindNextPlayer(bool bReverse, const char *name)
{
BasePlayer()->Observer_FindNextPlayer(bReverse, name);
}
EXT_FUNC bool CCSPlayer::SelectSpawnSpot(const char *pEntClassName, CBaseEntity *&pSpot)
{
return BasePlayer()->SelectSpawnSpot(pEntClassName, pSpot);
@ -556,6 +539,11 @@ EXT_FUNC bool CCSPlayer::CheckActivityInGame()
return (fabs(deltaYaw) >= 0.1f && fabs(deltaPitch) >= 0.1f);
}
EXT_FUNC void CCSPlayer::TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier)
{
BasePlayer()->TakeDamageImpulse(pAttacker, flKnockbackForce, flVelModifier);
}
void CCSPlayer::ResetVars()
{
m_szModel[0] = '\0';
@ -574,10 +562,24 @@ void CCSPlayer::ResetVars()
m_bSpawnProtectionEffects = false;
}
// Resets all stats
void CCSPlayer::ResetAllStats()
{
// Resets the kill history for this player
for (int i = 0; i < MAX_CLIENTS; i++)
{
m_iNumKilledByUnanswered[i] = 0;
m_bPlayerDominated[i] = false;
}
m_DamageList.Clear();
}
void CCSPlayer::OnSpawn()
{
m_bGameForcingRespawn = false;
m_flRespawnPending = 0.0f;
m_DamageList.Clear();
}
void CCSPlayer::OnKilled()
@ -595,3 +597,34 @@ void CCSPlayer::OnKilled()
}
#endif
}
void CCSPlayer::OnConnect()
{
ResetVars();
ResetAllStats();
m_iUserID = GETPLAYERUSERID(BasePlayer()->edict());
}
// Remember this amount of damage that we dealt for stats
void CCSPlayer::RecordDamage(CBasePlayer *pAttacker, float flDamage, float flFlashDurationTime)
{
if (!pAttacker || !pAttacker->IsPlayer())
return;
int attackerIndex = pAttacker->entindex() - 1;
if (attackerIndex < 0 || attackerIndex >= MAX_CLIENTS)
return;
CCSPlayer *pCSAttacker = pAttacker->CSPlayer();
// Accumulate damage
CDamageRecord_t &record = m_DamageList[attackerIndex];
if (record.flDamage > 0 && record.userId != pCSAttacker->m_iUserID)
record.flDamage = 0; // reset damage if attacker became another client
record.flDamage += flDamage;
record.userId = pCSAttacker->m_iUserID;
if (flFlashDurationTime > 0)
record.flFlashDurationTime = gpGlobals->time + flFlashDurationTime;
}

@ -0,0 +1,54 @@
/*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
*/
#include "precompiled.h"
EXT_FUNC BOOL CCSPlayerWeapon::DefaultDeploy(char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal)
{
return BasePlayerWeapon()->DefaultDeploy(szViewModel, szWeaponModel, iAnim, szAnimExt, skiplocal);
}
EXT_FUNC int CCSPlayerWeapon::DefaultReload(int iClipSize, int iAnim, float fDelay)
{
return BasePlayerWeapon()->DefaultReload(iClipSize, iAnim, fDelay);
}
EXT_FUNC bool CCSPlayerWeapon::DefaultShotgunReload(int iAnim, int iStartAnim, float fDelay, float fStartDelay, const char *pszReloadSound1, const char *pszReloadSound2)
{
return BasePlayerWeapon()->DefaultShotgunReload(iAnim, iStartAnim, fDelay, fStartDelay, pszReloadSound1, pszReloadSound2);
}
EXT_FUNC void CCSPlayerWeapon::KickBack(float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change)
{
BasePlayerWeapon()->KickBack(up_base, lateral_base, up_modifier, lateral_modifier, up_max, lateral_max, direction_change);
}
EXT_FUNC void CCSPlayerWeapon::SendWeaponAnim(int iAnim, int skiplocal)
{
BasePlayerWeapon()->SendWeaponAnim(iAnim, skiplocal);
}

@ -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;
@ -20,7 +24,7 @@ void CBasePlayerAmmo::Spawn()
BOOL CBasePlayerAmmo::AddAmmo(CBaseEntity *pOther)
{
auto ammoInfo = GetAmmoInfo(pev->classname);
if (pOther->GiveAmmo(ammoInfo->buyClipSize, ammoInfo->ammoName2) == -1)
if (!ammoInfo || pOther->GiveAmmo(ammoInfo->buyClipSize, ammoInfo->ammoName2) == -1)
{
return FALSE;
}

@ -179,6 +179,11 @@ NOXREF int CBaseAnimating::GetBodygroup(int iGroup)
return ::GetBodygroup(GET_MODEL_PTR(ENT(pev)), pev, iGroup);
}
float CBaseAnimating::GetSequenceDuration() const
{
return ::GetSequenceDuration(GET_MODEL_PTR(ENT(pev)), pev);
}
int CBaseAnimating::ExtractBbox(int sequence, float *mins, float *maxs)
{
return ::ExtractBbox(GET_MODEL_PTR(ENT(pev)), sequence, mins, maxs);

@ -12,7 +12,7 @@ server_studio_api_t IEngineStudio;
studiohdr_t *g_pstudiohdr;
float (*g_pRotationMatrix)[3][4];
float (*g_pBoneTransform)[128][3][4];
float (*g_pBoneTransform)[MAXSTUDIOBONES][3][4];
int ExtractBbox(void *pmodel, int sequence, float *mins, float *maxs)
{
@ -246,6 +246,21 @@ void GetSequenceInfo(void *pmodel, entvars_t *pev, float *pflFrameRate, float *p
*pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1);
}
float GetSequenceDuration(void *pmodel, entvars_t *pev)
{
studiohdr_t *pstudiohdr = (studiohdr_t *)pmodel;
if (!pstudiohdr)
return 0; // model ptr is not valid
if (pev->sequence < 0 || pev->sequence >= pstudiohdr->numseq)
return 0; // sequence is not valid
// get current sequence time
mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + int(pev->sequence);
return pseqdesc->numframes / pseqdesc->fps;
}
int GetSequenceFlags(void *pmodel, entvars_t *pev)
{
studiohdr_t *pstudiohdr = (studiohdr_t *)pmodel;
@ -522,7 +537,7 @@ C_DLLEXPORT int Server_GetBlendingInterface(int version, struct sv_blending_inte
IEngineStudio.Mod_Extradata = ((struct server_studio_api_s *)pstudio)->Mod_Extradata;
g_pRotationMatrix = (float (*)[3][4])rotationmatrix;
g_pBoneTransform = (float (*)[128][3][4])bonetransform;
g_pBoneTransform = (float (*)[MAXSTUDIOBONES][3][4])bonetransform;
return 1;
}
@ -532,7 +547,9 @@ void AngleQuaternion(vec_t *angles, vec_t *quaternion)
{
static const ALIGN16_BEG size_t ps_signmask[4] ALIGN16_END = { 0x80000000, 0, 0x80000000, 0 };
__m128 a = _mm_loadu_ps(angles);
vec4_t _ps_angles = { angles[0], angles[1], angles[2], 0.0f };
__m128 a = _mm_loadu_ps(_ps_angles);
a = _mm_mul_ps(a, _mm_load_ps(_ps_0p5)); //a *= 0.5
__m128 s, c;
sincos_ps(a, &s, &c);

@ -42,6 +42,7 @@ int LookupActivity(void *pmodel, entvars_t *pev, int activity);
int LookupActivityHeaviest(void *pmodel, entvars_t *pev, int activity);
int LookupSequence(void *pmodel, const char *label);
void GetSequenceInfo(void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed);
float GetSequenceDuration(void *pmodel, entvars_t *pev);
int GetSequenceFlags(void *pmodel, entvars_t *pev);
float SetController(void *pmodel, entvars_t *pev, int iController, float flValue);
float SetBlending(void *pmodel, entvars_t *pev, int iBlender, float flValue);

@ -451,17 +451,13 @@ BOOL CBaseMonster::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, f
if (pev->health <= 0.0f)
{
g_pevLastInflictor = pevInflictor;
if (bitsDamageType & DMG_ALWAYSGIB)
Killed(pevAttacker, GIB_ALWAYS);
KilledInflicted(pevInflictor, pevAttacker, GIB_ALWAYS);
else if (bitsDamageType & DMG_NEVERGIB)
Killed(pevAttacker, GIB_NEVER);
KilledInflicted(pevInflictor, pevAttacker, GIB_NEVER);
else
Killed(pevAttacker, GIB_NORMAL);
KilledInflicted(pevInflictor, pevAttacker, GIB_NORMAL);
g_pevLastInflictor = nullptr;
return FALSE;
}
if ((pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker))

@ -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), ""))
@ -429,6 +426,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())
@ -671,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), ""))
@ -892,3 +900,129 @@ float CCSBot::GetRangeToFarthestEscortedHostage() const
return away.m_farRange;
}
// Remove all occurrences of a given area from the path list
void CCSBot::RemovePath(CNavArea *area)
{
int i = 0;
while (i < m_pathLength)
{
if (m_path[i].area == area)
{
// If this area is linked to a ladder, clear the reference
if (m_path[i].ladder == m_pathLadder)
m_pathLadder = nullptr;
m_pathLength--;
// adjust the current path index if the removed element is being used
if (i == m_pathIndex)
{
if (i > 0)
m_pathIndex = i - 1;
else
m_pathIndex = 0;
}
if (m_pathLength != i)
Q_memmove(&m_path[i], &m_path[i + 1], (m_pathLength - i) * sizeof(m_path[0]));
// clear the slot
Q_memset(&m_path[m_pathLength], 0, sizeof(m_path[m_pathLength]));
}
else
{
i++;
}
}
}
// Remove a hiding spot from the checked spots list
void CCSBot::RemoveHidingSpot(HidingSpot *spot)
{
int i = 0;
while (i < m_checkedHidingSpotCount)
{
if (m_checkedHidingSpot[i].spot == spot)
{
m_checkedHidingSpotCount--;
if (m_checkedHidingSpotCount != i)
Q_memmove(&m_checkedHidingSpot[i], &m_checkedHidingSpot[i + 1], (m_checkedHidingSpotCount - i) * sizeof(m_checkedHidingSpot[0]));
// clear the slot
Q_memset(&m_checkedHidingSpot[m_checkedHidingSpotCount], 0, sizeof(m_checkedHidingSpot[m_checkedHidingSpotCount]));
}
else
{
i++;
}
}
}
// Handle navigation-related cleanup when a nav area, spot, or encounter is destroyed
void CCSBot::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead)
{
switch (navNotifyType)
{
case NAV_NOTIFY_DESTROY_AREA:
{
CNavArea *area = static_cast<CNavArea *>(dead);
// If the destroyed area was linked to a spot encounter, clear it
if (m_spotEncounter)
{
if (m_spotEncounter->from.area == area || m_spotEncounter->to.area == area)
m_spotEncounter = nullptr;
}
RemovePath(area);
// Invalidate any references to the destroyed area
if (m_noiseArea == area)
m_noiseArea = nullptr;
if (m_currentArea == area)
m_currentArea = nullptr;
if (m_lastKnownArea == area)
m_lastKnownArea = nullptr;
if (m_hideState.GetSearchArea() == area)
m_hideState.SetSearchArea(nullptr);
if (m_huntState.GetHuntArea() == area)
m_huntState.ClearHuntArea();
break;
}
case NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER:
{
CNavArea *area = static_cast<CNavArea *>(dead);
// Remove the encounter if it references the destroyed area
if (m_spotEncounter && area->HasSpotEncounter(m_spotEncounter))
m_spotEncounter = nullptr;
break;
}
case NAV_NOTIFY_DESTROY_SPOT:
{
HidingSpot *spot = static_cast<HidingSpot *>(dead);
// Remove the destroyed hiding spot from the spot order list
if (m_spotEncounter)
{
SpotOrderList &spotOrderList = m_spotEncounter->spotList;
spotOrderList.erase(std::remove_if(spotOrderList.begin(), spotOrderList.end(), [&](SpotOrder &spotOrder) {
return spotOrder.spot == spot;
}
), spotOrderList.end());
}
RemoveHidingSpot(spot);
break;
}
}
}

@ -42,9 +42,6 @@ enum
BOT_PROGGRESS_HIDE, // hide status bar progress
};
extern int _navAreaCount;
extern int _currentIndex;
class CCSBot;
class BotChatterInterface;
@ -74,6 +71,7 @@ public:
virtual const char *GetName() const { return "Hunt"; }
void ClearHuntArea() { m_huntArea = nullptr; }
CNavArea *GetHuntArea() { return m_huntArea; }
private:
CNavArea *m_huntArea;
@ -207,6 +205,7 @@ public:
const Vector &GetHidingSpot() const { return m_hidingSpot; }
void SetSearchArea(CNavArea *area) { m_searchFromArea = area; }
CNavArea *GetSearchArea() { return m_searchFromArea; }
void SetSearchRange(float range) { m_range = range; }
void SetDuration(float time) { m_duration = time; }
@ -378,6 +377,10 @@ public:
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
@ -532,12 +535,21 @@ public:
bool IsAwareOfEnemyDeath() const; // return true if we *noticed* that our enemy died
int GetLastVictimID() const; // return the ID (entindex) of the last victim we killed, or zero
#ifdef REGAMEDLL_ADD
bool CanSeeSniper(void) const; ///< return true if we can see an enemy sniper
bool HasSeenSniperRecently(void) const; ///< return true if we have seen a sniper recently
#endif
// navigation
bool HasPath() const;
void DestroyPath();
float GetFeetZ() const; // return Z of bottom of feet
void OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead);
void RemovePath(CNavArea *area);
void RemoveHidingSpot(HidingSpot *spot);
enum PathResult
{
PROGRESSING, // we are moving along the path
@ -920,6 +932,11 @@ private:
float m_fireWeaponTimestamp;
#ifdef REGAMEDLL_ADD
bool m_isEnemySniperVisible; ///< do we see an enemy sniper right now
CountdownTimer m_sawEnemySniperTimer; ///< tracking time since saw enemy sniper
#endif
// reaction time system
enum { MAX_ENEMY_QUEUE = 20 };
struct ReactionState
@ -970,7 +987,6 @@ private:
const CNavNode *m_navNodeList;
CNavNode *m_currentNode;
NavDirType m_generationDir;
NavAreaList::iterator m_analyzeIter;
enum ProcessType
{
@ -1109,6 +1125,11 @@ inline bool CCSBot::IsAtBombsite()
inline CCSBot::MoraleType CCSBot::GetMorale() const
{
#ifdef REGAMEDLL_ADD
if (cv_bot_excellent_morale.value != 0.0f)
return EXCELLENT;
#endif
return m_morale;
}
@ -1250,6 +1271,18 @@ inline int CCSBot::GetLastVictimID() const
return m_lastVictimID;
}
#ifdef REGAMEDLL_ADD
inline bool CCSBot::CanSeeSniper(void) const
{
return m_isEnemySniperVisible;
}
inline bool CCSBot::HasSeenSniperRecently(void) const
{
return !m_sawEnemySniperTimer.IsElapsed();
}
#endif
inline bool CCSBot::HasPath() const
{
return m_pathLength != 0;

@ -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), ""))
@ -249,6 +246,17 @@ void BotHostageBeingTakenMeme::Interpret(CCSBot *pSender, CCSBot *pReceiver) con
pReceiver->GetChatter()->Say("Affirmative");
}
#ifdef REGAMEDLL_ADD
//---------------------------------------------------------------------------------------------------------------
/**
* A teammate warned about snipers, so we shouldn't warn again for awhile
*/
void BotWarnSniperMeme::Interpret(CCSBot* sender, CCSBot* receiver) const
{
receiver->GetChatter()->FriendSpottedSniper();
}
#endif
BotSpeakable::BotSpeakable()
{
m_phrase = nullptr;
@ -467,6 +475,7 @@ bool BotPhraseManager::Initialize(const char *filename, int bankIndex)
phraseData = SharedParse(phraseData);
if (!phraseData)
{
if (phrase) delete phrase;
CONSOLE_ECHO("Error parsing '%s' - expected identifier\n", filename);
FREE_FILE(phraseDataFile);
return false;
@ -540,8 +549,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;
}
@ -1267,6 +1281,9 @@ void BotChatterInterface::Reset()
m_planInterval.Invalidate();
m_encourageTimer.Invalidate();
m_escortingHostageTimer.Invalidate();
#ifdef REGAMEDLL_ADD
m_warnSniperTimer.Invalidate();
#endif
}
// Register a statement for speaking
@ -1520,10 +1537,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), ""))
@ -1626,6 +1640,42 @@ void BotChatterInterface::EnemySpotted()
AddStatement(say);
}
#ifdef REGAMEDLL_ADD
//---------------------------------------------------------------------------------------------------------------
/**
* If a friend warned of snipers, don't warn again for awhile
*/
void BotChatterInterface::FriendSpottedSniper(void)
{
m_warnSniperTimer.Start(60.0f);
}
//---------------------------------------------------------------------------------------------------------------
/**
* Warn of an enemy sniper
*/
void BotChatterInterface::SpottedSniper(void)
{
if (!m_warnSniperTimer.IsElapsed())
{
return;
}
if (m_me->GetFriendsRemaining() == 0)
{
// no-one to warn
return;
}
BotStatement* say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
say->AppendPhrase(TheBotPhrases->GetPhrase("SniperWarning"));
say->AttachMeme(new BotWarnSniperMeme());
AddStatement(say);
}
#endif
NOXREF void BotChatterInterface::Clear(Place place)
{
BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);

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

@ -56,6 +56,11 @@ void CCSBot::OnEvent(GameEventType event, CBaseEntity *pEntity, CBaseEntity *pOt
DecreaseMorale();
}
break;
#ifdef REGAMEDLL_FIXES
case EVENT_NEW_MATCH:
m_morale = POSITIVE; // starting a new round makes everyone a little happy
break;
#endif
}
if (!IsAlive())

@ -28,6 +28,7 @@
#include "precompiled.h"
cvar_t cv_bot_enable = { "bot_enable", "0", 0, 0.0f, nullptr };
cvar_t cv_bot_traceview = { "bot_traceview", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_stop = { "bot_stop", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_show_nav = { "bot_show_nav", "0", FCVAR_SERVER, 0.0f, nullptr };
@ -62,6 +63,9 @@ 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 };
cvar_t cv_bot_excellent_morale = { "bot_excellent_morale", "0", 0, 0.0f, nullptr };
#else
// Migrated to bot_quota_mode, use "match"
cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr };
@ -131,6 +135,9 @@ 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);
CVAR_REGISTER(&cv_bot_excellent_morale);
#endif
}
@ -189,6 +196,11 @@ void CCSBot::ResetValues()
m_currentArea = nullptr;
m_lastKnownArea = nullptr;
#ifdef REGAMEDLL_ADD
m_isEnemySniperVisible = false;
m_sawEnemySniperTimer.Invalidate();
#endif
m_avoidFriendTimer.Invalidate();
m_isFriendInTheWay = false;
m_isWaitingBehindFriend = false;
@ -325,10 +337,10 @@ void CCSBot::ResetValues()
// NOTE: For some reason, this can be called twice when a bot is added.
void CCSBot::SpawnBot()
{
TheCSBots()->ValidateMapData();
TheCSBots()->LoadNavigationMap();
ResetValues();
Q_strcpy(m_name, STRING(pev->netname));
Q_strlcpy(m_name, STRING(pev->netname));
SetState(&m_buyState);
SetTouch(&CCSBot::BotTouch);

@ -28,6 +28,7 @@
#pragma once
extern cvar_t cv_bot_enable;
extern cvar_t cv_bot_traceview;
extern cvar_t cv_bot_stop;
extern cvar_t cv_bot_show_nav;
@ -62,6 +63,9 @@ 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;
extern cvar_t cv_bot_excellent_morale;
#else
extern cvar_t cv_bot_quota_match;
#endif

@ -30,8 +30,7 @@
const float updateTimesliceDuration = 0.5f;
int _navAreaCount = 0;
int _currentIndex = 0;
unsigned int _generationIndex = 0; // used for iterating nav areas during generation process
inline CNavNode *LadderEndSearch(CBaseEntity *pEntity, const Vector *pos, NavDirType mountDir)
{
@ -385,11 +384,8 @@ void CCSBot::UpdateLearnProcess()
void CCSBot::StartAnalyzeAlphaProcess()
{
m_processMode = PROCESS_ANALYZE_ALPHA;
m_analyzeIter = TheNavAreaList.begin();
_navAreaCount = TheNavAreaList.size();
_currentIndex = 0;
m_processMode = PROCESS_ANALYZE_ALPHA;
_generationIndex = 0;
ApproachAreaAnalysisPrep();
DestroyHidingSpots();
@ -400,15 +396,18 @@ void CCSBot::StartAnalyzeAlphaProcess()
bool CCSBot::AnalyzeAlphaStep()
{
_currentIndex++;
if (m_analyzeIter == TheNavAreaList.end())
_generationIndex++;
if (_generationIndex < 0 || _generationIndex >= TheNavAreaList.size())
return false;
CNavArea *area = (*m_analyzeIter);
// TODO: Pretty ugly and very slow way to access element by index
// There is no reason not to use a vector instead of a linked list
const NavAreaList::const_iterator &iter = std::next(TheNavAreaList.begin(), _generationIndex - 1);
CNavArea *area = (*iter);
area->ComputeHidingSpots();
area->ComputeApproachAreas();
m_analyzeIter++;
return true;
}
@ -426,29 +425,30 @@ void CCSBot::UpdateAnalyzeAlphaProcess()
}
}
float progress = (double(_currentIndex) / double(_navAreaCount)) * 0.5f;
float progress = (double(_generationIndex) / double(TheNavAreaList.size())) * 0.5f;
drawProgressMeter(progress, "#CZero_AnalyzingHidingSpots");
}
void CCSBot::StartAnalyzeBetaProcess()
{
m_processMode = PROCESS_ANALYZE_BETA;
m_analyzeIter = TheNavAreaList.begin();
_navAreaCount = TheNavAreaList.size();
_currentIndex = 0;
m_processMode = PROCESS_ANALYZE_BETA;
_generationIndex = 0;
}
bool CCSBot::AnalyzeBetaStep()
{
_currentIndex++;
if (m_analyzeIter == TheNavAreaList.end())
_generationIndex++;
if (_generationIndex < 0 || _generationIndex >= TheNavAreaList.size())
return false;
CNavArea *area = (*m_analyzeIter);
// TODO: Pretty ugly and very slow way to access element by index
// There is no reason not to use a vector instead of a linked list
const NavAreaList::const_iterator &iter = std::next(TheNavAreaList.begin(), _generationIndex - 1);
CNavArea *area = (*iter);
area->ComputeSpotEncounters();
area->ComputeSniperSpots();
m_analyzeIter++;
return true;
}
@ -466,7 +466,7 @@ void CCSBot::UpdateAnalyzeBetaProcess()
}
}
float progress = (double(_currentIndex) / double(_navAreaCount) + 1.0f) * 0.5f;
float progress = (double(_generationIndex) / double(TheNavAreaList.size()) + 1.0f) * 0.5f;
drawProgressMeter(progress, "#CZero_AnalyzingApproachPoints");
}
@ -477,31 +477,24 @@ void CCSBot::StartSaveProcess()
void CCSBot::UpdateSaveProcess()
{
char filename[256];
char msg[256];
char cmd[128];
char gd[64]{};
GET_GAME_DIR(gd);
GET_GAME_DIR(filename);
Q_strcat(filename, "\\");
Q_strcat(filename, TheBots->GetNavMapFilename());
HintMessageToAllPlayers("Saving...");
char filename[MAX_OSPATH];
Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, TheBots->GetNavMapFilename());
SaveNavigationMap(filename);
char msg[256]{};
Q_snprintf(msg, sizeof(msg), "Navigation file '%s' saved.", filename);
HintMessageToAllPlayers(msg);
CONSOLE_ECHO("%s\n", msg);
hideProgressMeter();
StartNormalProcess();
#ifndef REGAMEDLL_FIXES
Q_snprintf(cmd, sizeof(cmd), "map %s\n", STRING(gpGlobals->mapname));
#else
Q_snprintf(cmd, sizeof(cmd), "changelevel %s\n", STRING(gpGlobals->mapname));
#endif
SERVER_COMMAND(cmd);
// tell bot manager that the analysis is completed
if (TheCSBots())
TheCSBots()->AnalysisCompleted();
}
void CCSBot::StartNormalProcess()

@ -231,13 +231,12 @@ bool CCSBotManager::IsOnOffense(CBasePlayer *pPlayer) const
// Invoked when a map has just been loaded
void CCSBotManager::ServerActivate()
{
DestroyNavigationMap();
m_isMapDataLoaded = false;
m_zoneCount = 0;
m_gameScenario = SCENARIO_DEATHMATCH;
ValidateMapData();
LoadNavigationMap();
RestartRound();
m_isLearningMap = false;
@ -337,6 +336,10 @@ void CCSBotManager::ClientDisconnect(CBasePlayer *pPlayer)
pPlayer = GetClassPtr<CCSPlayer>((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,22 +399,24 @@ 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<CCSBot *>(pPlayer);
if (killThemAll || FStrEq(name, msg))
{
pPlayer->Kill();
}
pBot->Kill();
}
}
}
@ -423,13 +428,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);
@ -444,7 +453,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)));
}
}
}
}
@ -564,18 +577,21 @@ void CCSBotManager::ServerCommand(const char *pcmd)
}
else if (FStrEq(pcmd, "bot_nav_save"))
{
GET_GAME_DIR(buffer);
Q_strcat(buffer, "\\");
Q_strcat(buffer, CBotManager::GetNavMapFilename());
char gd[64]{};
GET_GAME_DIR(gd);
if (SaveNavigationMap(buffer))
CONSOLE_ECHO("Navigation map '%s' saved.\n", buffer);
char filename[MAX_OSPATH];
Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, CBotManager::GetNavMapFilename());
if (SaveNavigationMap(filename))
CONSOLE_ECHO("Navigation map '%s' saved.\n", filename);
else
CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", buffer);
CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", filename);
}
else if (FStrEq(pcmd, "bot_nav_load"))
{
ValidateMapData();
m_isMapDataLoaded = false; // force nav reload
LoadNavigationMap();
}
else if (FStrEq(pcmd, "bot_nav_use_place"))
{
@ -630,11 +646,15 @@ void CCSBotManager::ServerCommand(const char *pcmd)
{
CONSOLE_ECHO("Ambiguous\n");
}
else
else if (found)
{
CONSOLE_ECHO("Current place set to '%s'\n", found->GetName());
SetNavPlace(found->GetID());
}
else
{
CONSOLE_ECHO("Error - place name '%s' no exists in phrases BotChatter.db\n", msg);
}
}
}
else if (FStrEq(pcmd, "bot_nav_toggle_place_mode"))
@ -662,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;
@ -742,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;
}
@ -784,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
@ -818,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
@ -827,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
@ -846,21 +889,26 @@ void CCSBotManager::MaintainBotQuota()
if (m_isLearningMap)
return;
int totalHumansInGame = UTIL_HumansInGame();
int humanPlayersInGame = UTIL_HumansInGame(IGNORE_SPECTATORS);
int spectatorPlayersInGame = UTIL_SpectatorsInGame();
int humanPlayersInGame = UTIL_HumansInGame();
// don't add bots until local player has been registered, to make sure he's player ID #1
if (!IS_DEDICATED_SERVER() && totalHumansInGame == 0)
if (!IS_DEDICATED_SERVER() && humanPlayersInGame == 0)
return;
int desiredBotCount = int(cv_bot_quota.value);
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"))
@ -869,7 +917,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
{
@ -899,7 +947,7 @@ void CCSBotManager::MaintainBotQuota()
// wait for a player to join, if necessary
if (cv_bot_join_after_player.value > 0.0)
{
if (humanPlayersInGame == 0 && spectatorPlayersInGame == 0)
if (humanPlayersInGame == 0)
desiredBotCount = 0;
}
@ -916,13 +964,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)
{
@ -1039,7 +1089,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));
}
}
@ -1093,22 +1144,232 @@ private:
CCSBotManager::Zone *m_zone;
};
// Search the map entities to determine the game scenario and define important zones.
void CCSBotManager::ValidateMapData()
LINK_ENTITY_TO_CLASS(info_spawn_point, CPointEntity, CCSPointEntity)
inline bool IsFreeSpace(Vector vecOrigin, int iHullNumber, edict_t *pSkipEnt = nullptr)
{
if (UTIL_PointContents(vecOrigin) != CONTENTS_EMPTY)
return false;
TraceResult trace;
UTIL_TraceHull(vecOrigin, vecOrigin, dont_ignore_monsters, iHullNumber, pSkipEnt, &trace);
return (!trace.fStartSolid && !trace.fAllSolid && trace.fInOpen);
}
inline bool pointInRadius(Vector vecOrigin, float radius)
{
CBaseEntity *pEntity = nullptr;
while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecOrigin, radius)))
{
if (!UTIL_IsValidEntity(pEntity->edict()))
continue; // ignore the entity marked for deletion
if (FClassnameIs(pEntity->edict(), "info_spawn_point"))
return true;
}
return false;
}
// a simple algorithm that searches for the farthest point (so that the player does not look at the wall)
inline bool GetIdealLookYawForSpawnPoint(const Vector &vecStart, float &flIdealLookYaw)
{
const float ANGLE_STEP = 30.0f;
float bestDistance = 0.0f;
for (float angleYaw = 0.0f; angleYaw <= 360.0f; angleYaw += ANGLE_STEP)
{
TraceResult tr;
UTIL_MakeVectors(Vector(0, angleYaw, 0));
Vector vecEnd(vecStart + gpGlobals->v_forward * 8192);
UTIL_TraceLine(vecStart, vecEnd, ignore_monsters, nullptr, &tr);
float distance = (vecStart - tr.vecEndPos).Length();
if (distance > bestDistance)
{
bestDistance = distance;
flIdealLookYaw = angleYaw;
}
}
return bestDistance > 0.0f;
}
// this function from leaked csgo sources 2020y
inline bool IsValidArea(CNavArea *area)
{
ShortestPathCost cost;
bool bNotOrphaned;
// check that we can path from the nav area to a ct spawner to confirm it isn't orphaned.
CBaseEntity *CTSpawn = UTIL_FindEntityByClassname(nullptr, "info_player_start");
if (CTSpawn)
{
CNavArea *CTSpawnArea = TheNavAreaGrid.GetNearestNavArea(&CTSpawn->pev->origin);
bNotOrphaned = NavAreaBuildPath(area, CTSpawnArea, nullptr, cost);
if (bNotOrphaned)
return true;
}
// double check that we can path from the nav area to a t spawner to confirm it isn't orphaned.
CBaseEntity *TSpawn = UTIL_FindEntityByClassname(nullptr, "info_player_deathmatch");
if (TSpawn)
{
CNavArea *TSpawnArea = TheNavAreaGrid.GetNearestNavArea(&TSpawn->pev->origin);
bNotOrphaned = NavAreaBuildPath(area, TSpawnArea, nullptr, cost);
if (bNotOrphaned)
return true;
}
return false;
}
#ifdef REGAMEDLL_ADD
// Generates spawn points (info_spawn_point entities) for players and bots based on the navigation map data
// It uses the navigation areas to find valid spots for spawn points considering factors like area size, slope,
// available free space, and distance from other spawn points.
void GenerateSpawnPointsFromNavData()
{
// Remove any existing spawn points
UTIL_RemoveOther("info_spawn_point");
const int MAX_SPAWNS_POINTS = 128; // Max allowed spawn points
const float MAX_SLOPE = 0.85f; // Maximum slope allowed for a spawn point
const float MIN_AREA_SIZE = 32.0f; // Minimum area size for a valid spawn point
const float MIN_NEARBY_SPAWNPOINT = 128.0f; // Minimum distance between spawn point
// Total number of spawn points generated
int totalSpawns = 0;
for (CNavArea *area : TheNavAreaList)
{
if (totalSpawns >= MAX_SPAWNS_POINTS)
break;
if (!area)
continue;
// Skip areas that are too small
if (area->GetSizeX() < MIN_AREA_SIZE || area->GetSizeY() < MIN_AREA_SIZE)
continue;
// Skip areas with unwanted attributes (jump, crouch, etc.)
if (area->GetAttributes() != 0)
continue;
// Skip areas with steep slopes
if (area->GetAreaSlope() < MAX_SLOPE)
{
//CONSOLE_ECHO("Skip area slope: %0.3f\n", area->GetAreaSlope());
continue;
}
// Calculate the spawn point position above the area center
Vector vecOrigin = *area->GetCenter() + Vector(0, 0, HalfHumanHeight + 5);
// Ensure there is free space at the calculated position
if (!IsFreeSpace(vecOrigin, human_hull))
{
//CONSOLE_ECHO("No free space!\n");
continue;
}
if (pointInRadius(vecOrigin, MIN_NEARBY_SPAWNPOINT))
continue; // spawn point is too close to others
if (!IsValidArea(area))
continue;
// Calculate ideal spawn point yaw angle
float flIdealSpawnPointYaw = 0.0f;
if (GetIdealLookYawForSpawnPoint(vecOrigin, flIdealSpawnPointYaw))
{
CBaseEntity *pPoint = CBaseEntity::Create("info_spawn_point", vecOrigin, Vector(0, flIdealSpawnPointYaw, 0), nullptr);
if (pPoint)
{
totalSpawns++;
//CONSOLE_ECHO("Add spawn at x:%f y:%f z:%f with angle %0.1f slope %0.3f \n", vecOrigin.x, vecOrigin.y, vecOrigin.z, bestAngle.y, area->GetAreaSlope());
// use only for debugging
if (randomspawn.value > 1.0f)
{
SET_MODEL(ENT(pPoint->pev), "models/player.mdl");
pPoint->pev->sequence = ACT_IDLE;
pPoint->pev->rendermode = kRenderTransAdd;
pPoint->pev->renderamt = 150.0f;
}
}
}
}
CONSOLE_ECHO("Total spawns points: %i\n", totalSpawns);
}
#endif
// Load the map's navigation data
bool CCSBotManager::LoadNavigationMap()
{
// check if the map data is already loaded or if bots are not allowed
if (m_isMapDataLoaded || !AreBotsAllowed())
return;
return false;
m_isMapDataLoaded = true;
if (LoadNavigationMap())
// Clear navigation map data from previous map
DestroyNavigationMap();
// Try to load the map's navigation file
NavErrorType navStatus = ::LoadNavigationMap();
if (navStatus != NAV_OK)
{
CONSOLE_ECHO("Failed to load navigation map.\n");
return;
CONSOLE_ECHO("ERROR: Failed to load 'maps/%s.nav' file navigation map!\n", STRING(gpGlobals->mapname));
switch (navStatus)
{
case NAV_CANT_ACCESS_FILE:
CONSOLE_ECHO("\tNavigation file not found or access denied.\n");
break;
case NAV_INVALID_FILE:
CONSOLE_ECHO("\tInvalid navigation file format.\n");
break;
case NAV_BAD_FILE_VERSION:
CONSOLE_ECHO("\tBad navigation file version.\n");
break;
case NAV_CORRUPT_DATA:
CONSOLE_ECHO("\tCorrupted navigation data detected.\n");
break;
default:
break;
}
if (navStatus != NAV_CANT_ACCESS_FILE)
CONSOLE_ECHO("\tTry regenerating it using the command: bot_nav_analyze\n");
return false;
}
CONSOLE_ECHO("Navigation map loaded.\n");
// Determine the scenario for the current map (e.g., bomb defuse, hostage rescue etc)
DetermineMapScenario();
#ifdef REGAMEDLL_ADD
GenerateSpawnPointsFromNavData();
#endif
return true;
}
// Search the map entities to determine the game scenario and define important zones.
void CCSBotManager::DetermineMapScenario()
{
m_zoneCount = 0;
m_gameScenario = SCENARIO_DEATHMATCH;
@ -1160,6 +1421,13 @@ void CCSBotManager::ValidateMapData()
found = true;
isLegacy = false;
}
else if (FClassnameIs(pEntity->pev, "func_escapezone"))
{
m_gameScenario = SCENARIO_ESCAPE;
found = true;
isLegacy = false;
}
if (found)
{
@ -1241,6 +1509,59 @@ void CCSBotManager::ValidateMapData()
}
}
// Tell all bots that the given nav data no longer exists
// This function is called when a part of the map or the nav data is destroyed
void CCSBotManager::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead)
{
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (!pPlayer->IsBot())
continue;
// Notify the bot about the destroyed nav data
CCSBot *pBot = static_cast<CCSBot *>(pPlayer);
pBot->OnDestroyNavDataNotify(navNotifyType, dead);
}
}
// Called when the map analysis process has completed
// This function makes sure all bots are removed from the map analysis process
// and are reset to normal bot behavior. It also reloads the navigation map
// and triggers a game restart after the analysis is completed
void CCSBotManager::AnalysisCompleted()
{
// Ensure that all bots are no longer involved in map analysis and start their normal process
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (!pPlayer->IsBot())
continue;
CCSBot *pBot = static_cast<CCSBot *>(pPlayer);
pBot->StartNormalProcess();
}
m_isLearningMap = false;
m_isMapDataLoaded = false;
m_isAnalysisRequested = false;
// Try to reload the navigation map from the file
if (LoadNavigationMap())
{
// Initiate a game restart in 3 seconds
CVAR_SET_FLOAT("sv_restart", 3);
}
}
bool CCSBotManager::AddBot(const BotProfile *profile, BotProfileTeamType team)
{
if (!AreBotsAllowed())
@ -1448,6 +1769,7 @@ void CCSBotManager::SetLooseBomb(CBaseEntity *bomb)
if (bomb)
{
m_looseBombArea = TheNavAreaGrid.GetNearestNavArea(&bomb->pev->origin);
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
{
@ -1576,7 +1898,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())

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

@ -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())
@ -1294,7 +1291,7 @@ CCSBot::PathResult CCSBot::UpdatePathMovement(bool allowSpeedChange)
if (IsOnLadder())
Jump(MUST_JUMP);
assert(m_pathIndex < m_pathLength);
Assert(m_pathIndex < m_pathLength);
// Check if reached the end of the path
bool nearEndOfPath = false;

@ -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;

@ -255,7 +255,7 @@ void CCSBot::Update()
Vector dir = m_spotEncounter->path.to - m_spotEncounter->path.from;
float length = dir.NormalizeInPlace();
for (auto &order : m_spotEncounter->spotList) {
for (auto& order : m_spotEncounter->spotList) {
UTIL_DrawBeamPoints(m_spotEncounter->path.from + order.t * length * dir, *order.spot->GetPosition(), 3, 0, 255, 255);
}
}
@ -339,7 +339,7 @@ void CCSBot::Update()
UpdateReactionQueue();
// "threat" may be the same as our current enemy
CBasePlayer *threat = GetRecognizedEnemy();
CBasePlayer* threat = GetRecognizedEnemy();
if (threat)
{
// adjust our personal "safe" time
@ -437,7 +437,6 @@ void CCSBot::Update()
}
else
{
const int dada = offsetof(CCSBot, m_visibleEnemyParts);
// check LOS to current enemy (chest & head), in case he's dead (GetNearestEnemy() only returns live players)
// note we're not checking FOV - once we've acquired an enemy (which does check FOV), assume we know roughly where he is
if (IsVisible(m_enemy, false, &m_visibleEnemyParts))
@ -593,6 +592,10 @@ void CCSBot::Update()
SecondaryAttack();
}
#ifdef REGAMEDLL_ADD
if (!IsBlind())
{
#endif
// check encounter spots
UpdatePeripheralVision();
@ -602,11 +605,24 @@ void CCSBot::Update()
GetChatter()->SpottedBomber(GetBomber());
}
#ifdef REGAMEDLL_ADD
// watch for snipers
if (CanSeeSniper() && !HasSeenSniperRecently())
{
GetChatter()->SpottedSniper();
const float sniperRecentInterval = 20.0f;
m_sawEnemySniperTimer.Start(sniperRecentInterval);
}
#endif
if (CanSeeLooseBomb())
{
GetChatter()->SpottedLooseBomb(TheCSBots()->GetLooseBomb());
}
#ifdef REGAMEDLL_ADD
}
#endif
// Scenario interrupts
switch (TheCSBots()->GetScenario())
{

@ -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;
@ -691,6 +697,13 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
m_closestVisibleFriend = nullptr;
m_closestVisibleHumanFriend = nullptr;
#ifdef REGAMEDLL_ADD
m_isEnemySniperVisible = false;
CBasePlayer* sniperThreat = NULL;
float sniperThreatRange = 99999999999.9f;
bool sniperThreatIsFacingMe = false;
#endif
float closeFriendRange = 99999999999.9f;
float closeHumanFriendRange = 99999999999.9f;
@ -701,10 +714,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?
@ -786,6 +796,53 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
Vector d = pev->origin - pPlayer->pev->origin;
float distSq = d.LengthSquared();
#ifdef REGAMEDLL_ADD
CBasePlayerWeapon *pCurrentWeapon = static_cast<CBasePlayerWeapon *>(pPlayer->m_pActiveItem);
if (pCurrentWeapon && isSniperRifle(pCurrentWeapon))
{
m_isEnemySniperVisible = true;
if (sniperThreat)
{
if (IsPlayerLookingAtMe(pPlayer))
{
if (sniperThreatIsFacingMe)
{
// several snipers are facing us - keep closest
if (distSq < sniperThreatRange)
{
sniperThreat = pPlayer;
sniperThreatRange = distSq;
sniperThreatIsFacingMe = true;
}
}
else
{
// even if this sniper is farther away, keep it because he's aiming at us
sniperThreat = pPlayer;
sniperThreatRange = distSq;
sniperThreatIsFacingMe = true;
}
}
else
{
// this sniper is not looking at us, only consider it if we dont have a sniper facing us
if (!sniperThreatIsFacingMe && distSq < sniperThreatRange)
{
sniperThreat = pPlayer;
sniperThreatRange = distSq;
}
}
}
else
{
// first sniper we see
sniperThreat = pPlayer;
sniperThreatRange = distSq;
sniperThreatIsFacingMe = IsPlayerLookingAtMe(pPlayer);
}
}
#endif
// maintain set of visible threats, sorted by increasing distance
if (threatCount == 0)
{
@ -947,6 +1004,23 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
{
return currentThreat;
}
// if we are a sniper and we see a sniper threat, attack it unless
// there are other close enemies facing me
if (IsSniper() && sniperThreat)
{
const float closeCombatRange = 500.0f;
for (t = 0; t < threatCount; ++t)
{
if (threat[t].range < closeCombatRange && IsPlayerLookingAtMe(threat[t].enemy))
{
return threat[t].enemy;
}
}
return sniperThreat;
}
#endif
// otherwise, find the closest threat that without using shield

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

@ -95,10 +95,15 @@ void HuntState::OnUpdate(CCSBot *me)
{
if (!me->IsRogue() && me->CanSeeLooseBomb())
{
CNavArea *looseBombArea = TheCSBots()->GetLooseBombArea();
// if we are near the loose bomb and can see it, hide nearby and guard it
me->SetTask(CCSBot::GUARD_LOOSE_BOMB);
me->Hide(TheCSBots()->GetLooseBombArea());
me->GetChatter()->AnnouncePlan("GoingToGuardLooseBomb", TheCSBots()->GetLooseBombArea()->GetPlace());
me->Hide(looseBombArea);
if (looseBombArea)
me->GetChatter()->AnnouncePlan("GoingToGuardLooseBomb", looseBombArea->GetPlace());
return;
}
else if (TheCSBots()->IsBombPlanted())

@ -353,7 +353,7 @@ void IdleState::OnUpdate(CCSBot *me)
}
}
assert((0, "A CT bot doesn't know what to do while the bomb is planted!\n"));
DbgAssert(!"A CT bot doesn't know what to do while the bomb is planted!\n");
}
// if we have a sniper rifle, we like to camp, whether rogue or not
@ -773,6 +773,93 @@ void IdleState::OnUpdate(CCSBot *me)
}
break;
}
case CCSBotManager::SCENARIO_ESCAPE:
{
if (me->m_iTeam == TERRORIST)
{
// if early in round, pick a random zone, otherwise pick closest zone
const float earlyTime = 20.0f;
const CCSBotManager::Zone *zone = nullptr;
if (TheCSBots()->GetElapsedRoundTime() < earlyTime)
{
// pick random zone
zone = TheCSBots()->GetRandomZone();
}
else
{
// pick closest zone
zone = TheCSBots()->GetClosestZone(me->GetLastKnownArea(), PathCost(me));
}
if (zone)
{
// pick a random spot within the escape zone
const Vector *pos = TheCSBots()->GetRandomPositionInZone(zone);
if (pos)
{
// move to escape zone
// me->SetTask(CCSBot::VIP_ESCAPE);
me->Run();
me->MoveTo(pos);
return;
}
}
}
// CT
else
{
if (me->IsSniper())
{
if (RANDOM_FLOAT(0, 100) <= defenseSniperCampChance)
{
// snipe escape zone(s)
const CCSBotManager::Zone *zone = TheCSBots()->GetRandomZone();
if (zone)
{
CNavArea *area = TheCSBots()->GetRandomAreaInZone(zone);
if (area)
{
me->SetTask(CCSBot::MOVE_TO_SNIPER_SPOT);
me->Hide(area, -1.0, sniperHideRange);
me->SetDisposition(CCSBot::OPPORTUNITY_FIRE);
me->PrintIfWatched("Sniping near escape zone\n");
return;
}
}
}
}
// rogues just hunt, unless they want to snipe
// if the whole team has decided to rush, hunt
if (me->IsRogue() || TheCSBots()->IsDefenseRushing())
break;
// the lower our morale gets, the more we want to camp the escape zone(s)
float guardEscapeZoneChance = -34.0f * me->GetMorale();
if (RANDOM_FLOAT(0.0f, 100.0f) < guardEscapeZoneChance)
{
// guard escape zone(s)
const CCSBotManager::Zone *zone = TheCSBots()->GetRandomZone();
if (zone)
{
CNavArea *area = TheCSBots()->GetRandomAreaInZone(zone);
if (area)
{
// guard the escape zone - stay closer if our morale is low
//me->SetTask(CCSBot::GUARD_VIP_ESCAPE_ZONE);
me->PrintIfWatched("I'm guarding an escape zone\n");
float escapeGuardRange = 750.0f + 250.0f * (me->GetMorale() + 3);
me->Hide(area, -1.0, escapeGuardRange);
me->SetDisposition(CCSBot::OPPORTUNITY_FIRE);
return;
}
}
}
}
}
// deathmatch
default:
{

@ -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),
@ -671,7 +678,7 @@ void CBaseButton::ButtonActivate()
PlayLockSounds(pev, &m_ls, FALSE, TRUE);
}
assert(m_toggle_state == TS_AT_BOTTOM);
DbgAssert(m_toggle_state == TS_AT_BOTTOM);
m_toggle_state = TS_GOING_UP;
SetMoveDone(&CBaseButton::TriggerAndWait);
@ -688,7 +695,7 @@ void CBaseButton::ButtonActivate()
// Button has reached the "in/up" position. Activate its "targets", and pause before "popping out".
void CBaseButton::TriggerAndWait()
{
assert(m_toggle_state == TS_GOING_UP);
DbgAssert(m_toggle_state == TS_GOING_UP);
if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator))
return;
@ -724,7 +731,7 @@ void CBaseButton::TriggerAndWait()
// Starts the button moving "out/down".
void CBaseButton::ButtonReturn()
{
//assert(m_toggle_state == TS_AT_TOP);
DbgAssert(m_toggle_state == TS_AT_TOP);
m_toggle_state = TS_GOING_DOWN;
SetMoveDone(&CBaseButton::ButtonBackHome);
@ -763,7 +770,7 @@ void CBaseButton::Restart()
// Button has returned to start state. Quiesce it.
void CBaseButton::ButtonBackHome()
{
assert(m_toggle_state == TS_GOING_DOWN);
DbgAssert(m_toggle_state == TS_GOING_DOWN);
m_toggle_state = TS_AT_BOTTOM;
if (pev->spawnflags & SF_BUTTON_TOGGLE
@ -776,7 +783,11 @@ void CBaseButton::ButtonBackHome()
SUB_UseTargets(m_hActivator, USE_TOGGLE, 0);
}
if (!FStringNull(pev->target))
if (!FStringNull(pev->target)
#ifdef REGAMEDLL_FIXES
&& m_hActivator
#endif
)
{
edict_t *pentTarget = nullptr;
while ((pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target))))
@ -880,7 +891,7 @@ void CRotButton::Spawn()
m_vecAngle1 = pev->angles;
m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance;
assert(("rotating button start/end positions are equal", m_vecAngle1 != m_vecAngle2));
DbgAssertMsg(m_vecAngle1 != m_vecAngle2, "rotating button start/end positions are equal");
m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE);
m_fRotating = TRUE;

@ -260,7 +260,7 @@ void CCareerTask::OnEvent(GameEventType event, CBasePlayer *pVictim, CBasePlayer
while ((pHostage = UTIL_FindEntityByClassname(pHostage, "hostage_entity")))
{
if (pHostage && pHostage->IsDead())
if (pHostage->IsDead())
hostagesCount++;
}
@ -389,7 +389,6 @@ void CCareerTaskManager::Reset(bool deleteTasks)
delete task;
m_tasks.clear();
m_nextId = 0;
}
else
{
@ -397,6 +396,7 @@ void CCareerTaskManager::Reset(bool deleteTasks)
task->Reset();
}
m_nextId = 0;
m_finishedTaskTime = 0;
m_finishedTaskRound = 0;
m_shouldLatchRoundEndMessage = false;
@ -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++;
}

@ -63,6 +63,10 @@ NEW_DLL_FUNCTIONS gNewDLLFunctions =
nullptr
};
#ifndef REGAMEDLL_API
entvars_t *g_pevLastInflictor = nullptr;
#endif
CMemoryPool hashItemMemPool(sizeof(hash_item_t), 64);
int CaseInsensitiveHash(const char *string, int iBounds)
@ -697,7 +701,11 @@ BOOL CBaseEntity::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, fl
pev->health -= flDamage;
if (pev->health <= 0)
{
#ifdef REGAMEDLL_FIXES
KilledInflicted(pevInflictor, pevAttacker, GIB_NORMAL);
#else
Killed(pevAttacker, GIB_NORMAL);
#endif
return FALSE;
}
@ -866,6 +874,17 @@ BOOL CBaseEntity::IsInWorld()
}
// speed
#ifdef REGAMEDLL_FIXES
float maxvel = g_psv_maxvelocity->value;
if (pev->velocity.x > maxvel || pev->velocity.y > maxvel || pev->velocity.z > maxvel)
{
return FALSE;
}
if (pev->velocity.x < -maxvel || pev->velocity.y < -maxvel || pev->velocity.z < -maxvel)
{
return FALSE;
}
#else
if (pev->velocity.x >= 2000.0 || pev->velocity.y >= 2000.0 || pev->velocity.z >= 2000.0)
{
return FALSE;
@ -874,6 +893,7 @@ BOOL CBaseEntity::IsInWorld()
{
return FALSE;
}
#endif
return TRUE;
}
@ -1242,7 +1262,7 @@ bool EXT_FUNC IsPenetrableEntity_default(Vector &vecSrc, Vector &vecEnd, entvars
LINK_HOOK_CLASS_CHAIN(VectorRef, CBaseEntity, FireBullets3, (VectorRef vecSrc, VectorRef vecDirShooting, float vecSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand), vecSrc, vecDirShooting, vecSpread, flDistance, iPenetration, iBulletType, iDamage, flRangeModifier, pevAttacker, bPistol, shared_rand)
// Go to the trouble of combining multiple pellets into a single damage call.
// This version is used by Players, uses the random seed generator to sync client and server side shots.
VectorRef CBaseEntity::__API_HOOK(FireBullets3)(VectorRef vecSrc, VectorRef vecDirShooting, float vecSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand)
@ -1340,6 +1360,7 @@ VectorRef CBaseEntity::__API_HOOK(FireBullets3)(VectorRef vecSrc, VectorRef vecD
float flDamageModifier = 0.5;
int iStartPenetration = iPenetration;
while (iPenetration != 0)
{
ClearMultiDamage();
@ -1400,9 +1421,11 @@ VectorRef CBaseEntity::__API_HOOK(FireBullets3)(VectorRef vecSrc, VectorRef vecD
default:
break;
}
if (tr.flFraction != 1.0f)
{
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
int iPenetrationCur = iPenetration;
iPenetration--;
flCurrentDistance = tr.flFraction * flDistance;
@ -1426,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;
}
@ -1459,6 +1486,7 @@ VectorRef CBaseEntity::__API_HOOK(FireBullets3)(VectorRef vecSrc, VectorRef vecD
flDistance = (flDistance - flCurrentDistance) * flDistanceModifier;
vecEnd = vecSrc + (vecDir * flDistance);
pEntity->SetDmgPenetrationLevel(iStartPenetration - iPenetrationCur);
pEntity->TraceAttack(pevAttacker, iCurrentDamage, vecDir, &tr, (DMG_BULLET | DMG_NEVERGIB));
iCurrentDamage *= flDamageModifier;
}
@ -1570,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<CBasePlayerItem *>(pEntity);
if (pItem)
{
CBasePlayer *pOwner = GET_PRIVATE<CBasePlayer>(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

@ -242,8 +242,16 @@ public:
void SetBlocked(void (T::*pfn)(CBaseEntity *pOther));
void SetBlocked(std::nullptr_t);
void SetDmgPenetrationLevel(int iPenetrationLevel);
void ResetDmgPenetrationLevel();
int GetDmgPenetrationLevel() const;
void KilledInflicted(entvars_t *pevInflictor, entvars_t *pevAttacker, int iGib);
entvars_t *GetLastInflictor();
#ifdef REGAMEDLL_API
CCSEntity *m_pEntity;
CCSEntity *CSEntity() const;
#else
// We use this variables to store each ammo count.
// let's sacrifice this unused member, for its own needs in favor of m_pEntity
@ -328,6 +336,26 @@ inline void CBaseEntity::SetBlocked(std::nullptr_t)
m_pfnBlocked = nullptr;
}
#ifdef REGAMEDLL_API
inline CCSEntity *CBaseEntity::CSEntity() const
{
return m_pEntity;
}
#else // !REGAMEDLL_API
extern entvars_t *g_pevLastInflictor;
inline void CBaseEntity::SetDmgPenetrationLevel(int iPenetrationLevel) {}
inline void CBaseEntity::ResetDmgPenetrationLevel() {}
inline int CBaseEntity::GetDmgPenetrationLevel() const { return 0; }
inline entvars_t *CBaseEntity::GetLastInflictor() { return g_pevLastInflictor; }
inline void CBaseEntity::KilledInflicted(entvars_t *pevInflictor, entvars_t *pevAttacker, int iGib)
{
g_pevLastInflictor = pevInflictor;
Killed(pevAttacker, iGib);
g_pevLastInflictor = nullptr;
}
#endif // !REGAMEDLL_API
class CPointEntity: public CBaseEntity {
public:
virtual void Spawn();
@ -369,6 +397,7 @@ public:
float SetBoneController(int iController, float flValue = 0.0f);
void InitBoneControllers();
float GetSequenceDuration() const;
float SetBlending(int iBlender, float flValue);
void GetBonePosition(int iBone, Vector &origin, Vector &angles);
void GetAutomovement(Vector &origin, Vector &angles, float flInterval = 0.1f);

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

@ -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];
@ -249,7 +250,7 @@ void WriteSigonMessages()
#ifdef PLAY_GAMEDLL
// TODO: fix test demo
iFlags &= ~ITEM_FLAG_NOFIREUNDERWATER;
iFlags &= ~ITEM_FLAG_CUSTOM;
#endif
MESSAGE_BEGIN(MSG_INIT, gmsgWeaponList);
@ -438,6 +439,9 @@ NOXREF int CountTeams()
if (FNullEnt(pEntity->edict()))
break;
if (pEntity->IsDormant())
continue;
CBasePlayer *pPlayer = GetClassPtr<CCSPlayer>((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<CCSPlayer>((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<CCSPlayer>((CBasePlayer *)pEntity->pev)->m_iTeam == iTeam)
CBasePlayer *pPlayer = GetClassPtr<CCSPlayer>((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<CCSPlayer>((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<CCSPlayer>((CBasePlayer *)pTempEntity->pev);
if (!pTempPlayer || pTempPlayer->m_iTeam == UNASSIGNED)
@ -621,6 +627,9 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity)
return;
}
#ifdef REGAMEDLL_FIXES
pPlayer->m_bHasDefuser = false;
#endif
pPlayer->m_bNotKilled = true;
pPlayer->m_iIgnoreGlobalChat = IGNOREMSG_NONE;
pPlayer->m_iTeamKills = 0;
@ -670,10 +679,12 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity)
CBaseEntity *pTarget = nullptr;
pPlayer->m_pIntroCamera = UTIL_FindEntityByClassname(nullptr, "trigger_camera");
#ifndef REGAMEDLL_FIXES
if (g_pGameRules && g_pGameRules->IsMultiplayer())
{
CSGameRules()->m_bMapHasCameras = (pPlayer->m_pIntroCamera != nullptr);
}
#endif
if (pPlayer->m_pIntroCamera)
{
@ -691,7 +702,12 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity)
pPlayer->pev->angles = CamAngles;
pPlayer->pev->v_angle = pPlayer->pev->angles;
pPlayer->m_fIntroCamTime = gpGlobals->time + 6;
pPlayer->m_fIntroCamTime =
#ifdef REGAMEDLL_FIXES
(CSGameRules()->m_bMapHasCameras <= 1) ? 0.0 : // no need to refresh cameras if map has only one
#endif
gpGlobals->time + 6;
pPlayer->pev->view_ofs = g_vecZero;
}
#ifndef REGAMEDLL_FIXES
@ -717,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++)
{
@ -727,7 +743,7 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity)
}
#ifdef REGAMEDLL_API
pPlayer->CSPlayer()->ResetVars();
pPlayer->CSPlayer()->OnConnect();
#endif
UTIL_ClientPrintAll(HUD_PRINTNOTIFY, "#Game_connected", (sName[0] != '\0') ? sName : "<unconnected>");
@ -776,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;
@ -795,7 +811,9 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
if (*p == '"')
{
p++;
p[Q_strlen(p) - 1] = '\0';
size_t len = Q_strlen(p);
if (len > 0)
p[len - 1] = '\0';
}
// Check if buffer contains an invalid unicode sequence
@ -819,14 +837,24 @@ 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;
#ifdef REGAMEDLL_ADD
// there's no team on FFA mode
if (teamonly && CSGameRules()->IsFreeForAll() && (pPlayer->m_iTeam == CT || pPlayer->m_iTeam == TERRORIST))
teamonly = FALSE;
#endif
// team only
if (teamonly)
{
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);
@ -840,8 +868,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)
@ -851,7 +888,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;
}
@ -870,7 +907,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;
}
@ -933,8 +970,8 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
}
}
Q_strcat(text, p);
Q_strcat(text, "\n");
Q_strlcat(text, p);
Q_strlcat(text, "\n");
// loop through all players
// Start with the first player.
@ -953,6 +990,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;
@ -961,7 +1001,13 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
if (gpGlobals->deathmatch != 0.0f && CSGameRules()->m_VoiceGameMgr.PlayerHasBlockedPlayer(pReceiver, pPlayer))
continue;
if (teamonly && pReceiver->m_iTeam != pPlayer->m_iTeam)
if (teamonly
#ifdef REGAMEDLL_FIXES
&& CSGameRules()->PlayerRelationship(pPlayer, pReceiver) != GR_TEAMMATE
#else
&& pReceiver->m_iTeam != pPlayer->m_iTeam
#endif
)
continue;
if (
@ -974,7 +1020,13 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
continue;
}
if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY && pReceiver->m_iTeam == pPlayer->m_iTeam)
if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY
#ifdef REGAMEDLL_FIXES
&& CSGameRules()->PlayerRelationship(pPlayer, pReceiver) == GR_TEAMMATE
#else
&& pReceiver->m_iTeam == pPlayer->m_iTeam
#endif
)
|| pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_NONE)
{
MESSAGE_BEGIN(MSG_ONE, gmsgSayText, nullptr, pReceiver->pev);
@ -1194,7 +1246,9 @@ void BuyMachineGun(CBasePlayer *pPlayer, int iSlot)
BuyWeaponByWeaponID(pPlayer, WEAPON_M249);
}
void BuyItem(CBasePlayer *pPlayer, int iSlot)
LINK_HOOK_VOID_CHAIN(BuyItem, (CBasePlayer *pPlayer, int iSlot), pPlayer, iSlot)
void EXT_FUNC __API_HOOK(BuyItem)(CBasePlayer *pPlayer, int iSlot)
{
int iItemPrice = 0;
const char *pszItem = nullptr;
@ -1435,28 +1489,13 @@ void BuyItem(CBasePlayer *pPlayer, int iSlot)
if (pPlayer->m_iAccount >= DEFUSEKIT_PRICE)
{
bEnoughMoney = true;
pPlayer->m_bHasDefuser = true;
MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pPlayer->pev);
WRITE_BYTE(STATUSICON_SHOW);
WRITE_STRING("defuser");
WRITE_BYTE(0);
WRITE_BYTE(160);
WRITE_BYTE(0);
MESSAGE_END();
pPlayer->pev->body = 1;
pPlayer->GiveDefuser();
pPlayer->AddAccount(-DEFUSEKIT_PRICE, RT_PLAYER_BOUGHT_SOMETHING);
#ifdef REGAMEDLL_FIXES
EMIT_SOUND(ENT(pPlayer->pev), CHAN_VOICE, "items/kevlar.wav", VOL_NORM, ATTN_NORM);
#else
EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/kevlar.wav", VOL_NORM, ATTN_NORM);
#endif
pPlayer->SendItemStatus();
#ifdef BUILD_LATEST
pPlayer->SetScoreboardAttributes();
#endif
}
break;
@ -1474,7 +1513,6 @@ void BuyItem(CBasePlayer *pPlayer, int iSlot)
if (pPlayer->m_iAccount >= SHIELDGUN_PRICE)
{
bEnoughMoney = true;
pPlayer->DropPrimary();
pPlayer->GiveShield();
pPlayer->AddAccount(-SHIELDGUN_PRICE, RT_PLAYER_BOUGHT_SOMETHING);
@ -1911,7 +1949,7 @@ BOOL EXT_FUNC __API_HOOK(HandleMenu_ChooseTeam)(CBasePlayer *pPlayer, int slot)
MESSAGE_END();
#endif
// do we have fadetoblack on? (need to fade their screen back in)
if (fadetoblack.value)
if (fadetoblack.value == FADETOBLACK_STAY)
{
UTIL_ScreenFade(pPlayer, Vector(0, 0, 0), 0.001, 0, 0, FFADE_IN);
}
@ -2262,7 +2300,7 @@ bool EXT_FUNC __API_HOOK(BuyGunAmmo)(CBasePlayer *pPlayer, CBasePlayerItem *weap
if (pPlayer->m_iAccount >= info->clipCost)
{
#ifdef REGAMEDLL_FIXES
if (pPlayer->GiveAmmo(info->buyClipSize, info->ammoName2, weapon->iMaxAmmo1()) == -1)
if (pPlayer->GiveAmmo(info->buyClipSize, weapon->pszAmmo1(), weapon->iMaxAmmo1()) == -1)
return false;
EMIT_SOUND(ENT(weapon->pev), CHAN_ITEM, "items/9mmclip1.wav", VOL_NORM, ATTN_NORM);
@ -2334,6 +2372,9 @@ CBaseEntity *EntityFromUserID(int userID)
if (FNullEnt(pTempEntity->edict()))
break;
if (pTempEntity->IsDormant())
continue;
CBasePlayer *pTempPlayer = GetClassPtr<CCSPlayer>((CBasePlayer *)pTempEntity->pev);
if (pTempPlayer->m_iTeam != UNASSIGNED && userID == GETPLAYERUSERID(pTempEntity->edict()))
@ -2354,6 +2395,9 @@ NOXREF int CountPlayersInServer()
if (FNullEnt(pTempEntity->edict()))
break;
if (pTempEntity->IsDormant())
continue;
CBasePlayer *pTempPlayer = GetClassPtr<CCSPlayer>((CBasePlayer *)pTempEntity->pev);
if (pTempPlayer->m_iTeam != UNASSIGNED)
@ -2599,6 +2643,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)
@ -2680,11 +2733,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;
@ -3253,6 +3315,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 <num>
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<CCSPlayer>((CBasePlayer *)pev), pcmd))
@ -3334,7 +3416,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);
@ -3359,7 +3445,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);
@ -3673,6 +3763,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;
@ -4207,7 +4313,7 @@ void ClientPrecache()
PRECACHE_GENERIC("sprites/scope_arc_ne.tga");
PRECACHE_GENERIC("sprites/scope_arc_sw.tga");
m_usResetDecals = g_engfuncs.pfnPrecacheEvent(1, "events/decal_reset.sc");
m_usResetDecals = PRECACHE_EVENT(1, "events/decal_reset.sc");
}
const char *EXT_FUNC GetGameDescription()
@ -4483,7 +4589,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) {
@ -4491,7 +4597,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;
@ -4517,8 +4629,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)
@ -4817,6 +4943,16 @@ int EXT_FUNC GetWeaponData(edict_t *pEdict, struct weapon_data_s *info)
item->fuser2 = weapon->m_flStartThrow;
item->fuser3 = weapon->m_flReleaseThrow;
item->iuser1 = weapon->m_iSwing;
#ifdef REGAMEDLL_FIXES
if (pPlayerItem == pPlayer->m_pActiveItem && !weapon->m_fInReload && weapon->m_iClip == II.iMaxClip)
{
const WeaponInfoStruct *wpnInfo = GetDefaultWeaponInfo(II.iId);
if (wpnInfo && wpnInfo->gunClipSize != II.iMaxClip)
item->m_iClip = wpnInfo->gunClipSize;
}
#endif
}
}
@ -4849,7 +4985,12 @@ void EXT_FUNC UpdateClientData(const edict_t *ent, int sendweapons, struct clien
}
cd->flags = pev->flags;
#ifdef REGAMEDLL_FIXES
cd->health = max(pev->health, 0.0f);
#else
cd->health = pev->health;
#endif
cd->viewmodel = MODEL_INDEX(STRING(pev->viewmodel));
cd->waterlevel = pev->waterlevel;
cd->watertype = pev->watertype;
@ -4864,7 +5005,7 @@ void EXT_FUNC UpdateClientData(const edict_t *ent, int sendweapons, struct clien
cd->flSwimTime = pev->flSwimTime;
cd->waterjumptime = int(pev->teleport_time);
Q_strcpy(cd->physinfo, ENGINE_GETPHYSINFO(ent));
Q_strlcpy(cd->physinfo, ENGINE_GETPHYSINFO(ent));
cd->maxspeed = pev->maxspeed;
cd->fov = pev->fov;
@ -5075,8 +5216,10 @@ int EXT_FUNC InconsistentFile(const edict_t *pEdict, const char *filename, char
if (!CVAR_GET_FLOAT("mp_consistency"))
return 0;
const int BufferLen = 256;
// Default behavior is to kick the player
Q_sprintf(disconnect_message, "Server is enforcing file consistency for %s\n", filename);
Q_snprintf(disconnect_message, BufferLen, "Server is enforcing file consistency for %s\n", filename);
// Kick now with specified disconnect message.
return 1;

@ -112,6 +112,7 @@ extern unsigned short g_iShadowSprite;
void HandleMenu_ChooseAppearance_OrigFunc(CBasePlayer *pPlayer, int slot);
BOOL HandleMenu_ChooseTeam_OrigFunc(CBasePlayer *pPlayer, int slot);
bool BuyGunAmmo_OrigFunc(CBasePlayer *pPlayer, CBasePlayerItem *weapon, bool bBlinkMoney);
void BuyItem_OrigFunc(CBasePlayer *pPlayer, int iSlot);
CBaseEntity *BuyWeaponByWeaponID_OrigFunc(CBasePlayer *pPlayer, WeaponIdType weaponID);
void ShowMenu_OrigFunc(CBasePlayer *pPlayer, int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText);
void ShowVGUIMenu_OrigFunc(CBasePlayer *pPlayer, int MenuType, int BitMask, char *szOldMenu);

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

@ -4,24 +4,39 @@ void PlayerBlind(CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAt
{
UTIL_ScreenFade(pPlayer, color, fadeTime, fadeHold, alpha, 0);
if (!fadetoblack.value)
if (fadetoblack.value != FADETOBLACK_STAY)
{
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);
}
}
}
pPlayer->Blind(fadeTime * 0.33, fadeHold, fadeTime, alpha);
float flDurationTime = fadeTime * 0.33;
pPlayer->Blind(flDurationTime, fadeHold, fadeTime, alpha);
if (TheBots)
{
TheBots->OnEvent(EVENT_PLAYER_BLINDED_BY_FLASHBANG, pPlayer);
}
#if defined(REGAMEDLL_API) && defined(REGAMEDLL_ADD)
float flAdjustedDamage;
if (alpha > 200)
flAdjustedDamage = fadeTime / 3;
else
flAdjustedDamage = fadeTime / 1.75;
pPlayer->CSPlayer()->RecordDamage(CBasePlayer::Instance(pevAttacker), flAdjustedDamage * 16.0f, flDurationTime);
#endif
}
void RadiusFlash_TraceLine_hook(CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAttacker, Vector &vecSrc, Vector &vecSpot, TraceResult *tr)
@ -90,6 +105,19 @@ void RadiusFlash(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker,
if (tr2.flFraction >= 1.0)
{
#ifdef REGAMEDLL_ADD
switch ((int)teamflash.value)
{
case 0:
if (pPlayer->pev != pevAttacker && g_pGameRules->PlayerRelationship(pPlayer, CBaseEntity::Instance(pevAttacker)) == GR_TEAMMATE)
continue;
break;
case -1:
if (pPlayer->pev == pevAttacker || g_pGameRules->PlayerRelationship(pPlayer, CBaseEntity::Instance(pevAttacker)) == GR_TEAMMATE)
continue;
break;
}
#endif
if (tr.fStartSolid)
{
tr.vecEndPos = vecSrc;
@ -97,7 +125,6 @@ void RadiusFlash(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker,
}
flAdjustedDamage = flDamage - (vecSrc - tr.vecEndPos).Length() * falloff;
if (flAdjustedDamage < 0)
flAdjustedDamage = 0;
@ -258,8 +285,6 @@ void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker
damageRatio = GetAmountOfPlayerVisible(vecSrc, pEntity);
}
damageRatio = GetAmountOfPlayerVisible(vecSrc, pEntity);
float length;
#ifdef REGAMEDLL_ADD
// allow to damage breakable objects
@ -290,6 +315,8 @@ void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker
if (tr.flFraction != 1.0f)
flAdjustedDamage = 0.0f;
else
pEntity->SetDmgPenetrationLevel(1);
}
#endif
}

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

@ -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),
@ -215,7 +222,7 @@ void CBaseDoor::Spawn()
// Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big
m_vecPosition2 = m_vecPosition1 + (pev->movedir * (Q_fabs(real_t(pev->movedir.x * (pev->size.x - 2))) + Q_fabs(real_t(pev->movedir.y * (pev->size.y - 2))) + Q_fabs(real_t(pev->movedir.z * (pev->size.z - 2))) - m_flLip));
assert(("door start/end positions are equal", m_vecPosition1 != m_vecPosition2));
DbgAssertMsg(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal");
if (pev->spawnflags & SF_DOOR_START_OPEN)
{
@ -494,7 +501,7 @@ void CBaseDoor::DoorGoUp()
bool isReversing = (m_toggle_state == TS_GOING_DOWN);
// It could be going-down, if blocked.
assert(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN);
DbgAssert(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN);
// emit door moving and stop sounds on CHAN_STATIC so that the multicast doesn't
// filter them out and leave a client stuck with looping door sounds!
@ -634,7 +641,7 @@ void CBaseDoor::DoorHitTop()
EMIT_SOUND(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseArrived), VOL_NORM, ATTN_NORM);
}
assert(m_toggle_state == TS_GOING_UP);
DbgAssert(m_toggle_state == TS_GOING_UP);
m_toggle_state = TS_AT_TOP;
// toggle-doors don't come down automatically, they wait for refire.
@ -695,10 +702,7 @@ void CBaseDoor::DoorGoDown()
}
}
#ifdef DOOR_ASSERT
assert(m_toggle_state == TS_AT_TOP);
#endif
DbgAssert(m_toggle_state == TS_AT_TOP);
m_toggle_state = TS_GOING_DOWN;
SetMoveDone(&CBaseDoor::DoorHitBottom);
@ -724,7 +728,7 @@ void CBaseDoor::DoorHitBottom()
EMIT_SOUND(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseArrived), VOL_NORM, ATTN_NORM);
}
assert(m_toggle_state == TS_GOING_DOWN);
DbgAssert(m_toggle_state == TS_GOING_DOWN);
m_toggle_state = TS_AT_BOTTOM;
// Re-instate touch method, cycle is complete
@ -927,7 +931,7 @@ void CRotDoor::Spawn()
m_vecAngle1 = pev->angles;
m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance;
assert(("rotating door start/end positions are equal", m_vecAngle1 != m_vecAngle2));
DbgAssertMsg(m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal");
if (pev->spawnflags & SF_DOOR_PASSABLE)
pev->solid = SOLID_NOT;
@ -1011,7 +1015,7 @@ void CMomentaryDoor::Spawn()
// Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big
m_vecPosition2 = m_vecPosition1 + (pev->movedir * (Q_fabs(real_t(pev->movedir.x * (pev->size.x - 2))) + Q_fabs(real_t(pev->movedir.y * (pev->size.y - 2))) + Q_fabs(real_t(pev->movedir.z * (pev->size.z - 2))) - m_flLip));
assert(("door start/end positions are equal", m_vecPosition1 != m_vecPosition2));
DbgAssertMsg(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal");
if (pev->spawnflags & SF_DOOR_START_OPEN)
{

@ -130,6 +130,10 @@ inline edict_t *EntityHandle<T>::Set(edict_t *pEdict)
{
m_serialnumber = pEdict->serialnumber;
}
else
{
m_serialnumber = 0;
}
return pEdict;
}
@ -176,7 +180,7 @@ inline int EntityHandle<T>::GetSerialNumber() const
template <typename T>
inline bool EntityHandle<T>::operator==(T *pEntity) const
{
assert(("EntityHandle<T>::operator==: got a nullptr pointer!", pEntity != nullptr));
DbgAssertMsg(pEntity != nullptr, "EntityHandle<T>::operator==: got a nullptr pointer!");
if (m_serialnumber != pEntity->edict()->serialnumber)
{
@ -221,10 +225,10 @@ template <typename T>
inline T *EntityHandle<T>::operator->()
{
edict_t *pEdict = Get();
assert(("EntityHandle<T>::operator->: pointer is nullptr!", pEdict != nullptr));
DbgAssertMsg(pEdict != nullptr, "EntityHandle<T>::operator->: pointer is nullptr!");
T *pEntity = GET_PRIVATE<T>(pEdict);
assert(("EntityHandle<T>::operator->: pvPrivateData is nullptr!", pEntity != nullptr));
DbgAssertMsg(pEntity != nullptr, "EntityHandle<T>::operator->: pvPrivateData is nullptr!");
return pEntity;
}

@ -201,7 +201,7 @@ void ExplosionCreate(const Vector &center, 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;

@ -297,12 +297,12 @@ void CFuncTank::StopControl()
void CFuncTank::ControllerPostFrame()
{
assert(m_pController != nullptr);
if (gpGlobals->time < m_flNextAttack)
return;
if (m_pController->pev->button & IN_ATTACK)
Assert(m_pController != nullptr);
if (m_pController && m_pController->pev->button & IN_ATTACK)
{
Vector vecForward;
UTIL_MakeVectorsPrivate(pev->angles, vecForward, nullptr, nullptr);
@ -879,7 +879,7 @@ void CFuncTankControls::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T
}
// if this fails, most likely means save/restore hasn't worked properly
assert(m_pTank != nullptr);
DbgAssert(m_pTank != nullptr);
}
void CFuncTankControls::Think()

@ -9,6 +9,7 @@ cvar_t *g_psv_friction = nullptr;
cvar_t *g_psv_stopspeed = nullptr;
cvar_t *g_psv_stepsize = nullptr;
cvar_t *g_psv_clienttrace = nullptr;
cvar_t *g_psv_maxvelocity = nullptr;
cvar_t displaysoundlist = { "displaysoundlist", "0", 0, 0.0f, nullptr };
cvar_t timelimit = { "mp_timelimit", "0", FCVAR_SERVER, 0.0f, nullptr };
@ -159,16 +160,46 @@ cvar_t t_default_grenades = { "mp_t_default_grenades", "", 0, 0.0
cvar_t t_give_player_knife = { "mp_t_give_player_knife", "1", 0, 1.0f, nullptr };
cvar_t t_default_weapons_secondary = { "mp_t_default_weapons_secondary", "glock18", 0, 0.0f, nullptr };
cvar_t t_default_weapons_primary = { "mp_t_default_weapons_primary", "", 0, 0.0f, nullptr };
cvar_t default_weapons_random = { "mp_default_weapons_random", "", 0, 0.0f, nullptr };
cvar_t free_armor = { "mp_free_armor", "0", 0, 0.0f, nullptr };
cvar_t teamflash = { "mp_team_flash", "1", 0, 1.0f, nullptr };
cvar_t allchat = { "sv_allchat", "0", 0, 0.0f, nullptr };
cvar_t sv_autobunnyhopping = { "sv_autobunnyhopping", "0", 0, 0.0f, nullptr };
cvar_t sv_enablebunnyhopping = { "sv_enablebunnyhopping", "0", 0, 0.0f, nullptr };
cvar_t plant_c4_anywhere = { "mp_plant_c4_anywhere", "0", 0, 0.0f, nullptr };
cvar_t give_c4_frags = { "mp_give_c4_frags", "3", 0, 3.0f, nullptr };
cvar_t deathmsg_flags = { "mp_deathmsg_flags", "abc", 0, 0.0f, nullptr };
cvar_t assist_damage_threshold = { "mp_assist_damage_threshold", "40", 0, 40.0f, nullptr };
cvar_t freezetime_duck = { "mp_freezetime_duck", "1", 0, 1.0f, nullptr };
cvar_t freezetime_jump = { "mp_freezetime_jump", "1", 0, 1.0f, nullptr };
cvar_t jump_height = { "mp_jump_height", "45", FCVAR_SERVER, 45.0f, nullptr };
cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr };
cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr };
cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr };
cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr };
cvar_t dying_time = { "mp_dying_time", "3.0", 0, 3.0f, nullptr };
cvar_t defuser_allocation = { "mp_defuser_allocation", "0", 0, 0.0f, nullptr };
cvar_t location_area_info = { "mp_location_area_info", "0", 0, 0.0f, nullptr };
cvar_t chat_loc_fallback = { "mp_chat_loc_fallback", "1", 0, 1.0f, nullptr };
cvar_t item_respawn_time = { "mp_item_respawn_time", "30", FCVAR_SERVER, 30.0f, nullptr };
cvar_t weapon_respawn_time = { "mp_weapon_respawn_time", "20", FCVAR_SERVER, 20.0f, nullptr };
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 };
cvar_t flymove_method = { "mp_flymove_method", "0", 0, 0.0f, nullptr };
cvar_t stamina_restore_rate = { "mp_stamina_restore_rate", "0", 0, 0.f, nullptr };
cvar_t logkills = { "mp_logkills", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t randomspawn = { "mp_randomspawn", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t playerid_showhealth = { "mp_playerid_showhealth", "1", 0, 1.0f, nullptr };
cvar_t playerid_field = { "mp_playerid_field", "3", 0, 3.0f, nullptr };
cvar_t knockback = { "mp_knockback", "170", 0, 170.0f, nullptr };
void GameDLL_Version_f()
{
@ -220,8 +251,13 @@ void GameDLL_SwapTeams_f()
#endif // REGAMEDLL_ADD
SpewRetval_t GameDLL_SpewHandler(SpewType_t spewType, int level, const char *pMsg);
void EXT_FUNC GameDLLInit()
{
// By default, direct dbg reporting...
SpewOutputFunc(GameDLL_SpewHandler);
g_pskill = CVAR_GET_POINTER("skill");
g_psv_gravity = CVAR_GET_POINTER("sv_gravity");
g_psv_aim = CVAR_GET_POINTER("sv_aim");
@ -231,6 +267,7 @@ void EXT_FUNC GameDLLInit()
g_psv_stopspeed = CVAR_GET_POINTER("sv_stopspeed");
g_psv_stepsize = CVAR_GET_POINTER("sv_stepsize");
g_psv_clienttrace = CVAR_GET_POINTER("sv_clienttrace");
g_psv_maxvelocity = CVAR_GET_POINTER("sv_maxvelocity");
CVAR_REGISTER(&displaysoundlist);
CVAR_REGISTER(&timelimit);
@ -407,7 +444,9 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&t_give_player_knife);
CVAR_REGISTER(&t_default_weapons_secondary);
CVAR_REGISTER(&t_default_weapons_primary);
CVAR_REGISTER(&default_weapons_random);
CVAR_REGISTER(&free_armor);
CVAR_REGISTER(&teamflash);
CVAR_REGISTER(&allchat);
CVAR_REGISTER(&sv_autobunnyhopping);
CVAR_REGISTER(&sv_enablebunnyhopping);
@ -418,11 +457,49 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&legacy_vehicle_block);
CVAR_REGISTER(&dying_time);
CVAR_REGISTER(&deathmsg_flags);
CVAR_REGISTER(&assist_damage_threshold);
CVAR_REGISTER(&freezetime_duck);
CVAR_REGISTER(&freezetime_jump);
CVAR_REGISTER(&jump_height);
CVAR_REGISTER(&defuser_allocation);
CVAR_REGISTER(&location_area_info);
CVAR_REGISTER(&chat_loc_fallback);
CVAR_REGISTER(&item_respawn_time);
CVAR_REGISTER(&weapon_respawn_time);
CVAR_REGISTER(&ammo_respawn_time);
CVAR_REGISTER(&vote_flags);
CVAR_REGISTER(&votemap_min_time);
CVAR_REGISTER(&randomspawn);
CVAR_REGISTER(&cv_bot_enable);
CVAR_REGISTER(&cv_hostage_ai_enable);
CVAR_REGISTER(&logkills);
CVAR_REGISTER(&playerid_showhealth);
CVAR_REGISTER(&playerid_field);
CVAR_REGISTER(&stamina_restore_rate);
CVAR_REGISTER(&flymove_method);
CVAR_REGISTER(&knockback);
// print version
CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n");
// execute initial pre-configurations
SERVER_COMMAND("exec game_init.cfg\n");
SERVER_EXECUTE();
#endif // REGAMEDLL_ADD
Regamedll_Game_Init();
Bot_RegisterCVars();
Tutor_RegisterCVars();
Hostage_RegisterCVars();
@ -431,10 +508,29 @@ void EXT_FUNC GameDLLInit()
VoiceGameMgr_RegisterCVars();
#endif
#ifdef REGAMEDLL_ADD
// execute initial pre-configurations
SERVER_COMMAND("exec game_init.cfg\n");
SERVER_EXECUTE();
#endif
}
SpewRetval_t GameDLL_SpewHandler(SpewType_t spewType, int level, const char *pMsg)
{
bool bSpewPrint = (CVAR_GET_FLOAT("developer") >= level);
switch (spewType)
{
case SPEW_LOG:
case SPEW_MESSAGE:
if (bSpewPrint) UTIL_ServerPrint("%s", pMsg);
break;
case SPEW_WARNING:
if (bSpewPrint) UTIL_ServerPrint("Warning: %s", pMsg);
break;
case SPEW_ERROR:
Sys_Error("%s", pMsg);
return SPEW_ABORT; // fatal error, terminate it!
case SPEW_ASSERT:
UTIL_ServerPrint("Assert: %s", pMsg);
return SPEW_DEBUGGER; // assert always tries to debugger break
default:
break;
}
return SPEW_CONTINUE; // spew handled, continue on
}

@ -43,12 +43,13 @@
extern cvar_t *g_pskill;
extern cvar_t *g_psv_gravity;
extern cvar_t *g_psv_aim;
extern cvar_t *g_footsteps;
extern cvar_t *g_psv_accelerate;
extern cvar_t *g_psv_friction;
extern cvar_t *g_psv_stopspeed;
extern cvar_t *g_psv_stepsize;
extern cvar_t *g_psv_clienttrace;
extern cvar_t *g_footsteps;
extern cvar_t *g_psv_maxvelocity;
extern cvar_t displaysoundlist;
extern cvar_t timelimit;
@ -185,19 +186,44 @@ extern cvar_t t_default_grenades;
extern cvar_t t_give_player_knife;
extern cvar_t t_default_weapons_secondary;
extern cvar_t t_default_weapons_primary;
extern cvar_t default_weapons_random;
extern cvar_t free_armor;
extern cvar_t teamflash;
extern cvar_t allchat;
extern cvar_t sv_autobunnyhopping;
extern cvar_t sv_enablebunnyhopping;
extern cvar_t plant_c4_anywhere;
extern cvar_t give_c4_frags;
extern cvar_t hostages_rescued_ratio;
extern cvar_t legacy_vehicle_block;
extern cvar_t dying_time;
extern cvar_t deathmsg_flags;
extern cvar_t assist_damage_threshold;
extern cvar_t freezetime_duck;
extern cvar_t freezetime_jump;
extern cvar_t jump_height;
extern cvar_t defuser_allocation;
extern cvar_t location_area_info;
extern cvar_t chat_loc_fallback;
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;
extern cvar_t flymove_method;
extern cvar_t stamina_restore_rate;
extern cvar_t logkills;
extern cvar_t randomspawn;
extern cvar_t playerid_showhealth;
extern cvar_t playerid_field;
extern cvar_t knockback;
#endif
extern cvar_t scoreboard_showmoney;
extern cvar_t scoreboard_showhealth;
extern cvar_t scoreboard_showdefkit;
void GameDLLInit();

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

@ -31,27 +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_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 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 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
{
@ -206,7 +208,7 @@ enum
SCENARIO_BLOCK_PRISON_ESCAPE_TIME = BIT(8), // flag "i"
SCENARIO_BLOCK_BOMB_TIME = BIT(9), // flag "j"
SCENARIO_BLOCK_HOSTAGE_RESCUE_TIME = BIT(10), // flag "k"
};
// Player relationship return codes
@ -219,6 +221,49 @@ enum
GR_NEUTRAL,
};
// The number of times you must kill a given player to be dominating them
// Should always be more than 1
const int CS_KILLS_FOR_DOMINATION = 4;
// Flags for specifying extra info about player death
enum DeathMessageFlags
{
// float[3]
// Position where the victim was killed by the enemy
PLAYERDEATH_POSITION = 0x001,
// byte
// Index of the assistant who helped the attacker kill the victim
PLAYERDEATH_ASSISTANT = 0x002,
// short
// Bitsum classification for the rarity of the kill
// See enum KillRarity for details
PLAYERDEATH_KILLRARITY = 0x004
};
// Classifying various player kill methods in the game
enum KillRarity
{
KILLRARITY_HEADSHOT = 0x001, // Headshot
KILLRARITY_KILLER_BLIND = 0x002, // Killer was blind
KILLRARITY_NOSCOPE = 0x004, // No-scope sniper rifle kill
KILLRARITY_PENETRATED = 0x008, // Penetrated kill (through walls)
KILLRARITY_THRUSMOKE = 0x010, // Smoke grenade penetration kill (bullets went through smoke)
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_INAIR = 0x200 // Killer was in the air (skill to deal with high inaccuracy)
};
enum
{
DEFUSERALLOCATION_NONE = 0,
DEFUSERALLOCATION_RANDOM = 1,
DEFUSERALLOCATION_ALL = 2,
};
class CItem;
class CGameRules
@ -336,6 +381,8 @@ public:
inline void SetGameOver() { m_bGameOver = true; }
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
@ -541,7 +588,7 @@ public:
// check if the scenario has been won/lost
virtual void CheckWinConditions();
virtual void RemoveGuns();
virtual void GiveC4();
virtual CBasePlayer *GiveC4();
virtual void ChangeLevel();
virtual void GoToIntermission();
@ -564,10 +611,15 @@ public:
void RestartRound_OrigFunc();
void CheckWinConditions_OrigFunc();
void RemoveGuns_OrigFunc();
void GiveC4_OrigFunc();
CBasePlayer *GiveC4_OrigFunc();
void ChangeLevel_OrigFunc();
void GoToIntermission_OrigFunc();
void BalanceTeams_OrigFunc();
void Think_OrigFunc();
BOOL TeamFull_OrigFunc(int team_id);
BOOL TeamStacked_OrigFunc(int newTeam_id, int curTeam_id);
void PlayerGotWeapon_OrigFunc(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon);
void SendDeathMessage_OrigFunc(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, entvars_t *pevInflictor, const char *killerWeaponName, int iDeathMessageFlags, int iRarityOfKill);
#endif
public:
@ -692,6 +744,12 @@ public:
VFUNC bool HasRoundTimeExpired();
VFUNC bool IsBombPlanted();
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);
void GiveDefuserToRandomPlayer();
private:
void MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound(int iTeam);
@ -733,7 +791,7 @@ public:
bool m_bMapHasEscapeZone;
BOOL m_bMapHasVIPSafetyZone; // TRUE = has VIP safety zone, FALSE = does not have VIP safetyzone
BOOL m_bMapHasCameras;
int m_bMapHasCameras;
int m_iC4Timer;
int m_iC4Guy; // The current Terrorist who has the C4.
int m_iLoserBonus; // the amount of money the losing team gets. This scales up as they lose more rounds in a row
@ -921,6 +979,24 @@ inline float CGameRules::GetRadioTimeout()
#endif
}
inline float CGameRules::GetDyingTime()
{
#ifdef REGAMEDLL_ADD
return dying_time.value;
#else
return DEATH_ANIMATION_TIME;
#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();
@ -933,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();

@ -600,9 +600,15 @@ void CGrenade::__API_HOOK(SG_Detonate)()
}
m_bDetonated = true;
PLAYBACK_EVENT_FULL(0, nullptr, m_usEvent, 0, pev->origin, (float *)&g_vecZero, 0, 0, 0, 1, m_bLightSmoke, FALSE);
m_vSmokeDetonate = pev->origin;
int flags = 0;
#ifdef REGAMEDLL_FIXES
flags = FEV_RELIABLE;
#endif
PLAYBACK_EVENT_FULL(flags, nullptr, m_usEvent, 0, m_vSmokeDetonate, (float *)&g_vecZero, 0, 0, 0, 1, m_bLightSmoke, FALSE);
pev->velocity.x = RANDOM_FLOAT(-175, 175);
pev->velocity.y = RANDOM_FLOAT(-175, 175);
pev->velocity.z = RANDOM_FLOAT(250, 350);
@ -766,6 +772,13 @@ void CGrenade::BounceSound()
void CGrenade::TumbleThink()
{
#ifdef REGAMEDLL_FIXES
if (pev->velocity.IsLengthGreaterThan(g_psv_maxvelocity->value))
{
pev->velocity = pev->velocity.Normalize() * g_psv_maxvelocity->value;
}
#endif
if (!IsInWorld())
{
UTIL_Remove(this);
@ -803,6 +816,13 @@ void CGrenade::TumbleThink()
void CGrenade::SG_TumbleThink()
{
#ifdef REGAMEDLL_FIXES
if (pev->velocity.IsLengthGreaterThan(g_psv_maxvelocity->value))
{
pev->velocity = pev->velocity.Normalize() * g_psv_maxvelocity->value;
}
#endif
if (!IsInWorld())
{
UTIL_Remove(this);
@ -1150,6 +1170,12 @@ void CGrenade::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTy
if (!m_bIsC4)
return;
#ifdef REGAMEDLL_FIXES
// block the start of defuse if the bomb timer has expired
if (m_flC4Blow > 0 && gpGlobals->time >= m_flC4Blow)
return;
#endif
// TODO: We must be sure that the activator is a player.
CBasePlayer *pPlayer = GetClassPtr<CCSPlayer>((CBasePlayer *)pActivator->pev);
@ -1316,6 +1342,13 @@ void AnnounceFlashInterval(float interval, float offset)
void CGrenade::C4Think()
{
#ifdef REGAMEDLL_FIXES
if (pev->velocity.IsLengthGreaterThan(g_psv_maxvelocity->value))
{
pev->velocity = pev->velocity.Normalize() * g_psv_maxvelocity->value;
}
#endif
if (!IsInWorld())
{
#ifdef REGAMEDLL_FIXES
@ -1476,6 +1509,13 @@ void CGrenade::C4Think()
{
DefuseBombEnd(pPlayer, false);
}
#ifdef REGAMEDLL_FIXES
// if the bomb timer has expired and defuse is still ongoing, stop the defuse
else if (gpGlobals->time >= m_flC4Blow)
{
DefuseBombEnd(pPlayer, false);
}
#endif
}
else
{

@ -4,14 +4,14 @@ LINK_ENTITY_TO_CLASS(gib, CGib, CCSGib)
void CGib::LimitVelocity()
{
float length = pev->velocity.Length();
float topspeed = g_psv_maxvelocity->value * 0.75f;
// ceiling at 1500. The gib velocity equation is not bounded properly. Rather than tune it
// ceiling at topspeed. The gib velocity equation is not bounded properly. Rather than tune it
// in 3 separate places again, I'll just limit it here.
if (length > 1500.0)
if (pev->velocity.IsLengthGreaterThan(topspeed))
{
// This should really be sv_maxvelocity * 0.75 or something
pev->velocity = pev->velocity.Normalize() * 1500;
// DONE: This should really be sv_maxvelocity * 0.75 or something
pev->velocity = pev->velocity.Normalize() * topspeed;
}
}

@ -11,4 +11,3 @@ BOOL gDisplayTitle;
bool g_bIsBeta = false;
bool g_bIsCzeroGame = false;
bool g_bAllowedCSBot = false;
bool g_bHostageImprov = false;

@ -38,4 +38,3 @@ extern BOOL gDisplayTitle;
extern bool g_bIsBeta;
extern bool g_bIsCzeroGame;
extern bool g_bAllowedCSBot;
extern bool g_bHostageImprov;

@ -13,25 +13,9 @@ C_DLLEXPORT void WINAPI GiveFnptrsToDll(enginefuncs_t *pEnginefuncsTable, global
gpGlobals = pGlobals;
FileSystem_Init();
Regamedll_Game_Init();
}
#ifdef _WIN32
// DLL entry point
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
#else // _WIN32
#if defined(_LINUX)
void __attribute__((constructor)) DllMainLoad()
{
@ -41,4 +25,4 @@ void __attribute__((destructor)) DllMainUnload()
{
}
#endif // _WIN32
#endif // _LINUX

@ -28,6 +28,7 @@
#include "precompiled.h"
cvar_t cv_hostage_ai_enable = { "hostage_ai_enable", "0", 0, 0.0f, nullptr };
cvar_t cv_hostage_debug = { "hostage_debug", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_hostage_stop = { "hostage_stop", "0", FCVAR_SERVER, 0.0f, nullptr };
@ -268,39 +269,48 @@ void CHostage::Spawn()
void CHostage::Precache()
{
if (AreImprovAllowed())
if (cv_hostage_ai_enable.value)
{
string_t model = iStringNull;
static int which = 0;
switch (which)
{
default:
case REGULAR_GUY:
pev->model = MAKE_STRING("models/hostageA.mdl");
model = MAKE_STRING("models/hostageA.mdl");
break;
case OLD_GUY:
pev->model = MAKE_STRING("models/hostageB.mdl");
model = MAKE_STRING("models/hostageB.mdl");
break;
case BLACK_GUY:
pev->model = MAKE_STRING("models/hostageC.mdl");
model = MAKE_STRING("models/hostageC.mdl");
break;
case GOOFY_GUY:
pev->model = MAKE_STRING("models/hostageD.mdl");
break;
default:
model = MAKE_STRING("models/hostageD.mdl");
break;
}
m_whichModel = static_cast<ModelType>(which);
if (++which > 3)
which = 0;
if (++which > GOOFY_GUY)
which = REGULAR_GUY;
if (g_pFileSystem->FileExists(model))
{
pev->model = model;
}
else
{
// It seems that the model is missing, so use classic hostages
CVAR_SET_FLOAT("hostage_ai_enable", 0);
}
}
else
if (pev->model.IsNull())
{
m_whichModel = REGULAR_GUY;
if (pev->model.IsNull())
{
pev->model = MAKE_STRING("models/scientist.mdl");
}
pev->model = MAKE_STRING("models/scientist.mdl");
}
PRECACHE_MODEL(pev->model);
@ -342,7 +352,7 @@ void CHostage::IdleThink()
const float giveUpTime = (1 / 30.0f);
float const updateRate = 0.1f;
if (AreImprovAllowed() && !TheNavAreaList.empty())
if (cv_hostage_ai_enable.value && !TheNavAreaList.empty())
{
if (!m_improv)
{
@ -619,7 +629,7 @@ void CHostage::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir
BOOL CHostage::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
{
#ifdef REGAMEDLL_ADD
if (!CanTakeDamage(pevAttacker))
if (pevAttacker && !CanTakeDamage(pevAttacker))
return FALSE;
#endif
@ -771,7 +781,7 @@ void CHostage::SetDeathActivity()
return;
}
if (AreImprovAllowed())
if (cv_hostage_ai_enable.value)
{
switch (m_LastHitGroup)
{
@ -1242,7 +1252,7 @@ void CHostage::SendHostagePositionMsg()
if (!pEntity->IsPlayer())
continue;
if (pEntity->pev->flags == FL_DORMANT)
if (pEntity->IsDormant())
continue;
CBasePlayer *pTempPlayer = GetClassPtr<CCSPlayer>((CBasePlayer *)pEntity->pev);
@ -1271,7 +1281,7 @@ void CHostage::SendHostageEventMsg()
if (!pEntity->IsPlayer())
continue;
if (pEntity->pev->flags == FL_DORMANT)
if (pEntity->IsDormant())
continue;
CBasePlayer *pTempPlayer = GetClassPtr<CCSPlayer>((CBasePlayer *)pEntity->pev);
@ -1397,7 +1407,7 @@ void Hostage_RegisterCVars()
{
// These cvars are only used in czero
#ifdef REGAMEDLL_FIXES
if (!AreImprovAllowed())
if (!cv_hostage_ai_enable.value)
return;
#endif
@ -1432,7 +1442,7 @@ void CHostageManager::ServerActivate()
AddHostage(pHostage);
}
if (AreImprovAllowed())
if (cv_hostage_ai_enable.value)
{
for (auto& snd : hostageSoundStruct) {
m_chatter.AddSound(snd.type, snd.fileName);
@ -1568,6 +1578,9 @@ void SimpleChatter::AddSound(HostageChatterType type, char *filename)
Q_snprintf(actualFilename, sizeof(actualFilename), "sound\\%s", filename);
if (!g_pFileSystem->FileExists(actualFilename))
return;
chatter->file[chatter->count].filename = CloneString(filename);
chatter->file[chatter->count].duration = (double)GET_APPROX_WAVE_PLAY_LEN(actualFilename) / 1000.0;
@ -1605,6 +1618,9 @@ void SimpleChatter::Shuffle(ChatterSet *chatter)
char *SimpleChatter::GetSound(HostageChatterType type, float *duration)
{
ChatterSet *chatter = &m_chatter[type];
if (chatter->count == 0)
return nullptr;
char *sound;
Shuffle(chatter);

@ -77,6 +77,7 @@ enum HostageChatterType
extern CHostageManager *g_pHostages;
extern int g_iHostageNumber;
extern cvar_t cv_hostage_ai_enable;
extern cvar_t cv_hostage_debug;
extern cvar_t cv_hostage_stop;
@ -284,11 +285,5 @@ private:
SimpleChatter m_chatter;
};
// Determine whether hostage improv can be used or not
inline bool AreImprovAllowed()
{
return g_bHostageImprov;
}
void Hostage_RegisterCVars();
void InstallHostageManager();

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

@ -78,7 +78,7 @@ void HostageIdleState::OnUpdate(CHostageImprov *improv)
}
}
if (m_moveState && improv->IsAtMoveGoal())
if (m_moveState != NotMoving && improv->IsAtMoveGoal())
{
m_moveState = NotMoving;

@ -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;
@ -481,22 +481,9 @@ BOOL CItemThighPack::MyTouch(CBasePlayer *pPlayer)
return FALSE;
#endif
pPlayer->m_bHasDefuser = true;
pPlayer->pev->body = 1;
pPlayer->GiveDefuser();
ClientPrint(pPlayer->pev, HUD_PRINTCENTER, "#Got_defuser");
MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pPlayer->pev);
WRITE_BYTE(STATUSICON_SHOW);
WRITE_STRING("defuser");
WRITE_BYTE(0);
WRITE_BYTE(160);
WRITE_BYTE(0);
MESSAGE_END();
pPlayer->SendItemStatus();
pPlayer->SetScoreboardAttributes();
EMIT_SOUND(pPlayer->edict(), CHAN_VOICE, "items/kevlar.wav", VOL_NORM, ATTN_NORM);
if (TheTutor)

@ -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();

File diff suppressed because it is too large Load Diff

@ -6,7 +6,7 @@ int __API_HOOK(GetForceCamera)(CBasePlayer *pObserver)
{
int retVal;
if (!fadetoblack.value)
if (fadetoblack.value != FADETOBLACK_STAY)
{
retVal = int(CVAR_GET_FLOAT("mp_forcechasecam"));
@ -51,7 +51,7 @@ void UpdateClientEffects(CBasePlayer *pObserver, int oldMode)
{
bool clearProgress = false;
bool clearBlindness = false;
bool blindnessOk = (fadetoblack.value == 0);
bool blindnessOk = (fadetoblack.value != FADETOBLACK_STAY);
bool clearNightvision = false;
if (pObserver->GetObserverMode() == OBS_IN_EYE)
@ -478,10 +478,19 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_SetMode)(int iMode)
// verify observer target again
if (m_hObserverTarget)
{
#ifdef REGAMEDLL_FIXES
m_hObserverTarget = Observer_IsValidTarget( ENTINDEX(m_hObserverTarget->edict()), forcecamera != CAMERA_MODE_SPEC_ANYONE );
#else
CBasePlayer *pTarget = m_hObserverTarget;
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))
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
}
// set spectator mode
@ -525,14 +534,16 @@ 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;
m_bWasFollowing = false;
}
void CBasePlayer::Observer_Think()
LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, Observer_Think)
void EXT_FUNC CBasePlayer::__API_HOOK(Observer_Think)()
{
Observer_HandleButtons();
Observer_CheckTarget();

@ -32,6 +32,12 @@
#define CAMERA_MODE_SPEC_ONLY_TEAM 1
#define CAMERA_MODE_SPEC_ONLY_FIRST_PERSON 2
enum FadeToBlack {
FADETOBLACK_OFF,
FADETOBLACK_STAY,
FADETOBLACK_AT_DYING,
};
int GetForceCamera(CBasePlayer *pObserver);
void UpdateClientEffects(CBasePlayer *pObserver, int oldMode);

@ -23,7 +23,7 @@ void CPathCorner::KeyValue(KeyValueData *pkvd)
void CPathCorner::Spawn()
{
assert(("path_corner without a targetname", !pev->targetname.IsNull()));
DbgAssertMsg(!pev->targetname.IsNull(), "path_corner without a targetname");
}
TYPEDESCRIPTION CPathTrack::m_SaveData[] =

@ -382,7 +382,7 @@ void CFuncPlat::GoDown()
EMIT_SOUND(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseMovement), m_volume, ATTN_NORM);
}
assert(m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP);
DbgAssert(m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP);
m_toggle_state = TS_GOING_DOWN;
SetMoveDone(&CFuncPlat::CallHitBottom);
LinearMove(m_vecPosition2, pev->speed);
@ -401,7 +401,7 @@ void CFuncPlat::HitBottom()
EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM);
}
assert(m_toggle_state == TS_GOING_DOWN);
DbgAssert(m_toggle_state == TS_GOING_DOWN);
m_toggle_state = TS_AT_BOTTOM;
}
@ -413,7 +413,7 @@ void CFuncPlat::GoUp()
EMIT_SOUND(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseMovement), m_volume, ATTN_NORM);
}
assert(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN);
DbgAssert(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN);
m_toggle_state = TS_GOING_UP;
SetMoveDone(&CFuncPlat::CallHitTop);
LinearMove(m_vecPosition1, pev->speed);
@ -432,7 +432,7 @@ void CFuncPlat::HitTop()
EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM);
}
assert(m_toggle_state == TS_GOING_UP);
DbgAssert(m_toggle_state == TS_GOING_UP);
m_toggle_state = TS_AT_TOP;
if (!IsTogglePlat())
@ -456,7 +456,7 @@ void CFuncPlat::Blocked(CBaseEntity *pOther)
}
// Send the platform back where it came from
assert(m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN);
DbgAssert(m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN);
if (m_toggle_state == TS_GOING_UP)
{

File diff suppressed because it is too large Load Diff

@ -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
@ -444,6 +445,13 @@ public:
void Pain_OrigFunc(int iLastHitGroup, bool bHasArmour);
void DeathSound_OrigFunc();
void JoiningThink_OrigFunc();
void CheckTimeBasedDamage_OrigFunc();
edict_t *EntSelectSpawnPoint_OrigFunc();
void PlayerDeathThink_OrigFunc();
void Observer_Think_OrigFunc();
void RemoveAllItems_OrigFunc(BOOL removeSuit);
void UpdateStatusBar_OrigFunc();
void TakeDamageImpulse_OrigFunc(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier);
CCSPlayer *CSPlayer() const;
#endif // REGAMEDLL_API
@ -453,6 +461,7 @@ public:
static CBasePlayer *Instance(entvars_t *pev) { return Instance(ENT(pev)); }
static CBasePlayer *Instance(int offset) { return Instance(ENT(offset)); }
float GetDyingAnimationDuration() const;
void SpawnClientSideCorpse();
void Observer_FindNextPlayer(bool bReverse, const char *name = nullptr);
CBasePlayer *Observer_IsValidTarget(int iPlayerIndex, bool bSameTeam);
@ -494,6 +503,7 @@ public:
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();
@ -514,7 +524,9 @@ public:
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);
@ -531,6 +543,7 @@ public:
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);
@ -585,6 +598,7 @@ public:
bool IsReloading() const;
bool HasTimePassedSinceDeath(float duration) const;
bool IsBlind() const { return (m_blindUntilTime > gpGlobals->time); }
bool IsFullyBlind(const float flPeekTime = 0.6f) const { return m_blindAlpha >= 255 && m_blindFadeTime > (flPeekTime * 2.0f) && (m_blindStartTime + m_blindHoldTime + flPeekTime) > gpGlobals->time; }
bool IsAutoFollowAllowed() const { return (gpGlobals->time > m_allowAutoFollowTime); }
void InhibitAutoFollow(float duration) { m_allowAutoFollowTime = gpGlobals->time + duration; }
void AllowAutoFollow() { m_allowAutoFollowTime = 0; }
@ -592,7 +606,7 @@ public:
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();
@ -628,12 +642,15 @@ public:
void DropPrimary();
void OnSpawnEquip(bool addDefault = true, bool equipGame = true);
void RemoveBomb();
void GiveDefuser();
void RemoveDefuser();
void HideTimer();
bool MakeBomber();
bool GetIntoGame();
bool ShouldToShowAccount(CBasePlayer *pReceiver) const;
bool ShouldToShowHealthInfo(CBasePlayer *pReceiver) const;
const char *GetKillerWeaponName(entvars_t *pevInflictor, entvars_t *pevKiller) const;
bool ShouldGibPlayer(int iGib);
CBasePlayerItem *GetItemByName(const char *itemName);
CBasePlayerItem *GetItemById(WeaponIdType weaponID);
@ -643,6 +660,7 @@ public:
void UseEmpty();
void DropIdlePlayer(const char *reason);
bool Kill();
void TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier);
// templates
template<typename T = CBasePlayerItem, typename Functor>
@ -907,6 +925,7 @@ public:
CWeaponBox *CreateWeaponBox(CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo);
CWeaponBox *CreateWeaponBox_OrigFunc(CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo);
CItemThighPack *SpawnDefuser(const Vector &vecOrigin, edict_t *pentOwner);
class CWShield: public CBaseEntity
{
@ -946,7 +965,24 @@ inline bool CBasePlayer::HasTimePassedSinceDeath(float duration) const
inline CCSPlayer *CBasePlayer::CSPlayer() const {
return reinterpret_cast<CCSPlayer *>(this->m_pEntity);
}
#endif
#else // !REGAMEDLL_API
// Determine whether player can be gibbed or not
inline bool CBasePlayer::ShouldGibPlayer(int iGib)
{
// Always gib the player regardless of incoming damage
if (iGib == GIB_ALWAYS)
return true;
// Gib the player if health is below the gib damage threshold
if (pev->health < GIB_PLAYER_THRESHOLD && iGib != GIB_NEVER)
return true;
// do not gib the player
return false;
}
#endif // !REGAMEDLL_API
#ifdef REGAMEDLL_FIXES
@ -957,6 +993,19 @@ inline CBasePlayer *UTIL_PlayerByIndex(int playerIndex)
return GET_PRIVATE<CBasePlayer>(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)
@ -968,7 +1017,6 @@ inline CBasePlayer *UTIL_PlayerByIndexSafe(int playerIndex)
return pPlayer;
}
extern entvars_t *g_pevLastInflictor;
extern CBaseEntity *g_pLastSpawn;
extern CBaseEntity *g_pLastCTSpawn;
extern CBaseEntity *g_pLastTerroristSpawn;
@ -996,11 +1044,10 @@ void SendItemStatus(CBasePlayer *pPlayer);
const char *GetCSModelName(int item_id);
Vector VecVelocityForDamage(float flDamage);
int TrainSpeed(int iSpeed, int iMax);
const char *GetWeaponName(entvars_t *pevInflictor, entvars_t *pKiller);
void LogAttack(CBasePlayer *pAttacker, CBasePlayer *pVictim, int teamAttack, int healthHit, int armorHit, int newHealth, int newArmor, const char *killer_weapon_name);
bool CanSeeUseable(CBasePlayer *me, CBaseEntity *pEntity);
void FixPlayerCrouchStuck(edict_t *pPlayer);
BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot);
BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot, float fRadius);
CBaseEntity *FindEntityForward(CBaseEntity *pMe);
real_t GetPlayerPitch(const edict_t *pEdict);
real_t GetPlayerYaw(const edict_t *pEdict);

@ -30,16 +30,18 @@
#define QSTRING_DEFINE
constexpr unsigned int iStringNull = {0};
// Quake string (helper class)
class QString final
{
public:
#if XASH_64BIT
using qstring_t = int;
#else
using qstring_t = unsigned int;
#endif
QString(): m_string(iStringNull) {};
QString(qstring_t string): m_string(string) {};
QString();
QString(qstring_t string);
bool IsNull() const;
bool IsNullOrEmpty() const;
@ -52,13 +54,15 @@ public:
bool operator==(const char *pszString) const;
operator const char *() const;
operator unsigned int() const;
operator qstring_t() const;
const char *str() const;
private:
qstring_t m_string;
};
constexpr QString::qstring_t iStringNull = {0};
#ifdef USE_QSTRING
#define string_t QString
#endif
@ -70,10 +74,25 @@ private:
extern globalvars_t *gpGlobals;
#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (unsigned int)(offset)))
#define MAKE_STRING(str) ((unsigned int)(str) - (unsigned int)(STRING(0)))
#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (QString::qstring_t)(offset)))
#if XASH_64BIT
// Xash3D FWGS in 64-bit mode has internal string pool which allows mods to continue use 32-bit string_t
inline int MAKE_STRING(const char *str)
{
ptrdiff_t diff = str - STRING(0);
if (diff >= INT_MIN && diff <= INT_MAX)
return (int)diff;
return ALLOC_STRING(str);
}
#else
#define MAKE_STRING(str) ((QString::qstring_t)(str) - (QString::qstring_t)(STRING(0)))
#endif
// Inlines
inline QString::QString(): m_string(iStringNull) {}
inline QString::QString(qstring_t string): m_string(string) {}
inline bool QString::IsNull() const
{
return m_string == iStringNull;
@ -115,7 +134,7 @@ inline QString::operator const char *() const
return str();
}
inline QString::operator unsigned int() const
inline QString::operator qstring_t() const
{
return m_string;
}

@ -250,10 +250,10 @@ edict_t *CSaveRestoreBuffer::EntityFromIndex(int entityIndex)
int CSaveRestoreBuffer::EntityFlagsSet(int entityIndex, int flags)
{
if (!m_pData || entityIndex < 0)
if (!m_pData)
return 0;
if (!m_pData || entityIndex < 0 || entityIndex > m_pData->tableCount)
if (entityIndex < 0 || entityIndex > m_pData->tableCount)
return 0;
m_pData->pTable[entityIndex].flags |= flags;
@ -955,15 +955,15 @@ void CGlobalState::DumpGlobals()
void CGlobalState::EntityAdd(string_t globalname, string_t mapName, GLOBALESTATE state)
{
assert(!Find(globalname));
DbgAssert(!Find(globalname));
globalentity_t *pNewEntity = (globalentity_t *)calloc(sizeof(globalentity_t), 1);
assert(pNewEntity != nullptr);
DbgAssert(pNewEntity != nullptr);
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));
}
}

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

@ -1040,11 +1040,10 @@ void USENTENCEG_InitLRU(unsigned char *plru, int count)
// ipick is passed in as the requested sentence ordinal.
// ipick 'next' is returned.
// return of -1 indicates an error.
int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset)
int USENTENCEG_PickSequential(int isentenceg, char (&szfound)[64], int ipick, int freset)
{
char *szgroupname;
unsigned char count;
char sznum[12];
if (!fSentencesInit)
return -1;
@ -1061,10 +1060,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres
if (ipick >= count)
ipick = count - 1;
Q_strcpy(szfound, "!");
Q_strcat(szfound, szgroupname);
Q_snprintf(sznum, sizeof(sznum), "%d", ipick);
Q_strcat(szfound, sznum);
Q_snprintf(szfound, sizeof(szfound), "!%s%d", szgroupname, ipick);
if (ipick >= count)
{
@ -1084,13 +1080,12 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres
// rest of the lru filled with -1. The first integer in the lru is
// actually the size of the list. Returns ipick, the ordinal
// of the picked sentence within the group.
int USENTENCEG_Pick(int isentenceg, char *szfound)
int USENTENCEG_Pick(int isentenceg, char (&szfound)[64])
{
char *szgroupname;
unsigned char *plru;
unsigned char i;
unsigned char count;
char sznum[12];
unsigned char ipick = 0xFF;
BOOL ffound = FALSE;
@ -1119,11 +1114,7 @@ int USENTENCEG_Pick(int isentenceg, char *szfound)
if (ffound)
{
Q_strcpy(szfound, "!");
Q_strcat(szfound, szgroupname);
Q_snprintf(sznum, sizeof(sznum), "%d", ipick);
Q_strcat(szfound, sznum);
Q_snprintf(szfound, sizeof(szfound), "!%s%d", szgroupname, ipick);
return ipick;
}
else
@ -1168,8 +1159,6 @@ int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float atte
if (!fSentencesInit)
return -1;
name[0] = '\0';
ipick = USENTENCEG_Pick(isentenceg, name);
#ifndef REGAMEDLL_FIXES
@ -1194,8 +1183,6 @@ int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, float volume,
if (!fSentencesInit)
return -1;
name[0] = '\0';
isentenceg = SENTENCEG_GetIndex(szgroupname);
if (isentenceg < 0)
{
@ -1223,8 +1210,6 @@ int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, float v
if (!fSentencesInit)
return -1;
name[0] = '\0';
isentenceg = SENTENCEG_GetIndex(szgroupname);
if (isentenceg < 0)
return -1;
@ -1323,7 +1308,7 @@ void SENTENCEG_Init()
ALERT(at_warning, "Sentence %s longer than %d letters\n", pString, MAX_SENTENCE_NAME - 1);
}
Q_strcpy(gszallsentencenames[gcallsentences++], pString);
Q_strlcpy(gszallsentencenames[gcallsentences++], pString);
if (--j <= i)
continue;
@ -1354,10 +1339,10 @@ void SENTENCEG_Init()
break;
}
Q_strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i]));
Q_strlcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i]));
rgsentenceg[isentencegs].count = 1;
Q_strcpy(szgroup, &(buffer[i]));
Q_strlcpy(szgroup, &(buffer[i]));
continue;
}
@ -1377,7 +1362,7 @@ void SENTENCEG_Init()
i = 0;
while (rgsentenceg[i].count && i < MAX_SENTENCE_GROUPS)
while (i < MAX_SENTENCE_GROUPS && rgsentenceg[i].count)
{
USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count);
i++;
@ -1385,9 +1370,8 @@ void SENTENCEG_Init()
}
// convert sentence (sample) name to !sentencenum, return !sentencenum
int SENTENCEG_Lookup(const char *sample, char *sentencenum)
int SENTENCEG_Lookup(const char *sample, char (&sentencenum)[32])
{
char sznum[12];
int i;
// this is a sentence name; lookup sentence number
@ -1396,13 +1380,7 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum)
{
if (!Q_stricmp(gszallsentencenames[i], sample + 1))
{
if (sentencenum)
{
Q_strcpy(sentencenum, "!");
Q_snprintf(sznum, sizeof(sznum), "%d", i);
Q_strcat(sentencenum, sznum);
}
Q_snprintf(sentencenum, sizeof(sentencenum), "!%d", i);
return i;
}
}
@ -1580,7 +1558,7 @@ void TEXTURETYPE_Init()
j = Q_min(j, MAX_TEXTURENAME_LENGHT - 1 + i);
buffer[j] = '\0';
Q_strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i]));
Q_strlcpy(grgszTextureName[gcTextures++], &(buffer[i]));
}
FREE_FILE(pMemFile);
@ -1616,7 +1594,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
char chTextureType;
float fvol;
float fvolbar;
char szBuffer[64];
char szBuffer[MAX_TEXTURENAME_LENGHT];
const char *pTextureName;
float rgfl1[3];
float rgfl2[3];
@ -1666,8 +1644,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int
pTextureName++;
// '}}'
Q_strcpy(szBuffer, pTextureName);
szBuffer[MAX_TEXTURENAME_LENGHT - 1] = '\0';
Q_strlcpy(szBuffer, pTextureName);
// get texture type
chTextureType = TEXTURETYPE_Find(szBuffer);

@ -170,15 +170,13 @@ public:
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);

@ -330,8 +330,8 @@ void CBaseToggle::KeyValue(KeyValueData *pkvd)
// pev->origin traveling at flSpeed
void CBaseToggle::LinearMove(Vector vecDest, float flSpeed)
{
assert(("LinearMove: no speed is defined!", flSpeed != 0));
//assert(("LinearMove: no post-move function defined", m_pfnCallWhenMoveDone != nullptr));
DbgAssertMsg(flSpeed != 0, "LinearMove: no speed is defined!");
//DbgAssertMsg(m_pfnCallWhenMoveDone != nullptr, "LinearMove: no post-move function defined");
m_vecFinalDest = vecDest;
@ -382,8 +382,8 @@ NOXREF BOOL CBaseToggle::IsLockedByMaster()
// Just like LinearMove, but rotational.
void CBaseToggle::AngularMove(Vector vecDestAngle, float flSpeed)
{
assert(("AngularMove: no speed is defined!", flSpeed != 0));
//assert(("AngularMove: no post-move function defined", m_pfnCallWhenMoveDone != nullptr));
DbgAssertMsg(flSpeed != 0, "AngularMove: no speed is defined!");
//DbgAssertMsg(m_pfnCallWhenMoveDone != nullptr, "AngularMove: no post-move function defined");
m_vecFinalAngle = vecDestAngle;

@ -468,7 +468,10 @@ void CBaseTrigger::InitTrigger()
pev->movetype = MOVETYPE_NONE;
// set size and link into world
SET_MODEL(ENT(pev), STRING(pev->model));
if (FStringNull(pev->model))
UTIL_SetOrigin(pev, pev->origin); // link into the list
else
SET_MODEL(ENT(pev), STRING(pev->model));
if (CVAR_GET_FLOAT("showtriggers") == 0)
{
@ -582,7 +585,6 @@ void CTriggerCDAudio::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP
PlayTrack(pCaller->edict());
}
#ifdef REGAMEDLL_FIXES
const char *g_szMP3trackFileMap[] =
{
"", "",
@ -614,7 +616,6 @@ const char *g_szMP3trackFileMap[] =
"media/Suspense05.mp3",
"media/Suspense07.mp3"
};
#endif
void PlayCDTrack(edict_t *pClient, int iTrack)
{
@ -622,7 +623,7 @@ void PlayCDTrack(edict_t *pClient, int iTrack)
if (!pClient)
return;
if (iTrack < -1 || iTrack > 30)
if (iTrack < -1 || iTrack >= (int)ARRAYSIZE(g_szMP3trackFileMap))
{
ALERT(at_console, "TriggerCDAudio - Track %d out of range\n", iTrack);
return;
@ -642,7 +643,7 @@ void PlayCDTrack(edict_t *pClient, int iTrack)
CLIENT_COMMAND(pClient, UTIL_VarArgs("mp3 play %s\n", g_szMP3trackFileMap[iTrack]));
#else
char string[64];
Q_sprintf(string, "cd play %3d\n", iTrack);
Q_snprintf(string, sizeof(string), "cd play %3d\n", iTrack);
CLIENT_COMMAND(pClient, string);
#endif
}
@ -968,7 +969,7 @@ void CTriggerMultiple::Spawn()
InitTrigger();
assert(("trigger_multiple with health", pev->health == 0));
DbgAssertMsg(pev->health == 0, "trigger_multiple with health");
//UTIL_SetOrigin(pev, pev->origin);
//SET_MODEL(ENT(pev), STRING(pev->model));
@ -993,6 +994,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()
@ -1203,7 +1212,7 @@ void CChangeLevel::KeyValue(KeyValueData *pkvd)
ALERT(at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue);
}
Q_strcpy(m_szMapName, pkvd->szValue);
Q_strlcpy(m_szMapName, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "landmark"))
@ -1213,7 +1222,7 @@ void CChangeLevel::KeyValue(KeyValueData *pkvd)
ALERT(at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue);
}
Q_strcpy(m_szLandmarkName, pkvd->szValue);
Q_strlcpy(m_szLandmarkName, pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "changetarget"))
@ -1345,7 +1354,7 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator)
}
// This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory
Q_strcpy(st_szNextMap, m_szMapName);
Q_strlcpy(st_szNextMap, m_szMapName);
m_hActivator = pActivator;
SUB_UseTargets(pActivator, USE_TOGGLE, 0);
@ -1358,7 +1367,7 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator)
if (!FNullEnt(pentLandmark))
{
Q_strcpy(st_szNextSpot, m_szLandmarkName);
Q_strlcpy(st_szNextSpot, m_szLandmarkName);
gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin;
}
@ -1404,8 +1413,8 @@ int CChangeLevel::AddTransitionToList(LEVELLIST *pLevelList, int listCount, cons
}
}
Q_strcpy(pLevelList[listCount].mapName, pMapName);
Q_strcpy(pLevelList[listCount].landmarkName, pLandmarkName);
Q_strlcpy(pLevelList[listCount].mapName, pMapName);
Q_strlcpy(pLevelList[listCount].landmarkName, pLandmarkName);
pLevelList[listCount].pentLandmark = pentLandmark;
pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin;
@ -1580,12 +1589,12 @@ NOXREF void NextLevel()
{
gpGlobals->mapname = ALLOC_STRING("start");
pChange = GetClassPtr<CCSChangeLevel>((CChangeLevel *)nullptr);
Q_strcpy(pChange->m_szMapName, "start");
Q_strlcpy(pChange->m_szMapName, "start");
}
else
pChange = GetClassPtr<CCSChangeLevel>((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)
@ -1760,8 +1769,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++;
@ -1814,6 +1845,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)
@ -1976,7 +2027,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)

@ -204,6 +204,11 @@ public:
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

@ -75,7 +75,10 @@ void MonitorTutorStatus()
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
if (pPlayer && !pPlayer->IsBot())
if (!UTIL_IsValidPlayer(pPlayer))
continue;
if (!pPlayer->IsBot())
numHumans++;
}

@ -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] = '\0';
#endif
Q_strlcpy(buf, param->m_data, buflen);
delete param;
return buf;

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

@ -506,7 +506,11 @@ void UTIL_ScreenShake(const Vector &center, 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;
@ -1465,7 +1464,7 @@ void UTIL_Remove(CBaseEntity *pEntity)
pEntity->pev->targetname = 0;
}
NOXREF BOOL UTIL_IsValidEntity(edict_t *pent)
BOOL UTIL_IsValidEntity(edict_t *pent)
{
if (!pent || pent->free || (pent->v.flags & FL_KILLME))
return FALSE;
@ -1497,7 +1496,7 @@ void UTIL_RestartOther(const char *szClassname)
while ((pEntity = UTIL_FindEntityByClassname(pEntity, szClassname)))
{
pEntity->Restart();
#ifdef REGAMEDLL_ADD
FireTargets("game_entity_restart", pEntity, nullptr, USE_TOGGLE, 0.0);
#endif
@ -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
@ -1661,14 +1660,12 @@ int UTIL_ReadFlags(const char *c)
// Determine whether bots can be used or not
bool UTIL_AreBotsAllowed()
{
#ifdef REGAMEDLL_ADD
if (g_engfuncs.pfnEngCheckParm == nullptr)
return false;
#endif
if (AreRunningCZero())
{
#ifdef REGAMEDLL_ADD
if (g_engfuncs.pfnEngCheckParm == nullptr)
return false;
// If they pass in -nobots, don't allow bots. This is for people who host servers, to
// allow them to disallow bots to enforce CPU limits.
int nobots = ENG_CHECK_PARM("-nobots", nullptr);
@ -1688,15 +1685,10 @@ bool UTIL_AreBotsAllowed()
return true;
}
// allow the using of bots for CS 1.6
int bots = ENG_CHECK_PARM("-bots", nullptr);
if (bots)
{
return true;
}
#endif
return cv_bot_enable.value > 0;
#else
return false;
#endif
}
bool UTIL_IsBeta()
@ -1729,18 +1721,10 @@ bool UTIL_AreHostagesImprov()
}
#ifdef REGAMEDLL_ADD
if (g_engfuncs.pfnEngCheckParm == nullptr)
return false;
// someday in CS 1.6
int improv = ENG_CHECK_PARM("-host-improv", nullptr);
if (improv)
{
return true;
}
#endif
return cv_hostage_ai_enable.value > 0;
#else
return false;
#endif
}
int UTIL_GetNumPlayers()
@ -1749,15 +1733,27 @@ 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;
}
int UTIL_CountEntities(const char *szName)
{
int count = 0;
CBaseEntity *pEnt = nullptr;
while ((pEnt = UTIL_FindEntityByClassname(pEnt, szName)))
count++;
return count;
}
bool UTIL_IsSpawnPointOccupied(CBaseEntity *pSpot)
{
if (!pSpot)
@ -1808,10 +1804,11 @@ void NORETURN Sys_Error(const char *error, ...)
CONSOLE_ECHO("FATAL ERROR (shutting down): %s\n", text);
//TerminateProcess(GetCurrentProcess(), 1);
int *null = 0;
*null = 0;
exit(-1);
#if defined(_WIN32)
MessageBoxA(NULL, text, "Fatal error", MB_ICONERROR | MB_OK);
#endif
exit(EXIT_FAILURE);
}
int UTIL_CountPlayersInBrushVolume(bool bOnlyAlive, CBaseEntity *pBrushEntity, int &playersInCount, int &playersOutCount, CPlayerInVolumeAdapter *pAdapter)
@ -1825,7 +1822,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())

@ -297,6 +297,7 @@ bool UTIL_AreBotsAllowed();
bool UTIL_IsBeta();
bool UTIL_AreHostagesImprov();
int UTIL_GetNumPlayers();
int UTIL_CountEntities(const char *szName);
bool UTIL_IsSpawnPointOccupied(CBaseEntity *pSpot);
void MAKE_STRING_CLASS(const char *str, entvars_t *pev);
void NORETURN Sys_Error(const char *error, ...);

@ -126,7 +126,7 @@ void CFuncVehicle::Blocked(CBaseEntity *pOther)
float minz = pev->origin.z;
#ifdef REGAMEDLL_FIXES
float maxz = pev->origin.z + (2 * Q_abs(pev->mins.z - pev->maxs.z));
float maxz = pev->origin.z + (2 * Q_abs(pev->mins.z - pev->maxs.z));
#else
float maxz = pev->origin.z + (2 * Q_abs(int(pev->mins.z - pev->maxs.z)));
#endif
@ -343,15 +343,20 @@ void CFuncVehicle::CheckTurning()
if (pev->speed > 0)
{
UTIL_TraceLine(m_vFrontRight, m_vFrontRight - (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
if (tr.flFraction != 1.0f)
{
m_iTurnAngle = 1;
}
}
else if (pev->speed < 0)
{
UTIL_TraceLine(m_vBackLeft, m_vBackLeft + (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
}
if (tr.flFraction != 1.0f)
{
m_iTurnAngle = 1;
if (tr.flFraction != 1.0f)
{
m_iTurnAngle = 1;
}
}
}
else if (m_iTurnAngle > 0)
@ -359,15 +364,20 @@ void CFuncVehicle::CheckTurning()
if (pev->speed > 0)
{
UTIL_TraceLine(m_vFrontLeft, m_vFrontLeft + (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
if (tr.flFraction != 1.0f)
{
m_iTurnAngle = -1;
}
}
else if (pev->speed < 0)
{
UTIL_TraceLine(m_vBackRight, m_vBackRight - (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
}
if (tr.flFraction != 1.0f)
{
m_iTurnAngle = -1;
if (tr.flFraction != 1.0f)
{
m_iTurnAngle = -1;
}
}
}

@ -74,36 +74,52 @@ float GetBaseAccuracy(WeaponIdType id)
return 0.0f;
}
LINK_HOOK_VOID_CHAIN2(ClearMultiDamage)
// Resets the global multi damage accumulator
void ClearMultiDamage()
void EXT_FUNC __API_HOOK(ClearMultiDamage)()
{
gMultiDamage.pEntity = nullptr;
gMultiDamage.hEntity = nullptr;
gMultiDamage.amount = 0;
gMultiDamage.type = 0;
}
LINK_HOOK_VOID_CHAIN(ApplyMultiDamage, (entvars_t *pevInflictor, entvars_t *pevAttacker), pevInflictor, pevAttacker)
// Inflicts contents of global multi damage register on gMultiDamage.pEntity
void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker)
void EXT_FUNC __API_HOOK(ApplyMultiDamage)(entvars_t *pevInflictor, entvars_t *pevAttacker)
{
if (!gMultiDamage.pEntity)
EntityHandle<CBaseEntity> hEnt = gMultiDamage.hEntity;
if (!hEnt)
return;
gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type);
hEnt->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type);
// check again, the entity may be removed after taking damage
if (hEnt)
hEnt->ResetDmgPenetrationLevel();
}
void AddMultiDamage(entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType)
LINK_HOOK_VOID_CHAIN(AddMultiDamage, (entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType), pevInflictor, pEntity, flDamage, bitsDamageType)
void EXT_FUNC __API_HOOK(AddMultiDamage)(entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType)
{
if (!pEntity)
return;
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;
}
@ -208,10 +224,16 @@ struct {
#endif
// Precaches the ammo and queues the ammo info for sending to clients
void AddAmmoNameToAmmoRegistry(const char *szAmmoname)
int AddAmmoNameToAmmoRegistry(const char *szAmmoname)
{
// string validation
if (!szAmmoname || !szAmmoname[0])
{
return -1;
}
// make sure it's not already in the registry
for (int i = 0; i < MAX_AMMO_SLOTS; i++)
for (int i = 1; i < MAX_AMMO_SLOTS; i++)
{
if (!CBasePlayerItem::m_AmmoInfoArray[i].pszName)
continue;
@ -219,15 +241,15 @@ void AddAmmoNameToAmmoRegistry(const char *szAmmoname)
if (!Q_stricmp(CBasePlayerItem::m_AmmoInfoArray[i].pszName, szAmmoname))
{
// ammo already in registry, just quite
return;
return i;
}
}
giAmmoIndex++;
assert(giAmmoIndex < MAX_AMMO_SLOTS);
DbgAssert(giAmmoIndex < MAX_AMMO_SLOTS);
if (giAmmoIndex >= MAX_AMMO_SLOTS)
giAmmoIndex = 0;
giAmmoIndex = 1;
#ifdef REGAMEDLL_ADD
for (auto& ammo : ammoIndex)
@ -246,6 +268,8 @@ void AddAmmoNameToAmmoRegistry(const char *szAmmoname)
// Yes, this info is redundant
CBasePlayerItem::m_AmmoInfoArray[giAmmoIndex].iId = giAmmoIndex;
return giAmmoIndex;
}
// Precaches the weapon and queues the weapon info for sending to clients
@ -269,15 +293,8 @@ void UTIL_PrecacheOtherWeapon(const char *szClassname)
{
CBasePlayerItem::m_ItemInfoArray[info.iId] = info;
if (info.pszAmmo1 && info.pszAmmo1[0] != '\0')
{
AddAmmoNameToAmmoRegistry(info.pszAmmo1);
}
if (info.pszAmmo2 && info.pszAmmo2[0] != '\0')
{
AddAmmoNameToAmmoRegistry(info.pszAmmo2);
}
AddAmmoNameToAmmoRegistry(info.pszAmmo1);
AddAmmoNameToAmmoRegistry(info.pszAmmo2);
}
}
@ -501,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())
{
@ -538,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;
}
@ -558,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);
@ -589,11 +618,17 @@ void CBasePlayerItem::DefaultTouch(CBaseEntity *pOther)
CBasePlayer *pPlayer = static_cast<CBasePlayer *>(pOther);
if (pPlayer->m_bIsVIP
&& m_iId != WEAPON_USP
&&
#ifndef REGAMEDLL_FIXES
m_iId != WEAPON_USP
&& m_iId != WEAPON_GLOCK18
&& m_iId != WEAPON_P228
&& m_iId != WEAPON_DEAGLE
&& m_iId != WEAPON_KNIFE)
&& m_iId != WEAPON_KNIFE
#else
!IsSecondaryWeapon(m_iId)
#endif
)
{
return;
}
@ -623,11 +658,11 @@ void CBasePlayerWeapon::SetPlayerShieldAnim()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
Q_strcpy(m_pPlayer->m_szAnimExtention, "shield");
Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield");
}
else
{
Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
}
}
@ -637,7 +672,7 @@ void CBasePlayerWeapon::ResetPlayerShieldAnim()
{
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
}
}
}
@ -668,7 +703,7 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iDownAnim, UseDecrement() != FALSE);
Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun");
m_fMaxSpeed = 250.0f;
m_pPlayer->m_bShieldDrawn = false;
}
@ -676,7 +711,7 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
{
m_iWeaponState |= WPNSTATE_SHIELD_DRAWN;
SendWeaponAnim(iUpAnim, UseDecrement() != FALSE);
Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded");
Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded");
m_fMaxSpeed = 180.0f;
m_pPlayer->m_bShieldDrawn = true;
}
@ -691,8 +726,45 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
return true;
}
void CBasePlayerWeapon::KickBack(float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change)
LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayerWeapon, KickBack, (float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change), up_base, lateral_base, up_modifier, lateral_modifier, up_max, lateral_max, direction_change)
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<real_t>(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;
@ -733,6 +805,7 @@ void CBasePlayerWeapon::KickBack(float up_base, float lateral_base, float up_mod
{
m_iDirection = !m_iDirection;
}
#endif
}
void CBasePlayerWeapon::FireRemaining(int &shotsFired, float &shootTime, BOOL bIsGlock)
@ -758,9 +831,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
@ -769,8 +848,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
@ -814,18 +892,26 @@ BOOL CanAttack(float attack_time, float curtime, BOOL isPredicted)
bool CBasePlayerWeapon::HasSecondaryAttack()
{
#ifdef REGAMEDLL_API
if (CSPlayerWeapon()->m_iStateSecondaryAttack != WEAPON_SECONDARY_ATTACK_NONE)
{
switch (CSPlayerWeapon()->m_iStateSecondaryAttack)
{
case WEAPON_SECONDARY_ATTACK_SET:
return true;
case WEAPON_SECONDARY_ATTACK_BLOCK:
return false;
default:
break;
}
}
#endif
if (m_pPlayer && m_pPlayer->HasShield())
{
return true;
}
#ifdef REGAMEDLL_API
if (CSPlayerWeapon()->m_bHasSecondaryAttack)
{
return true;
}
#endif
switch (m_iId)
{
case WEAPON_AK47:
@ -888,7 +974,9 @@ void CBasePlayerWeapon::HandleInfiniteAmmo()
}
}
void CBasePlayerWeapon::ItemPostFrame()
LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayerWeapon, ItemPostFrame)
void EXT_FUNC CBasePlayerWeapon::__API_HOOK(ItemPostFrame)()
{
int usableButtons = m_pPlayer->pev->button;
@ -1109,8 +1197,10 @@ void CBasePlayerWeapon::ItemPostFrame()
}
}
void CBasePlayerItem::DestroyItem()
bool CBasePlayerItem::DestroyItem()
{
bool success = false;
if (m_pPlayer)
{
// if attached to a player, remove.
@ -1118,18 +1208,31 @@ void CBasePlayerItem::DestroyItem()
{
#ifdef REGAMEDLL_FIXES
if (m_iId == WEAPON_C4) {
m_pPlayer->m_bHasC4 = false;
m_pPlayer->pev->body = 0;
m_pPlayer->SetBombIcon(FALSE);
m_pPlayer->SetProgressBarTime(0);
}
m_pPlayer->pev->weapons &= ~(1 << m_iId);
// No more weapon
if ((m_pPlayer->pev->weapons & ~(1 << WEAPON_SUIT)) == 0) {
m_pPlayer->m_iHideHUD |= HIDEHUD_WEAPONS;
}
#endif
if (!m_pPlayer->m_rgpPlayerItems[PRIMARY_WEAPON_SLOT]) {
m_pPlayer->m_bHasPrimary = false;
}
#endif
success = true;
}
}
Kill();
return success;
}
int CBasePlayerItem::AddToPlayer(CBasePlayer *pPlayer)
@ -1195,8 +1298,6 @@ void CBasePlayerWeapon::Spawn()
if (GetItemInfo(&info)) {
CSPlayerItem()->SetItemInfo(&info);
}
CSPlayerWeapon()->m_bHasSecondaryAttack = HasSecondaryAttack();
#endif
}
@ -1222,8 +1323,18 @@ 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())
{
@ -1279,7 +1390,9 @@ int CBasePlayerWeapon::UpdateClientData(CBasePlayer *pPlayer)
return 1;
}
void CBasePlayerWeapon::SendWeaponAnim(int iAnim, int skiplocal)
LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayerWeapon, SendWeaponAnim, (int iAnim, int skiplocal), iAnim, skiplocal)
void EXT_FUNC CBasePlayerWeapon::__API_HOOK(SendWeaponAnim)(int iAnim, int skiplocal)
{
m_pPlayer->pev->weaponanim = iAnim;
@ -1384,7 +1497,7 @@ BOOL EXT_FUNC CBasePlayerWeapon::__API_HOOK(DefaultDeploy)(char *szViewModel, ch
m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel);
#endif
model_name = m_pPlayer->pev->viewmodel;
Q_strcpy(m_pPlayer->m_szAnimExtention, szAnimExt);
Q_strlcpy(m_pPlayer->m_szAnimExtention, szAnimExt);
SendWeaponAnim(iAnim, skiplocal);
m_pPlayer->m_flNextAttack = 0.75f;
@ -1405,9 +1518,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;
@ -1548,7 +1664,11 @@ int CBasePlayerWeapon::PrimaryAmmoIndex()
int CBasePlayerWeapon::SecondaryAmmoIndex()
{
#ifdef REGAMEDLL_ADD
return m_iSecondaryAmmoType;
#else
return -1;
#endif
}
void CBasePlayerWeapon::Holster(int skiplocal)
@ -1557,6 +1677,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
@ -1578,7 +1702,7 @@ int CBasePlayerWeapon::ExtractAmmo(CBasePlayerWeapon *pWeapon)
if (pszAmmo2())
{
res = AddSecondaryAmmo(0, (char *)pszAmmo2(), iMaxAmmo2());
res = pWeapon->AddSecondaryAmmo(0, (char *)pszAmmo2(), iMaxAmmo2());
}
return res;
@ -1793,6 +1917,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<<pWeapon->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)
{
@ -1821,7 +2030,12 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
pPlayer->OnTouchingWeapon(this);
bool bRemove = true;
bool bEmitSound = false;
#ifdef REGAMEDLL_FIXES
CBasePlayerItem *givenItem = nullptr;
#else
bool givenItem = false;
#endif
// go through my weapons and try to give the usable ones to the player.
// it's important the the player be given ammo first, so the weapons code doesn't refuse
@ -1831,6 +2045,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
@ -1881,8 +2096,8 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
MESSAGE_END();
pPlayer->m_bHasC4 = true;
pPlayer->SetBombIcon(FALSE);
pPlayer->pev->body = 1;
pPlayer->SetBombIcon(FALSE);
CBaseEntity *pEntity = nullptr;
while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player")))
@ -1893,7 +2108,7 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
if (!pEntity->IsPlayer())
continue;
if (pEntity->pev->flags == FL_DORMANT)
if (pEntity->IsDormant())
continue;
CBasePlayer *pTempPlayer = GetClassPtr<CCSPlayer>((CBasePlayer *)pEntity->pev);
@ -1927,44 +2142,38 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
}
else if (i == GRENADE_SLOT)
{
CBasePlayerWeapon *pGrenade = static_cast<CBasePlayerWeapon *>(m_rgpPlayerItems[i]);
CBasePlayerWeapon *pGrenade = static_cast<CBasePlayerWeapon *>(pItem);
if (pGrenade && pGrenade->IsWeapon())
{
int playerGrenades = pPlayer->m_rgAmmo[pGrenade->m_iPrimaryAmmoType];
#ifdef REGAMEDLL_FIXES
// sorry for hardcode :(
const int boxAmmoSlot = 1;
CBasePlayerItem *pNext = pItem->m_pNext;
if (playerGrenades < pGrenade->iMaxAmmo1())
// 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);
}
}
// unlink this weapon from the box
if (pPrev)
pPrev->m_pNext = pItem = pNext;
else
{
auto pNext = m_rgpPlayerItems[i]->m_pNext;
if (pPlayer->AddPlayerItem(pItem))
{
pItem->AttachToPlayer(pPlayer);
bEmitSound = true;
}
// unlink this weapon from the box
m_rgpPlayerItems[i] = pItem = pNext;
continue;
}
continue;
}
#else
int maxGrenades = 0;
const char *grenadeName = nullptr;
@ -1992,7 +2201,7 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
// there we will see only get one grenade. Next step - pick it up, do check again `entity_dump`,
// but this time we'll see them x2.
bEmitSound = true;
givenItem = true;
pPlayer->GiveNamedItem(grenadeName);
// unlink this weapon from the box
@ -2010,20 +2219,30 @@ 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);
bEmitSound = true;
#ifdef REGAMEDLL_FIXES
givenItem = pItem;
#else
givenItem = true;
#endif
}
// 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;
}
}
@ -2034,13 +2253,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;
@ -2048,9 +2272,21 @@ void CWeaponBox::Touch(CBaseEntity *pOther)
}
}
if (bEmitSound)
if (givenItem)
{
EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2.wav", VOL_NORM, ATTN_NORM);
#ifdef REGAMEDLL_FIXES
// BUGBUG: weaponbox links gun to player, then ammo is given
// so FShouldSwitchWeapon's CanHolster (which checks ammo) check inside AddPlayerItem
// return FALSE, causing an unarmed player to not deploy any weaponbox grenade
if (pPlayer->m_pActiveItem != givenItem && CSGameRules()->FShouldSwitchWeapon(pPlayer, givenItem))
{
// This re-check is done after ammo is given
// so it ensures player properly deploys grenade from floor
pPlayer->SwitchWeapon(givenItem);
}
#endif
}
if (bRemove)
@ -2168,6 +2404,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)
{
@ -2638,3 +2892,4 @@ int CBasePlayerItem::iFlags() const
{
return m_ItemInfoEx.iFlags;
}

@ -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
@ -129,7 +133,7 @@ struct AmmoInfo
struct MULTIDAMAGE
{
CBaseEntity *pEntity;
EntityHandle<CBaseEntity> hEntity;
float amount;
int type;
};
@ -296,7 +300,7 @@ public:
virtual int iItemSlot() { return 0; } // return 0 to MAX_ITEMS_SLOTS, used in hud
public:
void EXPORT DestroyItem();
bool EXPORT DestroyItem();
void EXPORT DefaultTouch(CBaseEntity *pOther);
void EXPORT FallThink();
void EXPORT Materialize();
@ -403,6 +407,9 @@ public:
BOOL DefaultDeploy_OrigFunc(char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal);
BOOL DefaultReload_OrigFunc(int iClipSize, int iAnim, float fDelay);
bool DefaultShotgunReload_OrigFunc(int iAnim, int iStartAnim, float fDelay, float fStartDelay, const char *pszReloadSound1, const char *pszReloadSound2);
void KickBack_OrigFunc(float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change);
void SendWeaponAnim_OrigFunc(int iAnim, int skiplocal);
void ItemPostFrame_OrigFunc();
CCSPlayerWeapon *CSPlayerWeapon() const;
#endif
@ -470,6 +477,9 @@ public:
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();
@ -534,7 +544,7 @@ enum usp_shield_e
USP_SHIELD_SHOOT_EMPTY,
USP_SHIELD_RELOAD,
USP_SHIELD_DRAW,
USP_SHIELD_UP_IDLE,
USP_SHIELD_IDLE_UP,
USP_SHIELD_UP,
USP_SHIELD_DOWN,
};
@ -900,6 +910,19 @@ enum deagle_e
DEAGLE_DRAW,
};
enum deagle_shield_e
{
DEAGLE_SHIELD_IDLE1,
DEAGLE_SHIELD_SHOOT,
DEAGLE_SHIELD_SHOOT2,
DEAGLE_SHIELD_SHOOT_EMPTY,
DEAGLE_SHIELD_RELOAD,
DEAGLE_SHIELD_DRAW,
DEAGLE_SHIELD_IDLE_UP,
DEAGLE_SHIELD_UP,
DEAGLE_SHIELD_DOWN,
};
class CDEAGLE: public CBasePlayerWeapon
{
public:
@ -1065,7 +1088,7 @@ enum glock18_shield_e
GLOCK18_SHIELD_SHOOT_EMPTY,
GLOCK18_SHIELD_RELOAD,
GLOCK18_SHIELD_DRAW,
GLOCK18_SHIELD_IDLE,
GLOCK18_SHIELD_IDLE_UP,
GLOCK18_SHIELD_UP,
GLOCK18_SHIELD_DOWN,
};
@ -1180,7 +1203,7 @@ enum knife_shield_e
KNIFE_SHIELD_SLASH,
KNIFE_SHIELD_ATTACKHIT,
KNIFE_SHIELD_DRAW,
KNIFE_SHIELD_UPIDLE,
KNIFE_SHIELD_IDLE_UP,
KNIFE_SHIELD_UP,
KNIFE_SHIELD_DOWN,
};
@ -1249,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; }
@ -1310,7 +1333,6 @@ private:
const float M3_MAX_SPEED = 230.0f;
const float M3_DAMAGE = 20.0f;
const Vector M3_CONE_VECTOR = Vector(0.0675, 0.0675, 0.0); // special shotgun spreads
enum m3_e
{
@ -1741,7 +1763,6 @@ private:
const float XM1014_MAX_SPEED = 240.0f;
const float XM1014_DAMAGE = 20.0f;
const Vector XM1014_CONE_VECTOR = Vector(0.0725, 0.0725, 0.0); // special shotgun spreads
enum xm1014_e
{
@ -1858,6 +1879,19 @@ enum fiveseven_e
FIVESEVEN_DRAW,
};
enum fiveseven_shield_e
{
FIVESEVEN_SHIELD_IDLE1,
FIVESEVEN_SHIELD_SHOOT,
FIVESEVEN_SHIELD_SHOOT2,
FIVESEVEN_SHIELD_SHOOT_EMPTY,
FIVESEVEN_SHIELD_RELOAD,
FIVESEVEN_SHIELD_DRAW,
FIVESEVEN_SHIELD_IDLE_UP,
FIVESEVEN_SHIELD_UP,
FIVESEVEN_SHIELD_DOWN,
};
class CFiveSeven: public CBasePlayerWeapon
{
public:
@ -2136,7 +2170,13 @@ int DamageDecal(CBaseEntity *pEntity, int bitsDamageType);
void DecalGunshot(TraceResult *pTrace, int iBulletType, bool ClientOnly, entvars_t *pShooter, bool bHitMetal);
void EjectBrass(const Vector &vecOrigin, const Vector &vecLeft, const Vector &vecVelocity, float rotation, int model, int soundtype, int entityIndex);
void EjectBrass2(const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype, entvars_t *pev);
void AddAmmoNameToAmmoRegistry(const char *szAmmoname);
int AddAmmoNameToAmmoRegistry(const char *szAmmoname);
void UTIL_PrecacheOtherWeapon(const char *szClassname);
BOOL CanAttack(float attack_time, float curtime, BOOL isPredicted);
float GetBaseAccuracy(WeaponIdType id);
#ifdef REGAMEDLL_API
void ClearMultiDamage_OrigFunc();
void ApplyMultiDamage_OrigFunc(entvars_t *pevInflictor, entvars_t *pevAttacker);
void AddMultiDamage_OrigFunc(entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType);
#endif

@ -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)
{
@ -529,10 +531,21 @@ WeaponInfoStruct *GetWeaponInfo(const char *weaponName)
return nullptr;
}
WeaponInfoStruct *GetDefaultWeaponInfo(int weaponID)
{
for (auto& info : g_weaponInfo_default) {
if (info.id == weaponID) {
return &info;
}
}
return nullptr;
}
AmmoInfoStruct *GetAmmoInfo(const char *ammoName)
{
for (auto& info : g_ammoInfo) {
if (!Q_stricmp(info.ammoName1, ammoName)) {
if (info.ammoName1 && !Q_stricmp(info.ammoName1, ammoName)) {
return &info;
}
}
@ -555,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)

@ -318,25 +318,12 @@ enum AmmoBuyAmount
AMMO_SMOKEGRENADE_BUY = 1,
};
enum shieldgun_e
{
SHIELDGUN_IDLE,
SHIELDGUN_SHOOT1,
SHIELDGUN_SHOOT2,
SHIELDGUN_SHOOT_EMPTY,
SHIELDGUN_RELOAD,
SHIELDGUN_DRAW,
SHIELDGUN_DRAWN_IDLE,
SHIELDGUN_UP,
SHIELDGUN_DOWN,
};
// custom
enum shieldgren_e
{
SHIELDREN_IDLE = 4,
SHIELDREN_UP,
SHIELDREN_DOWN
SHIELDGREN_IDLE = 4, // 3 is last grenade viewmodel sequence
SHIELDGREN_UP,
SHIELDGREN_DOWN
};
enum InventorySlotType
@ -458,6 +445,8 @@ void WeaponInfoReset();
WeaponInfoStruct *GetWeaponInfo(int weaponID);
WeaponInfoStruct *GetWeaponInfo(const char *weaponName);
WeaponInfoStruct *GetDefaultWeaponInfo(int weaponID);
AmmoInfoStruct *GetAmmoInfo(AmmoType ammoID);
AmmoInfoStruct *GetAmmoInfo(const char *ammoName);

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

@ -73,6 +73,15 @@ void CAUG::SecondaryAttack()
else
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 90;
#ifdef REGAMEDLL_FIXES
if (TheBots)
{
TheBots->OnEvent(EVENT_WEAPON_ZOOMED, m_pPlayer);
}
m_pPlayer->ResetMaxSpeed();
#endif
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.3f;
}

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

@ -93,7 +93,7 @@ void CDEAGLE::PrimaryAttack()
void CDEAGLE::SecondaryAttack()
{
ShieldSecondaryFire(SHIELDGUN_UP, SHIELDGUN_DOWN);
ShieldSecondaryFire(DEAGLE_SHIELD_UP, DEAGLE_SHIELD_DOWN);
}
void CDEAGLE::DEAGLEFire(float flSpread, float flCycleTime, BOOL fUseSemi)
@ -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;
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
#ifdef REGAMEDLL_FIXES
if (m_pPlayer->HasShield())
#endif
{
SendWeaponAnim(SHIELDGUN_DRAWN_IDLE, UseDecrement() != FALSE);
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 20.0f;
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
SendWeaponAnim(DEAGLE_SHIELD_IDLE_UP, UseDecrement() != FALSE);
}
}
#ifdef REGAMEDLL_FIXES
else if (m_iClip)
{
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0625f;
SendWeaponAnim(DEAGLE_IDLE1, UseDecrement() != FALSE);
}
#endif
}
}

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

@ -92,7 +92,7 @@ void CFiveSeven::PrimaryAttack()
void CFiveSeven::SecondaryAttack()
{
ShieldSecondaryFire(SHIELDGUN_UP, SHIELDGUN_DOWN);
ShieldSecondaryFire(FIVESEVEN_SHIELD_UP, FIVESEVEN_SHIELD_DOWN);
}
void CFiveSeven::FiveSevenFire(float flSpread, float flCycleTime, BOOL fUseSemi)
@ -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();
}
@ -208,7 +212,7 @@ void CFiveSeven::WeaponIdle()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
SendWeaponAnim(SHIELDGUN_DRAWN_IDLE, UseDecrement() != FALSE);
SendWeaponAnim(FIVESEVEN_SHIELD_IDLE_UP, UseDecrement() != FALSE);
}
}
else if (m_iClip)

@ -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;
@ -142,7 +142,7 @@ bool CFlashbang::ShieldSecondaryFire(int iUpAnim, int iDownAnim)
void CFlashbang::SecondaryAttack()
{
ShieldSecondaryFire(SHIELDGUN_DRAW, SHIELDGUN_DRAWN_IDLE);
ShieldSecondaryFire(SHIELDGREN_UP, SHIELDGREN_DOWN);
}
void CFlashbang::SetPlayerShieldAnim()
@ -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");
}
}
@ -236,7 +236,7 @@ void CFlashbang::WeaponIdle()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
SendWeaponAnim(SHIELDREN_IDLE, UseDecrement() != FALSE);
SendWeaponAnim(SHIELDGREN_IDLE, UseDecrement() != FALSE);
}
}
else

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

@ -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();
}
@ -295,7 +298,7 @@ void CGLOCK18::WeaponIdle()
if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN)
{
SendWeaponAnim(GLOCK18_SHIELD_IDLE, UseDecrement() != FALSE);
SendWeaponAnim(GLOCK18_SHIELD_IDLE_UP, UseDecrement() != FALSE);
}
}
// only idle if the slid isn't back

Some files were not shown because too many files have changed in this diff Show More