diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 35d851a0c..64cd3d3d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,7 +73,7 @@ jobs: testdemos: name: 'Test demos' - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 container: s1lentq/testdemos:latest needs: [windows] @@ -140,7 +140,7 @@ jobs: linux: name: 'Linux' - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 container: s1lentq/linux86buildtools:latest steps: @@ -173,7 +173,11 @@ jobs: fi shell: bash - - name: Build using Intel C++ Compiler 19.0 + - name: Build using Intel C++ Compiler 19.0 (only for release) + if: | + github.event_name == 'release' && + github.event.action == 'published' && + startsWith(github.ref, 'refs/tags/') run: | rm -rf build-icc && CC=icc CXX=icpc cmake -B build-icc && cmake --build build-icc -j8 @@ -189,7 +193,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 + 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 regamedll/version/appversion.h publish/appversion.h mv dist/ publish/ @@ -221,7 +225,7 @@ jobs: publish: name: 'Publish' - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 needs: [windows, testdemos, linux] steps: diff --git a/.gitignore b/.gitignore index dc6d161e8..6aa9bce05 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.bat *.log *.lnk +*.aps **/msvc/Debug* **/msvc/Release* **/msvc/Tests diff --git a/README.md b/README.md index 85a5f2246..30a282525 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_round_restart_delay | 5 | - | - | Number of seconds to delay before restarting a round after a win. | | mp_hegrenade_penetration | 0 | 0 | 1 | Disable grenade damage through walls.
`0` disabled
`1` enabled | | mp_nadedrops | 0 | 0 | 2 | Drop a grenade after player death.
`0` disabled
`1` drop first available grenade
`2` drop all grenades | +| mp_weapondrop | 1 | 0 | 3 | Drop player weapon after death.
`0` do not drop weapons after death
`1` drop best/heaviest weapon after death
`2` drop active weapon after death
`3` drop all weapons after death (primary and secondary) | +| mp_ammodrop | 1 | 0 | 2 | Drop ammo on weapon boxes on death or manual drop.
`0` always keep ammo on player
`1` drop all ammo only after death
`2` drop all ammo whenever player drops a weapon | | mp_roundrespawn_time | 20 | 0 | - | Player cannot respawn until next round if more than N seconds has elapsed since the beginning round.
`-1` means no time limit
| | mp_auto_reload_weapons | 0 | 0 | 1 | Automatically reload each weapon on player spawn.
`0` disabled
`1` enabled | | mp_refill_bpammo_weapons | 0 | 0 | 2 | Refill amount of backpack ammo up to the max.
`0` disabled
`1` refill backpack ammo on player spawn
`2` refill backpack ammo on player spawn and on the purchase of the item | @@ -98,6 +100,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_give_player_c4 | 1 | 0 | 1 | Whether this map should spawn a C4 bomb for a player or not.
`0` disabled
`1` enabled | | mp_weapons_allow_map_placed | 1 | 0 | 1 | When set, map weapons (located on the floor by map) will be shown.
`0` hide all map weapons.
`1` enabled
`NOTE`: Effect will work after round restart. | | mp_free_armor | 0 | 0 | 2 | Give free armor on player spawn.
`0` disabled
`1` Give Kevlar
`2` Give Kevlar + Helmet | +| mp_team_flash | 1 | -1 | 1 | Sets the behaviour for Flashbangs on teammates.
`-1` Don't affect teammates neither flash owner
`0` Don't affect teammates
`1` Affects teammates | | mp_fadetoblack | 0 | 0 | 2 | Observer's screen will fade to black on kill event or permanent.
`0` No fade.
`1` Fade to black and won't be able to watch anybody.
`2` fade to black only on kill moment. | | mp_falldamage | 1 | 0 | 1 | Damage from falling.
`0` disabled
`1` enabled | | sv_allchat | 1 | 0 | 1 | Players can receive all other players text chat, team restrictions apply
`0` disabled
`1` enabled | @@ -110,6 +113,11 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_max_alive_name_changes | -1 | -1 | - | Maximum amount of nickname changes when alive
`-1` unlimited
`0` Blocks name changes
`>0` Allow to change arbitrary amount of nicks | | sv_legacy_restart_entities | 0 | 0 | 1 | Legacy restart of entities on new round
`0` disabled
`1` enabled | | sv_block_vote_commands | 0 | 0 | 1 | When set, blocks `vote` and `votemap` commands.
`0` disabled
`1` enabled | +| mp_dying_time | 3.0 | 0.0 | - | Time for switch to free observing after death.
`0` - disable spectating around death.
`>0.00001` - time delay to start spectate.
`NOTE`: The countdown starts when the player’s death animation is finished. | +| mp_deathmsg_flags | abc | 0 | - | Sets a flags for extra information in the player's death message.
`0` disabled
`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. | +| mp_assist_damage_threshold | 40 | 0 | 100 | Sets the percentage of damage needed to score an assist. | +| mp_freezetime_duck | 1 | 0 | 1 | Allow players to duck during freezetime.
`0` disabled
`1` enabled | +| mp_freezetime_jump | 1 | 0 | 1 | Allow players to jump during freezetime.
`0` disabled
`1` enabled | ## How to install zBot for CS 1.6? diff --git a/dep/cppunitlite/msvc/cppunitlite.vcxproj b/dep/cppunitlite/msvc/cppunitlite.vcxproj index fbda29b7b..9d0a3f21f 100644 --- a/dep/cppunitlite/msvc/cppunitlite.vcxproj +++ b/dep/cppunitlite/msvc/cppunitlite.vcxproj @@ -40,6 +40,7 @@ v140 v141 v142 + v143 MultiByte @@ -49,6 +50,7 @@ v140 v141 v142 + v143 true MultiByte diff --git a/dist/delta.lst b/dist/delta.lst new file mode 100644 index 000000000..7da4af32a --- /dev/null +++ b/dist/delta.lst @@ -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 ) +} diff --git a/dist/game.cfg b/dist/game.cfg index 364ec57bf..f7cb92c2f 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -78,6 +78,24 @@ mp_hegrenade_penetration "0" // Default value: "0" mp_nadedrops "0" +// Drop player weapon after death +// 0 - do not drop weapons after death +// 1 - drop best/heaviest weapon after death (default behaviour) +// 2 - drop active weapon after death +// 3 - drop all weapons after death (primary and secondary) +// NOTE: Grenades are dropped separately depending on mp_nadedrops value +// +// Default value: "1" +mp_weapondrop "1" + +// Drop ammo on weapon boxes on death or manual drop +// 0 - always keep ammo on player +// 1 - drop all ammo only after death (default behaviour) +// 2 - drop all ammo whenever player drops a weapon (NOTE: Other weapons may remain without ammo due to same ammo sharing) +// +// Default value: "1" +mp_ammodrop "1" + // Player cannot respawn until next round // if more than N seconds has elapsed since the beginning round // -1 - means no time limit @@ -456,6 +474,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 @@ -503,7 +529,6 @@ mp_hostages_rescued_ratio "1.0" // // Default value: "1" mp_legacy_vehicle_block "1" - // Maximum amount of nickname changes before next respawn. // -1 - unlimited (default behaviour) // 0 - Blocks name changes @@ -525,3 +550,41 @@ sv_legacy_restart_entities 0 // // Default value: "0" sv_block_vote_commands 0 + +// Time for switch to free observing after death. +// NOTE: The countdown starts when the player’s 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" diff --git a/regamedll/CMakeLists.txt b/regamedll/CMakeLists.txt index 1b329ca95..69f710b31 100644 --- a/regamedll/CMakeLists.txt +++ b/regamedll/CMakeLists.txt @@ -161,6 +161,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 +229,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" diff --git a/regamedll/common/const.h b/regamedll/common/const.h index 3c9873114..024a2a3d5 100644 --- a/regamedll/common/const.h +++ b/regamedll/common/const.h @@ -96,6 +96,12 @@ // Goes into globalvars_t.trace_flags #define FTRACE_SIMPLEBOX BIT(0) // Traceline with a simple box +// Custom flags that we can retrive in pfnShouldCollide +// Starting from BIT(16) to reserve space for more flags for Engine +#define FTRACE_BULLET BIT(16) +#define FTRACE_FLASH BIT(17) +#define FTRACE_KNIFE BIT(18) + // walkmove modes #define WALKMOVE_NORMAL 0 // normal walkmove #define WALKMOVE_WORLDONLY 1 // doesn't hit ANY entities, no matter what the solid type diff --git a/regamedll/dlls/API/CAPI_Impl.cpp b/regamedll/dlls/API/CAPI_Impl.cpp index 0fe10a490..5bb6b3940 100644 --- a/regamedll/dlls/API/CAPI_Impl.cpp +++ b/regamedll/dlls/API/CAPI_Impl.cpp @@ -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, @@ -71,7 +164,18 @@ ReGameFuncs_t g_ReGameApiFuncs = { PlantBomb_api, SpawnHeadGib_api, - SpawnRandomGibs_api + SpawnRandomGibs_api, + + 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); @@ -204,6 +308,34 @@ GAMEHOOK_REGISTRY(CBasePlayer_Pain); 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); + int CReGameApi::GetMajorVersion() { return REGAMEDLL_API_VERSION_MAJOR; } @@ -265,35 +397,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); -} - EXPOSE_SINGLE_INTERFACE(CReGameApi, IReGameApi, VRE_GAMEDLL_API_VERSION); diff --git a/regamedll/dlls/API/CAPI_Impl.h b/regamedll/dlls/API/CAPI_Impl.h index 1be3dd232..0548a841f 100644 --- a/regamedll/dlls/API/CAPI_Impl.h +++ b/regamedll/dlls/API/CAPI_Impl.h @@ -458,8 +458,8 @@ typedef IHookChainClassImpl CReGameHook_CSGameRu typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CSGameRules_RemoveGuns; // CHalfLifeMultiplay::GiveC4 hook -typedef IHookChainClassImpl CReGameHook_CSGameRules_GiveC4; -typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CSGameRules_GiveC4; +typedef IHookChainClassImpl CReGameHook_CSGameRules_GiveC4; +typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CSGameRules_GiveC4; // CHalfLifeMultiplay::ChangeLevel hook typedef IHookChainClassImpl CReGameHook_CSGameRules_ChangeLevel; @@ -641,6 +641,110 @@ typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBase typedef IHookChainClassImpl CReGameHook_CBasePlayer_JoiningThink; typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_JoiningThink; +// FreeGameRules hook +typedef IHookChainImpl CReGameHook_FreeGameRules; +typedef IHookChainRegistryImpl CReGameHookRegistry_FreeGameRules; + +// PM_LadderMove hook +typedef IHookChainImpl CReGameHook_PM_LadderMove; +typedef IHookChainRegistryImpl CReGameHookRegistry_PM_LadderMove; + +// PM_WaterJump hook +typedef IHookChainImpl CReGameHook_PM_WaterJump; +typedef IHookChainRegistryImpl CReGameHookRegistry_PM_WaterJump; + +// PM_CheckWaterJump hook +typedef IHookChainImpl CReGameHook_PM_CheckWaterJump; +typedef IHookChainRegistryImpl CReGameHookRegistry_PM_CheckWaterJump; + +// PM_Jump hook +typedef IHookChainImpl CReGameHook_PM_Jump; +typedef IHookChainRegistryImpl CReGameHookRegistry_PM_Jump; + +// PM_Duck hook +typedef IHookChainImpl CReGameHook_PM_Duck; +typedef IHookChainRegistryImpl CReGameHookRegistry_PM_Duck; + +// PM_UnDuck hook +typedef IHookChainImpl CReGameHook_PM_UnDuck; +typedef IHookChainRegistryImpl CReGameHookRegistry_PM_UnDuck; + +// PM_PlayStepSound hook +typedef IHookChainImpl CReGameHook_PM_PlayStepSound; +typedef IHookChainRegistryImpl CReGameHookRegistry_PM_PlayStepSound; + +// PM_AirAccelerate hook +typedef IHookChainImpl CReGameHook_PM_AirAccelerate; +typedef IHookChainRegistryImpl CReGameHookRegistry_PM_AirAccelerate; + +// ClearMultiDamage hook +typedef IHookChainImpl CReGameHook_ClearMultiDamage; +typedef IHookChainRegistryImpl CReGameHookRegistry_ClearMultiDamage; + +// AddMultiDamage hook +typedef IHookChainImpl CReGameHook_AddMultiDamage; +typedef IHookChainRegistryImpl CReGameHookRegistry_AddMultiDamage; + +// ApplyMultiDamage hook +typedef IHookChainImpl CReGameHook_ApplyMultiDamage; +typedef IHookChainRegistryImpl CReGameHookRegistry_ApplyMultiDamage; + +// BuyItem hook +typedef IHookChainImpl CReGameHook_BuyItem; +typedef IHookChainRegistryImpl CReGameHookRegistry_BuyItem; + +// CHalfLifeMultiplay::Think hook +typedef IHookChainClassImpl CReGameHook_CSGameRules_Think; +typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CSGameRules_Think; + +// CHalfLifeMultiplay::TeamFull hook +typedef IHookChainClassImpl CReGameHook_CSGameRules_TeamFull; +typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CSGameRules_TeamFull; + +// CHalfLifeMultiplay::TeamStacked hook +typedef IHookChainClassImpl CReGameHook_CSGameRules_TeamStacked; +typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CSGameRules_TeamStacked; + +// CHalfLifeMultiplay::PlayerGotWeapon hook +typedef IHookChainClassImpl CReGameHook_CSGameRules_PlayerGotWeapon; +typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CSGameRules_PlayerGotWeapon; + +// CHalfLifeMultiplay::SendDeathMessage hook +typedef IHookChainClassImpl CReGameHook_CSGameRules_SendDeathMessage; +typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CSGameRules_SendDeathMessage; + +// CBotManager::OnEvent hook +typedef IHookChainClassImpl CReGameHook_CBotManager_OnEvent; +typedef IHookChainRegistryClassEmptyImpl CReGameHookRegistry_CBotManager_OnEvent; + +// CBasePlayer::CheckTimeBasedDamage hook +typedef IHookChainClassImpl CReGameHook_CBasePlayer_CheckTimeBasedDamage; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_CheckTimeBasedDamage; + +// CBasePlayer::EntSelectSpawnPoint hook +typedef IHookChainClassImpl CReGameHook_CBasePlayer_EntSelectSpawnPoint; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_EntSelectSpawnPoint; + +// CBasePlayerWeapon::ItemPostFrame hook +typedef IHookChainClassImpl CReGameHook_CBasePlayerWeapon_ItemPostFrame; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayerWeapon_ItemPostFrame; + +// CBasePlayerWeapon::KickBack hook +typedef IHookChainClassImpl CReGameHook_CBasePlayerWeapon_KickBack; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayerWeapon_KickBack; + +// CBasePlayerWeapon::SendWeaponAnim hook +typedef IHookChainClassImpl CReGameHook_CBasePlayerWeapon_SendWeaponAnim; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayerWeapon_SendWeaponAnim; + +// CBasePlayer::PlayerDeathThink hook +typedef IHookChainClassImpl CReGameHook_CBasePlayer_PlayerDeathThink; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_PlayerDeathThink; + +// CBasePlayer::Observer_Think hook +typedef IHookChainClassImpl CReGameHook_CBasePlayer_Observer_Think; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_Observer_Think; + class CReGameHookchains: public IReGameHookchains { public: // CBasePlayer virtual @@ -774,6 +878,34 @@ class CReGameHookchains: public IReGameHookchains { CReGameHookRegistry_CBasePlayer_DeathSound m_CBasePlayer_DeathSound; 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; + public: virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn(); virtual IReGameHookRegistry_CBasePlayer_Precache *CBasePlayer_Precache(); @@ -904,6 +1036,34 @@ class CReGameHookchains: public IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_Pain *CBasePlayer_Pain(); virtual IReGameHookRegistry_CBasePlayer_DeathSound *CBasePlayer_DeathSound(); 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(); }; extern CReGameHookchains g_ReGameHookchains; @@ -930,10 +1090,3 @@ class CReGameApi: public IReGameApi { 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); diff --git a/regamedll/dlls/API/CSEntity.cpp b/regamedll/dlls/API/CSEntity.cpp index 0e037d29e..00f7badc6 100644 --- a/regamedll/dlls/API/CSEntity.cpp +++ b/regamedll/dlls/API/CSEntity.cpp @@ -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); } diff --git a/regamedll/dlls/API/CSPlayer.cpp b/regamedll/dlls/API/CSPlayer.cpp index 96fab9054..ad368bbb9 100644 --- a/regamedll/dlls/API/CSPlayer.cpp +++ b/regamedll/dlls/API/CSPlayer.cpp @@ -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); } @@ -110,19 +112,16 @@ EXT_FUNC bool CCSPlayer::JoinTeam(TeamName team) } } + bool bAddFrags = false; if (pPlayer->pev->deadflag == DEAD_NO) { - ClientKill(pPlayer->edict()); - pPlayer->pev->frags++; + if (pPlayer->Kill()) + { + bAddFrags = true; + } } - MESSAGE_BEGIN(MSG_ALL, gmsgScoreInfo); - WRITE_BYTE(ENTINDEX(pPlayer->edict())); - WRITE_SHORT(int(pPlayer->pev->frags)); - WRITE_SHORT(pPlayer->m_iDeaths); - WRITE_SHORT(0); - WRITE_SHORT(0); - MESSAGE_END(); + pPlayer->AddPoints(bAddFrags, TRUE); // Switch their actual team... pPlayer->m_bTeamChanged = true; @@ -151,15 +150,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")) @@ -209,39 +200,34 @@ EXT_FUNC bool CCSPlayer::RemovePlayerItemEx(const char* pszItemName, bool bRemov auto pItem = GetItemByName(pszItemName); if (pItem) { - if (FClassnameIs(pItem->pev, "weapon_c4")) { - pPlayer->m_bHasC4 = false; - pPlayer->pev->body = 0; - pPlayer->SetBombIcon(FALSE); - pPlayer->SetProgressBarTime(0); - } - if (pItem->IsWeapon()) { - if (pItem == pPlayer->m_pActiveItem) { - ((CBasePlayerWeapon *)pItem)->RetireWeapon(); + // These weapons have a unique type of ammo that is used only by them + // If a weapon is removed, its ammo is also reduced, unless the ammo can be used by another weapon + if (!bRemoveAmmo && (IsGrenadeWeapon(pItem->m_iId) || pItem->m_iId == WEAPON_C4)) + { + if (pPlayer->m_rgAmmo[pItem->PrimaryAmmoIndex()] > 0) + pPlayer->m_rgAmmo[pItem->PrimaryAmmoIndex()]--; + + // Hold the weapon until it runs out of ammo + if (pPlayer->m_rgAmmo[pItem->PrimaryAmmoIndex()] > 0) + return true; // ammo was reduced, this will be considered a successful result } if (bRemoveAmmo) { - pPlayer->m_rgAmmo[ pItem->PrimaryAmmoIndex() ] = 0; - } - } - - if (pPlayer->RemovePlayerItem(pItem)) { - pPlayer->pev->weapons &= ~(1 << pItem->m_iId); - // No more weapon - if ((pPlayer->pev->weapons & ~(1 << WEAPON_SUIT)) == 0) { - pPlayer->m_iHideHUD |= HIDEHUD_WEAPONS; + pPlayer->m_rgAmmo[pItem->PrimaryAmmoIndex()] = 0; } - pItem->Kill(); + if (pItem == pPlayer->m_pActiveItem) { + ((CBasePlayerWeapon *)pItem)->RetireWeapon(); - if (!pPlayer->m_rgpPlayerItems[PRIMARY_WEAPON_SLOT]) { - pPlayer->m_bHasPrimary = false; + if (pItem->CanHolster() && pItem != pPlayer->m_pActiveItem && !(pPlayer->pev->weapons &(1 << pItem->m_iId))) { + return true; + } } - - return true; } + + return pItem->DestroyItem(); } return false; @@ -258,11 +244,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"); @@ -275,7 +263,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) @@ -303,14 +291,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() @@ -514,6 +502,21 @@ EXT_FUNC bool CCSPlayer::HintMessageEx(const char *pMessage, float duration, boo return BasePlayer()->HintMessageEx(pMessage, duration, bDisplayIfPlayerDead, bOverride); } +EXT_FUNC void CCSPlayer::Reset() +{ + BasePlayer()->Reset(); +} + +EXT_FUNC void CCSPlayer::OnSpawnEquip(bool addDefault, bool equipGame) +{ + BasePlayer()->OnSpawnEquip(addDefault, equipGame); +} + +EXT_FUNC void CCSPlayer::SetScoreboardAttributes(CBasePlayer *destination) +{ + BasePlayer()->SetScoreboardAttributes(destination); +} + EXT_FUNC bool CCSPlayer::CheckActivityInGame() { const CBasePlayer* pPlayer = BasePlayer(); @@ -526,7 +529,7 @@ EXT_FUNC bool CCSPlayer::CheckActivityInGame() return (fabs(deltaYaw) >= 0.1f && fabs(deltaPitch) >= 0.1f); } -void CCSPlayer::Reset() +void CCSPlayer::ResetVars() { m_szModel[0] = '\0'; @@ -542,6 +545,18 @@ void CCSPlayer::Reset() m_bAutoBunnyHopping = false; m_bMegaBunnyJumping = false; m_iAliveNameChanges = 0; + 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; + } } void CCSPlayer::OnSpawn() @@ -549,6 +564,7 @@ void CCSPlayer::OnSpawn() m_bGameForcingRespawn = false; m_flRespawnPending = 0.0f; m_iAliveNameChanges = 0; + m_DamageList.Clear(); } void CCSPlayer::OnKilled() @@ -566,3 +582,33 @@ void CCSPlayer::OnKilled() } #endif } + +void CCSPlayer::OnConnect() +{ + ResetVars(); + 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; +} diff --git a/regamedll/dlls/API/CSPlayerWeapon.cpp b/regamedll/dlls/API/CSPlayerWeapon.cpp new file mode 100644 index 000000000..51a5fd806 --- /dev/null +++ b/regamedll/dlls/API/CSPlayerWeapon.cpp @@ -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); +} diff --git a/regamedll/dlls/animating.cpp b/regamedll/dlls/animating.cpp index 8e7d84334..9e104f22e 100644 --- a/regamedll/dlls/animating.cpp +++ b/regamedll/dlls/animating.cpp @@ -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); diff --git a/regamedll/dlls/animation.cpp b/regamedll/dlls/animation.cpp index 83c0bd403..7d5df6f07 100644 --- a/regamedll/dlls/animation.cpp +++ b/regamedll/dlls/animation.cpp @@ -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; } diff --git a/regamedll/dlls/animation.h b/regamedll/dlls/animation.h index 54af21a8c..7889a140b 100644 --- a/regamedll/dlls/animation.h +++ b/regamedll/dlls/animation.h @@ -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); diff --git a/regamedll/dlls/basemonster.cpp b/regamedll/dlls/basemonster.cpp index a134d99c7..bfa9a1e14 100644 --- a/regamedll/dlls/basemonster.cpp +++ b/regamedll/dlls/basemonster.cpp @@ -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)) diff --git a/regamedll/dlls/basemonster.h b/regamedll/dlls/basemonster.h index dbdc22c66..63f8d8d41 100644 --- a/regamedll/dlls/basemonster.h +++ b/regamedll/dlls/basemonster.h @@ -34,7 +34,7 @@ enum { - ITBD_PARALLYZE = 0, + ITBD_PARALYZE = 0, ITBD_NERVE_GAS, ITBD_POISON, ITBD_RADIATION, diff --git a/regamedll/dlls/bot/cs_bot.h b/regamedll/dlls/bot/cs_bot.h index 27d8bd59e..345e11fbd 100644 --- a/regamedll/dlls/bot/cs_bot.h +++ b/regamedll/dlls/bot/cs_bot.h @@ -42,9 +42,6 @@ enum BOT_PROGGRESS_HIDE, // hide status bar progress }; -extern int _navAreaCount; -extern int _currentIndex; - class CCSBot; class BotChatterInterface; @@ -970,7 +967,6 @@ class CCSBot: public CBot const CNavNode *m_navNodeList; CNavNode *m_currentNode; NavDirType m_generationDir; - NavAreaList::iterator m_analyzeIter; enum ProcessType { diff --git a/regamedll/dlls/bot/cs_bot_learn.cpp b/regamedll/dlls/bot/cs_bot_learn.cpp index bb6df51d2..76edded7a 100644 --- a/regamedll/dlls/bot/cs_bot_learn.cpp +++ b/regamedll/dlls/bot/cs_bot_learn.cpp @@ -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"); } diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp index 786a3f08f..7793e8151 100644 --- a/regamedll/dlls/bot/cs_bot_manager.cpp +++ b/regamedll/dlls/bot/cs_bot_manager.cpp @@ -78,7 +78,7 @@ CCSBotManager::CCSBotManager() char *dataPointer = (char *)LOAD_FILE_FOR_ME((char *)filename, &dataLength); if (!dataPointer) { - TheBotProfiles->Init("BotProfile.db"); + TheBotProfiles->Init(cv_bot_profile_db.string); } else { @@ -410,11 +410,7 @@ void CCSBotManager::ServerCommand(const char *pcmd) { if (killThemAll || FStrEq(name, msg)) { -#ifdef REGAMEDLL_FIXES - ClientKill(pPlayer->edict()); -#else - pPlayer->TakeDamage(pPlayer->pev, pPlayer->pev, 9999.9f, DMG_CRUSH); -#endif + pPlayer->Kill(); } } } @@ -634,11 +630,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")) diff --git a/regamedll/dlls/bot/cs_bot_pathfind.cpp b/regamedll/dlls/bot/cs_bot_pathfind.cpp index 3b733ea14..00386be7b 100644 --- a/regamedll/dlls/bot/cs_bot_pathfind.cpp +++ b/regamedll/dlls/bot/cs_bot_pathfind.cpp @@ -1294,7 +1294,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; diff --git a/regamedll/dlls/bot/cs_bot_update.cpp b/regamedll/dlls/bot/cs_bot_update.cpp index 635360d03..37d496659 100644 --- a/regamedll/dlls/bot/cs_bot_update.cpp +++ b/regamedll/dlls/bot/cs_bot_update.cpp @@ -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)) diff --git a/regamedll/dlls/bot/states/cs_bot_idle.cpp b/regamedll/dlls/bot/states/cs_bot_idle.cpp index 125d5fee4..e38bde885 100644 --- a/regamedll/dlls/bot/states/cs_bot_idle.cpp +++ b/regamedll/dlls/bot/states/cs_bot_idle.cpp @@ -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 diff --git a/regamedll/dlls/buttons.cpp b/regamedll/dlls/buttons.cpp index c559f8c03..8e38b369f 100644 --- a/regamedll/dlls/buttons.cpp +++ b/regamedll/dlls/buttons.cpp @@ -671,7 +671,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 +688,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 +724,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 +763,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 +776,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 +884,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; diff --git a/regamedll/dlls/career_tasks.cpp b/regamedll/dlls/career_tasks.cpp index 0b0c45a56..200c67558 100644 --- a/regamedll/dlls/career_tasks.cpp +++ b/regamedll/dlls/career_tasks.cpp @@ -136,10 +136,14 @@ void CCareerTask::OnWeaponKill(int weaponId, int weaponClassId, bool headshot, b if (!pHostage->IsAlive()) continue; +#ifndef REGAMEDLL_FIXES if (!pHostage->IsFollowingSomeone()) continue; if (pHostage->m_target == pVictim) +#else + if (pHostage->IsFollowing(pVictim)) +#endif hostagesCount++; } @@ -211,11 +215,14 @@ void CCareerTask::OnEvent(GameEventType event, CBasePlayer *pVictim, CBasePlayer { if (!pHostage->IsAlive()) continue; - +#ifndef REGAMEDLL_FIXES if (!pHostage->IsFollowingSomeone()) continue; if (pHostage->m_target == pAttacker) +#else + if (pHostage->IsFollowing(pAttacker)) +#endif hostagesCount++; } diff --git a/regamedll/dlls/cbase.cpp b/regamedll/dlls/cbase.cpp index 9bf5abef0..1d706299b 100644 --- a/regamedll/dlls/cbase.cpp +++ b/regamedll/dlls/cbase.cpp @@ -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; } @@ -1039,6 +1059,9 @@ void CBaseEntity::__API_HOOK(FireBullets)(ULONG cShots, VectorRef vecSrc, Vector vecDir = vecDirShooting + x * vecSpread.x * vecRight + y * vecSpread.y * vecUp; vecEnd = vecSrc + vecDir * flDistance; +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_BULLET; +#endif UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), &tr); tracer = 0; @@ -1182,6 +1205,9 @@ void CBaseEntity::__API_HOOK(FireBuckshots)(ULONG cShots, VectorRef vecSrc, Vect vecDir = vecDirShooting + x * vecSpread.x * vecRight + y * vecSpread.y * vecUp; vecEnd = vecSrc + vecDir * flDistance; +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_BULLET; +#endif UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), &tr); tracer = 0; @@ -1236,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) @@ -1334,9 +1360,14 @@ VectorRef CBaseEntity::__API_HOOK(FireBullets3)(VectorRef vecSrc, VectorRef vecD float flDamageModifier = 0.5; + int iStartPenetration = iPenetration; while (iPenetration != 0) { ClearMultiDamage(); + +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_BULLET; +#endif UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev), &tr); if (TheBots && tr.flFraction != 1.0f) @@ -1390,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; @@ -1449,6 +1482,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; } diff --git a/regamedll/dlls/cbase.h b/regamedll/dlls/cbase.h index 1e11bbeef..8149356fa 100644 --- a/regamedll/dlls/cbase.h +++ b/regamedll/dlls/cbase.h @@ -242,8 +242,16 @@ class CBaseEntity { 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 @@ class CBaseAnimating: public CBaseDelay { 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); diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index 0440308d5..2cf9dbd63 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -375,29 +375,13 @@ void EXT_FUNC ClientKill(edict_t *pEntity) entvars_t *pev = &pEntity->v; CBasePlayer *pPlayer = CBasePlayer::Instance(pev); - if (pPlayer->GetObserverMode() != OBS_NONE) - return; - - if (pPlayer->m_iJoiningState != JOINED) - return; - // prevent suiciding too often if (pPlayer->m_fNextSuicideTime > gpGlobals->time) return; - pPlayer->m_LastHitGroup = HITGROUP_GENERIC; - // don't let them suicide for 1 second after suiciding pPlayer->m_fNextSuicideTime = gpGlobals->time + 1.0f; - - // have the player kill themself - pEntity->v.health = 0; - pPlayer->Killed(pev, GIB_NEVER); - - if (CSGameRules()->m_pVIP == pPlayer) - { - CSGameRules()->m_iConsecutiveVIP = 10; - } + pPlayer->Kill(); } LINK_HOOK_VOID_CHAIN(ShowMenu, (CBasePlayer *pPlayer, int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText), pPlayer, bitsValidSlots, nDisplayTime, fNeedMore, pszText) @@ -637,6 +621,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; @@ -686,10 +673,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) { @@ -707,7 +696,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 @@ -743,7 +737,7 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity) } #ifdef REGAMEDLL_API - pPlayer->CSPlayer()->Reset(); + pPlayer->CSPlayer()->OnConnect(); #endif UTIL_ClientPrintAll(HUD_PRINTNOTIFY, "#Game_connected", (sName[0] != '\0') ? sName : ""); @@ -1210,7 +1204,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; @@ -1451,28 +1447,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; @@ -1490,7 +1471,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); @@ -1774,6 +1754,9 @@ BOOL EXT_FUNC __API_HOOK(HandleMenu_ChooseTeam)(CBasePlayer *pPlayer, int slot) } TeamName team = UNASSIGNED; +#ifdef REGAMEDLL_FIXES + bool bAddFrags = false; +#endif switch (slot) { @@ -1856,10 +1839,15 @@ BOOL EXT_FUNC __API_HOOK(HandleMenu_ChooseTeam)(CBasePlayer *pPlayer, int slot) { if (pPlayer->m_iTeam != UNASSIGNED && pPlayer->pev->deadflag == DEAD_NO) { - ClientKill(pPlayer->edict()); - - // add 1 to frags to balance out the 1 subtracted for killing yourself - pPlayer->pev->frags++; + if (pPlayer->Kill()) + { + // add 1 to frags to balance out the 1 subtracted for killing yourself +#ifdef REGAMEDLL_FIXES + bAddFrags = true; +#else + pPlayer->pev->frags++; +#endif + } } pPlayer->RemoveAllItems(TRUE); @@ -1895,15 +1883,15 @@ BOOL EXT_FUNC __API_HOOK(HandleMenu_ChooseTeam)(CBasePlayer *pPlayer, int slot) #ifndef REGAMEDLL_FIXES MESSAGE_BEGIN(MSG_BROADCAST, gmsgScoreInfo); -#else - MESSAGE_BEGIN(MSG_ALL, gmsgScoreInfo); -#endif WRITE_BYTE(ENTINDEX(pPlayer->edict())); WRITE_SHORT(int(pPlayer->pev->frags)); WRITE_SHORT(pPlayer->m_iDeaths); WRITE_SHORT(0); WRITE_SHORT(0); MESSAGE_END(); +#else + pPlayer->AddPoints(bAddFrags, TRUE); +#endif pPlayer->m_pIntroCamera = nullptr; pPlayer->m_bTeamChanged = true; @@ -1926,7 +1914,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); } @@ -2087,10 +2075,10 @@ BOOL EXT_FUNC __API_HOOK(HandleMenu_ChooseTeam)(CBasePlayer *pPlayer, int slot) pPlayer->m_iMenu = Menu_ChooseAppearance; // Show the appropriate Choose Appearance menu - // This must come before ClientKill() for CheckWinConditions() to function properly + // This must come before pPlayer->Kill() for CheckWinConditions() to function properly if (pPlayer->pev->deadflag == DEAD_NO) { - ClientKill(pPlayer->edict()); + pPlayer->Kill(); } } @@ -2277,7 +2265,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); @@ -4840,6 +4828,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 } } @@ -4872,7 +4870,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; diff --git a/regamedll/dlls/client.h b/regamedll/dlls/client.h index ee98ddbca..68586b2a4 100644 --- a/regamedll/dlls/client.h +++ b/regamedll/dlls/client.h @@ -119,6 +119,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); diff --git a/regamedll/dlls/combat.cpp b/regamedll/dlls/combat.cpp index f5ec1ce15..4cbc485dc 100644 --- a/regamedll/dlls/combat.cpp +++ b/regamedll/dlls/combat.cpp @@ -4,7 +4,7 @@ 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++) { @@ -16,16 +16,30 @@ void PlayerBlind(CBasePlayer *pPlayer, entvars_t *pevInflictor, entvars_t *pevAt } } - 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) { +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_FLASH; +#endif UTIL_TraceLine(vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), tr); } @@ -87,6 +101,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; @@ -94,7 +121,6 @@ void RadiusFlash(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, } flAdjustedDamage = flDamage - (vecSrc - tr.vecEndPos).Length() * falloff; - if (flAdjustedDamage < 0) flAdjustedDamage = 0; @@ -287,6 +313,8 @@ void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker if (tr.flFraction != 1.0f) flAdjustedDamage = 0.0f; + else + pEntity->SetDmgPenetrationLevel(1); } #endif } diff --git a/regamedll/dlls/doors.cpp b/regamedll/dlls/doors.cpp index c16fe0083..ada7e6a82 100644 --- a/regamedll/dlls/doors.cpp +++ b/regamedll/dlls/doors.cpp @@ -215,7 +215,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 +494,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 +634,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. @@ -696,7 +696,7 @@ void CBaseDoor::DoorGoDown() } #ifdef DOOR_ASSERT - assert(m_toggle_state == TS_AT_TOP); + DbgAssert(m_toggle_state == TS_AT_TOP); #endif m_toggle_state = TS_GOING_DOWN; @@ -724,7 +724,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 +927,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 +1011,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) { diff --git a/regamedll/dlls/effects.cpp b/regamedll/dlls/effects.cpp index 16cc2e6ab..f934edd4b 100644 --- a/regamedll/dlls/effects.cpp +++ b/regamedll/dlls/effects.cpp @@ -1737,10 +1737,12 @@ Vector CBlood::BloodPosition(CBaseEntity *pActivator) void CBlood::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { + const Vector direction = Direction(); + if (pev->spawnflags & SF_BLOOD_STREAM) - UTIL_BloodStream(BloodPosition(pActivator), Direction(), (Color() == BLOOD_COLOR_RED) ? 70 : Color(), int(BloodAmount())); + UTIL_BloodStream(BloodPosition(pActivator), direction, (Color() == BLOOD_COLOR_RED) ? 70 : Color(), int(BloodAmount())); else - UTIL_BloodDrips(BloodPosition(pActivator), Direction(), Color(), int(BloodAmount())); + UTIL_BloodDrips(BloodPosition(pActivator), Color(), int(BloodAmount())); if (pev->spawnflags & SF_BLOOD_DECAL) { diff --git a/regamedll/dlls/ehandle.h b/regamedll/dlls/ehandle.h index 66897fbbe..9a8717826 100644 --- a/regamedll/dlls/ehandle.h +++ b/regamedll/dlls/ehandle.h @@ -176,7 +176,7 @@ inline int EntityHandle::GetSerialNumber() const template inline bool EntityHandle::operator==(T *pEntity) const { - assert(("EntityHandle::operator==: got a nullptr pointer!", pEntity != nullptr)); + DbgAssertMsg(pEntity != nullptr, "EntityHandle::operator==: got a nullptr pointer!"); if (m_serialnumber != pEntity->edict()->serialnumber) { @@ -221,10 +221,10 @@ template inline T *EntityHandle::operator->() { edict_t *pEdict = Get(); - assert(("EntityHandle::operator->: pointer is nullptr!", pEdict != nullptr)); + DbgAssertMsg(pEdict != nullptr, "EntityHandle::operator->: pointer is nullptr!"); T *pEntity = GET_PRIVATE(pEdict); - assert(("EntityHandle::operator->: pvPrivateData is nullptr!", pEntity != nullptr)); + DbgAssertMsg(pEntity != nullptr, "EntityHandle::operator->: pvPrivateData is nullptr!"); return pEntity; } diff --git a/regamedll/dlls/func_tank.cpp b/regamedll/dlls/func_tank.cpp index 1ca0e966e..e12c90768 100644 --- a/regamedll/dlls/func_tank.cpp +++ b/regamedll/dlls/func_tank.cpp @@ -297,11 +297,11 @@ void CFuncTank::StopControl() void CFuncTank::ControllerPostFrame() { - assert(m_pController != nullptr); - if (gpGlobals->time < m_flNextAttack) return; + Assert(m_pController != nullptr); + if (m_pController->pev->button & IN_ATTACK) { Vector vecForward; @@ -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() diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index fdfd26184..9b3e2f7b2 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -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 }; @@ -109,6 +110,8 @@ cvar_t maxmoney = { "mp_maxmoney", "16000", FCVAR_SERVER, 0.0f, nul cvar_t round_infinite = { "mp_round_infinite", "0", FCVAR_SERVER, 0.0f, nullptr }; cvar_t hegrenade_penetration = { "mp_hegrenade_penetration", "0", 0, 0.0f, nullptr }; cvar_t nadedrops = { "mp_nadedrops", "0", 0, 0.0f, nullptr }; +cvar_t weapondrop = { "mp_weapondrop", "1", 0, 1.0f, nullptr }; +cvar_t ammodrop = { "mp_ammodrop", "1", 0, 1.0f, nullptr }; cvar_t roundrespawn_time = { "mp_roundrespawn_time", "20", 0, 20.0f, nullptr }; cvar_t auto_reload_weapons = { "mp_auto_reload_weapons", "0", 0, 0.0f, nullptr }; cvar_t refill_bpammo_weapons = { "mp_refill_bpammo_weapons", "0", 0, 0.0f, nullptr }; // Useful for mods like DeathMatch, GunGame, ZombieMod etc @@ -158,11 +161,16 @@ cvar_t t_give_player_knife = { "mp_t_give_player_knife", "1", 0, 1 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 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 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 }; @@ -170,6 +178,10 @@ cvar_t max_alive_name_changes = { "mp_max_alive_name_changes", "-1", cvar_t legacy_restart_entities = { "sv_legacy_restart_entities", "0", 0, 0.0f, nullptr }; cvar_t sv_block_vote_commands = { "sv_block_vote_commands", "0", 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 }; + void GameDLL_Version_f() { if (Q_stricmp(CMD_ARGV(1), "version") != 0) @@ -220,8 +232,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 +248,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); @@ -353,6 +371,8 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&round_infinite); CVAR_REGISTER(&hegrenade_penetration); CVAR_REGISTER(&nadedrops); + CVAR_REGISTER(&weapondrop); + CVAR_REGISTER(&ammodrop); CVAR_REGISTER(&roundrespawn_time); CVAR_REGISTER(&auto_reload_weapons); CVAR_REGISTER(&refill_bpammo_weapons); @@ -406,6 +426,7 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&t_default_weapons_secondary); CVAR_REGISTER(&t_default_weapons_primary); CVAR_REGISTER(&free_armor); + CVAR_REGISTER(&teamflash); CVAR_REGISTER(&allchat); CVAR_REGISTER(&sv_autobunnyhopping); CVAR_REGISTER(&sv_enablebunnyhopping); @@ -414,6 +435,13 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&hostages_rescued_ratio); 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(&max_alive_name_changes); CVAR_REGISTER(&legacy_restart_entities); CVAR_REGISTER(&sv_block_vote_commands); @@ -438,3 +466,28 @@ void EXT_FUNC GameDLLInit() #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 +} diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index d1894aa2a..270ee8019 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -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; @@ -138,6 +139,8 @@ extern cvar_t maxmoney; extern cvar_t round_infinite; extern cvar_t hegrenade_penetration; extern cvar_t nadedrops; +extern cvar_t weapondrop; +extern cvar_t ammodrop; extern cvar_t roundrespawn_time; extern cvar_t auto_reload_weapons; extern cvar_t refill_bpammo_weapons; @@ -184,6 +187,7 @@ extern cvar_t t_give_player_knife; extern cvar_t t_default_weapons_secondary; extern cvar_t t_default_weapons_primary; extern cvar_t free_armor; +extern cvar_t teamflash; extern cvar_t allchat; extern cvar_t sv_autobunnyhopping; extern cvar_t sv_enablebunnyhopping; @@ -191,6 +195,11 @@ 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 max_alive_name_changes; extern cvar_t legacy_restart_entities; diff --git a/regamedll/dlls/gamerules.cpp b/regamedll/dlls/gamerules.cpp index d31e6b565..45210e212 100644 --- a/regamedll/dlls/gamerules.cpp +++ b/regamedll/dlls/gamerules.cpp @@ -141,3 +141,13 @@ CGameRules *EXT_FUNC __API_HOOK(InstallGameRules)() return new CHalfLifeMultiplay; } + +LINK_HOOK_VOID_CHAIN(FreeGameRules, (CGameRules **pGameRules), pGameRules) + +void EXT_FUNC __API_HOOK(FreeGameRules)(CGameRules **pGameRules) +{ + if (!pGameRules || !(*pGameRules)) + return; + + delete (*pGameRules); +} diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h index ed0111a50..e29aaba88 100644 --- a/regamedll/dlls/gamerules.h +++ b/regamedll/dlls/gamerules.h @@ -46,6 +46,7 @@ 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 int MAX_INTERMISSION_TIME = 120; // longest the intermission can last, in seconds @@ -186,6 +187,10 @@ enum GR_PLR_DROP_AMMO_ALL, GR_PLR_DROP_AMMO_ACTIVE, GR_PLR_DROP_AMMO_NO, + +#ifdef REGAMEDLL_ADD + GR_PLR_DROP_GUN_BEST, +#endif }; // custom enum @@ -202,7 +207,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 @@ -215,6 +220,41 @@ 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 +}; + class CItem; class CGameRules @@ -332,6 +372,7 @@ class CGameRules inline void SetGameOver() { m_bGameOver = true; } static float GetItemKillDelay(); static float GetRadioTimeout(); + static float GetDyingTime(); public: BOOL m_bFreezePeriod; // TRUE at beginning of round, set to FALSE when the period expires @@ -537,7 +578,7 @@ class CHalfLifeMultiplay: public CGameRules // 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(); @@ -560,10 +601,15 @@ class CHalfLifeMultiplay: public CGameRules 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: @@ -688,6 +734,10 @@ class CHalfLifeMultiplay: public CGameRules VFUNC bool HasRoundTimeExpired(); VFUNC bool IsBombPlanted(); + void SendDeathMessage(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, entvars_t *pevInflictor, const char *killerWeaponName, int iDeathMessageFlags, int iRarityOfKill); + int GetRarityOfKill(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, const char *killerWeaponName, bool bFlashAssist); + CBasePlayer *CheckAssistsToKill(CBaseEntity *pKiller, CBasePlayer *pVictim, bool &bFlashAssist); + private: void MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound(int iTeam); @@ -729,7 +779,7 @@ class CHalfLifeMultiplay: public CGameRules 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 @@ -831,9 +881,11 @@ extern CGameRules DLLEXPORT *g_pGameRules; #ifdef REGAMEDLL_API CGameRules *InstallGameRules_OrigFunc(); +void FreeGameRules_OrigFunc(CGameRules **pGameRules); #endif CGameRules *InstallGameRules(); +void FreeGameRules(CGameRules **pGameRules); // Gets us at the CS game rules inline CHalfLifeMultiplay *CSGameRules() @@ -915,6 +967,15 @@ inline float CGameRules::GetRadioTimeout() #endif } +inline float CGameRules::GetDyingTime() +{ +#ifdef REGAMEDLL_ADD + return dying_time.value; +#else + return DEATH_ANIMATION_TIME; +#endif +} + bool IsBotSpeaking(); void SV_Continue_f(); void SV_Tutor_Toggle_f(); diff --git a/regamedll/dlls/ggrenade.cpp b/regamedll/dlls/ggrenade.cpp index 48c52622c..f4b3e8809 100644 --- a/regamedll/dlls/ggrenade.cpp +++ b/regamedll/dlls/ggrenade.cpp @@ -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); @@ -1085,7 +1105,7 @@ void CGrenade::__API_HOOK(DefuseBombEnd)(CBasePlayer *pPlayer, bool bDefused) CSGameRules()->CheckWinConditions(); #ifdef REGAMEDLL_ADD - m_pBombDefuser->pev->frags += (int)give_c4_frags.value; + m_pBombDefuser->AddPoints((int)give_c4_frags.value, TRUE); #else // give the defuser credit for defusing the bomb m_pBombDefuser->pev->frags += 3.0f; @@ -1316,6 +1336,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 @@ -1440,7 +1467,7 @@ void CGrenade::C4Think() if (pBombOwner) { #ifdef REGAMEDLL_ADD - pBombOwner->pev->frags += (int)give_c4_frags.value; + pBombOwner->AddPoints((int)give_c4_frags.value, TRUE); #else pBombOwner->pev->frags += 3.0f; #endif diff --git a/regamedll/dlls/gib.cpp b/regamedll/dlls/gib.cpp index 5b9122d04..9301e283f 100644 --- a/regamedll/dlls/gib.cpp +++ b/regamedll/dlls/gib.cpp @@ -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; } } diff --git a/regamedll/dlls/h_export.cpp b/regamedll/dlls/h_export.cpp index 47189b833..486a3eedf 100644 --- a/regamedll/dlls/h_export.cpp +++ b/regamedll/dlls/h_export.cpp @@ -16,22 +16,7 @@ C_DLLEXPORT void WINAPI GiveFnptrsToDll(enginefuncs_t *pEnginefuncsTable, global 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 +26,4 @@ void __attribute__((destructor)) DllMainUnload() { } -#endif // _WIN32 +#endif // _LINUX diff --git a/regamedll/dlls/items.cpp b/regamedll/dlls/items.cpp index fc67bc57f..03620e362 100644 --- a/regamedll/dlls/items.cpp +++ b/regamedll/dlls/items.cpp @@ -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) diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index 19650e257..d16a53970 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -382,7 +382,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() m_iNumTerrorist = 0; m_iNumSpawnableCT = 0; m_iNumSpawnableTerrorist = 0; - m_bMapHasCameras = FALSE; + m_bMapHasCameras = -1; m_iLoserBonus = m_rgRewardAccountRules[RR_LOSER_BONUS_DEFAULT]; m_iNumConsecutiveCTLoses = 0; @@ -696,9 +696,9 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(CleanUpMap)() PLAYBACK_EVENT((FEV_GLOBAL | FEV_RELIABLE), 0, m_usResetDecals); } -LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2(CHalfLifeMultiplay, CSGameRules, GiveC4) +LINK_HOOK_CLASS_CUSTOM_CHAIN2(CBasePlayer *, CHalfLifeMultiplay, CSGameRules, GiveC4) -void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(GiveC4)() +CBasePlayer *EXT_FUNC CHalfLifeMultiplay::__API_HOOK(GiveC4)() { int iTeamCount; int iTemp = 0; @@ -759,7 +759,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(GiveC4)() { #ifdef REGAMEDLL_FIXES // we already have bomber - return; + return pPlayer; #endif } } @@ -787,10 +787,12 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(GiveC4)() if (pPlayer->pev->deadflag != DEAD_NO || pPlayer->m_iTeam != TERRORIST) continue; - pPlayer->MakeBomber(); - return; + if (pPlayer->MakeBomber()) + return pPlayer; } } + + return nullptr; } void CHalfLifeMultiplay::QueueCareerRoundEndMenu(float tmDelay, int iWinStatus) @@ -2050,6 +2052,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)() #endif pPlayer->RoundRespawn(); + +#ifdef REGAMEDLL_ADD + FireTargets("game_entity_restart", pPlayer, nullptr, USE_TOGGLE, 0.0); +#endif } // Gooseman : The following code fixes the HUD icon bug @@ -2088,6 +2094,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)() m_bTargetBombed = m_bBombDefused = false; m_bLevelInitialized = false; m_bCompleteReset = false; + +#ifdef REGAMEDLL_ADD + FireTargets("game_round_start", nullptr, nullptr, USE_TOGGLE, 0.0); +#endif } BOOL CHalfLifeMultiplay::IsThereABomber() @@ -2129,7 +2139,9 @@ BOOL CHalfLifeMultiplay::IsThereABomb() return FALSE; } -BOOL CHalfLifeMultiplay::TeamFull(int team_id) +LINK_HOOK_CLASS_CUSTOM_CHAIN(BOOL, CHalfLifeMultiplay, CSGameRules, TeamFull, (int team_id), team_id) + +BOOL EXT_FUNC CHalfLifeMultiplay::__API_HOOK(TeamFull)(int team_id) { switch (team_id) { @@ -2143,8 +2155,10 @@ BOOL CHalfLifeMultiplay::TeamFull(int team_id) return FALSE; } +LINK_HOOK_CLASS_CUSTOM_CHAIN(BOOL, CHalfLifeMultiplay, CSGameRules, TeamStacked, (int newTeam_id, int curTeam_id), newTeam_id, curTeam_id) + // checks to see if the desired team is stacked, returns true if it is -BOOL CHalfLifeMultiplay::TeamStacked(int newTeam_id, int curTeam_id) +BOOL EXT_FUNC CHalfLifeMultiplay::__API_HOOK(TeamStacked)(int newTeam_id, int curTeam_id) { // players are allowed to change to their own team if (newTeam_id == curTeam_id) @@ -2377,7 +2391,9 @@ void CHalfLifeMultiplay::PickNextVIP() } } -void CHalfLifeMultiplay::Think() +LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2(CHalfLifeMultiplay, CSGameRules, Think) + +void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(Think)() { MonitorTutorStatus(); m_VoiceGameMgr.Update(gpGlobals->frametime); @@ -2400,7 +2416,7 @@ void CHalfLifeMultiplay::Think() MESSAGE_BEGIN(MSG_ALL, gmsgForceCam); WRITE_BYTE(forcecamera.value != 0); WRITE_BYTE(forcechasecam.value != 0); - WRITE_BYTE(fadetoblack.value != 0); + WRITE_BYTE(fadetoblack.value == FADETOBLACK_STAY); MESSAGE_END(); m_flForceCameraValue = forcecamera.value; @@ -3085,17 +3101,11 @@ void CHalfLifeMultiplay::CheckLevelInitialized() { // Count the number of spawn points for each team // This determines the maximum number of players allowed on each - CBaseEntity *pEnt = nullptr; - - m_iSpawnPointCount_Terrorist = 0; - m_iSpawnPointCount_CT = 0; - - while ((pEnt = UTIL_FindEntityByClassname(pEnt, "info_player_deathmatch"))) - m_iSpawnPointCount_Terrorist++; - - while ((pEnt = UTIL_FindEntityByClassname(pEnt, "info_player_start"))) - m_iSpawnPointCount_CT++; - + m_iSpawnPointCount_Terrorist = UTIL_CountEntities("info_player_deathmatch"); + m_iSpawnPointCount_CT = UTIL_CountEntities("info_player_start"); +#ifdef REGAMEDLL_FIXES + m_bMapHasCameras = UTIL_CountEntities("trigger_camera"); +#endif m_bLevelInitialized = true; } } @@ -3463,7 +3473,7 @@ void CHalfLifeMultiplay::InitHUD(CBasePlayer *pl) MESSAGE_BEGIN(MSG_ONE, gmsgForceCam, nullptr, pl->edict()); WRITE_BYTE(forcecamera.value != 0); WRITE_BYTE(forcechasecam.value != 0); - WRITE_BYTE(fadetoblack.value != 0); + WRITE_BYTE(fadetoblack.value == FADETOBLACK_STAY); MESSAGE_END(); if (m_bGameOver) @@ -3588,13 +3598,14 @@ void CHalfLifeMultiplay::ClientDisconnected(edict_t *pClient) pPlayer->DropPlayerItem("weapon_c4"); } -#ifndef REGAMEDLL_FIXES - // Why ? DropPlayerItem didn't handle item_thighpack if (pPlayer->m_bHasDefuser) { - pPlayer->DropPlayerItem("item_thighpack"); - } +#ifdef REGAMEDLL_FIXES + SpawnDefuser(pPlayer->pev->origin, nullptr); +#else + pPlayer->DropPlayerItem("item_thighpack"); // DropPlayerItem didn't handle item_thighpack #endif + } if (pPlayer->m_bIsVIP) { @@ -3881,7 +3892,7 @@ BOOL EXT_FUNC CHalfLifeMultiplay::__API_HOOK(FPlayerCanRespawn)(CBasePlayer *pPl { // If this player just connected and fadetoblack is on, then maybe // the server admin doesn't want him peeking around. - if (fadetoblack.value != 0.0f) + if (fadetoblack.value == FADETOBLACK_STAY) { UTIL_ScreenFade(pPlayer, Vector(0, 0, 0), 3, 3, 255, (FFADE_OUT | FFADE_STAYOUT)); } @@ -3923,7 +3934,9 @@ LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN(CHalfLifeMultiplay, CSGameRules, PlayerKilled, void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor) { DeathNotice(pVictim, pKiller, pInflictor); - +#ifdef REGAMEDLL_FIXES + pVictim->pev->flags &= ~FL_FROZEN; +#endif pVictim->m_afPhysicsFlags &= ~PFLAG_ONTRAIN; pVictim->m_iDeaths++; pVictim->m_bNotKilled = false; @@ -3931,6 +3944,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, pVictim->m_iTrain = (TRAIN_NEW | TRAIN_OFF); SET_VIEW(ENT(pVictim->pev), ENT(pVictim->pev)); +#ifdef REGAMEDLL_FIXES + int iKillerFrags = 0; +#endif + CBasePlayer *peKiller = nullptr; CBaseEntity *ktmp = CBaseEntity::Instance(pKiller); @@ -3953,12 +3970,15 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, } FireTargets("game_playerdie", pVictim, pVictim, USE_TOGGLE, 0); - // Did the player kill himself? if (pVictim->pev == pKiller) { // Players lose a frag for killing themselves +#ifdef REGAMEDLL_FIXES + iKillerFrags = -1; +#else pKiller->frags -= 1; +#endif } else if (peKiller && peKiller->IsPlayer()) { @@ -3968,7 +3988,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, if (g_pGameRules->PlayerRelationship(pVictim, killer) == GR_TEAMMATE) { // if a player dies by from teammate +#ifdef REGAMEDLL_FIXES + iKillerFrags = -IPointsForKill(peKiller, pVictim); +#else pKiller->frags -= IPointsForKill(peKiller, pVictim); +#endif killer->AddAccount(PAYBACK_FOR_KILLED_TEAMMATES, RT_TEAMMATES_KILLED); killer->m_iTeamKills++; @@ -4008,7 +4032,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, else { // if a player dies in a deathmatch game and the killer is a client, award the killer some points +#ifdef REGAMEDLL_FIXES + iKillerFrags = IPointsForKill(peKiller, pVictim); +#else pKiller->frags += IPointsForKill(peKiller, pVictim); +#endif if (pVictim->m_bIsVIP) { @@ -4040,7 +4068,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, else { // killed by the world +#ifdef REGAMEDLL_FIXES + iKillerFrags = -1; +#else pKiller->frags -= 1; +#endif } // update the scores @@ -4063,7 +4095,9 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, if (ep && ep->Classify() == CLASS_PLAYER) { CBasePlayer *PK = static_cast(ep); - +#ifdef REGAMEDLL_FIXES + PK->AddPoints(iKillerFrags, TRUE); +#else MESSAGE_BEGIN(MSG_ALL, gmsgScoreInfo); WRITE_BYTE(ENTINDEX(PK->edict())); WRITE_SHORT(int(PK->pev->frags)); @@ -4071,7 +4105,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, WRITE_SHORT(0); WRITE_SHORT(PK->m_iTeam); MESSAGE_END(); - +#endif // let the killer paint another decal as soon as he'd like. PK->m_flNextDecalTime = gpGlobals->time; } @@ -4079,102 +4113,60 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerKilled)(CBasePlayer *pVictim, LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN(CHalfLifeMultiplay, CSGameRules, DeathNotice, (CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor), pVictim, pKiller, pevInflictor) -void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor) +void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim, entvars_t *pevKiller, entvars_t *pevInflictor) { // by default, the player is killed by the world - const char *killer_weapon_name = "world"; - int killer_index = 0; + CBasePlayer *pKiller = (pevKiller->flags & FL_CLIENT) ? CBasePlayer::Instance(pevKiller) : nullptr; + const char *killer_weapon_name = pVictim->GetKillerWeaponName(pevInflictor, pevKiller); -#ifndef REGAMEDLL_FIXES - // Hack to fix name change - char *tau = "tau_cannon"; - char *gluon = "gluon gun"; -#endif - - // Is the killer a client? - if (pKiller->flags & FL_CLIENT) + if (!TheTutor) { - killer_index = ENTINDEX(ENT(pKiller)); + int iRarityOfKill = 0; + int iDeathMessageFlags = PLAYERDEATH_POSITION; // set default bit + + CBasePlayer *pAssister = nullptr; - if (pevInflictor) + bool bFlashAssist = false; + if ((pAssister = CheckAssistsToKill(pKiller, pVictim, bFlashAssist))) { - if (pevInflictor == pKiller) - { - // If the inflictor is the killer, then it must be their current weapon doing the damage - CBasePlayer *pAttacker = CBasePlayer::Instance(pKiller); - if (pAttacker && pAttacker->IsPlayer()) - { - if (pAttacker->m_pActiveItem) - { - killer_weapon_name = pAttacker->m_pActiveItem->pszName(); - } - } - } - else - { - // it's just that easy - killer_weapon_name = STRING(pevInflictor->classname); - } + // Add a flag indicating the presence of an assistant who assisted in the kill + iDeathMessageFlags |= PLAYERDEATH_ASSISTANT; } - } - else -#ifdef REGAMEDLL_FIXES - if (pevInflictor) -#endif - { - killer_weapon_name = STRING(pevInflictor->classname); - } - // strip the monster_* or weapon_* from the inflictor's classname - const char cut_weapon[] = "weapon_"; - const char cut_monster[] = "monster_"; - const char cut_func[] = "func_"; - - // replace the code names with the 'real' names - if (!Q_strncmp(killer_weapon_name, cut_weapon, sizeof(cut_weapon) - 1)) - killer_weapon_name += sizeof(cut_weapon) - 1; + iRarityOfKill = GetRarityOfKill(pKiller, pVictim, pAssister, killer_weapon_name, bFlashAssist); + if (iRarityOfKill != 0) + { + // Add a flag indicating that the attacker killed the victim in a rare way + iDeathMessageFlags |= PLAYERDEATH_KILLRARITY; + } - else if (!Q_strncmp(killer_weapon_name, cut_monster, sizeof(cut_monster) - 1)) - killer_weapon_name += sizeof(cut_monster) - 1; + SendDeathMessage(pKiller, pVictim, pAssister, pevInflictor, killer_weapon_name, iDeathMessageFlags, iRarityOfKill); - else if (!Q_strncmp(killer_weapon_name, cut_func, sizeof(cut_func) - 1)) - killer_weapon_name += sizeof(cut_func) - 1; + // Updates the stats of who has killed whom + if (pKiller && pKiller->IsPlayer() && PlayerRelationship(pVictim, pKiller) != GR_TEAMMATE) + { + int iPlayerIndexKiller = pKiller->entindex(); + int iPlayerIndexVictim = pVictim->entindex(); - if (!TheTutor) - { - MESSAGE_BEGIN(MSG_ALL, gmsgDeathMsg); - WRITE_BYTE(killer_index); // the killer - WRITE_BYTE(ENTINDEX(pVictim->edict())); // the victim - WRITE_BYTE(pVictim->m_bHeadshotKilled); // is killed headshot - WRITE_STRING(killer_weapon_name); // what they were killed by (should this be a string?) - MESSAGE_END(); + pKiller->CSPlayer()->m_iNumKilledByUnanswered[iPlayerIndexVictim - 1] = 0; + pVictim->CSPlayer()->m_iNumKilledByUnanswered[iPlayerIndexKiller - 1]++; + } } - // This weapons from HL isn't it? -#ifndef REGAMEDLL_FIXES - if (!Q_strcmp(killer_weapon_name, "egon")) - killer_weapon_name = gluon; - - else if (!Q_strcmp(killer_weapon_name, "gauss")) - killer_weapon_name = tau; -#endif - // Did he kill himself? - if (pVictim->pev == pKiller) + if (pVictim->pev == pevKiller) { // killed self char *team = GetTeam(pVictim->m_iTeam); UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name); } - else if (pKiller->flags & FL_CLIENT) + else if (pevKiller->flags & FL_CLIENT) { - CBasePlayer *pAttacker = CBasePlayer::Instance(pKiller); - const char *VictimTeam = GetTeam(pVictim->m_iTeam); - const char *KillerTeam = (pAttacker && pAttacker->IsPlayer()) ? GetTeam(pAttacker->m_iTeam) : ""; + const char *KillerTeam = (pKiller && pKiller->IsPlayer()) ? GetTeam(pKiller->m_iTeam) : ""; - UTIL_LogPrintf("\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", STRING(pKiller->netname), GETPLAYERUSERID(ENT(pKiller)), GETPLAYERAUTHID(ENT(pKiller)), + UTIL_LogPrintf("\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", STRING(pevKiller->netname), GETPLAYERUSERID(ENT(pevKiller)), GETPLAYERAUTHID(ENT(pevKiller)), KillerTeam, STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), GETPLAYERAUTHID(pVictim->edict()), VictimTeam, killer_weapon_name); } else @@ -4197,7 +4189,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim, if (pevInflictor) WRITE_SHORT(ENTINDEX(ENT(pevInflictor))); // index number of secondary entity else - WRITE_SHORT(ENTINDEX(ENT(pKiller))); // index number of secondary entity + WRITE_SHORT(ENTINDEX(ENT(pevKiller))); // index number of secondary entity if (pVictim->m_bHeadshotKilled) WRITE_LONG(9 | DRC_FLAG_DRAMATIC | DRC_FLAG_SLOWMOTION); @@ -4207,8 +4199,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim, MESSAGE_END(); } +LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN(CHalfLifeMultiplay, CSGameRules, PlayerGotWeapon, (CBasePlayer *pPlayer, CBasePlayerItem *pWeapon), pPlayer, pWeapon) + // Player has grabbed a weapon that was sitting in the world -void CHalfLifeMultiplay::PlayerGotWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) +void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerGotWeapon)(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) { ; } @@ -4338,11 +4332,29 @@ LINK_HOOK_CLASS_CUSTOM_CHAIN(int, CHalfLifeMultiplay, CSGameRules, DeadPlayerWea int EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeadPlayerWeapons)(CBasePlayer *pPlayer) { - return GR_PLR_DROP_GUN_ACTIVE; +#ifdef REGAMEDLL_ADD + switch ((int)weapondrop.value) + { + case 3: + return GR_PLR_DROP_GUN_ALL; + case 2: + break; + case 1: + return GR_PLR_DROP_GUN_BEST; + default: + return GR_PLR_DROP_GUN_NO; + } +#endif + return GR_PLR_DROP_GUN_ACTIVE; // keep original value in return } int CHalfLifeMultiplay::DeadPlayerAmmo(CBasePlayer *pPlayer) { +#ifdef REGAMEDLL_ADD + if (ammodrop.value == 0.0f) + return GR_PLR_DROP_AMMO_NO; +#endif + return GR_PLR_DROP_AMMO_ACTIVE; } @@ -4876,7 +4888,7 @@ void CHalfLifeMultiplay::ProcessMapVote(CBasePlayer *pPlayer, int iVote) } } -LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2(CHalfLifeMultiplay, CSGameRules, ChangeLevel); +LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN2(CHalfLifeMultiplay, CSGameRules, ChangeLevel) // Server is changing to a new level, check mapcycle.txt for map name and setup info void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)() @@ -4903,7 +4915,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)() // find the map to change to char *mapcfile = (char *)CVAR_GET_STRING("mapcyclefile"); - assert(mapcfile != nullptr); + Assert(mapcfile != nullptr); szCommands[0] = '\0'; szRules[0] = '\0'; @@ -4939,7 +4951,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)() { keeplooking = false; - assert(item != nullptr); + Assert(item != nullptr); if (item->minplayers != 0) { @@ -5156,7 +5168,11 @@ void CHalfLifeMultiplay::ChangePlayerTeam(CBasePlayer *pPlayer, const char *pTea pPlayer->Killed(pPlayer->pev, bGib ? GIB_ALWAYS : GIB_NEVER); // add 1 to frags to balance out the 1 subtracted for killing yourself +#ifdef REGAMEDLL_FIXES + pPlayer->AddPoints(1, TRUE); +#else pPlayer->pev->frags++; +#endif } pPlayer->m_iTeam = newTeam; @@ -5184,3 +5200,217 @@ bool CHalfLifeMultiplay::CanPlayerBuy(CBasePlayer *pPlayer) const return true; } + +// +// Checks for assists in a kill situation +// +// This function analyzes damage records and player actions to determine the player who contributed the most to a kill, +// considering factors such as damage dealt and the use of flashbang grenades +// +// pKiller - The killer entity (Note: The killer may be a non-player) +// pVictim - The victim player +// bFlashAssist - A flag indicating whether a flashbang was used in the assist +// Returns - A pointer to the player who gave the most assistance, or NULL if appropriate assistant is not found +// +CBasePlayer *CHalfLifeMultiplay::CheckAssistsToKill(CBaseEntity *pKiller, CBasePlayer *pVictim, bool &bFlashAssist) +{ +#ifdef REGAMEDLL_ADD + CCSPlayer::DamageList_t &victimDamageTakenList = pVictim->CSPlayer()->GetDamageList(); + + float maxDamage = 0.0f; + int maxDamageIndex = -1; + CBasePlayer *maxDamagePlayer = nullptr; + + // Find the best assistant + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + const CCSPlayer::CDamageRecord_t &record = victimDamageTakenList[i - 1]; + if (record.flDamage == 0) + continue; // dealt no damage + + CBasePlayer *pAttackerPlayer = UTIL_PlayerByIndex(i); + if (!pAttackerPlayer || pAttackerPlayer->IsDormant()) + continue; // ignore idle clients + + CCSPlayer *pCSAttackerPlayer = pAttackerPlayer->CSPlayer(); + if (record.userId != pCSAttackerPlayer->m_iUserID) + continue; // another client? + + if (pAttackerPlayer == pKiller || pAttackerPlayer == pVictim) + continue; // ignore involved as killer or victim + + if (record.flDamage > maxDamage) + { + // If the assistant used a flash grenade to aid in the kill, + // make sure that the victim was blinded, and that the duration of the flash effect is still preserved + if (record.flFlashDurationTime > 0 && (!pVictim->IsBlind() || record.flFlashDurationTime <= gpGlobals->time)) + continue; + + maxDamage = record.flDamage; + maxDamagePlayer = pAttackerPlayer; + maxDamageIndex = i; + } + } + + // Note: Only the highest damaging player can be an assistant + // The condition checks if the damage dealt by the player exceeds a certain percentage of the victim's max health + // Default threshold is 40%, meaning the assistant must deal at least 40% of the victim's max health as damage + if (maxDamagePlayer && maxDamage > (assist_damage_threshold.value / 100.0f) * pVictim->pev->max_health) + { + bFlashAssist = victimDamageTakenList[maxDamageIndex - 1].flFlashDurationTime > 0; // if performed the flash assist + return maxDamagePlayer; + } +#endif + + return nullptr; +} + +// +// Check the rarity estimation for a kill +// +// Estimation to represent the rarity of a kill based on various factors, including assists with flashbang grenades, +// headshot kills, kills through walls, the killer's blindness, no-scope sniper rifle kills, and kills through smoke +// +// pKiller - The entity who committed the kill (Note: The killer may be a non-player) +// pVictim - The player who was killed +// pAssister - The assisting player (if any) +// killerWeaponName - The name of the weapon used by the killer +// bFlashAssist - A flag indicating whether an assist was made with a flashbang +// Returns an integer estimation representing the rarity of the kill +// Use with PLAYERDEATH_KILLRARITY flag to indicate a rare kill in death messages +// +int CHalfLifeMultiplay::GetRarityOfKill(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, const char *killerWeaponName, bool bFlashAssist) +{ + int iRarity = 0; + + // The killer player kills the victim with an assistant flashbang grenade + if (pAssister && bFlashAssist) + iRarity |= KILLRARITY_ASSISTEDFLASH; + + // The killer player kills the victim with a headshot + if (pVictim->m_bHeadshotKilled) + iRarity |= KILLRARITY_HEADSHOT; + + // The killer player was blind + CBasePlayer *pKillerPlayer = static_cast(pKiller); + if (pKillerPlayer && pKillerPlayer->IsPlayer()) + { + WeaponClassType weaponClass = AliasToWeaponClass(killerWeaponName); + if (pKillerPlayer != pVictim + && weaponClass != WEAPONCLASS_NONE + && weaponClass != WEAPONCLASS_KNIFE + && weaponClass != WEAPONCLASS_GRENADE) + { + // The killer player kills the victim through the walls + if (pVictim->GetDmgPenetrationLevel() > 0) + iRarity |= KILLRARITY_PENETRATED; + + if (pKillerPlayer->IsFullyBlind()) + iRarity |= KILLRARITY_KILLER_BLIND; + + // The killer player kills the victim with a sniper rifle with no scope + if (weaponClass == WEAPONCLASS_SNIPERRIFLE && pKillerPlayer->m_iClientFOV == DEFAULT_FOV) + iRarity |= KILLRARITY_NOSCOPE; + + // The killer player kills the victim through smoke + const Vector inEyePos = pKillerPlayer->EyePosition(); + if (TheCSBots()->IsLineBlockedBySmoke(&inEyePos, &pVictim->pev->origin)) + iRarity |= KILLRARITY_THRUSMOKE; + } + + // Calculate # of unanswered kills between killer & victim + // This is plus 1 as this function gets called before the stat is updated + // That is done so that the domination and revenge will be calculated prior + // to the death message being sent to the clients + int iAttackerEntityIndex = pKillerPlayer->entindex(); + Assert(iAttackerEntityIndex > 0 && iAttackerEntityIndex <= MAX_CLIENTS); + + int iKillsUnanswered = pVictim->CSPlayer()->m_iNumKilledByUnanswered[iAttackerEntityIndex - 1] + 1; + if (iKillsUnanswered == CS_KILLS_FOR_DOMINATION || pKillerPlayer->CSPlayer()->IsPlayerDominated(pVictim->entindex() - 1)) + { + // this is the Nth unanswered kill between killer and victim, killer is now dominating victim + iRarity |= KILLRARITY_DOMINATION; + + // set victim to be dominated by killer + pKillerPlayer->CSPlayer()->SetPlayerDominated(pVictim, true); + } + else if (pVictim->CSPlayer()->IsPlayerDominated(pKillerPlayer->entindex() - 1)) + { + // the killer killed someone who was dominating him, gains revenge + iRarity |= KILLRARITY_REVENGE; + + // set victim to no longer be dominating the killer + pVictim->CSPlayer()->SetPlayerDominated(pKillerPlayer, false); + } + } + + return iRarity; +} + +LINK_HOOK_CLASS_VOID_CUSTOM_CHAIN(CHalfLifeMultiplay, CSGameRules, SendDeathMessage, (CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, entvars_t *pevInflictor, const char *killerWeaponName, int iDeathMessageFlags, int iRarityOfKill), pKiller, pVictim, pAssister, pevInflictor, killerWeaponName, iDeathMessageFlags, iRarityOfKill) + +// +// Sends death messages to all players, including info about the killer, victim, weapon used, +// extra death flags, death position, assistant, and kill rarity +// +// +// pKiller - The entity who performed the kill (Note: The killer may be a non-player) +// pVictim - The player who was killed +// pAssister - The assisting player (if any) +// killerWeaponName - The name of the weapon used by the killer +// iDeathMessageFlags - Flags indicating extra death message info +// iRarityOfKill - An bitsums representing the rarity classification of the kill +// +void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(SendDeathMessage)(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, entvars_t *pevInflictor, const char *killerWeaponName, int iDeathMessageFlags, int iRarityOfKill) +{ + CBasePlayer *pKillerPlayer = (pKiller && pKiller->IsPlayer()) ? static_cast(pKiller) : nullptr; + + // Only the player can dominate the victim + if ((iRarityOfKill & KILLRARITY_DOMINATION) && pKillerPlayer && pVictim != pKillerPlayer) + { + // Sets the beginning of domination over the victim until he takes revenge + int iKillsUnanswered = pVictim->CSPlayer()->m_iNumKilledByUnanswered[pKillerPlayer->entindex() - 1] + 1; + if (iKillsUnanswered == CS_KILLS_FOR_DOMINATION) + iRarityOfKill |= KILLRARITY_DOMINATION_BEGAN; + } + + MESSAGE_BEGIN(MSG_ALL, gmsgDeathMsg); + WRITE_BYTE((pKiller && pKiller->IsPlayer()) ? pKiller->entindex() : 0); // the killer + WRITE_BYTE(pVictim->entindex()); // the victim + WRITE_BYTE(pVictim->m_bHeadshotKilled); // is killed headshot + WRITE_STRING(killerWeaponName); // what they were killed by (should this be a string?) + +#ifdef REGAMEDLL_ADD + iDeathMessageFlags &= UTIL_ReadFlags(deathmsg_flags.string); // leave only allowed bitsums for extra info + + // Send the victim's death position only + // 1. if it is not a free for all mode + // 2. if the attacker is a player and they are not teammates + if (IsFreeForAll() || !pKillerPlayer || PlayerRelationship(pKillerPlayer, pVictim) == GR_TEAMMATE) + iDeathMessageFlags &= ~PLAYERDEATH_POSITION; // do not send a position + + if (iDeathMessageFlags > 0) + { + WRITE_LONG(iDeathMessageFlags); + + // Writes the coordinates of the place where the victim died + // The victim has just been killed, so this usefully display 'X' dead icon on the HUD radar + if (iDeathMessageFlags & PLAYERDEATH_POSITION) + { + WRITE_COORD(pVictim->pev->origin.x); + WRITE_COORD(pVictim->pev->origin.y); + WRITE_COORD(pVictim->pev->origin.z); + } + + // Writes the index of the teammate who assisted in the kill + if (iDeathMessageFlags & PLAYERDEATH_ASSISTANT) + WRITE_BYTE(pAssister->entindex()); + + // Writes the rarity classification of the kill + if (iDeathMessageFlags & PLAYERDEATH_KILLRARITY) + WRITE_LONG(iRarityOfKill); + } +#endif + + MESSAGE_END(); +} diff --git a/regamedll/dlls/observer.cpp b/regamedll/dlls/observer.cpp index 336b7b3cc..4b3521a6c 100644 --- a/regamedll/dlls/observer.cpp +++ b/regamedll/dlls/observer.cpp @@ -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 @@ -532,9 +541,11 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_SetMode)(int 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(); Observer_CheckProperties(); -} +} \ No newline at end of file diff --git a/regamedll/dlls/observer.h b/regamedll/dlls/observer.h index 722c977a4..743936ff9 100644 --- a/regamedll/dlls/observer.h +++ b/regamedll/dlls/observer.h @@ -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); diff --git a/regamedll/dlls/pathcorner.cpp b/regamedll/dlls/pathcorner.cpp index 062d1716a..306c2819c 100644 --- a/regamedll/dlls/pathcorner.cpp +++ b/regamedll/dlls/pathcorner.cpp @@ -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[] = diff --git a/regamedll/dlls/plats.cpp b/regamedll/dlls/plats.cpp index 75a0e96d9..f0735053b 100644 --- a/regamedll/dlls/plats.cpp +++ b/regamedll/dlls/plats.cpp @@ -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) { diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index d86b320ef..3b6671e6e 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -82,8 +82,6 @@ const char *CDeadHEV::m_szPoses[] = "deadtable" }; -entvars_t *g_pevLastInflictor; - LINK_ENTITY_TO_CLASS(player, CBasePlayer, CCSPlayer) #ifdef REGAMEDLL_API @@ -761,24 +759,30 @@ void EXT_FUNC CBasePlayer::__API_HOOK(TraceAttack)(entvars_t *pevAttacker, float AddMultiDamage(pevAttacker, this, flDamage, bitsDamageType); } -const char *GetWeaponName(entvars_t *pevInflictor, entvars_t *pKiller) +const char *CBasePlayer::GetKillerWeaponName(entvars_t *pevInflictor, entvars_t *pevKiller) const { // by default, the player is killed by the world const char *killer_weapon_name = "world"; // Is the killer a client? - if (pKiller->flags & FL_CLIENT) + if (pevKiller->flags & FL_CLIENT) { if (pevInflictor) { - if (pevInflictor == pKiller) + if (pevInflictor == pevKiller) { - // If the inflictor is the killer, then it must be their current weapon doing the damage - CBasePlayer *pAttacker = CBasePlayer::Instance(pKiller); - if (pAttacker && pAttacker->IsPlayer()) +#ifdef REGAMEDLL_FIXES + // Ignore the inflictor's weapon if victim killed self + if (pevKiller != pev) +#endif { - if (pAttacker->m_pActiveItem) - killer_weapon_name = pAttacker->m_pActiveItem->pszName(); + // If the inflictor is the killer, then it must be their current weapon doing the damage + CBasePlayer *pAttacker = CBasePlayer::Instance(pevKiller); + if (pAttacker && pAttacker->IsPlayer()) + { + if (pAttacker->m_pActiveItem) + killer_weapon_name = pAttacker->m_pActiveItem->pszName(); + } } } else @@ -797,10 +801,11 @@ const char *GetWeaponName(entvars_t *pevInflictor, entvars_t *pKiller) } // strip the monster_* or weapon_* from the inflictor's classname - const char cut_weapon[] = "weapon_"; + const char cut_weapon[] = "weapon_"; const char cut_monster[] = "monster_"; - const char cut_func[] = "func_"; + const char cut_func[] = "func_"; + // replace the code names with the 'real' names if (!Q_strncmp(killer_weapon_name, cut_weapon, sizeof(cut_weapon) - 1)) killer_weapon_name += sizeof(cut_weapon) - 1; @@ -971,7 +976,7 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva m_bKilledByGrenade = true; } - LogAttack(pAttack, this, bTeamAttack, int(flDamage), armorHit, pev->health - flDamage, pev->armorvalue, GetWeaponName(pevInflictor, pevAttacker)); + LogAttack(pAttack, this, bTeamAttack, int(flDamage), armorHit, pev->health - flDamage, pev->armorvalue, GetKillerWeaponName(pevInflictor, pevAttacker)); bTookDamage = CBaseMonster::TakeDamage(pevInflictor, pevAttacker, int(flDamage), bitsDamageType); if (bTookDamage) @@ -986,9 +991,13 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva CBasePlayer *pPlayerAttacker = CBasePlayer::Instance(pevAttacker); if (pPlayerAttacker && !pPlayerAttacker->IsBot() && pPlayerAttacker->m_iTeam != m_iTeam) { - TheCareerTasks->HandleEnemyInjury(GetWeaponName(pevInflictor, pevAttacker), pPlayerAttacker->HasShield(), pPlayerAttacker); + TheCareerTasks->HandleEnemyInjury(GetKillerWeaponName(pevInflictor, pevAttacker), pPlayerAttacker->HasShield(), pPlayerAttacker); } } + +#ifdef REGAMEDLL_API + CSPlayer()->RecordDamage(pAttack, flDamage); +#endif } { @@ -1049,7 +1058,7 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva pAttacker = GetClassPtr((CBaseEntity *)pevAttacker); - if (pAttacker->IsPlayer()) + if (pAttacker->IsPlayer() && !(pAttacker == this && (bitsDamageType & DMG_FALL))) { pAttack = GetClassPtr((CBasePlayer *)pevAttacker); @@ -1091,16 +1100,18 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva pAttack->m_flLastAttackedTeammate = gpGlobals->time; } - } #ifdef REGAMEDLL_ADD - // bullets hurt teammates less - flDamage *= clamp(((bitsDamageType & DMG_BULLET) ? - ff_damage_reduction_bullets.value : - ff_damage_reduction_other.value), 0.0f, 1.0f); -#else - flDamage *= 0.35; + // bullets hurt teammates less + flDamage *= clamp(((bitsDamageType & DMG_BULLET) ? + ff_damage_reduction_bullets.value : + ff_damage_reduction_other.value), 0.0f, 1.0f); #endif // #ifdef REGAMEDLL_ADD + } + +#ifndef REGAMEDLL_ADD + flDamage *= 0.35; +#endif } if (pAttack->m_pActiveItem) @@ -1169,9 +1180,6 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva } } - // keep track of amount of damage last sustained - m_lastDamageAmount = flDamage; - // Armor // armor doesn't protect against fall or drown damage! if (pev->armorvalue != 0.0f && !(bitsDamageType & (DMG_DROWN | DMG_FALL)) && IsArmored(m_LastHitGroup)) @@ -1211,7 +1219,10 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva Pain(m_LastHitGroup, false); } - LogAttack(pAttack, this, bTeamAttack, flDamage, armorHit, pev->health - flDamage, pev->armorvalue, GetWeaponName(pevInflictor, pevAttacker)); + // keep track of amount of damage last sustained + m_lastDamageAmount = flDamage; + + LogAttack(pAttack, this, bTeamAttack, flDamage, armorHit, pev->health - flDamage, pev->armorvalue, GetKillerWeaponName(pevInflictor, pevAttacker)); // this cast to INT is critical!!! If a player ends up with 0.5 health, the engine will get that // as an int (zero) and think the player is dead! (this will incite a clientside screentilt, etc) @@ -1229,9 +1240,13 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva CBasePlayer *pPlayerAttacker = CBasePlayer::Instance(pevAttacker); if (pPlayerAttacker && !pPlayerAttacker->IsBot() && pPlayerAttacker->m_iTeam != m_iTeam) { - TheCareerTasks->HandleEnemyInjury(GetWeaponName(pevInflictor, pevAttacker), pPlayerAttacker->HasShield(), pPlayerAttacker); + TheCareerTasks->HandleEnemyInjury(GetKillerWeaponName(pevInflictor, pevAttacker), pPlayerAttacker->HasShield(), pPlayerAttacker); } } + +#ifdef REGAMEDLL_API + CSPlayer()->RecordDamage(pAttack, flDamage); +#endif } { @@ -1292,7 +1307,7 @@ LINK_HOOK_CHAIN(CWeaponBox *, CreateWeaponBox, (CBasePlayerItem *pItem, CBasePla CWeaponBox *EXT_FUNC __API_HOOK(CreateWeaponBox)(CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo) { // create a box to pack the stuff into. - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create("weaponbox", origin, angles, ENT(pPlayerOwner->pev)); + CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create("weaponbox", origin, angles, pPlayerOwner ? ENT(pPlayerOwner->pev) : nullptr); if (pWeaponBox) { @@ -1306,11 +1321,21 @@ CWeaponBox *EXT_FUNC __API_HOOK(CreateWeaponBox)(CBasePlayerItem *pItem, CBasePl // pack the ammo bool exhaustibleAmmo = (pItem->iFlags() & ITEM_FLAG_EXHAUSTIBLE) == ITEM_FLAG_EXHAUSTIBLE; - if (exhaustibleAmmo || packAmmo) + if ((exhaustibleAmmo || packAmmo) && pPlayerOwner) { +#ifndef REGAMEDLL_ADD pWeaponBox->PackAmmo(MAKE_STRING(pItem->pszAmmo1()), pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()]); - +#else + pWeaponBox->GiveAmmo(pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()], (char *)pItem->pszAmmo1(), pItem->iMaxAmmo1()); +#endif +#ifndef REGAMEDLL_FIXES + // by removing ammo ONLY on exhaustible weapons (slot 4 and 5) + // you are allowing to duplicate ammo whenever: + // (1) you have 2 weapons sharing the same ammo type (e.g. mp5navy and glock) + // (2) you are dropping a weapon alive and pickup another (with same ammo type) without ammo + // and, logically, you throw your ammo with your gun with packing enabled if (exhaustibleAmmo) +#endif { pPlayerOwner->m_rgAmmo[pItem->PrimaryAmmoIndex()] = 0; } @@ -1322,10 +1347,10 @@ CWeaponBox *EXT_FUNC __API_HOOK(CreateWeaponBox)(CBasePlayerItem *pItem, CBasePl return pWeaponBox; } -void PackPlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) +CWeaponBox *PackPlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) { if (!pItem) - return; + return nullptr; const char *modelName = GetCSModelName(pItem->m_iId); if (modelName) @@ -1335,7 +1360,7 @@ void PackPlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) Vector vecVelocity = pPlayer->pev->velocity * 0.75f; // create a box to pack the stuff into - CreateWeaponBox(pItem, pPlayer, + return CreateWeaponBox(pItem, pPlayer, modelName, vecOrigin, vecAngles, @@ -1343,6 +1368,8 @@ void PackPlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) CGameRules::GetItemKillDelay(), packAmmo ); } + + return nullptr; } #ifdef REGAMEDLL_ADD @@ -1399,78 +1426,130 @@ void PackPlayerNade(CBasePlayer *pPlayer, CBasePlayerItem *pItem, bool packAmmo) void CBasePlayer::PackDeadPlayerItems() { // get the game rules - bool bPackGun = (g_pGameRules->DeadPlayerWeapons(this) != GR_PLR_DROP_GUN_NO); + int iPackGun = g_pGameRules->DeadPlayerWeapons(this); bool bPackAmmo = (g_pGameRules->DeadPlayerAmmo(this) != GR_PLR_DROP_AMMO_NO); - if (bPackGun) + if (iPackGun != GR_PLR_DROP_GUN_NO) { - bool bShieldDropped = false; + bool bSkipPrimSec = false; if (HasShield()) { DropShield(); - bShieldDropped = true; +#ifdef REGAMEDLL_ADD + if(iPackGun != GR_PLR_DROP_GUN_ALL) +#endif + { + bSkipPrimSec = true; + } } int nBestWeight = 0; CBasePlayerItem *pBestItem = nullptr; - for (int n = 0; n < MAX_ITEM_TYPES; n++) +#ifdef REGAMEDLL_ADD + int iGunsPacked = 0; + + if (iPackGun == GR_PLR_DROP_GUN_ACTIVE) { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[n]; + // check if we've just already dropped our active gun + if (!bSkipPrimSec && m_pActiveItem && m_pActiveItem->CanDrop() && m_pActiveItem->iItemSlot() < KNIFE_SLOT) + { + pBestItem = m_pActiveItem; - while (pPlayerItem) + // if active item is undroppable, then nothing is dropped + } + + // are we allowing nade drop? + if ((int)nadedrops.value >= 1) { - ItemInfo info; - if (pPlayerItem->iItemSlot() < KNIFE_SLOT && !bShieldDropped) + // goto item loop but skip guns + iPackGun = GR_PLR_DROP_GUN_ALL; + bSkipPrimSec = true; + } + } + + if (iPackGun == GR_PLR_DROP_GUN_ALL || iPackGun == GR_PLR_DROP_GUN_BEST) +#endif + { + for (int n = 0; n < MAX_ITEM_TYPES; n++) + { + // there's a weapon here. Should I pack it? + CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[n]; + + while (pPlayerItem) { + ItemInfo info; + if (pPlayerItem->iItemSlot() < KNIFE_SLOT && !bSkipPrimSec) + { #ifdef REGAMEDLL_API - if (pPlayerItem->CSPlayerItem()->GetItemInfo(&info)) + if (pPlayerItem->CSPlayerItem()->GetItemInfo(&info) #else - if (pPlayerItem->GetItemInfo(&info)) + if (pPlayerItem->GetItemInfo(&info) #endif - { - if (info.iWeight > nBestWeight) +#ifdef REGAMEDLL_FIXES + && pPlayerItem->CanDrop() // needs to be droppable +#endif + ) { - nBestWeight = info.iWeight; - pBestItem = pPlayerItem; +#ifdef REGAMEDLL_ADD + if (iPackGun == GR_PLR_DROP_GUN_ALL) + { + CBasePlayerItem *pNext = pPlayerItem->m_pNext; + + CWeaponBox *pWeaponBox = PackPlayerItem(this, pPlayerItem, bPackAmmo); + if (pWeaponBox) + { + // just push a few units in forward to separate them + pWeaponBox->pev->velocity = pWeaponBox->pev->velocity * (1.0 + (iGunsPacked * 0.2)); + iGunsPacked++; + } + + pPlayerItem = pNext; + continue; + } +#endif + if (info.iWeight > nBestWeight) + { + nBestWeight = info.iWeight; + pBestItem = pPlayerItem; + } } } - } - // drop a grenade after death - else if (pPlayerItem->iItemSlot() == GRENADE_SLOT) - { - if (AreRunningCZero()) + // drop a grenade after death + else if (pPlayerItem->iItemSlot() == GRENADE_SLOT) { + if (AreRunningCZero()) + { #ifdef REGAMEDLL_FIXES - if (pPlayerItem->m_flStartThrow == 0.0f && m_rgAmmo[pPlayerItem->PrimaryAmmoIndex()] > 0) + if (pPlayerItem->m_flStartThrow == 0.0f && m_rgAmmo[pPlayerItem->PrimaryAmmoIndex()] > 0) #endif - { - PackPlayerItem(this, pPlayerItem, true); + { + PackPlayerItem(this, pPlayerItem, true); + } } - } #ifdef REGAMEDLL_ADD - else - { - switch ((int)nadedrops.value) - { - case 1: - PackPlayerNade(this, pPlayerItem, true); - break; - case 2: + else { - CBasePlayerItem *pNext = pPlayerItem->m_pNext; - PackPlayerNade(this, pPlayerItem, true); - pPlayerItem = pNext; - continue; - } + switch ((int)nadedrops.value) + { + case 1: + PackPlayerNade(this, pPlayerItem, true); + break; + case 2: + { + CBasePlayerItem *pNext = pPlayerItem->m_pNext; + PackPlayerNade(this, pPlayerItem, true); + pPlayerItem = pNext; + continue; + } + } } - } #endif - } + } - pPlayerItem = pPlayerItem->m_pNext; + pPlayerItem = pPlayerItem->m_pNext; + } } } @@ -1628,7 +1707,6 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)() void CBasePlayer::RemoveAllItems(BOOL removeSuit) { - bool bKillProgBar = false; int i; #ifdef REGAMEDLL_FIXES @@ -1642,34 +1720,18 @@ void CBasePlayer::RemoveAllItems(BOOL removeSuit) if (m_bHasDefuser) { RemoveDefuser(); - - MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pev); - WRITE_BYTE(STATUSICON_HIDE); - WRITE_STRING("defuser"); - MESSAGE_END(); - - SendItemStatus(); - bKillProgBar = true; } if (m_bHasC4) { m_bHasC4 = false; pev->body = 0; - - MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pev); - WRITE_BYTE(STATUSICON_HIDE); - WRITE_STRING("c4"); - MESSAGE_END(); - - bKillProgBar = true; + SetBombIcon(FALSE); + SetProgressBarTime(0); } RemoveShield(); - if (bKillProgBar) - SetProgressBarTime(0); - if (m_pActiveItem) { ResetAutoaim(); @@ -2059,8 +2121,27 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) } TheCareerTasks->HandleDeath(m_iTeam, this); + +#ifdef REGAMEDLL_FIXES + if (!m_bKilledByBomb) + { + CBasePlayer *pAttacker = CBasePlayer::Instance(pevAttacker); + + if(pAttacker /*safety*/ && !pAttacker->IsBot() && pAttacker->m_iTeam != m_iTeam) + { + if (pAttacker->HasShield()) + killerHasShield = true; + + if (IsBot() && IsBlind()) // dystopm: shouldn't be !IsBot() ? + wasBlind = true; + + TheCareerTasks->HandleEnemyKill(wasBlind, GetKillerWeaponName(GetLastInflictor(), pevAttacker), m_bHeadshotKilled, killerHasShield, pAttacker, this); // last 2 param swapped to match function definition + } + } +#endif } +#ifndef REGAMEDLL_FIXES if (!m_bKilledByBomb) { CBasePlayer *pAttacker = CBasePlayer::Instance(pevAttacker); @@ -2085,16 +2166,17 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) { if (TheCareerTasks) { - TheCareerTasks->HandleEnemyKill(wasBlind, GetWeaponName(g_pevLastInflictor, pevAttacker), m_bHeadshotKilled, killerHasShield, this, pPlayer); + TheCareerTasks->HandleEnemyKill(wasBlind, GetKillerWeaponName(GetLastInflictor(), pevAttacker), m_bHeadshotKilled, killerHasShield, this, pPlayer); } } } } +#endif } if (!m_bKilledByBomb) { - g_pGameRules->PlayerKilled(this, pevAttacker, g_pevLastInflictor); + g_pGameRules->PlayerKilled(this, pevAttacker, GetLastInflictor()); } MESSAGE_BEGIN(MSG_ONE, gmsgNVGToggle, nullptr, pev); @@ -2224,6 +2306,8 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) UTIL_ScreenFade(this, Vector(0, 0, 0), 3, 3, 255, (FFADE_OUT | FFADE_STAYOUT)); } #else + + float flDyingDuration = GetSequenceDuration() + CGameRules::GetDyingTime(); switch ((int)fadetoblack.value) { default: @@ -2239,12 +2323,12 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) break; } - case 1: + case FADETOBLACK_STAY: { - UTIL_ScreenFade(this, Vector(0, 0, 0), 3, 3, 255, (FFADE_OUT | FFADE_STAYOUT)); + UTIL_ScreenFade(this, Vector(0, 0, 0), 0.8f, flDyingDuration, 255, (FFADE_OUT | FFADE_STAYOUT)); break; } - case 2: + case FADETOBLACK_AT_DYING: { pev->iuser1 = OBS_CHASE_FREE; pev->iuser2 = ENTINDEX(edict()); @@ -2255,15 +2339,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) MESSAGE_BEGIN(MSG_ONE, gmsgADStop, nullptr, pev); MESSAGE_END(); - for (int i = 1; i <= gpGlobals->maxClients; i++) - { - CBasePlayer* pObserver = UTIL_PlayerByIndex(i); - - if (pObserver == this || (pObserver && pObserver->IsObservingPlayer(this))) - { - UTIL_ScreenFade(pObserver, Vector(0, 0, 0), 1, 4, 255, (FFADE_OUT)); - } - } + UTIL_ScreenFade(this, Vector(0, 0, 0), 0.8f, flDyingDuration, 255, (FFADE_OUT)); break; } @@ -2334,8 +2410,8 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) } SetSuitUpdate(nullptr, SUIT_SENTENCE, SUIT_REPEAT_OK); - m_iClientHealth = 0; + m_iClientHealth = 0; MESSAGE_BEGIN(MSG_ONE, gmsgHealth, nullptr, pev); WRITE_BYTE(m_iClientHealth); MESSAGE_END(); @@ -2363,31 +2439,18 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) else if (m_bHasDefuser) { RemoveDefuser(); - #ifdef REGAMEDLL_FIXES - CItemThighPack *pDefuser = (CItemThighPack *)CBaseEntity::Create("item_thighpack", pev->origin, g_vecZero, ENT(pev)); - - pDefuser->SetThink(&CBaseEntity::SUB_Remove); - pDefuser->pev->nextthink = gpGlobals->time + CGameRules::GetItemKillDelay(); - pDefuser->pev->spawnflags |= SF_NORESPAWN; + SpawnDefuser(pev->origin, ENT(pev)); #else GiveNamedItem("item_thighpack"); #endif - - MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pev); - WRITE_BYTE(STATUSICON_HIDE); - WRITE_STRING("defuser"); - MESSAGE_END(); - - SendItemStatus(); - } - - if (m_bIsDefusing) - { - SetProgressBarTime(0); } +#ifndef REGAMEDLL_FIXES + // NOTE: moved to RemoveDefuser m_bIsDefusing = false; +#endif + BuyZoneIcon_Clear(this); #ifdef REGAMEDLL_ADD @@ -2404,7 +2467,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) HintMessage("#Hint_cannot_play_because_tk", TRUE, TRUE); } - if ((pev->health < -9000 && iGib != GIB_NEVER) || iGib == GIB_ALWAYS) + if (ShouldGibPlayer(iGib)) { #ifndef REGAMEDLL_FIXES @@ -3578,16 +3641,20 @@ void EXT_FUNC CBasePlayer::__API_HOOK(JoiningThink)() ResetMenu(); m_iJoiningState = SHOWTEAMSELECT; +#ifndef REGAMEDLL_FIXES + // NOTE: client already clears StatusIcon on join MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pev); WRITE_BYTE(STATUSICON_HIDE); WRITE_STRING("defuser"); MESSAGE_END(); - m_bHasDefuser = false; + m_bHasDefuser = false; // set in ClientPutInServer +#endif m_fLastMovement = gpGlobals->time; m_bMissionBriefing = false; - SendItemStatus(); + SendItemStatus(); // NOTE: must be on UpdateClientData + break; } case READINGLTEXT: @@ -3611,7 +3678,11 @@ void EXT_FUNC CBasePlayer::__API_HOOK(JoiningThink)() } } - if (m_pIntroCamera && gpGlobals->time >= m_fIntroCamTime) + if (m_pIntroCamera && gpGlobals->time >= m_fIntroCamTime +#ifdef REGAMEDLL_FIXES + && m_fIntroCamTime > 0.0 // update only if cameras are available +#endif + ) { // find the next another camera m_pIntroCamera = UTIL_FindEntityByClassname(m_pIntroCamera, "trigger_camera"); @@ -3706,18 +3777,11 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Disappear)() else if (m_bHasDefuser) { RemoveDefuser(); - -#ifndef REGAMEDLL_FIXES +#ifdef REGAMEDLL_FIXES + SpawnDefuser(pev->origin, ENT(pev)); +#else GiveNamedItem("item_thighpack"); #endif - - MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pev); - WRITE_BYTE(STATUSICON_HIDE); - WRITE_STRING("defuser"); - MESSAGE_END(); - - SendItemStatus(); - SetProgressBarTime(0); } BuyZoneIcon_Clear(this); @@ -3729,7 +3793,9 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Disappear)() pev->angles.z = 0; } -void CBasePlayer::PlayerDeathThink() +LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, PlayerDeathThink) + +void EXT_FUNC CBasePlayer::__API_HOOK(PlayerDeathThink)() { if (m_iJoiningState != JOINED) return; @@ -3789,7 +3855,7 @@ void CBasePlayer::PlayerDeathThink() { // if the player has been dead for one second longer than allowed by forcerespawn, // forcerespawn isn't on. Send the player off to an intermission camera until they choose to respawn. - if (g_pGameRules->IsMultiplayer() && HasTimePassedSinceDeath(3.0f) && !(m_afPhysicsFlags & PFLAG_OBSERVER)) + if (g_pGameRules->IsMultiplayer() && HasTimePassedSinceDeath(CGameRules::GetDyingTime()) && !(m_afPhysicsFlags & PFLAG_OBSERVER)) { // Send message to everybody to spawn a corpse. SpawnClientSideCorpse(); @@ -3878,9 +3944,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(RoundRespawn)() #ifdef REGAMEDLL_FIXES if (m_bPunishedForTK && pev->health > 0) - { - ClientKill(ENT(pev)); - } + Kill(); #endif } @@ -4047,11 +4111,10 @@ void CBasePlayer::PlayerUse() if (pTrain && pTrain->Classify() == CLASS_VEHICLE) { #ifdef REGAMEDLL_ADD - if (legacy_vehicle_block.value) - ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; -#else - ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; + if (legacy_vehicle_block.value == 0) + return; #endif + ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; } return; } @@ -4593,12 +4656,17 @@ void EXT_FUNC CBasePlayer::__API_HOOK(PreThink)() { m_afPhysicsFlags &= ~PFLAG_ONTRAIN; m_iTrain = (TRAIN_NEW | TRAIN_OFF); + +#ifdef REGAMEDLL_FIXES + if (pTrain && pTrain->Classify() == CLASS_VEHICLE) // ensure func_vehicle's m_pDriver assignation +#endif + { #ifdef REGAMEDLL_ADD - if (legacy_vehicle_block.value) - ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; -#else - ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; + if (legacy_vehicle_block.value == 0) + return; #endif + ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; + } return; } } @@ -4607,12 +4675,17 @@ void EXT_FUNC CBasePlayer::__API_HOOK(PreThink)() // Turn off the train if you jump, strafe, or the train controls go dead m_afPhysicsFlags &= ~PFLAG_ONTRAIN; m_iTrain = (TRAIN_NEW | TRAIN_OFF); + +#ifdef REGAMEDLL_FIXES + if (pTrain->Classify() == CLASS_VEHICLE) // ensure func_vehicle's m_pDriver assignation +#endif + { #ifdef REGAMEDLL_ADD - if (legacy_vehicle_block.value) - ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; -#else - ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; + if (legacy_vehicle_block.value == 0) + return; #endif + ((CFuncVehicle *)pTrain)->m_pDriver = nullptr; + } return; } @@ -4718,6 +4791,8 @@ void EXT_FUNC CBasePlayer::__API_HOOK(PreThink)() #endif } +LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, CheckTimeBasedDamage) + // If player is taking time based damage, continue doing damage to player - // this simulates the effect of being poisoned, gassed, dosed with radiation etc - // anything that continues to do damage even after the initial contact stops. @@ -4726,7 +4801,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(PreThink)() // The m_bitsDamageType bit MUST be set if any damage is to be taken. // This routine will detect the initial on value of the m_bitsDamageType // and init the appropriate counter. Only processes damage every second. -void CBasePlayer::CheckTimeBasedDamage() +void EXT_FUNC CBasePlayer::__API_HOOK(CheckTimeBasedDamage)() { int i; byte bDuration = 0; @@ -4751,7 +4826,7 @@ void CBasePlayer::CheckTimeBasedDamage() { switch (i) { - case ITBD_PARALLYZE: + case ITBD_PARALYZE: // UNDONE - flag movement as half-speed bDuration = PARALYZE_DURATION; break; @@ -5107,7 +5182,17 @@ void EXT_FUNC CBasePlayer::__API_HOOK(PostThink)() #endif { m_LastHitGroup = HITGROUP_GENERIC; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL); + + // FIXED: The player falling to the ground, + // the damage caused by the fall is initiated by himself (and not by the world) + entvars_t *pevAttacker = +#ifdef REGAMEDLL_FIXES + pev; +#else + VARS(eoNullEntity); +#endif + TakeDamage(pevAttacker, pevAttacker, flFallDamage, DMG_FALL); + pev->punchangle.x = 0; if (TheBots) { @@ -5293,7 +5378,9 @@ CBaseEntity *g_pLastSpawn; CBaseEntity *g_pLastCTSpawn; CBaseEntity *g_pLastTerroristSpawn; -edict_t *CBasePlayer::EntSelectSpawnPoint() +LINK_HOOK_CLASS_CHAIN2(edict_t *, CBasePlayer, EntSelectSpawnPoint) + +edict_t *EXT_FUNC CBasePlayer::__API_HOOK(EntSelectSpawnPoint)() { CBaseEntity *pSpot; @@ -5622,10 +5709,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Spawn)() ReloadWeapons(); #endif - if (m_bHasDefuser) - pev->body = 1; - else - pev->body = 0; + pev->body = m_bHasDefuser ? 1 : 0; if (m_bMissionBriefing) { @@ -5937,6 +6021,8 @@ void CBasePlayer::Reset() if (CSPlayer()->GetProtectionState() == CCSPlayer::ProtectionSt_Active) { RemoveSpawnProtection(); } + + CSPlayer()->ResetAllStats(); #endif } @@ -6312,6 +6398,11 @@ void CBasePlayer::ForceClientDllUpdate() #ifdef REGAMEDLL_FIXES // fix for https://github.com/ValveSoftware/halflife/issues/1567 m_iClientHideHUD = -1; + m_flNextSBarUpdateTime = -1; + InitStatusBar(); +#ifdef BUILD_LATEST + m_tmNextAccountHealthUpdate = -1; +#endif #endif m_iClientHealth = -1; @@ -6324,6 +6415,84 @@ void CBasePlayer::ForceClientDllUpdate() // Now force all the necessary messages to be sent. UpdateClientData(); HandleSignals(); + +#ifdef REGAMEDLL_FIXES + // Update HUD backpack ammo + for (int i = 0; i < MAX_AMMO_SLOTS; i++) + m_rgAmmoLast[i] = -1; + + // Force update server name + MESSAGE_BEGIN(MSG_ONE, gmsgServerName, nullptr, pev); + WRITE_STRING(CVAR_GET_STRING("hostname")); + MESSAGE_END(); + + MESSAGE_BEGIN(MSG_ONE, SVC_ROOMTYPE, nullptr, pev); + WRITE_SHORT(int(CVAR_GET_FLOAT("room_type"))); + MESSAGE_END(); + + SendItemStatus(); + + // Loop through all active players and update their info to the client who started recording the demo + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); + if (!pPlayer || FNullEnt(pPlayer->edict())) + continue; + + if (pPlayer->IsDormant()) + continue; + + if (pev->deadflag == DEAD_NO) + { + // NOTE: Don't use here PlayerRelationShip, + // because we have to send a radar message about the players in the team anyway, + // even if they are not teammates + bool sameTeam = pPlayer->m_iTeam == m_iTeam; + if (sameTeam) + { + const Vector &vecOrigin = CSGameRules()->IsFreeForAll() ? + g_vecZero : pPlayer->pev->origin; + + MESSAGE_BEGIN(MSG_ONE, gmsgRadar, nullptr, pev); + WRITE_BYTE(pPlayer->entindex()); + WRITE_COORD(vecOrigin.x); + WRITE_COORD(vecOrigin.y); + WRITE_COORD(vecOrigin.z); + MESSAGE_END(); + } + + // Update last location of players + if (sameTeam || pPlayer->m_iTeam == SPECTATOR) + { + if (pPlayer->m_lastLocation[0]) + { + MESSAGE_BEGIN(MSG_ONE, gmsgLocation, nullptr, pev); + WRITE_BYTE(pPlayer->entindex()); + WRITE_STRING(pPlayer->m_lastLocation); + MESSAGE_END(); + } + } + } + + // Update team info + MESSAGE_BEGIN(MSG_ONE, gmsgTeamInfo, nullptr, pev); + WRITE_BYTE(pPlayer->entindex()); + WRITE_STRING(GetTeamName(pPlayer->m_iTeam)); + MESSAGE_END(); + + // Update score info Frags, Deaths, etc + MESSAGE_BEGIN(MSG_ONE, gmsgScoreInfo, nullptr, pev); + WRITE_BYTE(pPlayer->entindex()); + WRITE_SHORT(int(pPlayer->pev->frags)); + WRITE_SHORT(pPlayer->m_iDeaths); + WRITE_SHORT(0); + WRITE_SHORT(pPlayer->m_iTeam); + MESSAGE_END(); + + // Update player attributes DEAD, BOMB, VIP etc + pPlayer->SetScoreAttrib(this); + } +#endif } LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, ImpulseCommands) @@ -6351,8 +6520,6 @@ void EXT_FUNC CBasePlayer::__API_HOOK(ImpulseCommands)() else iOn = 0; - assert(gmsgLogo > 0); - MESSAGE_BEGIN(MSG_ONE, gmsgLogo, nullptr, pev); WRITE_BYTE(iOn); MESSAGE_END(); @@ -6530,7 +6697,7 @@ void CBasePlayer::CheatImpulseCommands(int iImpulse) TraceResult tr; Vector dir(0, 0, 1); - UTIL_BloodDrips(pev->origin, dir, BLOOD_COLOR_RED, 2000); + UTIL_BloodDrips(pev->origin, BLOOD_COLOR_RED, 2000); for (int r = 1; r < 4; r++) { @@ -6990,9 +7157,6 @@ void CBasePlayer::SendAmmoUpdate() { m_rgAmmoLast[i] = m_rgAmmo[i]; - assert(m_rgAmmo[i] >= 0); - assert(m_rgAmmo[i] <= 255); - // send "Ammo" update message MESSAGE_BEGIN(MSG_ONE, gmsgAmmoX, nullptr, pev); WRITE_BYTE(i); @@ -7274,8 +7438,6 @@ void EXT_FUNC CBasePlayer::__API_HOOK(UpdateClientData)() { m_iClientBattery = int(pev->armorvalue); - assert(gmsgBattery > 0); - // send "armor" update message MESSAGE_BEGIN(MSG_ONE, gmsgBattery, nullptr, pev); WRITE_SHORT(int(pev->armorvalue)); @@ -7297,7 +7459,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(UpdateClientData)() if (pEntity) { - damageOrigin = pEntity->Center(); + if (pEntity == this && (m_bitsDamageType & DMG_FALL)) + damageOrigin = Vector(0, 0, 0); // do not show direction of damage caused by fall + else + damageOrigin = pEntity->Center(); } } @@ -7354,8 +7519,6 @@ void EXT_FUNC CBasePlayer::__API_HOOK(UpdateClientData)() if (m_iTrain & TRAIN_NEW) { - assert(gmsgTrain > 0); - // send "train hud" update message MESSAGE_BEGIN(MSG_ONE, gmsgTrain, nullptr, pev); WRITE_BYTE(m_iTrain & 0xF); @@ -7978,8 +8141,10 @@ CBaseEntity *EXT_FUNC CBasePlayer::__API_HOOK(DropPlayerItem)(const char *pszIte g_pGameRules->GetNextBestWeapon(this, pWeapon); UTIL_MakeVectors(pev->angles); +#ifndef REGAMEDLL_FIXES if (pWeapon->iItemSlot() == PRIMARY_WEAPON_SLOT) - m_bHasPrimary = false; + m_bHasPrimary = false; // I may have more than just 1 primary weapon :) +#endif if (FClassnameIs(pWeapon->pev, "weapon_c4")) { @@ -8028,19 +8193,33 @@ CBaseEntity *EXT_FUNC CBasePlayer::__API_HOOK(DropPlayerItem)(const char *pszIte Vector vecAngles = pev->angles; Vector vecVelocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; + bool bPackAmmo = false; + +#ifdef REGAMEDLL_ADD + if (ammodrop.value >= 2.0f) + bPackAmmo = true; +#endif + CWeaponBox *pWeaponBox = CreateWeaponBox(pWeapon, this, modelname, vecOrigin, vecAngles, vecVelocity, CGameRules::GetItemKillDelay(), - false); + bPackAmmo + ); if (!pWeaponBox) { return nullptr; } +#ifdef REGAMEDLL_FIXES + if (!m_rgpPlayerItems[PRIMARY_WEAPON_SLOT]) { + m_bHasPrimary = false; // ensure value assignation on successful weapon removal + } +#endif + if (FClassnameIs(pWeapon->pev, "weapon_c4")) { pWeaponBox->m_bIsBomb = true; @@ -8212,14 +8391,6 @@ void CBasePlayer::__API_HOOK(SwitchTeam)() { RemoveDefuser(); - MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pev); - WRITE_BYTE(STATUSICON_HIDE); - WRITE_STRING("defuser"); - MESSAGE_END(); - - SendItemStatus(); - SetProgressBarTime(0); - #ifndef REGAMEDLL_FIXES // NOTE: unreachable code - Vaqtincha for (int i = 0; i < MAX_ITEM_TYPES; i++) @@ -8448,7 +8619,6 @@ void CStripWeapons::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE if (slot == ALL_OTHER_ITEMS) { - pPlayer->CSPlayer()->RemovePlayerItem("item_thighpack"); pPlayer->CSPlayer()->RemovePlayerItem("item_longjump"); pPlayer->CSPlayer()->RemovePlayerItem("item_assaultsuit"); pPlayer->CSPlayer()->RemovePlayerItem("item_kevlar"); @@ -8737,6 +8907,23 @@ int GetPlayerGaitsequence(const edict_t *pEdict) return pPlayer->m_iGaitsequence; } +float CBasePlayer::GetDyingAnimationDuration() const +{ + float animDuration = -1.0f; + + if (CGameRules::GetDyingTime() < DEATH_ANIMATION_TIME) // a short time, timeDiff estimates to be small + { + float flSequenceDuration = GetSequenceDuration(); + if (flSequenceDuration > 0) + animDuration = flSequenceDuration; + } + + if (animDuration <= 0) + animDuration = CGameRules::GetDyingTime(); // in case of failure + + return animDuration; +} + void CBasePlayer::SpawnClientSideCorpse() { #ifdef REGAMEDLL_FIXES @@ -8744,9 +8931,7 @@ void CBasePlayer::SpawnClientSideCorpse() if (pev->effects & EF_NODRAW) return; - // do not make a corpse if the player goes to respawn. - if (pev->deadflag == DEAD_RESPAWNABLE) - return; + // deadflag == DEAD_RESPAWNABLE already checked before #endif #ifdef REGAMEDLL_ADD @@ -8756,6 +8941,27 @@ void CBasePlayer::SpawnClientSideCorpse() char *infobuffer = GET_INFO_BUFFER(edict()); char *pModel = GET_KEY_VALUE(infobuffer, "model"); + float timeDiff = pev->animtime - gpGlobals->time; + +#ifdef REGAMEDLL_ADD + if (CGameRules::GetDyingTime() < DEATH_ANIMATION_TIME) // a short time, timeDiff estimates to be small + { + float animDuration = GetDyingAnimationDuration(); + + // client receives a negative value + animDuration *= -1.0; + + if (animDuration < timeDiff) // reasonable way to fix client side unfinished sequence bug + { + // by some reason, if client receives a value less + // than "(negative current sequence time) * 100" + // animation will play visually awkward + // at this function call time, player death animation + // has already finished so we can safely fake it + timeDiff = animDuration; + } + } +#endif MESSAGE_BEGIN(MSG_ALL, gmsgSendCorpse); WRITE_STRING(pModel); @@ -8765,14 +8971,17 @@ void CBasePlayer::SpawnClientSideCorpse() WRITE_COORD(pev->angles.x); WRITE_COORD(pev->angles.y); WRITE_COORD(pev->angles.z); - WRITE_LONG((pev->animtime - gpGlobals->time) * 100); + WRITE_LONG(timeDiff * 100); WRITE_BYTE(pev->sequence); WRITE_BYTE(pev->body); WRITE_BYTE(m_iTeam); WRITE_BYTE(entindex()); MESSAGE_END(); +#ifndef REGAMEDLL_FIXES + // already defined in StartDeathCam m_canSwitchObserverModes = true; +#endif if (TheTutor) { @@ -9821,7 +10030,7 @@ void CBasePlayer::UpdateLocation(bool forceUpdate) const char *placeName = ""; - if (pev->deadflag == DEAD_NO && AreRunningCZero()) + if (pev->deadflag == DEAD_NO && AreBotsAllowed()) { // search the place name where is located the player Place playerPlace = TheNavAreaGrid.GetPlace(&pev->origin); @@ -10021,10 +10230,61 @@ void CBasePlayer::RemoveBomb() } } +void CBasePlayer::GiveDefuser() +{ + m_bHasDefuser = true; + pev->body = 1; + + MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pev); + WRITE_BYTE(STATUSICON_SHOW); + WRITE_STRING("defuser"); + WRITE_BYTE(0); + WRITE_BYTE(160); + WRITE_BYTE(0); + MESSAGE_END(); + + SendItemStatus(); + +#if defined(REGAMEDLL_FIXES) || defined(BUILD_LATEST) + SetScoreboardAttributes(); +#endif +} + void CBasePlayer::RemoveDefuser() { m_bHasDefuser = false; pev->body = 0; + + MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, nullptr, pev); + WRITE_BYTE(STATUSICON_HIDE); + WRITE_STRING("defuser"); + MESSAGE_END(); + + SendItemStatus(); + +#ifdef REGAMEDLL_FIXES + if (m_bIsDefusing) + { + SetProgressBarTime(0); + m_bIsDefusing = false; + } +#else + SetProgressBarTime(0); +#endif +} + +CItemThighPack *SpawnDefuser(const Vector &vecOrigin, edict_t *pentOwner) +{ + CItemThighPack *pDefuser = (CItemThighPack *)CBaseEntity::Create("item_thighpack", vecOrigin, g_vecZero, pentOwner); + + if (pDefuser) + { + pDefuser->SetThink(&CBaseEntity::SUB_Remove); + pDefuser->pev->nextthink = gpGlobals->time + CGameRules::GetItemKillDelay(); + pDefuser->pev->spawnflags |= SF_NORESPAWN; + } + + return pDefuser; } void CBasePlayer::Disconnect() @@ -10099,8 +10359,8 @@ bool EXT_FUNC CBasePlayer::__API_HOOK(MakeBomber)() } m_bHasC4 = true; - SetBombIcon(); pev->body = 1; + SetBombIcon(); m_flDisplayHistory |= DHF_BOMB_RETRIEVED; HintMessage("#Hint_you_have_the_bomb", FALSE, TRUE); @@ -10263,6 +10523,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetSpawnProtection)(float flProtectionTime #ifdef REGAMEDLL_ADD if (respawn_immunity_effects.value > 0) { + CSPlayer()->m_bSpawnProtectionEffects = true; pev->rendermode = kRenderTransAdd; pev->renderamt = 100.0f; @@ -10284,12 +10545,11 @@ LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, RemoveSpawnProtection) void CBasePlayer::__API_HOOK(RemoveSpawnProtection)() { #ifdef REGAMEDLL_ADD - if (respawn_immunity_effects.value > 0) + if (CSPlayer()->m_bSpawnProtectionEffects) { - if (pev->rendermode == kRenderTransAdd && - pev->renderamt == 100.0f) + if (pev->rendermode == kRenderTransAdd && pev->renderamt == 100.0f) { - pev->renderamt = 255.0f; + pev->renderamt = 255.0f; pev->rendermode = kRenderNormal; } @@ -10297,6 +10557,8 @@ void CBasePlayer::__API_HOOK(RemoveSpawnProtection)() WRITE_BYTE(STATUSICON_HIDE); WRITE_STRING("suithelmet_full"); MESSAGE_END(); + + CSPlayer()->m_bSpawnProtectionEffects = false; } CSPlayer()->m_flSpawnProtectionEndTime = 0.0f; @@ -10327,3 +10589,23 @@ void EXT_FUNC CBasePlayer::__API_HOOK(DropIdlePlayer)(const char *reason) SERVER_COMMAND(UTIL_VarArgs("kick \"%s\"\n", STRING(pev->netname))); #endif // #ifdef REGAMEDLL_FIXES } + +bool CBasePlayer::Kill() +{ + if (GetObserverMode() != OBS_NONE) + return false; + + if (m_iJoiningState != JOINED) + return false; + + m_LastHitGroup = HITGROUP_GENERIC; + + // have the player kill himself + pev->health = 0.0f; + Killed(pev, GIB_NEVER); + + if (CSGameRules()->m_pVIP == this) + CSGameRules()->m_iConsecutiveVIP = 10; + + return true; +} diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h index e62c1b730..4595bf226 100644 --- a/regamedll/dlls/player.h +++ b/regamedll/dlls/player.h @@ -444,6 +444,10 @@ class CBasePlayer: public CBaseMonster { 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(); CCSPlayer *CSPlayer() const; #endif // REGAMEDLL_API @@ -453,6 +457,7 @@ class CBasePlayer: public CBaseMonster { 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); @@ -585,6 +590,7 @@ class CBasePlayer: public CBaseMonster { 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; } @@ -628,12 +634,15 @@ class CBasePlayer: public CBaseMonster { 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); @@ -642,6 +651,7 @@ class CBasePlayer: public CBaseMonster { void RemoveSpawnProtection(); void UseEmpty(); void DropIdlePlayer(const char *reason); + bool Kill(); // templates template @@ -906,6 +916,7 @@ class CBasePlayer: public CBaseMonster { 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 { @@ -945,7 +956,24 @@ inline bool CBasePlayer::HasTimePassedSinceDeath(float duration) const inline CCSPlayer *CBasePlayer::CSPlayer() const { return reinterpret_cast(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 @@ -967,7 +995,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; @@ -995,7 +1022,6 @@ 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); diff --git a/regamedll/dlls/saverestore.cpp b/regamedll/dlls/saverestore.cpp index a8e63d126..a3a55c7f6 100644 --- a/regamedll/dlls/saverestore.cpp +++ b/regamedll/dlls/saverestore.cpp @@ -955,10 +955,10 @@ 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; diff --git a/regamedll/dlls/subs.cpp b/regamedll/dlls/subs.cpp index ad269c062..4c938c270 100644 --- a/regamedll/dlls/subs.cpp +++ b/regamedll/dlls/subs.cpp @@ -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; diff --git a/regamedll/dlls/triggers.cpp b/regamedll/dlls/triggers.cpp index f454806ce..c4af258c4 100644 --- a/regamedll/dlls/triggers.cpp +++ b/regamedll/dlls/triggers.cpp @@ -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) { @@ -968,7 +971,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)); diff --git a/regamedll/dlls/tutor_base_tutor.cpp b/regamedll/dlls/tutor_base_tutor.cpp index 8723ca2c8..2268d18b7 100644 --- a/regamedll/dlls/tutor_base_tutor.cpp +++ b/regamedll/dlls/tutor_base_tutor.cpp @@ -104,7 +104,7 @@ char *TutorMessageEvent::GetNextParameter(char *buf, int buflen) Q_strncpy(buf, param->m_data, buflen); #ifdef REGAMEDLL_FIXES - buf[buflen] = '\0'; + buf[buflen - 1] = '\0'; #endif delete param; diff --git a/regamedll/dlls/util.cpp b/regamedll/dlls/util.cpp index 6c10ca406..7c3c3db6c 100644 --- a/regamedll/dlls/util.cpp +++ b/regamedll/dlls/util.cpp @@ -1056,7 +1056,7 @@ void UTIL_BloodStream(const Vector &origin, const Vector &direction, int color, MESSAGE_END(); } -void UTIL_BloodDrips(const Vector &origin, const Vector &direction, int color, int amount) +void UTIL_BloodDrips(const Vector &origin, int color, int amount) { if (!UTIL_ShouldShowBlood(color)) return; @@ -1497,6 +1497,10 @@ 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 } } @@ -1727,7 +1731,7 @@ 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) @@ -1754,6 +1758,17 @@ int UTIL_GetNumPlayers() 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) @@ -1804,10 +1819,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) diff --git a/regamedll/dlls/util.h b/regamedll/dlls/util.h index baeea3634..f96be669b 100644 --- a/regamedll/dlls/util.h +++ b/regamedll/dlls/util.h @@ -262,7 +262,7 @@ bool UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator); BOOL UTIL_ShouldShowBlood(int color); int UTIL_PointContents(const Vector &vec); void UTIL_BloodStream(const Vector &origin, const Vector &direction, int color, int amount); -void UTIL_BloodDrips(const Vector &origin, const Vector &direction, int color, int amount); +void UTIL_BloodDrips(const Vector &origin, int color, int amount); Vector UTIL_RandomBloodVector(); void UTIL_BloodDecalTrace(TraceResult *pTrace, int bloodColor); void UTIL_DecalTrace(TraceResult *pTrace, int decalNumber); @@ -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, ...); diff --git a/regamedll/dlls/vehicle.cpp b/regamedll/dlls/vehicle.cpp index ffd0bc550..3ff84b941 100644 --- a/regamedll/dlls/vehicle.cpp +++ b/regamedll/dlls/vehicle.cpp @@ -150,7 +150,7 @@ void CFuncVehicle::Blocked(CBaseEntity *pOther) if (pOther->Classify() == CLASS_PLAYER) { CBasePlayer* playerOther = static_cast(pOther); - if (!playerDriver || (!friendlyfire.value && playerDriver->m_iTeam == playerOther->m_iTeam)) + if (!playerDriver || !g_pGameRules->FPlayerCanTakeDamage(playerOther, playerDriver)) { // Just kick player return; diff --git a/regamedll/dlls/weapons.cpp b/regamedll/dlls/weapons.cpp index b727d38eb..d3877fbba 100644 --- a/regamedll/dlls/weapons.cpp +++ b/regamedll/dlls/weapons.cpp @@ -70,27 +70,35 @@ float GetBaseAccuracy(WeaponIdType id) case WEAPON_MP5N: return 0.0f; } + + 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.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) return; gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type); - + gMultiDamage.pEntity->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; @@ -110,7 +118,7 @@ void AddMultiDamage(entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamag void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { - UTIL_BloodDrips(vecSpot, g_vecAttackDir, bloodColor, int(flDamage)); + UTIL_BloodDrips(vecSpot, bloodColor, int(flDamage)); } NOXREF int DamageDecal(CBaseEntity *pEntity, int bitsDamageType) @@ -206,10 +214,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; @@ -217,15 +231,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) @@ -244,6 +258,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 @@ -267,15 +283,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); } } @@ -689,7 +698,9 @@ 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) { real_t flKickUp; float flKickLateral; @@ -759,8 +770,9 @@ void CBasePlayerWeapon::FireRemaining(int &shotsFired, float &shootTime, BOOL bI 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); +#ifndef REGAMEDLL_FIXES --m_pPlayer->ammo_9mm; - +#endif PLAYBACK_EVENT_FULL(flag, m_pPlayer->edict(), m_usFireGlock18, 0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, int(m_pPlayer->pev->punchangle.x * 10000), int(m_pPlayer->pev->punchangle.y * 10000), m_iClip == 0, FALSE); } @@ -768,7 +780,9 @@ void CBasePlayerWeapon::FireRemaining(int &shotsFired, float &shootTime, BOOL bI { 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); +#ifndef REGAMEDLL_FIXES --m_pPlayer->ammo_556nato; +#endif #ifdef REGAMEDLL_ADD // HACKHACK: client-side weapon prediction fix @@ -809,6 +823,21 @@ 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; @@ -876,7 +905,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; @@ -1101,8 +1132,10 @@ void CBasePlayerWeapon::ItemPostFrame() } } -void CBasePlayerItem::DestroyItem() +bool CBasePlayerItem::DestroyItem() { + bool success = false; + if (m_pPlayer) { // if attached to a player, remove. @@ -1110,18 +1143,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) @@ -1187,8 +1233,6 @@ void CBasePlayerWeapon::Spawn() if (GetItemInfo(&info)) { CSPlayerItem()->SetItemInfo(&info); } - - CSPlayerWeapon()->m_bHasSecondaryAttack = HasSecondaryAttack(); #endif } @@ -1271,7 +1315,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; @@ -1590,7 +1636,17 @@ int CBasePlayerWeapon::ExtractClipAmmo(CBasePlayerWeapon *pWeapon) iAmmo = m_iClip; } - return pWeapon->m_pPlayer->GiveAmmo(iAmmo, pszAmmo1(), iMaxAmmo1()); + int iIdAmmo = pWeapon->m_pPlayer->GiveAmmo(iAmmo, pszAmmo1(), iMaxAmmo1()); + +#ifdef REGAMEDLL_FIXES + if (iIdAmmo > 0 && IsGrenadeWeapon(m_iId)) + { + // grenades have WEAPON_NOCLIP force play the "got ammo" sound. + EMIT_SOUND(pWeapon->m_pPlayer->edict(), CHAN_ITEM, "items/9mmclip1.wav", VOL_NORM, ATTN_NORM); + } +#endif + + return iIdAmmo; } // RetireWeapon - no more ammo for this gun, put it away. @@ -1803,7 +1859,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 @@ -1863,8 +1924,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"))) @@ -1915,19 +1976,35 @@ void CWeaponBox::Touch(CBaseEntity *pOther) int playerGrenades = pPlayer->m_rgAmmo[pGrenade->m_iPrimaryAmmoType]; #ifdef REGAMEDLL_FIXES - auto info = GetWeaponInfo(pGrenade->m_iId); - if (info && playerGrenades < info->maxRounds) + // sorry for hardcode :( + const int boxAmmoSlot = 1; + + if (playerGrenades < pGrenade->iMaxAmmo1()) { - auto pNext = m_rgpPlayerItems[i]->m_pNext; - if (pPlayer->AddPlayerItem(pItem)) + if (m_rgAmmo[boxAmmoSlot] > 1 && playerGrenades > 0) { - pItem->AttachToPlayer(pPlayer); - bEmitSound = true; + if (!FStringNull(m_rgiszAmmo[boxAmmoSlot]) + && pPlayer->GiveAmmo(1, STRING(m_rgiszAmmo[boxAmmoSlot]), pGrenade->iMaxAmmo1()) != -1) + { + m_rgAmmo[boxAmmoSlot]--; + + EMIT_SOUND(pPlayer->edict(), CHAN_ITEM, "items/9mmclip1.wav", VOL_NORM, ATTN_NORM); + } } + else + { + auto pNext = m_rgpPlayerItems[i]->m_pNext; - // unlink this weapon from the box - m_rgpPlayerItems[i] = pItem = pNext; - continue; + if (pPlayer->AddPlayerItem(pItem)) + { + pItem->AttachToPlayer(pPlayer); + givenItem = pItem; + } + + // unlink this weapon from the box + m_rgpPlayerItems[i] = pItem = pNext; + continue; + } } #else @@ -1958,7 +2035,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 @@ -1980,7 +2057,11 @@ void CWeaponBox::Touch(CBaseEntity *pOther) if (pPlayer->AddPlayerItem(pItem)) { pItem->AttachToPlayer(pPlayer); - bEmitSound = true; +#ifdef REGAMEDLL_FIXES + givenItem = pItem; +#else + givenItem = true; +#endif } // unlink this weapon from the box @@ -2001,7 +2082,11 @@ 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])); +#else + pPlayer->GiveAmmo(m_rgAmmo[n], STRING(m_rgiszAmmo[n]), m_rgAmmo[n]); +#endif // now empty the ammo from the weaponbox since we just gave it to the player m_rgiszAmmo[n] = iStringNull; @@ -2010,9 +2095,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) @@ -2600,3 +2697,4 @@ int CBasePlayerItem::iFlags() const { return m_ItemInfoEx.iFlags; } + diff --git a/regamedll/dlls/weapons.h b/regamedll/dlls/weapons.h index bd22989e3..431284fb9 100644 --- a/regamedll/dlls/weapons.h +++ b/regamedll/dlls/weapons.h @@ -296,7 +296,7 @@ class CBasePlayerItem: public CBaseAnimating 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 +403,9 @@ class CBasePlayerWeapon: public CBasePlayerItem 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 @@ -534,7 +537,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 +903,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 +1081,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, }; @@ -1151,15 +1167,16 @@ class CHEGrenade: public CBasePlayerWeapon }; -const float KNIFE_BODYHIT_VOLUME = 128.0f; -const float KNIFE_WALLHIT_VOLUME = 512.0f; -const float KNIFE_MAX_SPEED = 250.0f; -const float KNIFE_MAX_SPEED_SHIELD = 180.0f; -const float KNIFE_STAB_DAMAGE = 65.0f; -const float KNIFE_SWING_DAMAGE = 15.0f; -const float KNIFE_SWING_DAMAGE_FAST = 20.0f; -const float KNIFE_STAB_DISTANCE = 32.0f; -const float KNIFE_SWING_DISTANCE = 48.0f; +const float KNIFE_BODYHIT_VOLUME = 128.0f; +const float KNIFE_WALLHIT_VOLUME = 512.0f; +const float KNIFE_MAX_SPEED = 250.0f; +const float KNIFE_MAX_SPEED_SHIELD = 180.0f; +const float KNIFE_STAB_DAMAGE = 65.0f; +const float KNIFE_SWING_DAMAGE = 15.0f; +const float KNIFE_SWING_DAMAGE_FAST = 20.0f; +const float KNIFE_STAB_DISTANCE = 32.0f; +const float KNIFE_SWING_DISTANCE = 48.0f; +const float KNIFE_BACKSTAB_MULTIPLIER = 3.0f; enum knife_e { @@ -1179,7 +1196,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, }; @@ -1220,19 +1237,41 @@ class CKnife: public CBasePlayerWeapon void SetPlayerShieldAnim(); void ResetPlayerShieldAnim(); + float KnifeStabDamage() const; + float KnifeSwingDamage(bool fast) const; + float KnifeStabDistance() const; + float KnifeSwingDistance() const; + float KnifeBackStabMultiplier() const; + private: TraceResult m_trHit; unsigned short m_usKnife; - // Extra RegameDLL features +#ifdef REGAMEDLL_API float m_flStabBaseDamage; float m_flSwingBaseDamage; float m_flSwingBaseDamage_Fast; float m_flStabDistance; float m_flSwingDistance; + + float m_flBackStabMultiplier; +#endif }; +#ifdef REGAMEDLL_API +inline float CKnife::KnifeStabDamage() const { return m_flStabBaseDamage; } +inline float CKnife::KnifeSwingDamage(bool fast) const { return fast ? m_flSwingBaseDamage_Fast : m_flSwingBaseDamage; } +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 +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; } +inline float CKnife::KnifeSwingDistance() const { return KNIFE_SWING_DISTANCE; } +inline float CKnife::KnifeBackStabMultiplier() const { return KNIFE_BACKSTAB_MULTIPLIER; } +#endif // REGAMEDLL_API const float M249_MAX_SPEED = 220.0f; const float M249_DAMAGE = 32.0f; @@ -1835,6 +1874,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: @@ -2113,7 +2165,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 diff --git a/regamedll/dlls/weapontype.cpp b/regamedll/dlls/weapontype.cpp index 209c7b89d..2b8ae4458 100644 --- a/regamedll/dlls/weapontype.cpp +++ b/regamedll/dlls/weapontype.cpp @@ -529,6 +529,17 @@ 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) { diff --git a/regamedll/dlls/weapontype.h b/regamedll/dlls/weapontype.h index e3527e5fa..2005b6af7 100644 --- a/regamedll/dlls/weapontype.h +++ b/regamedll/dlls/weapontype.h @@ -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); diff --git a/regamedll/dlls/world.cpp b/regamedll/dlls/world.cpp index efbb4dcf1..55147af09 100644 --- a/regamedll/dlls/world.cpp +++ b/regamedll/dlls/world.cpp @@ -288,11 +288,7 @@ void CWorld::Precache() CVAR_SET_STRING("room_type", "0"); // Set up game rules - if (g_pGameRules) - { - delete g_pGameRules; - } - + FreeGameRules(&g_pGameRules); g_pGameRules = InstallGameRules(); // NOTE: What is the essence of soundent in CS 1.6? I think this is for NPC monsters - s1lent diff --git a/regamedll/dlls/wpn_shared/wpn_aug.cpp b/regamedll/dlls/wpn_shared/wpn_aug.cpp index c54780f3a..988c74808 100644 --- a/regamedll/dlls/wpn_shared/wpn_aug.cpp +++ b/regamedll/dlls/wpn_shared/wpn_aug.cpp @@ -78,21 +78,19 @@ void CAUG::SecondaryAttack() void CAUG::PrimaryAttack() { + const float flCycleTime = (m_pPlayer->pev->fov == DEFAULT_FOV) ? 0.0825f : 0.135f; + if (!(m_pPlayer->pev->flags & FL_ONGROUND)) { - AUGFire(0.035 + (0.4 * m_flAccuracy), 0.0825, FALSE); + AUGFire(0.035 + (0.4 * m_flAccuracy), flCycleTime, FALSE); } else if (m_pPlayer->pev->velocity.Length2D() > 140) { - AUGFire(0.035 + (0.07 * m_flAccuracy), 0.0825, FALSE); - } - else if (m_pPlayer->pev->fov == DEFAULT_FOV) - { - AUGFire(0.02 * m_flAccuracy, 0.0825, FALSE); + AUGFire(0.035 + (0.07 * m_flAccuracy), flCycleTime, FALSE); } else { - AUGFire(0.02 * m_flAccuracy, 0.135, FALSE); + AUGFire(0.02 * m_flAccuracy, flCycleTime, FALSE); } } diff --git a/regamedll/dlls/wpn_shared/wpn_deagle.cpp b/regamedll/dlls/wpn_shared/wpn_deagle.cpp index f7a97d5d0..7dbed0c6b 100644 --- a/regamedll/dlls/wpn_shared/wpn_deagle.cpp +++ b/regamedll/dlls/wpn_shared/wpn_deagle.cpp @@ -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) @@ -204,7 +204,7 @@ void CDEAGLE::WeaponIdle() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - SendWeaponAnim(SHIELDGUN_DRAWN_IDLE, UseDecrement() != FALSE); + SendWeaponAnim(DEAGLE_SHIELD_IDLE_UP, UseDecrement() != FALSE); } } } diff --git a/regamedll/dlls/wpn_shared/wpn_fiveseven.cpp b/regamedll/dlls/wpn_shared/wpn_fiveseven.cpp index 67f2f3d57..31f211f08 100644 --- a/regamedll/dlls/wpn_shared/wpn_fiveseven.cpp +++ b/regamedll/dlls/wpn_shared/wpn_fiveseven.cpp @@ -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) @@ -208,7 +208,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) diff --git a/regamedll/dlls/wpn_shared/wpn_flashbang.cpp b/regamedll/dlls/wpn_shared/wpn_flashbang.cpp index c5462e49b..0443353e8 100644 --- a/regamedll/dlls/wpn_shared/wpn_flashbang.cpp +++ b/regamedll/dlls/wpn_shared/wpn_flashbang.cpp @@ -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() @@ -236,7 +236,7 @@ void CFlashbang::WeaponIdle() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - SendWeaponAnim(SHIELDREN_IDLE, UseDecrement() != FALSE); + SendWeaponAnim(SHIELDGREN_IDLE, UseDecrement() != FALSE); } } else diff --git a/regamedll/dlls/wpn_shared/wpn_glock18.cpp b/regamedll/dlls/wpn_shared/wpn_glock18.cpp index b82d5148f..c2f5399d5 100644 --- a/regamedll/dlls/wpn_shared/wpn_glock18.cpp +++ b/regamedll/dlls/wpn_shared/wpn_glock18.cpp @@ -295,7 +295,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 diff --git a/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp b/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp index 3f17e7254..49d8eb7a8 100644 --- a/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp +++ b/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp @@ -144,7 +144,7 @@ bool CHEGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim) void CHEGrenade::SecondaryAttack() { - ShieldSecondaryFire(SHIELDGUN_DRAW, SHIELDGUN_DRAWN_IDLE); + ShieldSecondaryFire(SHIELDGREN_UP, SHIELDGREN_DOWN); } void CHEGrenade::SetPlayerShieldAnim() @@ -247,7 +247,7 @@ void CHEGrenade::WeaponIdle() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - SendWeaponAnim(SHIELDREN_IDLE, UseDecrement() != FALSE); + SendWeaponAnim(SHIELDGREN_IDLE, UseDecrement() != FALSE); } } else diff --git a/regamedll/dlls/wpn_shared/wpn_knife.cpp b/regamedll/dlls/wpn_shared/wpn_knife.cpp index 18275c047..fcbf2d949 100644 --- a/regamedll/dlls/wpn_shared/wpn_knife.cpp +++ b/regamedll/dlls/wpn_shared/wpn_knife.cpp @@ -12,6 +12,7 @@ void CKnife::Spawn() m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN; m_iClip = WEAPON_NOCLIP; +#ifdef REGAMEDLL_API m_flStabBaseDamage = KNIFE_STAB_DAMAGE; m_flSwingBaseDamage = KNIFE_SWING_DAMAGE; m_flSwingBaseDamage_Fast = KNIFE_SWING_DAMAGE_FAST; @@ -19,6 +20,9 @@ void CKnife::Spawn() m_flStabDistance = KNIFE_STAB_DISTANCE; m_flSwingDistance = KNIFE_SWING_DISTANCE; + m_flBackStabMultiplier = KNIFE_BACKSTAB_MULTIPLIER; +#endif + // Get ready to fall down FallInit(); @@ -44,12 +48,16 @@ void CKnife::Precache() m_usKnife = PRECACHE_EVENT(1, "events/knife.sc"); +#ifdef REGAMEDLL_API m_flStabBaseDamage = KNIFE_STAB_DAMAGE; m_flSwingBaseDamage = KNIFE_SWING_DAMAGE; m_flSwingBaseDamage_Fast = KNIFE_SWING_DAMAGE_FAST; m_flStabDistance = KNIFE_STAB_DISTANCE; m_flSwingDistance = KNIFE_SWING_DISTANCE; + + m_flBackStabMultiplier = KNIFE_BACKSTAB_MULTIPLIER; +#endif } int CKnife::GetItemInfo(ItemInfo *p) @@ -121,6 +129,9 @@ void FindHullIntersection(const Vector &vecSrc, TraceResult &tr, float *mins, fl distance = 1e6f; vecHullEnd = vecSrc + ((vecHullEnd - vecSrc) * 2); +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_KNIFE; +#endif UTIL_TraceLine(vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace); if (tmpTrace.flFraction < 1.0f) @@ -139,6 +150,9 @@ void FindHullIntersection(const Vector &vecSrc, TraceResult &tr, float *mins, fl vecEnd.y = vecHullEnd.y + minmaxs[j][1]; vecEnd.z = vecHullEnd.z + minmaxs[k][2]; +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_KNIFE; +#endif UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace); if (tmpTrace.flFraction < 1.0f) @@ -166,14 +180,7 @@ void CKnife::SetPlayerShieldAnim() if (!m_pPlayer->HasShield()) return; - if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) - { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shield"); - } - else - { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldknife"); - } + Q_strcpy(m_pPlayer->m_szAnimExtention, (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) != 0 ? "shield" : "shieldknife"); } void CKnife::ResetPlayerShieldAnim() @@ -271,13 +278,23 @@ BOOL CKnife::Swing(BOOL fFirst) UTIL_MakeVectors(m_pPlayer->pev->v_angle); vecSrc = m_pPlayer->GetGunPosition(); - vecEnd = vecSrc + gpGlobals->v_forward * m_flSwingDistance; + vecEnd = vecSrc + gpGlobals->v_forward * KnifeSwingDistance(); +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_KNIFE; +#endif UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, m_pPlayer->edict(), &tr); if (tr.flFraction >= 1.0f) { +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_KNIFE; +#endif UTIL_TraceHull(vecSrc, vecEnd, dont_ignore_monsters, head_hull, m_pPlayer->edict(), &tr); +#ifdef REGAMEDLL_ADD + // We manually reset it because Engine doesn't unlike TraceLine + gpGlobals->trace_flags = 0; +#endif if (tr.flFraction < 1.0f) { @@ -303,8 +320,8 @@ BOOL CKnife::Swing(BOOL fFirst) { switch ((m_iSwing++) % 2) { - case 0: SendWeaponAnim(KNIFE_MIDATTACK1HIT, UseDecrement() != FALSE); break; - case 1: SendWeaponAnim(KNIFE_MIDATTACK2HIT, UseDecrement() != FALSE); break; + case 0: SendWeaponAnim(KNIFE_MIDATTACK1HIT, UseDecrement() != FALSE); break; + case 1: SendWeaponAnim(KNIFE_MIDATTACK2HIT, UseDecrement() != FALSE); break; } // miss @@ -322,10 +339,15 @@ BOOL CKnife::Swing(BOOL fFirst) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f; // play wiff or swish sound - if (RANDOM_LONG(0, 1)) - EMIT_SOUND_DYN(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_slash1.wav", VOL_NORM, ATTN_NORM, 0, 94); - else - EMIT_SOUND_DYN(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_slash2.wav", VOL_NORM, ATTN_NORM, 0, 94); + EMIT_SOUND_DYN(m_pPlayer->edict(), + CHAN_WEAPON, + RANDOM_LONG(0, 1) ? + "weapons/knife_slash1.wav" : + "weapons/knife_slash2.wav", + VOL_NORM, + ATTN_NORM, + 0, + 94); // player "shoot" animation m_pPlayer->SetAnimation(PLAYER_ATTACK1); @@ -340,8 +362,8 @@ BOOL CKnife::Swing(BOOL fFirst) { switch ((m_iSwing++) % 2) { - case 0: SendWeaponAnim(KNIFE_MIDATTACK1HIT, UseDecrement() != FALSE); break; - case 1: SendWeaponAnim(KNIFE_MIDATTACK2HIT, UseDecrement() != FALSE); break; + case 0: SendWeaponAnim(KNIFE_MIDATTACK1HIT, UseDecrement() != FALSE); break; + case 1: SendWeaponAnim(KNIFE_MIDATTACK2HIT, UseDecrement() != FALSE); break; } m_flNextPrimaryAttack = GetNextAttackDelay(0.4); @@ -368,10 +390,11 @@ BOOL CKnife::Swing(BOOL fFirst) m_pPlayer->SetAnimation(PLAYER_ATTACK1); ClearMultiDamage(); - if (m_flNextPrimaryAttack + 0.4f < UTIL_WeaponTimeBase()) - pEntity->TraceAttack(m_pPlayer->pev, m_flSwingBaseDamage_Fast, gpGlobals->v_forward, &tr, (DMG_NEVERGIB | DMG_BULLET)); - else - pEntity->TraceAttack(m_pPlayer->pev, m_flSwingBaseDamage, gpGlobals->v_forward, &tr, (DMG_NEVERGIB | DMG_BULLET)); + pEntity->TraceAttack(m_pPlayer->pev, + KnifeSwingDamage(m_flNextPrimaryAttack + 0.4f < UTIL_WeaponTimeBase()), + gpGlobals->v_forward, + &tr, + (DMG_NEVERGIB | DMG_BULLET)); ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); @@ -379,28 +402,27 @@ BOOL CKnife::Swing(BOOL fFirst) if (pEntity) // -V595 #endif { + if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE #ifdef REGAMEDLL_FIXES - if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE && pEntity->Classify() != CLASS_VEHICLE) -#else - if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) + && pEntity->Classify() != CLASS_VEHICLE #endif + ) { // play thwack or smack sound switch (RANDOM_LONG(0, 3)) { - case 0: EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_hit1.wav", VOL_NORM, ATTN_NORM); break; - case 1: EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_hit2.wav", VOL_NORM, ATTN_NORM); break; - case 2: EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_hit3.wav", VOL_NORM, ATTN_NORM); break; - case 3: EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_hit4.wav", VOL_NORM, ATTN_NORM); break; + case 0: EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_hit1.wav", VOL_NORM, ATTN_NORM); break; + case 1: EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_hit2.wav", VOL_NORM, ATTN_NORM); break; + case 2: EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_hit3.wav", VOL_NORM, ATTN_NORM); break; + case 3: EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_hit4.wav", VOL_NORM, ATTN_NORM); break; } m_pPlayer->m_iWeaponVolume = KNIFE_BODYHIT_VOLUME; if (!pEntity->IsAlive()) return TRUE; - else - flVol = 0.1f; + flVol = 0.1f; fHitWorld = FALSE; } } @@ -449,13 +471,23 @@ BOOL CKnife::Stab(BOOL fFirst) UTIL_MakeVectors(m_pPlayer->pev->v_angle); vecSrc = m_pPlayer->GetGunPosition(); - vecEnd = vecSrc + gpGlobals->v_forward * m_flStabDistance; + vecEnd = vecSrc + gpGlobals->v_forward * KnifeStabDistance(); +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_KNIFE; +#endif UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, m_pPlayer->edict(), &tr); if (tr.flFraction >= 1.0f) { +#ifdef REGAMEDLL_ADD + gpGlobals->trace_flags = FTRACE_KNIFE; +#endif UTIL_TraceHull(vecSrc, vecEnd, dont_ignore_monsters, head_hull, m_pPlayer->edict(), &tr); +#ifdef REGAMEDLL_ADD + // We manually reset it because Engine doesn't unlike TraceLine + gpGlobals->trace_flags = 0; +#endif if (tr.flFraction < 1.0f) { @@ -486,10 +518,15 @@ BOOL CKnife::Stab(BOOL fFirst) m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0f; // play wiff or swish sound - if (RANDOM_LONG(0, 1)) - EMIT_SOUND_DYN(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_slash1.wav", VOL_NORM, ATTN_NORM, 0, 94); - else - EMIT_SOUND_DYN(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_slash2.wav", VOL_NORM, ATTN_NORM, 0, 94); + EMIT_SOUND_DYN(m_pPlayer->edict(), + CHAN_WEAPON, + RANDOM_LONG(0, 1) ? + "weapons/knife_slash1.wav" : + "weapons/knife_slash2.wav", + VOL_NORM, + ATTN_NORM, + 0, + 94); // player "shoot" animation m_pPlayer->SetAnimation(PLAYER_ATTACK1); @@ -517,7 +554,7 @@ BOOL CKnife::Stab(BOOL fFirst) // player "shoot" animation m_pPlayer->SetAnimation(PLAYER_ATTACK1); - float flDamage = m_flStabBaseDamage; + float flDamage = KnifeStabDamage(); if (pEntity && pEntity->IsPlayer()) { @@ -532,10 +569,10 @@ BOOL CKnife::Stab(BOOL fFirst) flDot = DotProduct(vec2LOS, gpGlobals->v_forward.Make2D()); - //Triple the damage if we are stabbing them in the back. + // Multiply the damage if we are stabbing them in the back. if (flDot > 0.80f) { - flDamage *= 3.0f; + flDamage *= KnifeBackStabMultiplier(); } } @@ -549,11 +586,11 @@ BOOL CKnife::Stab(BOOL fFirst) if (pEntity) // -V595 #endif { + if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE #ifdef REGAMEDLL_FIXES - if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE && pEntity->Classify() != CLASS_VEHICLE) -#else - if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) + && pEntity->Classify() != CLASS_VEHICLE #endif + ) { EMIT_SOUND(m_pPlayer->edict(), CHAN_WEAPON, "weapons/knife_stab.wav", VOL_NORM, ATTN_NORM); m_pPlayer->m_iWeaponVolume = KNIFE_BODYHIT_VOLUME; diff --git a/regamedll/dlls/wpn_shared/wpn_p228.cpp b/regamedll/dlls/wpn_shared/wpn_p228.cpp index 6e2c8d05b..b64f5fcf3 100644 --- a/regamedll/dlls/wpn_shared/wpn_p228.cpp +++ b/regamedll/dlls/wpn_shared/wpn_p228.cpp @@ -92,7 +92,7 @@ void CP228::PrimaryAttack() void CP228::SecondaryAttack() { - ShieldSecondaryFire(SHIELDGUN_UP, SHIELDGUN_DOWN); + ShieldSecondaryFire(P228_SHIELD_UP, P228_SHIELD_DOWN); } void CP228::P228Fire(float flSpread, float flCycleTime, BOOL fUseSemi) diff --git a/regamedll/dlls/wpn_shared/wpn_sg552.cpp b/regamedll/dlls/wpn_shared/wpn_sg552.cpp index c95a66878..e86eec412 100644 --- a/regamedll/dlls/wpn_shared/wpn_sg552.cpp +++ b/regamedll/dlls/wpn_shared/wpn_sg552.cpp @@ -77,21 +77,19 @@ void CSG552::SecondaryAttack() void CSG552::PrimaryAttack() { + const float flCycleTime = (m_pPlayer->pev->fov == DEFAULT_FOV) ? 0.0825f : 0.135f; + if (!(m_pPlayer->pev->flags & FL_ONGROUND)) { - SG552Fire(0.035 + (0.45 * m_flAccuracy), 0.0825, FALSE); + SG552Fire(0.035 + (0.45 * m_flAccuracy), flCycleTime, FALSE); } else if (m_pPlayer->pev->velocity.Length2D() > 140) { - SG552Fire(0.035 + (0.075 * m_flAccuracy), 0.0825, FALSE); - } - else if (m_pPlayer->pev->fov == DEFAULT_FOV) - { - SG552Fire(0.02 * m_flAccuracy, 0.0825, FALSE); + SG552Fire(0.035 + (0.075 * m_flAccuracy), flCycleTime, FALSE); } else { - SG552Fire(0.02 * m_flAccuracy, 0.135, FALSE); + SG552Fire(0.02 * m_flAccuracy, flCycleTime, FALSE); } } diff --git a/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp b/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp index d63fe3a69..ae13158b4 100644 --- a/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp +++ b/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp @@ -145,7 +145,7 @@ bool CSmokeGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim) void CSmokeGrenade::SecondaryAttack() { - ShieldSecondaryFire(SHIELDGUN_DRAW, SHIELDGUN_DRAWN_IDLE); + ShieldSecondaryFire(SHIELDGREN_UP, SHIELDGREN_DOWN); } void CSmokeGrenade::SetPlayerShieldAnim() @@ -251,7 +251,7 @@ void CSmokeGrenade::WeaponIdle() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - SendWeaponAnim(SHIELDREN_IDLE, UseDecrement() != FALSE); + SendWeaponAnim(SHIELDGREN_IDLE, UseDecrement() != FALSE); } } else diff --git a/regamedll/dlls/wpn_shared/wpn_usp.cpp b/regamedll/dlls/wpn_shared/wpn_usp.cpp index 6141baebe..0d830d690 100644 --- a/regamedll/dlls/wpn_shared/wpn_usp.cpp +++ b/regamedll/dlls/wpn_shared/wpn_usp.cpp @@ -279,7 +279,7 @@ void CUSP::WeaponIdle() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - SendWeaponAnim(USP_DRAW, UseDecrement()); + SendWeaponAnim(USP_SHIELD_IDLE_UP, UseDecrement()); } } else if (m_iClip) diff --git a/regamedll/engine/studio.h b/regamedll/engine/studio.h index bbd18b47b..b896ccdff 100644 --- a/regamedll/engine/studio.h +++ b/regamedll/engine/studio.h @@ -32,195 +32,338 @@ #pragma once #endif -#include "studio_event.h" +#define MAXSTUDIOTRIANGLES 20000 // TODO: tune this +#define MAXSTUDIOVERTS 2048 // TODO: tune this +#define MAXSTUDIOSEQUENCES 2048 // total animation sequences +#define MAXSTUDIOSKINS 100 // total textures +#define MAXSTUDIOSRCBONES 512 // bones allowed at source movement +#define MAXSTUDIOBONES 128 // total bones actually used +#define MAXSTUDIOMODELS 32 // sub-models per model +#define MAXSTUDIOBODYPARTS 32 +#define MAXSTUDIOGROUPS 16 +#define MAXSTUDIOANIMATIONS 2048 // per sequence +#define MAXSTUDIOMESHES 256 +#define MAXSTUDIOEVENTS 1024 +#define MAXSTUDIOPIVOTS 256 +#define MAXSTUDIOCONTROLLERS 8 -#define MAXSTUDIOTRIANGLES 20000 // TODO: tune this -#define MAXSTUDIOVERTS 2048 // TODO: tune this -#define MAXSTUDIOSEQUENCES 256 // total animation sequences -#define MAXSTUDIOSKINS 100 // total textures -#define MAXSTUDIOSRCBONES 512 // bones allowed at source movement -#define MAXSTUDIOBONES 128 // total bones actually used -#define MAXSTUDIOMODELS 32 // sub-models per model -#define MAXSTUDIOBODYPARTS 32 -#define MAXSTUDIOGROUPS 16 -#define MAXSTUDIOANIMATIONS 512 // per sequence -#define MAXSTUDIOMESHES 256 -#define MAXSTUDIOEVENTS 1024 -#define MAXSTUDIOPIVOTS 256 -#define MAXSTUDIOCONTROLLERS 8 +typedef struct +{ + int id; + int version; -// lighting options -#define STUDIO_NF_FLATSHADE 0x0001 -#define STUDIO_NF_CHROME 0x0002 -#define STUDIO_NF_FULLBRIGHT 0x0004 + char name[64]; + int length; -// motion flags -#define STUDIO_X 0x0001 -#define STUDIO_Y 0x0002 -#define STUDIO_Z 0x0004 -#define STUDIO_XR 0x0008 -#define STUDIO_YR 0x0010 -#define STUDIO_ZR 0x0020 -#define STUDIO_LX 0x0040 -#define STUDIO_LY 0x0080 -#define STUDIO_LZ 0x0100 -#define STUDIO_AX 0x0200 -#define STUDIO_AY 0x0400 -#define STUDIO_AZ 0x0800 -#define STUDIO_AXR 0x1000 -#define STUDIO_AYR 0x2000 -#define STUDIO_AZR 0x4000 -#define STUDIO_TYPES 0x7FFF -#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance + vec3_t eyeposition; // ideal eye position + vec3_t min; // ideal movement hull size + vec3_t max; -// sequence flags -#define STUDIO_LOOPING 0x0001 + vec3_t bbmin; // clipping bounding box + vec3_t bbmax; -// bone flags -#define STUDIO_HAS_NORMALS 0x0001 -#define STUDIO_HAS_VERTICES 0x0002 -#define STUDIO_HAS_BBOX 0x0004 -#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them + int flags; -#define RAD_TO_STUDIO (32768.0/M_PI) -#define STUDIO_TO_RAD (M_PI/32768.0) + int numbones; // bones + int boneindex; -typedef struct -{ - int id; - int version; - char name[64]; - int length; - vec3_t eyeposition; // ideal eye position - vec3_t min; // ideal movement hull size - vec3_t max; - vec3_t bbmin; // clipping bounding box - vec3_t bbmax; - int flags; - int numbones; // bones - int boneindex; - int numbonecontrollers; // bone controllers - int bonecontrollerindex; - int numhitboxes; // complex bounding boxes - int hitboxindex; - int numseq; // animation sequences - int seqindex; - int numseqgroups; // demand loaded sequences - int seqgroupindex; - int numtextures; // raw textures - int textureindex; - int texturedataindex; - int numskinref; // replaceable textures - int numskinfamilies; - int skinindex; - int numbodyparts; - int bodypartindex; - int numattachments; // queryable attachable points - int attachmentindex; - int soundtable; - int soundindex; - int soundgroups; - int soundgroupindex; - int numtransitions; // animation node to animation node transition graph - int transitionindex; + int numbonecontrollers; // bone controllers + int bonecontrollerindex; + + int numhitboxes; // complex bounding boxes + int hitboxindex; + + int numseq; // animation sequences + int seqindex; + + int numseqgroups; // demand loaded sequences + int seqgroupindex; + int numtextures; // raw textures + int textureindex; + int texturedataindex; + + int numskinref; // replaceable textures + int numskinfamilies; + int skinindex; + + int numbodyparts; + int bodypartindex; + + int numattachments; // queryable attachable points + int attachmentindex; + + int soundtable; + int soundindex; + int soundgroups; + int soundgroupindex; + + int numtransitions; // animation node to animation node transition graph + int transitionindex; } studiohdr_t; -// bones -typedef struct +// header for demand loaded sequence group data +typedef struct { - char name[32]; // bone name for symbolic links - int parent; // parent bone - int flags; // ?? - int bonecontroller[6]; // bone controller index, -1 == none - float value[6]; // default DoF values - float scale[6]; // scale for delta DoF values + int id; + int version; + char name[64]; + int length; +} studioseqhdr_t; + +// bones +typedef struct +{ + char name[32]; // bone name for symbolic links + int parent; // parent bone + int flags; // ?? + int bonecontroller[6]; // bone controller index, -1 == none + float value[6]; // default DoF values + float scale[6]; // scale for delta DoF values } mstudiobone_t; + // bone controllers -typedef struct +typedef struct { - int bone; // -1 == 0 - int type; // X, Y, Z, XR, YR, ZR, M - float start; - float end; - int rest; // byte index value at rest - int index; // 0-3 user set controller, 4 mouth - + int bone; // -1 == 0 + int type; // X, Y, Z, XR, YR, ZR, M + float start; + float end; + int rest; // byte index value at rest + int index; // 0-3 user set controller, 4 mouth } mstudiobonecontroller_t; -// demand loaded sequence groups +// intersection boxes typedef struct { - char label[32]; // textual name - char name[64]; // file name - int32 unused1; // cache index pointer - int unused2; // hack for group 0 + int bone; + int group; // intersection group + vec3_t bbmin; // bounding box + vec3_t bbmax; +} mstudiobbox_t; +// demand loaded sequence groups +typedef struct +{ + char label[32]; // textual name + char name[64]; // file name + int32 unused1; // was "cache" - index pointer + int unused2; // was "data" - hack for group 0 } mstudioseqgroup_t; // sequence descriptions typedef struct { - char label[32]; // sequence label - float fps; // frames per second - int flags; // looping/non-looping flags - int activity; - int actweight; - int numevents; - int eventindex; - int numframes; // number of frames per sequence - int numpivots; // number of foot pivots - int pivotindex; - int motiontype; - int motionbone; - vec3_t linearmovement; - int automoveposindex; - int automoveangleindex; - vec3_t bbmin; // per sequence bounding box - vec3_t bbmax; - int numblends; - int animindex; // mstudioanim_t pointer relative to start of sequence group data - // [blend][bone][X, Y, Z, XR, YR, ZR] - int blendtype[2]; // X, Y, Z, XR, YR, ZR - float blendstart[2]; // starting value - float blendend[2]; // ending value - int blendparent; - int seqgroup; // sequence group for demand loading - int entrynode; // transition node at entry - int exitnode; // transition node at exit - int nodeflags; // transition rules - int nextseq; // auto advancing sequences + char label[32]; // sequence label + float fps; // frames per second + int flags; // looping/non-looping flags + + int activity; + int actweight; + + int numevents; + int eventindex; + + int numframes; // number of frames per sequence + + int numpivots; // number of foot pivots + int pivotindex; + + int motiontype; + int motionbone; + vec3_t linearmovement; + int automoveposindex; + int automoveangleindex; + + vec3_t bbmin; // per sequence bounding box + vec3_t bbmax; + + int numblends; + int animindex; // mstudioanim_t pointer relative to start of sequence group data + // [blend][bone][X, Y, Z, XR, YR, ZR] + + int blendtype[2]; // X, Y, Z, XR, YR, ZR + float blendstart[2]; // starting value + float blendend[2]; // ending value + int blendparent; + + int seqgroup; // sequence group for demand loading + + int entrynode; // transition node at entry + int exitnode; // transition node at exit + int nodeflags; // transition rules + + int nextseq; // auto advancing sequences } mstudioseqdesc_t; -typedef struct +// events +#include "studio_event.h" +/* +typedef struct +{ + int frame; + int event; + int type; + char options[64]; +} mstudioevent_t; +*/ + +// pivots +typedef struct { - unsigned short offset[6]; + vec3_t org; // pivot point + int start; + int end; +} mstudiopivot_t; +// attachment +typedef struct +{ + char name[32]; + int type; + int bone; + vec3_t org; // attachment point + vec3_t vectors[3]; +} mstudioattachment_t; + +typedef struct +{ + unsigned short offset[6]; } mstudioanim_t; // animation frames -typedef union +typedef union { - struct - { - byte valid; - byte total; + struct { + byte valid; + byte total; } num; - short int value; - + short value; } mstudioanimvalue_t; + + // body part index typedef struct { - char name[64]; - int nummodels; - int base; - int modelindex; // index into models array - + char name[64]; + int nummodels; + int base; + int modelindex; // index into models array } mstudiobodyparts_t; + + +// skin info +typedef struct +{ + char name[64]; + int flags; + int width; + int height; + int index; +} mstudiotexture_t; + + +// skin families +// short index[skinfamilies][skinref] + +// studio models +typedef struct +{ + char name[64]; + + int type; + + float boundingradius; + + int nummesh; + int meshindex; + + int numverts; // number of unique vertices + int vertinfoindex; // vertex bone info + int vertindex; // vertex vec3_t + int numnorms; // number of unique surface normals + int norminfoindex; // normal bone info + int normindex; // normal vec3_t + + int numgroups; // deformation groups + int groupindex; +} mstudiomodel_t; + + +// vec3_t boundingbox[model][bone][2]; // complex intersection info + + +// meshes +typedef struct +{ + int numtris; + int triindex; + int skinref; + int numnorms; // per mesh normals + int normindex; // normal vec3_t +} mstudiomesh_t; + +// triangles +#if 0 +typedef struct +{ + short vertindex; // index into vertex array + short normindex; // index into normal array + short s,t; // s,t position on skin +} mstudiotrivert_t; +#endif + +#define STUDIO_DYNAMIC_LIGHT 0x0100 // dynamically get lighting from floor or ceil (flying monsters) +#define STUDIO_TRACE_HITBOX 0x0200 // always use hitbox trace instead of bbox + +// lighting options +#define STUDIO_NF_FLATSHADE 0x0001 +#define STUDIO_NF_CHROME 0x0002 +#define STUDIO_NF_FULLBRIGHT 0x0004 +#define STUDIO_NF_NOMIPS 0x0008 +#define STUDIO_NF_ALPHA 0x0010 +#define STUDIO_NF_ADDITIVE 0x0020 +#define STUDIO_NF_MASKED 0x0040 + +// motion flags +#define STUDIO_X 0x0001 +#define STUDIO_Y 0x0002 +#define STUDIO_Z 0x0004 +#define STUDIO_XR 0x0008 +#define STUDIO_YR 0x0010 +#define STUDIO_ZR 0x0020 +#define STUDIO_LX 0x0040 +#define STUDIO_LY 0x0080 +#define STUDIO_LZ 0x0100 +#define STUDIO_AX 0x0200 +#define STUDIO_AY 0x0400 +#define STUDIO_AZ 0x0800 +#define STUDIO_AXR 0x1000 +#define STUDIO_AYR 0x2000 +#define STUDIO_AZR 0x4000 +#define STUDIO_TYPES 0x7FFF +#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance + +// sequence flags +#define STUDIO_LOOPING 0x0001 + +// bone flags +#define STUDIO_HAS_NORMALS 0x0001 +#define STUDIO_HAS_VERTICES 0x0002 +#define STUDIO_HAS_BBOX 0x0004 +#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them + +#define RAD_TO_STUDIO (32768.0/M_PI) +#define STUDIO_TO_RAD (M_PI/32768.0) + + +#define STUDIO_NUM_HULLS 128 +#define STUDIO_NUM_PLANES (STUDIO_NUM_HULLS * 6) +#define STUDIO_CACHE_SIZE 16 + #endif // STUDIO_H diff --git a/regamedll/engine/unicode_strtools.cpp b/regamedll/engine/unicode_strtools.cpp index e7e113ba6..6dbf19417 100644 --- a/regamedll/engine/unicode_strtools.cpp +++ b/regamedll/engine/unicode_strtools.cpp @@ -756,9 +756,8 @@ int Q_UnicodeConvertT(const SrcType *pIn, int nInChars, DstType *pOut, int nOutB if (bErr) { -#ifdef _DEBUG - AssertMsg(!(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence"); -#endif + DbgAssertMsg(!(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence"); + if (ePolicy & _STRINGCONVERTFLAG_SKIP) { nOut -= EncodeDstLen(uVal); @@ -793,9 +792,8 @@ int Q_UnicodeConvertT(const SrcType *pIn, int nInChars, DstType *pOut, int nOutB nOut += EncodeDst(uVal, pOut + nOut); if (bErr) { -#ifdef _DEBUG - AssertMsg(!(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence"); -#endif + DbgAssertMsg(!(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence"); + if (ePolicy & _STRINGCONVERTFLAG_SKIP) { nOut -= EncodeDstLen(uVal); diff --git a/regamedll/game_shared/bitvec.h b/regamedll/game_shared/bitvec.h index 52f91b539..36c6b7384 100644 --- a/regamedll/game_shared/bitvec.h +++ b/regamedll/game_shared/bitvec.h @@ -127,7 +127,7 @@ inline CBitVec &CBitVec::operator=(CBitVec const & template inline CBitVecAccessor CBitVec::operator[](int i) { - assert(i >= 0 && i < GetNumBits()); + DbgAssert(i >= 0 && i < GetNumBits()); return CBitVecAccessor(m_DWords, i); } @@ -152,13 +152,13 @@ inline bool CBitVec::operator!=(CBitVec const &other) template inline uint32 CBitVec::GetDWord(int i) { - assert(i >= 0 && i < NUM_DWORDS); + DbgAssert(i >= 0 && i < NUM_DWORDS); return m_DWords[i]; } template inline void CBitVec::SetDWord(int i, uint32 val) { - assert(i >= 0 && i < NUM_DWORDS); + DbgAssert(i >= 0 && i < NUM_DWORDS); m_DWords[i] = val; } diff --git a/regamedll/game_shared/bot/bot_manager.cpp b/regamedll/game_shared/bot/bot_manager.cpp index 6e75cef75..285a26a36 100644 --- a/regamedll/game_shared/bot/bot_manager.cpp +++ b/regamedll/game_shared/bot/bot_manager.cpp @@ -213,10 +213,12 @@ const char *CBotManager::GetNavMapFilename() const return filename; } +LINK_HOOK_CLASS_VOID_CHAIN(CBotManager, OnEvent, (GameEventType event, CBaseEntity* pEntity, CBaseEntity* pOther), event, pEntity, pOther) + // Invoked when given player does given event (some events have NULL player). // Events are propogated to all bots. // TODO: This has become the game-wide event dispatcher. We should restructure this. -void CBotManager::OnEvent(GameEventType event, CBaseEntity *pEntity, CBaseEntity *pOther) +void CBotManager::__API_HOOK(OnEvent)(GameEventType event, CBaseEntity* pEntity, CBaseEntity* pOther) { // propogate event to all bots for (int i = 1; i <= gpGlobals->maxClients; i++) diff --git a/regamedll/game_shared/bot/bot_manager.h b/regamedll/game_shared/bot/bot_manager.h index 788c54ca9..dfcfd8edc 100644 --- a/regamedll/game_shared/bot/bot_manager.h +++ b/regamedll/game_shared/bot/bot_manager.h @@ -81,6 +81,10 @@ class CBotManager virtual void OnEvent(GameEventType event, CBaseEntity *pEntity = nullptr, CBaseEntity *pOther = nullptr); // Invoked when event occurs in the game (some events have NULL entity). virtual unsigned int GetPlayerPriority(CBasePlayer *pPlayer) const = 0; // return priority of player (0 = max pri) +#ifdef REGAMEDLL_API + void OnEvent_OrigFunc(GameEventType event, CBaseEntity* pEntity = nullptr, CBaseEntity* pOther = nullptr); +#endif + public: const char *GetNavMapFilename() const; // return the filename for this map's "nav" file diff --git a/regamedll/game_shared/bot/bot_util.cpp b/regamedll/game_shared/bot/bot_util.cpp index d14aaaeba..9b5e2013e 100644 --- a/regamedll/game_shared/bot/bot_util.cpp +++ b/regamedll/game_shared/bot/bot_util.cpp @@ -613,6 +613,13 @@ void CONSOLE_ECHO_LOGGED(const char *pszMsg, ...) void BotPrecache() { +#ifdef REGAMEDLL_FIXES + // all resources above are used between navarea, improved bots and tutor + // you can run cs1.6 with bots so it's not only limited to czero + if (!AreRunningCZero() && !AreBotsAllowed()) + return; +#endif + s_iBeamSprite = PRECACHE_MODEL("sprites/smoke.spr"); PRECACHE_SOUND("buttons/bell1.wav"); @@ -621,7 +628,12 @@ void BotPrecache() PRECACHE_SOUND("buttons/button11.wav"); PRECACHE_SOUND("buttons/latchunlocked2.wav"); PRECACHE_SOUND("buttons/lightswitch2.wav"); - PRECACHE_SOUND("ambience/quail1.wav"); + +#ifdef REGAMEDLL_FIXES + PRECACHE_GENERIC("sound/ambience/quail1.wav"); +#else + PRECACHE_SOUND("ambience/quail1.wav"); // not used internally +#endif PRECACHE_SOUND("events/tutor_msg.wav"); PRECACHE_SOUND("events/enemy_died.wav"); diff --git a/regamedll/game_shared/bot/nav_file.cpp b/regamedll/game_shared/bot/nav_file.cpp index 1e8bf7170..ad04f52c9 100644 --- a/regamedll/game_shared/bot/nav_file.cpp +++ b/regamedll/game_shared/bot/nav_file.cpp @@ -15,7 +15,6 @@ #include #include -#include #ifndef _WIN32 #include @@ -42,7 +41,7 @@ PlaceDirectory::EntryType PlaceDirectory::GetEntry(Place place) const auto it = std::find(m_directory.begin(), m_directory.end(), place); if (it == m_directory.end()) { - assert(false && "PlaceDirectory::GetEntry failure"); + DbgAssert(false && "PlaceDirectory::GetEntry failure"); return 0; } @@ -54,7 +53,7 @@ void PlaceDirectory::AddPlace(Place place) if (place == UNDEFINED_PLACE) return; - assert(place < 1000); + DbgAssert(place < 1000); if (IsKnown(place)) return; @@ -70,7 +69,7 @@ Place PlaceDirectory::EntryToPlace(EntryType entry) const unsigned int i = entry - 1; if (i > m_directory.size()) { - assert(false && "PlaceDirectory::EntryToPlace: Invalid entry"); + DbgAssert(false && "PlaceDirectory::EntryToPlace: Invalid entry"); return UNDEFINED_PLACE; } diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj index 3e882d9e6..57e09e917 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj +++ b/regamedll/msvc/ReGameDLL.vcxproj @@ -47,6 +47,10 @@ + + + + @@ -536,14 +540,9 @@ - - - - - - true - true - + + + true true @@ -783,6 +782,8 @@ + + @@ -805,6 +806,9 @@ false + + + {70A2B904-B7DB-4C48-8DE0-AF567360D572} ReGameDLL @@ -818,7 +822,8 @@ v120 v140 v141 - v142 + v142 + v143 DynamicLibrary @@ -827,7 +832,8 @@ v120 v140 v141 - v142 + v142 + v143 true @@ -837,7 +843,8 @@ v120 v140 v141 - v142 + v142 + v143 true @@ -847,7 +854,8 @@ v120 v140 v141 - v142 + v142 + v143 Application @@ -855,7 +863,8 @@ v120_xp v140_xp v141_xp - v142 + v142 + v143 MultiByte diff --git a/regamedll/msvc/ReGameDLL.vcxproj.filters b/regamedll/msvc/ReGameDLL.vcxproj.filters index d8c27981d..ef2017ae4 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj.filters +++ b/regamedll/msvc/ReGameDLL.vcxproj.filters @@ -540,6 +540,9 @@ dlls\API + + dlls\API + regamedll @@ -552,6 +555,12 @@ public + + public\tier0 + + + public\tier0 + @@ -1049,5 +1058,16 @@ dlls\addons + + public + + + public\tier0 + + + + + public\tier0 + \ No newline at end of file diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp index 75d4a4909..b41a23927 100644 --- a/regamedll/pm_shared/pm_shared.cpp +++ b/regamedll/pm_shared/pm_shared.cpp @@ -12,6 +12,10 @@ char pm_grgchTextureType[MAX_TEXTURES]; playermove_t *pmove = nullptr; BOOL g_onladder = FALSE; +#ifdef REGAMEDLL_API +static CCSPlayer *pmoveplayer = nullptr; +#endif + #ifdef CLIENT_DLL int iJumpSpectator; float vJumpOrigin[3]; @@ -134,7 +138,7 @@ char EXT_FUNC PM_FindTextureType(char *name) int left, right, pivot; int val; - assert(pm_shared_initialized); + DbgAssert(pm_shared_initialized); left = 0; right = pm_gcTextures - 1; @@ -162,7 +166,9 @@ char EXT_FUNC PM_FindTextureType(char *name) return CHAR_TEX_CONCRETE; } -void PM_PlayStepSound(int step, float fvol) +LINK_HOOK_VOID_CHAIN(PM_PlayStepSound, (int step, float fvol), step, fvol) + +void EXT_FUNC __API_HOOK(PM_PlayStepSound)(int step, float fvol) { static int iSkipStep = 0; int irand; @@ -365,7 +371,7 @@ void PM_CatagorizeTextureType() pmove->chtexturetype = PM_FindTextureType(pmove->sztexturename); } -LINK_HOOK_VOID_CHAIN2(PM_UpdateStepSound); +LINK_HOOK_VOID_CHAIN2(PM_UpdateStepSound) void EXT_FUNC __API_HOOK(PM_UpdateStepSound)() { @@ -1127,7 +1133,9 @@ void PM_Friction() VectorCopy(newvel, pmove->velocity); } -void PM_AirAccelerate(vec_t *wishdir, float wishspeed, float accel) +LINK_HOOK_VOID_CHAIN(PM_AirAccelerate, (vec_t *wishdir, float wishspeed, float accel), wishdir, wishspeed, accel) + +void EXT_FUNC __API_HOOK(PM_AirAccelerate)(vec_t *wishdir, float wishspeed, float accel) { int i; float addspeed; @@ -1274,7 +1282,7 @@ void PM_WaterMove() PM_FlyMove(); } -LINK_HOOK_VOID_CHAIN(PM_AirMove, (int playerIndex = 0), pmove->player_index + 1); +LINK_HOOK_VOID_CHAIN(PM_AirMove, (int playerIndex = 0), pmove->player_index + 1) void EXT_FUNC __API_HOOK(PM_AirMove)(int playerIndex) { @@ -1793,7 +1801,9 @@ void PM_FixPlayerCrouchStuck(int direction) VectorCopy(test, pmove->origin); } -void PM_UnDuck() +LINK_HOOK_VOID_CHAIN2(PM_UnDuck) + +void EXT_FUNC __API_HOOK(PM_UnDuck)() { #ifdef REGAMEDLL_ADD if (unduck_method.value) @@ -1863,7 +1873,9 @@ void PM_UnDuck() } } -void PM_Duck() +LINK_HOOK_VOID_CHAIN2(PM_Duck) + +void EXT_FUNC __API_HOOK(PM_Duck)() { int buttonsChanged = (pmove->oldbuttons ^ pmove->cmd.buttons); // These buttons have changed this frame int nButtonPressed = buttonsChanged & pmove->cmd.buttons; // The changed ones still down are "pressed" @@ -1881,8 +1893,8 @@ void PM_Duck() } #ifdef REGAMEDLL_ADD - // Prevent ducking if the iuser3 variable is contain PLAYER_PREVENT_DUCK - if ((pmove->iuser3 & PLAYER_PREVENT_DUCK) == PLAYER_PREVENT_DUCK) + if ((pmove->iuser3 & PLAYER_PREVENT_DUCK) == PLAYER_PREVENT_DUCK // Prevent ducking if the iuser3 variable is contain PLAYER_PREVENT_DUCK + || freezetime_duck.value == 0.0f && CSGameRules()->IsFreezePeriod()) // Prevent ducking during freezetime if the freezetime_duck cvar is 0 { // Try to unduck if (pmove->flags & FL_DUCKING) @@ -1899,9 +1911,16 @@ void PM_Duck() return; } - pmove->cmd.forwardmove *= PLAYER_DUCKING_MULTIPLIER; - pmove->cmd.sidemove *= PLAYER_DUCKING_MULTIPLIER; - pmove->cmd.upmove *= PLAYER_DUCKING_MULTIPLIER; + real_t mult = PLAYER_DUCKING_MULTIPLIER; + +#ifdef REGAMEDLL_API + if (pmoveplayer->m_flDuckSpeedMultiplier > 0.0) + mult = pmoveplayer->m_flDuckSpeedMultiplier; +#endif + + pmove->cmd.forwardmove *= mult; + pmove->cmd.sidemove *= mult; + pmove->cmd.upmove *= mult; if (pmove->cmd.buttons & IN_DUCK) { @@ -1967,7 +1986,9 @@ void PM_Duck() } } -void PM_LadderMove(physent_t *pLadder) +LINK_HOOK_VOID_CHAIN(PM_LadderMove, (physent_t *pLadder), pLadder) + +void EXT_FUNC __API_HOOK(PM_LadderMove)(physent_t *pLadder) { vec3_t ladderCenter; trace_t trace; @@ -2013,7 +2034,16 @@ void PM_LadderMove(physent_t *pLadder) if (pmove->flags & FL_DUCKING) { - flSpeed *= PLAYER_DUCKING_MULTIPLIER; +#ifdef REGAMEDLL_API + if (pmoveplayer->m_flDuckSpeedMultiplier > 0.0) + { + flSpeed *= pmoveplayer->m_flDuckSpeedMultiplier; + } + else +#endif + { + flSpeed *= PLAYER_DUCKING_MULTIPLIER; + } } if (pmove->cmd.buttons & IN_BACK) @@ -2117,7 +2147,9 @@ physent_t *PM_Ladder() return nullptr; } -void PM_WaterJump() +LINK_HOOK_VOID_CHAIN2(PM_WaterJump) + +void EXT_FUNC __API_HOOK(PM_WaterJump)() { if (pmove->waterjumptime > 10000) { @@ -2342,7 +2374,23 @@ void PM_PreventMegaBunnyJumping() VectorScale(pmove->velocity, fraction, pmove->velocity); } -void PM_Jump() +inline real_t PM_JumpHeight(bool longjump) +{ +#ifdef REGAMEDLL_API + if (longjump) + { + if(pmoveplayer->m_flLongJumpHeight > 0.0) + return pmoveplayer->m_flLongJumpHeight; + } + else if (pmoveplayer->m_flJumpHeight > 0.0) + return pmoveplayer->m_flJumpHeight; +#endif + return Q_sqrt(2.0 * 800.0f * (longjump ? 56.0f : 45.0f)); +} + +LINK_HOOK_VOID_CHAIN2(PM_Jump) + +void EXT_FUNC __API_HOOK(PM_Jump)() { if (pmove->dead) { @@ -2401,8 +2449,8 @@ void PM_Jump() } #ifdef REGAMEDLL_ADD - // Prevent jumping if the iuser3 variable is contain PLAYER_PREVENT_JUMP - if ((pmove->iuser3 & PLAYER_PREVENT_JUMP) == PLAYER_PREVENT_JUMP) + if ((pmove->iuser3 & PLAYER_PREVENT_JUMP) == PLAYER_PREVENT_JUMP // Prevent jumping if the iuser3 variable is contain PLAYER_PREVENT_JUMP + || freezetime_jump.value == 0.0f && CSGameRules()->IsFreezePeriod()) // Prevent jumping during freezetime if the freezetime_jump cvar is 0 { return; } @@ -2418,16 +2466,12 @@ void PM_Jump() return; } -#ifdef REGAMEDLL_API - const CCSPlayer* player = UTIL_PlayerByIndex(pmove->player_index + 1)->CSPlayer(); -#endif - // don't pogo stick if (pmove->oldbuttons & IN_JUMP #ifdef REGAMEDLL_ADD && sv_autobunnyhopping.value <= 0.0 #ifdef REGAMEDLL_API - && !player->m_bAutoBunnyHopping + && !pmoveplayer->m_bAutoBunnyHopping #endif #endif ) @@ -2448,7 +2492,7 @@ void PM_Jump() #ifdef REGAMEDLL_ADD if (sv_enablebunnyhopping.value <= 0.0 #ifdef REGAMEDLL_API - && !player->m_bMegaBunnyJumping + && !pmoveplayer->m_bMegaBunnyJumping #endif ) #endif @@ -2478,23 +2522,34 @@ void PM_Jump() { pmove->punchangle[0] = -5.0f; - for (int i = 0; i < 2; i++) +#ifdef REGAMEDLL_API + if (pmoveplayer->m_flLongJumpForce > 0.0) { - pmove->velocity[i] = pmove->forward[i] * PLAYER_LONGJUMP_SPEED * 1.6f; + fvel = pmoveplayer->m_flLongJumpForce; + } + else +#endif + { + fvel = PLAYER_LONGJUMP_SPEED * 1.6f; + } + + for (int i = 0; i < 2; i++) + { + pmove->velocity[i] = pmove->forward[i] * fvel; } - pmove->velocity[2] = Q_sqrt(2 * 800 * 56.0f); + pmove->velocity[2] = PM_JumpHeight(true); } else { - pmove->velocity[2] = Q_sqrt(2 * 800 * 45.0f); + pmove->velocity[2] = PM_JumpHeight(false); } } else #endif { // NOTE: don't do it in .f (float) - pmove->velocity[2] = Q_sqrt(2.0 * 800.0f * 45.0f); + pmove->velocity[2] = PM_JumpHeight(false); } if (pmove->fuser2 > 0.0f) @@ -2514,7 +2569,9 @@ void PM_Jump() pmove->oldbuttons |= IN_JUMP; } -void PM_CheckWaterJump() +LINK_HOOK_VOID_CHAIN2(PM_CheckWaterJump) + +void EXT_FUNC __API_HOOK(PM_CheckWaterJump)() { vec3_t vecStart, vecEnd; vec3_t flatforward; @@ -3207,7 +3264,7 @@ void PM_CreateStuckTable() } } -LINK_HOOK_VOID_CHAIN(PM_Move, (struct playermove_s *ppmove, int server), ppmove, server); +LINK_HOOK_VOID_CHAIN(PM_Move, (struct playermove_s *ppmove, int server), ppmove, server) // This module implements the shared player physics code between any particular game and // the engine. The same PM_Move routine is built into the game .dll and the client .dll and is @@ -3215,9 +3272,13 @@ LINK_HOOK_VOID_CHAIN(PM_Move, (struct playermove_s *ppmove, int server), ppmove, // and client. This will ensure that prediction behaves appropriately. void EXT_FUNC __API_HOOK(PM_Move)(struct playermove_s *ppmove, int server) { - assert(pm_shared_initialized); + DbgAssert(pm_shared_initialized); pmove = ppmove; + +#ifdef REGAMEDLL_API + pmoveplayer = UTIL_PlayerByIndex(pmove->player_index + 1)->CSPlayer(); +#endif PM_PlayerMove((server != 0) ? TRUE : FALSE); @@ -3252,11 +3313,11 @@ NOXREF int PM_GetPhysEntInfo(int ent) return -1; } -LINK_HOOK_VOID_CHAIN(PM_Init, (struct playermove_s *ppmove), ppmove); +LINK_HOOK_VOID_CHAIN(PM_Init, (struct playermove_s *ppmove), ppmove) void EXT_FUNC __API_HOOK(PM_Init)(struct playermove_s *ppmove) { - assert(!pm_shared_initialized); + DbgAssert(!pm_shared_initialized); pmove = ppmove; diff --git a/regamedll/pm_shared/pm_shared.h b/regamedll/pm_shared/pm_shared.h index 94113ae0a..2c0385f40 100644 --- a/regamedll/pm_shared/pm_shared.h +++ b/regamedll/pm_shared/pm_shared.h @@ -77,12 +77,21 @@ void PM_Init(struct playermove_s *ppmove); void PM_Move(struct playermove_s *ppmove, int server); char PM_FindTextureType(char *name); void PM_AirMove_internal(); +void PM_LadderMove(physent_t *pLadder); #ifdef REGAMEDLL_API void PM_Init_OrigFunc(struct playermove_s *ppmove); void PM_Move_OrigFunc(struct playermove_s *ppmove, int server); void PM_AirMove_OrigFunc(int playerIndex = 0); void PM_UpdateStepSound_OrigFunc(); +void PM_LadderMove_OrigFunc(physent_t *pLadder); +void PM_WaterJump_OrigFunc(); +void PM_CheckWaterJump_OrigFunc(); +void PM_Jump_OrigFunc(); +void PM_Duck_OrigFunc(); +void PM_UnDuck_OrigFunc(); +void PM_PlayStepSound_OrigFunc(int step, float fvol); +void PM_AirAccelerate_OrigFunc(vec_t *wishdir, float wishspeed, float accel); #else void PM_AirMove(int playerIndex = 0); #endif diff --git a/regamedll/public/interface.cpp b/regamedll/public/interface.cpp index 8c6dd0ccc..d1cf92830 100644 --- a/regamedll/public/interface.cpp +++ b/regamedll/public/interface.cpp @@ -230,7 +230,7 @@ void *InitializeInterface(char const *interfaceName, CreateInterfaceFn *factoryL } // No provider for requested interface!!! - // assert(!"No provider for requested interface!!!"); + // Assert(!"No provider for requested interface!!!"); return nullptr; } diff --git a/regamedll/public/regamedll/API/CSEntity.h b/regamedll/public/regamedll/API/CSEntity.h index 92882bd84..4d73075e7 100644 --- a/regamedll/public/regamedll/API/CSEntity.h +++ b/regamedll/public/regamedll/API/CSEntity.h @@ -33,8 +33,10 @@ class CCSEntity { public: CCSEntity() : - m_pContainingEntity(nullptr) + m_pContainingEntity(nullptr), + m_pevLastInflictor(nullptr) { + m_ucDmgPenetrationLevel = 0; } virtual ~CCSEntity() {} @@ -42,13 +44,19 @@ class CCSEntity virtual void FireBuckshots(ULONG cShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iTracerFreq, int iDamage, entvars_t *pevAttacker); virtual Vector 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); + CBaseEntity *BaseEntity() const; + public: CBaseEntity *m_pContainingEntity; + unsigned char m_ucDmgPenetrationLevel; // penetration level of the damage caused by the inflictor + entvars_t *m_pevLastInflictor; private: #if defined(_MSC_VER) -#pragma region reserve_vfuncs_Region +#pragma region reserve_data_Region #endif + char CCSEntity_Reserve[0x3FF7]; + virtual void func_reserve1() {}; virtual void func_reserve2() {}; virtual void func_reserve3() {}; @@ -84,28 +92,71 @@ class CCSEntity #endif }; +// Inlines +inline CBaseEntity *CCSEntity::BaseEntity() const +{ + return this->m_pContainingEntity; +} + +#ifdef REGAMEDLL_API +inline void CBaseEntity::SetDmgPenetrationLevel(int iPenetrationLevel) +{ + CSEntity()->m_ucDmgPenetrationLevel = iPenetrationLevel; +} + +inline void CBaseEntity::ResetDmgPenetrationLevel() +{ + CSEntity()->m_ucDmgPenetrationLevel = 0; +} + +inline int CBaseEntity::GetDmgPenetrationLevel() const +{ + return CSEntity()->m_ucDmgPenetrationLevel; +} + +inline void CBaseEntity::KilledInflicted(entvars_t *pevInflictor, entvars_t *pevAttacker, int iGib) +{ + CSEntity()->m_pevLastInflictor = pevInflictor; + Killed(pevAttacker, iGib); + CSEntity()->m_pevLastInflictor = nullptr; +} + +inline entvars_t *CBaseEntity::GetLastInflictor() +{ + return CSEntity()->m_pevLastInflictor; +} +#endif + class CCSDelay: public CCSEntity { public: +private: + int CCSDelay_Reserve[0x100]; }; class CCSAnimating: public CCSDelay { public: +private: + int CCSAnimating_Reserve[0x100]; }; class CCSToggle: public CCSAnimating { public: +private: + int CCSToggle_Reserve[0x100]; }; class CCSMonster: public CCSToggle { public: +private: + int CCSMonster_Reserve[0x100]; }; -#define CSENTITY_API_INTERFACE_VERSION "CSENTITY_API_INTERFACE_VERSION002" +#define CSENTITY_API_INTERFACE_VERSION "CSENTITY_API_INTERFACE_VERSION003" diff --git a/regamedll/public/regamedll/API/CSPlayer.h b/regamedll/public/regamedll/API/CSPlayer.h index 9ce4c15d0..18558a433 100644 --- a/regamedll/public/regamedll/API/CSPlayer.h +++ b/regamedll/public/regamedll/API/CSPlayer.h @@ -30,6 +30,7 @@ #include #include +#include enum WeaponInfiniteAmmoMode { @@ -50,9 +51,23 @@ class CCSPlayer: public CCSMonster { m_bAutoBunnyHopping(false), m_bMegaBunnyJumping(false), m_bPlantC4Anywhere(false), - m_iAliveNameChanges(0) + m_iAliveNameChanges(0), + m_bSpawnProtectionEffects(false), + m_flJumpHeight(0), + m_flLongJumpHeight(0), + m_flLongJumpForce(0), + m_flDuckSpeedMultiplier(0), + m_iUserID(-1), + m_iGibDamageThreshold(GIB_PLAYER_THRESHOLD) { m_szModel[0] = '\0'; + + // Resets the kill history for this player + for (int i = 0; i < MAX_CLIENTS; i++) + { + m_iNumKilledByUnanswered[i] = 0; + m_bPlayerDominated[i] = false; + } } virtual bool IsConnected() const; @@ -62,8 +77,8 @@ class CCSPlayer: public CCSMonster { virtual CBaseEntity *GiveNamedItemEx(const char *pszName); virtual void GiveDefaultItems(); virtual void GiveShield(bool bDeploy = true); - virtual void DropShield(bool bDeploy = true); - virtual void DropPlayerItem(const char *pszItemName); + virtual CBaseEntity *DropShield(bool bDeploy = true); + virtual CBaseEntity* DropPlayerItem(const char *pszItemName); virtual bool RemoveShield(); virtual void RemoveAllItems(bool bRemoveSuit); virtual bool RemovePlayerItem(const char* pszItemName); @@ -100,11 +115,19 @@ class CCSPlayer: public CCSMonster { virtual void SetSpawnProtection(float flProtectionTime); virtual void RemoveSpawnProtection(); virtual bool HintMessageEx(const char *pMessage, float duration = 6.0f, bool bDisplayIfPlayerDead = false, bool bOverride = false); + virtual void Reset(); + virtual void OnSpawnEquip(bool addDefault = true, bool equipGame = true); + virtual void SetScoreboardAttributes(CBasePlayer *destination = nullptr); + + bool IsPlayerDominated(int iPlayerIndex) const; + void SetPlayerDominated(CBasePlayer *pPlayer, bool bDominated); - void Reset(); + void ResetVars(); + void ResetAllStats(); void OnSpawn(); void OnKilled(); + void OnConnect(); CBasePlayer *BasePlayer() const; @@ -133,6 +156,27 @@ class CCSPlayer: public CCSMonster { bool m_bMegaBunnyJumping; bool m_bPlantC4Anywhere; int m_iAliveNameChanges; + bool m_bSpawnProtectionEffects; + double m_flJumpHeight; + double m_flLongJumpHeight; + double m_flLongJumpForce; + double m_flDuckSpeedMultiplier; + + int m_iUserID; + struct CDamageRecord_t + { + float flDamage = 0.0f; + float flFlashDurationTime = 0.0f; + int userId = -1; + }; + using DamageList_t = CUtlArray; + DamageList_t m_DamageList; // A unified array of recorded damage that includes giver and taker in each entry + DamageList_t &GetDamageList() { return m_DamageList; } + void RecordDamage(CBasePlayer *pAttacker, float flDamage, float flFlashDurationTime = -1); + int m_iNumKilledByUnanswered[MAX_CLIENTS]; // [0-31] how many unanswered kills this player has been dealt by each other player + bool m_bPlayerDominated[MAX_CLIENTS]; // [0-31] array of state per other player whether player is dominating other players + + int m_iGibDamageThreshold; // negative health to reach to gib player }; // Inlines @@ -154,3 +198,37 @@ inline CCSPlayer::EProtectionState CCSPlayer::GetProtectionState() const // has expired return ProtectionSt_Expired; } + +// Returns whether this player is dominating the specified other player +inline bool CCSPlayer::IsPlayerDominated(int iPlayerIndex) const +{ + if (iPlayerIndex < 0 || iPlayerIndex >= MAX_CLIENTS) + return false; + + return m_bPlayerDominated[iPlayerIndex]; +} + +// Sets whether this player is dominating the specified other player +inline void CCSPlayer::SetPlayerDominated(CBasePlayer *pPlayer, bool bDominated) +{ + int iPlayerIndex = pPlayer->entindex(); + Assert(iPlayerIndex > 0 && iPlayerIndex <= MAX_CLIENTS); + m_bPlayerDominated[iPlayerIndex - 1] = bDominated; +} + +#ifdef 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 < CSPlayer()->m_iGibDamageThreshold && iGib != GIB_NEVER) + return true; + + // do not gib the player + return false; +} +#endif diff --git a/regamedll/public/regamedll/API/CSPlayerWeapon.h b/regamedll/public/regamedll/API/CSPlayerWeapon.h index 70317c931..22c020464 100644 --- a/regamedll/public/regamedll/API/CSPlayerWeapon.h +++ b/regamedll/public/regamedll/API/CSPlayerWeapon.h @@ -28,19 +28,32 @@ #pragma once +enum SecondaryAtkState : uint8_t +{ + WEAPON_SECONDARY_ATTACK_NONE = 0, + WEAPON_SECONDARY_ATTACK_SET, + WEAPON_SECONDARY_ATTACK_BLOCK +}; + class CBasePlayerWeapon; class CCSPlayerWeapon: public CCSPlayerItem { public: CCSPlayerWeapon() : - m_bHasSecondaryAttack(false) + m_iStateSecondaryAttack(WEAPON_SECONDARY_ATTACK_NONE) { } + virtual BOOL DefaultDeploy(char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal = 0); + virtual int DefaultReload(int iClipSize, int iAnim, float fDelay); + virtual bool DefaultShotgunReload(int iAnim, int iStartAnim, float fDelay, float fStartDelay, const char *pszReloadSound1 = nullptr, const char *pszReloadSound2 = nullptr); + virtual void KickBack(float up_base, float lateral_base, float up_modifier, float lateral_modifier, float up_max, float lateral_max, int direction_change); + virtual void SendWeaponAnim(int iAnim, int skiplocal = 0); + CBasePlayerWeapon *BasePlayerWeapon() const; public: - bool m_bHasSecondaryAttack; + SecondaryAtkState m_iStateSecondaryAttack; float m_flBaseDamage; }; @@ -49,3 +62,4 @@ inline CBasePlayerWeapon *CCSPlayerWeapon::BasePlayerWeapon() const { return reinterpret_cast(this->m_pContainingEntity); } + diff --git a/regamedll/public/regamedll/regamedll_api.h b/regamedll/public/regamedll/regamedll_api.h index ba7a8517c..4aeb12545 100644 --- a/regamedll/public/regamedll/regamedll_api.h +++ b/regamedll/public/regamedll/regamedll_api.h @@ -38,7 +38,7 @@ #include #define REGAMEDLL_API_VERSION_MAJOR 5 -#define REGAMEDLL_API_VERSION_MINOR 21 +#define REGAMEDLL_API_VERSION_MINOR 26 // CBasePlayer::Spawn hook typedef IHookChainClass IReGameHook_CBasePlayer_Spawn; @@ -337,8 +337,8 @@ typedef IHookChain IReGameHook_CSGameRules_RemoveGuns; typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_RemoveGuns; // CHalfLifeMultiplay::GiveC4 hook -typedef IHookChain IReGameHook_CSGameRules_GiveC4; -typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_GiveC4; +typedef IHookChain IReGameHook_CSGameRules_GiveC4; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_GiveC4; // CHalfLifeMultiplay::ChangeLevel hook typedef IHookChain IReGameHook_CSGameRules_ChangeLevel; @@ -520,6 +520,110 @@ typedef IHookChainRegistryClass IReGameHookRegistry_CBa typedef IHookChainClass IReGameHook_CBasePlayer_JoiningThink; typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_JoiningThink; +// FreeGameRules hook +typedef IHookChain IReGameHook_FreeGameRules; +typedef IHookChainRegistry IReGameHookRegistry_FreeGameRules; + +// PM_LadderMove hook +typedef IHookChain IReGameHook_PM_LadderMove; +typedef IHookChainRegistry IReGameHookRegistry_PM_LadderMove; + +// PM_WaterJump hook +typedef IHookChain IReGameHook_PM_WaterJump; +typedef IHookChainRegistry IReGameHookRegistry_PM_WaterJump; + +// PM_CheckWaterJump hook +typedef IHookChain IReGameHook_PM_CheckWaterJump; +typedef IHookChainRegistry IReGameHookRegistry_PM_CheckWaterJump; + +// PM_Jump hook +typedef IHookChain IReGameHook_PM_Jump; +typedef IHookChainRegistry IReGameHookRegistry_PM_Jump; + +// PM_Duck hook +typedef IHookChain IReGameHook_PM_Duck; +typedef IHookChainRegistry IReGameHookRegistry_PM_Duck; + +// PM_UnDuck hook +typedef IHookChain IReGameHook_PM_UnDuck; +typedef IHookChainRegistry IReGameHookRegistry_PM_UnDuck; + +// PM_PlayStepSound hook +typedef IHookChain IReGameHook_PM_PlayStepSound; +typedef IHookChainRegistry IReGameHookRegistry_PM_PlayStepSound; + +// PM_AirAccelerate hook +typedef IHookChain IReGameHook_PM_AirAccelerate; +typedef IHookChainRegistry IReGameHookRegistry_PM_AirAccelerate; + +// ClearMultiDamage hook +typedef IHookChain IReGameHook_ClearMultiDamage; +typedef IHookChainRegistry IReGameHookRegistry_ClearMultiDamage; + +// AddMultiDamage hook +typedef IHookChain IReGameHook_AddMultiDamage; +typedef IHookChainRegistry IReGameHookRegistry_AddMultiDamage; + +// ApplyMultiDamage hook +typedef IHookChain IReGameHook_ApplyMultiDamage; +typedef IHookChainRegistry IReGameHookRegistry_ApplyMultiDamage; + +// BuyItem hook +typedef IHookChain IReGameHook_BuyItem; +typedef IHookChainRegistry IReGameHookRegistry_BuyItem; + +// CHalfLifeMultiplay::Think hook +typedef IHookChain IReGameHook_CSGameRules_Think; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_Think; + +// CHalfLifeMultiplay::TeamFull hook +typedef IHookChain IReGameHook_CSGameRules_TeamFull; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_TeamFull; + +// CHalfLifeMultiplay::TeamStacked hook +typedef IHookChain IReGameHook_CSGameRules_TeamStacked; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_TeamStacked; + +// CHalfLifeMultiplay::PlayerGotWeapon hook +typedef IHookChain IReGameHook_CSGameRules_PlayerGotWeapon; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_PlayerGotWeapon; + +// CBotManager::OnEvent hook +typedef IHookChain IReGameHook_CBotManager_OnEvent; +typedef IHookChainRegistry IReGameHookRegistry_CBotManager_OnEvent; + +// CBasePlayer::CheckTimeBasedDamage hook +typedef IHookChainClass IReGameHook_CBasePlayer_CheckTimeBasedDamage; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_CheckTimeBasedDamage; + +// CBasePlayer::EntSelectSpawnPoint hook +typedef IHookChainClass IReGameHook_CBasePlayer_EntSelectSpawnPoint; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_EntSelectSpawnPoint; + +// CBasePlayerWeapon::ItemPostFrame hook +typedef IHookChainClass IReGameHook_CBasePlayerWeapon_ItemPostFrame; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayerWeapon_ItemPostFrame; + +// CBasePlayerWeapon::KickBack hook +typedef IHookChainClass IReGameHook_CBasePlayerWeapon_KickBack; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayerWeapon_KickBack; + +// CBasePlayerWeapon::SendWeaponAnim hook +typedef IHookChainClass IReGameHook_CBasePlayerWeapon_SendWeaponAnim; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayerWeapon_SendWeaponAnim; + +// CHalfLifeMultiplay::SendDeathMessage hook +typedef IHookChain IReGameHook_CSGameRules_SendDeathMessage; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_SendDeathMessage; + +// CBasePlayer::PlayerDeathThink hook +typedef IHookChainClass IReGameHook_CBasePlayer_PlayerDeathThink; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_PlayerDeathThink; + +// CBasePlayer::Observer_Think hook +typedef IHookChainClass IReGameHook_CBasePlayer_Observer_Think; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Observer_Think; + class IReGameHookchains { public: virtual ~IReGameHookchains() {} @@ -653,6 +757,34 @@ class IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_Pain *CBasePlayer_Pain() = 0; virtual IReGameHookRegistry_CBasePlayer_DeathSound *CBasePlayer_DeathSound() = 0; virtual IReGameHookRegistry_CBasePlayer_JoiningThink *CBasePlayer_JoiningThink() = 0; + + virtual IReGameHookRegistry_FreeGameRules *FreeGameRules() = 0; + virtual IReGameHookRegistry_PM_LadderMove *PM_LadderMove() = 0; + virtual IReGameHookRegistry_PM_WaterJump *PM_WaterJump() = 0; + virtual IReGameHookRegistry_PM_CheckWaterJump *PM_CheckWaterJump() = 0; + virtual IReGameHookRegistry_PM_Jump *PM_Jump() = 0; + virtual IReGameHookRegistry_PM_Duck *PM_Duck() = 0; + virtual IReGameHookRegistry_PM_UnDuck *PM_UnDuck() = 0; + virtual IReGameHookRegistry_PM_PlayStepSound *PM_PlayStepSound() = 0; + virtual IReGameHookRegistry_PM_AirAccelerate *PM_AirAccelerate() = 0; + virtual IReGameHookRegistry_ClearMultiDamage *ClearMultiDamage() = 0; + virtual IReGameHookRegistry_AddMultiDamage *AddMultiDamage() = 0; + virtual IReGameHookRegistry_ApplyMultiDamage *ApplyMultiDamage() = 0; + virtual IReGameHookRegistry_BuyItem *BuyItem() = 0; + virtual IReGameHookRegistry_CSGameRules_Think *CSGameRules_Think() = 0; + virtual IReGameHookRegistry_CSGameRules_TeamFull *CSGameRules_TeamFull() = 0; + virtual IReGameHookRegistry_CSGameRules_TeamStacked *CSGameRules_TeamStacked() = 0; + virtual IReGameHookRegistry_CSGameRules_PlayerGotWeapon *CSGameRules_PlayerGotWeapon() = 0; + virtual IReGameHookRegistry_CBotManager_OnEvent *CBotManager_OnEvent() = 0; + virtual IReGameHookRegistry_CBasePlayer_CheckTimeBasedDamage *CBasePlayer_CheckTimeBasedDamage() = 0; + virtual IReGameHookRegistry_CBasePlayer_EntSelectSpawnPoint *CBasePlayer_EntSelectSpawnPoint() = 0; + virtual IReGameHookRegistry_CBasePlayerWeapon_ItemPostFrame *CBasePlayerWeapon_ItemPostFrame() = 0; + virtual IReGameHookRegistry_CBasePlayerWeapon_KickBack *CBasePlayerWeapon_KickBack() = 0; + virtual IReGameHookRegistry_CBasePlayerWeapon_SendWeaponAnim *CBasePlayerWeapon_SendWeaponAnim() = 0; + virtual IReGameHookRegistry_CSGameRules_SendDeathMessage *CSGameRules_SendDeathMessage() = 0; + + virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0; + virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0; }; struct ReGameFuncs_t { @@ -670,6 +802,15 @@ struct ReGameFuncs_t { class CGrenade *(*PlantBomb)(entvars_t *pevOwner, Vector &vecStart, Vector &vecVelocity); class CGib *(*SpawnHeadGib)(entvars_t* pevVictim); void (*SpawnRandomGibs)(entvars_t* pevVictim, int cGibs, int human); + void (*UTIL_RestartOther)(const char *szClassname); + void (*UTIL_ResetEntities)(); + void (*UTIL_RemoveOther)(const char *szClassname, int nCount); + void (*UTIL_DecalTrace)(TraceResult *pTrace, int decalNumber); + void (*UTIL_Remove)(CBaseEntity *pEntity); + int (*AddAmmoNameToAmmoRegistry)(const char *szAmmoname); + void (*TextureTypePlaySound)(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType); + class CWeaponBox *(*CreateWeaponBox)(CBasePlayerItem *pItem, CBasePlayer *pPlayerOwner, const char *modelName, Vector &origin, Vector &angles, Vector &velocity, float lifeTime, bool packAmmo); + class CGrenade *(*SpawnGrenade)(WeaponIdType weaponId, entvars_t *pevOwner, Vector &vecSrc, Vector &vecThrow, float time, int iTeam, unsigned short usEvent); }; class IReGameApi { diff --git a/regamedll/public/regamedll/regamedll_const.h b/regamedll/public/regamedll/regamedll_const.h index ddbe62af4..4599c58f2 100644 --- a/regamedll/public/regamedll/regamedll_const.h +++ b/regamedll/public/regamedll/regamedll_const.h @@ -106,3 +106,4 @@ #define GIB_NEVER 1 // Never gib, no matter how much death damage is done ( freezing, etc ) #define GIB_ALWAYS 2 // Always gib ( Houndeye Shock, Barnacle Bite ) #define GIB_HEALTH_VALUE -30 +#define GIB_PLAYER_THRESHOLD -9000 diff --git a/regamedll/public/tier0/assert_dialog.cpp b/regamedll/public/tier0/assert_dialog.cpp new file mode 100644 index 000000000..11bb9442b --- /dev/null +++ b/regamedll/public/tier0/assert_dialog.cpp @@ -0,0 +1,302 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#include "precompiled.h" +#include "resource.h" + +class CDialogInitInfo +{ +public: + const char *m_pFilename; + int m_iLine; + const char *m_pExpression; +}; + +class CAssertDisable +{ +public: + char m_Filename[MAX_OSPATH]; + + // If these are not -1, then this CAssertDisable only disables asserts on lines between + // these values (inclusive). + int m_LineMin; + int m_LineMax; + + // Decremented each time we hit this assert and ignore it, until it's 0. + // Then the CAssertDisable is removed. + // If this is -1, then we always ignore this assert. + int m_nIgnoreTimes; + + CAssertDisable *m_pNext; +}; + +static CDialogInitInfo g_Info{}; +static bool g_bAssertsEnabled = true; +static CAssertDisable *g_pAssertDisables = nullptr; + +// Set to true if they want to break in the debugger +static bool g_bBreak = false; + +// Internal functions +static HINSTANCE g_hTier0Instance = nullptr; +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, // handle to the DLL module + DWORD fdwReason, // reason for calling function + LPVOID lpvReserved // reserved +) +{ + g_hTier0Instance = hinstDLL; + return true; +} + +static bool IsDebugBreakEnabled() +{ + static bool bResult = (Q_strstr(Plat_GetCommandLine(), "-debugbreak") != nullptr); + return bResult; +} + +static bool AreAssertsDisabled() +{ + static bool bResult = (Q_strstr(Plat_GetCommandLine(), "-noassert") != nullptr); + return bResult; +} + +static bool AreAssertsEnabledInFileLine(const char *pFilename, int iLine) +{ + CAssertDisable **pPrev = &g_pAssertDisables; + CAssertDisable *pNext = nullptr; + + for (CAssertDisable *pCur = g_pAssertDisables; pCur; pCur = pNext) + { + pNext = pCur->m_pNext; + + if (Q_stricmp(pFilename, pCur->m_Filename) == 0) + { + // Are asserts disabled in the whole file? + bool bAssertsEnabled = true; + if (pCur->m_LineMin == -1 && pCur->m_LineMax == -1) + bAssertsEnabled = false; + + // Are asserts disabled on the specified line? + if (iLine >= pCur->m_LineMin && iLine <= pCur->m_LineMax) + bAssertsEnabled = false; + + if (!bAssertsEnabled) + { + // If this assert is only disabled for the next N times, then countdown.. + if (pCur->m_nIgnoreTimes > 0) + { + pCur->m_nIgnoreTimes--; + + if (pCur->m_nIgnoreTimes == 0) + { + // Remove this one from the list. + *pPrev = pNext; + delete pCur; + continue; + } + } + + return false; + } + } + + pPrev = &pCur->m_pNext; + } + + return true; +} + +CAssertDisable *CreateNewAssertDisable(const char *pFilename) +{ + CAssertDisable *pDisable = new CAssertDisable; + pDisable->m_pNext = g_pAssertDisables; + g_pAssertDisables = pDisable; + + pDisable->m_LineMin = pDisable->m_LineMax = -1; + pDisable->m_nIgnoreTimes = -1; + + Q_strlcpy(pDisable->m_Filename, g_Info.m_pFilename); + + return pDisable; +} + +void IgnoreAssertsInCurrentFile() +{ + CreateNewAssertDisable(g_Info.m_pFilename); +} + +CAssertDisable *IgnoreAssertsNearby(int nRange) +{ + CAssertDisable *pDisable = CreateNewAssertDisable(g_Info.m_pFilename); + pDisable->m_LineMin = g_Info.m_iLine - nRange; + pDisable->m_LineMax = g_Info.m_iLine - nRange; + return pDisable; +} + +static int g_iLastLineRange = 5; +static int g_nLastIgnoreNumTimes = 1; + +int CALLBACK AssertDialogProc( + HWND hDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter +) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + SetDlgItemText(hDlg, IDC_ASSERT_MSG_CTRL, g_Info.m_pExpression); + SetDlgItemText(hDlg, IDC_FILENAME_CONTROL, g_Info.m_pFilename); + + SetDlgItemInt(hDlg, IDC_LINE_CONTROL, g_Info.m_iLine, false); + SetDlgItemInt(hDlg, IDC_IGNORE_NUMLINES, g_iLastLineRange, false); + SetDlgItemInt(hDlg, IDC_IGNORE_NUMTIMES, g_nLastIgnoreNumTimes, false); + + // Center the dialog. + RECT rcDlg, rcDesktop; + GetWindowRect(hDlg, &rcDlg); + GetWindowRect(GetDesktopWindow(), &rcDesktop); + SetWindowPos(hDlg, HWND_TOP, + ((rcDesktop.right - rcDesktop.left) - (rcDlg.right - rcDlg.left)) / 2, + ((rcDesktop.bottom - rcDesktop.top) - (rcDlg.bottom - rcDlg.top)) / 2, + 0, 0, + SWP_NOSIZE + ); + + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + // Ignore this assert N times + case IDC_IGNORE_THIS: + { + BOOL bTranslated = false; + UINT value = GetDlgItemInt(hDlg, IDC_IGNORE_NUMTIMES, &bTranslated, false); + if (bTranslated && value > 1) + { + CAssertDisable *pDisable = IgnoreAssertsNearby(0); + pDisable->m_nIgnoreTimes = value - 1; + g_nLastIgnoreNumTimes = value; + } + + EndDialog(hDlg, 0); + return TRUE; + } + case IDC_IGNORE_NEARBY: + { + BOOL bTranslated = false; + UINT value = GetDlgItemInt(hDlg, IDC_IGNORE_NUMLINES, &bTranslated, false); + if (!bTranslated || value < 1) + return TRUE; + + IgnoreAssertsNearby(value); + EndDialog(hDlg, 0); + return TRUE; + } + case IDC_IGNORE_FILE: + IgnoreAssertsInCurrentFile(); + EndDialog(hDlg, 0); + return TRUE; + // Always ignore this assert + case IDC_IGNORE_ALWAYS: + IgnoreAssertsNearby(0); + EndDialog(hDlg, 0); + return TRUE; + case IDC_IGNORE_ALL: + g_bAssertsEnabled = false; + EndDialog(hDlg, 0); + return TRUE; + case IDC_BREAK: + g_bBreak = true; + EndDialog(hDlg, 0); + return TRUE; + } + case WM_KEYDOWN: + { + // Escape? + if (wParam == 2) + { + // Ignore this assert + EndDialog(hDlg, 0); + return TRUE; + } + + break; + } + + return TRUE; + } + } + + return FALSE; +} + +static HWND g_hBestParentWindow = nullptr; + +static BOOL CALLBACK ParentWindowEnumProc( + HWND hWnd, // handle to parent window + LPARAM lParam // application-defined value +) +{ + if (IsWindowVisible(hWnd)) + { + DWORD procID; + GetWindowThreadProcessId(hWnd, &procID); + if (procID == (DWORD)lParam) + { + g_hBestParentWindow = hWnd; + return FALSE; // don't iterate any more. + } + } + + return TRUE; +} + +static HWND FindLikelyParentWindow() +{ + // Enumerate top-level windows and take the first visible one with our processID. + g_hBestParentWindow = nullptr; + EnumWindows(ParentWindowEnumProc, GetCurrentProcessId()); + return g_hBestParentWindow; +} + +bool DoNewAssertDialog(const char *pFilename, int line, const char *pExpression) +{ + if (AreAssertsDisabled()) + return false; + + // If they have the old mode enabled (always break immediately), then just break right into + // the debugger like we used to do. + if (IsDebugBreakEnabled()) + return true; + + // Have ALL Asserts been disabled? + if (!g_bAssertsEnabled) + return false; + + // Has this specific Assert been disabled? + if (!AreAssertsEnabledInFileLine(pFilename, line)) + return false; + + // Now create the dialog. + g_Info.m_pFilename = pFilename; + g_Info.m_iLine = line; + g_Info.m_pExpression = pExpression; + + g_bBreak = false; + + HWND hParentWindow = FindLikelyParentWindow(); + DialogBox(g_hTier0Instance, MAKEINTRESOURCE(IDD_ASSERT_DIALOG), hParentWindow, AssertDialogProc); + + return g_bBreak; +} diff --git a/regamedll/public/tier0/assert_dialog.rc b/regamedll/public/tier0/assert_dialog.rc new file mode 100644 index 000000000..e8683cf41 --- /dev/null +++ b/regamedll/public/tier0/assert_dialog.rc @@ -0,0 +1,117 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ASSERT_DIALOG DIALOG DISCARDABLE 0, 0, 268, 158 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Assert" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "File:",IDC_NOID,7,7,23,9 + LTEXT "c:/cstrike16/src/blah.cpp",IDC_FILENAME_CONTROL,36,7,217,8 + LTEXT "Line:",IDC_NOID,7,18,23,9 + LTEXT "45",IDC_LINE_CONTROL,36,18,217,8 + LTEXT "Assert:",IDC_NOID,7,29,23,9 + CONTROL "ASSERT MESSAGE",IDC_ASSERT_MSG_CTRL,"Static", + SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,36,29,217,9 + DEFPUSHBUTTON "&Break in Debugger",IDC_BREAK,7,49,98,14 + PUSHBUTTON "&Ignore This Assert",IDC_IGNORE_THIS,7,66,98,14 + EDITTEXT IDC_IGNORE_NUMTIMES,110,66,24,14,ES_AUTOHSCROLL | + ES_NUMBER + LTEXT "time(s).",IDC_NOID,138,68,23,8 + PUSHBUTTON "Always Ignore &This Assert",IDC_IGNORE_ALWAYS,7,84,98, + 14 + PUSHBUTTON "Ignore &Nearby Asserts",IDC_IGNORE_NEARBY,7,102,98,14 + LTEXT "within",IDC_NOID,109,105,19,8 + EDITTEXT IDC_IGNORE_NUMLINES,131,102,40,14,ES_AUTOHSCROLL | + ES_NUMBER + LTEXT "lines.",IDC_NOID,175,105,17,8 + PUSHBUTTON "Ignore Asserts in This &File",IDC_IGNORE_FILE,7,120,98, + 14 + PUSHBUTTON "Ignore &All Asserts",IDC_IGNORE_ALL,7,137,98,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ASSERT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 261 + TOPMARGIN, 7 + BOTTOMMARGIN, 151 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/regamedll/public/tier0/dbg.cpp b/regamedll/public/tier0/dbg.cpp index ebf36c2e4..35c99fe38 100644 --- a/regamedll/public/tier0/dbg.cpp +++ b/regamedll/public/tier0/dbg.cpp @@ -1,50 +1,17 @@ -/* -* -* 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. -* -*/ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// #include "precompiled.h" -// Internal structures -enum -{ - MAX_GROUP_NAME_LENGTH = 48 -}; - -struct SpewGroup_t -{ - char m_GroupName[MAX_GROUP_NAME_LENGTH]; - int m_Level; -}; - - // Templates to assist in validating pointers: void _AssertValidReadPtr(void *ptr, int count) { -#ifdef _WIN32 +#if defined(_WIN32) Assert(!IsBadReadPtr(ptr, count)); #else Assert(ptr); @@ -54,7 +21,7 @@ void _AssertValidReadPtr(void *ptr, int count) void _AssertValidWritePtr(void *ptr, int count) { -#ifdef _WIN32 +#if defined(_WIN32) Assert(!IsBadWritePtr(ptr, count)); #else Assert(ptr); @@ -63,26 +30,29 @@ void _AssertValidWritePtr(void *ptr, int count) void _AssertValidReadWritePtr(void *ptr, int count) { -#ifdef _WIN32 +#if defined(_WIN32) Assert(!(IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr, count))); #else Assert(ptr); #endif } +#if defined(DBGFLAG_ASSERT) void AssertValidStringPtr(const char *ptr, int maxchar) { -#ifdef _WIN32 +#if defined(_WIN32) Assert(!IsBadStringPtr(ptr, maxchar)); #else Assert(ptr); #endif } +#endif // DBGFLAG_ASSERT // Globals -SpewRetval_t DefaultSpewFunc(SpewType_t type, const char *pMsg) +SpewRetval_t DefaultSpewFunc(SpewType_t type, int level, const char *pMsg) { printf("%s", pMsg); + if (type == SPEW_ASSERT) return SPEW_DEBUGGER; else if (type == SPEW_ERROR) @@ -93,13 +63,10 @@ SpewRetval_t DefaultSpewFunc(SpewType_t type, const char *pMsg) static SpewOutputFunc_t s_SpewOutputFunc = DefaultSpewFunc; -static const char *s_pFileName; -static int s_Line; -static SpewType_t s_SpewType; - -static SpewGroup_t *s_pSpewGroups = 0; -static int s_GroupCount = 0; -static int s_DefaultLevel = 0; +static const char *s_pMessage = nullptr; +static const char *s_pFileName = nullptr; +static int s_Line = 0; +static SpewType_t s_SpewType = SPEW_MESSAGE; // Spew output management. void SpewOutputFunc(SpewOutputFunc_t func) @@ -119,54 +86,92 @@ SpewOutputFunc_t GetSpewOutputFunc() } } +void _ExitOnFatalAssert() +{ + Msg("Fatal assert failed: %s, file %s line %d. Application exiting.\n", s_pMessage, s_pFileName, s_Line); + +#if defined(WIN32) + TerminateProcess(GetCurrentProcess(), EXIT_FAILURE); // die, die RIGHT NOW! (don't call exit() so destructors will not get run) +#else + exit(EXIT_FAILURE); // forcefully shutdown of the process without destructors running +#endif +} + // Spew functions void _SpewInfo(SpewType_t type, const char *pFile, int line) { - // Only grab the file name. Ignore the path. - const char *pSlash = strrchr(pFile, '\\'); - const char *pSlash2 = strrchr(pFile, '/'); + // Only grab the file name. Ignore the path + const char *pSlash = Q_strrchr(pFile, '\\'); + const char *pSlash2 = Q_strrchr(pFile, '/'); + if (pSlash < pSlash2) pSlash = pSlash2; s_pFileName = pSlash ? pSlash + 1 : pFile; - s_Line = line; - s_SpewType = type; + s_Line = line; + s_SpewType = type; } -SpewRetval_t _SpewMessage(SpewType_t spewType, const char *pMsgFormat, va_list args) +SpewRetval_t _SpewMessageV(SpewType_t spewType, int level, const char *pMsgFormat, va_list args) { - char pTempBuffer[1024]; + if (level < 0) level = DBG_DEFAULT_LEVEL; + + static char szTempBuffer[4096]{}; + szTempBuffer[0] = '\0'; + s_pMessage = szTempBuffer; + + // check that we won't artifically truncate the string + assert(Q_strlen(pMsgFormat) < sizeof(szTempBuffer)); // Printf the file and line for warning + assert only... int len = 0; - if ((spewType == SPEW_ASSERT)) + if (spewType == SPEW_ASSERT) + { + len = Q_snprintf(szTempBuffer, sizeof(szTempBuffer), "%s (%d) : ", s_pFileName, s_Line); + } + + if (len == -1) { - len = sprintf(pTempBuffer, "%s (%d) : ", s_pFileName, s_Line); + return SPEW_ABORT; } // Create the message.... - len += vsprintf(&pTempBuffer[len], pMsgFormat, args); + len += Q_vsnprintf(&szTempBuffer[len], sizeof(szTempBuffer) - len, pMsgFormat, args); + + // Use normal assert here; to avoid recursion + assert(len < sizeof(szTempBuffer)); // Add \n for warning and assert if ((spewType == SPEW_ASSERT)) { - len += sprintf(&pTempBuffer[len], "\n"); + len += Q_snprintf(&szTempBuffer[len], sizeof(szTempBuffer) - len, "\n"); + Plat_OutputDebugString(szTempBuffer); } - assert(len < 1024); // use normal assert here; to avoid recursion. + // use normal assert here; to avoid recursion + assert((size_t)len < (sizeof(szTempBuffer) / sizeof(szTempBuffer[0]) - 1)); assert(s_SpewOutputFunc); // direct it to the appropriate target(s) - SpewRetval_t ret = s_SpewOutputFunc(spewType, pTempBuffer); + SpewRetval_t ret = s_SpewOutputFunc(spewType, level, szTempBuffer); switch (ret) { // Put the break into the macro so it would occur in the right place - //case SPEW_DEBUGGER: - // DebuggerBreak(); - // break; + case SPEW_DEBUGGER: + { + if (spewType != SPEW_ASSERT) + DebuggerBreakIfDebugging(); + break; + } case SPEW_ABORT: - // MessageBox(nullptr, "Error in _SpewMessage", "Error", MB_OK); - exit(0); + { +#if defined(WIN32) + TerminateProcess(GetCurrentProcess(), EXIT_FAILURE); // die, die RIGHT NOW! (don't call exit() so destructors will not get run) +#else + exit(EXIT_FAILURE); // forcefully shutdown of the process without destructors running +#endif + break; + } default: break; } @@ -174,81 +179,52 @@ SpewRetval_t _SpewMessage(SpewType_t spewType, const char *pMsgFormat, va_list a return ret; } -SpewRetval_t _SpewMessage(const char *pMsgFormat, ...) -{ - va_list args; - va_start(args, pMsgFormat); - SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); - va_end(args); - return ret; -} - -SpewRetval_t _DSpewMessage(const char *pGroupName, int level, const char *pMsgFormat, ...) -{ - if (!IsSpewActive(pGroupName, level)) - return SPEW_CONTINUE; - - va_list args; - va_start(args, pMsgFormat); - SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); - va_end(args); - return ret; -} +#if defined(_WIN32) +// Returns true if they want to break in the debugger +bool DoNewAssertDialog(const char *pFile, int line, const char *pExpression); +#endif -void Msg(const char *pMsgFormat, ...) +bool _SpewAssertDialog() { - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); - va_end(args); +#if defined(_WIN32) + return DoNewAssertDialog(s_pFileName, s_Line, s_pMessage); +#else + return false; +#endif } -void DMsg(const char *pGroupName, int level, const char *pMsgFormat, ...) +SpewRetval_t _SpewAssert(const char *pFile, int line, int level, const char *pMsgFormat, ...) { - if (!IsSpewActive(pGroupName, level)) - return; + _SpewInfo(SPEW_ASSERT, pFile, line); va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); - va_end(args); -} - -void Warning(const char *pMsgFormat, ...) -{ - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_WARNING, pMsgFormat, args); + SpewRetval_t ret = _SpewMessageV(s_SpewType, level, pMsgFormat, args); va_end(args); + return ret; } -void DWarning(const char *pGroupName, int level, const char *pMsgFormat, ...) +void _Msg(int level, const char *pMsgFormat, ...) { - if (!IsSpewActive(pGroupName, level)) - return; - va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_WARNING, pMsgFormat, args); + _SpewMessageV(SPEW_MESSAGE, level, pMsgFormat, args); va_end(args); } -void Log(const char *pMsgFormat, ...) +void _Warning(int level, const char *pMsgFormat, ...) { va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_LOG, pMsgFormat, args); + _SpewMessageV(SPEW_WARNING, level, pMsgFormat, args); va_end(args); } -void DLog(const char *pGroupName, int level, const char *pMsgFormat, ...) +void _Log(int level, const char *pMsgFormat, ...) { - if (!IsSpewActive(pGroupName, level)) - return; - va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_LOG, pMsgFormat, args); + _SpewMessageV(SPEW_LOG, level, pMsgFormat, args); va_end(args); } @@ -256,146 +232,6 @@ void Error(const char *pMsgFormat, ...) { va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_ERROR, pMsgFormat, args); + _SpewMessageV(SPEW_ERROR, DBG_DEFAULT_LEVEL, pMsgFormat, args); va_end(args); } - -// A couple of super-common dynamic spew messages, here for convenience -// These looked at the "developer" group, print if it's level 1 or higher -void DevMsg(int level, char const *pMsgFormat, ...) -{ - if (!IsSpewActive("developer", level)) - return; - - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); - va_end(args); -} - -void DevWarning(int level, const char *pMsgFormat, ...) -{ - if (!IsSpewActive("developer", level)) - return; - - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_WARNING, pMsgFormat, args); - va_end(args); -} - -void DevLog(int level, const char *pMsgFormat, ...) -{ - if (!IsSpewActive("developer", level)) - return; - - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_LOG, pMsgFormat, args); - va_end(args); -} - -void DevMsg(const char *pMsgFormat, ...) -{ - if (!IsSpewActive("developer", 1)) - return; - - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); - va_end(args); -} - -void DevWarning(const char *pMsgFormat, ...) -{ - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_WARNING, pMsgFormat, args); - va_end(args); -} - -void DevLog(const char *pMsgFormat, ...) -{ - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_LOG, pMsgFormat, args); - va_end(args); -} - -// Find a group, return true if found, false if not. Return in ind the -// index of the found group, or the index of the group right before where the -// group should be inserted into the list to maintain sorted order. -bool FindSpewGroup(const char *pGroupName, int *pInd) -{ - int s = 0; - if (s_GroupCount) - { - int e = (int)(s_GroupCount - 1); - while (s <= e) - { - int m = (s + e) >> 1; - int cmp = Q_stricmp(pGroupName, s_pSpewGroups[m].m_GroupName); - if (!cmp) - { - *pInd = m; - return true; - } - - if (cmp < 0) - e = m - 1; - else - s = m + 1; - } - } - - *pInd = s; - return false; -} - -// Sets the priority level for a spew group -void SpewActivate(const char *pGroupName, int level) -{ - Assert(pGroupName); - - // check for the default group first... - if ((pGroupName[0] == '*') && (pGroupName[1] == '\0')) - { - s_DefaultLevel = level; - return; - } - - // Normal case, search in group list using binary search. - // If not found, grow the list of groups and insert it into the - // right place to maintain sorted order. Then set the level. - int ind; - if (!FindSpewGroup(pGroupName, &ind)) - { - // not defined yet, insert an entry. - s_GroupCount++; - if (s_pSpewGroups) - { - s_pSpewGroups = (SpewGroup_t *)realloc(s_pSpewGroups, s_GroupCount * sizeof(SpewGroup_t)); - - // shift elements down to preserve order - int numToMove = s_GroupCount - ind - 1; - memmove(&s_pSpewGroups[ind + 1], &s_pSpewGroups[ind], numToMove * sizeof(SpewGroup_t)); - } - else - s_pSpewGroups = (SpewGroup_t *)malloc(s_GroupCount * sizeof(SpewGroup_t)); - - Assert(strlen(pGroupName) < MAX_GROUP_NAME_LENGTH); - strcpy(s_pSpewGroups[ind].m_GroupName, pGroupName); - } - s_pSpewGroups[ind].m_Level = level; -} - -// Tests to see if a particular spew is active -bool IsSpewActive(const char *pGroupName, int level) -{ - // If we don't find the spew group, use the default level. - int ind; - if (FindSpewGroup(pGroupName, &ind)) - return s_pSpewGroups[ind].m_Level >= level; - else - return s_DefaultLevel >= level; -} diff --git a/regamedll/public/tier0/dbg.h b/regamedll/public/tier0/dbg.h index 38e992f67..848250414 100644 --- a/regamedll/public/tier0/dbg.h +++ b/regamedll/public/tier0/dbg.h @@ -1,30 +1,10 @@ -/* -* -* 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. -* -*/ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// #pragma once @@ -34,16 +14,7 @@ #include #include -// dll export stuff -#ifdef TIER0_DLL_EXPORT -#define DBG_INTERFACE DLL_EXPORT -#define DBG_OVERLOAD DLL_GLOBAL_EXPORT -#define DBG_CLASS DLL_CLASS_EXPORT -#else -#define DBG_INTERFACE DLL_IMPORT -#define DBG_OVERLOAD DLL_GLOBAL_IMPORT -#define DBG_CLASS DLL_CLASS_IMPORT -#endif +#define DBG_DEFAULT_LEVEL 0 // Usage model for the Dbg library // @@ -87,22 +58,6 @@ // Msg("Isn't this exciting %d?", 5); // Error("I'm just thrilled"); // -// Dynamic Spew messages -// -// It is possible to dynamically turn spew on and off. Dynamic spew is -// identified by a spew group and priority level. To turn spew on for a -// particular spew group, use SpewActivate("group", level). This will -// cause all spew in that particular group with priority levels <= the -// level specified in the SpewActivate function to be printed. Use DSpew -// to perform the spew: -// -// DWarning("group", level, "Oh I feel even yummier!\n"); -// -// Priority level 0 means that the spew will *always* be printed, and group -// '*' is the default spew group. If a DWarning is encountered using a group -// whose priority has not been set, it will use the priority of the default -// group. The priority of the default group is initially set to 0. -// // Spew output // // The output of the spew system can be redirected to an externally-supplied @@ -131,12 +86,6 @@ // } // ); // -// Code can be activated based on the dynamic spew groups also. Use -// -// DBG_DCODE("group", level, -// { int x = 5; ++x; } -// ); -// // 3. Breaking into the debugger. // // To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK @@ -170,7 +119,7 @@ enum SpewRetval_t }; // Type of externally defined function used to display debug spew -typedef SpewRetval_t (*SpewOutputFunc_t)(SpewType_t spewType, const char *pMsg); +typedef SpewRetval_t (*SpewOutputFunc_t)(SpewType_t spewType, int level, const char *pMsg); // Used to redirect spew output void SpewOutputFunc(SpewOutputFunc_t func); @@ -178,134 +127,220 @@ void SpewOutputFunc(SpewOutputFunc_t func); // Used ot get the current spew output function SpewOutputFunc_t GetSpewOutputFunc(); -// Used to manage spew groups and subgroups -void SpewActivate(const char *pGroupName, int level); -bool IsSpewActive(const char *pGroupName, int level); - // Used to display messages, should never be called directly. -void _SpewInfo(SpewType_t type, const char *pFile, int line); -SpewRetval_t _SpewMessage(const char *pMsg, ...); -SpewRetval_t _DSpewMessage(const char *pGroupName, int level, const char *pMsg, ...); - -// Used to define macros, never use these directly. -#define _Assert(_exp) \ - do { \ - if (!(_exp)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - if (_SpewMessage("Assertion Failed: " #_exp) == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ - } while (0) - -#define _AssertMsg(_exp, _msg) \ - do { \ - if (!(_exp)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - if (_SpewMessage(_msg) == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ - } while (0) - -#define _AssertFunc(_exp, _f) \ - do { \ - if (!(_exp)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - SpewRetval_t ret = _SpewMessage("Assertion Failed!" #_exp); \ - _f; \ - if (ret == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ - } while (0) +SpewRetval_t _SpewAssert(const char *pFile, int line, int level, const char *pMsg, ...); +void _ExitOnFatalAssert(); +bool _SpewAssertDialog(); -#define _AssertEquals(_exp, _expectedValue) \ - do { \ - if ((_exp) != (_expectedValue)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - SpewRetval_t ret = _SpewMessage("Expected %d but got %d!", (_expectedValue), (_exp)); \ - if (ret == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ +inline bool ShouldUseNewAssertDialog() +{ +#if defined(DBGFLAG_ASSERTDLG) + return true; // always show an assert dialog +#else + return Plat_IsInDebugSession(); // only show an assert dialog if the process is being debugged +#endif // DBGFLAG_ASSERTDLG +} + +#define _AssertMsg(_exp, _msg, _executeExp, _bFatal) \ + do { \ + if (!(_exp)) \ + { \ + SpewRetval_t ret = _SpewAssert(__FILE__, __LINE__, DBG_DEFAULT_LEVEL, _msg); \ + if (ret == SPEW_DEBUGGER) \ + { \ + if (!ShouldUseNewAssertDialog() || _SpewAssertDialog()) \ + DebuggerBreakIfDebugging(); \ + } \ + _executeExp; \ + if (_bFatal) \ + _ExitOnFatalAssert(); \ + } \ } while (0) -#define _AssertFloatEquals(_exp, _expectedValue, _tol) \ - do { \ - if (fabs((_exp) - (_expectedValue)) > (_tol)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - SpewRetval_t ret = _SpewMessage("Expected %f but got %f!", (_expectedValue), (_exp)); \ - if (ret == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ +#define _AssertMsgWarn(_exp, _msg) \ + if (!(_exp)) \ + { \ + Warning("%s (%d) : " _msg, __FILE__, __LINE__); \ + } \ + +#define _AssertMsgOnce(_exp, _msg, _bFatal) \ + do { \ + static bool fAsserted = false; \ + if (!fAsserted && !(_exp)) \ + { \ + fAsserted = true; \ + _AssertMsg(_exp, _msg, (fAsserted = true), _bFatal); \ + } \ } while (0) // Spew macros... -#ifdef _DEBUG - -#define Assert(_exp) _Assert(_exp) -#define AssertMsg(_exp, _msg) _AssertMsg(_exp, _msg) -#define AssertFunc(_exp, _f) _AssertFunc(_exp, _f) -#define AssertEquals(_exp, _expectedValue) _AssertEquals(_exp, _expectedValue) -#define AssertFloatEquals(_exp, _expectedValue, _tol) _AssertFloatEquals(_exp, _expectedValue, _tol) -#define Verify(_exp) _Assert(_exp) - -#define AssertMsg1(_exp, _msg, a1) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1)) -#define AssertMsg2(_exp, _msg, a1, a2) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2)) -#define AssertMsg3(_exp, _msg, a1, a2, a3) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3)) -#define AssertMsg4(_exp, _msg, a1, a2, a3, a4) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4)) -#define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5)) -#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6)) -#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6)) -#define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7)) -#define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8)) -#define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8, a9)) - -#else // _DEBUG +// AssertFatal macros +// AssertFatal is used to detect an unrecoverable error condition. +// If enabled, it may display an assert dialog (if DBGFLAG_ASSERTDLG is turned on or running under the debugger), +// and always terminates the application + +#if defined(DBGFLAG_ASSERTFATAL) + +#define AssertWarn(_exp) _AssertMsgWarn(_exp, "Assertion Failed: " #_exp) +#define AssertFatal(_exp) _AssertMsg(_exp, "Assertion Failed: " #_exp, ((void)0), true) +#define AssertFatalOnce(_exp) _AssertMsgOnce(_exp, "Assertion Failed: " #_exp, true) +#define AssertFatalMsg(_exp, _msg) _AssertMsg(_exp, _msg, ((void)0), true) +#define AssertFatalMsgOnce(_exp, _msg) _AssertMsgOnce(_exp, _msg, true) +#define AssertFatalFunc(_exp, _f) _AssertMsg(_exp, "Assertion Failed: " #_exp, _f, true) +#define AssertFatalEquals(_exp, _expectedValue) AssertFatalMsg2((_exp) == (_expectedValue), "Expected %d but got %d!", (_expectedValue), (_exp)) +#define AssertFatalFloatEquals(_exp, _expectedValue, _tol) AssertFatalMsg2(fabs((_exp) - (_expectedValue)) <= (_tol), "Expected %f but got %f!", (_expectedValue), (_exp)) +#define VerifyFatal(_exp) AssertFatal(_exp) +#define VerifyEqualsFatal(_exp, _expectedValue) AssertFatalEquals(_exp, _expectedValue) + +#if defined(_DEBUG) + #define DbgVerifyFatal(_exp) AssertFatal(_exp) +#else + #define DbgVerifyFatal(_exp) ((void)0) +#endif -#define Assert(_exp) ((void)0) -#define AssertMsg(_exp, _msg) ((void)0) -#define AssertFunc(_exp, _f) ((void)0) -#define AssertEquals(_exp, _expectedValue) ((void)0) -#define AssertFloatEquals(_exp, _expectedValue, _tol) ((void)0) -#define Verify(_exp) (_exp) - -#define AssertMsg1(_exp, _msg, a1) ((void)0) -#define AssertMsg2(_exp, _msg, a1, a2) ((void)0) -#define AssertMsg3(_exp, _msg, a1, a2, a3) ((void)0) -#define AssertMsg4(_exp, _msg, a1, a2, a3, a4) ((void)0) -#define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) ((void)0) -#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) -#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) -#define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) ((void)0) -#define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) ((void)0) -#define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) ((void)0) +#define AssertFatalMsg1(_exp, _msg, a1) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1).ToString()) +#define AssertFatalMsg2(_exp, _msg, a1, a2) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2).ToString()) +#define AssertFatalMsg3(_exp, _msg, a1, a2, a3) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3).ToString()) +#define AssertFatalMsg4(_exp, _msg, a1, a2, a3, a4) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4).ToString()) +#define AssertFatalMsg5(_exp, _msg, a1, a2, a3, a4, a5) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5).ToString()) +#define AssertFatalMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6).ToString()) +#define AssertFatalMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7).ToString()) +#define AssertFatalMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8).ToString()) +#define AssertFatalMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8, a9).ToString()) + +#else // DBGFLAG_ASSERTFATAL + +#define AssertWarn(_exp) ((void)0) +#define AssertFatal(_exp) ((void)0) +#define AssertFatalOnce(_exp) ((void)0) +#define AssertFatalMsg(_exp, _msg) ((void)0) +#define AssertFatalMsgOnce(_exp, _msg) ((void)0) +#define AssertFatalFunc(_exp, _f) ((void)0) +#define AssertFatalEquals(_exp, _expectedValue) ((void)0) +#define AssertFatalFloatEquals(_exp, _expectedValue, _tol) ((void)0) +#define VerifyFatal(_exp) (_exp) +#define VerifyEqualsFatal(_exp, _expectedValue) (_exp) + +#define DbgVerifyFatal(_exp) (_exp) + +#define AssertFatalMsg1(_exp, _msg, a1) ((void)0) +#define AssertFatalMsg2(_exp, _msg, a1, a2) ((void)0) +#define AssertFatalMsg3(_exp, _msg, a1, a2, a3) ((void)0) +#define AssertFatalMsg4(_exp, _msg, a1, a2, a3, a4) ((void)0) +#define AssertFatalMsg5(_exp, _msg, a1, a2, a3, a4, a5) ((void)0) +#define AssertFatalMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) +#define AssertFatalMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) ((void)0) +#define AssertFatalMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) ((void)0) +#define AssertFatalMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) ((void)0) + +#endif // DBGFLAG_ASSERTFATAL + +#if defined(DBGFLAG_ASSERT) + +#define Assert(_exp) _AssertMsg(_exp, "Assertion Failed: " #_exp, ((void)0), false) +#define AssertMsg_(_exp, _msg) _AssertMsg(_exp, _msg, ((void)0), false) +#define AssertOnce(_exp) _AssertMsgOnce(_exp, "Assertion Failed: " #_exp, false) +#define AssertMsgOnce(_exp, _msg) _AssertMsgOnce(_exp, _msg, false) +#define AssertFunc(_exp, _f) _AssertMsg(_exp, "Assertion Failed: " #_exp, _f, false) +#define AssertEquals(_exp, _expectedValue) AssertMsg2((_exp) == (_expectedValue), "Expected %d but got %d!", (_expectedValue), (_exp)) +#define AssertFloatEquals(_exp, _expectedValue, _tol) AssertMsg2(fabs((_exp) - (_expectedValue)) <= (_tol), "Expected %f but got %f!", (_expectedValue), (_exp)) +#define Verify(_exp) (_exp) +#define VerifyEquals(_exp, _expectedValue) AssertEquals(_exp, _expectedValue) + +#if defined(_DEBUG) + #define DbgVerify(_exp) (_exp) + #define DbgAssert(_exp) Assert(_exp) + #define DbgAssertMsg(_exp, _msg) AssertMsg(_exp, _msg) + #define DbgAssertMsg1(_exp, _msg, a1) AssertMsg1(_exp, _msg, a1) + #define DbgAssertMsg2(_exp, _msg, a1, a2) AssertMsg2(_exp, _msg, a1, a2) + #define DbgAssertMsg3(_exp, _msg, a1, a2, a3) AssertMsg3(_exp, _msg, a1, a2, a3) + #define DbgAssertMsg4(_exp, _msg, a1, a2, a3) AssertMsg4(_exp, _msg, a1, a2, a3, a4) + #define DbgAssertMsg5(_exp, _msg, a1, a2, a3) AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) + #define DbgAssertMsg6(_exp, _msg, a1, a2, a3) AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) + #define DbgAssertMsg7(_exp, _msg, a1, a2, a3) AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) + #define DbgAssertMsg8(_exp, _msg, a1, a2, a3) AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) + #define DbgAssertMsg9(_exp, _msg, a1, a2, a3) AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) +#else + #define DbgVerify(_exp) ((void)0) + #define DbgAssert(_exp) ((void)0) + #define DbgAssertMsg(_exp, _msg) ((void)0) + #define DbgAssertMsg1(_exp, _msg, a1) ((void)0) + #define DbgAssertMsg2(_exp, _msg, a1, a2) ((void)0) + #define DbgAssertMsg3(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg4(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg5(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg6(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg7(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg8(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg9(_exp, _msg, a1, a2, a3) ((void)0) +#endif -#endif // _DEBUG +#define AssertMsg(_exp, _msg) AssertMsg_(_exp, _msg) +#define AssertMsg1(_exp, _msg, a1) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1).ToString()) +#define AssertMsg2(_exp, _msg, a1, a2) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2).ToString()) +#define AssertMsg3(_exp, _msg, a1, a2, a3) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3).ToString()) +#define AssertMsg4(_exp, _msg, a1, a2, a3, a4) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4).ToString()) +#define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5).ToString()) +#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6).ToString()) +#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6).ToString()) +#define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7).ToString()) +#define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8).ToString()) +#define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8, a9).ToString()) + +#else // DBGFLAG_ASSERT + +#define Assert(_exp) ((void)0) +#define AssertMsg(_exp, _msg) ((void)0) +#define AssertOnce(_exp) ((void)0) +#define AssertMsgOnce(_exp, _msg) ((void)0) +#define AssertFunc(_exp, _f) ((void)0) +#define AssertEquals(_exp, _expectedValue) ((void)0) +#define AssertFloatEquals(_exp, _expectedValue, _tol) ((void)0) + +#define Verify(_exp) ((void)0) +#define VerifyEquals(_exp, _expectedValue) ((void)0) + +#define DbgVerify(_exp) ((void)0) +#define DbgAssert(_exp) ((void)0) +#define DbgAssertMsg(_exp, _msg) ((void)0) +#define DbgAssertMsg1(_exp, _msg, a1) ((void)0) +#define DbgAssertMsg2(_exp, _msg, a1, a2) ((void)0) +#define DbgAssertMsg3(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg4(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg5(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg6(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg7(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg8(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg9(_exp, _msg, a1, a2, a3) ((void)0) + +#define AssertMsg1(_exp, _msg, a1) ((void)0) +#define AssertMsg2(_exp, _msg, a1, a2) ((void)0) +#define AssertMsg3(_exp, _msg, a1, a2, a3) ((void)0) +#define AssertMsg4(_exp, _msg, a1, a2, a3, a4) ((void)0) +#define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) ((void)0) +#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) +#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) +#define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) ((void)0) +#define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) ((void)0) +#define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) ((void)0) + +#endif // DBGFLAG_ASSERT + +// default level versions (level 0) +#define Msg(...) _Msg (0, __VA_ARGS__) +#define Warning(...) _Warning(0, __VA_ARGS__) +#define Log(...) _Log (0, __VA_ARGS__) + +// These looked at the "developer" functions +#define DevMsg(...) _Msg (1, __VA_ARGS__) +#define DevWarning(...) _Warning(1, __VA_ARGS__) +#define DevLog(...) _Log (1, __VA_ARGS__) // These are always compiled in -void Msg(const char *pMsg, ...); -void DMsg(const char *pGroupName, int level, const char *pMsg, ...); - -void Warning(const char *pMsg, ...); -void DWarning(const char *pGroupName, int level, const char *pMsg, ...); - -void Log(const char *pMsg, ...); -void DLog(const char *pGroupName, int level, const char *pMsg, ...); - -void Error(const char *pMsg, ...); +void _Msg (int level, const char *pMsg, ...); +void _Warning(int level, const char *pMsg, ...); +void _Log (int level, const char *pMsg, ...); +void Error (const char *pMsg, ...); // You can use this macro like a runtime assert macro. // If the condition fails, then Error is called with the message. This macro is called @@ -320,57 +355,39 @@ void Error(const char *pMsg, ...); Error msg; \ } -// A couple of super-common dynamic spew messages, here for convenience -// These looked at the "developer" group -void DevMsg(int level, char const* pMsg, ...); -void DevWarning(int level, const char *pMsg, ...); -void DevLog(int level, const char *pMsg, ...); - -// default level versions (level 1) -void DevMsg(char const* pMsg, ...); -void DevWarning(const char *pMsg, ...); -void DevLog(const char *pMsg, ...); - // Code macros, debugger interface -#ifdef _DEBUG -#define DBG_CODE(_code) if (0) ; else { _code } -#define DBG_DCODE(_g, _l, _code) if (IsSpewActive(_g, _l)) { _code } else {} -#define DBG_BREAK() DebuggerBreak() +#if defined(_DEBUG) + #define DBG_CODE(_code) if (0) ; else { _code } + #define DBG_DCODE(_g, _l, _code) if (IsSpewActive(_g, _l)) { _code } else {} + #define DBG_BREAK() DebuggerBreakIfDebugging() #else // _DEBUG -#define DBG_CODE(_code) ((void)0) -#define DBG_DCODE(_g, _l, _code) ((void)0) -#define DBG_BREAK() ((void)0) + #define DBG_CODE(_code) ((void)0) + #define DBG_DCODE(_g, _l, _code) ((void)0) + #define DBG_BREAK() ((void)0) #endif // _DEBUG -// Macro to assist in asserting constant invariants during compilation -#define UID_PREFIX generated_id_ -#define UID_CAT1(a, c) a ## c -#define UID_CAT2(a, c) UID_CAT1(a,c) -#define UNIQUE_ID UID_CAT2(UID_PREFIX, __LINE__) - -#ifdef _DEBUG -#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;} -#define ASSERT_INVARIANT(pred) static void UNIQUE_ID() { COMPILE_TIME_ASSERT(pred) } -#else -#define COMPILE_TIME_ASSERT(pred) -#define ASSERT_INVARIANT(pred) -#endif - // Templates to assist in validating pointers: // Have to use these stubs so we don't have to include windows.h here. void _AssertValidReadPtr(void *ptr, int count = 1); void _AssertValidWritePtr(void *ptr, int count = 1); void _AssertValidReadWritePtr(void *ptr, int count = 1); - void AssertValidStringPtr(const char *ptr, int maxchar = 0xFFFFFF); -template inline void AssertValidReadPtr(T *ptr, int count = 1) { _AssertValidReadPtr((void *)ptr, count); } -template inline void AssertValidWritePtr(T *ptr, int count = 1) { _AssertValidWritePtr((void *)ptr, count); } -template inline void AssertValidReadWritePtr(T *ptr, int count = 1) { _AssertValidReadWritePtr((void *)ptr, count); } - -#define AssertValidThis() AssertValidReadWritePtr(this, sizeof(*this)) +#if defined(DBGFLAG_ASSERT) + void AssertValidStringPtr(const char *ptr, int maxchar = 0xFFFFFF); + template inline void AssertValidReadPtr(T *ptr, int count = 1) { _AssertValidReadPtr((void *)ptr, count); } + template inline void AssertValidWritePtr(T *ptr, int count = 1) { _AssertValidWritePtr((void *)ptr, count); } + template inline void AssertValidReadWritePtr(T *ptr, int count = 1) { _AssertValidReadWritePtr((void *)ptr, count); } + #define AssertValidThis() AssertValidReadWritePtr(this, sizeof(*this)) +#else + #define AssertValidStringPtr(...) ((void)0) + #define AssertValidReadPtr(...) ((void)0) + #define AssertValidWritePtr(...) ((void)0) + #define AssertValidReadWritePtr(...) ((void)0) + #define AssertValidThis() ((void)0) +#endif // #if defined(DBGFLAG_ASSERT) // Macro to protect functions that are not reentrant -#ifdef _DEBUG +#if defined(_DEBUG) class CReentryGuard { public: @@ -406,6 +423,7 @@ class CDbgFmtMsg va_start(arg_ptr, pszFormat); _vsnprintf(m_szBuf, sizeof(m_szBuf) - 1, pszFormat, arg_ptr); va_end(arg_ptr); + m_szBuf[sizeof(m_szBuf) - 1] = '\0'; } @@ -414,14 +432,11 @@ class CDbgFmtMsg return m_szBuf; } + const char *ToString() const + { + return m_szBuf; + } + private: char m_szBuf[256]; }; - -// Embed debug info in each file. -//#ifdef _WIN32 -//#ifdef _DEBUG -//#pragma comment(compiler) -//#pragma comment(exestr,"*** DEBUG file detected, Last Compile: " __DATE__ ", " __TIME__ " ***") -//#endif -//#endif diff --git a/regamedll/public/tier0/platform.h b/regamedll/public/tier0/platform.h index c10ae8b9b..5703cf53b 100644 --- a/regamedll/public/tier0/platform.h +++ b/regamedll/public/tier0/platform.h @@ -41,7 +41,14 @@ #endif // Used to step into the debugger -#define DebuggerBreak() __asm { int 3 } +#if defined(__GNUC__) && !defined(__clang__) + #define DebuggerBreak() __asm__ __volatile__("int3;") +#else + #define DebuggerBreak() __asm { int 3 } +#endif + +#define DebuggerBreakIfDebugging() if (Plat_IsInDebugSession()) { DebuggerBreak(); } +#define DebuggerSegFault() { volatile int *null = 0; *null = 0; } // C functions for external declarations that call the appropriate C++ methods #ifndef EXPORT @@ -105,6 +112,37 @@ #endif #endif +// +// Macro to assist in asserting constant invariants during compilation + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +// This implementation of compile time assert has zero cost (so it can safely be +// included in release builds) and can be used at file scope or function scope. +#define COMPILE_TIME_ASSERT(pred) static_assert(pred, "Compile time assert constraint is not true: " #pred) + +// ASSERT_INVARIANT used to be needed in order to allow COMPILE_TIME_ASSERTs at global +// scope. However the new COMPILE_TIME_ASSERT macro supports that by default. +#define ASSERT_INVARIANT(pred) COMPILE_TIME_ASSERT(pred) + +// Macro to assist in asserting constant invariants during compilation +// +// If available use static_assert instead of weird language tricks. This +// leads to much more readable messages when compile time assert constraints +// are violated. +#if !defined(OSX) && (_MSC_VER > 1500 || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) + #define PLAT_COMPILE_TIME_ASSERT(pred) static_assert(pred, "Compile time assert constraint is not true: " #pred) +#else + #define PLAT_COMPILE_TIME_ASSERT(pred) typedef int UNIQUE_ID[ (pred) ? 1 : -1] +#endif + +bool Plat_IsInDebugSession(); +void Plat_DebugString(const char *psz); +void Plat_OutputDebugString(const char *psz); +void Plat_OutputDebugStringRaw(const char *psz); +const char *Plat_GetCommandLine(); + // Methods to invoke the constructor, copy constructor, and destructor template inline void Construct(T *pMemory) diff --git a/regamedll/public/tier0/platform_posix.cpp b/regamedll/public/tier0/platform_posix.cpp new file mode 100644 index 000000000..202040b90 --- /dev/null +++ b/regamedll/public/tier0/platform_posix.cpp @@ -0,0 +1,113 @@ +/* +* +* 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" + +bool Plat_IsInDebugSession() +{ +#if defined(OSX) + int mib[4]; + struct kinfo_proc info; + size_t size; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + size = sizeof(info); + info.kp_proc.p_flag = 0; + sysctl(mib, 4, &info, &size, NULL, 0); + bool result = ((info.kp_proc.p_flag & P_TRACED) == P_TRACED); + return result; +#elif defined(_LINUX) + char s[256]; + snprintf(s, 256, "/proc/%d/cmdline", getppid()); + FILE *fp = fopen(s, "r"); + if (fp) + { + fread(s, 256, 1, fp); + fclose(fp); + return (0 == strncmp(s, "gdb", 3)); + } + return false; +#endif +} + +void Plat_OutputDebugStringRaw(const char *psz) +{ + fprintf(stderr, "%s", psz); +} + +void Plat_OutputDebugString(const char *psz) +{ + fprintf(stderr, "%s", psz); +} + +void Plat_DebugString(const char *psz) +{ + fprintf(stderr, "%s", psz); +} + +static char g_CmdLine[2048]{}; + +const char *Plat_GetCommandLine() +{ +#if defined(_LINUX) + static bool commandline_initialized = false; + if (!commandline_initialized) + { + commandline_initialized = true; + + FILE *fp = fopen("/proc/self/cmdline", "rb"); + if (fp) + { + size_t nCharRead = 0; + + // -1 to leave room for the '\0' + nCharRead = fread(g_CmdLine, sizeof(g_CmdLine[0]), ARRAYSIZE(g_CmdLine) - 1, fp); + if (feof(fp) && !ferror(fp)) // Should have read the whole command line without error + { + Assert(nCharRead < ARRAYSIZE(g_CmdLine)); + + for (int i = 0; i < nCharRead; i++) + { + if (!g_CmdLine[i]) + g_CmdLine[i] = ' '; + } + + g_CmdLine[nCharRead] = '\0'; + } + + fclose(fp); + } + + Assert(g_CmdLine[0]); + } +#endif // LINUX + + return g_CmdLine; +} diff --git a/regamedll/public/tier0/platform_win32.cpp b/regamedll/public/tier0/platform_win32.cpp new file mode 100644 index 000000000..0ffbf7cf3 --- /dev/null +++ b/regamedll/public/tier0/platform_win32.cpp @@ -0,0 +1,57 @@ +/* +* +* 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" + +bool Plat_IsInDebugSession() +{ + return IsDebuggerPresent() != FALSE; +} + +void Plat_OutputDebugStringRaw(const char *psz) +{ + OutputDebugString(psz); +} + +void Plat_OutputDebugString(const char *psz) +{ + static char buf[4096]; + int len = Q_snprintf(buf, sizeof(buf), "%s", psz); + Assert(len > 0); + OutputDebugString(buf); +} + +void Plat_DebugString(const char *psz) +{ + Plat_OutputDebugString(psz); +} + +const char *Plat_GetCommandLine() +{ + return GetCommandLineA(); +} diff --git a/regamedll/public/tier0/resource.h b/regamedll/public/tier0/resource.h new file mode 100644 index 000000000..d261901a6 --- /dev/null +++ b/regamedll/public/tier0/resource.h @@ -0,0 +1,44 @@ +/* +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by assert_dialog.rc +// + +#define IDD_ASSERT_DIALOG 101 +#define IDC_FILENAME_CONTROL 1000 +#define IDC_LINE_CONTROL 1001 +#define IDC_IGNORE_FILE 1002 +#define IDC_IGNORE_NEARBY 1003 +#define IDC_IGNORE_NUMLINES 1004 +#define IDC_IGNORE_THIS 1005 +#define IDC_BREAK 1006 +#define IDC_IGNORE_ALL 1008 +#define IDC_IGNORE_ALWAYS 1009 +#define IDC_IGNORE_NUMTIMES 1010 +#define IDC_ASSERT_MSG_CTRL 1011 +#define IDC_NOID -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1005 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/regamedll/public/utlarray.h b/regamedll/public/utlarray.h new file mode 100644 index 000000000..1da8aafb0 --- /dev/null +++ b/regamedll/public/utlarray.h @@ -0,0 +1,303 @@ +/* +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +*/ + +#pragma once + +// A growable array class that maintains a free list and keeps elements +// in the same location +#include "tier0/platform.h" +#include "tier0/dbg.h" + +#include + +#define FOR_EACH_ARRAY(vecName, iteratorName)\ + for (int iteratorName = 0; (vecName).IsUtlArray && iteratorName < (vecName).Count(); iteratorName++) + +#define FOR_EACH_ARRAY_BACK(vecName, iteratorName)\ + for (int iteratorName = (vecName).Count() - 1; (vecName).IsUtlArray && iteratorName >= 0; iteratorName--) + +template +class CUtlArray +{ +public: + typedef T ElemType_t; + enum { IsUtlArray = true }; // Used to match this at compiletime + + CUtlArray(); + CUtlArray(T *pMemory, size_t count); + ~CUtlArray(); + + CUtlArray &operator=(const CUtlArray &other); + CUtlArray(CUtlArray const &vec); + + // element access + T &operator[](int i); + const T &operator[](int i) const; + T &Element(int i); + const T &Element(int i) const; + T &Random(); + const T &Random() const; + + T *Base(); + const T *Base() const; + + // Returns the number of elements in the array, NumAllocated() is included for consistency with UtlVector + int Count() const; + int NumAllocated() const; + + // Is element index valid? + bool IsValidIndex(int i) const; + static int InvalidIndex(); + + void CopyArray(const T *pArray, size_t count); + + void Clear(); + void RemoveAll(); + void Swap(CUtlArray< T, MAX_SIZE> &vec); + + // Finds an element (element needs operator== defined) + int Find(const T &src) const; + void FillWithValue(const T &src); + + bool HasElement(const T &src) const; + + // sort using std:: and expecting a "<" function to be defined for the type + void Sort(); + void Sort(bool (*pfnLessFunc)(const T &src1, const T &src2)); + +#if defined(_WIN32) + void Sort(int (__cdecl *pfnCompare)(const T *, const T *)); +#else + void Sort(int (*pfnCompare)(const T *, const T *)); +#endif + + // sort using std:: with a predicate. e.g. [] -> bool (const T &a, const T &b) const { return a < b; } + template + void SortPredicate(F &&predicate); + +protected: + T m_Memory[MAX_SIZE]; +}; + +// Constructor +template +inline CUtlArray::CUtlArray() +{ +} + +template +inline CUtlArray::CUtlArray(T *pMemory, size_t count) +{ + CopyArray(pMemory, count); +} + +// Destructor +template +inline CUtlArray::~CUtlArray() +{ +} + +template +inline CUtlArray &CUtlArray::operator=(const CUtlArray &other) +{ + if (this != &other) + { + for (size_t n = 0; n < MAX_SIZE; n++) + m_Memory[n] = other.m_Memory[n]; + } + + return *this; +} + +template +inline CUtlArray::CUtlArray(CUtlArray const &vec) +{ + for (size_t n = 0; n < MAX_SIZE; n++) + m_Memory[n] = vec.m_Memory[n]; +} + +template +inline T *CUtlArray::Base() +{ + return &m_Memory[0]; +} + +template +inline const T *CUtlArray::Base() const +{ + return &m_Memory[0]; +} + +// Element access +template +inline T &CUtlArray::operator[](int i) +{ + DbgAssert(IsValidIndex(i)); + return m_Memory[i]; +} + +template +inline const T &CUtlArray::operator[](int i) const +{ + DbgAssert(IsValidIndex(i)); + return m_Memory[i]; +} + +template +inline T &CUtlArray::Element(int i) +{ + DbgAssert(IsValidIndex(i)); + return m_Memory[i]; +} + +template +inline const T &CUtlArray::Element(int i) const +{ + DbgAssert(IsValidIndex(i)); + return m_Memory[i]; +} + +// Count +template +inline int CUtlArray::Count() const +{ + return (int)MAX_SIZE; +} + +template +inline int CUtlArray::NumAllocated() const +{ + return (int)MAX_SIZE; +} + +// Is element index valid? +template +inline bool CUtlArray::IsValidIndex(int i) const +{ + return (i >= 0) && (i < MAX_SIZE); +} + +// Returns in invalid index +template +inline int CUtlArray::InvalidIndex() +{ + return -1; +} + +// Sort methods +template +void CUtlArray::Sort() +{ + std::sort(Base(), Base() + Count()); +} + +template +void CUtlArray::Sort(bool (*pfnLessFunc)(const T &src1, const T &src2)) +{ + std::sort(Base(), Base() + Count(), + [pfnLessFunc](const T &a, const T &b) -> bool + { + if (&a == &b) + return false; + + return (*pfnLessFunc)(a, b); + }); +} + +#if defined(_WIN32) + +template +void CUtlArray::Sort(int (__cdecl *pfnCompare)(const T *, const T *)) +{ + typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *); + if (Count() <= 1) + return; + + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); +} + +#else // #if defined(_LINUX) + +template +void CUtlArray::Sort(int (*pfnCompare)(const T *, const T *)) +{ + typedef int (*QSortCompareFunc_t)(const void *, const void *); + if (Count() <= 1) + return; + + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); +} +#endif // #if defined(_LINUX) + +template +template +void CUtlArray::SortPredicate(F &&predicate) +{ + std::sort(Base(), Base() + Count(), predicate); +} + +template +void CUtlArray::CopyArray(const T *pArray, size_t count) +{ + DbgAssert(count < MAX_SIZE); + + for (size_t n = 0; n < count; n++) + m_Memory[n] = pArray[n]; +} + +template +void CUtlArray::Clear() +{ + Q_memset(m_Memory, 0, MAX_SIZE * sizeof(T)); +} + +template +void CUtlArray::RemoveAll() +{ + Clear(); +} + +template +void CUtlArray::Swap(CUtlArray< T, MAX_SIZE> &vec) +{ + for (size_t n = 0; n < MAX_SIZE; n++) + SWAP(m_Memory[n], vec.m_Memory[n]); +} + +// Finds an element (element needs operator== defined) +template +int CUtlArray::Find(const T &src) const +{ + for (int i = 0; i < Count(); i++) + { + if (Element(i) == src) + return i; + } + + return -1; +} + +template +void CUtlArray::FillWithValue(const T &src) +{ + for (int i = 0; i < Count(); i++) + Element(i) = src; +} + +template +bool CUtlArray::HasElement(const T &src) const +{ + return (Find(src) >= 0); +} diff --git a/regamedll/public/utllinkedlist.h b/regamedll/public/utllinkedlist.h index c93369897..6d05231c9 100644 --- a/regamedll/public/utllinkedlist.h +++ b/regamedll/public/utllinkedlist.h @@ -248,14 +248,14 @@ inline I CUtlLinkedList::Tail() const template inline I CUtlLinkedList::Previous(I i) const { - Assert(IsValidIndex(i)); + DbgAssert(IsValidIndex(i)); return InternalElement(i).m_Previous; } template inline I CUtlLinkedList::Next(I i) const { - Assert(IsValidIndex(i)); + DbgAssert(IsValidIndex(i)); return InternalElement(i).m_Next; } @@ -319,7 +319,7 @@ I CUtlLinkedList::AllocInternal(bool multilist) if (m_TotalElements == m_Memory.NumAllocated()) m_Memory.Grow(); - Assert(m_TotalElements != InvalidIndex()); + DbgAssert(m_TotalElements != InvalidIndex()); elem = (I)m_TotalElements; m_TotalElements++; @@ -356,7 +356,7 @@ I CUtlLinkedList::Alloc(bool multilist) template void CUtlLinkedList::Free(I elem) { - Assert(IsValidIndex(elem)); + DbgAssert(IsValidIndex(elem)); Unlink(elem); ListElem_t &internalElem = InternalElement(elem); @@ -520,7 +520,7 @@ void CUtlLinkedList::RemoveAll() template void CUtlLinkedList::LinkBefore(I before, I elem) { - Assert(IsValidIndex(elem)); + DbgAssert(IsValidIndex(elem)); // Unlink it if it's in the list at the moment Unlink(elem); @@ -540,7 +540,7 @@ void CUtlLinkedList::LinkBefore(I before, I elem) { // Here, we're not linking to the end. Set the prev pointer to point to // the element we're linking. - Assert(IsInList(before)); + DbgAssert(IsInList(before)); ListElem_t& beforeElem = InternalElement(before); newElem.m_Previous = beforeElem.m_Previous; beforeElem.m_Previous = elem; @@ -559,7 +559,7 @@ void CUtlLinkedList::LinkBefore(I before, I elem) template void CUtlLinkedList::LinkAfter(I after, I elem) { - Assert(IsValidIndex(elem)); + DbgAssert(IsValidIndex(elem)); // Unlink it if it's in the list at the moment if (IsInList(elem)) @@ -579,7 +579,7 @@ void CUtlLinkedList::LinkAfter(I after, I elem) { // Here, we're not linking to the end. Set the next pointer to point to // the element we're linking. - Assert(IsInList(after)); + DbgAssert(IsInList(after)); ListElem_t& afterElem = InternalElement(after); newElem.m_Next = afterElem.m_Next; afterElem.m_Next = elem; @@ -598,7 +598,7 @@ void CUtlLinkedList::LinkAfter(I after, I elem) template void CUtlLinkedList::Unlink(I elem) { - Assert(IsValidIndex(elem)); + DbgAssert(IsValidIndex(elem)); if (IsInList(elem)) { ListElem_t *pBase = m_Memory.Base(); diff --git a/regamedll/public/utlmap.h b/regamedll/public/utlmap.h index f414604a1..2432b75e5 100644 --- a/regamedll/public/utlmap.h +++ b/regamedll/public/utlmap.h @@ -250,7 +250,7 @@ inline void CUtlMap::PurgeAndDeleteElements() template void DeepCopyMap(const CUtlMap &pmapIn, CUtlMap *out_pmapOut) { - Assert(out_pmapOut); + DbgAssert(out_pmapOut); out_pmapOut->Purge(); FOR_EACH_MAP_FAST(pmapIn, i) diff --git a/regamedll/public/utlmemory.h b/regamedll/public/utlmemory.h index a28bfea1f..1761dfa23 100644 --- a/regamedll/public/utlmemory.h +++ b/regamedll/public/utlmemory.h @@ -121,7 +121,7 @@ template CUtlMemory::CUtlMemory(int nGrowSize, int nInitSize) : m_pMemory(0), m_nAllocationCount(nInitSize), m_nGrowSize(nGrowSize) { - Assert((nGrowSize >= 0) && (nGrowSize != EXTERNAL_BUFFER_MARKER)); + DbgAssert((nGrowSize >= 0) && (nGrowSize != EXTERNAL_BUFFER_MARKER)); if (m_nAllocationCount) { m_pMemory = (T *)malloc(m_nAllocationCount * sizeof(T)); @@ -149,7 +149,7 @@ void CUtlMemory::Init(int nGrowSize, int nInitSize) m_nGrowSize = nGrowSize; m_nAllocationCount = nInitSize; - Assert(nGrowSize >= 0); + DbgAssert(nGrowSize >= 0); if (m_nAllocationCount) { m_pMemory = (T *)malloc(m_nAllocationCount * sizeof(T)); @@ -174,28 +174,28 @@ void CUtlMemory::SetExternalBuffer(T *pMemory, int numElements) template inline T& CUtlMemory::operator[](I i) { - Assert(IsIdxValid(i)); + DbgAssert(IsIdxValid(i)); return m_pMemory[i]; } template inline T const& CUtlMemory::operator[](I i) const { - Assert(IsIdxValid(i)); + DbgAssert(IsIdxValid(i)); return m_pMemory[i]; } template inline T& CUtlMemory::Element(I i) { - Assert(IsIdxValid(i)); + DbgAssert(IsIdxValid(i)); return m_pMemory[i]; } template inline T const& CUtlMemory::Element(I i) const { - Assert(IsIdxValid(i)); + DbgAssert(IsIdxValid(i)); return m_pMemory[i]; } @@ -209,7 +209,7 @@ bool CUtlMemory::IsExternallyAllocated() const template void CUtlMemory::SetGrowSize(int nSize) { - Assert((nSize >= 0) && (nSize != EXTERNAL_BUFFER_MARKER)); + DbgAssert((nSize >= 0) && (nSize != EXTERNAL_BUFFER_MARKER)); m_nGrowSize = nSize; } @@ -250,12 +250,12 @@ inline bool CUtlMemory::IsIdxValid(I i) const template void CUtlMemory::Grow(int num) { - Assert(num > 0); + DbgAssert(num > 0); if (IsExternallyAllocated()) { // Can't grow a buffer whose memory was externally allocated - Assert(0); + DbgAssert(0); return; } @@ -281,7 +281,7 @@ void CUtlMemory::Grow(int num) { // Compute an allocation which is at least as big as a cache line... m_nAllocationCount = (31 + sizeof(T)) / sizeof(T); - Assert(m_nAllocationCount != 0); + DbgAssert(m_nAllocationCount != 0); } } @@ -305,7 +305,7 @@ inline void CUtlMemory::EnsureCapacity(int num) if (IsExternallyAllocated()) { // Can't grow a buffer whose memory was externally allocated - Assert(0); + DbgAssert(0); return; } diff --git a/regamedll/public/utlrbtree.h b/regamedll/public/utlrbtree.h index 100ccbc90..114829df3 100644 --- a/regamedll/public/utlrbtree.h +++ b/regamedll/public/utlrbtree.h @@ -398,7 +398,7 @@ inline typename CUtlRBTree::Links_t const &CUtlRBTree::L template inline typename CUtlRBTree::Links_t &CUtlRBTree::Links(I i) { - Assert(i != InvalidIndex()); + DbgAssert(i != InvalidIndex()); return *(Links_t *)&m_Elements[i]; } @@ -460,7 +460,7 @@ I CUtlRBTree::NewNode() template void CUtlRBTree::FreeNode(I i) { - Assert(IsValidIndex(i) && (i != InvalidIndex())); + DbgAssert(IsValidIndex(i) && (i != InvalidIndex())); Destruct(&Element(i)); SetLeftChild(i, i); // indicates it's in not in the tree SetRightChild(i, m_FirstFree); @@ -624,7 +624,7 @@ void CUtlRBTree::LinkToParent(I i, I parent, bool isLeft) InsertRebalance(i); - Assert(IsValid()); + DbgAssert(IsValid()); } // Rebalance the tree after a deletion @@ -872,7 +872,7 @@ I CUtlRBTree::FirstInorder() const template I CUtlRBTree::NextInorder(I i) const { - Assert(IsValidIndex(i)); + DbgAssert(IsValidIndex(i)); if (RightChild(i) != InvalidIndex()) { @@ -895,7 +895,7 @@ I CUtlRBTree::NextInorder(I i) const template I CUtlRBTree::PrevInorder(I i) const { - Assert(IsValidIndex(i)); + DbgAssert(IsValidIndex(i)); if (LeftChild(i) != InvalidIndex()) { @@ -953,7 +953,7 @@ I CUtlRBTree::NextPreorder(I i) const template I CUtlRBTree::PrevPreorder(I i) const { - Assert(0); // Not implemented yet + DbgAssert(0); // Not implemented yet return InvalidIndex(); } @@ -1120,7 +1120,7 @@ void CUtlRBTree::SetLessFunc(typename CUtlRBTree::LessFu template void CUtlRBTree::FindInsertionPosition(T const &insert, I &parent, bool &leftchild) { - Assert(m_LessFunc); + DbgAssert(m_LessFunc); // Find where node belongs I current = m_Root; @@ -1167,7 +1167,7 @@ void CUtlRBTree::Insert(const T *pArray, int nItems) template I CUtlRBTree::Find(T const &search) const { - Assert(m_LessFunc); + DbgAssert(m_LessFunc); I current = m_Root; while (current != InvalidIndex()) diff --git a/regamedll/public/utlsymbol.cpp b/regamedll/public/utlsymbol.cpp index 1299d785d..078ff67d7 100644 --- a/regamedll/public/utlsymbol.cpp +++ b/regamedll/public/utlsymbol.cpp @@ -126,7 +126,7 @@ const char *CUtlSymbolTable::String(CUtlSymbol id) const if (!id.IsValid()) return ""; - assert(m_Lookup.IsValidIndex((UtlSymId_t)id)); + DbgAssert(m_Lookup.IsValidIndex((UtlSymId_t)id)); return &m_Strings[id]; } diff --git a/regamedll/public/utlvector.h b/regamedll/public/utlvector.h index 6dcd250f1..e3f34e585 100644 --- a/regamedll/public/utlvector.h +++ b/regamedll/public/utlvector.h @@ -30,6 +30,8 @@ #include "utlmemory.h" +#include + template class CUtlVector { @@ -126,9 +128,23 @@ class CUtlVector // Set the size by which it grows when it needs to allocate more memory. void SetGrowSize(int size); + // sort using std:: and expecting a "<" function to be defined for the type + void Sort(); + void Sort(bool (*pfnLessFunc)(const T &src1, const T &src2)); + +#if defined(_WIN32) + void Sort(int (__cdecl *pfnCompare)(const T *, const T *)); +#else + void Sort(int (*pfnCompare)(const T *, const T *)); +#endif + + // sort using std:: with a predicate. e.g. [] -> bool (const T &a, const T &b) const { return a < b; } + template + void SortPredicate(F &&predicate); + protected: // Can't copy this unless we explicitly do it! - CUtlVector(CUtlVector const &vec) { assert(0); } + CUtlVector(CUtlVector const &vec) { Assert(0); } // Grows the vector void GrowVector(int num = 1); @@ -187,28 +203,28 @@ inline CUtlVector &CUtlVector::operator=(const CUtlVector &other) template inline T &CUtlVector::operator[](int i) { - assert(IsValidIndex(i)); + DbgAssert(IsValidIndex(i)); return m_Memory[i]; } template inline T const &CUtlVector::operator[](int i) const { - assert(IsValidIndex(i)); + DbgAssert(IsValidIndex(i)); return m_Memory[i]; } template inline T &CUtlVector::Element(int i) { - assert(IsValidIndex(i)); + DbgAssert(IsValidIndex(i)); return m_Memory[i]; } template inline T const &CUtlVector::Element(int i) const { - assert(IsValidIndex(i)); + DbgAssert(IsValidIndex(i)); return m_Memory[i]; } @@ -285,7 +301,7 @@ void CUtlVector::EnsureCount(int num) template void CUtlVector::ShiftElementsRight(int elem, int num) { - assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + DbgAssert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); int numToMove = m_Size - elem - num; if ((numToMove > 0) && (num > 0)) memmove(&Element(elem+num), &Element(elem), numToMove * sizeof(T)); @@ -294,7 +310,7 @@ void CUtlVector::ShiftElementsRight(int elem, int num) template void CUtlVector::ShiftElementsLeft(int elem, int num) { - assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + DbgAssert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); int numToMove = m_Size - elem - num; if ((numToMove > 0) && (num > 0)) { @@ -329,7 +345,7 @@ template int CUtlVector::InsertBefore(int elem) { // Can insert at the end - assert((elem == Count()) || IsValidIndex(elem)); + DbgAssert((elem == Count()) || IsValidIndex(elem)); GrowVector(); ShiftElementsRight(elem); @@ -360,7 +376,7 @@ template< class T > int CUtlVector::InsertBefore(int elem, T const &src) { // Can insert at the end - assert((elem == Count()) || IsValidIndex(elem)); + DbgAssert((elem == Count()) || IsValidIndex(elem)); GrowVector(); ShiftElementsRight(elem); @@ -434,7 +450,7 @@ inline int CUtlVector::InsertMultipleBefore(int elem, int num, const T *pToIn return elem; // Can insert at the end - assert((elem == Count()) || IsValidIndex(elem)); + DbgAssert((elem == Count()) || IsValidIndex(elem)); GrowVector(num); ShiftElementsRight(elem, num); @@ -480,7 +496,7 @@ bool CUtlVector::HasElement(T const &src) template void CUtlVector::FastRemove(int elem) { - assert(IsValidIndex(elem)); + DbgAssert(IsValidIndex(elem)); Destruct(&Element(elem)); if (m_Size > 0) @@ -511,8 +527,8 @@ void CUtlVector::FindAndRemove(T const &src) template void CUtlVector::RemoveMultiple(int elem, int num) { - assert(IsValidIndex(elem)); - assert(elem + num <= Count()); + DbgAssert(IsValidIndex(elem)); + DbgAssert(elem + num <= Count()); for (int i = elem + num; --i >= elem;) Destruct(&Element(i)); @@ -562,3 +578,55 @@ void CUtlVector::SetGrowSize(int size) { m_Memory.SetGrowSize(size); } + +// Sort methods +template +void CUtlVector::Sort() +{ + std::sort(Base(), Base() + Count()); +} + +template +void CUtlVector::Sort(bool (*pfnLessFunc)(const T &src1, const T &src2)) +{ + std::sort(Base(), Base() + Count(), + [pfnLessFunc](const T &a, const T &b) -> bool + { + if (&a == &b) + return false; + + return (*pfnLessFunc)(a, b); + }); +} + +#if defined(_WIN32) + +template +void CUtlVector::Sort(int (__cdecl *pfnCompare)(const T *, const T *)) +{ + typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *); + if (Count() <= 1) + return; + + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); +} + +#else // #if defined(_LINUX) + +template +void CUtlVector::Sort(int (*pfnCompare)(const T *, const T *)) +{ + typedef int (*QSortCompareFunc_t)(const void *, const void *); + if (Count() <= 1) + return; + + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); +} +#endif // #if defined(_LINUX) + +template +template +void CUtlVector::SortPredicate(F &&predicate) +{ + std::sort(Base(), Base() + Count(), predicate); +} diff --git a/regamedll/regamedll/precompiled.h b/regamedll/regamedll/precompiled.h index 62d6dd3da..e4c3b1bb4 100644 --- a/regamedll/regamedll/precompiled.h +++ b/regamedll/regamedll/precompiled.h @@ -45,6 +45,15 @@ // Valve libs stuff #include "tier0/platform.h" + +// Asserts are always compiled in pre-released or nightly builds +#if !defined(_RELEASEPROD) + #define DBGFLAG_ASSERT // Turns Assert on or off + #define DBGFLAG_ASSERTFATAL // Turns AssertFatal on or off + #define DBGFLAG_ASSERTDLG // Turns assert dialogs on or off and debug breaks on or off when not under the debugger + // (Dialogs will always be on when process is being debugged.) +#endif + #include "tier0/dbg.h" #include "dlls.h" diff --git a/regamedll/version/version.h b/regamedll/version/version.h index ba22bb751..0f32ed96e 100644 --- a/regamedll/version/version.h +++ b/regamedll/version/version.h @@ -6,5 +6,5 @@ #pragma once #define VERSION_MAJOR 5 -#define VERSION_MINOR 21 +#define VERSION_MINOR 26 #define VERSION_MAINTENANCE 0