diff --git a/README.md b/README.md index 6713f49a..ecda6502 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_give_c4_frags | 3 | - | - | How many bonuses (frags) will get the player who defused or exploded the bomb. | | mp_hostages_rescued_ratio | 1.0 | 0.0 | 1.0 | Ratio of hostages rescued to win the round. | | mp_legacy_vehicle_block | 1 | 0 | 1 | Legacy func_vehicle behavior when blocked by another entity.
`0` New behavior
`1` Legacy behavior | +| 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.| ## How to install zBot for CS 1.6? diff --git a/dist/game.cfg b/dist/game.cfg index 25ba9877..76b28aa7 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -521,3 +521,11 @@ mp_hostages_rescued_ratio "1.0" // // Default value: "1" mp_legacy_vehicle_block "1" + +// Time for switch to free observing after death. +// NOTE: The countdown starts when the 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" diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 2e0ef12b..237a8f51 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -170,6 +170,8 @@ cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, n 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) @@ -418,6 +420,8 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&legacy_vehicle_block); + CVAR_REGISTER(&dying_time); + // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index ed2ae509..18ae0fdb 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -192,8 +192,9 @@ extern cvar_t sv_enablebunnyhopping; extern cvar_t plant_c4_anywhere; extern cvar_t give_c4_frags; extern cvar_t hostages_rescued_ratio; - extern cvar_t legacy_vehicle_block; +extern cvar_t dying_time; + #endif extern cvar_t scoreboard_showmoney; diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h index d6975df0..f6c621bd 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 @@ -206,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 @@ -336,6 +337,7 @@ public: 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 @@ -921,6 +923,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/player.cpp b/regamedll/dlls/player.cpp index 92a0d69e..58f82720 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -3857,7 +3857,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(); @@ -8818,9 +8818,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 @@ -8830,6 +8828,41 @@ 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 = -1.0; + + studiohdr_t *pstudiohdr = (studiohdr_t *)GET_MODEL_PTR(ENT(pev)); + if (pstudiohdr && pev->sequence < pstudiohdr->numseq) // model ptr and sequence validation + { + // get current sequence time + mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + int(pev->sequence); + animDuration = pseqdesc->numframes / pseqdesc->fps; + } + + if (animDuration <= 0.0) + { + // in case of failure + animDuration = DEATH_ANIMATION_TIME; + } + + // 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); @@ -8839,14 +8872,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) {