diff options
| author | Cristei Gabriel <cristei.g772@gmail.com> | 2023-11-26 14:45:20 +0200 |
|---|---|---|
| committer | Cristei Gabriel <cristei.g772@gmail.com> | 2023-11-26 14:45:20 +0200 |
| commit | a22914735903c4495b3af453668bf316111e5126 (patch) | |
| tree | f14283f87b97df9c1b0c2778487da00554fd4211 | |
| parent | c29160ec194bebb6dbbd18cc078cb6556f937f98 (diff) | |
| parent | 2d51c1ae80693f586f719640571591779bcb0c2d (diff) | |
Merge branch 'main' of https://github.com/navewindre/networkheaven
| -rw-r--r-- | sourcemod-1.5-dev/scripting/ljstats.sp | 7573 | ||||
| -rw-r--r-- | sourcemod/scripting/game_manager.sp | 233 | ||||
| -rw-r--r-- | sourcemod/scripting/sm_speedometer.sp | 9 |
3 files changed, 4167 insertions, 3648 deletions
diff --git a/sourcemod-1.5-dev/scripting/ljstats.sp b/sourcemod-1.5-dev/scripting/ljstats.sp index 29c4881..202dd9b 100644 --- a/sourcemod-1.5-dev/scripting/ljstats.sp +++ b/sourcemod-1.5-dev/scripting/ljstats.sp @@ -23,8 +23,8 @@ #define BHOP_TIME 0.3 #define STAMINA_RECHARGE_TIME 0.58579 #define SW_ANGLE_THRESHOLD 20.0 -#define LJ_HEIGHT_DELTA_MIN -0.01 // Dropjump limit -#define LJ_HEIGHT_DELTA_MAX 1.5 // Upjump limit +#define LJ_HEIGHT_DELTA_MIN -0.01 // Dropjump limit +#define LJ_HEIGHT_DELTA_MAX 1.5 // Upjump limit #define CJ_HEIGHT_DELTA_MIN -0.01 #define CJ_HEIGHT_DELTA_MAX 1.5 #define WJ_HEIGHT_DELTA_MIN -0.01 @@ -34,97 +34,104 @@ #define LAJ_HEIGHT_DELTA_MIN -6.0 #define LAJ_HEIGHT_DELTA_MAX 0.0 #define HUD_HINT_SIZE 256 +#define STRAFE_TRAINER_TICKS 9 public Plugin:myinfo = { - name = "ljstats", - author = "Miu, maintained and updated by networkheaven.net", - description = "longjump stats", - version = LJSTATS_VERSION, - url = "https://forums.alliedmods.net/showthread.php?p=2060983" + name = "ljstats", + author = "Miu, maintained and updated by networkheaven.net", + description = "longjump stats", + version = LJSTATS_VERSION, + url = "https://forums.alliedmods.net/showthread.php?p=2060983" } enum PlayerState { - bool:bLJEnabled, - bool:bHidePanel, - bool:bHideBhopPanel, - bool:bShowBhopStats, - bool:bBeam, + bool:bLJEnabled, + bool:bHidePanel, + bool:bHideBhopPanel, + bool:bShowBhopStats, + bool:bStrafeTrainer, + bool:bBeam, bool:bDeadstrafe, - bool:bSound, - bool:bBlockMode, - nVerbosity, - bool:bShowAllJumps, - bool:bShowPrestrafeHint, - - Float:fBlockDistance, - Float:vBlockNormal[2], - Float:vBlockEndPos[3], - bool:bFailedBlock, - - bool:bDuck, - bool:bLastDuckState, - bool:bSecondLastDuckState, - - JUMP_DIRECTION:JumpDir, - ILLEGAL_JUMP_FLAGS:IllegalJumpFlags, - - JUMP_TYPE:LastJumpType, - JUMP_TYPE:JumpType, - Float:fLandTime, - Float:fLastJumpHeightDelta, - nBhops, - - bool:bOnGround, - bool:bOnLadder, - - Float:fEdge, - Float:vJumpOrigin[3], - Float:fWJDropPre, - Float:fPrestrafe, - Float:fJumpDistance, - Float:fHeightDelta, - Float:fJumpHeight, - Float:fSync, - Float:fMaxSpeed, - Float:fFinalSpeed, - Float:fTrajectory, - Float:fGain, - Float:fLoss, - - STRAFE_DIRECTION:CurStrafeDir, - nStrafes, - STRAFE_DIRECTION:StrafeDir[MAX_STRAFES], - Float:fStrafeGain[MAX_STRAFES], - Float:fStrafeLoss[MAX_STRAFES], - Float:fStrafeSync[MAX_STRAFES], - nStrafeTicks[MAX_STRAFES], - nStrafeTicksSynced[MAX_STRAFES], - nTotalTicks, - Float:fTotalAngle, - Float:fSyncedAngle, - - bool:bStamina, - nJumpTick, - nLastAerialTick, - - Float:vLastOrigin[3], - Float:vLastAngles[3], - Float:vLastVelocity[3], + bool:bSound, + bool:bBlockMode, + nVerbosity, + bool:bShowAllJumps, + bool:bShowPrestrafeHint, + nSpeedometer, + + Float:fBlockDistance, + Float:vBlockNormal[2], + Float:vBlockEndPos[3], + bool:bFailedBlock, + + bool:bDuck, + bool:bLastDuckState, + bool:bSecondLastDuckState, + + JUMP_DIRECTION:JumpDir, + ILLEGAL_JUMP_FLAGS:IllegalJumpFlags, + + JUMP_TYPE:LastJumpType, + JUMP_TYPE:JumpType, + Float:fLandTime, + Float:fLastJumpHeightDelta, + nBhops, + + bool:bOnGround, + bool:bOnLadder, + bool:bPerf, + + Float:fEdge, + Float:vJumpOrigin[3], + Float:fJumpSpeed, + Float:fWJDropPre, + Float:fPrestrafe, + Float:fJumpDistance, + Float:fHeightDelta, + Float:fJumpHeight, + Float:fSync, + Float:fMaxSpeed, + Float:fFinalSpeed, + Float:fTrajectory, + Float:fGain, + Float:fLoss, + + STRAFE_DIRECTION:CurStrafeDir, + nStrafes, + STRAFE_DIRECTION:StrafeDir[MAX_STRAFES], + Float:fStrafeGain[MAX_STRAFES], + Float:fStrafeLoss[MAX_STRAFES], + Float:fStrafeSync[MAX_STRAFES], + nStrafeTicks[MAX_STRAFES], + nStrafeTicksSynced[MAX_STRAFES], + nTotalTicks, + Float:fTotalAngle, + Float:fSyncedAngle, + Float:fStrafePercentages[STRAFE_TRAINER_TICKS], + nTrainerTicks, + + bool:bStamina, + nJumpTick, + nLastAerialTick, + + Float:vLastOrigin[3], + Float:vLastAngles[3], + Float:vLastVelocity[3], Float:vTPOrigin[3], Float:vTPAngles[3], - - String:strHUDHint[HUD_HINT_SIZE / 4], // string characters are stored as cells - - Float:fPersonalBest, - - nSpectators, - nSpectatorTarget, - - GAP_SELECTION_MODE:GapSelectionMode, - Float:vGapPoint1[3], - LastButtons, + + String:strHUDHint[HUD_HINT_SIZE / 4], // string characters are stored as cells + + Float:fPersonalBest, + + nSpectators, + nSpectatorTarget, + + GAP_SELECTION_MODE:GapSelectionMode, + Float:vGapPoint1[3], + LastButtons, } #define LJTOP_MIN_NUM_STATS_0 7 @@ -134,179 +141,179 @@ enum PlayerState enum TopStats { - String:m_strName[64 / 4], - String:m_strSteamID[32 / 4], - Float:m_fDistance, - Float:m_fPrestrafe, - m_nStrafes, // - Float:m_fSync, - Float:m_fMaxSpeed, - m_nTotalTicks, - Float:m_fSyncedAngle, - Float:m_fTotalAngle, // - Float:m_fHeightDelta, - Float:m_fBlockDistance, - Float:m_fTrajectory, - m_nTimestamp, - - STRAFE_DIRECTION:m_StrafeDir[LJTOP_MAX_STRAFES], - Float:m_fStrafeGain[LJTOP_MAX_STRAFES], - Float:m_fStrafeLoss[LJTOP_MAX_STRAFES], - m_nStrafeTicks[LJTOP_MAX_STRAFES], - Float:m_fStrafeSync[LJTOP_MAX_STRAFES], + String:m_strName[64 / 4], + String:m_strSteamID[32 / 4], + Float:m_fDistance, + Float:m_fPrestrafe, + m_nStrafes, // + Float:m_fSync, + Float:m_fMaxSpeed, + m_nTotalTicks, + Float:m_fSyncedAngle, + Float:m_fTotalAngle, // + Float:m_fHeightDelta, + Float:m_fBlockDistance, + Float:m_fTrajectory, + m_nTimestamp, + + STRAFE_DIRECTION:m_StrafeDir[LJTOP_MAX_STRAFES], + Float:m_fStrafeGain[LJTOP_MAX_STRAFES], + Float:m_fStrafeLoss[LJTOP_MAX_STRAFES], + m_nStrafeTicks[LJTOP_MAX_STRAFES], + Float:m_fStrafeSync[LJTOP_MAX_STRAFES], } enum ILLEGAL_JUMP_FLAGS { - IJF_NONE = 0, - IJF_WORLD = 1 << 0, - IJF_BOOSTER = 1 << 1, - IJF_GRAVITY = 1 << 2, - IJF_TELEPORT = 1 << 3, - IJF_LAGGEDMOVEMENTVALUE = 1 << 4, - IJF_PRESTRAFE = 1 << 5, - IJF_SCOUT = 1 << 6, - IJF_NOCLIP = 1 << 7, + IJF_NONE = 0, + IJF_WORLD = 1 << 0, + IJF_BOOSTER = 1 << 1, + IJF_GRAVITY = 1 << 2, + IJF_TELEPORT = 1 << 3, + IJF_LAGGEDMOVEMENTVALUE = 1 << 4, + IJF_PRESTRAFE = 1 << 5, + IJF_SCOUT = 1 << 6, + IJF_NOCLIP = 1 << 7, } enum JUMP_TYPE { - JT_LONGJUMP, - JT_COUNTJUMP, - JT_WEIRDJUMP, - JT_BHOPJUMP, - JT_LADDERJUMP, - JT_BHOP, - JT_DROP, - JT_END, + JT_LONGJUMP, + JT_COUNTJUMP, + JT_WEIRDJUMP, + JT_BHOPJUMP, + JT_LADDERJUMP, + JT_BHOP, + JT_DROP, + JT_END, } enum JUMP_DIRECTION { - JD_NONE, // Indeterminate - JD_NORMAL, - JD_FORWARDS = JD_NORMAL, - JD_SIDEWAYS, - JD_BACKWARDS, - JD_END, + JD_NONE, // Indeterminate + JD_NORMAL, + JD_FORWARDS = JD_NORMAL, + JD_SIDEWAYS, + JD_BACKWARDS, + JD_END, } enum STRAFE_DIRECTION { - SD_NONE, - SD_W, - SD_D, - SD_A, - SD_S, - SD_WA, - SD_WD, - SD_SA, - SD_SD, - SD_END, + SD_NONE, + SD_W, + SD_D, + SD_A, + SD_S, + SD_WA, + SD_WD, + SD_SA, + SD_SD, + SD_END, } enum GAP_SELECTION_MODE { - GSM_NONE, - GSM_GAP, - GSM_GAPSECOND, - GSM_BLOCKGAP, + GSM_NONE, + GSM_GAP, + GSM_GAPSECOND, + GSM_BLOCKGAP, } enum LJTOP_TABLE { - LT_LJ, - LT_SWLJ, - LT_BWLJ, - LT_CJ, - LT_BJ, - LT_LAJ, - LT_END + LT_LJ, + LT_SWLJ, + LT_BWLJ, + LT_CJ, + LT_BJ, + LT_LAJ, + LT_END } new String:g_strLJTopTags[LT_END][] = { - "lj", - "swlj", - "bwlj", - "cj", - "bj", - "laj" + "lj", + "swlj", + "bwlj", + "cj", + "bj", + "laj" }; new String:g_strLJTopTableName[LT_END][] = { - "Longjump", - "Sideways longjump", - "Backwards longjump", - "Countjump", - "Bhopjump", - "Ladderjump" + "Longjump", + "Sideways longjump", + "Backwards longjump", + "Countjump", + "Bhopjump", + "Ladderjump" }; new String:g_strLJTopOutput[LT_END][] = { - "lj", - "sideways lj", - "backwards lj", - "countjump", - "bhopjump", - "ladderjump" + "lj", + "sideways lj", + "backwards lj", + "countjump", + "bhopjump", + "ladderjump" }; new String:g_strJumpType[JT_END][] = { - "Longjump", - "Countjump", - "Weirdjump", - "Bhopjump", - "Ladderjump", - "Bhop", - "Drop" + "Longjump", + "Countjump", + "Weirdjump", + "Bhopjump", + "Ladderjump", + "Bhop", + "Drop" }; new String:g_strJumpTypeLwr[JT_END][] = { - "longjump", - "countjump", - "weirdjump", - "bhopjump", - "ladderjump", - "bhop", - "drop" + "longjump", + "countjump", + "weirdjump", + "bhopjump", + "ladderjump", + "bhop", + "drop" }; new String:g_strJumpTypeShort[JT_END][] = { - "LJ", - "CJ", - "WJ", - "BJ", - "LAJ", - "Bhop", - "Drop" + "LJ", + "CJ", + "WJ", + "BJ", + "LAJ", + "Bhop", + "Drop" }; new const Float:g_fHeightDeltaMin[JT_END] = { - LJ_HEIGHT_DELTA_MIN, - LJ_HEIGHT_DELTA_MIN, - WJ_HEIGHT_DELTA_MIN, - BJ_HEIGHT_DELTA_MIN, - LAJ_HEIGHT_DELTA_MIN, - -3.402823466e38, - -3.402823466e38 + LJ_HEIGHT_DELTA_MIN, + LJ_HEIGHT_DELTA_MIN, + WJ_HEIGHT_DELTA_MIN, + BJ_HEIGHT_DELTA_MIN, + LAJ_HEIGHT_DELTA_MIN, + -3.402823466e38, + -3.402823466e38 }; new const Float:g_fHeightDeltaMax[JT_END] = { - LJ_HEIGHT_DELTA_MAX, - LJ_HEIGHT_DELTA_MAX, - WJ_HEIGHT_DELTA_MAX, - BJ_HEIGHT_DELTA_MAX, - LAJ_HEIGHT_DELTA_MAX, - 3.402823466e38, - 3.402823466e38 + LJ_HEIGHT_DELTA_MAX, + LJ_HEIGHT_DELTA_MAX, + WJ_HEIGHT_DELTA_MAX, + BJ_HEIGHT_DELTA_MAX, + LAJ_HEIGHT_DELTA_MAX, + 3.402823466e38, + 3.402823466e38 }; // SourcePawn is silly @@ -360,6 +367,8 @@ new Handle:g_hCvarLJSound4File = INVALID_HANDLE; new Handle:g_hCvarLJSound5File = INVALID_HANDLE; new Handle:g_hCvarLJSoundToAll[5] = {INVALID_HANDLE, ...}; +new Handle:nh_warmup = INVALID_HANDLE; + new Handle:g_hCvarMaxspeed = INVALID_HANDLE; new Handle:g_hCvarEnableBunnyHopping = INVALID_HANDLE; @@ -376,6 +385,8 @@ new Handle:g_hCookieVerbosity = INVALID_HANDLE; new Handle:g_hCookieShowAllJumps = INVALID_HANDLE; new Handle:g_hCookieShowPrestrafeHint = INVALID_HANDLE; new Handle:g_hCookiePersonalBest = INVALID_HANDLE; +new Handle:g_hCookieStrafeTrainer = INVALID_HANDLE; +new Handle:g_hCookieSpeedometer = INVALID_HANDLE; new g_ColorMin[3] = {0xAD, 0xD8, 0xE6}; // Lightblue! new g_ColorMax[3] = {0x00, 0x00, 0xFF}; @@ -403,167 +414,172 @@ new Float:g_fBJSound[5] = {250.0, 255.0, 260.0, 265.0, 0.0}; new String:g_strLJSoundFile[5][64] = {"misc/perfect.wav", "misc/mod_wickedsick.wav", "misc/mod_godlike.wav", "misc/holyshit.wav", ""}; new bool:g_bLJSoundToAll[5] = false; -new Float:g_fMaxspeed = 320.0; // sv_maxspeed -new bool:g_bEnableBunnyHopping = true; // sv_enablebunnyhopping +new Float:g_fMaxspeed = 320.0; // sv_maxspeed +new bool:g_bEnableBunnyHopping = true; // sv_enablebunnyhopping Handle:CreateCvar(String:strName[], String:strValue[]) { - new Handle:hCvar = CreateConVar(strName, strValue); - HookConVarChange(hCvar, OnCvarChange); - - return hCvar; + new Handle:hCvar = CreateConVar(strName, strValue); + HookConVarChange(hCvar, OnCvarChange); + + return hCvar; } public OnPluginStart() { - DB_Connect(); - DB_CreateTables(); - DB_LoadLJTop(); - - CreateConVar("mljstats_version", LJSTATS_VERSION, "ljstats version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); - - g_hCvarColorMin = CreateCvar("ljstats_color_min", "ADD8E6"); - g_hCvarColorMax = CreateCvar("ljstats_color_max", "0000FF"); + DB_Connect(); + DB_CreateTables(); + DB_LoadLJTop(); + + CreateConVar("mljstats_version", LJSTATS_VERSION, "ljstats version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); + + g_hCvarColorMin = CreateCvar("ljstats_color_min", "ADD8E6"); + g_hCvarColorMax = CreateCvar("ljstats_color_max", "0000FF"); g_hCvarColorTop = CreateCvar("ljstats_color_top", "FFFF00"); - g_hCvarLJMin = CreateCvar("ljstats_lj_min", "260"); - g_hCvarLJMax = CreateCvar("ljstats_lj_max", "275"); - g_hCvarNonLJMax = CreateCvar("ljstats_nonlj_max", "275"); - g_hCvarLJMaxPrestrafe = CreateCvar("ljstats_lj_max_prestrafe", "280"); - g_hCvarLJScoutStats = CreateCvar("ljstats_lj_scout_stats", "0"); - g_hCvarLJNoDuckMin = CreateCvar("ljstats_lj_noduck_min", "256"); - g_hCvarLJClientMin = CreateCvar("ljstats_lj_client_min", "0.0"); - g_hCvarWJMin = CreateCvar("ljstats_wj_min", "270"); - g_hCvarWJDropMax = CreateCvar("ljstats_wj_drop_max", "30.0"); - g_hCvarBJMin = CreateCvar("ljstats_bj_min", "270"); - g_hCvarBJMax = CreateCvar("ljstats_bj_max", "265"); - g_hCvarLAJMin = CreateCvar("ljstats_laj_min", "140"); - g_hCvarVerbosity = CreateCvar("ljstats_verbosity", "2"); - g_hCvarPrintFailedBlockStats = CreateCvar("ljstats_print_failed_block_stats", "1"); - g_hCvarShowBhopStats = CreateCvar("ljstats_show_bhop_stats", "0"); - g_hCvarOutput16Style = CreateCvar("ljstats_output_1.6_style", "0"); - g_hCvarLJTopAllowEasyBJ = CreateCvar("ljstats_ljtop_allow_easybhopjump", "1"); - g_hCvarLJSound = CreateCvar("ljstats_lj_sound", "1"); - g_hCvarLJSound1 = CreateCvar("ljstats_lj_sound1", "260"); - g_hCvarLJSound2 = CreateCvar("ljstats_lj_sound2", "265"); - g_hCvarLJSound3 = CreateCvar("ljstats_lj_sound3", "268"); - g_hCvarLJSound4 = CreateCvar("ljstats_lj_sound4", "270"); - g_hCvarLJSound5 = CreateCvar("ljstats_lj_sound5", "0"); + g_hCvarLJMin = CreateCvar("ljstats_lj_min", "260"); + g_hCvarLJMax = CreateCvar("ljstats_lj_max", "275"); + g_hCvarNonLJMax = CreateCvar("ljstats_nonlj_max", "275"); + g_hCvarLJMaxPrestrafe = CreateCvar("ljstats_lj_max_prestrafe", "280"); + g_hCvarLJScoutStats = CreateCvar("ljstats_lj_scout_stats", "0"); + g_hCvarLJNoDuckMin = CreateCvar("ljstats_lj_noduck_min", "256"); + g_hCvarLJClientMin = CreateCvar("ljstats_lj_client_min", "0.0"); + g_hCvarWJMin = CreateCvar("ljstats_wj_min", "270"); + g_hCvarWJDropMax = CreateCvar("ljstats_wj_drop_max", "30.0"); + g_hCvarBJMin = CreateCvar("ljstats_bj_min", "270"); + g_hCvarBJMax = CreateCvar("ljstats_bj_max", "265"); + g_hCvarLAJMin = CreateCvar("ljstats_laj_min", "140"); + g_hCvarVerbosity = CreateCvar("ljstats_verbosity", "2"); + g_hCvarPrintFailedBlockStats = CreateCvar("ljstats_print_failed_block_stats", "1"); + g_hCvarShowBhopStats = CreateCvar("ljstats_show_bhop_stats", "0"); + g_hCvarOutput16Style = CreateCvar("ljstats_output_1.6_style", "0"); + g_hCvarLJTopAllowEasyBJ = CreateCvar("ljstats_ljtop_allow_easybhopjump", "1"); + g_hCvarLJSound = CreateCvar("ljstats_lj_sound", "1"); + g_hCvarLJSound1 = CreateCvar("ljstats_lj_sound1", "260"); + g_hCvarLJSound2 = CreateCvar("ljstats_lj_sound2", "265"); + g_hCvarLJSound3 = CreateCvar("ljstats_lj_sound3", "268"); + g_hCvarLJSound4 = CreateCvar("ljstats_lj_sound4", "270"); + g_hCvarLJSound5 = CreateCvar("ljstats_lj_sound5", "0"); g_hCvarBJSound1 = CreateCvar("ljstats_bj_sound1", "250"); - g_hCvarBJSound2 = CreateCvar("ljstats_bj_sound2", "255"); - g_hCvarBJSound3 = CreateCvar("ljstats_bj_sound3", "260"); - g_hCvarBJSound4 = CreateCvar("ljstats_bj_sound4", "265"); - g_hCvarBJSound5 = CreateCvar("ljstats_bj_sound5", "0"); - g_hCvarLJSound1File = CreateCvar("ljstats_lj_sound1_file", g_strLJSoundFile[0]); - g_hCvarLJSound2File = CreateCvar("ljstats_lj_sound2_file", g_strLJSoundFile[1]); - g_hCvarLJSound3File = CreateCvar("ljstats_lj_sound3_file", g_strLJSoundFile[2]); - g_hCvarLJSound4File = CreateCvar("ljstats_lj_sound4_file", g_strLJSoundFile[3]); - g_hCvarLJSound5File = CreateCvar("ljstats_lj_sound5_file", g_strLJSoundFile[4]); - g_hCvarLJSoundToAll[0] = CreateCvar("ljstats_lj_sound1_to_all", "0"); - g_hCvarLJSoundToAll[1] = CreateCvar("ljstats_lj_sound2_to_all", "0"); - g_hCvarLJSoundToAll[2] = CreateCvar("ljstats_lj_sound3_to_all", "0"); - g_hCvarLJSoundToAll[3] = CreateCvar("ljstats_lj_sound4_to_all", "0"); - g_hCvarLJSoundToAll[4] = CreateCvar("ljstats_lj_sound5_to_all", "0"); - - g_hCvarMaxspeed = FindConVar("sv_maxspeed"); - if(g_hCvarMaxspeed) - { - g_fMaxspeed = GetConVarFloat(g_hCvarMaxspeed); - } - - HookConVarChange(g_hCvarMaxspeed, OnCvarChange); - - g_hCvarEnableBunnyHopping = FindConVar("sv_enablebunnyhopping"); - if(g_hCvarEnableBunnyHopping) - { - g_bEnableBunnyHopping = GetConVarBool(g_hCvarEnableBunnyHopping); - } - - HookConVarChange(g_hCvarEnableBunnyHopping, OnCvarChange); - - CreateNative("LJStats_CancelJump", Native_CancelJump); - - HookEvent("player_jump", Event_PlayerJump); - HookEvent("player_death", Event_PlayerDeath); - - RegConsoleCmd("sm_ljhelp", Command_LJHelp); - - RegConsoleCmd("sm_lj", Command_LJSettings); - RegConsoleCmd("sm_ljsettings", Command_LJSettings); - RegConsoleCmd("sm_ljs", Command_LJSettings); - RegConsoleCmd("sm_ljpanel", Command_LJPanel); - RegConsoleCmd("sm_ljbeam", Command_LJBeam); - RegConsoleCmd("sm_ljdeadstrafe", Command_LJDeadstrafe); - RegConsoleCmd("sm_ljblock", Command_LJBlock); - RegConsoleCmd("sm_ljb", Command_LJBlock); - RegConsoleCmd("sm_ljsound", Command_LJSound); - RegConsoleCmd("sm_ljver", Command_LJVersion); - RegConsoleCmd("sm_ljversion", Command_LJVersion); - RegConsoleCmd("sm_ljtop", Command_LJTop); - #if defined LJSERV - RegConsoleCmd("sm_wr", Command_LJTop); - #endif + g_hCvarBJSound2 = CreateCvar("ljstats_bj_sound2", "255"); + g_hCvarBJSound3 = CreateCvar("ljstats_bj_sound3", "260"); + g_hCvarBJSound4 = CreateCvar("ljstats_bj_sound4", "265"); + g_hCvarBJSound5 = CreateCvar("ljstats_bj_sound5", "0"); + g_hCvarLJSound1File = CreateCvar("ljstats_lj_sound1_file", g_strLJSoundFile[0]); + g_hCvarLJSound2File = CreateCvar("ljstats_lj_sound2_file", g_strLJSoundFile[1]); + g_hCvarLJSound3File = CreateCvar("ljstats_lj_sound3_file", g_strLJSoundFile[2]); + g_hCvarLJSound4File = CreateCvar("ljstats_lj_sound4_file", g_strLJSoundFile[3]); + g_hCvarLJSound5File = CreateCvar("ljstats_lj_sound5_file", g_strLJSoundFile[4]); + g_hCvarLJSoundToAll[0] = CreateCvar("ljstats_lj_sound1_to_all", "0"); + g_hCvarLJSoundToAll[1] = CreateCvar("ljstats_lj_sound2_to_all", "0"); + g_hCvarLJSoundToAll[2] = CreateCvar("ljstats_lj_sound3_to_all", "0"); + g_hCvarLJSoundToAll[3] = CreateCvar("ljstats_lj_sound4_to_all", "0"); + g_hCvarLJSoundToAll[4] = CreateCvar("ljstats_lj_sound5_to_all", "0"); + + g_hCvarMaxspeed = FindConVar("sv_maxspeed"); + if(g_hCvarMaxspeed) + { + g_fMaxspeed = GetConVarFloat(g_hCvarMaxspeed); + } + + HookConVarChange(g_hCvarMaxspeed, OnCvarChange); + + g_hCvarEnableBunnyHopping = FindConVar("sv_enablebunnyhopping"); + if(g_hCvarEnableBunnyHopping) + { + g_bEnableBunnyHopping = GetConVarBool(g_hCvarEnableBunnyHopping); + } + + HookConVarChange(g_hCvarEnableBunnyHopping, OnCvarChange); + + CreateNative("LJStats_CancelJump", Native_CancelJump); + + HookEvent("player_jump", Event_PlayerJump); + HookEvent("player_death", Event_PlayerDeath); + HookEvent("player_spawn", Event_PlayerSpawn); + + RegConsoleCmd("sm_ljhelp", Command_LJHelp); + + RegConsoleCmd("sm_lj", Command_LJSettings); + RegConsoleCmd("sm_ljsettings", Command_LJSettings); + RegConsoleCmd("sm_ljs", Command_LJSettings); + RegConsoleCmd("sm_ljpanel", Command_LJPanel); + RegConsoleCmd("sm_ljbeam", Command_LJBeam); + RegConsoleCmd("sm_ljdeadstrafe", Command_LJDeadstrafe); + RegConsoleCmd("sm_ljblock", Command_LJBlock); + RegConsoleCmd("sm_ljb", Command_LJBlock); + RegConsoleCmd("sm_ljsound", Command_LJSound); + RegConsoleCmd("sm_ljver", Command_LJVersion); + RegConsoleCmd("sm_ljversion", Command_LJVersion); + RegConsoleCmd("sm_ljtop", Command_LJTop); + #if defined LJSERV + RegConsoleCmd("sm_wr", Command_LJTop); + #endif RegConsoleCmd("sm_tpmenu", Command_CheckpointPanel); - RegAdminCmd("sm_ljtopdelete", Command_LJTopDelete, ADMFLAG_RCON); + RegAdminCmd("sm_ljtopdelete", Command_LJTopDelete, ADMFLAG_RCON); RegAdminCmd("sm_kz", Command_KZ, ADMFLAG_RCON); - RegConsoleCmd("sm_gap", Command_Gap); - RegConsoleCmd("sm_blockgap", Command_BlockGap); - RegConsoleCmd("sm_tele", Command_Tele); - RegAdminCmd("sm_ljtopdeleteall", Command_Delete, ADMFLAG_RCON); - RegConsoleCmd("sm_ljpb", Command_PersonalBest); - RegConsoleCmd("sm_pb", Command_PersonalBest); - RegConsoleCmd("sm_personalbest", Command_PersonalBest); - RegConsoleCmd("sm_pr", Command_PersonalBest); - RegConsoleCmd("sm_resetpersonalbest", Command_ResetPersonalBest); - RegAdminCmd("sm_ljtoploadfromfile", Command_LJTopLoadFromFile, ADMFLAG_RCON); - - g_hCookieDefaultsSet = RegClientCookie("ljstats_defaultsset", "ljstats_defaultsset", CookieAccess_Public); - g_hCookieLJEnabled = RegClientCookie("ljstats_ljenabled", "ljstats_ljenabled", CookieAccess_Public); - g_hCookieBlockMode = RegClientCookie("ljstats_blockmode", "ljstats_blockmode", CookieAccess_Public); - g_hCookieBeam = RegClientCookie("ljstats_beam", "ljstats_beam", CookieAccess_Public); - g_hCookieDeadstrafe = RegClientCookie("ljstats_deadstrafe", "ljstats_deadstrafe", CookieAccess_Public); - g_hCookieSound = RegClientCookie("ljstats_sound", "ljstats_sound", CookieAccess_Public); - g_hCookieHidePanel = RegClientCookie("ljstats_hidepanel", "ljstats_hidepanel", CookieAccess_Public); - g_hCookieHideBhopPanel = RegClientCookie("ljstats_hidebhoppanel", "ljstats_hidebhoppanel", CookieAccess_Public); - g_hCookieShowBhopStats = RegClientCookie("ljstats_showbhopstats", "ljstats_showbhopstats", CookieAccess_Public); - g_hCookieVerbosity = RegClientCookie("ljstats_verbosity", "ljstats_verbosity", CookieAccess_Public); - g_hCookieShowAllJumps = RegClientCookie("ljstats_showalljumps", "ljstats_showalljumps", CookieAccess_Public); - g_hCookieShowPrestrafeHint = RegClientCookie("ljstats_showprestrafehint", "ljstats_showprestrafehint", CookieAccess_Public); - g_hCookiePersonalBest = RegClientCookie("ljstats_personalbest", "ljstats_personalbest", CookieAccess_Private); - - for(new i = 1; i < MaxClients; i++) - { - if(IsClientInGame(i)) - { - OnClientPutInServer(i); - OnClientCookiesCached(i); - } - } + RegConsoleCmd("sm_gap", Command_Gap); + RegConsoleCmd("sm_strafetrainer", Command_StrafeTrainer); + RegConsoleCmd("sm_speed", Command_Speedometer); + RegConsoleCmd("sm_blockgap", Command_BlockGap); + RegConsoleCmd("sm_tele", Command_Tele); + RegAdminCmd("sm_ljtopdeleteall", Command_Delete, ADMFLAG_RCON); + RegConsoleCmd("sm_ljpb", Command_PersonalBest); + RegConsoleCmd("sm_pb", Command_PersonalBest); + RegConsoleCmd("sm_personalbest", Command_PersonalBest); + RegConsoleCmd("sm_pr", Command_PersonalBest); + RegConsoleCmd("sm_resetpersonalbest", Command_ResetPersonalBest); + RegAdminCmd("sm_ljtoploadfromfile", Command_LJTopLoadFromFile, ADMFLAG_RCON); + + g_hCookieDefaultsSet = RegClientCookie("ljstats_defaultsset", "ljstats_defaultsset", CookieAccess_Public); + g_hCookieLJEnabled = RegClientCookie("ljstats_ljenabled", "ljstats_ljenabled", CookieAccess_Public); + g_hCookieBlockMode = RegClientCookie("ljstats_blockmode", "ljstats_blockmode", CookieAccess_Public); + g_hCookieBeam = RegClientCookie("ljstats_beam", "ljstats_beam", CookieAccess_Public); + g_hCookieDeadstrafe = RegClientCookie("ljstats_deadstrafe", "ljstats_deadstrafe", CookieAccess_Public); + g_hCookieSound = RegClientCookie("ljstats_sound", "ljstats_sound", CookieAccess_Public); + g_hCookieHidePanel = RegClientCookie("ljstats_hidepanel", "ljstats_hidepanel", CookieAccess_Public); + g_hCookieHideBhopPanel = RegClientCookie("ljstats_hidebhoppanel", "ljstats_hidebhoppanel", CookieAccess_Public); + g_hCookieShowBhopStats = RegClientCookie("ljstats_showbhopstats", "ljstats_showbhopstats", CookieAccess_Public); + g_hCookieVerbosity = RegClientCookie("ljstats_verbosity", "ljstats_verbosity", CookieAccess_Public); + g_hCookieShowAllJumps = RegClientCookie("ljstats_showalljumps", "ljstats_showalljumps", CookieAccess_Public); + g_hCookieShowPrestrafeHint = RegClientCookie("ljstats_showprestrafehint", "ljstats_showprestrafehint", CookieAccess_Public); + g_hCookiePersonalBest = RegClientCookie("ljstats_personalbest", "ljstats_personalbest", CookieAccess_Private); + g_hCookieStrafeTrainer = RegClientCookie("ljstats_strafetrainer", "ljstats_strafetrainer", CookieAccess_Private); + g_hCookieSpeedometer = RegClientCookie("ljstats_speedometer", "ljstats_speedometer", CookieAccess_Private); + + for(new i = 1; i < MaxClients; i++) + { + if(IsClientInGame(i)) + { + OnClientPutInServer(i); + OnClientCookiesCached(i); + } + } } /* enum TopStats { - String:m_strName[64 / 4], - String:m_strSteamID[32 / 4], - Float:m_fDistance, - Float:m_fPrestrafe, - m_nStrafes, // - Float:m_fSync, - Float:m_fMaxSpeed, - m_nTotalTicks, - Float:m_fSyncedAngle, - Float:m_fTotalAngle, // - Float:m_fHeightDelta, - Float:m_fBlockDistance, - Float:m_fTrajectory, - m_nTimestamp, - - STRAFE_DIRECTION:m_StrafeDir[LJTOP_MAX_STRAFES], - Float:m_fStrafeGain[LJTOP_MAX_STRAFES], - Float:m_fStrafeLoss[LJTOP_MAX_STRAFES], - m_nStrafeTicks[LJTOP_MAX_STRAFES], - Float:m_fStrafeSync[LJTOP_MAX_STRAFES], + String:m_strName[64 / 4], + String:m_strSteamID[32 / 4], + Float:m_fDistance, + Float:m_fPrestrafe, + m_nStrafes, // + Float:m_fSync, + Float:m_fMaxSpeed, + m_nTotalTicks, + Float:m_fSyncedAngle, + Float:m_fTotalAngle, // + Float:m_fHeightDelta, + Float:m_fBlockDistance, + Float:m_fTrajectory, + m_nTimestamp, + + STRAFE_DIRECTION:m_StrafeDir[LJTOP_MAX_STRAFES], + Float:m_fStrafeGain[LJTOP_MAX_STRAFES], + Float:m_fStrafeLoss[LJTOP_MAX_STRAFES], + m_nStrafeTicks[LJTOP_MAX_STRAFES], + Float:m_fStrafeSync[LJTOP_MAX_STRAFES], } */ @@ -578,254 +594,254 @@ new Handle:g_DB = INVALID_HANDLE; DB_Connect() { - if (g_DB != INVALID_HANDLE) - { - CloseHandle(g_DB); - } - - decl String:error[255]; - g_DB = SQL_Connect("ljstats", true, error, sizeof(error)); - - if (g_DB == INVALID_HANDLE) - { - LogError(error); - CloseHandle(g_DB); - } + if (g_DB != INVALID_HANDLE) + { + CloseHandle(g_DB); + } + + decl String:error[255]; + g_DB = SQL_Connect("ljstats", true, error, sizeof(error)); + + if (g_DB == INVALID_HANDLE) + { + LogError(error); + CloseHandle(g_DB); + } } DB_CreateTables() { - new Handle:hQ = SQL_Query(g_DB, SQL_CreateLJTopTable); - - if(hQ == INVALID_HANDLE) - { - decl String:error[255]; - SQL_GetError(g_DB, error, sizeof(error)); - LogError("DB_CreateTables failed: %s", error); - return; - } - - SQL_Query(g_DB, SQL_CreateLJTopStrafesTable); - - if(hQ == INVALID_HANDLE) - { - decl String:error[255]; - SQL_GetError(g_DB, error, sizeof(error)); - LogError("DB_CreateTables failed: %s", error); - return; - } + new Handle:hQ = SQL_Query(g_DB, SQL_CreateLJTopTable); + + if(hQ == INVALID_HANDLE) + { + decl String:error[255]; + SQL_GetError(g_DB, error, sizeof(error)); + LogError("DB_CreateTables failed: %s", error); + return; + } + + SQL_Query(g_DB, SQL_CreateLJTopStrafesTable); + + if(hQ == INVALID_HANDLE) + { + decl String:error[255]; + SQL_GetError(g_DB, error, sizeof(error)); + LogError("DB_CreateTables failed: %s", error); + return; + } } DB_LoadLJTop() { - SQL_TQuery(g_DB, DB_LoadLJTop_Callback, SQL_LoadLJTop); - SQL_TQuery(g_DB, DB_LoadLJTopStrafes_Callback, SQL_LoadLJTopStrafes); + SQL_TQuery(g_DB, DB_LoadLJTop_Callback, SQL_LoadLJTop); + SQL_TQuery(g_DB, DB_LoadLJTopStrafes_Callback, SQL_LoadLJTopStrafes); } public DB_LoadLJTop_Callback(Handle:owner, Handle:hndl, String:error[], any:pack) { - if(hndl == INVALID_HANDLE) - { - LogError("DB_LoadLJTop failed: %s", error); - return; - } - - new rows = SQL_GetRowCount(hndl); - - new it[LT_END] = {0, ...}; - - for(new i = 0; i < rows; i++) - { - SQL_FetchRow(hndl); - - decl String:table[16], String:name[64], String:steamid[32]; - - SQL_FetchStringByName(hndl, "ljtable", table, sizeof(table)); - - new iTable = _:GetLJTopTable(table); - - if(it[iTable] > LJTOP_NUM_ENTRIES - 1) - { - LogError("Too many rows for table %s", table); - return; - } - - if (iTable == -1) - { - LogError("DB_LoadLJTop: Invalid table %s", table); - return; - } - - SQL_FetchStringByName(hndl, "name", name, sizeof(name)); - SQL_FetchStringByName(hndl, "steamid", steamid, sizeof(steamid)); - - strcopy(g_LJTop[iTable][it[iTable]][m_strName], 64, name); - strcopy(g_LJTop[iTable][it[iTable]][m_strSteamID], 32, steamid); - - g_LJTop[iTable][it[iTable]][m_fDistance] = SQL_FetchFloatByName(hndl, "distance"); - g_LJTop[iTable][it[iTable]][m_fPrestrafe] = SQL_FetchFloatByName(hndl, "prestrafe"); - g_LJTop[iTable][it[iTable]][m_nStrafes] = SQL_FetchIntByName(hndl, "strafes"); - g_LJTop[iTable][it[iTable]][m_fSync] = SQL_FetchFloatByName(hndl, "sync"); - g_LJTop[iTable][it[iTable]][m_fMaxSpeed] = SQL_FetchFloatByName(hndl, "maxspeed"); - g_LJTop[iTable][it[iTable]][m_nTotalTicks] = SQL_FetchIntByName(hndl, "totalticks"); - g_LJTop[iTable][it[iTable]][m_fSyncedAngle] = SQL_FetchFloatByName(hndl, "syncedangle"); - g_LJTop[iTable][it[iTable]][m_fTotalAngle] = SQL_FetchFloatByName(hndl, "totalangle"); - g_LJTop[iTable][it[iTable]][m_fBlockDistance] = SQL_FetchFloatByName(hndl, "blockdistance"); - g_LJTop[iTable][it[iTable]][m_fTrajectory] = SQL_FetchFloatByName(hndl, "trajectory"); - g_LJTop[iTable][it[iTable]][m_nTimestamp] = SQL_FetchIntByName(hndl, "timestamp"); - - it[iTable]++; - } - - LJTopCreateMainMenu(); - for(new LJTOP_TABLE:i; i < LT_END; i++) - { - LJTopCreateMenu(i); - } + if(hndl == INVALID_HANDLE) + { + LogError("DB_LoadLJTop failed: %s", error); + return; + } + + new rows = SQL_GetRowCount(hndl); + + new it[LT_END] = {0, ...}; + + for(new i = 0; i < rows; i++) + { + SQL_FetchRow(hndl); + + decl String:table[16], String:name[64], String:steamid[32]; + + SQL_FetchStringByName(hndl, "ljtable", table, sizeof(table)); + + new iTable = _:GetLJTopTable(table); + + if(it[iTable] > LJTOP_NUM_ENTRIES - 1) + { + LogError("Too many rows for table %s", table); + return; + } + + if (iTable == -1) + { + LogError("DB_LoadLJTop: Invalid table %s", table); + return; + } + + SQL_FetchStringByName(hndl, "name", name, sizeof(name)); + SQL_FetchStringByName(hndl, "steamid", steamid, sizeof(steamid)); + + strcopy(g_LJTop[iTable][it[iTable]][m_strName], 64, name); + strcopy(g_LJTop[iTable][it[iTable]][m_strSteamID], 32, steamid); + + g_LJTop[iTable][it[iTable]][m_fDistance] = SQL_FetchFloatByName(hndl, "distance"); + g_LJTop[iTable][it[iTable]][m_fPrestrafe] = SQL_FetchFloatByName(hndl, "prestrafe"); + g_LJTop[iTable][it[iTable]][m_nStrafes] = SQL_FetchIntByName(hndl, "strafes"); + g_LJTop[iTable][it[iTable]][m_fSync] = SQL_FetchFloatByName(hndl, "sync"); + g_LJTop[iTable][it[iTable]][m_fMaxSpeed] = SQL_FetchFloatByName(hndl, "maxspeed"); + g_LJTop[iTable][it[iTable]][m_nTotalTicks] = SQL_FetchIntByName(hndl, "totalticks"); + g_LJTop[iTable][it[iTable]][m_fSyncedAngle] = SQL_FetchFloatByName(hndl, "syncedangle"); + g_LJTop[iTable][it[iTable]][m_fTotalAngle] = SQL_FetchFloatByName(hndl, "totalangle"); + g_LJTop[iTable][it[iTable]][m_fBlockDistance] = SQL_FetchFloatByName(hndl, "blockdistance"); + g_LJTop[iTable][it[iTable]][m_fTrajectory] = SQL_FetchFloatByName(hndl, "trajectory"); + g_LJTop[iTable][it[iTable]][m_nTimestamp] = SQL_FetchIntByName(hndl, "timestamp"); + + it[iTable]++; + } + + LJTopCreateMainMenu(); + for(new LJTOP_TABLE:i; i < LT_END; i++) + { + LJTopCreateMenu(i); + } } public DB_LoadLJTopStrafes_Callback(Handle:owner, Handle:hndl, String:error[], any:pack) { - if(hndl == INVALID_HANDLE) - { - LogError("DB_LoadLJTopStrafes failed: %s", error); - return; - } - - new rows = SQL_GetRowCount(hndl); - - for(new i = 0; i < rows; i++) - { - SQL_FetchRow(hndl); - - decl String:table[16]; - - SQL_FetchStringByName(hndl, "ljtable", table, sizeof(table)); - - new iTable = -1; - - for(new LJTOP_TABLE:j; j < LT_END; j++) - { - if(!strcmp(g_strLJTopTags[j], table)) - { - iTable = _:j; - break; - } - } - - if (iTable == -1) - { - LogError("DB_LoadLJTop: Invalid table %s", table); - return; - } - - new iEntry = SQL_FetchIntByName(hndl, "rank"); - new iStrafe = SQL_FetchIntByName(hndl, "strafenum"); - - decl String:key[3]; - SQL_FetchStringByName(hndl, "dir", key, sizeof(key)); - - g_LJTop[iTable][iEntry][m_StrafeDir][iStrafe] = GetStrafeDir(key); - g_LJTop[iTable][iEntry][m_fStrafeGain][iStrafe] = SQL_FetchFloatByName(hndl, "gain"); - g_LJTop[iTable][iEntry][m_fStrafeLoss][iStrafe] = SQL_FetchFloatByName(hndl, "loss"); - g_LJTop[iTable][iEntry][m_nStrafeTicks][iStrafe] = SQL_FetchIntByName(hndl, "ticks"); - g_LJTop[iTable][iEntry][m_fStrafeSync][iStrafe] = SQL_FetchFloatByName(hndl, "sync"); - } + if(hndl == INVALID_HANDLE) + { + LogError("DB_LoadLJTopStrafes failed: %s", error); + return; + } + + new rows = SQL_GetRowCount(hndl); + + for(new i = 0; i < rows; i++) + { + SQL_FetchRow(hndl); + + decl String:table[16]; + + SQL_FetchStringByName(hndl, "ljtable", table, sizeof(table)); + + new iTable = -1; + + for(new LJTOP_TABLE:j; j < LT_END; j++) + { + if(!strcmp(g_strLJTopTags[j], table)) + { + iTable = _:j; + break; + } + } + + if (iTable == -1) + { + LogError("DB_LoadLJTop: Invalid table %s", table); + return; + } + + new iEntry = SQL_FetchIntByName(hndl, "rank"); + new iStrafe = SQL_FetchIntByName(hndl, "strafenum"); + + decl String:key[3]; + SQL_FetchStringByName(hndl, "dir", key, sizeof(key)); + + g_LJTop[iTable][iEntry][m_StrafeDir][iStrafe] = GetStrafeDir(key); + g_LJTop[iTable][iEntry][m_fStrafeGain][iStrafe] = SQL_FetchFloatByName(hndl, "gain"); + g_LJTop[iTable][iEntry][m_fStrafeLoss][iStrafe] = SQL_FetchFloatByName(hndl, "loss"); + g_LJTop[iTable][iEntry][m_nStrafeTicks][iStrafe] = SQL_FetchIntByName(hndl, "ticks"); + g_LJTop[iTable][iEntry][m_fStrafeSync][iStrafe] = SQL_FetchFloatByName(hndl, "sync"); + } } DB_SaveLJTop() { - SQL_TQuery(g_DB, DB_EmptyCallback, SQL_DeleteLJTop); - SQL_TQuery(g_DB, DB_EmptyCallback, SQL_DeleteLJTopStrafes); - - new Handle:hTxn = SQL_CreateTransaction(); - - decl String:sQuery[1024]; - - for(new LJTOP_TABLE:i; i < LT_END; i++) - { - for (new j = 0; j < LJTOP_NUM_ENTRIES; j++) - { - if (g_LJTop[i][j][m_strSteamID][0] == 0) - continue; - - decl String:EscapedName[512]; - if (!SQL_EscapeString(g_DB, g_LJTop[i][j][m_strName], EscapedName, sizeof(EscapedName))) - { - LogError("Failed to escape %s's name when writing ljs to database! Writing name without quotes instead", g_LJTop[i][j][m_strName]); - strcopy(EscapedName, sizeof(EscapedName), g_LJTop[i][j][m_strName]); - new index = 0; - while ((index = StrContains(EscapedName, "'")) != -1) - { - strcopy(EscapedName[index], sizeof(EscapedName) - index, EscapedName[index + 1]); - } - } - FormatEx(sQuery, sizeof(sQuery), "INSERT INTO ljtop (ljtable, name, steamid, distance, prestrafe, strafes, sync, maxspeed, totalticks, syncedangle, totalangle, heightdelta, blockdistance, trajectory, timestamp) VALUES ('%s', '%s', '%s', %f, %f, %d, %f, %f, %d, %f, %f, %f, %f, %f, %d)", - g_strLJTopTags[i], - EscapedName, - g_LJTop[i][j][m_strSteamID], - g_LJTop[i][j][m_fDistance], - g_LJTop[i][j][m_fPrestrafe], - g_LJTop[i][j][m_nStrafes], - g_LJTop[i][j][m_fSync], - g_LJTop[i][j][m_fMaxSpeed], - g_LJTop[i][j][m_nTotalTicks], - g_LJTop[i][j][m_fSyncedAngle], - g_LJTop[i][j][m_fTotalAngle], - g_LJTop[i][j][m_fHeightDelta], - g_LJTop[i][j][m_fBlockDistance], - g_LJTop[i][j][m_fTrajectory], - g_LJTop[i][j][m_nTimestamp]); - - SQL_AddQuery(hTxn, sQuery); - - for (new k = 0; k < g_LJTop[i][j][m_nStrafes]; k++) - { - decl String:key[3]; - GetStrafeKey(key, g_LJTop[i][j][m_StrafeDir][k]); - - FormatEx(sQuery, sizeof(sQuery), "INSERT INTO ljtopstrafes (ljtable, rank, strafenum, dir, gain, loss, ticks, sync) VALUES ('%s', %d, %d, '%s', %f, %f, %d, %f)", - g_strLJTopTags[i], - j, - k, - key, - g_LJTop[i][j][m_fStrafeGain][k], - g_LJTop[i][j][m_fStrafeLoss][k], - g_LJTop[i][j][m_nStrafeTicks][k], - g_LJTop[i][j][m_fStrafeSync][k]); - - SQL_AddQuery(hTxn, sQuery); - } - } - } - - SQL_ExecuteTransaction(g_DB, hTxn, SQLTxnSuccess:-1, DB_TxnFailure); + SQL_TQuery(g_DB, DB_EmptyCallback, SQL_DeleteLJTop); + SQL_TQuery(g_DB, DB_EmptyCallback, SQL_DeleteLJTopStrafes); + + new Handle:hTxn = SQL_CreateTransaction(); + + decl String:sQuery[1024]; + + for(new LJTOP_TABLE:i; i < LT_END; i++) + { + for (new j = 0; j < LJTOP_NUM_ENTRIES; j++) + { + if (g_LJTop[i][j][m_strSteamID][0] == 0) + continue; + + decl String:EscapedName[512]; + if (!SQL_EscapeString(g_DB, g_LJTop[i][j][m_strName], EscapedName, sizeof(EscapedName))) + { + LogError("Failed to escape %s's name when writing ljs to database! Writing name without quotes instead", g_LJTop[i][j][m_strName]); + strcopy(EscapedName, sizeof(EscapedName), g_LJTop[i][j][m_strName]); + new index = 0; + while ((index = StrContains(EscapedName, "'")) != -1) + { + strcopy(EscapedName[index], sizeof(EscapedName) - index, EscapedName[index + 1]); + } + } + FormatEx(sQuery, sizeof(sQuery), "INSERT INTO ljtop (ljtable, name, steamid, distance, prestrafe, strafes, sync, maxspeed, totalticks, syncedangle, totalangle, heightdelta, blockdistance, trajectory, timestamp) VALUES ('%s', '%s', '%s', %f, %f, %d, %f, %f, %d, %f, %f, %f, %f, %f, %d)", + g_strLJTopTags[i], + EscapedName, + g_LJTop[i][j][m_strSteamID], + g_LJTop[i][j][m_fDistance], + g_LJTop[i][j][m_fPrestrafe], + g_LJTop[i][j][m_nStrafes], + g_LJTop[i][j][m_fSync], + g_LJTop[i][j][m_fMaxSpeed], + g_LJTop[i][j][m_nTotalTicks], + g_LJTop[i][j][m_fSyncedAngle], + g_LJTop[i][j][m_fTotalAngle], + g_LJTop[i][j][m_fHeightDelta], + g_LJTop[i][j][m_fBlockDistance], + g_LJTop[i][j][m_fTrajectory], + g_LJTop[i][j][m_nTimestamp]); + + SQL_AddQuery(hTxn, sQuery); + + for (new k = 0; k < g_LJTop[i][j][m_nStrafes]; k++) + { + decl String:key[3]; + GetStrafeKey(key, g_LJTop[i][j][m_StrafeDir][k]); + + FormatEx(sQuery, sizeof(sQuery), "INSERT INTO ljtopstrafes (ljtable, rank, strafenum, dir, gain, loss, ticks, sync) VALUES ('%s', %d, %d, '%s', %f, %f, %d, %f)", + g_strLJTopTags[i], + j, + k, + key, + g_LJTop[i][j][m_fStrafeGain][k], + g_LJTop[i][j][m_fStrafeLoss][k], + g_LJTop[i][j][m_nStrafeTicks][k], + g_LJTop[i][j][m_fStrafeSync][k]); + + SQL_AddQuery(hTxn, sQuery); + } + } + } + + SQL_ExecuteTransaction(g_DB, hTxn, SQLTxnSuccess:-1, DB_TxnFailure); } public DB_EmptyCallback(Handle:owner, Handle:hndl, String:error[], any:pack) { - if(hndl == INVALID_HANDLE) - { - LogError(error); - } + if(hndl == INVALID_HANDLE) + { + LogError(error); + } } public DB_TxnFailure(Handle:db, any:data, numQueries, const String:error[], failIndex, any:queryData[]) { - LogError("DB_SaveLJTop: Transaction failed: %s", error); + LogError("DB_SaveLJTop: Transaction failed: %s", error); } LJTOP_TABLE:GetLJTopTable(const String:table[]) { - for(new LJTOP_TABLE:j; j < LT_END; j++) - { - if(!strcmp(g_strLJTopTags[j], table)) - { - return j; - } - } - - return LJTOP_TABLE:-1; + for(new LJTOP_TABLE:j; j < LT_END; j++) + { + if(!strcmp(g_strLJTopTags[j], table)) + { + return j; + } + } + + return LJTOP_TABLE:-1; } #define ON_CVAR_CHANGE_BOOL(%0,%1) else if(hCvar == %0) { %1 = bool:StringToInt(strNewValue); } @@ -834,88 +850,88 @@ LJTOP_TABLE:GetLJTopTable(const String:table[]) public OnCvarChange(Handle:hCvar, const String:strOldValue[], const String:strNewValue[]) { - if(hCvar == g_hCvarColorMin) - { - new nColor = StringToInt(strNewValue, 16); - g_ColorMin[0] = (nColor & 0xFF0000) >> 16; - g_ColorMin[1] = (nColor & 0xFF00) >> 8; - g_ColorMin[2] = nColor & 0xFF; - } - else if(hCvar == g_hCvarColorMax) - { - new nColor = StringToInt(strNewValue, 16); - g_ColorMax[0] = (nColor & 0xFF0000) >> 16; - g_ColorMax[1] = (nColor & 0xFF00) >> 8; - g_ColorMax[2] = nColor & 0xFF; - } + if(hCvar == g_hCvarColorMin) + { + new nColor = StringToInt(strNewValue, 16); + g_ColorMin[0] = (nColor & 0xFF0000) >> 16; + g_ColorMin[1] = (nColor & 0xFF00) >> 8; + g_ColorMin[2] = nColor & 0xFF; + } + else if(hCvar == g_hCvarColorMax) + { + new nColor = StringToInt(strNewValue, 16); + g_ColorMax[0] = (nColor & 0xFF0000) >> 16; + g_ColorMax[1] = (nColor & 0xFF00) >> 8; + g_ColorMax[2] = nColor & 0xFF; + } else if(hCvar == g_hCvarColorTop) { new nColor = StringToInt(strNewValue, 16); - g_ColorTop[0] = (nColor & 0xFF0000) >> 16; - g_ColorTop[1] = (nColor & 0xFF00) >> 8; - g_ColorTop[2] = nColor & 0xFF; - } - ON_CVAR_CHANGE_FLOAT(g_hCvarLJMin, g_fLJMin) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJMax, g_fLJMax) - ON_CVAR_CHANGE_FLOAT(g_hCvarNonLJMax, g_fNonLJMax) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJMaxPrestrafe, g_fLJMaxPrestrafe) - ON_CVAR_CHANGE_BOOL(g_hCvarLJScoutStats, g_bLJScoutStats) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJNoDuckMin, g_fLJNoDuckMin) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJClientMin, g_fLJClientMin) - ON_CVAR_CHANGE_FLOAT(g_hCvarWJMin, g_fWJMin) - ON_CVAR_CHANGE_FLOAT(g_hCvarWJDropMax, g_fWJDropMax) - ON_CVAR_CHANGE_FLOAT(g_hCvarBJMin, g_fBJMin) - ON_CVAR_CHANGE_FLOAT(g_hCvarBJMax, g_fBJMax) - ON_CVAR_CHANGE_FLOAT(g_hCvarLAJMin, g_fLAJMin) - ON_CVAR_CHANGE_INT(g_hCvarVerbosity, g_nVerbosity) - ON_CVAR_CHANGE_BOOL(g_hCvarPrintFailedBlockStats, g_bPrintFailedBlockStats) - ON_CVAR_CHANGE_BOOL(g_hCvarShowBhopStats, g_bShowBhopStats) - ON_CVAR_CHANGE_BOOL(g_hCvarOutput16Style, g_bOutput16Style) - ON_CVAR_CHANGE_BOOL(g_hCvarLJTopAllowEasyBJ, g_bLJTopAllowEasyBJ) - ON_CVAR_CHANGE_BOOL(g_hCvarLJSound, g_bLJSound) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound1, g_fLJSound[0]) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound2, g_fLJSound[1]) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound3, g_fLJSound[2]) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound4, g_fLJSound[3]) - ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound5, g_fLJSound[4]) + g_ColorTop[0] = (nColor & 0xFF0000) >> 16; + g_ColorTop[1] = (nColor & 0xFF00) >> 8; + g_ColorTop[2] = nColor & 0xFF; + } + ON_CVAR_CHANGE_FLOAT(g_hCvarLJMin, g_fLJMin) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJMax, g_fLJMax) + ON_CVAR_CHANGE_FLOAT(g_hCvarNonLJMax, g_fNonLJMax) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJMaxPrestrafe, g_fLJMaxPrestrafe) + ON_CVAR_CHANGE_BOOL(g_hCvarLJScoutStats, g_bLJScoutStats) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJNoDuckMin, g_fLJNoDuckMin) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJClientMin, g_fLJClientMin) + ON_CVAR_CHANGE_FLOAT(g_hCvarWJMin, g_fWJMin) + ON_CVAR_CHANGE_FLOAT(g_hCvarWJDropMax, g_fWJDropMax) + ON_CVAR_CHANGE_FLOAT(g_hCvarBJMin, g_fBJMin) + ON_CVAR_CHANGE_FLOAT(g_hCvarBJMax, g_fBJMax) + ON_CVAR_CHANGE_FLOAT(g_hCvarLAJMin, g_fLAJMin) + ON_CVAR_CHANGE_INT(g_hCvarVerbosity, g_nVerbosity) + ON_CVAR_CHANGE_BOOL(g_hCvarPrintFailedBlockStats, g_bPrintFailedBlockStats) + ON_CVAR_CHANGE_BOOL(g_hCvarShowBhopStats, g_bShowBhopStats) + ON_CVAR_CHANGE_BOOL(g_hCvarOutput16Style, g_bOutput16Style) + ON_CVAR_CHANGE_BOOL(g_hCvarLJTopAllowEasyBJ, g_bLJTopAllowEasyBJ) + ON_CVAR_CHANGE_BOOL(g_hCvarLJSound, g_bLJSound) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound1, g_fLJSound[0]) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound2, g_fLJSound[1]) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound3, g_fLJSound[2]) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound4, g_fLJSound[3]) + ON_CVAR_CHANGE_FLOAT(g_hCvarLJSound5, g_fLJSound[4]) ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound1, g_fBJSound[0]) - ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound2, g_fBJSound[1]) - ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound3, g_fBJSound[2]) - ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound4, g_fBJSound[3]) - ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound5, g_fBJSound[4]) - ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[0], g_bLJSoundToAll[0]) - ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[1], g_bLJSoundToAll[1]) - ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[2], g_bLJSoundToAll[2]) - ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[3], g_bLJSoundToAll[3]) - ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[4], g_bLJSoundToAll[4]) - else if(hCvar == g_hCvarLJSound1File) - { - strcopy(g_strLJSoundFile[0], sizeof(g_strLJSoundFile[]), strNewValue); - PrecacheSound(g_strLJSoundFile[0]); - } - else if(hCvar == g_hCvarLJSound2File) - { - strcopy(g_strLJSoundFile[1], sizeof(g_strLJSoundFile[]), strNewValue); - PrecacheSound(g_strLJSoundFile[1]); - } - else if(hCvar == g_hCvarLJSound3File) - { - strcopy(g_strLJSoundFile[2], sizeof(g_strLJSoundFile[]), strNewValue); - PrecacheSound(g_strLJSoundFile[2]); - } - else if(hCvar == g_hCvarLJSound4File) - { - strcopy(g_strLJSoundFile[3], sizeof(g_strLJSoundFile[]), strNewValue); - PrecacheSound(g_strLJSoundFile[3]); - } - else if(hCvar == g_hCvarLJSound5File) - { - strcopy(g_strLJSoundFile[4], sizeof(g_strLJSoundFile[]), strNewValue); - PrecacheSound(g_strLJSoundFile[4]); - } - - ON_CVAR_CHANGE_FLOAT(g_hCvarMaxspeed, g_fMaxspeed) - ON_CVAR_CHANGE_BOOL(g_hCvarEnableBunnyHopping, g_bEnableBunnyHopping) + ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound2, g_fBJSound[1]) + ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound3, g_fBJSound[2]) + ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound4, g_fBJSound[3]) + ON_CVAR_CHANGE_FLOAT(g_hCvarBJSound5, g_fBJSound[4]) + ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[0], g_bLJSoundToAll[0]) + ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[1], g_bLJSoundToAll[1]) + ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[2], g_bLJSoundToAll[2]) + ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[3], g_bLJSoundToAll[3]) + ON_CVAR_CHANGE_BOOL(g_hCvarLJSoundToAll[4], g_bLJSoundToAll[4]) + else if(hCvar == g_hCvarLJSound1File) + { + strcopy(g_strLJSoundFile[0], sizeof(g_strLJSoundFile[]), strNewValue); + PrecacheSound(g_strLJSoundFile[0]); + } + else if(hCvar == g_hCvarLJSound2File) + { + strcopy(g_strLJSoundFile[1], sizeof(g_strLJSoundFile[]), strNewValue); + PrecacheSound(g_strLJSoundFile[1]); + } + else if(hCvar == g_hCvarLJSound3File) + { + strcopy(g_strLJSoundFile[2], sizeof(g_strLJSoundFile[]), strNewValue); + PrecacheSound(g_strLJSoundFile[2]); + } + else if(hCvar == g_hCvarLJSound4File) + { + strcopy(g_strLJSoundFile[3], sizeof(g_strLJSoundFile[]), strNewValue); + PrecacheSound(g_strLJSoundFile[3]); + } + else if(hCvar == g_hCvarLJSound5File) + { + strcopy(g_strLJSoundFile[4], sizeof(g_strLJSoundFile[]), strNewValue); + PrecacheSound(g_strLJSoundFile[4]); + } + + ON_CVAR_CHANGE_FLOAT(g_hCvarMaxspeed, g_fMaxspeed) + ON_CVAR_CHANGE_BOOL(g_hCvarEnableBunnyHopping, g_bEnableBunnyHopping) } #undef ON_CVAR_CHANGE_BOOL @@ -924,374 +940,464 @@ public OnCvarChange(Handle:hCvar, const String:strOldValue[], const String:strNe public OnMapStart() { - g_BeamModel = PrecacheModel("materials/sprites/bluelaser1.vmt"); - - for(new i; i < LJSOUND_NUM; i++) - { - if(g_strLJSoundFile[i][0] != 0) - { - PrecacheSound(g_strLJSoundFile[i]); - } - } + if( nh_warmup == INVALID_HANDLE ) { + nh_warmup = FindConVar( "nh_warmup" ); + } + + g_BeamModel = PrecacheModel("materials/sprites/bluelaser1.vmt"); + + for(new i; i < LJSOUND_NUM; i++) + { + if(g_strLJSoundFile[i][0] != 0) + { + PrecacheSound(g_strLJSoundFile[i]); + } + } } public OnClientPutInServer(client) { - /* - #if defined LJSERV - g_PlayerStates[client][bLJEnabled] = true; - #else - g_PlayerStates[client][bLJEnabled] = true; - #endif - g_PlayerStates[client][bBeam] = false; - g_PlayerStates[client][bSound] = true; - //#if defined LJSERV - //g_PlayerStates[client][bBlockMode] = true; - //#else - g_PlayerStates[client][bBlockMode] = false; - //#endif - g_PlayerStates[client][nVerbosity] = g_nVerbosity; - */ - - g_PlayerStates[client][bHidePanel] = true; - g_PlayerStates[client][bLJEnabled] = true; - g_PlayerStates[client][bOnGround] = true; - g_PlayerStates[client][fBlockDistance] = -1.0; - g_PlayerStates[client][IllegalJumpFlags] = IJF_NONE; - g_PlayerStates[client][nSpectators] = 0; - g_PlayerStates[client][nSpectatorTarget] = -1; + /* + #if defined LJSERV + g_PlayerStates[client][bLJEnabled] = true; + #else + g_PlayerStates[client][bLJEnabled] = true; + #endif + g_PlayerStates[client][bBeam] = false; + g_PlayerStates[client][bSound] = true; + //#if defined LJSERV + //g_PlayerStates[client][bBlockMode] = true; + //#else + g_PlayerStates[client][bBlockMode] = false; + //#endif + g_PlayerStates[client][nVerbosity] = g_nVerbosity; + */ + + g_PlayerStates[client][bHidePanel] = true; + g_PlayerStates[client][bLJEnabled] = true; + g_PlayerStates[client][bOnGround] = true; + g_PlayerStates[client][fBlockDistance] = -1.0; + g_PlayerStates[client][IllegalJumpFlags] = IJF_NONE; + g_PlayerStates[client][nSpectators] = 0; + g_PlayerStates[client][nSpectatorTarget] = -1; g_PlayerStates[client][vTPOrigin][0] = 0.0; g_PlayerStates[client][vTPOrigin][1] = 0.0; g_PlayerStates[client][vTPOrigin][2] = 0.0; - /* - #if defined LJSERV - g_PlayerStates[client][bShowPrestrafeHint] = true; - #endif - */ + /* + #if defined LJSERV + g_PlayerStates[client][bShowPrestrafeHint] = true; + #endif + */ g_PlayerStates[client][bShowAllJumps] = true; - SDKHook(client, SDKHook_Touch, hkTouch); + SDKHook(client, SDKHook_Touch, hkTouch); } public Action:hkTouch(client, other) { - new Float:vOrigin[3]; - GetClientAbsOrigin(client, vOrigin); - - if(other == 0 && !(GetEntityFlags(client) & FL_ONGROUND) && - !(g_PlayerStates[client][bBlockMode] && g_PlayerStates[client][bFailedBlock] && - vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] < HEIGHT_DELTA_MIN(JT_LONGJUMP))) - { - g_PlayerStates[client][IllegalJumpFlags] |= IJF_WORLD; - - #if defined DEBUG - PrintToChat(client, "%d, %d, %f, %d, %d", g_PlayerStates[client][bBlockMode], g_PlayerStates[client][bFailedBlock], vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2], - vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] < HEIGHT_DELTA_MIN(JT_LONGJUMP), GetGameTickCount()); - #endif - } - else - { - decl String:strClassname[64]; - GetEdictClassname(other, strClassname, sizeof(strClassname)); - - if(!strcmp(strClassname, "trigger_push")) - { - g_PlayerStates[client][IllegalJumpFlags] |= IJF_BOOSTER; - - #if defined DEBUG - PrintToChat(client, "booster"); - #endif - } - } + new Float:vOrigin[3]; + GetClientAbsOrigin(client, vOrigin); + + if(other == 0 && !(GetEntityFlags(client) & FL_ONGROUND) && + !(g_PlayerStates[client][bBlockMode] && g_PlayerStates[client][bFailedBlock] && + vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] < HEIGHT_DELTA_MIN(JT_LONGJUMP))) + { + g_PlayerStates[client][IllegalJumpFlags] |= IJF_WORLD; + + #if defined DEBUG + PrintToChat(client, "%d, %d, %f, %d, %d", g_PlayerStates[client][bBlockMode], g_PlayerStates[client][bFailedBlock], vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2], + vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] < HEIGHT_DELTA_MIN(JT_LONGJUMP), GetGameTickCount()); + #endif + } + else + { + decl String:strClassname[64]; + GetEdictClassname(other, strClassname, sizeof(strClassname)); + + if(!strcmp(strClassname, "trigger_push")) + { + g_PlayerStates[client][IllegalJumpFlags] |= IJF_BOOSTER; + + #if defined DEBUG + PrintToChat(client, "booster"); + #endif + } + } } public Action:Command_Delete(client, args) { - SQL_Query(g_DB, "drop table ljtop"); - SQL_Query(g_DB, "drop table ljtopstrafes"); - - return Plugin_Handled; + SQL_Query(g_DB, "drop table ljtop"); + SQL_Query(g_DB, "drop table ljtopstrafes"); + + return Plugin_Handled; } public Action:Command_LJHelp(client, args) { - new Handle:hHelpPanel = CreatePanel(); - - SetPanelTitle(hHelpPanel, "!lj"); - DrawPanelText(hHelpPanel, "!ljsettings, !ljs"); - DrawPanelText(hHelpPanel, "!ljpanel"); - DrawPanelText(hHelpPanel, "!ljbeam"); - DrawPanelText(hHelpPanel, "!ljblock"); - DrawPanelText(hHelpPanel, "!ljsound"); - DrawPanelText(hHelpPanel, "!gap"); - DrawPanelText(hHelpPanel, "!blockgap"); - DrawPanelText(hHelpPanel, "!ljtop"); - - SendPanelToClient(hHelpPanel, client, EmptyPanelHandler, 10); - - CloseHandle(hHelpPanel); - - return Plugin_Handled; + new Handle:hHelpPanel = CreatePanel(); + + SetPanelTitle(hHelpPanel, "!lj"); + DrawPanelText(hHelpPanel, "!ljsettings, !ljs"); + DrawPanelText(hHelpPanel, "!ljpanel"); + DrawPanelText(hHelpPanel, "!ljbeam"); + DrawPanelText(hHelpPanel, "!ljblock"); + DrawPanelText(hHelpPanel, "!ljsound"); + DrawPanelText(hHelpPanel, "!gap"); + DrawPanelText(hHelpPanel, "!blockgap"); + DrawPanelText(hHelpPanel, "!ljtop"); + DrawPanelText(hHelpPanel, "!strafetrainer"); + + SendPanelToClient(hHelpPanel, client, EmptyPanelHandler, 10); + + CloseHandle(hHelpPanel); + + return Plugin_Handled; } + public Action:Command_LJ(client, args) { - g_PlayerStates[client][bLJEnabled] = !g_PlayerStates[client][bLJEnabled]; - SetCookie(client, g_hCookieLJEnabled, g_PlayerStates[client][bLJEnabled]); - PrintToChat(client, "Longjump stats %s", g_PlayerStates[client][bLJEnabled] ? "ENABLED" : "DISABLED"); - - return Plugin_Handled; + g_PlayerStates[client][bLJEnabled] = !g_PlayerStates[client][bLJEnabled]; + SetCookie(client, g_hCookieLJEnabled, g_PlayerStates[client][bLJEnabled]); + PrintToChat(client, "Longjump stats %s", g_PlayerStates[client][bLJEnabled] ? "ENABLED" : "DISABLED"); + + return Plugin_Handled; } public Action:Command_LJSettings(client, args) { - ShowSettingsPanel(client); - - return Plugin_Handled; + ShowSettingsPanel(client); + + return Plugin_Handled; +} + +public SpeedometerMenuHandler( Handle:hMenu, MenuAction:ma, client, nItem ) { + switch( ma ) { + case MenuAction_Select: { + switch( nItem ) { + case 0: { + g_PlayerStates[client][nSpeedometer] = nItem; + PrintToChat( client, "\x04Speedometer has been disabled." ); + } + case 1: { + g_PlayerStates[client][nSpeedometer] = nItem; + PrintToChat( client, "\x04Speedometer will be displayed at the top." ); + } + case 2: { + g_PlayerStates[client][nSpeedometer] = nItem; + PrintToChat( client, "\x04Speedometer will be displayed at the bottom." ); + } + } + + + SetCookie(client, g_hCookieSpeedometer, g_PlayerStates[client][nSpeedometer]); + } + case MenuAction_Cancel: { + CloseHandle( hMenu ); + } + } +} + + +public Action:Command_Speedometer(client, args) +{ + new Handle:hPanel = CreateMenu(SpeedometerMenuHandler); + + AddMenuItem( hPanel, "nospd", "no speedometer" ); + AddMenuItem( hPanel, "top", "show at the top" ); + AddMenuItem( hPanel, "bot", "show at the bottom" ); + DisplayMenu( hPanel, client, MENU_TIME_FOREVER ); } public OnClientCookiesCached(client) { - decl String:strCookie[64]; - - GetClientCookie(client, g_hCookieDefaultsSet, strCookie, sizeof(strCookie)); - - if(StringToInt(strCookie) == 0) - { - SetCookie(client, g_hCookieLJEnabled, true); - SetCookie(client, g_hCookieSound, g_bLJSound); - - SetCookie(client, g_hCookieShowBhopStats, g_bShowBhopStats); - SetCookie(client, g_hCookieHidePanel, true); - - - SetCookie(client, g_hCookieVerbosity, g_nVerbosity); - - SetCookie(client, g_hCookieShowAllJumps, true); - - #if defined LJSERV - SetCookie(client, g_hCookieShowPrestrafeHint, true); - #endif - - SetCookie(client, g_hCookieDefaultsSet, true); - } - - - GetClientCookie(client, g_hCookieLJEnabled, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bLJEnabled] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookieBlockMode, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bBlockMode] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookieBeam, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bBeam] = bool:StringToInt(strCookie); + decl String:strCookie[64]; + + GetClientCookie(client, g_hCookieDefaultsSet, strCookie, sizeof(strCookie)); + + if(StringToInt(strCookie) == 0) + { + SetCookie(client, g_hCookieLJEnabled, true); + SetCookie(client, g_hCookieSound, g_bLJSound); + + SetCookie(client, g_hCookieShowBhopStats, g_bShowBhopStats); + SetCookie(client, g_hCookieHidePanel, true); + + + SetCookie(client, g_hCookieVerbosity, g_nVerbosity); + + SetCookie(client, g_hCookieShowAllJumps, true); + + #if defined LJSERV + SetCookie(client, g_hCookieShowPrestrafeHint, true); + #endif + + SetCookie(client, g_hCookieDefaultsSet, true); + } + + + GetClientCookie(client, g_hCookieLJEnabled, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bLJEnabled] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieBlockMode, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bBlockMode] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieStrafeTrainer, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bStrafeTrainer] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieBeam, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bBeam] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieSpeedometer, strCookie, sizeof(strCookie)); + g_PlayerStates[client][nSpeedometer] = StringToInt(strCookie); GetClientCookie(client, g_hCookieDeadstrafe, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bDeadstrafe] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookieSound, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bSound] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookieHidePanel, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bHidePanel] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookieHideBhopPanel, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bHideBhopPanel] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookieShowBhopStats, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bShowBhopStats] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookieVerbosity, strCookie, sizeof(strCookie)); - g_PlayerStates[client][nVerbosity] = StringToInt(strCookie); - - GetClientCookie(client, g_hCookieShowAllJumps, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bShowAllJumps] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookieShowPrestrafeHint, strCookie, sizeof(strCookie)); - g_PlayerStates[client][bShowPrestrafeHint] = bool:StringToInt(strCookie); - - GetClientCookie(client, g_hCookiePersonalBest, strCookie, sizeof(strCookie)); - g_PlayerStates[client][fPersonalBest] = StringToFloat(strCookie); + g_PlayerStates[client][bDeadstrafe] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieSound, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bSound] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieHidePanel, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bHidePanel] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieHideBhopPanel, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bHideBhopPanel] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieShowBhopStats, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bShowBhopStats] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieVerbosity, strCookie, sizeof(strCookie)); + g_PlayerStates[client][nVerbosity] = StringToInt(strCookie); + + GetClientCookie(client, g_hCookieShowAllJumps, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bShowAllJumps] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookieShowPrestrafeHint, strCookie, sizeof(strCookie)); + g_PlayerStates[client][bShowPrestrafeHint] = bool:StringToInt(strCookie); + + GetClientCookie(client, g_hCookiePersonalBest, strCookie, sizeof(strCookie)); + g_PlayerStates[client][fPersonalBest] = StringToFloat(strCookie); } ShowSettingsPanel(client) { - new Handle:hMenu = CreateMenu(SettingsMenuHandler); - - decl String:buf[64]; + new Handle:hMenu = CreateMenu(SettingsMenuHandler); + + decl String:buf[64]; - AddMenuItem(hMenu, "tpmenu", "Show TP menu"); + AddMenuItem(hMenu, "tpmenu", "Show TP menu"); - Format(buf, sizeof(buf), "LJ stats: %s", g_PlayerStates[client][bLJEnabled] ? "On" : "Off"); - AddMenuItem(hMenu, "ljenabled", buf); - - Format(buf, sizeof(buf), "Beam: %s", g_PlayerStates[client][bBeam] ? "On" : "Off"); - AddMenuItem(hMenu, "beam", buf); + Format(buf, sizeof(buf), "LJ stats: %s", g_PlayerStates[client][bLJEnabled] ? "On" : "Off"); + AddMenuItem(hMenu, "ljenabled", buf); + + Format(buf, sizeof(buf), "Beam: %s", g_PlayerStates[client][bBeam] ? "On" : "Off"); + AddMenuItem(hMenu, "beam", buf); Format(buf, sizeof(buf), "Deadstrafe (beam): %s", g_PlayerStates[client][bDeadstrafe] ? "On" : "Off"); - AddMenuItem(hMenu, "deadstrafe", buf); - - Format(buf, sizeof(buf), "Sounds: %s", g_PlayerStates[client][bSound] ? "On" : "Off"); - AddMenuItem(hMenu, "sound", buf); - - Format(buf, sizeof(buf), "Panel: %s", !g_PlayerStates[client][bHidePanel] ? "On" : "Off"); - AddMenuItem(hMenu, "panel", buf); - - Format(buf, sizeof(buf), "Bhop panel: %s", !g_PlayerStates[client][bHideBhopPanel] ? "On" : "Off"); - AddMenuItem(hMenu, "bhoppanel", buf); - - Format(buf, sizeof(buf), "Bhop stats: %s", g_PlayerStates[client][bShowBhopStats] ? "On" : "Off"); - AddMenuItem(hMenu, "bhopstats", buf); - - Format(buf, sizeof(buf), "Verbosity: %d", g_PlayerStates[client][nVerbosity]); - AddMenuItem(hMenu, "verbosity", buf); - - Format(buf, sizeof(buf), "Show all jumps: %s", g_PlayerStates[client][bShowAllJumps] ? "On" : "Off"); - AddMenuItem(hMenu, "showalljumps", buf); - - Format(buf, sizeof(buf), "Prestrafe hint: %s", g_PlayerStates[client][bShowPrestrafeHint] ? "On" : "Off"); - AddMenuItem(hMenu, "prestrafehint", buf); - - DisplayMenu(hMenu, client, 0); + AddMenuItem(hMenu, "deadstrafe", buf); + + if( g_PlayerStates[client][nSpeedometer] == 0 ) { + Format(buf, sizeof(buf), "Speed: off" ); + } + else if( g_PlayerStates[client][nSpeedometer] == 1 ) { + Format(buf, sizeof(buf), "Speed: top" ); + } + else if( g_PlayerStates[client][nSpeedometer] == 2 ) { + Format(buf, sizeof(buf), "Speed: bottom" ); + } + + AddMenuItem(hMenu, "speed", buf); + + Format(buf, sizeof(buf), "Sounds: %s", g_PlayerStates[client][bSound] ? "On" : "Off"); + AddMenuItem(hMenu, "sound", buf); + + Format(buf, sizeof(buf), "Panel: %s", !g_PlayerStates[client][bHidePanel] ? "On" : "Off"); + AddMenuItem(hMenu, "panel", buf); + + Format(buf, sizeof(buf), "Bhop panel: %s", !g_PlayerStates[client][bHideBhopPanel] ? "On" : "Off"); + AddMenuItem(hMenu, "bhoppanel", buf); + + Format(buf, sizeof(buf), "Bhop stats: %s", g_PlayerStates[client][bShowBhopStats] ? "On" : "Off"); + AddMenuItem(hMenu, "bhopstats", buf); + + Format(buf, sizeof(buf), "Verbosity: %d", g_PlayerStates[client][nVerbosity]); + AddMenuItem(hMenu, "verbosity", buf); + + Format(buf, sizeof(buf), "Show all jumps: %s", g_PlayerStates[client][bShowAllJumps] ? "On" : "Off"); + AddMenuItem(hMenu, "showalljumps", buf); + + Format(buf, sizeof(buf), "Prestrafe hint: %s", g_PlayerStates[client][bShowPrestrafeHint] ? "On" : "Off"); + AddMenuItem(hMenu, "prestrafehint", buf); + + Format(buf, sizeof(buf), "Strafe trainer: %s", g_PlayerStates[client][bStrafeTrainer] ? "On" : "Off"); + AddMenuItem(hMenu, "strafetrainer", buf); + + DisplayMenu(hMenu, client, 0); } public SettingsMenuHandler(Handle:hMenu, MenuAction:ma, client, nItem) { - switch(ma) - { - case MenuAction_Select: - { - decl String:strInfo[16]; - - if(!GetMenuItem(hMenu, nItem, strInfo, sizeof(strInfo))) - { - LogError("rip menu..."); - return; - } - + switch(ma) + { + case MenuAction_Select: + { + decl String:strInfo[16]; + + if(!GetMenuItem(hMenu, nItem, strInfo, sizeof(strInfo))) + { + LogError("rip menu..."); + return; + } + if(!strcmp(strInfo, "tpmenu")) { Command_CheckpointPanel(client, 0); } - else if(!strcmp(strInfo, "ljenabled")) - { - g_PlayerStates[client][bLJEnabled] = !g_PlayerStates[client][bLJEnabled]; - SetCookie(client, g_hCookieLJEnabled, g_PlayerStates[client][bLJEnabled]); - PrintToChat(client, "LJ stats are now %s", g_PlayerStates[client][bLJEnabled] ? "on" : "off"); - ShowSettingsPanel(client); - } - else if(!strcmp(strInfo, "beam")) - { - g_PlayerStates[client][bBeam] = !g_PlayerStates[client][bBeam]; - SetCookie(client, g_hCookieBeam, g_PlayerStates[client][bBeam]); - PrintToChat(client, "Beam is now %s", g_PlayerStates[client][bBeam] ? "on" : "off"); - ShowSettingsPanel(client); - } + else if(!strcmp(strInfo, "ljenabled")) + { + g_PlayerStates[client][bLJEnabled] = !g_PlayerStates[client][bLJEnabled]; + SetCookie(client, g_hCookieLJEnabled, g_PlayerStates[client][bLJEnabled]); + PrintToChat(client, "LJ stats are now %s", g_PlayerStates[client][bLJEnabled] ? "on" : "off"); + ShowSettingsPanel(client); + } + else if(!strcmp(strInfo, "beam")) + { + g_PlayerStates[client][bBeam] = !g_PlayerStates[client][bBeam]; + SetCookie(client, g_hCookieBeam, g_PlayerStates[client][bBeam]); + PrintToChat(client, "Beam is now %s", g_PlayerStates[client][bBeam] ? "on" : "off"); + ShowSettingsPanel(client); + } else if(!strcmp(strInfo, "deadstrafe")) - { - g_PlayerStates[client][bDeadstrafe] = !g_PlayerStates[client][bDeadstrafe]; - SetCookie(client, g_hCookieDeadstrafe, g_PlayerStates[client][bDeadstrafe]); - PrintToChat(client, "Deadstrafe beam is now %s", g_PlayerStates[client][bDeadstrafe] ? "on" : "off"); - ShowSettingsPanel(client); - } - else if(!strcmp(strInfo, "sound")) - { - g_PlayerStates[client][bSound] = !g_PlayerStates[client][bSound]; - SetCookie(client, g_hCookieSound, g_PlayerStates[client][bSound]); - PrintToChat(client, "Sound is now %s", g_PlayerStates[client][bSound] ? "on" : "off"); - ShowSettingsPanel(client); - } - else if(!strcmp(strInfo, "panel")) - { - g_PlayerStates[client][bHidePanel] = !g_PlayerStates[client][bHidePanel]; - SetCookie(client, g_hCookieHidePanel, g_PlayerStates[client][bHidePanel]); - PrintToChat(client, "Panel is now %s", g_PlayerStates[client][bHidePanel] ? "hidden" : "visible"); - ShowSettingsPanel(client); - } - else if(!strcmp(strInfo, "bhoppanel")) - { - g_PlayerStates[client][bHideBhopPanel] = !g_PlayerStates[client][bHideBhopPanel]; - SetCookie(client, g_hCookieHideBhopPanel, g_PlayerStates[client][bHideBhopPanel]); - PrintToChat(client, "Bhop panel is now %s", g_PlayerStates[client][bHideBhopPanel] ? "hidden" : "visible"); - ShowSettingsPanel(client); - } - else if(!strcmp(strInfo, "bhopstats")) - { - g_PlayerStates[client][bShowBhopStats] = !g_PlayerStates[client][bShowBhopStats]; - SetCookie(client, g_hCookieShowBhopStats, g_PlayerStates[client][bShowBhopStats]); - PrintToChat(client, "Bhop stats are now %s", g_PlayerStates[client][bShowBhopStats] ? "on" : "off"); - ShowSettingsPanel(client); - } - else if(!strcmp(strInfo, "verbosity")) - { - hMenu = CreateMenu(VerbosityMenuHandler); - - AddMenuItem(hMenu, "0", "0"); - AddMenuItem(hMenu, "1", "1"); - AddMenuItem(hMenu, "2", "2"); - AddMenuItem(hMenu, "3", "3"); - - DisplayMenu(hMenu, client, 0); - } - else if(!strcmp(strInfo, "showalljumps")) - { - g_PlayerStates[client][bShowAllJumps] = !g_PlayerStates[client][bShowAllJumps]; - SetCookie(client, g_hCookieShowAllJumps, g_PlayerStates[client][bShowAllJumps]); - PrintToChat(client, "Showing all jumps is now %s", g_PlayerStates[client][bShowAllJumps] ? "on" : "off"); - ShowSettingsPanel(client); - } - else if(!strcmp(strInfo, "prestrafehint")) - { - g_PlayerStates[client][bShowPrestrafeHint] = !g_PlayerStates[client][bShowPrestrafeHint]; - SetCookie(client, g_hCookieShowPrestrafeHint, g_PlayerStates[client][bShowPrestrafeHint]); - PrintToChat(client, "Prestrafe hint is now %s", g_PlayerStates[client][bShowPrestrafeHint] ? "on" : "off"); - ShowSettingsPanel(client); - } - } - - case MenuAction_End: - { - CloseHandle(hMenu); - } - } + { + g_PlayerStates[client][bDeadstrafe] = !g_PlayerStates[client][bDeadstrafe]; + SetCookie(client, g_hCookieDeadstrafe, g_PlayerStates[client][bDeadstrafe]); + PrintToChat(client, "Deadstrafe beam is now %s", g_PlayerStates[client][bDeadstrafe] ? "on" : "off"); + ShowSettingsPanel(client); + } + else if(!strcmp(strInfo, "sound")) + { + g_PlayerStates[client][bSound] = !g_PlayerStates[client][bSound]; + SetCookie(client, g_hCookieSound, g_PlayerStates[client][bSound]); + PrintToChat(client, "Sound is now %s", g_PlayerStates[client][bSound] ? "on" : "off"); + ShowSettingsPanel(client); + } + else if(!strcmp(strInfo, "speed")) { + Command_Speedometer( client, 0 ); + } + else if(!strcmp(strInfo, "panel")) + { + g_PlayerStates[client][bHidePanel] = !g_PlayerStates[client][bHidePanel]; + SetCookie(client, g_hCookieHidePanel, g_PlayerStates[client][bHidePanel]); + PrintToChat(client, "Panel is now %s", g_PlayerStates[client][bHidePanel] ? "hidden" : "visible"); + ShowSettingsPanel(client); + } + else if(!strcmp(strInfo, "bhoppanel")) + { + g_PlayerStates[client][bHideBhopPanel] = !g_PlayerStates[client][bHideBhopPanel]; + SetCookie(client, g_hCookieHideBhopPanel, g_PlayerStates[client][bHideBhopPanel]); + PrintToChat(client, "Bhop panel is now %s", g_PlayerStates[client][bHideBhopPanel] ? "hidden" : "visible"); + ShowSettingsPanel(client); + } + else if(!strcmp(strInfo, "bhopstats")) + { + g_PlayerStates[client][bShowBhopStats] = !g_PlayerStates[client][bShowBhopStats]; + SetCookie(client, g_hCookieShowBhopStats, g_PlayerStates[client][bShowBhopStats]); + PrintToChat(client, "Bhop stats are now %s", g_PlayerStates[client][bShowBhopStats] ? "on" : "off"); + ShowSettingsPanel(client); + } + else if(!strcmp(strInfo, "verbosity")) + { + hMenu = CreateMenu(VerbosityMenuHandler); + + AddMenuItem(hMenu, "0", "0"); + AddMenuItem(hMenu, "1", "1"); + AddMenuItem(hMenu, "2", "2"); + AddMenuItem(hMenu, "3", "3"); + + DisplayMenu(hMenu, client, 0); + } + else if(!strcmp(strInfo, "showalljumps")) + { + g_PlayerStates[client][bShowAllJumps] = !g_PlayerStates[client][bShowAllJumps]; + SetCookie(client, g_hCookieShowAllJumps, g_PlayerStates[client][bShowAllJumps]); + PrintToChat(client, "Showing all jumps is now %s", g_PlayerStates[client][bShowAllJumps] ? "on" : "off"); + ShowSettingsPanel(client); + } + else if(!strcmp(strInfo, "prestrafehint")) + { + g_PlayerStates[client][bShowPrestrafeHint] = !g_PlayerStates[client][bShowPrestrafeHint]; + SetCookie(client, g_hCookieShowPrestrafeHint, g_PlayerStates[client][bShowPrestrafeHint]); + PrintToChat(client, "Prestrafe hint is now %s", g_PlayerStates[client][bShowPrestrafeHint] ? "on" : "off"); + ShowSettingsPanel(client); + } + else if(!strcmp(strInfo, "strafetrainer")) { + g_PlayerStates[client][bStrafeTrainer] = !g_PlayerStates[client][bStrafeTrainer]; + SetCookie(client, g_hCookieStrafeTrainer, g_PlayerStates[client][bStrafeTrainer]); + + PrintToChat( client, "Strafe trainer is now %s", g_PlayerStates[client][bStrafeTrainer] ? "ENABLED" : "DISABLED" ); + ShowSettingsPanel(client); + } + } + + case MenuAction_End: + { + CloseHandle(hMenu); + } + } } SetCookie(client, Handle:hCookie, n) { - decl String:strCookie[64]; - - IntToString(n, strCookie, sizeof(strCookie)); + decl String:strCookie[64]; + + IntToString(n, strCookie, sizeof(strCookie)); - SetClientCookie(client, hCookie, strCookie); + SetClientCookie(client, hCookie, strCookie); } SetCookieFloat(client, Handle:hCookie, Float:n) { - decl String:strCookie[64]; - - FloatToString(n, strCookie, sizeof(strCookie)); - - SetClientCookie(client, hCookie, strCookie); + decl String:strCookie[64]; + + FloatToString(n, strCookie, sizeof(strCookie)); + + SetClientCookie(client, hCookie, strCookie); } public VerbosityMenuHandler(Handle:hMenu, MenuAction:ma, client, nItem) { - switch(ma) - { - case MenuAction_Select: - { - g_PlayerStates[client][nVerbosity] = nItem; - SetCookie(client, g_hCookieVerbosity, g_PlayerStates[client][nVerbosity]); - PrintToChat(client, "Verbosity level is now %d", g_PlayerStates[client][nVerbosity]); - - ShowSettingsPanel(client); - } - - case MenuAction_End: - { - CloseHandle(hMenu); - } - } + switch(ma) + { + case MenuAction_Select: + { + g_PlayerStates[client][nVerbosity] = nItem; + SetCookie(client, g_hCookieVerbosity, g_PlayerStates[client][nVerbosity]); + PrintToChat(client, "Verbosity level is now %d", g_PlayerStates[client][nVerbosity]); + + ShowSettingsPanel(client); + } + + case MenuAction_End: + { + CloseHandle(hMenu); + } + } +} + +public bool:AreAllOnOneTeam( client ) { + new team = GetClientTeam( client ); + for( new i = 1; i < GetMaxClients(); ++i ) { + if( !IsClientConnected(i) || !IsClientInGame(i) ) + continue; + + new team2 = GetClientTeam( i ); + if( team2 > 1 && team != team2 ) { + return false; + } + } + + return true; } public CheckpointMenuHandler( Handle:hMenu, MenuAction:ma, client, nItem ) { @@ -1320,7 +1426,6 @@ public CheckpointMenuHandler( Handle:hMenu, MenuAction:ma, client, nItem ) { } } -new Handle:nh_warmup = INVALID_HANDLE; public Action:Command_SavePoint(client, args) { if( !g_PlayerStates[client][bOnGround] ) { PrintToChat( client, "\x07FF00FFCannot save a checkpoint midair!" ); @@ -1331,7 +1436,7 @@ public Action:Command_SavePoint(client, args) { nh_warmup = FindConVar( "nh_warmup" ); } - if( nh_warmup && GetConVarInt( nh_warmup ) == 0 ) { + if( nh_warmup && GetConVarInt( nh_warmup ) == 0 && !AreAllOnOneTeam( client ) ) { PrintToChat( client, "\x07FF00FF Can only teleport during warmup." ); return Plugin_Handled; } @@ -1339,8 +1444,8 @@ public Action:Command_SavePoint(client, args) { new Float:vOrigin[3]; GetClientAbsOrigin(client, vOrigin); - Array_Copy(vOrigin, g_PlayerStates[client][vTPOrigin], 3); - Array_Copy(g_PlayerStates[client][vLastAngles], g_PlayerStates[client][vTPAngles], 3); + Array_Copy(vOrigin, g_PlayerStates[client][vTPOrigin], 3); + Array_Copy(g_PlayerStates[client][vLastAngles], g_PlayerStates[client][vTPAngles], 3); PrintToChat( client, "\x04Checkpoint saved." ); return Plugin_Handled; @@ -1356,19 +1461,37 @@ public Action:Command_LoadPoint(client, args) { nh_warmup = FindConVar( "nh_warmup" ); } - if( nh_warmup && GetConVarInt( nh_warmup ) == 0 ) { + if( nh_warmup && GetConVarInt( nh_warmup ) == 0 && !AreAllOnOneTeam( client ) ) { PrintToChat( client, "\x07FF00FFCan only teleport during warmup." ); return Plugin_Handled; } - new Float:vVelocity[3], Float:vOrigin[3], Float:vAngle[3]; + new Float:vVelocity[3], Float:vOrigin[3], Float:vAngle[3], Float:vDelta[2], Float:dist; vVelocity[0] = 0.0; vVelocity[1] = 0.0; vVelocity[2] = -2.0; Array_Copy(g_PlayerStates[client][vTPOrigin], vOrigin, 3); - Array_Copy(g_PlayerStates[client][vTPAngles], vAngle, 3); + for( new i = 1; i < GetMaxClients(); ++i ) { + if( i == client || !IsClientInGame(i) || !IsPlayerAlive(i) ) + continue; + + new Float:vOrigin2[3]; + GetClientAbsOrigin( i, vOrigin2 ); + + vDelta[0] = vOrigin[0] - vOrigin2[0]; + vDelta[1] = vOrigin[1] - vOrigin2[1]; + + dist = SquareRoot( vDelta[0] * vDelta[0] + vDelta[1] * vDelta[1] ); + + if( FloatAbs( vOrigin[2] - vOrigin2[2] ) < 64 && FloatAbs(dist) < 64 ) { + PrintToChat( client, "\x07FF00FFCannot load checkpoint because a player is standing there." ); + return Plugin_Handled; + } + } + + Array_Copy(g_PlayerStates[client][vTPAngles], vAngle, 3); if( vOrigin[0] == 0.0 && vOrigin[1] == 0.0 && vOrigin[2] == 0.0 ) { PrintToChat( client, "\x07FF00FFYou do not have a valid checkpoint." ); @@ -1393,7 +1516,7 @@ public Action:Command_CheckpointPanel(client, args) { nh_warmup = FindConVar( "nh_warmup" ); } - if( nh_warmup && GetConVarInt( nh_warmup ) == 0 ) { + if( nh_warmup && GetConVarInt( nh_warmup ) == 0 && !AreAllOnOneTeam( client ) ) { PrintToChat( client, "\x07FF00FFCan only teleport during warmup." ); return Plugin_Handled; } @@ -1407,6 +1530,13 @@ public Action:Command_CheckpointPanel(client, args) { return Plugin_Handled; } +public Action:Command_StrafeTrainer( client, args ) { + g_PlayerStates[client][bStrafeTrainer] = !g_PlayerStates[client][bStrafeTrainer]; + SetCookie(client, g_hCookieStrafeTrainer, g_PlayerStates[client][bStrafeTrainer]); + + PrintToChat( client, "Strafe trainer is now %s", g_PlayerStates[client][bStrafeTrainer] ? "ENABLED" : "DISABLED" ); +} + public Action:Command_KZ(client, args) { if( nh_warmup == INVALID_HANDLE ) { nh_warmup = FindConVar( "nh_warmup" ); @@ -1425,2252 +1555,2437 @@ public Action:Command_KZ(client, args) { public Action:Command_LJDeadstrafe(client, args) { - g_PlayerStates[client][bDeadstrafe] = !g_PlayerStates[client][bDeadstrafe]; - SetCookie(client, g_hCookieDeadstrafe, g_PlayerStates[client][bDeadstrafe]); - PrintToChat(client, "Deadstrafe beam %s", g_PlayerStates[client][bDeadstrafe] ? "ENABLED" : "DISABLED"); - - return Plugin_Handled; + g_PlayerStates[client][bDeadstrafe] = !g_PlayerStates[client][bDeadstrafe]; + SetCookie(client, g_hCookieDeadstrafe, g_PlayerStates[client][bDeadstrafe]); + PrintToChat(client, "Deadstrafe beam %s", g_PlayerStates[client][bDeadstrafe] ? "ENABLED" : "DISABLED"); + + return Plugin_Handled; } public Action:Command_LJPanel(client, args) { - g_PlayerStates[client][bHidePanel] = !g_PlayerStates[client][bHidePanel]; - SetCookie(client, g_hCookieHidePanel, g_PlayerStates[client][bHidePanel]); - PrintToChat(client, "Longjump panel %s", !g_PlayerStates[client][bHidePanel] ? "ENABLED" : "DISABLED"); - - return Plugin_Handled; + g_PlayerStates[client][bHidePanel] = !g_PlayerStates[client][bHidePanel]; + SetCookie(client, g_hCookieHidePanel, g_PlayerStates[client][bHidePanel]); + PrintToChat(client, "Longjump panel %s", !g_PlayerStates[client][bHidePanel] ? "ENABLED" : "DISABLED"); + + return Plugin_Handled; } public Action:Command_LJBeam(client, args) { - g_PlayerStates[client][bBeam] = !g_PlayerStates[client][bBeam]; - SetCookie(client, g_hCookieBeam, g_PlayerStates[client][bBeam]); - PrintToChat(client, "Longjump beam %s", g_PlayerStates[client][bBeam] ? "ENABLED" : "DISABLED"); - - return Plugin_Handled; + g_PlayerStates[client][bBeam] = !g_PlayerStates[client][bBeam]; + SetCookie(client, g_hCookieBeam, g_PlayerStates[client][bBeam]); + PrintToChat(client, "Longjump beam %s", g_PlayerStates[client][bBeam] ? "ENABLED" : "DISABLED"); + + return Plugin_Handled; } public Action:Command_LJBlock(client, args) { - return Plugin_Handled; + return Plugin_Handled; } public Action:Command_LJSound(client, args) { - g_PlayerStates[client][bSound] = !g_PlayerStates[client][bSound]; - SetCookie(client, g_hCookieSound, g_PlayerStates[client][bSound]); - PrintToChat(client, "Longjump sounds %s", g_PlayerStates[client][bSound] ? "enabled" : "disabled"); - - return Plugin_Handled; + g_PlayerStates[client][bSound] = !g_PlayerStates[client][bSound]; + SetCookie(client, g_hCookieSound, g_PlayerStates[client][bSound]); + PrintToChat(client, "Longjump sounds %s", g_PlayerStates[client][bSound] ? "enabled" : "disabled"); + + return Plugin_Handled; } public Action:Command_LJVersion(client, args) { - CPrintToChat(client, "{green}ljstats %s by Miu -w-, updated by networkheaven team.", LJSTATS_VERSION); - - return Plugin_Handled; + CPrintToChat(client, "{green}ljstats %s by Miu -w-, updated by networkheaven team.", LJSTATS_VERSION); + + return Plugin_Handled; } public Action:Command_LJTop(client, args) { - //SendPanelToClient(g_hLJTopLJPanel, client, EmptyPanelHandler, 10); - DisplayMenu(g_hLJTopMainMenu, client, MENU_TIME_FOREVER); - - return Plugin_Handled; + //SendPanelToClient(g_hLJTopLJPanel, client, EmptyPanelHandler, 10); + DisplayMenu(g_hLJTopMainMenu, client, MENU_TIME_FOREVER); + + return Plugin_Handled; } public Action:Command_LJTopDelete(client, args) { - decl String:buf[32]; - GetCmdArg(1, buf, sizeof(buf)); - - new LJTOP_TABLE:nLJTopTable = LJTOP_TABLE:-1; - - for(new LJTOP_TABLE:i; i < LT_END; i++) - { - if(!strcmp(g_strLJTopTags[i], buf)) - { - nLJTopTable = i; - break; - } - } - - if(nLJTopTable == LJTOP_TABLE:-1) - { - PrintToChat(client, "Unrecognized table %s", buf); - - return Plugin_Handled; - } - - - decl String:str[4]; - GetCmdArg(2, str, sizeof(str)); - new n = StringToInt(str) - 1; - - if(n < 0 || n > LJTOP_NUM_ENTRIES - 1) - { - PrintToChat(client, "Invalid entry"); - - return Plugin_Handled; - } - - PrintToChat(client, "Removing %s's %.2f in table %d (%s)", g_LJTop[nLJTopTable][n][m_strName], g_LJTop[nLJTopTable][n][m_fDistance], nLJTopTable, buf); - - LJTopMoveUp(nLJTopTable, n); - - LJTopSave(); - LJTopCreateMenu(nLJTopTable); - - return Plugin_Handled; + decl String:buf[32]; + GetCmdArg(1, buf, sizeof(buf)); + + new LJTOP_TABLE:nLJTopTable = LJTOP_TABLE:-1; + + for(new LJTOP_TABLE:i; i < LT_END; i++) + { + if(!strcmp(g_strLJTopTags[i], buf)) + { + nLJTopTable = i; + break; + } + } + + if(nLJTopTable == LJTOP_TABLE:-1) + { + PrintToChat(client, "Unrecognized table %s", buf); + + return Plugin_Handled; + } + + + decl String:str[4]; + GetCmdArg(2, str, sizeof(str)); + new n = StringToInt(str) - 1; + + if(n < 0 || n > LJTOP_NUM_ENTRIES - 1) + { + PrintToChat(client, "Invalid entry"); + + return Plugin_Handled; + } + + PrintToChat(client, "Removing %s's %.2f in table %d (%s)", g_LJTop[nLJTopTable][n][m_strName], g_LJTop[nLJTopTable][n][m_fDistance], nLJTopTable, buf); + + LJTopMoveUp(nLJTopTable, n); + + LJTopSave(); + LJTopCreateMenu(nLJTopTable); + + return Plugin_Handled; } public Action:Command_Gap(client, args) { - new Handle:hGapPanel = CreatePanel(); - - SetPanelTitle(hGapPanel, "Select point 1"); - - SendPanelToClient(hGapPanel, client, EmptyPanelHandler, 10); - - CloseHandle(hGapPanel); - - g_PlayerStates[client][GapSelectionMode] = GSM_GAP; - - return Plugin_Handled; + new Handle:hGapPanel = CreatePanel(); + + SetPanelTitle(hGapPanel, "Select point 1"); + + SendPanelToClient(hGapPanel, client, EmptyPanelHandler, 10); + + CloseHandle(hGapPanel); + + g_PlayerStates[client][GapSelectionMode] = GSM_GAP; + + return Plugin_Handled; } public Action:Command_BlockGap(client, args) { - new Handle:hGapPanel = CreatePanel(); - - SetPanelTitle(hGapPanel, "Select block"); - - SendPanelToClient(hGapPanel, client, EmptyPanelHandler, 10); - - CloseHandle(hGapPanel); - - g_PlayerStates[client][GapSelectionMode] = GSM_BLOCKGAP; - - return Plugin_Handled; + new Handle:hGapPanel = CreatePanel(); + + SetPanelTitle(hGapPanel, "Select block"); + + SendPanelToClient(hGapPanel, client, EmptyPanelHandler, 10); + + CloseHandle(hGapPanel); + + g_PlayerStates[client][GapSelectionMode] = GSM_BLOCKGAP; + + return Plugin_Handled; } GapSelect(client, buttons) { - if(!(buttons & IN_ATTACK || buttons & IN_ATTACK2 || buttons & IN_USE) || - g_PlayerStates[client][LastButtons] & IN_ATTACK || g_PlayerStates[client][LastButtons] & IN_ATTACK2 || g_PlayerStates[client][LastButtons] & IN_USE) - { - return; - } - - new Float:vPoint[3], Float:vNormal[3]; - GetGapPoint(vPoint, vNormal, client); - - switch(g_PlayerStates[client][GapSelectionMode]) - { - case GSM_GAP: - { - Array_Copy(vPoint, g_PlayerStates[client][vGapPoint1], 3); - - SendPanelMsg(client, "Select point 2"); - - g_PlayerStates[client][GapSelectionMode] = GSM_GAPSECOND; - } - - case GSM_GAPSECOND: - { - new Float:vPoint1[3]; - Array_Copy(g_PlayerStates[client][vGapPoint1], vPoint1, 3); - - new Float:xy = Pow(Pow(vPoint[0] - vPoint1[0], 2.0) + Pow(vPoint[1] - vPoint1[1], 2.0), 0.5); - - SendPanelMsg(client, "distance: %.2f, xy: %.2f, z: %.2f", GetVectorDistance(vPoint, vPoint1), xy, vPoint1[2] - vPoint[2]); - - CreateBeamClient(client, vPoint, vPoint1, 0, 0, 128, 5.0); - - g_PlayerStates[client][GapSelectionMode] = GSM_NONE; - } - - case GSM_BLOCKGAP: - { - new Float:vBlockEnd[3], Float:vOrigin[3]; - GetClientAbsOrigin(client, vOrigin); - GetOppositePoint(vBlockEnd, vPoint, vNormal); - - SendPanelMsg(client, "block: %.2f", GetVectorDistance(vPoint, vBlockEnd)); - - CreateBeamClient(client, vPoint, vBlockEnd, 255, 0, 0, 5.0); - - g_PlayerStates[client][GapSelectionMode] = GSM_NONE; - } - - } + if(!(buttons & IN_ATTACK || buttons & IN_ATTACK2 || buttons & IN_USE) || + g_PlayerStates[client][LastButtons] & IN_ATTACK || g_PlayerStates[client][LastButtons] & IN_ATTACK2 || g_PlayerStates[client][LastButtons] & IN_USE) + { + return; + } + + new Float:vPoint[3], Float:vNormal[3]; + GetGapPoint(vPoint, vNormal, client); + + switch(g_PlayerStates[client][GapSelectionMode]) + { + case GSM_GAP: + { + Array_Copy(vPoint, g_PlayerStates[client][vGapPoint1], 3); + + SendPanelMsg(client, "Select point 2"); + + g_PlayerStates[client][GapSelectionMode] = GSM_GAPSECOND; + } + + case GSM_GAPSECOND: + { + new Float:vPoint1[3]; + Array_Copy(g_PlayerStates[client][vGapPoint1], vPoint1, 3); + + new Float:xy = Pow(Pow(vPoint[0] - vPoint1[0], 2.0) + Pow(vPoint[1] - vPoint1[1], 2.0), 0.5); + + SendPanelMsg(client, "distance: %.2f, xy: %.2f, z: %.2f", GetVectorDistance(vPoint, vPoint1), xy, vPoint1[2] - vPoint[2]); + + CreateBeamClient(client, vPoint, vPoint1, 0, 0, 128, 5.0); + + g_PlayerStates[client][GapSelectionMode] = GSM_NONE; + } + + case GSM_BLOCKGAP: + { + new Float:vBlockEnd[3], Float:vOrigin[3]; + GetClientAbsOrigin(client, vOrigin); + GetOppositePoint(vBlockEnd, vPoint, vNormal); + + SendPanelMsg(client, "block: %.2f", GetVectorDistance(vPoint, vBlockEnd)); + + CreateBeamClient(client, vPoint, vBlockEnd, 255, 0, 0, 5.0); + + g_PlayerStates[client][GapSelectionMode] = GSM_NONE; + } + + } } public Action:Command_Tele(client, args) { - g_PlayerStates[client][IllegalJumpFlags] |= IJF_TELEPORT; - - return Plugin_Continue; + g_PlayerStates[client][IllegalJumpFlags] |= IJF_TELEPORT; + + return Plugin_Continue; } public Action:Command_PersonalBest(client, args) { - CPrintToChat(client, "{green}Your longjump record is {default}%.2f{green} units", g_PlayerStates[client][fPersonalBest]); - - return Plugin_Handled; + CPrintToChat(client, "{green}Your longjump record is {default}%.2f{green} units", g_PlayerStates[client][fPersonalBest]); + + return Plugin_Handled; } UpdatePersonalBest(client) { - if(g_PlayerStates[client][JumpType] != JT_LONGJUMP) - { - return; - } - - if(g_PlayerStates[client][fJumpDistance] > g_PlayerStates[client][fPersonalBest]) - { - g_PlayerStates[client][fPersonalBest] = g_PlayerStates[client][fJumpDistance]; - - CPrintToChat(client, "{green}Congratulations, you have a new longjump record with {default}%.2f{green} units!", g_PlayerStates[client][fPersonalBest]); - - SetCookieFloat(client, g_hCookiePersonalBest, g_PlayerStates[client][fPersonalBest]); - } + if(g_PlayerStates[client][JumpType] != JT_LONGJUMP) + { + return; + } + + if(g_PlayerStates[client][fJumpDistance] > g_PlayerStates[client][fPersonalBest]) + { + g_PlayerStates[client][fPersonalBest] = g_PlayerStates[client][fJumpDistance]; + + CPrintToChat(client, "{green}Congratulations, you have a new longjump record with {default}%.2f{green} units!", g_PlayerStates[client][fPersonalBest]); + + SetCookieFloat(client, g_hCookiePersonalBest, g_PlayerStates[client][fPersonalBest]); + } } public Action:Command_ResetPersonalBest(client, args) { - SetCookieFloat(client, g_hCookiePersonalBest, 0.0); - g_PlayerStates[client][fPersonalBest] = 0.0; - - return Plugin_Continue; + SetCookieFloat(client, g_hCookiePersonalBest, 0.0); + g_PlayerStates[client][fPersonalBest] = 0.0; + + return Plugin_Continue; } public Action:Command_LJTopLoadFromFile(client, args) { - decl String:arg[PLATFORM_MAX_PATH]; - GetCmdArgString(arg, sizeof(arg)); - LJTopLoad(arg); - - return Plugin_Handled; + decl String:arg[PLATFORM_MAX_PATH]; + GetCmdArgString(arg, sizeof(arg)); + LJTopLoad(arg); + + return Plugin_Handled; } LJTopCreateMainMenu() { - if(g_hLJTopMainMenu != INVALID_HANDLE) - { - CloseHandle(g_hLJTopMainMenu); - } - - g_hLJTopMainMenu = CreateMenu(LJTopMainMenuHandler); - - for(new LJTOP_TABLE:i; i < LT_END; i++) - { - AddMenuItem(g_hLJTopMainMenu, g_strLJTopTags[i], g_strLJTopTableName[i]); - } + if(g_hLJTopMainMenu != INVALID_HANDLE) + { + CloseHandle(g_hLJTopMainMenu); + } + + g_hLJTopMainMenu = CreateMenu(LJTopMainMenuHandler); + + for(new LJTOP_TABLE:i; i < LT_END; i++) + { + AddMenuItem(g_hLJTopMainMenu, g_strLJTopTags[i], g_strLJTopTableName[i]); + } } public LJTopMainMenuHandler(Handle:hMenu, MenuAction:ma, client, nItem) { - switch(ma) - { - case MenuAction_Select: - { - decl String:strInfo[16]; - - if(!GetMenuItem(hMenu, nItem, strInfo, sizeof(strInfo))) - { - PrintToChat(client, "rip menu..."); - return; - } - - for(new LJTOP_TABLE:i = LJTOP_TABLE:0; i < LT_END; i++) - { - if(!strcmp(g_strLJTopTags[i], strInfo)) - { - DisplayMenu(g_hLJTopMenus[i], client, 0); - - break; - } - } - } - - case MenuAction_End: - { - } - } + switch(ma) + { + case MenuAction_Select: + { + decl String:strInfo[16]; + + if(!GetMenuItem(hMenu, nItem, strInfo, sizeof(strInfo))) + { + PrintToChat(client, "rip menu..."); + return; + } + + for(new LJTOP_TABLE:i = LJTOP_TABLE:0; i < LT_END; i++) + { + if(!strcmp(g_strLJTopTags[i], strInfo)) + { + DisplayMenu(g_hLJTopMenus[i], client, 0); + + break; + } + } + } + + case MenuAction_End: + { + } + } } LJTopCreateMenu(LJTOP_TABLE:nTable) { - if(g_hLJTopMenus[nTable] != INVALID_HANDLE) - { - CloseHandle(g_hLJTopMenus[nTable]); - } - - g_hLJTopMenus[nTable] = CreateMenu(LJTopRecordMenuHandler); - - decl String:buf[128], String:info[32]; - - Format(buf, sizeof(buf), "%s top", g_strLJTopTableName[nTable]); - - SetMenuTitle(g_hLJTopMenus[nTable], buf); - - for(new i; i < LJTOP_NUM_ENTRIES; i++) - { - if(g_LJTop[nTable][i][m_strName][0] == 0) - { - break; - } - + if(g_hLJTopMenus[nTable] != INVALID_HANDLE) + { + CloseHandle(g_hLJTopMenus[nTable]); + } + + g_hLJTopMenus[nTable] = CreateMenu(LJTopRecordMenuHandler); + + decl String:buf[128], String:info[32]; + + Format(buf, sizeof(buf), "%s top", g_strLJTopTableName[nTable]); + + SetMenuTitle(g_hLJTopMenus[nTable], buf); + + for(new i; i < LJTOP_NUM_ENTRIES; i++) + { + if(g_LJTop[nTable][i][m_strName][0] == 0) + { + break; + } + FormatEx(buf, sizeof(buf), "%s - %.2f (%.2f, %d @ %d%%, %.2f)", g_LJTop[nTable][i][m_strName], g_LJTop[nTable][i][m_fDistance], g_LJTop[nTable][i][m_fPrestrafe], g_LJTop[nTable][i][m_nStrafes], RoundFloat(g_LJTop[nTable][i][m_fSync]), g_LJTop[nTable][i][m_fMaxSpeed]); - - FormatEx(info, sizeof(info), "%s;%d", g_strLJTopTags[nTable], i); - - AddMenuItem(g_hLJTopMenus[nTable], info, buf); - } - - //SetMenuExitBackButton(g_hLJTopMenus[nTable], true); + + FormatEx(info, sizeof(info), "%s;%d", g_strLJTopTags[nTable], i); + + AddMenuItem(g_hLJTopMenus[nTable], info, buf); + } + + //SetMenuExitBackButton(g_hLJTopMenus[nTable], true); } public LJTopRecordMenuHandler(Handle:hMenu, MenuAction:ma, client, nItem) { - switch(ma) - { - case MenuAction_Select: - { - decl String:info[16]; - - if(!GetMenuItem(hMenu, nItem, info, sizeof(info))) - { - LogError("rip menu..."); - return; - } - - decl String:split[2][16], String:sTime[128], String:buf[128]; - ExplodeString(info, ";", split, sizeof(split), sizeof(split[])); - - new iTable = _:GetLJTopTable(split[0]); - new iEntry = StringToInt(split[1]); - - if(iTable == -1) - { - LogError("Unrecognized table %s"); - return; - } - - new Handle:hPanel = CreatePanel(); - - FormatTime(sTime, sizeof(sTime), NULL_STRING, g_LJTop[iTable][iEntry][m_nTimestamp]); // "%B %d %Y %T" - - FormatEx(buf, sizeof(buf), "%s's %.2f -- %s\n ", g_LJTop[iTable][iEntry][m_strName], g_LJTop[iTable][iEntry][m_fDistance], sTime); - - SetPanelTitle(hPanel, buf); - + switch(ma) + { + case MenuAction_Select: + { + decl String:info[16]; + + if(!GetMenuItem(hMenu, nItem, info, sizeof(info))) + { + LogError("rip menu..."); + return; + } + + decl String:split[2][16], String:sTime[128], String:buf[128]; + ExplodeString(info, ";", split, sizeof(split), sizeof(split[])); + + new iTable = _:GetLJTopTable(split[0]); + new iEntry = StringToInt(split[1]); + + if(iTable == -1) + { + LogError("Unrecognized table %s"); + return; + } + + new Handle:hPanel = CreatePanel(); + + FormatTime(sTime, sizeof(sTime), NULL_STRING, g_LJTop[iTable][iEntry][m_nTimestamp]); // "%B %d %Y %T" + + FormatEx(buf, sizeof(buf), "%s's %.2f -- %s\n ", g_LJTop[iTable][iEntry][m_strName], g_LJTop[iTable][iEntry][m_fDistance], sTime); + + SetPanelTitle(hPanel, buf); + DrawPanelTextF(hPanel, " key gain loss time sync"); - for(new i = 0; i < g_LJTop[iTable][iEntry][m_nStrafes] && i < 16; i++) - { - decl String:strStrafeKey[3]; - GetStrafeKey(strStrafeKey, g_LJTop[iTable][iEntry][m_StrafeDir][i]); - - DrawPanelTextF(hPanel, "%d %s %.2f %.2f %.2f %.2f", - i + 1, - strStrafeKey, - g_LJTop[iTable][iEntry][m_fStrafeGain][i], g_LJTop[iTable][iEntry][m_fStrafeLoss][i], - float(g_LJTop[iTable][iEntry][m_nStrafeTicks][i]) / g_LJTop[iTable][iEntry][m_nTotalTicks] * 100, - g_LJTop[iTable][iEntry][m_fStrafeSync][i]); - } - - DrawPanelTextF(hPanel, "total sync: %.2f%%", g_LJTop[iTable][iEntry][m_fSync]); - - SendPanelToClient(hPanel, client, RecordPanelHandler, 0); - - CloseHandle(hPanel); - } - - case MenuAction_Cancel: - { - if(nItem == -3) - { - DisplayMenu(g_hLJTopMainMenu, client, 0); - } - } - } + for(new i = 0; i < g_LJTop[iTable][iEntry][m_nStrafes] && i < 16; i++) + { + decl String:strStrafeKey[3]; + GetStrafeKey(strStrafeKey, g_LJTop[iTable][iEntry][m_StrafeDir][i]); + + DrawPanelTextF(hPanel, "%d %s %.2f %.2f %.2f %.2f", + i + 1, + strStrafeKey, + g_LJTop[iTable][iEntry][m_fStrafeGain][i], g_LJTop[iTable][iEntry][m_fStrafeLoss][i], + float(g_LJTop[iTable][iEntry][m_nStrafeTicks][i]) / g_LJTop[iTable][iEntry][m_nTotalTicks] * 100, + g_LJTop[iTable][iEntry][m_fStrafeSync][i]); + } + + DrawPanelTextF(hPanel, "total sync: %.2f%%", g_LJTop[iTable][iEntry][m_fSync]); + + SendPanelToClient(hPanel, client, RecordPanelHandler, 0); + + CloseHandle(hPanel); + } + + case MenuAction_Cancel: + { + if(nItem == -3) + { + DisplayMenu(g_hLJTopMainMenu, client, 0); + } + } + } } public RecordPanelHandler(Handle:hMenu, MenuAction:ma, client, nItem) { - switch(ma) - { - case MenuAction_Select: - { - DisplayMenu(g_hLJTopMainMenu, client, 0); - } - } + switch(ma) + { + case MenuAction_Select: + { + DisplayMenu(g_hLJTopMainMenu, client, 0); + } + } } LJTopLoad(const String:strPath[]) { - // Load top stats into memory from file - - /*decl String:strPath[PLATFORM_MAX_PATH]; - - BuildPath(Path_SM, strPath, PLATFORM_MAX_PATH, LJTOP_DIR); - - if(!DirExists(strPath)) - { - PrintToServer("[LJTop] Dir %s nonexistent", strPath); - return; - } - - StrCat(strPath, sizeof(strPath), LJTOP_FILE);*/ - - new Handle:hFile = OpenFile(strPath, "r"); - - if(hFile == INVALID_HANDLE) - { - LogError("[LJTop] Error opening %s", strPath); - return; - } - - decl String:strLine[1024]; // omg, so big it is??? - decl String:strBuffers[LJTOP_MAX_NUM_STATS][64]; - - ReadFileLine(hFile, strLine, sizeof(strLine)); - - new /*nVersion, */MinStats; - if(!strcmp(strLine, "1\n")) - { - //nVersion = 1; - MinStats = LJTOP_MIN_NUM_STATS_1; - - if(IsEndOfFile(hFile)) - { - PrintToServer("[LJTop] EOF"); - return; - } - - ReadFileLine(hFile, strLine, sizeof(strLine)); - } - else - { - //nVersion = 0; - MinStats = LJTOP_MIN_NUM_STATS_0; - } - - do - { - #if defined DEBUG - PrintToServer("[LJTop] read %s", strLine); - #endif - - static LJTOP_TABLE:nTable = LJTOP_TABLE:-1; - static nEntry = 0; - - new bool:bTable; - - for(new LJTOP_TABLE:j; j < LT_END; j++) - { - decl String:strTag[16]; - Format(strTag, sizeof(strTag), "%s:\n", g_strLJTopTags[j]); - if(!strcmp(strLine, strTag)) - { - PrintToServer("[LJTop] read tag: %s", g_strLJTopTags[j]); - nTable = j; - nEntry = 0; - bTable = true; - } - } - - if(bTable) - { - continue; - } - - if(nTable == LJTOP_TABLE:-1) - { - PrintToServer("[LJTop] no table for line %s", strLine); - continue; - } - - if(nEntry >= LJTOP_NUM_ENTRIES) - { - PrintToServer("[LJTop] Too many entries for table %d; ignoring line", nTable); - continue; - } - - new nLength = ExplodeString(strLine, ";", strBuffers, LJTOP_MAX_NUM_STATS, sizeof(strBuffers[]), false); - - if(nLength < MinStats) - { - PrintToServer("[LJTop] Unexpected entry %d length (expected at least %d, got %d); ignoring line", nEntry + 1, MinStats, nLength); - continue; - } - - new k; - strcopy(g_LJTop[nTable][nEntry][m_strName], 64, strBuffers[k++]); - strcopy(g_LJTop[nTable][nEntry][m_strSteamID], 32, strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fDistance] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fPrestrafe] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_nStrafes] = StringToInt(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fSync] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fMaxSpeed] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_nTotalTicks] = StringToInt(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fHeightDelta] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fSyncedAngle] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fTotalAngle] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fHeightDelta] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fBlockDistance] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fTrajectory] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_nTimestamp] = StringToInt(strBuffers[k++]); - - for(new l; l < (nLength - MinStats) / 5 && l < LJTOP_MAX_STRAFES && k < 64 - 5; l++) - { - g_LJTop[nTable][nEntry][m_StrafeDir][l] = GetStrafeDir(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fStrafeGain][l] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fStrafeLoss][l] = StringToFloat(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_nStrafeTicks][l] = StringToInt(strBuffers[k++]); - g_LJTop[nTable][nEntry][m_fStrafeSync][l] = StringToFloat(strBuffers[k++]); - } - - nEntry++; - - #if defined DEBUG - PrintToServer("read %s %.2f in table %d", g_LJTop[nTable][nEntry][m_strName], g_LJTop[nTable][nEntry][m_fDistance], nTable); - #endif - } - while(!IsEndOfFile(hFile) && ReadFileLine(hFile, strLine, sizeof(strLine))); - - CloseHandle(hFile); + // Load top stats into memory from file + + /*decl String:strPath[PLATFORM_MAX_PATH]; + + BuildPath(Path_SM, strPath, PLATFORM_MAX_PATH, LJTOP_DIR); + + if(!DirExists(strPath)) + { + PrintToServer("[LJTop] Dir %s nonexistent", strPath); + return; + } + + StrCat(strPath, sizeof(strPath), LJTOP_FILE);*/ + + new Handle:hFile = OpenFile(strPath, "r"); + + if(hFile == INVALID_HANDLE) + { + LogError("[LJTop] Error opening %s", strPath); + return; + } + + decl String:strLine[1024]; // omg, so big it is??? + decl String:strBuffers[LJTOP_MAX_NUM_STATS][64]; + + ReadFileLine(hFile, strLine, sizeof(strLine)); + + new /*nVersion, */MinStats; + if(!strcmp(strLine, "1\n")) + { + //nVersion = 1; + MinStats = LJTOP_MIN_NUM_STATS_1; + + if(IsEndOfFile(hFile)) + { + PrintToServer("[LJTop] EOF"); + return; + } + + ReadFileLine(hFile, strLine, sizeof(strLine)); + } + else + { + //nVersion = 0; + MinStats = LJTOP_MIN_NUM_STATS_0; + } + + do + { + #if defined DEBUG + PrintToServer("[LJTop] read %s", strLine); + #endif + + static LJTOP_TABLE:nTable = LJTOP_TABLE:-1; + static nEntry = 0; + + new bool:bTable; + + for(new LJTOP_TABLE:j; j < LT_END; j++) + { + decl String:strTag[16]; + Format(strTag, sizeof(strTag), "%s:\n", g_strLJTopTags[j]); + if(!strcmp(strLine, strTag)) + { + PrintToServer("[LJTop] read tag: %s", g_strLJTopTags[j]); + nTable = j; + nEntry = 0; + bTable = true; + } + } + + if(bTable) + { + continue; + } + + if(nTable == LJTOP_TABLE:-1) + { + PrintToServer("[LJTop] no table for line %s", strLine); + continue; + } + + if(nEntry >= LJTOP_NUM_ENTRIES) + { + PrintToServer("[LJTop] Too many entries for table %d; ignoring line", nTable); + continue; + } + + new nLength = ExplodeString(strLine, ";", strBuffers, LJTOP_MAX_NUM_STATS, sizeof(strBuffers[]), false); + + if(nLength < MinStats) + { + PrintToServer("[LJTop] Unexpected entry %d length (expected at least %d, got %d); ignoring line", nEntry + 1, MinStats, nLength); + continue; + } + + new k; + strcopy(g_LJTop[nTable][nEntry][m_strName], 64, strBuffers[k++]); + strcopy(g_LJTop[nTable][nEntry][m_strSteamID], 32, strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fDistance] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fPrestrafe] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_nStrafes] = StringToInt(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fSync] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fMaxSpeed] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_nTotalTicks] = StringToInt(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fHeightDelta] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fSyncedAngle] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fTotalAngle] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fHeightDelta] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fBlockDistance] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fTrajectory] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_nTimestamp] = StringToInt(strBuffers[k++]); + + for(new l; l < (nLength - MinStats) / 5 && l < LJTOP_MAX_STRAFES && k < 64 - 5; l++) + { + g_LJTop[nTable][nEntry][m_StrafeDir][l] = GetStrafeDir(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fStrafeGain][l] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fStrafeLoss][l] = StringToFloat(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_nStrafeTicks][l] = StringToInt(strBuffers[k++]); + g_LJTop[nTable][nEntry][m_fStrafeSync][l] = StringToFloat(strBuffers[k++]); + } + + nEntry++; + + #if defined DEBUG + PrintToServer("read %s %.2f in table %d", g_LJTop[nTable][nEntry][m_strName], g_LJTop[nTable][nEntry][m_fDistance], nTable); + #endif + } + while(!IsEndOfFile(hFile) && ReadFileLine(hFile, strLine, sizeof(strLine))); + + CloseHandle(hFile); } LJTopSave() { - DB_SaveLJTop(); + DB_SaveLJTop(); } /*LJTopSave() { - // Delete old file and write entirely new one - - decl String:strPath[PLATFORM_MAX_PATH]; - - BuildPath(Path_SM, strPath, PLATFORM_MAX_PATH, LJTOP_DIR); - - if(!DirExists(strPath)) - { - CreateDirectory(strPath, 0x3FF); // 0777 - } - - StrCat(strPath, sizeof(strPath), LJTOP_FILE); - - new Handle:hFile = OpenFile(strPath, "w"); // This will overwrite the old file - - if(hFile == INVALID_HANDLE) - { - PrintToServer("[LJTop] Error opening %s", strPath); - return; - } - - WriteFileLine(hFile, "1", false); - - decl String:buf[512], String:buf2[128]; - - for(new nIndex; nIndex < _:LT_END; nIndex++) - { - Format(buf, sizeof(buf), "%s:", g_strLJTopTags[nIndex]); - if(!WriteFileLine(hFile, buf, false)) - { - PrintToServer("[LJTop] Error writing to %s", strPath); - PrintToChatAll("[LJTop] Error saving ljtop"); - } - - for(new i; i < LJTOP_NUM_ENTRIES; i++) - { - if(g_LJTop[nIndex][i][m_strSteamID][0] == 0) - { - break; - } - - Format(buf, sizeof(buf), "%s;%s;%f;%f;%d;%f;%f;%d;%f;%f;%f;%f;%f;%f;%d;", - g_LJTop[nIndex][i][m_strName], - g_LJTop[nIndex][i][m_strSteamID], - g_LJTop[nIndex][i][m_fDistance], - g_LJTop[nIndex][i][m_fPrestrafe], - g_LJTop[nIndex][i][m_nStrafes], - - g_LJTop[nIndex][i][m_fSync], - g_LJTop[nIndex][i][m_fMaxSpeed], - g_LJTop[nIndex][i][m_nTotalTicks], - g_LJTop[nIndex][i][m_fHeightDelta], - g_LJTop[nIndex][i][m_fSyncedAngle], - - g_LJTop[nIndex][i][m_fTotalAngle], - g_LJTop[nIndex][i][m_fHeightDelta], - g_LJTop[nIndex][i][m_fBlockDistance], - g_LJTop[nIndex][i][m_fTrajectory], - g_LJTop[nIndex][i][m_nTimestamp]); - - for(new j; j < g_LJTop[nIndex][i][m_nStrafes] && j < LJTOP_MAX_STRAFES; j++) - { - decl String:strStrafeKey[4]; - GetStrafeKey(strStrafeKey, g_LJTop[nIndex][i][m_StrafeDir][j]); - Format(buf2, sizeof(buf2), "%s;%f;%f;%d;%f;", - strStrafeKey, - g_LJTop[nIndex][i][m_fStrafeGain][j], - g_LJTop[nIndex][i][m_fStrafeLoss][j], - g_LJTop[nIndex][i][m_nStrafeTicks][j], - g_LJTop[nIndex][i][m_fStrafeSync][j]); - - StrCat(buf, sizeof(buf), buf2); - } - - if(!WriteFileLine(hFile, buf)) - { - PrintToServer("[LJTop] Error writing to %s", strPath); - PrintToChatAll("[LJTop] Error saving ljtop"); - } - } - } - - CloseHandle(hFile); + // Delete old file and write entirely new one + + decl String:strPath[PLATFORM_MAX_PATH]; + + BuildPath(Path_SM, strPath, PLATFORM_MAX_PATH, LJTOP_DIR); + + if(!DirExists(strPath)) + { + CreateDirectory(strPath, 0x3FF); // 0777 + } + + StrCat(strPath, sizeof(strPath), LJTOP_FILE); + + new Handle:hFile = OpenFile(strPath, "w"); // This will overwrite the old file + + if(hFile == INVALID_HANDLE) + { + PrintToServer("[LJTop] Error opening %s", strPath); + return; + } + + WriteFileLine(hFile, "1", false); + + decl String:buf[512], String:buf2[128]; + + for(new nIndex; nIndex < _:LT_END; nIndex++) + { + Format(buf, sizeof(buf), "%s:", g_strLJTopTags[nIndex]); + if(!WriteFileLine(hFile, buf, false)) + { + PrintToServer("[LJTop] Error writing to %s", strPath); + PrintToChatAll("[LJTop] Error saving ljtop"); + } + + for(new i; i < LJTOP_NUM_ENTRIES; i++) + { + if(g_LJTop[nIndex][i][m_strSteamID][0] == 0) + { + break; + } + + Format(buf, sizeof(buf), "%s;%s;%f;%f;%d;%f;%f;%d;%f;%f;%f;%f;%f;%f;%d;", + g_LJTop[nIndex][i][m_strName], + g_LJTop[nIndex][i][m_strSteamID], + g_LJTop[nIndex][i][m_fDistance], + g_LJTop[nIndex][i][m_fPrestrafe], + g_LJTop[nIndex][i][m_nStrafes], + + g_LJTop[nIndex][i][m_fSync], + g_LJTop[nIndex][i][m_fMaxSpeed], + g_LJTop[nIndex][i][m_nTotalTicks], + g_LJTop[nIndex][i][m_fHeightDelta], + g_LJTop[nIndex][i][m_fSyncedAngle], + + g_LJTop[nIndex][i][m_fTotalAngle], + g_LJTop[nIndex][i][m_fHeightDelta], + g_LJTop[nIndex][i][m_fBlockDistance], + g_LJTop[nIndex][i][m_fTrajectory], + g_LJTop[nIndex][i][m_nTimestamp]); + + for(new j; j < g_LJTop[nIndex][i][m_nStrafes] && j < LJTOP_MAX_STRAFES; j++) + { + decl String:strStrafeKey[4]; + GetStrafeKey(strStrafeKey, g_LJTop[nIndex][i][m_StrafeDir][j]); + Format(buf2, sizeof(buf2), "%s;%f;%f;%d;%f;", + strStrafeKey, + g_LJTop[nIndex][i][m_fStrafeGain][j], + g_LJTop[nIndex][i][m_fStrafeLoss][j], + g_LJTop[nIndex][i][m_nStrafeTicks][j], + g_LJTop[nIndex][i][m_fStrafeSync][j]); + + StrCat(buf, sizeof(buf), buf2); + } + + if(!WriteFileLine(hFile, buf)) + { + PrintToServer("[LJTop] Error writing to %s", strPath); + PrintToChatAll("[LJTop] Error saving ljtop"); + } + } + } + + CloseHandle(hFile); }*/ GetStrafeKey(String:str[], STRAFE_DIRECTION:Dir) { - if(Dir == SD_W) - { - strcopy(str, 3, "W"); - } - else if(Dir == SD_A) - { - strcopy(str, 3, "A"); - } - else if(Dir == SD_S) - { - strcopy(str, 3, "S"); - } - else if(Dir == SD_D) - { - strcopy(str, 3, "D"); - } - else if(Dir == SD_WA) - { - strcopy(str, 3, "WA"); - } - else if(Dir == SD_WD) - { - strcopy(str, 3, "WD"); - } - else if(Dir == SD_SA) - { - strcopy(str, 3, "SA"); - } - else if(Dir == SD_SD) - { - strcopy(str, 3, "SD"); - } + if(Dir == SD_W) + { + strcopy(str, 3, "W"); + } + else if(Dir == SD_A) + { + strcopy(str, 3, "A"); + } + else if(Dir == SD_S) + { + strcopy(str, 3, "S"); + } + else if(Dir == SD_D) + { + strcopy(str, 3, "D"); + } + else if(Dir == SD_WA) + { + strcopy(str, 3, "WA"); + } + else if(Dir == SD_WD) + { + strcopy(str, 3, "WD"); + } + else if(Dir == SD_SA) + { + strcopy(str, 3, "SA"); + } + else if(Dir == SD_SD) + { + strcopy(str, 3, "SD"); + } } STRAFE_DIRECTION:GetStrafeDir(String:str[]) { - if(!strcmp(str, "W")) - { - return SD_W; - } - else if(!strcmp(str, "A")) - { - return SD_A; - } - else if(!strcmp(str, "S")) - { - return SD_S; - } - else if(!strcmp(str, "D")) - { - return SD_D; - } - else if(!strcmp(str, "WA")) - { - return SD_WA; - } - else if(!strcmp(str, "WD")) - { - return SD_WD; - } - else if(!strcmp(str, "SA")) - { - return SD_SA; - } - else if(!strcmp(str, "SD")) - { - return SD_SD; - } - - return SD_NONE; + if(!strcmp(str, "W")) + { + return SD_W; + } + else if(!strcmp(str, "A")) + { + return SD_A; + } + else if(!strcmp(str, "S")) + { + return SD_S; + } + else if(!strcmp(str, "D")) + { + return SD_D; + } + else if(!strcmp(str, "WA")) + { + return SD_WA; + } + else if(!strcmp(str, "WD")) + { + return SD_WD; + } + else if(!strcmp(str, "SA")) + { + return SD_SA; + } + else if(!strcmp(str, "SD")) + { + return SD_SD; + } + + return SD_NONE; } LJTopMoveDown(LJTOP_TABLE:nIndex, nOldPos, nPos) { - // move entries down for insertion - for(new i = nOldPos - 1; i >= nPos; i--) - { - strcopy(g_LJTop[nIndex][i + 1][m_strName], 64, g_LJTop[nIndex][i][m_strName]); - strcopy(g_LJTop[nIndex][i + 1][m_strSteamID], 32, g_LJTop[nIndex][i][m_strSteamID]); - g_LJTop[nIndex][i + 1][m_fDistance] = g_LJTop[nIndex][i][m_fDistance]; - g_LJTop[nIndex][i + 1][m_fPrestrafe] = g_LJTop[nIndex][i][m_fPrestrafe]; - g_LJTop[nIndex][i + 1][m_nStrafes] = g_LJTop[nIndex][i][m_nStrafes]; - g_LJTop[nIndex][i + 1][m_fSync] = g_LJTop[nIndex][i][m_fSync]; - g_LJTop[nIndex][i + 1][m_fMaxSpeed] = g_LJTop[nIndex][i][m_fMaxSpeed]; - g_LJTop[nIndex][i + 1][m_nTotalTicks] = g_LJTop[nIndex][i][m_nTotalTicks]; - g_LJTop[nIndex][i + 1][m_fSyncedAngle] = g_LJTop[nIndex][i][m_fSyncedAngle]; - g_LJTop[nIndex][i + 1][m_fTotalAngle] = g_LJTop[nIndex][i][m_fTotalAngle]; - g_LJTop[nIndex][i + 1][m_fHeightDelta] = g_LJTop[nIndex][i][m_fHeightDelta]; - g_LJTop[nIndex][i + 1][m_fBlockDistance] = g_LJTop[nIndex][i][m_fBlockDistance]; - g_LJTop[nIndex][i + 1][m_fTrajectory] = g_LJTop[nIndex][i][m_fTrajectory]; - g_LJTop[nIndex][i + 1][m_nTimestamp] = g_LJTop[nIndex][i][m_nTimestamp]; - - for(new j; j < g_LJTop[nIndex][i][m_nStrafes]; j++) - { - g_LJTop[nIndex][i + 1][m_StrafeDir][j] = g_LJTop[nIndex][i][m_StrafeDir][j]; - g_LJTop[nIndex][i + 1][m_fStrafeGain][j] = g_LJTop[nIndex][i][m_fStrafeGain][j]; - g_LJTop[nIndex][i + 1][m_fStrafeLoss][j] = g_LJTop[nIndex][i][m_fStrafeLoss][j]; - g_LJTop[nIndex][i + 1][m_nStrafeTicks][j] = g_LJTop[nIndex][i][m_nStrafeTicks][j]; - g_LJTop[nIndex][i + 1][m_fStrafeSync][j] = g_LJTop[nIndex][i][m_fStrafeSync][j]; - } - } + // move entries down for insertion + for(new i = nOldPos - 1; i >= nPos; i--) + { + strcopy(g_LJTop[nIndex][i + 1][m_strName], 64, g_LJTop[nIndex][i][m_strName]); + strcopy(g_LJTop[nIndex][i + 1][m_strSteamID], 32, g_LJTop[nIndex][i][m_strSteamID]); + g_LJTop[nIndex][i + 1][m_fDistance] = g_LJTop[nIndex][i][m_fDistance]; + g_LJTop[nIndex][i + 1][m_fPrestrafe] = g_LJTop[nIndex][i][m_fPrestrafe]; + g_LJTop[nIndex][i + 1][m_nStrafes] = g_LJTop[nIndex][i][m_nStrafes]; + g_LJTop[nIndex][i + 1][m_fSync] = g_LJTop[nIndex][i][m_fSync]; + g_LJTop[nIndex][i + 1][m_fMaxSpeed] = g_LJTop[nIndex][i][m_fMaxSpeed]; + g_LJTop[nIndex][i + 1][m_nTotalTicks] = g_LJTop[nIndex][i][m_nTotalTicks]; + g_LJTop[nIndex][i + 1][m_fSyncedAngle] = g_LJTop[nIndex][i][m_fSyncedAngle]; + g_LJTop[nIndex][i + 1][m_fTotalAngle] = g_LJTop[nIndex][i][m_fTotalAngle]; + g_LJTop[nIndex][i + 1][m_fHeightDelta] = g_LJTop[nIndex][i][m_fHeightDelta]; + g_LJTop[nIndex][i + 1][m_fBlockDistance] = g_LJTop[nIndex][i][m_fBlockDistance]; + g_LJTop[nIndex][i + 1][m_fTrajectory] = g_LJTop[nIndex][i][m_fTrajectory]; + g_LJTop[nIndex][i + 1][m_nTimestamp] = g_LJTop[nIndex][i][m_nTimestamp]; + + for(new j; j < g_LJTop[nIndex][i][m_nStrafes]; j++) + { + g_LJTop[nIndex][i + 1][m_StrafeDir][j] = g_LJTop[nIndex][i][m_StrafeDir][j]; + g_LJTop[nIndex][i + 1][m_fStrafeGain][j] = g_LJTop[nIndex][i][m_fStrafeGain][j]; + g_LJTop[nIndex][i + 1][m_fStrafeLoss][j] = g_LJTop[nIndex][i][m_fStrafeLoss][j]; + g_LJTop[nIndex][i + 1][m_nStrafeTicks][j] = g_LJTop[nIndex][i][m_nStrafeTicks][j]; + g_LJTop[nIndex][i + 1][m_fStrafeSync][j] = g_LJTop[nIndex][i][m_fStrafeSync][j]; + } + } } LJTopMoveUp(LJTOP_TABLE:nIndex, nPos) { - for(new i = nPos; i < 9; i++) - { - strcopy(g_LJTop[nIndex][i][m_strName], 64, g_LJTop[nIndex][i + 1][m_strName]); - strcopy(g_LJTop[nIndex][i][m_strSteamID], 32, g_LJTop[nIndex][i + 1][m_strSteamID]); - g_LJTop[nIndex][i][m_fDistance] = g_LJTop[nIndex][i + 1][m_fDistance]; - g_LJTop[nIndex][i][m_fPrestrafe] = g_LJTop[nIndex][i + 1][m_fPrestrafe]; - g_LJTop[nIndex][i][m_nStrafes] = g_LJTop[nIndex][i + 1][m_nStrafes]; - g_LJTop[nIndex][i][m_fSync] = g_LJTop[nIndex][i + 1][m_fSync]; - g_LJTop[nIndex][i][m_fMaxSpeed] = g_LJTop[nIndex][i + 1][m_fMaxSpeed]; - g_LJTop[nIndex][i][m_nTotalTicks] = g_LJTop[nIndex][i + 1][m_nTotalTicks]; - g_LJTop[nIndex][i][m_fSyncedAngle] = g_LJTop[nIndex][i + 1][m_fSyncedAngle]; - g_LJTop[nIndex][i][m_fTotalAngle] = g_LJTop[nIndex][i + 1][m_fTotalAngle]; - g_LJTop[nIndex][i][m_fHeightDelta] = g_LJTop[nIndex][i + 1][m_fHeightDelta]; - g_LJTop[nIndex][i][m_fBlockDistance] = g_LJTop[nIndex][i + 1][m_fBlockDistance]; - g_LJTop[nIndex][i][m_fTrajectory] = g_LJTop[nIndex][i + 1][m_fTrajectory]; - g_LJTop[nIndex][i][m_nTimestamp] = g_LJTop[nIndex][i + 1][m_nTimestamp]; - - for(new j; j < g_LJTop[nIndex][i + 1][m_nStrafes]; j++) - { - g_LJTop[nIndex][i][m_StrafeDir][j] = g_LJTop[nIndex][i + 1][m_StrafeDir][j]; - g_LJTop[nIndex][i][m_fStrafeGain][j] = g_LJTop[nIndex][i + 1][m_fStrafeGain][j]; - g_LJTop[nIndex][i][m_fStrafeLoss][j] = g_LJTop[nIndex][i + 1][m_fStrafeLoss][j]; - g_LJTop[nIndex][i][m_nStrafeTicks][j] = g_LJTop[nIndex][i + 1][m_nStrafeTicks][j]; - g_LJTop[nIndex][i][m_fStrafeSync][j] = g_LJTop[nIndex][i + 1][m_fStrafeSync][j]; - } - } - - // Clear last entry to prevent duplicates - strcopy(g_LJTop[nIndex][9][m_strName], 64, ""); - strcopy(g_LJTop[nIndex][9][m_strSteamID], 32, ""); - g_LJTop[nIndex][9][m_fDistance] = 0.0; - g_LJTop[nIndex][9][m_fPrestrafe] = 0.0; - g_LJTop[nIndex][9][m_nStrafes] = 0; - g_LJTop[nIndex][9][m_fSync] = 0.0; - g_LJTop[nIndex][9][m_fMaxSpeed] = 0.0; - g_LJTop[nIndex][9][m_nTotalTicks] = 0; - g_LJTop[nIndex][9][m_fSyncedAngle] = 0.0; - g_LJTop[nIndex][9][m_fTotalAngle] = 0.0; - g_LJTop[nIndex][9][m_fHeightDelta] = 0.0; - g_LJTop[nIndex][9][m_fBlockDistance] = 0.0; - g_LJTop[nIndex][9][m_nTimestamp] = 0; - - for(new j; j < g_LJTop[nIndex][9][m_nStrafes]; j++) - { - g_LJTop[nIndex][9][m_StrafeDir][j] = SD_NONE; - g_LJTop[nIndex][9][m_fStrafeGain][j] = 0.0; - g_LJTop[nIndex][9][m_fStrafeLoss][j] = 0.0; - g_LJTop[nIndex][9][m_nStrafeTicks][j] = 0; - g_LJTop[nIndex][9][m_fStrafeSync][j] = 0.0; - } + for(new i = nPos; i < 9; i++) + { + strcopy(g_LJTop[nIndex][i][m_strName], 64, g_LJTop[nIndex][i + 1][m_strName]); + strcopy(g_LJTop[nIndex][i][m_strSteamID], 32, g_LJTop[nIndex][i + 1][m_strSteamID]); + g_LJTop[nIndex][i][m_fDistance] = g_LJTop[nIndex][i + 1][m_fDistance]; + g_LJTop[nIndex][i][m_fPrestrafe] = g_LJTop[nIndex][i + 1][m_fPrestrafe]; + g_LJTop[nIndex][i][m_nStrafes] = g_LJTop[nIndex][i + 1][m_nStrafes]; + g_LJTop[nIndex][i][m_fSync] = g_LJTop[nIndex][i + 1][m_fSync]; + g_LJTop[nIndex][i][m_fMaxSpeed] = g_LJTop[nIndex][i + 1][m_fMaxSpeed]; + g_LJTop[nIndex][i][m_nTotalTicks] = g_LJTop[nIndex][i + 1][m_nTotalTicks]; + g_LJTop[nIndex][i][m_fSyncedAngle] = g_LJTop[nIndex][i + 1][m_fSyncedAngle]; + g_LJTop[nIndex][i][m_fTotalAngle] = g_LJTop[nIndex][i + 1][m_fTotalAngle]; + g_LJTop[nIndex][i][m_fHeightDelta] = g_LJTop[nIndex][i + 1][m_fHeightDelta]; + g_LJTop[nIndex][i][m_fBlockDistance] = g_LJTop[nIndex][i + 1][m_fBlockDistance]; + g_LJTop[nIndex][i][m_fTrajectory] = g_LJTop[nIndex][i + 1][m_fTrajectory]; + g_LJTop[nIndex][i][m_nTimestamp] = g_LJTop[nIndex][i + 1][m_nTimestamp]; + + for(new j; j < g_LJTop[nIndex][i + 1][m_nStrafes]; j++) + { + g_LJTop[nIndex][i][m_StrafeDir][j] = g_LJTop[nIndex][i + 1][m_StrafeDir][j]; + g_LJTop[nIndex][i][m_fStrafeGain][j] = g_LJTop[nIndex][i + 1][m_fStrafeGain][j]; + g_LJTop[nIndex][i][m_fStrafeLoss][j] = g_LJTop[nIndex][i + 1][m_fStrafeLoss][j]; + g_LJTop[nIndex][i][m_nStrafeTicks][j] = g_LJTop[nIndex][i + 1][m_nStrafeTicks][j]; + g_LJTop[nIndex][i][m_fStrafeSync][j] = g_LJTop[nIndex][i + 1][m_fStrafeSync][j]; + } + } + + // Clear last entry to prevent duplicates + strcopy(g_LJTop[nIndex][9][m_strName], 64, ""); + strcopy(g_LJTop[nIndex][9][m_strSteamID], 32, ""); + g_LJTop[nIndex][9][m_fDistance] = 0.0; + g_LJTop[nIndex][9][m_fPrestrafe] = 0.0; + g_LJTop[nIndex][9][m_nStrafes] = 0; + g_LJTop[nIndex][9][m_fSync] = 0.0; + g_LJTop[nIndex][9][m_fMaxSpeed] = 0.0; + g_LJTop[nIndex][9][m_nTotalTicks] = 0; + g_LJTop[nIndex][9][m_fSyncedAngle] = 0.0; + g_LJTop[nIndex][9][m_fTotalAngle] = 0.0; + g_LJTop[nIndex][9][m_fHeightDelta] = 0.0; + g_LJTop[nIndex][9][m_fBlockDistance] = 0.0; + g_LJTop[nIndex][9][m_nTimestamp] = 0; + + for(new j; j < g_LJTop[nIndex][9][m_nStrafes]; j++) + { + g_LJTop[nIndex][9][m_StrafeDir][j] = SD_NONE; + g_LJTop[nIndex][9][m_fStrafeGain][j] = 0.0; + g_LJTop[nIndex][9][m_fStrafeLoss][j] = 0.0; + g_LJTop[nIndex][9][m_nStrafeTicks][j] = 0; + g_LJTop[nIndex][9][m_fStrafeSync][j] = 0.0; + } } LJTopUpdate(client) { - if(g_PlayerStates[client][JumpType] == JT_LONGJUMP) - { - if(g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_LJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) - { - LJTopUpdateTable(client, LT_LJ); - } - if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_SWLJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) - { - LJTopUpdateTable(client, LT_SWLJ); - } - if(g_PlayerStates[client][JumpDir] == JD_BACKWARDS && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_BWLJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) - { - LJTopUpdateTable(client, LT_BWLJ); - } - } - else if(g_PlayerStates[client][JumpType] == JT_COUNTJUMP && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_CJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) - { - LJTopUpdateTable(client, LT_CJ); - } - else if(g_PlayerStates[client][JumpType] == JT_BHOPJUMP && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_BJ][LJTOP_NUM_ENTRIES - 1][m_fDistance] && (!g_PlayerStates[client][bStamina] || g_bLJTopAllowEasyBJ)) // There's no such thing as an easy bj, only sore jaws, pubes down your throat and the taste of acidic ejaculate - { - LJTopUpdateTable(client, LT_BJ); - } - else if(g_PlayerStates[client][JumpType] == JT_LADDERJUMP && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_LAJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) - { - LJTopUpdateTable(client, LT_LAJ); - } -} - + if(g_PlayerStates[client][JumpType] == JT_LONGJUMP) + { + if(g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_LJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) + { + LJTopUpdateTable(client, LT_LJ); + } + if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_SWLJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) + { + LJTopUpdateTable(client, LT_SWLJ); + } + if(g_PlayerStates[client][JumpDir] == JD_BACKWARDS && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_BWLJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) + { + LJTopUpdateTable(client, LT_BWLJ); + } + } + else if(g_PlayerStates[client][JumpType] == JT_COUNTJUMP && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_CJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) + { + LJTopUpdateTable(client, LT_CJ); + } + else if(g_PlayerStates[client][JumpType] == JT_BHOPJUMP && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_BJ][LJTOP_NUM_ENTRIES - 1][m_fDistance] && (!g_PlayerStates[client][bStamina] || g_bLJTopAllowEasyBJ)) // There's no such thing as an easy bj, only sore jaws, pubes down your throat and the taste of acidic ejaculate + { + LJTopUpdateTable(client, LT_BJ); + } + else if(g_PlayerStates[client][JumpType] == JT_LADDERJUMP && g_PlayerStates[client][fJumpDistance] > g_LJTop[LT_LAJ][LJTOP_NUM_ENTRIES - 1][m_fDistance]) + { + LJTopUpdateTable(client, LT_LAJ); + } +} + +GetStrafeString( String:buffer[], maxlength, Float:percentage ) { + if( percentage > 0.5 && percentage <= 1.5 ){ + new spaces = RoundFloat( (percentage - 0.5) / 0.05 ); + for( new i = 0; i <= spaces + 1; i++ ) { + FormatEx(buffer, maxlength, "%s ", buffer); + } + + FormatEx(buffer, maxlength, "%s|", buffer); + + for( new i = 0; i <= (21 - spaces); i++ ) { + FormatEx(buffer, maxlength, "%s ", buffer); + } + } + else + Format(buffer, maxlength, "%s", percentage < 1.0 ? "| " : " |"); +} + +StrafeTrainer( client, bool: onGround, Float:angles[3], Float:velocity[3] ) { + if( !g_PlayerStates[client][bStrafeTrainer] || !IsPlayerAlive( client ) ) + return; + + if( onGround ) + return; + + if( g_PlayerStates[client][bOnLadder] ) + return; + + new Float:velocity2d[3]; + Array_Copy( velocity, velocity2d, 2 ); + new Float:speed = GetVectorLength( velocity2d ); + + new Float:surf_friction = 1.0; + if( velocity[2] > 0 && velocity[2] < 140.0 ) + surf_friction = 0.25; + + new Float:perfAngle = RadToDeg( ArcTangent( 30.0 * surf_friction / speed ) ); + new Float:curAngle = angles[1]; + new Float:diff = g_PlayerStates[client][vLastAngles][1] - curAngle; + while( diff > 180.0 ) + diff -= 360.0; + while( diff < -180.0 ) + diff += 360.0; + + new Float:percentage = FloatAbs(diff / perfAngle) * 100; + if( g_PlayerStates[client][nTrainerTicks] >= STRAFE_TRAINER_TICKS ) { + new Float:AvgPercentage = 0.0; + + for( new i = 0; i < STRAFE_TRAINER_TICKS; ++i ) { + AvgPercentage += g_PlayerStates[client][fStrafePercentages][i]; + g_PlayerStates[client][fStrafePercentages][i] = 0.0; + } + + AvgPercentage /= STRAFE_TRAINER_TICKS; + + new String:msg[256], String:strafe[32]; + GetStrafeString( strafe, sizeof(strafe), AvgPercentage * 0.01 ); + + Format(msg, sizeof(msg), "%d\%", RoundFloat(AvgPercentage)); + Format(msg, sizeof(msg), "%s\n══════^══════", msg); + Format(msg, sizeof(msg), "%s\n %s ", msg, strafe); + Format(msg, sizeof(msg), "%s\n══════^══════", msg); + + new Float:offset = FloatAbs( 1.0 - AvgPercentage * 0.01 ); + new r, g, b; + + if( offset < 0.05 ) { + r = 0; + g = 255; + b = 0; + } + else if( 0.05 <= offset < 0.1 ) { + r = 128; + g = 255; + b = 0; + } + else if( 0.1 <= offset < 0.25 ) { + r = 255; + g = 255; + b = 0; + } + else if( 0.25 <= offset < 0.5 ) { + r = 255; + g = 128; + b = 0; + } + else { + r = 255; + g = 0; + b = 0; + } + + new Handle:hText = CreateHudSynchronizer(); + if(hText != INVALID_HANDLE) + { + SetHudTextParams(-1.0, 0.2, GetTickInterval() * (STRAFE_TRAINER_TICKS+1), r, g, b, 255, 0, 0.0, 0.0, 0.1); + ShowSyncHudText(client, hText, msg); + CloseHandle(hText); + } + + g_PlayerStates[client][nTrainerTicks] = 0; + } + + new tick = g_PlayerStates[client][nTrainerTicks]; + g_PlayerStates[client][fStrafePercentages][tick] = percentage; + g_PlayerStates[client][nTrainerTicks]++; +} + +Speedometer( client, bool: bJump, bool: bGround, Float:velocity[3] ) { + + new Float:speed = GetVectorLength( velocity ); + new String:sBuffer[64]; + + if( (g_PlayerStates[client][bOnGround] || g_PlayerStates[client][bOnLadder]) && !bJump ) { + g_PlayerStates[client][fJumpSpeed] = speed; + } + + if( (!g_PlayerStates[client][bOnGround]) && bGround && bJump ) { + g_PlayerStates[client][bPerf] = true; + g_PlayerStates[client][fJumpSpeed] = speed; + } + else if( bGround || g_PlayerStates[client][bOnLadder] ) { + g_PlayerStates[client][bPerf] = false; + g_PlayerStates[client][fJumpSpeed] = speed; + } + + if( !g_PlayerStates[client][nSpeedometer] ) + return; + + Format(sBuffer, sizeof(sBuffer), "%.0f", speed ); + if( !bGround && !g_PlayerStates[client][bOnLadder] ) { + Format(sBuffer, sizeof(sBuffer), "%s\n(%.0f)", sBuffer, g_PlayerStates[client][fJumpSpeed] ); + } + + new r, g, b; + if( g_PlayerStates[client][bPerf] ) { + r = b = 0; + g = 255; + } + else { + r = 255; + g = 255; + b = 255; + } + + switch( g_PlayerStates[client][nSpeedometer] ) { + case 1: { + SetHudTextParams(-1.0, 0.325, 0.05, r, g, b, 255, 0, 0.0, 0.0, 0.0); + ShowHudText(client, 1, sBuffer); + } + + case 2: { + SetHudTextParams(-1.0, 0.85, 0.05, r, g, b, 255, 0, 0.0, 0.0, 0.0); + ShowHudText(client, 1, sBuffer); + } + } +} + LJTopUpdateTable(client, LJTOP_TABLE:nLJTopTable) { - decl String:strName[64], String:strSteamID[32]; - GetClientName(client, strName, sizeof(strName)); - GetClientAuthString(client, strSteamID, sizeof(strSteamID)); - - decl nIndex; - while((nIndex = FindCharInString(strName, ';')) != -1) - { - strName[nIndex] = '-'; - } - - new nPos = 0; - - while(nPos < 9 && g_PlayerStates[client][fJumpDistance] < g_LJTop[nLJTopTable][nPos][m_fDistance]) // longest statement in history - { - if(!strcmp(g_LJTop[nLJTopTable][nPos][m_strSteamID], strSteamID)) - { - // player already has better record - g_LJTop[nLJTopTable][nPos][m_strName] = strName; // update name - return; - } - - nPos++; - } - - new nOldPos = -1; - - for(new i = 0; i < 10; i++) - { - if(!strcmp(g_LJTop[nLJTopTable][i][m_strSteamID], strSteamID)) - { - nOldPos = i; - break; - } - } - - new bool:bSilent; - - if(g_PlayerStates[client][fJumpDistance] < g_fLJMin) - { - bSilent = true; - } - - /* - enum TopStats - { - String:m_strName[64 / 4], - String:m_strSteamID[32 / 4], - Float:m_fDistance, - Float:m_fPrestrafe, - m_nStrafes, - Float:m_fSync, - Float:m_fMaxSpeed, - m_nTotalTicks, - Float:m_fSyncedAngle, - Float:m_fTotalAngle, - Float:m_fHeightDelta, - Float:m_fBlockDistance, - Float:m_fTrajectory, - m_nTimestamp, - - m_StrafeDir[LJTOP_MAX_STRAFES], - Float:m_fStrafeGain[LJTOP_MAX_STRAFES], - Float:m_fStrafeLoss[LJTOP_MAX_STRAFES], - m_nStrafeTicks[LJTOP_MAX_STRAFES], - Float:m_fStrafeSync[LJTOP_MAX_STRAFES], - } - */ - - LJTopMoveDown(nLJTopTable, nOldPos == -1 ? 9 : nOldPos, nPos); - - // overwrite entry - strcopy(g_LJTop[nLJTopTable][nPos][m_strName], 64, strName); - strcopy(g_LJTop[nLJTopTable][nPos][m_strSteamID], 32, strSteamID); - g_LJTop[nLJTopTable][nPos][m_fDistance] = g_PlayerStates[client][fJumpDistance]; - g_LJTop[nLJTopTable][nPos][m_fPrestrafe] = g_PlayerStates[client][fPrestrafe]; - g_LJTop[nLJTopTable][nPos][m_nStrafes] = g_PlayerStates[client][nStrafes]; - g_LJTop[nLJTopTable][nPos][m_fSync] = g_PlayerStates[client][fSync]; - g_LJTop[nLJTopTable][nPos][m_fMaxSpeed] = g_PlayerStates[client][fMaxSpeed]; - g_LJTop[nLJTopTable][nPos][m_nTotalTicks] = g_PlayerStates[client][nTotalTicks]; - g_LJTop[nLJTopTable][nPos][m_fSyncedAngle] = g_PlayerStates[client][fSyncedAngle]; - g_LJTop[nLJTopTable][nPos][m_fTotalAngle] = g_PlayerStates[client][fTotalAngle]; - g_LJTop[nLJTopTable][nPos][m_fHeightDelta] = g_PlayerStates[client][fHeightDelta]; - g_LJTop[nLJTopTable][nPos][m_fBlockDistance] = g_PlayerStates[client][fBlockDistance]; - g_LJTop[nLJTopTable][nPos][m_fTrajectory] = g_PlayerStates[client][fTrajectory]; - g_LJTop[nLJTopTable][nPos][m_nTimestamp] = GetTime(); - - for(new j; j < g_PlayerStates[client][nStrafes]; j++) - { - g_LJTop[nLJTopTable][nPos][m_StrafeDir][j] = g_PlayerStates[client][StrafeDir][j]; - g_LJTop[nLJTopTable][nPos][m_fStrafeGain][j] = g_PlayerStates[client][fStrafeGain][j]; - g_LJTop[nLJTopTable][nPos][m_fStrafeLoss][j] = g_PlayerStates[client][fStrafeLoss][j]; - g_LJTop[nLJTopTable][nPos][m_nStrafeTicks][j] = g_PlayerStates[client][nStrafeTicks][j]; - g_LJTop[nLJTopTable][nPos][m_fStrafeSync][j] = g_PlayerStates[client][fStrafeSync][j]; - } - - LJTopSave(); - LJTopCreateMenu(nLJTopTable); - - if(bSilent) - { - return; - } - + decl String:strName[64], String:strSteamID[32]; + GetClientName(client, strName, sizeof(strName)); + GetClientAuthString(client, strSteamID, sizeof(strSteamID)); + + decl nIndex; + while((nIndex = FindCharInString(strName, ';')) != -1) + { + strName[nIndex] = '-'; + } + + new nPos = 0; + + while(nPos < 9 && g_PlayerStates[client][fJumpDistance] < g_LJTop[nLJTopTable][nPos][m_fDistance]) // longest statement in history + { + if(!strcmp(g_LJTop[nLJTopTable][nPos][m_strSteamID], strSteamID)) + { + // player already has better record + g_LJTop[nLJTopTable][nPos][m_strName] = strName; // update name + return; + } + + nPos++; + } + + new nOldPos = -1; + + for(new i = 0; i < 10; i++) + { + if(!strcmp(g_LJTop[nLJTopTable][i][m_strSteamID], strSteamID)) + { + nOldPos = i; + break; + } + } + + new bool:bSilent; + + if(g_PlayerStates[client][fJumpDistance] < g_fLJMin) + { + bSilent = true; + } + + /* + enum TopStats + { + String:m_strName[64 / 4], + String:m_strSteamID[32 / 4], + Float:m_fDistance, + Float:m_fPrestrafe, + m_nStrafes, + Float:m_fSync, + Float:m_fMaxSpeed, + m_nTotalTicks, + Float:m_fSyncedAngle, + Float:m_fTotalAngle, + Float:m_fHeightDelta, + Float:m_fBlockDistance, + Float:m_fTrajectory, + m_nTimestamp, + + m_StrafeDir[LJTOP_MAX_STRAFES], + Float:m_fStrafeGain[LJTOP_MAX_STRAFES], + Float:m_fStrafeLoss[LJTOP_MAX_STRAFES], + m_nStrafeTicks[LJTOP_MAX_STRAFES], + Float:m_fStrafeSync[LJTOP_MAX_STRAFES], + } + */ + + LJTopMoveDown(nLJTopTable, nOldPos == -1 ? 9 : nOldPos, nPos); + + // overwrite entry + strcopy(g_LJTop[nLJTopTable][nPos][m_strName], 64, strName); + strcopy(g_LJTop[nLJTopTable][nPos][m_strSteamID], 32, strSteamID); + g_LJTop[nLJTopTable][nPos][m_fDistance] = g_PlayerStates[client][fJumpDistance]; + g_LJTop[nLJTopTable][nPos][m_fPrestrafe] = g_PlayerStates[client][fPrestrafe]; + g_LJTop[nLJTopTable][nPos][m_nStrafes] = g_PlayerStates[client][nStrafes]; + g_LJTop[nLJTopTable][nPos][m_fSync] = g_PlayerStates[client][fSync]; + g_LJTop[nLJTopTable][nPos][m_fMaxSpeed] = g_PlayerStates[client][fMaxSpeed]; + g_LJTop[nLJTopTable][nPos][m_nTotalTicks] = g_PlayerStates[client][nTotalTicks]; + g_LJTop[nLJTopTable][nPos][m_fSyncedAngle] = g_PlayerStates[client][fSyncedAngle]; + g_LJTop[nLJTopTable][nPos][m_fTotalAngle] = g_PlayerStates[client][fTotalAngle]; + g_LJTop[nLJTopTable][nPos][m_fHeightDelta] = g_PlayerStates[client][fHeightDelta]; + g_LJTop[nLJTopTable][nPos][m_fBlockDistance] = g_PlayerStates[client][fBlockDistance]; + g_LJTop[nLJTopTable][nPos][m_fTrajectory] = g_PlayerStates[client][fTrajectory]; + g_LJTop[nLJTopTable][nPos][m_nTimestamp] = GetTime(); + + for(new j; j < g_PlayerStates[client][nStrafes]; j++) + { + g_LJTop[nLJTopTable][nPos][m_StrafeDir][j] = g_PlayerStates[client][StrafeDir][j]; + g_LJTop[nLJTopTable][nPos][m_fStrafeGain][j] = g_PlayerStates[client][fStrafeGain][j]; + g_LJTop[nLJTopTable][nPos][m_fStrafeLoss][j] = g_PlayerStates[client][fStrafeLoss][j]; + g_LJTop[nLJTopTable][nPos][m_nStrafeTicks][j] = g_PlayerStates[client][nStrafeTicks][j]; + g_LJTop[nLJTopTable][nPos][m_fStrafeSync][j] = g_PlayerStates[client][fStrafeSync][j]; + } + + LJTopSave(); + LJTopCreateMenu(nLJTopTable); + + if(bSilent) + { + return; + } + CPrintToChatAll("%s {green}%s top {default}%d{green} in %s top with {default}%.2f{green} %s!", strName, nPos == nOldPos ? "has improved their" : "is now", nPos + 1, g_strLJTopOutput[nLJTopTable], g_PlayerStates[client][fJumpDistance], g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); } public Native_CancelJump(Handle:hPlugin, nParams) { - CancelJump(GetNativeCell(1)); + CancelJump(GetNativeCell(1)); } CancelJump(client) { - g_PlayerStates[client][bOnGround] = true; + g_PlayerStates[client][bOnGround] = true; } public Action:Event_PlayerJump(Handle:event, const String:name[], bool:dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "userid")); - - PlayerJump(client); + new client = GetClientOfUserId(GetEventInt(event, "userid")); + + PlayerJump(client); } public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) { new id = GetEventInt(event, "userid"); - g_PlayerStates[id][IllegalJumpFlags] = IJF_NOCLIP; + new client = GetClientOfUserId( id ); + g_PlayerStates[client][IllegalJumpFlags] = IJF_TELEPORT; +} + +public Action:Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) { + new id = GetEventInt(event, "userid"); + new client = GetClientOfUserId( id ); + g_PlayerStates[client][IllegalJumpFlags] = IJF_TELEPORT; } // cba with another enum so JT_LONGJUMP = jump, JT_DROP = slide off edge, JT_LADDERJUMP = ladder PlayerJump(client, JUMP_TYPE:JumpType2 = JT_LONGJUMP) { - g_PlayerStates[client][bOnGround] = false; - - new Float:fTime = GetGameTime(); - if(fTime - g_PlayerStates[client][fLandTime] < BHOP_TIME)//if((g_PlayerStates[client][nLastAerialTick] - GetGameTickCount()) * GetTickInterval() < BHOP_TIME) - { - g_PlayerStates[client][nBhops]++; - } - else - { - g_PlayerStates[client][nBhops] = 0; - - // Only reset flags when jump chain stops so that players can't e.g. boost in the first jump and get a high distance on the next in a bhopjump - g_PlayerStates[client][IllegalJumpFlags] = IJF_NONE; - } - - g_PlayerStates[client][fLastJumpHeightDelta] = g_PlayerStates[client][fHeightDelta]; - - for(new i = 0; i < g_PlayerStates[client][nStrafes] && i < MAX_STRAFES; i++) - { - g_PlayerStates[client][fStrafeGain][i] = 0.0; - g_PlayerStates[client][fStrafeLoss][i] = 0.0; - g_PlayerStates[client][fStrafeSync][i] = 0.0; - g_PlayerStates[client][nStrafeTicks][i] = 0; - g_PlayerStates[client][nStrafeTicksSynced][i] = 0; - } - - // Reset stuff - g_PlayerStates[client][JumpDir] = JD_NONE; - g_PlayerStates[client][CurStrafeDir] = SD_NONE; - g_PlayerStates[client][nStrafes] = 0; - g_PlayerStates[client][fSync] = 0.0; - g_PlayerStates[client][fMaxSpeed] = 0.0; - g_PlayerStates[client][fJumpHeight] = 0.0; - g_PlayerStates[client][nTotalTicks] = 0; - g_PlayerStates[client][fTotalAngle] = 0.0; - g_PlayerStates[client][fSyncedAngle] = 0.0; - g_PlayerStates[client][fEdge] = -1.0; - g_PlayerStates[client][fBlockDistance] = -1.0; - g_PlayerStates[client][bStamina] = !GetEntPropFloat(client, Prop_Send, "m_flStamina"); - g_PlayerStates[client][bFailedBlock] = false; - g_PlayerStates[client][fTrajectory] = 0.0; - g_PlayerStates[client][fGain] = 0.0; - g_PlayerStates[client][fLoss] = 0.0; - g_PlayerStates[client][nJumpTick] = GetGameTickCount(); - - if(JumpType2 == JT_LONGJUMP && g_PlayerStates[client][bBlockMode]) - { - g_PlayerStates[client][fBlockDistance] = GetBlockDistance(client); - } - - - g_PlayerStates[client][LastJumpType] = g_PlayerStates[client][JumpType]; - - // Determine jump type - if(JumpType2 == JT_DROP || JumpType2 == JT_LADDERJUMP) - { - g_PlayerStates[client][JumpType] = JumpType2; - } - else - { - if(g_PlayerStates[client][nBhops] > 1) - { - g_PlayerStates[client][JumpType] = JT_BHOP; - } - else if(g_PlayerStates[client][nBhops] == 1) - { - if(g_PlayerStates[client][LastJumpType] == JT_DROP) - { - g_PlayerStates[client][fWJDropPre] = g_PlayerStates[client][fPrestrafe]; - g_PlayerStates[client][JumpType] = JT_WEIRDJUMP; - } - else if(g_PlayerStates[client][fLastJumpHeightDelta] > HEIGHT_DELTA_MIN(JT_LONGJUMP)) - { - g_PlayerStates[client][JumpType] = JT_BHOPJUMP; - } - else - { - g_PlayerStates[client][JumpType] = JT_BHOP; - } - } - else - { - if(GetEntProp(client, Prop_Send, "m_bDucking", 1)) - { - g_PlayerStates[client][JumpType] = JT_COUNTJUMP; - } - else - { - g_PlayerStates[client][JumpType] = JT_LONGJUMP; - } - } - } - - // Jumpoff origin - new Float:vOrigin[3]; - GetClientAbsOrigin(client, vOrigin); - Array_Copy(vOrigin, g_PlayerStates[client][vJumpOrigin], 3); - - // Prestrafe - g_PlayerStates[client][fPrestrafe] = GetSpeed(client); - - if(g_PlayerStates[client][JumpType] == JT_LONGJUMP || g_PlayerStates[client][JumpType] == JT_COUNTJUMP) - { - if(g_PlayerStates[client][fPrestrafe] > g_fLJMaxPrestrafe) - { - g_PlayerStates[client][IllegalJumpFlags] |= IJF_PRESTRAFE; - } - - if(!g_bLJScoutStats && (g_fMaxspeed > 250.0 && GetEntPropFloat(client, Prop_Data, "m_flMaxspeed") > 250.0)) - { - new String:strPlayerWeapon[32]; - GetClientWeapon(client, strPlayerWeapon, sizeof(strPlayerWeapon)); - - if(!strcmp(strPlayerWeapon, "weapon_scout") || strPlayerWeapon[0] == 0) - { - g_PlayerStates[client][IllegalJumpFlags] |= IJF_SCOUT; - } - } - } - - if(JumpType2 == JT_LONGJUMP || g_PlayerStates[client][JumpType] == JT_COUNTJUMP) - { - g_PlayerStates[client][fEdge] = GetEdge(client); - } - - if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][bBeam]) - { - StopBeam(client); - - g_PlayerStates[client][bBeam] = true; - } + g_PlayerStates[client][bOnGround] = false; + + new Float:fTime = GetGameTime(); + if(fTime - g_PlayerStates[client][fLandTime] < BHOP_TIME)//if((g_PlayerStates[client][nLastAerialTick] - GetGameTickCount()) * GetTickInterval() < BHOP_TIME) + { + g_PlayerStates[client][nBhops]++; + } + else + { + g_PlayerStates[client][nBhops] = 0; + + // Only reset flags when jump chain stops so that players can't e.g. boost in the first jump and get a high distance on the next in a bhopjump + g_PlayerStates[client][IllegalJumpFlags] = IJF_NONE; + } + + g_PlayerStates[client][fLastJumpHeightDelta] = g_PlayerStates[client][fHeightDelta]; + + for(new i = 0; i < g_PlayerStates[client][nStrafes] && i < MAX_STRAFES; i++) + { + g_PlayerStates[client][fStrafeGain][i] = 0.0; + g_PlayerStates[client][fStrafeLoss][i] = 0.0; + g_PlayerStates[client][fStrafeSync][i] = 0.0; + g_PlayerStates[client][nStrafeTicks][i] = 0; + g_PlayerStates[client][nStrafeTicksSynced][i] = 0; + } + + // Reset stuff + g_PlayerStates[client][JumpDir] = JD_NONE; + g_PlayerStates[client][CurStrafeDir] = SD_NONE; + g_PlayerStates[client][nStrafes] = 0; + g_PlayerStates[client][fSync] = 0.0; + g_PlayerStates[client][fMaxSpeed] = 0.0; + g_PlayerStates[client][fJumpHeight] = 0.0; + g_PlayerStates[client][nTotalTicks] = 0; + g_PlayerStates[client][fTotalAngle] = 0.0; + g_PlayerStates[client][fSyncedAngle] = 0.0; + g_PlayerStates[client][fEdge] = -1.0; + g_PlayerStates[client][fBlockDistance] = -1.0; + g_PlayerStates[client][bStamina] = !GetEntPropFloat(client, Prop_Send, "m_flStamina"); + g_PlayerStates[client][bFailedBlock] = false; + g_PlayerStates[client][fTrajectory] = 0.0; + g_PlayerStates[client][fGain] = 0.0; + g_PlayerStates[client][fLoss] = 0.0; + g_PlayerStates[client][nJumpTick] = GetGameTickCount(); + + if(JumpType2 == JT_LONGJUMP && g_PlayerStates[client][bBlockMode]) + { + g_PlayerStates[client][fBlockDistance] = GetBlockDistance(client); + } + + + g_PlayerStates[client][LastJumpType] = g_PlayerStates[client][JumpType]; + + // Determine jump type + if(JumpType2 == JT_DROP || JumpType2 == JT_LADDERJUMP) + { + g_PlayerStates[client][JumpType] = JumpType2; + } + else + { + if(g_PlayerStates[client][nBhops] > 1) + { + g_PlayerStates[client][JumpType] = JT_BHOP; + } + else if(g_PlayerStates[client][nBhops] == 1) + { + if(g_PlayerStates[client][LastJumpType] == JT_DROP) + { + g_PlayerStates[client][fWJDropPre] = g_PlayerStates[client][fPrestrafe]; + g_PlayerStates[client][JumpType] = JT_WEIRDJUMP; + } + else if(g_PlayerStates[client][fLastJumpHeightDelta] > HEIGHT_DELTA_MIN(JT_LONGJUMP)) + { + g_PlayerStates[client][JumpType] = JT_BHOPJUMP; + } + else + { + g_PlayerStates[client][JumpType] = JT_BHOP; + } + } + else + { + if(GetEntProp(client, Prop_Send, "m_bDucking", 1)) + { + g_PlayerStates[client][JumpType] = JT_COUNTJUMP; + } + else + { + g_PlayerStates[client][JumpType] = JT_LONGJUMP; + } + } + } + + // Jumpoff origin + new Float:vOrigin[3]; + GetClientAbsOrigin(client, vOrigin); + Array_Copy(vOrigin, g_PlayerStates[client][vJumpOrigin], 3); + + // Prestrafe + g_PlayerStates[client][fPrestrafe] = GetSpeed(client); + + if(g_PlayerStates[client][JumpType] == JT_LONGJUMP || g_PlayerStates[client][JumpType] == JT_COUNTJUMP) + { + if(g_PlayerStates[client][fPrestrafe] > g_fLJMaxPrestrafe) + { + g_PlayerStates[client][IllegalJumpFlags] |= IJF_PRESTRAFE; + } + + if(!g_bLJScoutStats && (g_fMaxspeed > 250.0 && GetEntPropFloat(client, Prop_Data, "m_flMaxspeed") > 250.0)) + { + new String:strPlayerWeapon[32]; + GetClientWeapon(client, strPlayerWeapon, sizeof(strPlayerWeapon)); + + if(!strcmp(strPlayerWeapon, "weapon_scout") || strPlayerWeapon[0] == 0) + { + g_PlayerStates[client][IllegalJumpFlags] |= IJF_SCOUT; + } + } + } + + if(JumpType2 == JT_LONGJUMP || g_PlayerStates[client][JumpType] == JT_COUNTJUMP) + { + g_PlayerStates[client][fEdge] = GetEdge(client); + } + + if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][bBeam]) + { + StopBeam(client); + + g_PlayerStates[client][bBeam] = true; + } } StopBeam(client) { - g_PlayerStates[client][bBeam] = false; + g_PlayerStates[client][bBeam] = false; } GetJumpDistance(client) { - new Float:vCurOrigin[3]; - GetClientAbsOrigin(client, vCurOrigin); - - g_PlayerStates[client][fHeightDelta] = vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2]; - - vCurOrigin[2] = 0.0; - - new Float:v[3]; - Array_Copy(g_PlayerStates[client][vJumpOrigin], v, 3); - - v[2] = 0.0; - - if(g_PlayerStates[client][JumpType] == JT_LADDERJUMP) - { - g_PlayerStates[client][fJumpDistance] = GetVectorDistance(v, vCurOrigin); - } - else - { - g_PlayerStates[client][fJumpDistance] = GetVectorDistance(v, vCurOrigin) + 32; - } - - g_PlayerStates[client][bDuck] = bool:GetEntProp(client, Prop_Send, "m_bDucked", 1); - //g_PlayerStates[client][nTotalTicks] = GetGameTickCount() - g_PlayerStates[client][nJumpTick]; + new Float:vCurOrigin[3]; + GetClientAbsOrigin(client, vCurOrigin); + + g_PlayerStates[client][fHeightDelta] = vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2]; + + vCurOrigin[2] = 0.0; + + new Float:v[3]; + Array_Copy(g_PlayerStates[client][vJumpOrigin], v, 3); + + v[2] = 0.0; + + if(g_PlayerStates[client][JumpType] == JT_LADDERJUMP) + { + g_PlayerStates[client][fJumpDistance] = GetVectorDistance(v, vCurOrigin); + } + else + { + g_PlayerStates[client][fJumpDistance] = GetVectorDistance(v, vCurOrigin) + 32; + } + + g_PlayerStates[client][bDuck] = bool:GetEntProp(client, Prop_Send, "m_bDucked", 1); + //g_PlayerStates[client][nTotalTicks] = GetGameTickCount() - g_PlayerStates[client][nJumpTick]; } GetJumpDistanceLastTick(client) { - new Float:vCurOrigin[3]; - Array_Copy(g_PlayerStates[client][vLastOrigin], vCurOrigin, 3); - - g_PlayerStates[client][fHeightDelta] = vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2]; - - vCurOrigin[2] = 0.0; - - new Float:v[3]; - Array_Copy(g_PlayerStates[client][vJumpOrigin], v, 3); - - v[2] = 0.0; - - g_PlayerStates[client][fJumpDistance] = GetVectorDistance(v, vCurOrigin) + 32.0; - - g_PlayerStates[client][bDuck] = g_PlayerStates[client][bSecondLastDuckState]; - //g_PlayerStates[client][nTotalTicks] = GetGameTickCount() - g_PlayerStates[client][nJumpTick]; - //g_PlayerStates[client][nTotalTicks] -= 1; + new Float:vCurOrigin[3]; + Array_Copy(g_PlayerStates[client][vLastOrigin], vCurOrigin, 3); + + g_PlayerStates[client][fHeightDelta] = vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2]; + + vCurOrigin[2] = 0.0; + + new Float:v[3]; + Array_Copy(g_PlayerStates[client][vJumpOrigin], v, 3); + + v[2] = 0.0; + + g_PlayerStates[client][fJumpDistance] = GetVectorDistance(v, vCurOrigin) + 32.0; + + g_PlayerStates[client][bDuck] = g_PlayerStates[client][bSecondLastDuckState]; + //g_PlayerStates[client][nTotalTicks] = GetGameTickCount() - g_PlayerStates[client][nJumpTick]; + //g_PlayerStates[client][nTotalTicks] -= 1; } CheckValidJump(client) { - new Float:vOrigin[3]; - GetClientAbsOrigin(client, vOrigin); - - // Check gravity - new Float:fGravity = GetEntPropFloat(client, Prop_Data, "m_flGravity"); - if(fGravity != 1.0 && fGravity != 0.0) - { - g_PlayerStates[client][IllegalJumpFlags] |= IJF_GRAVITY; - } - - // Check speed - if(GetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue") != 1.0) - { - g_PlayerStates[client][IllegalJumpFlags] |= IJF_LAGGEDMOVEMENTVALUE; - } - - if(GetEntityMoveType(client) & MOVETYPE_NOCLIP) - { - g_PlayerStates[client][IllegalJumpFlags] |= IJF_NOCLIP; - } - - - // Teleport check - new Float:vLastOrig[3], Float:vLastVel[3], Float:vVel[3]; - Array_Copy(g_PlayerStates[client][vLastOrigin], vLastOrig, 3); - Array_Copy(g_PlayerStates[client][vLastVelocity], vLastVel, 3); - GetEntPropVector(client, Prop_Data, "m_vecVelocity", vVel); - - vLastOrig[2] = 0.0; - vOrigin[2] = 0.0; - vLastVel[2] = 0.0; - vVel[2] = 0.0; - - // If the player moved further than their last velocity, they teleported - // It's slightly off, so adjust velocity - // pretty suk // less suk - /* - teleported 2.461413, 2.461400 - teleported 2.468606, 2.468604 - teleported 2.488778, 2.488739 - teleported 2.517628, 2.517453 - teleported 2.534332, 2.534170 - teleported 2.550610, 2.550508 - teleported 2.567417, 2.567395 - teleported 2.598604, 2.598514 - teleported 2.612708, 2.612616 - teleported 2.633581, 2.633533 - teleported 2.634170, 2.634044 - teleported 2.646703, 2.646473 - teleported 2.657407, 2.657327 - teleported 2.669471, 2.669248 - teleported 2.710047, 2.709968 - teleported 2.723108, 2.722937 - teleported 2.742104, 2.742006 - teleported 2.744069, 2.743859 - teleported 2.751010, 2.750807 - teleported 2.759773, 2.759721 - teleported 2.771660, 2.771600 - teleported 2.822698, 2.822640 - teleported 2.839976, 2.839771 - teleported 2.839976, 2.839771 - teleported 2.850264, 2.850194 - teleported 2.882310, 2.882229 - teleported 2.894205, 2.894115 - teleported 2.905041, 2.905009 - teleported 2.920642, 2.920416 - */ - if(GetVectorDistance(vLastOrig, vOrigin) > GetVectorLength(vVel) / (1.0 / GetTickInterval()) + 0.001) - { - #if defined DEBUG - PrintToChat(client, "teleported %f, %f (%f)", GetVectorDistance(vLastOrig, vOrigin), GetVectorLength(vVel) / (1.0 / GetTickInterval()) + 0.001, GetVectorLength(vLastVel) / (1.0 / GetTickInterval())); - #endif - - if(g_PlayerStates[client][bBlockMode]) - { - if(g_PlayerStates[client][bFailedBlock]) - { - #if defined DEBUG - PrintToChat(client, "failedblock; returning"); - #endif - - return; - } - else - { - #if defined DEBUG - PrintToChat(client, "failedblocklongjump 3 tp %s %f %f %d", - g_PlayerStates[client][vLastOrigin][2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP) ? "saved" : "not saved", - g_PlayerStates[client][vLastOrigin][2], g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP), GetGameTickCount()); - #endif - - if(g_PlayerStates[client][vLastOrigin][2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP)) - { - GetJumpDistanceLastTick(client); - g_PlayerStates[client][bFailedBlock] = true; - - return; - } - } - } - - g_PlayerStates[client][IllegalJumpFlags] |= IJF_TELEPORT; - } + new Float:vOrigin[3]; + GetClientAbsOrigin(client, vOrigin); + + // Check gravity + new Float:fGravity = GetEntPropFloat(client, Prop_Data, "m_flGravity"); + if(fGravity != 1.0 && fGravity != 0.0) + { + g_PlayerStates[client][IllegalJumpFlags] |= IJF_GRAVITY; + } + + // Check speed + if(GetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue") != 1.0) + { + g_PlayerStates[client][IllegalJumpFlags] |= IJF_LAGGEDMOVEMENTVALUE; + } + + if(GetEntityMoveType(client) & MOVETYPE_NOCLIP) + { + g_PlayerStates[client][IllegalJumpFlags] |= IJF_NOCLIP; + } + + + // Teleport check + new Float:vLastOrig[3], Float:vLastVel[3], Float:vVel[3]; + Array_Copy(g_PlayerStates[client][vLastOrigin], vLastOrig, 3); + Array_Copy(g_PlayerStates[client][vLastVelocity], vLastVel, 3); + GetEntPropVector(client, Prop_Data, "m_vecVelocity", vVel); + + vLastOrig[2] = 0.0; + vOrigin[2] = 0.0; + vLastVel[2] = 0.0; + vVel[2] = 0.0; + + // If the player moved further than their last velocity, they teleported + // It's slightly off, so adjust velocity + // pretty suk // less suk + /* + teleported 2.461413, 2.461400 + teleported 2.468606, 2.468604 + teleported 2.488778, 2.488739 + teleported 2.517628, 2.517453 + teleported 2.534332, 2.534170 + teleported 2.550610, 2.550508 + teleported 2.567417, 2.567395 + teleported 2.598604, 2.598514 + teleported 2.612708, 2.612616 + teleported 2.633581, 2.633533 + teleported 2.634170, 2.634044 + teleported 2.646703, 2.646473 + teleported 2.657407, 2.657327 + teleported 2.669471, 2.669248 + teleported 2.710047, 2.709968 + teleported 2.723108, 2.722937 + teleported 2.742104, 2.742006 + teleported 2.744069, 2.743859 + teleported 2.751010, 2.750807 + teleported 2.759773, 2.759721 + teleported 2.771660, 2.771600 + teleported 2.822698, 2.822640 + teleported 2.839976, 2.839771 + teleported 2.839976, 2.839771 + teleported 2.850264, 2.850194 + teleported 2.882310, 2.882229 + teleported 2.894205, 2.894115 + teleported 2.905041, 2.905009 + teleported 2.920642, 2.920416 + */ + if(GetVectorDistance(vLastOrig, vOrigin) > GetVectorLength(vVel) / (1.0 / GetTickInterval()) + 0.001) + { + #if defined DEBUG + PrintToChat(client, "teleported %f, %f (%f)", GetVectorDistance(vLastOrig, vOrigin), GetVectorLength(vVel) / (1.0 / GetTickInterval()) + 0.001, GetVectorLength(vLastVel) / (1.0 / GetTickInterval())); + #endif + + if(g_PlayerStates[client][bBlockMode]) + { + if(g_PlayerStates[client][bFailedBlock]) + { + #if defined DEBUG + PrintToChat(client, "failedblock; returning"); + #endif + + return; + } + else + { + #if defined DEBUG + PrintToChat(client, "failedblocklongjump 3 tp %s %f %f %d", + g_PlayerStates[client][vLastOrigin][2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP) ? "saved" : "not saved", + g_PlayerStates[client][vLastOrigin][2], g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP), GetGameTickCount()); + #endif + + if(g_PlayerStates[client][vLastOrigin][2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP)) + { + GetJumpDistanceLastTick(client); + g_PlayerStates[client][bFailedBlock] = true; + + return; + } + } + } + + g_PlayerStates[client][IllegalJumpFlags] |= IJF_TELEPORT; + } } TBAnglesToUV(Float:vOut[3], const Float:vAngles[3]) { - vOut[0] = Cosine(vAngles[1] * FLOAT_PI / 180.0) * Cosine(vAngles[0] * FLOAT_PI / 180.0); - vOut[1] = Sine(vAngles[1] * FLOAT_PI / 180.0) * Cosine(vAngles[0] * FLOAT_PI / 180.0); - vOut[2] = -Sine(vAngles[0] * FLOAT_PI / 180.0); + vOut[0] = Cosine(vAngles[1] * FLOAT_PI / 180.0) * Cosine(vAngles[0] * FLOAT_PI / 180.0); + vOut[1] = Sine(vAngles[1] * FLOAT_PI / 180.0) * Cosine(vAngles[0] * FLOAT_PI / 180.0); + vOut[2] = -Sine(vAngles[0] * FLOAT_PI / 180.0); } _OnPlayerRunCmd(client, buttons, const Float:vOrigin[3], const Float:vAngles[3], const Float:vVelocity[3], bool:bDucked, bool:bGround) { - if(g_PlayerStates[client][GapSelectionMode] != GSM_NONE) - { - GapSelect(client, buttons); - } - - // Manage spectators - if(IsClientObserver(client)) - { - if(g_PlayerStates[client][bLJEnabled]) - { - new nObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); - - if(nObserverMode == 4 || nObserverMode == 3) - { - new nTarget = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); - - if(g_PlayerStates[client][nSpectatorTarget] != nTarget) - { - if(g_PlayerStates[client][nSpectatorTarget] != -1 && g_PlayerStates[client][nSpectatorTarget] > 0 && g_PlayerStates[client][nSpectatorTarget] < MaxClients) - { - g_PlayerStates[g_PlayerStates[client][nSpectatorTarget]][nSpectators]--; - } - + if(g_PlayerStates[client][GapSelectionMode] != GSM_NONE) + { + GapSelect(client, buttons); + } + + // Manage spectators + if(IsClientObserver(client)) + { + if(g_PlayerStates[client][bLJEnabled]) + { + new nObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); + + if(nObserverMode == 4 || nObserverMode == 3) + { + new nTarget = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); + + if(g_PlayerStates[client][nSpectatorTarget] != nTarget) + { + if(g_PlayerStates[client][nSpectatorTarget] != -1 && g_PlayerStates[client][nSpectatorTarget] > 0 && g_PlayerStates[client][nSpectatorTarget] < MaxClients) + { + g_PlayerStates[g_PlayerStates[client][nSpectatorTarget]][nSpectators]--; + } + if( nTarget > 0 && nTarget < MaxClients ) { g_PlayerStates[nTarget][nSpectators]++; } - g_PlayerStates[client][nSpectatorTarget] = nTarget; - } - } - } - else - { - if(g_PlayerStates[client][nSpectatorTarget] != -1) - { - if(g_PlayerStates[client][nSpectatorTarget] > 0 && g_PlayerStates[client][nSpectatorTarget] < MaxClients) - { - g_PlayerStates[g_PlayerStates[client][nSpectatorTarget]][nSpectators]--; - } - g_PlayerStates[client][nSpectatorTarget] = -1; - } - } - - return; - } - else - { - if(g_PlayerStates[client][nSpectatorTarget] != -1) - { - g_PlayerStates[g_PlayerStates[client][nSpectatorTarget]][nSpectators]--; - g_PlayerStates[client][nSpectatorTarget] = -1; - } - } - - if(!g_PlayerStates[client][bOnGround]) - CheckValidJump(client); - - new bool:teleport = !!(g_PlayerStates[client][IllegalJumpFlags] & IJF_TELEPORT); - - // BEAMU - if(g_PlayerStates[client][bBeam] && !bGround && !teleport && (g_PlayerStates[client][bShowBhopStats] || g_PlayerStates[client][nBhops] < 2)) - { - new Float:v1[3], Float:v2[3]; - v1[0] = vOrigin[0]; - v1[1] = vOrigin[1]; - v1[2] = g_PlayerStates[client][vJumpOrigin][2]; - - v2[0] = g_PlayerStates[client][vLastOrigin][0]; - v2[1] = g_PlayerStates[client][vLastOrigin][1]; - v2[2] = g_PlayerStates[client][vJumpOrigin][2]; - - new color[4] = {255, 255, 255, 100}; + g_PlayerStates[client][nSpectatorTarget] = nTarget; + } + } + } + else + { + if(g_PlayerStates[client][nSpectatorTarget] != -1) + { + if(g_PlayerStates[client][nSpectatorTarget] > 0 && g_PlayerStates[client][nSpectatorTarget] < MaxClients) + { + g_PlayerStates[g_PlayerStates[client][nSpectatorTarget]][nSpectators]--; + } + g_PlayerStates[client][nSpectatorTarget] = -1; + } + } + + return; + } + + + + if(g_PlayerStates[client][nSpectatorTarget] != -1) + { + g_PlayerStates[g_PlayerStates[client][nSpectatorTarget]][nSpectators]--; + g_PlayerStates[client][nSpectatorTarget] = -1; + } + + if(!g_PlayerStates[client][bOnGround]) + CheckValidJump(client); + + new bool:teleport = !!(g_PlayerStates[client][IllegalJumpFlags] & IJF_TELEPORT); + + // BEAMU + if(g_PlayerStates[client][bBeam] && !bGround && !teleport && (g_PlayerStates[client][bShowBhopStats] || g_PlayerStates[client][nBhops] < 2)) + { + new Float:v1[3], Float:v2[3]; + v1[0] = vOrigin[0]; + v1[1] = vOrigin[1]; + v1[2] = g_PlayerStates[client][vJumpOrigin][2]; + + v2[0] = g_PlayerStates[client][vLastOrigin][0]; + v2[1] = g_PlayerStates[client][vLastOrigin][1]; + v2[2] = g_PlayerStates[client][vJumpOrigin][2]; + + new color[4] = {255, 255, 255, 100}; if(bDucked) { color[1] = 0; color[2] = 0; } else if( vVelocity[2] > 0 && vVelocity[2] < 140 && g_PlayerStates[client][bDeadstrafe] ) { - color[1] = 120; + color[1] = (g_PlayerStates[client][CurStrafeDir] % STRAFE_DIRECTION:2) ? 80 : 120; color[2] = 0; } else if(g_PlayerStates[client][CurStrafeDir] % STRAFE_DIRECTION:2) - { - color[0] = 128; - color[1] = 128; - } - - TE_SetupBeamPoints(v1, v2, g_BeamModel, 0, 0, 0, 10.0, 3.0, 3.0, 10, 0.0, color, 0); - TE_SendToClient(client); - } - - - // Call PlayerJump for ladder jumps or walking off the edge - if(GetEntityMoveType(client) == MOVETYPE_LADDER) - { - g_PlayerStates[client][bOnLadder] = true; - } - else - { - if(g_PlayerStates[client][bOnLadder]) - { - PlayerJump(client, JT_LADDERJUMP); - } - - g_PlayerStates[client][bOnLadder] = false; - } - - if(!bGround) - { - if(g_PlayerStates[client][bOnGround]) - { - PlayerJump(client, JT_DROP); - } - } - - - if(g_PlayerStates[client][bOnGround] || g_PlayerStates[client][nStrafes] >= MAX_STRAFES || (!g_PlayerStates[client][bLJEnabled] && !g_PlayerStates[client][nSpectators]) || g_PlayerStates[client][bFailedBlock]) - { - // dumb language - if((bGround || g_PlayerStates[client][bOnLadder]) && !g_PlayerStates[client][bOnGround]) - { - PlayerLand(client); - } - - if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][bShowPrestrafeHint]) - { - PrintPrestrafeHint(client); - } - - return; - } - - - if(!bGround) - { - g_PlayerStates[client][nLastAerialTick] = GetGameTickCount(); - - if(GetVSpeed(vVelocity) > g_PlayerStates[client][fMaxSpeed]) - g_PlayerStates[client][fMaxSpeed] = GetVSpeed(vVelocity); - - if(vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] > g_PlayerStates[client][fJumpHeight]) - g_PlayerStates[client][fJumpHeight] = vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2]; - - // Record the failed distance, but since it will trigger if you duck late, only save it if it's certain that the player will not land - if(g_PlayerStates[client][bBlockMode] && - !g_PlayerStates[client][bFailedBlock] && - (bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] + 1.0 || - !bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] + 1.5) && - vOrigin[2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP)) - { - GetJumpDistance(client); - #if defined DEBUG - PrintToChat(client, "getting failed dist, %d, %f, %f", - vOrigin[2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP), vOrigin[2], g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP)); - #endif - } - - - #if defined DEBUG - if(vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2]) - { - PrintToChat(client, "%d, %d, %d", bDucked, vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP), !bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] - 10.5); - } - #endif - - // Check if the player is still capable of landing - if(g_PlayerStates[client][bBlockMode] && !g_PlayerStates[client][bFailedBlock] && - (bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP)/* + 1.0*/ || // You land at 0.79 elevation when ducking - !bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] - 10.5)) - // Ducking increases your origin by 8.5; you land at 1.47 units elevation when ducking, so around 10.0; 10.5 for good measure - { - StopBeam(client); - - g_PlayerStates[client][bDuck] = bDucked; - g_PlayerStates[client][bFailedBlock] = true; - - #if defined DEBUG - PrintToChat(client, "failedblocklongjump 1 %.2f, %d", vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2], GetGameTickCount()); - #endif - - if(bGround && !g_PlayerStates[client][bOnGround]) - { - PlayerLand(client); - } - - if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][bShowPrestrafeHint]) - { - PrintPrestrafeHint(client); - } - - return; - } - } - - - if(g_PlayerStates[client][JumpDir] == JD_BACKWARDS) - { - new Float:vAnglesUV[3]; - TBAnglesToUV(vAnglesUV, vAngles); - - new Float:vVelocityDir[3]; - vVelocityDir = vVelocity; - vVelocityDir[2] = 0.0; - NormalizeVector(vVelocityDir, vVelocityDir); - - if(ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) < FLOAT_PI / 2) - { - g_PlayerStates[client][JumpDir] = JD_NORMAL; - } - } - - // check for multiple keys -- it will spam strafes when multiple are held without this - new nButtonCount; - if(buttons & IN_MOVELEFT) - nButtonCount++; - if(buttons & IN_MOVERIGHT) - nButtonCount++; - if(buttons & IN_FORWARD) - nButtonCount++; - if(buttons & IN_BACK) - nButtonCount++; - - if(nButtonCount == 1) - { - if(g_PlayerStates[client][CurStrafeDir] != SD_A && buttons & IN_MOVELEFT) - { - if(g_PlayerStates[client][JumpDir] == JD_NONE) - { - new Float:vAnglesUV[3]; - TBAnglesToUV(vAnglesUV, vAngles); - - new Float:vVelocityDir[3]; - vVelocityDir = vVelocity; - vVelocityDir[2] = 0.0; - NormalizeVector(vVelocityDir, vVelocityDir); - - if(ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) > FLOAT_PI / 2) - { - g_PlayerStates[client][JumpDir] = JD_BACKWARDS; - } - else - { - g_PlayerStates[client][JumpDir] = JD_NORMAL; - } - } - - if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS) - { - g_PlayerStates[client][JumpDir] = JD_NORMAL; - } - - g_PlayerStates[client][StrafeDir][g_PlayerStates[client][nStrafes]] = SD_A; - g_PlayerStates[client][CurStrafeDir] = SD_A; - g_PlayerStates[client][nStrafes]++; - } - else if(g_PlayerStates[client][CurStrafeDir] != SD_D && buttons & IN_MOVERIGHT) - { - if(g_PlayerStates[client][JumpDir] == JD_NONE) - { - new Float:vAnglesUV[3]; - TBAnglesToUV(vAnglesUV, vAngles); - - new Float:vVelocityDir[3]; - vVelocityDir = vVelocity; - vVelocityDir[2] = 0.0; - NormalizeVector(vVelocityDir, vVelocityDir); - - if(ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) > FLOAT_PI / 2) - { - g_PlayerStates[client][JumpDir] = JD_BACKWARDS; - } - else - { - g_PlayerStates[client][JumpDir] = JD_NORMAL; - } - } - - else if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS) - { - g_PlayerStates[client][JumpDir] = JD_NORMAL; - } - - g_PlayerStates[client][StrafeDir][g_PlayerStates[client][nStrafes]] = SD_D; - g_PlayerStates[client][CurStrafeDir] = SD_D; - g_PlayerStates[client][nStrafes]++; - } - else if(g_PlayerStates[client][CurStrafeDir] != SD_W && buttons & IN_FORWARD) - { - if(g_PlayerStates[client][JumpDir] == JD_NONE && (vVelocity[0] || vVelocity[1])) - { - new Float:vAnglesUV[3]; - TBAnglesToUV(vAnglesUV, vAngles); - - new Float:vVelocityDir[3]; - vVelocityDir = vVelocity; - vVelocityDir[2] = 0.0; - NormalizeVector(vVelocityDir, vVelocityDir); - - if(DegToRad(90.0 - SW_ANGLE_THRESHOLD) < ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) < DegToRad(90.0 + SW_ANGLE_THRESHOLD)) - { - g_PlayerStates[client][JumpDir] = JD_SIDEWAYS; - } - } - - g_PlayerStates[client][StrafeDir][g_PlayerStates[client][nStrafes]] = SD_W; - g_PlayerStates[client][CurStrafeDir] = SD_W; - g_PlayerStates[client][nStrafes]++; - } - else if(g_PlayerStates[client][CurStrafeDir] != SD_S && buttons & IN_BACK) - { - if(g_PlayerStates[client][JumpDir] == JD_NONE && (vVelocity[0] || vVelocity[1])) - { - new Float:vAnglesUV[3]; - TBAnglesToUV(vAnglesUV, vAngles); - - new Float:vVelocityDir[3]; - vVelocityDir = vVelocity; - vVelocityDir[2] = 0.0; - NormalizeVector(vVelocityDir, vVelocityDir); - - if(DegToRad(90.0 - SW_ANGLE_THRESHOLD) < ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) < DegToRad(90.0 + SW_ANGLE_THRESHOLD)) - { - g_PlayerStates[client][JumpDir] = JD_SIDEWAYS; - } - } - - g_PlayerStates[client][StrafeDir][g_PlayerStates[client][nStrafes]] = SD_S; - g_PlayerStates[client][CurStrafeDir] = SD_S; - g_PlayerStates[client][nStrafes]++; - } - } - - if(g_PlayerStates[client][nStrafes] > 0) - { - new Float:v[3], Float:v2[3]; - Array_Copy(g_PlayerStates[client][vLastVelocity], v, 3); - Array_Copy(g_PlayerStates[client][vLastAngles], v2, 3); - - new Float:fVelDelta = GetSpeed(client) - GetVSpeed(v); - - new Float:fAngleDelta = fmod((FloatAbs(vAngles[1] - v2[1]) + 180.0), 360.0) - 180.0; - - g_PlayerStates[client][nStrafeTicks][g_PlayerStates[client][nStrafes] - 1]++; - - g_PlayerStates[client][fTotalAngle] += fAngleDelta; - - if(fVelDelta > 0.0) - { - g_PlayerStates[client][fStrafeGain][g_PlayerStates[client][nStrafes] - 1] += fVelDelta; - g_PlayerStates[client][fGain] += fVelDelta; - - g_PlayerStates[client][nStrafeTicksSynced][g_PlayerStates[client][nStrafes] - 1]++; - - g_PlayerStates[client][fSyncedAngle] += fAngleDelta; - } - else - { - g_PlayerStates[client][fStrafeLoss][g_PlayerStates[client][nStrafes] - 1] -= fVelDelta; - g_PlayerStates[client][fLoss] -= fVelDelta; - } - } - - g_PlayerStates[client][nTotalTicks]++; - g_PlayerStates[client][fTrajectory] += GetSpeed(client) * GetTickInterval(); - - if(bGround && !g_PlayerStates[client][bOnGround]) - { - PlayerLand(client); - } - - if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][bShowPrestrafeHint]) - { - PrintPrestrafeHint(client); - } + { + color[0] = 128; + color[1] = 128; + } + + TE_SetupBeamPoints(v1, v2, g_BeamModel, 0, 0, 0, 10.0, 3.0, 3.0, 10, 0.0, color, 0); + TE_SendToClient(client); + } + + + // Call PlayerJump for ladder jumps or walking off the edge + if(GetEntityMoveType(client) == MOVETYPE_LADDER) + { + g_PlayerStates[client][bOnLadder] = true; + } + else + { + if(g_PlayerStates[client][bOnLadder]) + { + PlayerJump(client, JT_LADDERJUMP); + } + + g_PlayerStates[client][bOnLadder] = false; + } + + if(!bGround) + { + if(g_PlayerStates[client][bOnGround]) + { + PlayerJump(client, JT_DROP); + } + } + + + if(g_PlayerStates[client][bOnGround] || g_PlayerStates[client][nStrafes] >= MAX_STRAFES || (!g_PlayerStates[client][bLJEnabled] && !g_PlayerStates[client][nSpectators]) || g_PlayerStates[client][bFailedBlock]) + { + // dumb language + if((bGround || g_PlayerStates[client][bOnLadder]) && !g_PlayerStates[client][bOnGround]) + { + PlayerLand(client); + } + + if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][bShowPrestrafeHint]) + { + PrintPrestrafeHint(client); + } + + return; + } + + + if(!bGround) + { + g_PlayerStates[client][nLastAerialTick] = GetGameTickCount(); + + if(GetVSpeed(vVelocity) > g_PlayerStates[client][fMaxSpeed]) + g_PlayerStates[client][fMaxSpeed] = GetVSpeed(vVelocity); + + if(vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] > g_PlayerStates[client][fJumpHeight]) + g_PlayerStates[client][fJumpHeight] = vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2]; + + // Record the failed distance, but since it will trigger if you duck late, only save it if it's certain that the player will not land + if(g_PlayerStates[client][bBlockMode] && + !g_PlayerStates[client][bFailedBlock] && + (bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] + 1.0 || + !bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] + 1.5) && + vOrigin[2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP)) + { + GetJumpDistance(client); + #if defined DEBUG + PrintToChat(client, "getting failed dist, %d, %f, %f", + vOrigin[2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP), vOrigin[2], g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP)); + #endif + } + + + #if defined DEBUG + if(vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2]) + { + PrintToChat(client, "%d, %d, %d", bDucked, vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP), !bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] - 10.5); + } + #endif + + // Check if the player is still capable of landing + if(g_PlayerStates[client][bBlockMode] && !g_PlayerStates[client][bFailedBlock] && + (bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP)/* + 1.0*/ || // You land at 0.79 elevation when ducking + !bDucked && vOrigin[2] <= g_PlayerStates[client][vJumpOrigin][2] - 10.5)) + // Ducking increases your origin by 8.5; you land at 1.47 units elevation when ducking, so around 10.0; 10.5 for good measure + { + StopBeam(client); + + g_PlayerStates[client][bDuck] = bDucked; + g_PlayerStates[client][bFailedBlock] = true; + + #if defined DEBUG + PrintToChat(client, "failedblocklongjump 1 %.2f, %d", vOrigin[2] - g_PlayerStates[client][vJumpOrigin][2], GetGameTickCount()); + #endif + + if(bGround && !g_PlayerStates[client][bOnGround]) + { + PlayerLand(client); + } + + if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][bShowPrestrafeHint]) + { + PrintPrestrafeHint(client); + } + + return; + } + } + + + if(g_PlayerStates[client][JumpDir] == JD_BACKWARDS) + { + new Float:vAnglesUV[3]; + TBAnglesToUV(vAnglesUV, vAngles); + + new Float:vVelocityDir[3]; + vVelocityDir = vVelocity; + vVelocityDir[2] = 0.0; + NormalizeVector(vVelocityDir, vVelocityDir); + + if(ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) < FLOAT_PI / 2) + { + g_PlayerStates[client][JumpDir] = JD_NORMAL; + } + } + + // check for multiple keys -- it will spam strafes when multiple are held without this + new nButtonCount; + if(buttons & IN_MOVELEFT) + nButtonCount++; + if(buttons & IN_MOVERIGHT) + nButtonCount++; + if(buttons & IN_FORWARD) + nButtonCount++; + if(buttons & IN_BACK) + nButtonCount++; + + if(nButtonCount == 1) + { + if(g_PlayerStates[client][CurStrafeDir] != SD_A && buttons & IN_MOVELEFT) + { + if(g_PlayerStates[client][JumpDir] == JD_NONE) + { + new Float:vAnglesUV[3]; + TBAnglesToUV(vAnglesUV, vAngles); + + new Float:vVelocityDir[3]; + vVelocityDir = vVelocity; + vVelocityDir[2] = 0.0; + NormalizeVector(vVelocityDir, vVelocityDir); + + if(ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) > FLOAT_PI / 2) + { + g_PlayerStates[client][JumpDir] = JD_BACKWARDS; + } + else + { + g_PlayerStates[client][JumpDir] = JD_NORMAL; + } + } + + if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS) + { + g_PlayerStates[client][JumpDir] = JD_NORMAL; + } + + g_PlayerStates[client][StrafeDir][g_PlayerStates[client][nStrafes]] = SD_A; + g_PlayerStates[client][CurStrafeDir] = SD_A; + g_PlayerStates[client][nStrafes]++; + } + else if(g_PlayerStates[client][CurStrafeDir] != SD_D && buttons & IN_MOVERIGHT) + { + if(g_PlayerStates[client][JumpDir] == JD_NONE) + { + new Float:vAnglesUV[3]; + TBAnglesToUV(vAnglesUV, vAngles); + + new Float:vVelocityDir[3]; + vVelocityDir = vVelocity; + vVelocityDir[2] = 0.0; + NormalizeVector(vVelocityDir, vVelocityDir); + + if(ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) > FLOAT_PI / 2) + { + g_PlayerStates[client][JumpDir] = JD_BACKWARDS; + } + else + { + g_PlayerStates[client][JumpDir] = JD_NORMAL; + } + } + + else if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS) + { + g_PlayerStates[client][JumpDir] = JD_NORMAL; + } + + g_PlayerStates[client][StrafeDir][g_PlayerStates[client][nStrafes]] = SD_D; + g_PlayerStates[client][CurStrafeDir] = SD_D; + g_PlayerStates[client][nStrafes]++; + } + else if(g_PlayerStates[client][CurStrafeDir] != SD_W && buttons & IN_FORWARD) + { + if(g_PlayerStates[client][JumpDir] == JD_NONE && (vVelocity[0] || vVelocity[1])) + { + new Float:vAnglesUV[3]; + TBAnglesToUV(vAnglesUV, vAngles); + + new Float:vVelocityDir[3]; + vVelocityDir = vVelocity; + vVelocityDir[2] = 0.0; + NormalizeVector(vVelocityDir, vVelocityDir); + + if(DegToRad(90.0 - SW_ANGLE_THRESHOLD) < ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) < DegToRad(90.0 + SW_ANGLE_THRESHOLD)) + { + g_PlayerStates[client][JumpDir] = JD_SIDEWAYS; + } + } + + g_PlayerStates[client][StrafeDir][g_PlayerStates[client][nStrafes]] = SD_W; + g_PlayerStates[client][CurStrafeDir] = SD_W; + g_PlayerStates[client][nStrafes]++; + } + else if(g_PlayerStates[client][CurStrafeDir] != SD_S && buttons & IN_BACK) + { + if(g_PlayerStates[client][JumpDir] == JD_NONE && (vVelocity[0] || vVelocity[1])) + { + new Float:vAnglesUV[3]; + TBAnglesToUV(vAnglesUV, vAngles); + + new Float:vVelocityDir[3]; + vVelocityDir = vVelocity; + vVelocityDir[2] = 0.0; + NormalizeVector(vVelocityDir, vVelocityDir); + + if(DegToRad(90.0 - SW_ANGLE_THRESHOLD) < ArcCosine(GetVectorDotProduct(vAnglesUV, vVelocityDir)) < DegToRad(90.0 + SW_ANGLE_THRESHOLD)) + { + g_PlayerStates[client][JumpDir] = JD_SIDEWAYS; + } + } + + g_PlayerStates[client][StrafeDir][g_PlayerStates[client][nStrafes]] = SD_S; + g_PlayerStates[client][CurStrafeDir] = SD_S; + g_PlayerStates[client][nStrafes]++; + } + } + + if(g_PlayerStates[client][nStrafes] > 0) + { + new Float:v[3], Float:v2[3]; + Array_Copy(g_PlayerStates[client][vLastVelocity], v, 3); + Array_Copy(g_PlayerStates[client][vLastAngles], v2, 3); + + new Float:fVelDelta = GetSpeed(client) - GetVSpeed(v); + + new Float:fAngleDelta = fmod((FloatAbs(vAngles[1] - v2[1]) + 180.0), 360.0) - 180.0; + + g_PlayerStates[client][nStrafeTicks][g_PlayerStates[client][nStrafes] - 1]++; + + g_PlayerStates[client][fTotalAngle] += fAngleDelta; + + if(fVelDelta > 0.0) + { + g_PlayerStates[client][fStrafeGain][g_PlayerStates[client][nStrafes] - 1] += fVelDelta; + g_PlayerStates[client][fGain] += fVelDelta; + + g_PlayerStates[client][nStrafeTicksSynced][g_PlayerStates[client][nStrafes] - 1]++; + + g_PlayerStates[client][fSyncedAngle] += fAngleDelta; + } + else + { + g_PlayerStates[client][fStrafeLoss][g_PlayerStates[client][nStrafes] - 1] -= fVelDelta; + g_PlayerStates[client][fLoss] -= fVelDelta; + } + } + + g_PlayerStates[client][nTotalTicks]++; + g_PlayerStates[client][fTrajectory] += GetSpeed(client) * GetTickInterval(); + + if(bGround && !g_PlayerStates[client][bOnGround]) + { + PlayerLand(client); + } + + if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][bShowPrestrafeHint]) + { + PrintPrestrafeHint(client); + } } public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:vAngles[3], &weapon) { - new Float:vOrigin[3], Float:vVelocity[3]; - new bool:bDucked = bool:GetEntProp(client, Prop_Send, "m_bDucked", 1), bool:bGround = bool:(GetEntityFlags(client) & FL_ONGROUND); - GetClientAbsOrigin(client, vOrigin); - GetEntPropVector(client, Prop_Data, "m_vecVelocity", vVelocity); - - _OnPlayerRunCmd(client, buttons, vOrigin, vAngles, vVelocity, bDucked, bGround); - - Array_Copy(vOrigin, g_PlayerStates[client][vLastOrigin], 3); - Array_Copy(vAngles, g_PlayerStates[client][vLastAngles], 3); - Array_Copy(vVelocity, g_PlayerStates[client][vLastVelocity], 3); - g_PlayerStates[client][bSecondLastDuckState] = g_PlayerStates[client][bLastDuckState]; - g_PlayerStates[client][bLastDuckState] = bDucked; - g_PlayerStates[client][LastButtons] = buttons; - - return Plugin_Continue; + new Float:vOrigin[3], Float:vVelocity[3]; + new bool:bDucked = bool:GetEntProp(client, Prop_Send, "m_bDucked", 1), bool:bGround = bool:(GetEntityFlags(client) & FL_ONGROUND); + GetClientAbsOrigin(client, vOrigin); + GetEntPropVector(client, Prop_Data, "m_vecVelocity", vVelocity); + + new bool:jump = !!(buttons & IN_JUMP); + new Float:vVelocitycopy[3]; + Array_Copy( vVelocity, vVelocitycopy, 2 ); + + Speedometer( client, jump, bGround, vVelocitycopy ); + _OnPlayerRunCmd(client, buttons, vOrigin, vAngles, vVelocity, bDucked, bGround); + + StrafeTrainer( client, bGround, vAngles, vVelocity ); + + + Array_Copy(vOrigin, g_PlayerStates[client][vLastOrigin], 3); + Array_Copy(vAngles, g_PlayerStates[client][vLastAngles], 3); + Array_Copy(vVelocity, g_PlayerStates[client][vLastVelocity], 3); + g_PlayerStates[client][bSecondLastDuckState] = g_PlayerStates[client][bLastDuckState]; + g_PlayerStates[client][bLastDuckState] = bDucked; + g_PlayerStates[client][LastButtons] = buttons; + + return Plugin_Continue; } PrintPrestrafeHint(client) { - new bool:bGround = bool:(GetEntityFlags(client) & FL_ONGROUND); - decl String:strHint[128]; - - Format(strHint, sizeof(strHint), "Pre: %.2f", bGround && !GetEntPropFloat(client, Prop_Send, "m_flStamina") ? GetSpeed(client) : g_PlayerStates[client][fPrestrafe]); - - if(g_PlayerStates[client][fEdge] != -1.0 && !bGround) - { - Append(strHint, sizeof(strHint), " | e: %.2f", g_PlayerStates[client][fEdge]); - } - - if(!bGround) - { - Append(strHint, sizeof(strHint), "\nG: %d | L: %d\nMaxspeed: %d", RoundFloat(g_PlayerStates[client][fGain]), RoundFloat(g_PlayerStates[client][fLoss]), RoundFloat(g_PlayerStates[client][fMaxSpeed])); - } - - PrintHintText(client, strHint); + new bool:bGround = bool:(GetEntityFlags(client) & FL_ONGROUND); + decl String:strHint[128]; + + Format(strHint, sizeof(strHint), "Pre: %.2f", bGround && !GetEntPropFloat(client, Prop_Send, "m_flStamina") ? GetSpeed(client) : g_PlayerStates[client][fPrestrafe]); + + if(g_PlayerStates[client][fEdge] != -1.0 && !bGround) + { + Append(strHint, sizeof(strHint), " | e: %.2f", g_PlayerStates[client][fEdge]); + } + + if(!bGround) + { + Append(strHint, sizeof(strHint), "\nG: %d | L: %d\nMaxspeed: %d", RoundFloat(g_PlayerStates[client][fGain]), RoundFloat(g_PlayerStates[client][fLoss]), RoundFloat(g_PlayerStates[client][fMaxSpeed])); + } + + if( nh_warmup != INVALID_HANDLE ) { + new wm = GetConVarInt( nh_warmup ); + if( wm > 0 ) { + new secs = wm % 60; + new mins = (wm - secs) / 60; + + Append( strHint, sizeof( strHint ), "\n---[ WARMUP %d:%02d ] ---", mins, secs ); + } + else if( wm < 0 ) { + Append( strHint, sizeof( strHint ), "\n---[ WARMUP ] ---" ); + } + } + + PrintHintText(client, strHint); } PlayerLand(client) { - g_PlayerStates[client][bOnGround] = true; - - g_PlayerStates[client][fLandTime] = GetGameTime(); - - if(!g_PlayerStates[client][bLJEnabled] && !g_PlayerStates[client][nSpectators] || !g_PlayerStates[client][bShowBhopStats] && g_PlayerStates[client][nBhops] > 1) - return; - - - - // Final CheckValidJump - //CheckValidJump(client); - - - new Float:vCurOrigin[3]; - GetClientAbsOrigin(client, vCurOrigin); - g_PlayerStates[client][fFinalSpeed] = GetSpeed(client); - - - #if defined DEBUG - if(g_PlayerStates[client][bFailedBlock] && vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] > -2.0) - PrintToChat(client, "failed block && height delta = %f", vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2]); - - PrintToChat(client, "%d", g_PlayerStates[client][bFailedBlock]); - #endif - - // Calculate distances - if(!g_PlayerStates[client][bFailedBlock])// || // if block longjump failed, distances have already been written in mid-air. - //vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] >= HEIGHT_DELTA_MIN(JT_LONGJUMP)) // bugs sometimes if you land on last tick (I think) idk how else 2 fix - { - GetJumpDistance(client); - - g_PlayerStates[client][bFailedBlock] = false; - } - - // don't show drop stats - if(g_PlayerStates[client][JumpType] == JT_DROP) - return; - - if(!g_PlayerStates[client][bShowAllJumps]) - { - if(g_PlayerStates[client][JumpType] == JT_LONGJUMP) - { - if(g_PlayerStates[client][fHeightDelta] > HEIGHT_DELTA_MIN(g_PlayerStates[client][JumpType]) && g_PlayerStates[client][fHeightDelta] < HEIGHT_DELTA_MAX(g_PlayerStates[client][JumpType])) - { - if(g_PlayerStates[client][fJumpDistance] < 240.0) - { - return; - } - } - else // Dropjump/upjump - { - if(g_PlayerStates[client][fJumpDistance] < 240.0 - g_PlayerStates[client][fHeightDelta]) - { - return; - } - } - } - else if(g_PlayerStates[client][fJumpDistance] < 240.0) - { - return; - } - } - - // Check whether the player actually moved past the block edge - if(g_PlayerStates[client][bBlockMode] && !g_PlayerStates[client][bFailedBlock]) - { - if(!g_PlayerStates[client][vBlockNormal][0] || !g_PlayerStates[client][vBlockNormal][1]) - { - // bools are not actually handled as 1 bit bools but 32 bit cells so n = normal.y gives out of bounds exception - // !!normal.y or !normal.x rather - // pawn good - new bool:n = !g_PlayerStates[client][vBlockNormal][0]; - - if(g_PlayerStates[client][vBlockNormal][n] > 0.0) - { - if(vCurOrigin[n] + 16.0 * g_PlayerStates[client][vBlockNormal][n] < g_PlayerStates[client][vBlockEndPos][n]) - { - g_PlayerStates[client][bFailedBlock] = true; - } - } - else - { - if(vCurOrigin[n] + 16.0 * g_PlayerStates[client][vBlockNormal][n] > g_PlayerStates[client][vBlockEndPos][n]) - { - g_PlayerStates[client][bFailedBlock] = true; - } - } - } - else - { - new Float:vAdjCurOrigin[3], Float:vInvNormal[3]; - vAdjCurOrigin = vCurOrigin; - Array_Copy(g_PlayerStates[client][vBlockNormal], vInvNormal, 2); - ScaleVector(vInvNormal, -1.0); - Adjust(vAdjCurOrigin, vInvNormal); - - - // f(endpos.x) + (origin.x - endpos.x) * b = (f(endpos.x) - endpos.x * b) + origin.x * b = f(0) + origin.x * b - // block normal is perpendicular to the edge direction, so b = 1 / (normal rot 90).x - // dx and dy should have same sign so ccw rot if facing down, cw rot if up - new Float:b = 1 / (g_PlayerStates[client][vBlockNormal][0] < 0 ? g_PlayerStates[client][vBlockNormal][1] : -g_PlayerStates[client][vBlockNormal][1]); - new Float:fPos = g_PlayerStates[client][vBlockEndPos][1] + (vAdjCurOrigin[0] - g_PlayerStates[client][vBlockEndPos][0]) * b; - - if(g_PlayerStates[client][vBlockNormal][1] > 0.0 ? vAdjCurOrigin[1] < fPos : vAdjCurOrigin[1] > fPos) - { - g_PlayerStates[client][bFailedBlock] = true; - } - - - #if defined DEBUG - PrintToChat(client, "block normal: %.2f, %.2f\n%.2f, %.2f, %.2f", - g_PlayerStates[client][vBlockNormal][0], - g_PlayerStates[client][vBlockNormal][1], - vAdjCurOrigin[1], - fPos, - g_PlayerStates[client][vBlockEndPos][1]); - - new Float:v1[3], Float:v2[3]; - v1[2] = g_PlayerStates[client][vBlockEndPos][2] + 0.1; - v2[2] = g_PlayerStates[client][vBlockEndPos][2] + 0.1; - v1[0] = g_PlayerStates[client][vBlockEndPos][0] - 50; - v1[1] = g_PlayerStates[client][vBlockEndPos][1] + (v1[0] - g_PlayerStates[client][vBlockEndPos][0]) * b; - v2[0] = g_PlayerStates[client][vBlockEndPos][0] + 50; - v2[1] = g_PlayerStates[client][vBlockEndPos][1] + (v2[0] - g_PlayerStates[client][vBlockEndPos][0]) * b; - CreateBeam2(v1, v2, 0, 0, 255); - - if(g_PlayerStates[client][bFailedBlock]) - { - PrintToChat(client, "failedblocklongjump 2"); - } - #endif - } - } - - - // sum sync - g_PlayerStates[client][fSync] = 0.0; - - for(new i = 0; i < g_PlayerStates[client][nStrafes] && i < MAX_STRAFES; i++) - { - g_PlayerStates[client][fSync] += g_PlayerStates[client][nStrafeTicksSynced][i]; - g_PlayerStates[client][fStrafeSync][i] = float(g_PlayerStates[client][nStrafeTicksSynced][i]) / g_PlayerStates[client][nStrafeTicks][i] * 100; - } - - g_PlayerStates[client][fSync] /= g_PlayerStates[client][nTotalTicks]; - g_PlayerStates[client][fSync] *= 100; - - - - - //// - // Write HUD hint - //// - - decl String:buf[1024]; - - g_PlayerStates[client][strHUDHint][0] = 0; - - - decl String:strJump[32]; - - if(g_PlayerStates[client][fHeightDelta] > HEIGHT_DELTA_MAX(g_PlayerStates[client][JumpType])) - { - if(g_PlayerStates[client][JumpType] == JT_LONGJUMP) - { - strJump = "Upjump"; - } - else - { - Format(strJump, sizeof(strJump), "Up%s", g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); - } - } - else if(g_PlayerStates[client][fHeightDelta] < HEIGHT_DELTA_MIN(g_PlayerStates[client][JumpType])) - { - if(g_PlayerStates[client][JumpType] == JT_LONGJUMP) - { - strJump = "Dropjump"; - } - else - { - Format(strJump, sizeof(strJump), "Drop%s", g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); - } - } - else - { - strcopy(strJump, sizeof(strJump), g_strJumpType[g_PlayerStates[client][JumpType]]); - } - - decl String:strJumpDir[16]; - strJumpDir = g_PlayerStates[client][JumpDir] == JD_SIDEWAYS ? " sideways" : g_PlayerStates[client][JumpDir] == JD_BACKWARDS ? " backwards" : ""; - - Format(buf, sizeof(buf), "%s%s%s\npre: %.2f", - strJump, strJumpDir, - g_PlayerStates[client][JumpType] == JT_LONGJUMP && - g_PlayerStates[client][fHeightDelta] >= HEIGHT_DELTA_MIN(g_PlayerStates[client][JumpType]) && - g_PlayerStates[client][IllegalJumpFlags] == IJF_NONE && - g_PlayerStates[client][nTotalTicks] > 77 ? " (extended)" : "", - g_PlayerStates[client][fPrestrafe]); - - StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); - - if(g_PlayerStates[client][JumpType] == JT_WEIRDJUMP && g_PlayerStates[client][nVerbosity] > 1) - { - Format(buf, sizeof(buf), " (%.2f)", - g_PlayerStates[client][fWJDropPre]); - - StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); - } - - Format(buf, sizeof(buf), "; dist: %.2f", - g_PlayerStates[client][fJumpDistance]); - - StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); - - if(g_PlayerStates[client][fEdge] != -1.0) - { - Format(buf, sizeof(buf), "; edge: %.2f", - g_PlayerStates[client][fEdge]); - - StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); - } - - StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, "\n"); - - Format(buf, sizeof(buf), "strafes: %d (%.0f); max: %.2f", - g_PlayerStates[client][nStrafes], - g_PlayerStates[client][fSync], - g_PlayerStates[client][fMaxSpeed]); - - StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); - - if(g_PlayerStates[client][nVerbosity] > 2) - { - Format(buf, sizeof(buf), "\n%s%.2f; %.2f; %.4f%; %d", - g_PlayerStates[client][fHeightDelta] >= 0.0 ? "+" : "", - g_PlayerStates[client][fHeightDelta], - g_PlayerStates[client][fJumpHeight], - (g_PlayerStates[client][fJumpDistance] - 32.0) / g_PlayerStates[client][fTrajectory], - g_PlayerStates[client][nTotalTicks]); - - StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); - } - - - if(g_PlayerStates[client][bLJEnabled]) - { - buf[0] = 0; - - Append(buf, sizeof(buf), "\n"); - - - Append(buf, sizeof(buf), "%s%s%s\nDistance: %.2f", - strJump, strJumpDir, - g_PlayerStates[client][JumpType] == JT_LONGJUMP && - g_PlayerStates[client][fHeightDelta] > HEIGHT_DELTA_MIN(g_PlayerStates[client][JumpType]) - && g_PlayerStates[client][nTotalTicks] > 77 ? " (extended)" : "", - g_PlayerStates[client][fJumpDistance]); - - Append(buf, sizeof(buf), "; prestrafe: %.2f", - g_PlayerStates[client][fPrestrafe]); - - if(g_PlayerStates[client][JumpType] == JT_WEIRDJUMP) - { - Append(buf, sizeof(buf), "; drop prestrafe: %.2f", - g_PlayerStates[client][fWJDropPre]); - } - - if(g_PlayerStates[client][fEdge] != -1.0) - { - Append(buf, sizeof(buf), "; edge: %.2f", - g_PlayerStates[client][fEdge]); - } - - if(g_PlayerStates[client][nTotalTicks] == 78) - { - new Float:vCurOrigin2[3]; - Array_Copy(g_PlayerStates[client][vLastOrigin], vCurOrigin2, 3); - - vCurOrigin2[2] = 0.0; - - new Float:v[3]; - Array_Copy(g_PlayerStates[client][vJumpOrigin], v, 3); - - v[2] = 0.0; - - new Float:ProjDist = GetVectorDistance(v, vCurOrigin2) + 32.0; - - Append(buf, sizeof(buf), "; projected real distance: %.2f", ProjDist); - } - - Append(buf, sizeof(buf), "\nStrafes: %d; sync: %.2f%%; maxspeed (gain): %.2f (%.2f)", - g_PlayerStates[client][nStrafes], - g_PlayerStates[client][fSync], - g_PlayerStates[client][fMaxSpeed], - g_PlayerStates[client][fMaxSpeed] - g_PlayerStates[client][fPrestrafe]); - - Append(buf, sizeof(buf), "\nHeight diff: %s%.2f; jump height: %.2f; efficiency: %.4f; ticks: %d; degrees synced/degrees turned: %.2f/%.2f", - g_PlayerStates[client][fHeightDelta] >= 0.0 ? "+" : "", - g_PlayerStates[client][fHeightDelta], - g_PlayerStates[client][fJumpHeight], - (g_PlayerStates[client][fJumpDistance] - 32.0) / g_PlayerStates[client][fTrajectory], - g_PlayerStates[client][nTotalTicks], - g_PlayerStates[client][fSyncedAngle], g_PlayerStates[client][fTotalAngle]); - - PrintToConsole(client, buf); - - - new Handle:hBuffer = StartMessageOne("KeyHintText", client); - BfWriteByte(hBuffer, 1); - BfWriteString(hBuffer, g_PlayerStates[client][strHUDHint]); - EndMessage(); - } - - - //// - // Panel - //// - - new Handle:hStatsPanel = CreatePanel(); - - - Format(buf, 128, "%s %.2f %s%.2f", - g_strJumpTypeShort[g_PlayerStates[client][JumpType]], - g_PlayerStates[client][fJumpDistance], - g_PlayerStates[client][fHeightDelta] > 0.01 ? "+" : "", - g_PlayerStates[client][fHeightDelta]); - - SetPanelTitle(hStatsPanel, buf); - - - if(g_PlayerStates[client][bLJEnabled]) - { - PrintToConsole(client, "--------------------------------"); - } - - // Print first 16 strafes to panel - for(new i = 0; i < g_PlayerStates[client][nStrafes] && i < 16; i++) - { - decl String:strStrafeKey[3]; - GetStrafeKey(strStrafeKey, g_PlayerStates[client][StrafeDir][i]); - DrawPanelTextF(hStatsPanel, "%d %s %.2f %.2f %.2f %.2f", - i + 1, - strStrafeKey, - g_PlayerStates[client][fStrafeGain][i], g_PlayerStates[client][fStrafeLoss][i], - float(g_PlayerStates[client][nStrafeTicks][i]) / g_PlayerStates[client][nTotalTicks] * 100, - float(g_PlayerStates[client][nStrafeTicksSynced][i]) / g_PlayerStates[client][nStrafeTicks][i] * 100); - } - - // Print strafes to console - if(g_PlayerStates[client][bLJEnabled]) - { - PrintToConsole(client, "# Key Gain Loss Time Sync"); - - for(new i = 0; i < g_PlayerStates[client][nStrafes] && i < MAX_STRAFES; i++) - { - decl String:strStrafeKey[3]; - GetStrafeKey(strStrafeKey, g_PlayerStates[client][StrafeDir][i]); - Format(buf, sizeof(buf), "%d %s %6.2f %6.2f %6.2f %6.2f", i + 1, - strStrafeKey, - g_PlayerStates[client][fStrafeGain][i], g_PlayerStates[client][fStrafeLoss][i], - float(g_PlayerStates[client][nStrafeTicks][i]) / g_PlayerStates[client][nTotalTicks] * 100, - float(g_PlayerStates[client][nStrafeTicksSynced][i]) / g_PlayerStates[client][nStrafeTicks][i] * 100); - - PrintToConsole(client, buf); - } - } - - DrawPanelTextF(hStatsPanel, " %.2f%%", g_PlayerStates[client][fSync]); - - if(g_PlayerStates[client][nVerbosity] > 2) - { - DrawPanelTextF(hStatsPanel, " %.2f/%.2f", g_PlayerStates[client][fSyncedAngle], g_PlayerStates[client][fTotalAngle]); - } - - DrawPanelTextF(hStatsPanel, " %s", g_PlayerStates[client][bDuck] ? "Duck" : g_PlayerStates[client][bLastDuckState] ? "Partial Duck" : "No Duck"); - - if(g_PlayerStates[client][bLJEnabled]) - { - /*PrintToConsole(client, " %.2f%%", g_PlayerStates[client][fSync]); - - if(g_nVerbosity > 1) - { - PrintToConsole(client, " %.2f/%.2f", g_PlayerStates[client][fSyncedAngle], g_PlayerStates[client][fTotalAngle]); - }*/ - - PrintToConsole(client, " %s", g_PlayerStates[client][bDuck] ? "Duck" : g_PlayerStates[client][bLastDuckState] ? "Partial Duck" : "No Duck"); - - PrintToConsole(client, ""); // Newline - } - - if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][JumpType] != JT_BHOP && g_PlayerStates[client][IllegalJumpFlags]) - { - PrintToConsole(client, "Illegal jump: "); - - if(g_PlayerStates[client][IllegalJumpFlags] & IJF_WORLD) - { - PrintToConsole(client, "Lateral world collision (hit wall/surf)"); - } - - if(g_PlayerStates[client][IllegalJumpFlags] & IJF_BOOSTER) - { - PrintToConsole(client, "Booster"); - } - - if(g_PlayerStates[client][IllegalJumpFlags] & IJF_GRAVITY) - { - PrintToConsole(client, "Gravity"); - } - - if(g_PlayerStates[client][IllegalJumpFlags] & IJF_TELEPORT) - { - PrintToConsole(client, "Teleport"); - } - - if(g_PlayerStates[client][IllegalJumpFlags] & IJF_LAGGEDMOVEMENTVALUE) - { - PrintToConsole(client, "Lagged movement value"); - } - - if(g_PlayerStates[client][IllegalJumpFlags] & IJF_PRESTRAFE) - { - PrintToConsole(client, "Prestrafe > %.2f", g_fLJMaxPrestrafe); - } - - if(g_PlayerStates[client][IllegalJumpFlags] & IJF_SCOUT) - { - PrintToConsole(client, "Scout"); - } - - if(g_PlayerStates[client][IllegalJumpFlags] & IJF_NOCLIP) - { - PrintToConsole(client, "noclip"); - } - - PrintToConsole(client, ""); // Newline - } - - if(g_PlayerStates[client][bLJEnabled] && !g_PlayerStates[client][bHidePanel] && g_PlayerStates[client][nVerbosity] > 0 && !(g_PlayerStates[client][bHideBhopPanel] && g_PlayerStates[client][nBhops] > 1)) - { - SendPanelToClient(hStatsPanel, client, EmptyPanelHandler, 5); - } - - - - // Send to spectators of this player - for(new i = 1; i <= MaxClients; i++) - { - if(IsClientInGame(i) && !IsClientSourceTV(i) && !IsClientReplay(i) && !IsFakeClient(i)) - { - if(g_PlayerStates[i][nSpectatorTarget] == client) - { - if(g_PlayerStates[i][nVerbosity] > 0 && !g_PlayerStates[i][bHidePanel]) - { - SendPanelToClient(hStatsPanel, i, EmptyPanelHandler, 5); - } - - new Handle:hBuffer2 = StartMessageOne("KeyHintText", i); - BfWriteByte(hBuffer2, 1); - BfWriteString(hBuffer2, g_PlayerStates[client][strHUDHint]); - EndMessage(); - } - } - } - - CloseHandle(hStatsPanel); - - - //// - // Print chat message - //// - - if(!g_PlayerStates[client][bLJEnabled] || - g_PlayerStates[client][IllegalJumpFlags] != IJF_NONE || - g_PlayerStates[client][fHeightDelta] < HEIGHT_DELTA_MIN(JUMP_TYPE:(g_PlayerStates[client][JumpType] == JT_BHOP ? JT_BHOPJUMP : g_PlayerStates[client][JumpType])) || - g_PlayerStates[client][bFailedBlock] && !g_bPrintFailedBlockStats) - { - return; - } - - if(g_PlayerStates[client][JumpType] == JT_BHOPJUMP && g_PlayerStates[client][fLastJumpHeightDelta] < HEIGHT_DELTA_MIN(JT_BHOPJUMP)) - { - return; - } - - - switch(g_PlayerStates[client][JumpType]) - { - case JT_LONGJUMP, JT_COUNTJUMP: - { - new Float:fMin = (g_fLJNoDuckMin != 0.0 && !g_PlayerStates[client][bDuck] && !g_PlayerStates[client][bLastDuckState]) ? g_fLJNoDuckMin : g_fLJMin; - - if(fMin != 0.0 && g_PlayerStates[client][fJumpDistance] >= fMin) - { - OutputJump(client, buf); - } - - if(g_bLJSound && g_PlayerStates[client][bSound]) - { - for(new i = 0; i < LJSOUND_NUM; i++) - { - if(g_PlayerStates[client][fJumpDistance] >= g_fLJSound[i]) - { - if(i == LJSOUND_NUM || g_PlayerStates[client][fJumpDistance] < g_fLJSound[i + 1] || g_fLJSound[i + 1] == 0.0) - { - if(g_bLJSoundToAll[i]) - { - for(new j = 1; j < MaxClients; j++) - { - if(IsClientInGame(client) && !IsFakeClient(client) && g_PlayerStates[j][bSound] && IsClientInGame(j)) - { - EmitSoundToClient(j, g_strLJSoundFile[i]); - } - } - } - else - { - EmitSoundToClient(client, g_strLJSoundFile[i]); - } - - break; - } - } - else - { - break; - } - } - } - } - - case JT_WEIRDJUMP: - { - if(g_fWJMin != 0.0 && g_PlayerStates[client][fJumpDistance] > g_fWJMin && (g_fWJDropMax == 0.0 || g_fWJDropMax >= FloatAbs(g_PlayerStates[client][fLastJumpHeightDelta]))) - { - OutputJump(client, buf); - } - } - - case JT_BHOPJUMP: - { - if(g_fBJMin != 0.0 && g_PlayerStates[client][fJumpDistance] >= g_fBJMin) - { - OutputJump(client, buf); - } + g_PlayerStates[client][bOnGround] = true; + + g_PlayerStates[client][fLandTime] = GetGameTime(); + + if(!g_PlayerStates[client][bLJEnabled] && !g_PlayerStates[client][nSpectators] || !g_PlayerStates[client][bShowBhopStats] && g_PlayerStates[client][nBhops] > 1) + return; + + + + // Final CheckValidJump + //CheckValidJump(client); + + + new Float:vCurOrigin[3]; + GetClientAbsOrigin(client, vCurOrigin); + g_PlayerStates[client][fFinalSpeed] = GetSpeed(client); + + + #if defined DEBUG + if(g_PlayerStates[client][bFailedBlock] && vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] > -2.0) + PrintToChat(client, "failed block && height delta = %f", vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2]); + + PrintToChat(client, "%d", g_PlayerStates[client][bFailedBlock]); + #endif + + // Calculate distances + if(!g_PlayerStates[client][bFailedBlock])// || // if block longjump failed, distances have already been written in mid-air. + //vCurOrigin[2] - g_PlayerStates[client][vJumpOrigin][2] >= HEIGHT_DELTA_MIN(JT_LONGJUMP)) // bugs sometimes if you land on last tick (I think) idk how else 2 fix + { + GetJumpDistance(client); + + g_PlayerStates[client][bFailedBlock] = false; + } + + // don't show drop stats + if(g_PlayerStates[client][JumpType] == JT_DROP) + return; + + if(!g_PlayerStates[client][bShowAllJumps]) + { + if(g_PlayerStates[client][JumpType] == JT_LONGJUMP) + { + if(g_PlayerStates[client][fHeightDelta] > HEIGHT_DELTA_MIN(g_PlayerStates[client][JumpType]) && g_PlayerStates[client][fHeightDelta] < HEIGHT_DELTA_MAX(g_PlayerStates[client][JumpType])) + { + if(g_PlayerStates[client][fJumpDistance] < 240.0) + { + return; + } + } + else // Dropjump/upjump + { + if(g_PlayerStates[client][fJumpDistance] < 240.0 - g_PlayerStates[client][fHeightDelta]) + { + return; + } + } + } + else if(g_PlayerStates[client][fJumpDistance] < 240.0) + { + return; + } + } + + // Check whether the player actually moved past the block edge + if(g_PlayerStates[client][bBlockMode] && !g_PlayerStates[client][bFailedBlock]) + { + if(!g_PlayerStates[client][vBlockNormal][0] || !g_PlayerStates[client][vBlockNormal][1]) + { + // bools are not actually handled as 1 bit bools but 32 bit cells so n = normal.y gives out of bounds exception + // !!normal.y or !normal.x rather + // pawn good + new bool:n = !g_PlayerStates[client][vBlockNormal][0]; + + if(g_PlayerStates[client][vBlockNormal][n] > 0.0) + { + if(vCurOrigin[n] + 16.0 * g_PlayerStates[client][vBlockNormal][n] < g_PlayerStates[client][vBlockEndPos][n]) + { + g_PlayerStates[client][bFailedBlock] = true; + } + } + else + { + if(vCurOrigin[n] + 16.0 * g_PlayerStates[client][vBlockNormal][n] > g_PlayerStates[client][vBlockEndPos][n]) + { + g_PlayerStates[client][bFailedBlock] = true; + } + } + } + else + { + new Float:vAdjCurOrigin[3], Float:vInvNormal[3]; + vAdjCurOrigin = vCurOrigin; + Array_Copy(g_PlayerStates[client][vBlockNormal], vInvNormal, 2); + ScaleVector(vInvNormal, -1.0); + Adjust(vAdjCurOrigin, vInvNormal); + + + // f(endpos.x) + (origin.x - endpos.x) * b = (f(endpos.x) - endpos.x * b) + origin.x * b = f(0) + origin.x * b + // block normal is perpendicular to the edge direction, so b = 1 / (normal rot 90).x + // dx and dy should have same sign so ccw rot if facing down, cw rot if up + new Float:b = 1 / (g_PlayerStates[client][vBlockNormal][0] < 0 ? g_PlayerStates[client][vBlockNormal][1] : -g_PlayerStates[client][vBlockNormal][1]); + new Float:fPos = g_PlayerStates[client][vBlockEndPos][1] + (vAdjCurOrigin[0] - g_PlayerStates[client][vBlockEndPos][0]) * b; + + if(g_PlayerStates[client][vBlockNormal][1] > 0.0 ? vAdjCurOrigin[1] < fPos : vAdjCurOrigin[1] > fPos) + { + g_PlayerStates[client][bFailedBlock] = true; + } + + + #if defined DEBUG + PrintToChat(client, "block normal: %.2f, %.2f\n%.2f, %.2f, %.2f", + g_PlayerStates[client][vBlockNormal][0], + g_PlayerStates[client][vBlockNormal][1], + vAdjCurOrigin[1], + fPos, + g_PlayerStates[client][vBlockEndPos][1]); + + new Float:v1[3], Float:v2[3]; + v1[2] = g_PlayerStates[client][vBlockEndPos][2] + 0.1; + v2[2] = g_PlayerStates[client][vBlockEndPos][2] + 0.1; + v1[0] = g_PlayerStates[client][vBlockEndPos][0] - 50; + v1[1] = g_PlayerStates[client][vBlockEndPos][1] + (v1[0] - g_PlayerStates[client][vBlockEndPos][0]) * b; + v2[0] = g_PlayerStates[client][vBlockEndPos][0] + 50; + v2[1] = g_PlayerStates[client][vBlockEndPos][1] + (v2[0] - g_PlayerStates[client][vBlockEndPos][0]) * b; + CreateBeam2(v1, v2, 0, 0, 255); + + if(g_PlayerStates[client][bFailedBlock]) + { + PrintToChat(client, "failedblocklongjump 2"); + } + #endif + } + } + + + // sum sync + g_PlayerStates[client][fSync] = 0.0; + + for(new i = 0; i < g_PlayerStates[client][nStrafes] && i < MAX_STRAFES; i++) + { + g_PlayerStates[client][fSync] += g_PlayerStates[client][nStrafeTicksSynced][i]; + g_PlayerStates[client][fStrafeSync][i] = float(g_PlayerStates[client][nStrafeTicksSynced][i]) / g_PlayerStates[client][nStrafeTicks][i] * 100; + } + + g_PlayerStates[client][fSync] /= g_PlayerStates[client][nTotalTicks]; + g_PlayerStates[client][fSync] *= 100; + + + + + //// + // Write HUD hint + //// + + decl String:buf[1024]; + + g_PlayerStates[client][strHUDHint][0] = 0; + + + decl String:strJump[32]; + + if(g_PlayerStates[client][fHeightDelta] > HEIGHT_DELTA_MAX(g_PlayerStates[client][JumpType])) + { + if(g_PlayerStates[client][JumpType] == JT_LONGJUMP) + { + strJump = "Upjump"; + } + else + { + Format(strJump, sizeof(strJump), "Up%s", g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); + } + } + else if(g_PlayerStates[client][fHeightDelta] < HEIGHT_DELTA_MIN(g_PlayerStates[client][JumpType])) + { + if(g_PlayerStates[client][JumpType] == JT_LONGJUMP) + { + strJump = "Dropjump"; + } + else + { + Format(strJump, sizeof(strJump), "Drop%s", g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); + } + } + else + { + strcopy(strJump, sizeof(strJump), g_strJumpType[g_PlayerStates[client][JumpType]]); + } + + decl String:strJumpDir[16]; + strJumpDir = g_PlayerStates[client][JumpDir] == JD_SIDEWAYS ? " sideways" : g_PlayerStates[client][JumpDir] == JD_BACKWARDS ? " backwards" : ""; + + Format(buf, sizeof(buf), "%s%s%s\npre: %.2f", + strJump, strJumpDir, + g_PlayerStates[client][JumpType] == JT_LONGJUMP && + g_PlayerStates[client][fHeightDelta] >= HEIGHT_DELTA_MIN(g_PlayerStates[client][JumpType]) && + g_PlayerStates[client][IllegalJumpFlags] == IJF_NONE && + g_PlayerStates[client][nTotalTicks] > 77 ? " (extended)" : "", + g_PlayerStates[client][fPrestrafe]); + + StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); + + if(g_PlayerStates[client][JumpType] == JT_WEIRDJUMP && g_PlayerStates[client][nVerbosity] > 1) + { + Format(buf, sizeof(buf), " (%.2f)", + g_PlayerStates[client][fWJDropPre]); + + StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); + } + + Format(buf, sizeof(buf), "; dist: %.2f", + g_PlayerStates[client][fJumpDistance]); + + StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); + + if(g_PlayerStates[client][fEdge] != -1.0) + { + Format(buf, sizeof(buf), "; edge: %.2f", + g_PlayerStates[client][fEdge]); + + StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); + } + + StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, "\n"); + + Format(buf, sizeof(buf), "strafes: %d (%.0f); max: %.2f", + g_PlayerStates[client][nStrafes], + g_PlayerStates[client][fSync], + g_PlayerStates[client][fMaxSpeed]); + + StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); + + if(g_PlayerStates[client][nVerbosity] > 2) + { + Format(buf, sizeof(buf), "\n%s%.2f; %.2f; %.4f%; %d", + g_PlayerStates[client][fHeightDelta] >= 0.0 ? "+" : "", + g_PlayerStates[client][fHeightDelta], + g_PlayerStates[client][fJumpHeight], + (g_PlayerStates[client][fJumpDistance] - 32.0) / g_PlayerStates[client][fTrajectory], + g_PlayerStates[client][nTotalTicks]); + + StrCat(g_PlayerStates[client][strHUDHint], HUD_HINT_SIZE, buf); + } + + + if(g_PlayerStates[client][bLJEnabled]) + { + buf[0] = 0; + + Append(buf, sizeof(buf), "\n"); + + + Append(buf, sizeof(buf), "%s%s%s\nDistance: %.2f", + strJump, strJumpDir, + g_PlayerStates[client][JumpType] == JT_LONGJUMP && + g_PlayerStates[client][fHeightDelta] > HEIGHT_DELTA_MIN(g_PlayerStates[client][JumpType]) + && g_PlayerStates[client][nTotalTicks] > 77 ? " (extended)" : "", + g_PlayerStates[client][fJumpDistance]); + + Append(buf, sizeof(buf), "; prestrafe: %.2f", + g_PlayerStates[client][fPrestrafe]); + + if(g_PlayerStates[client][JumpType] == JT_WEIRDJUMP) + { + Append(buf, sizeof(buf), "; drop prestrafe: %.2f", + g_PlayerStates[client][fWJDropPre]); + } + + if(g_PlayerStates[client][fEdge] != -1.0) + { + Append(buf, sizeof(buf), "; edge: %.2f", + g_PlayerStates[client][fEdge]); + } + + if(g_PlayerStates[client][nTotalTicks] == 78) + { + new Float:vCurOrigin2[3]; + Array_Copy(g_PlayerStates[client][vLastOrigin], vCurOrigin2, 3); + + vCurOrigin2[2] = 0.0; + + new Float:v[3]; + Array_Copy(g_PlayerStates[client][vJumpOrigin], v, 3); + + v[2] = 0.0; + + new Float:ProjDist = GetVectorDistance(v, vCurOrigin2) + 32.0; + + Append(buf, sizeof(buf), "; projected real distance: %.2f", ProjDist); + } + + Append(buf, sizeof(buf), "\nStrafes: %d; sync: %.2f%%; maxspeed (gain): %.2f (%.2f)", + g_PlayerStates[client][nStrafes], + g_PlayerStates[client][fSync], + g_PlayerStates[client][fMaxSpeed], + g_PlayerStates[client][fMaxSpeed] - g_PlayerStates[client][fPrestrafe]); + + Append(buf, sizeof(buf), "\nHeight diff: %s%.2f; jump height: %.2f; efficiency: %.4f; ticks: %d; degrees synced/degrees turned: %.2f/%.2f", + g_PlayerStates[client][fHeightDelta] >= 0.0 ? "+" : "", + g_PlayerStates[client][fHeightDelta], + g_PlayerStates[client][fJumpHeight], + (g_PlayerStates[client][fJumpDistance] - 32.0) / g_PlayerStates[client][fTrajectory], + g_PlayerStates[client][nTotalTicks], + g_PlayerStates[client][fSyncedAngle], g_PlayerStates[client][fTotalAngle]); + + PrintToConsole(client, buf); + + + new Handle:hBuffer = StartMessageOne("KeyHintText", client); + BfWriteByte(hBuffer, 1); + BfWriteString(hBuffer, g_PlayerStates[client][strHUDHint]); + EndMessage(); + } + + + //// + // Panel + //// + + new Handle:hStatsPanel = CreatePanel(); + + + Format(buf, 128, "%s %.2f %s%.2f", + g_strJumpTypeShort[g_PlayerStates[client][JumpType]], + g_PlayerStates[client][fJumpDistance], + g_PlayerStates[client][fHeightDelta] > 0.01 ? "+" : "", + g_PlayerStates[client][fHeightDelta]); + + SetPanelTitle(hStatsPanel, buf); + + + if(g_PlayerStates[client][bLJEnabled]) + { + PrintToConsole(client, "--------------------------------"); + } + + // Print first 16 strafes to panel + for(new i = 0; i < g_PlayerStates[client][nStrafes] && i < 16; i++) + { + decl String:strStrafeKey[3]; + GetStrafeKey(strStrafeKey, g_PlayerStates[client][StrafeDir][i]); + DrawPanelTextF(hStatsPanel, "%d %s %.2f %.2f %.2f %.2f", + i + 1, + strStrafeKey, + g_PlayerStates[client][fStrafeGain][i], g_PlayerStates[client][fStrafeLoss][i], + float(g_PlayerStates[client][nStrafeTicks][i]) / g_PlayerStates[client][nTotalTicks] * 100, + float(g_PlayerStates[client][nStrafeTicksSynced][i]) / g_PlayerStates[client][nStrafeTicks][i] * 100); + } + + // Print strafes to console + if(g_PlayerStates[client][bLJEnabled]) + { + PrintToConsole(client, "# Key Gain Loss Time Sync"); + + for(new i = 0; i < g_PlayerStates[client][nStrafes] && i < MAX_STRAFES; i++) + { + decl String:strStrafeKey[3]; + GetStrafeKey(strStrafeKey, g_PlayerStates[client][StrafeDir][i]); + Format(buf, sizeof(buf), "%d %s %6.2f %6.2f %6.2f %6.2f", i + 1, + strStrafeKey, + g_PlayerStates[client][fStrafeGain][i], g_PlayerStates[client][fStrafeLoss][i], + float(g_PlayerStates[client][nStrafeTicks][i]) / g_PlayerStates[client][nTotalTicks] * 100, + float(g_PlayerStates[client][nStrafeTicksSynced][i]) / g_PlayerStates[client][nStrafeTicks][i] * 100); + + PrintToConsole(client, buf); + } + } + + DrawPanelTextF(hStatsPanel, " %.2f%%", g_PlayerStates[client][fSync]); + + if(g_PlayerStates[client][nVerbosity] > 2) + { + DrawPanelTextF(hStatsPanel, " %.2f/%.2f", g_PlayerStates[client][fSyncedAngle], g_PlayerStates[client][fTotalAngle]); + } + + DrawPanelTextF(hStatsPanel, " %s", g_PlayerStates[client][bDuck] ? "Duck" : g_PlayerStates[client][bLastDuckState] ? "Partial Duck" : "No Duck"); + + if(g_PlayerStates[client][bLJEnabled]) + { + /*PrintToConsole(client, " %.2f%%", g_PlayerStates[client][fSync]); + + if(g_nVerbosity > 1) + { + PrintToConsole(client, " %.2f/%.2f", g_PlayerStates[client][fSyncedAngle], g_PlayerStates[client][fTotalAngle]); + }*/ + + PrintToConsole(client, " %s", g_PlayerStates[client][bDuck] ? "Duck" : g_PlayerStates[client][bLastDuckState] ? "Partial Duck" : "No Duck"); + + PrintToConsole(client, ""); // Newline + } + + if(g_PlayerStates[client][bLJEnabled] && g_PlayerStates[client][JumpType] != JT_BHOP && g_PlayerStates[client][IllegalJumpFlags]) + { + PrintToConsole(client, "Illegal jump: "); + + if(g_PlayerStates[client][IllegalJumpFlags] & IJF_WORLD) + { + PrintToConsole(client, "Lateral world collision (hit wall/surf)"); + } + + if(g_PlayerStates[client][IllegalJumpFlags] & IJF_BOOSTER) + { + PrintToConsole(client, "Booster"); + } + + if(g_PlayerStates[client][IllegalJumpFlags] & IJF_GRAVITY) + { + PrintToConsole(client, "Gravity"); + } + + if(g_PlayerStates[client][IllegalJumpFlags] & IJF_TELEPORT) + { + PrintToConsole(client, "Teleport"); + } + + if(g_PlayerStates[client][IllegalJumpFlags] & IJF_LAGGEDMOVEMENTVALUE) + { + PrintToConsole(client, "Lagged movement value"); + } + + if(g_PlayerStates[client][IllegalJumpFlags] & IJF_PRESTRAFE) + { + PrintToConsole(client, "Prestrafe > %.2f", g_fLJMaxPrestrafe); + } + + if(g_PlayerStates[client][IllegalJumpFlags] & IJF_SCOUT) + { + PrintToConsole(client, "Scout"); + } + + if(g_PlayerStates[client][IllegalJumpFlags] & IJF_NOCLIP) + { + PrintToConsole(client, "noclip"); + } + + PrintToConsole(client, ""); // Newline + } + + if(g_PlayerStates[client][bLJEnabled] && !g_PlayerStates[client][bHidePanel] && g_PlayerStates[client][nVerbosity] > 0 && !(g_PlayerStates[client][bHideBhopPanel] && g_PlayerStates[client][nBhops] > 1)) + { + SendPanelToClient(hStatsPanel, client, EmptyPanelHandler, 5); + } + + + + // Send to spectators of this player + for(new i = 1; i <= MaxClients; i++) + { + if(IsClientInGame(i) && !IsClientSourceTV(i) && !IsClientReplay(i) && !IsFakeClient(i)) + { + if(g_PlayerStates[i][nSpectatorTarget] == client) + { + if(g_PlayerStates[i][nVerbosity] > 0 && !g_PlayerStates[i][bHidePanel]) + { + SendPanelToClient(hStatsPanel, i, EmptyPanelHandler, 5); + } + + new Handle:hBuffer2 = StartMessageOne("KeyHintText", i); + BfWriteByte(hBuffer2, 1); + BfWriteString(hBuffer2, g_PlayerStates[client][strHUDHint]); + EndMessage(); + } + } + } + + CloseHandle(hStatsPanel); + + + //// + // Print chat message + //// + + if(!g_PlayerStates[client][bLJEnabled] || + g_PlayerStates[client][IllegalJumpFlags] != IJF_NONE || + g_PlayerStates[client][fHeightDelta] < HEIGHT_DELTA_MIN(JUMP_TYPE:(g_PlayerStates[client][JumpType] == JT_BHOP ? JT_BHOPJUMP : g_PlayerStates[client][JumpType])) || + g_PlayerStates[client][bFailedBlock] && !g_bPrintFailedBlockStats) + { + return; + } + + if(g_PlayerStates[client][JumpType] == JT_BHOPJUMP && g_PlayerStates[client][fLastJumpHeightDelta] < HEIGHT_DELTA_MIN(JT_BHOPJUMP)) + { + return; + } + + + switch(g_PlayerStates[client][JumpType]) + { + case JT_LONGJUMP, JT_COUNTJUMP: + { + new Float:fMin = (g_fLJNoDuckMin != 0.0 && !g_PlayerStates[client][bDuck] && !g_PlayerStates[client][bLastDuckState]) ? g_fLJNoDuckMin : g_fLJMin; + + if(fMin != 0.0 && g_PlayerStates[client][fJumpDistance] >= fMin) + { + OutputJump(client, buf); + } + + if(g_bLJSound && g_PlayerStates[client][bSound]) + { + for(new i = 0; i < LJSOUND_NUM; i++) + { + if(g_PlayerStates[client][fJumpDistance] >= g_fLJSound[i]) + { + if(i == LJSOUND_NUM || g_PlayerStates[client][fJumpDistance] < g_fLJSound[i + 1] || g_fLJSound[i + 1] == 0.0) + { + if(g_bLJSoundToAll[i]) + { + for(new j = 1; j < MaxClients; j++) + { + if(IsClientInGame(client) && !IsFakeClient(client) && g_PlayerStates[j][bSound] && IsClientInGame(j)) + { + EmitSoundToClient(j, g_strLJSoundFile[i]); + } + } + } + else + { + EmitSoundToClient(client, g_strLJSoundFile[i]); + } + + break; + } + } + else + { + break; + } + } + } + } + + case JT_WEIRDJUMP: + { + if(g_fWJMin != 0.0 && g_PlayerStates[client][fJumpDistance] > g_fWJMin && (g_fWJDropMax == 0.0 || g_fWJDropMax >= FloatAbs(g_PlayerStates[client][fLastJumpHeightDelta]))) + { + OutputJump(client, buf); + } + } + + case JT_BHOPJUMP: + { + if(g_fBJMin != 0.0 && g_PlayerStates[client][fJumpDistance] >= g_fBJMin) + { + OutputJump(client, buf); + } if(g_bLJSound && g_PlayerStates[client][bSound]) - { - for(new i = 0; i < LJSOUND_NUM; i++) - { - if(g_PlayerStates[client][fJumpDistance] >= g_fBJSound[i]) - { - if(i == (LJSOUND_NUM - 1) || g_PlayerStates[client][fJumpDistance] < g_fBJSound[i + 1] || g_fBJSound[i + 1] == 0.0) - { - if(g_bLJSoundToAll[i]) - { - for(new j = 1; j < MaxClients; j++) - { - if(IsClientInGame(client) && !IsFakeClient(client) && g_PlayerStates[j][bSound] && IsClientInGame(j)) - { - EmitSoundToClient(j, g_strLJSoundFile[i]); - } - } - } - else - { - EmitSoundToClient(client, g_strLJSoundFile[i]); - } - - break; - } - } - else - { - break; - } - } - } - } - - case JT_LADDERJUMP: - { - if(g_fLAJMin != 0.0 && g_PlayerStates[client][fJumpDistance] >= g_fLAJMin) - { - OutputJump(client, buf); - } - } - } - - UpdatePersonalBest(client); - - LJTopUpdate(client); + { + for(new i = 0; i < LJSOUND_NUM; i++) + { + if(g_PlayerStates[client][fJumpDistance] >= g_fBJSound[i]) + { + if(i == (LJSOUND_NUM - 1) || g_PlayerStates[client][fJumpDistance] < g_fBJSound[i + 1] || g_fBJSound[i + 1] == 0.0) + { + if(g_bLJSoundToAll[i]) + { + for(new j = 1; j < MaxClients; j++) + { + if(IsClientInGame(client) && !IsFakeClient(client) && g_PlayerStates[j][bSound] && IsClientInGame(j)) + { + EmitSoundToClient(j, g_strLJSoundFile[i]); + } + } + } + else + { + EmitSoundToClient(client, g_strLJSoundFile[i]); + } + + break; + } + } + else + { + break; + } + } + } + } + + case JT_LADDERJUMP: + { + if(g_fLAJMin != 0.0 && g_PlayerStates[client][fJumpDistance] >= g_fLAJMin) + { + OutputJump(client, buf); + } + } + } + + UpdatePersonalBest(client); + + LJTopUpdate(client); } public EmptyPanelHandler(Handle:hPanel, MenuAction:ma, Param1, Param2) @@ -3679,31 +3994,31 @@ public EmptyPanelHandler(Handle:hPanel, MenuAction:ma, Param1, Param2) OutputJump(client, String:buf[1024]) { - new Float:fMin = (g_fLJNoDuckMin != 0.0 && !g_PlayerStates[client][bDuck] && !g_PlayerStates[client][bLastDuckState]) ? g_fLJNoDuckMin : g_fLJMin; - new Float:fMinClamp = g_fLJMin ? g_fLJMin : g_fLJNoDuckMin ? g_fLJNoDuckMin : g_fLJClientMin; - new Float:fMax = g_fLJMax; - - new bool:bPrintToAll = true; - - if(g_PlayerStates[client][JumpType] == JT_LONGJUMP && g_fLJClientMin != 0 && g_PlayerStates[client][fJumpDistance] < fMin) - { - fMin = g_fLJClientMin; - bPrintToAll = false; - } - - if(!g_bOutput16Style) - { - decl String:strOutput[512]; - - decl String:strName[64]; - GetClientName(client, strName, sizeof(strName)); - - Format(strOutput, sizeof(strOutput), "%s {green}%s%sed ", - strName, - g_PlayerStates[client][JumpType] == JT_BHOPJUMP && g_PlayerStates[client][bStamina] ? "easy" : "", - g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); - - if(g_PlayerStates[client][JumpType] != JT_LADDERJUMP) + new Float:fMin = (g_fLJNoDuckMin != 0.0 && !g_PlayerStates[client][bDuck] && !g_PlayerStates[client][bLastDuckState]) ? g_fLJNoDuckMin : g_fLJMin; + new Float:fMinClamp = g_fLJMin ? g_fLJMin : g_fLJNoDuckMin ? g_fLJNoDuckMin : g_fLJClientMin; + new Float:fMax = g_fLJMax; + + new bool:bPrintToAll = true; + + if(g_PlayerStates[client][JumpType] == JT_LONGJUMP && g_fLJClientMin != 0 && g_PlayerStates[client][fJumpDistance] < fMin) + { + fMin = g_fLJClientMin; + bPrintToAll = false; + } + + if(!g_bOutput16Style) + { + decl String:strOutput[512]; + + decl String:strName[64]; + GetClientName(client, strName, sizeof(strName)); + + Format(strOutput, sizeof(strOutput), "%s {green}%s%sed ", + strName, + g_PlayerStates[client][JumpType] == JT_BHOPJUMP && g_PlayerStates[client][bStamina] ? "easy" : "", + g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); + + if(g_PlayerStates[client][JumpType] != JT_LADDERJUMP) { if(g_PlayerStates[client][JumpType] != JT_LONGJUMP && g_PlayerStates[client][JumpType] != JT_COUNTJUMP) @@ -3734,178 +4049,178 @@ OutputJump(client, String:buf[1024]) nColor[0], nColor[1], nColor[2]); StrCat(strOutput, sizeof(strOutput), buf); - } - - Format(buf, sizeof(buf), "%.2f{green} units", g_PlayerStates[client][fJumpDistance]); - - StrCat(strOutput, sizeof(strOutput), buf); - - if(g_PlayerStates[client][JumpDir] != JD_FORWARDS) - { - if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS) - { - StrCat(strOutput, sizeof(strOutput), " sideways"); - } - else if(g_PlayerStates[client][JumpDir] == JD_BACKWARDS) - { - StrCat(strOutput, sizeof(strOutput), " backwards"); - } - } - - if(!g_PlayerStates[client][bDuck] && !g_PlayerStates[client][bLastDuckState]) - { - StrCat(strOutput, sizeof(strOutput), " no duck"); - } - - if(g_PlayerStates[client][bBlockMode]) - { - if(g_PlayerStates[client][fBlockDistance] != -1.0) - { - Format(buf, sizeof(buf), " @ %.1f block%s", g_PlayerStates[client][fBlockDistance], g_PlayerStates[client][bFailedBlock] ? " (failed)" : ""); - - StrCat(strOutput, sizeof(strOutput), buf); - } - else if(g_PlayerStates[client][bFailedBlock]) - { - StrCat(strOutput, sizeof(strOutput), " @ ? block (failed)"); - } - } - - StrCat(strOutput, sizeof(strOutput), "!"); - - if(g_nVerbosity > 1) - { - Format(buf, sizeof(buf), " ({lightblue}%.2f{green}, {lightblue}%d{green} @ {lightblue}%d%%{green}, {lightblue}%d{green}", - g_PlayerStates[client][fPrestrafe], g_PlayerStates[client][nStrafes], RoundFloat(g_PlayerStates[client][fSync]), RoundFloat(g_PlayerStates[client][fMaxSpeed])); - - StrCat(strOutput, sizeof(strOutput), buf); - } - else if(g_nVerbosity > 0) - { - Format(buf, sizeof(buf), " ({lightblue}%.2f{green}, {lightblue}%d{green} @ {lightblue}%d%%{green}", - g_PlayerStates[client][fPrestrafe], g_PlayerStates[client][nStrafes], RoundFloat(g_PlayerStates[client][fSync])); - - StrCat(strOutput, sizeof(strOutput), buf); - } - - if(g_PlayerStates[client][bBlockMode] && g_PlayerStates[client][fBlockDistance] != -1.0 && g_PlayerStates[client][fEdge] != -1.0) - { - Format(buf, sizeof(buf), ", edge: {lightblue}%.2f{default}", g_PlayerStates[client][fEdge]); - - StrCat(strOutput, sizeof(strOutput), buf); - } - - StrCat(strOutput, sizeof(strOutput), ")"); - - if(bPrintToAll) - { - CPrintToChatAll("%s", strOutput); - } - else - { - CPrintToChat(client, "%s", strOutput); - } - } - else - { - decl String:strOutput[512]; - - if(g_PlayerStates[client][fJumpDistance] < (g_PlayerStates[client][JumpType] == JT_LONGJUMP ? 265.0 : g_PlayerStates[client][JumpType] == JT_LADDERJUMP ? 155.0 : 285.0)) - { - strcopy(strOutput, sizeof(strOutput), "{white}"); - } - else if(g_PlayerStates[client][fJumpDistance] < (g_PlayerStates[client][JumpType] == JT_LONGJUMP ? 268.0 : g_PlayerStates[client][JumpType] == JT_LADDERJUMP ? 165.0 : 295.0)) - { - strcopy(strOutput, sizeof(strOutput), "{green}"); - } - else - { - strcopy(strOutput, sizeof(strOutput), "{red}"); - } - - decl String:strName[64]; - GetClientName(client, strName, sizeof(strName)); - - Format(buf, sizeof(buf), "%s jumped %.2f units", - strName, g_PlayerStates[client][fJumpDistance]); - - StrCat(strOutput, sizeof(strOutput), buf); - - if(g_PlayerStates[client][JumpType]) - { - Format(buf, sizeof(buf), " with %s%s", - g_PlayerStates[client][JumpType] == JT_BHOPJUMP && g_PlayerStates[client][bStamina] ? "easy" : "", - g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); - - StrCat(strOutput, sizeof(strOutput), buf); - } - - if(g_PlayerStates[client][JumpDir] != JD_FORWARDS) - { - if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS) - { - StrCat(strOutput, sizeof(strOutput), " sideways"); - } - else if(g_PlayerStates[client][JumpDir] == JD_BACKWARDS) - { - StrCat(strOutput, sizeof(strOutput), " backwards"); - } - } - - if(!g_PlayerStates[client][bDuck] && !g_PlayerStates[client][bLastDuckState]) - { - StrCat(strOutput, sizeof(strOutput), " no duck"); - } - - if(g_PlayerStates[client][bBlockMode]) - { - if(g_PlayerStates[client][fBlockDistance] != -1.0) - { - Format(buf, sizeof(buf), " @ %.1f block%s", g_PlayerStates[client][fBlockDistance], g_PlayerStates[client][bFailedBlock] ? " (failed)" : ""); - - StrCat(strOutput, sizeof(strOutput), buf); - } - else if(g_PlayerStates[client][bFailedBlock]) - { - StrCat(strOutput, sizeof(strOutput), " @ ? block (failed)"); - } - } - - StrCat(strOutput, sizeof(strOutput), "!"); - - if(g_nVerbosity > 2) - { - Format(buf, sizeof(buf), " (%.2f, %d @ %d%%, %d", - g_PlayerStates[client][fPrestrafe], g_PlayerStates[client][nStrafes], RoundFloat(g_PlayerStates[client][fSync]), RoundFloat(g_PlayerStates[client][fMaxSpeed])); - - StrCat(strOutput, sizeof(strOutput), buf); - } - else if(g_nVerbosity > 1) - { - Format(buf, sizeof(buf), " (%.2f, %d @ %d%%", - g_PlayerStates[client][fPrestrafe], g_PlayerStates[client][nStrafes], RoundFloat(g_PlayerStates[client][fSync])); - - StrCat(strOutput, sizeof(strOutput), buf); - } - - if(g_PlayerStates[client][bBlockMode] && g_PlayerStates[client][fBlockDistance] != -1.0 && g_PlayerStates[client][fEdge] != -1.0) - { - Format(buf, sizeof(buf), ", edge: %.2f", g_PlayerStates[client][fEdge]); - - StrCat(strOutput, sizeof(strOutput), buf); - } - - StrCat(strOutput, sizeof(strOutput), ")"); - - if(bPrintToAll) - { - CPrintToChatAll("%s", strOutput); - } - else - { - CPrintToChat(client, "%s", strOutput); - } - } + } + + Format(buf, sizeof(buf), "%.2f{green} units", g_PlayerStates[client][fJumpDistance]); + + StrCat(strOutput, sizeof(strOutput), buf); + + if(g_PlayerStates[client][JumpDir] != JD_FORWARDS) + { + if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS) + { + StrCat(strOutput, sizeof(strOutput), " sideways"); + } + else if(g_PlayerStates[client][JumpDir] == JD_BACKWARDS) + { + StrCat(strOutput, sizeof(strOutput), " backwards"); + } + } + + if(!g_PlayerStates[client][bDuck] && !g_PlayerStates[client][bLastDuckState]) + { + StrCat(strOutput, sizeof(strOutput), " no duck"); + } + + if(g_PlayerStates[client][bBlockMode]) + { + if(g_PlayerStates[client][fBlockDistance] != -1.0) + { + Format(buf, sizeof(buf), " @ %.1f block%s", g_PlayerStates[client][fBlockDistance], g_PlayerStates[client][bFailedBlock] ? " (failed)" : ""); + + StrCat(strOutput, sizeof(strOutput), buf); + } + else if(g_PlayerStates[client][bFailedBlock]) + { + StrCat(strOutput, sizeof(strOutput), " @ ? block (failed)"); + } + } + + StrCat(strOutput, sizeof(strOutput), "!"); + + if(g_nVerbosity > 1) + { + Format(buf, sizeof(buf), " ({lightblue}%.2f{green}, {lightblue}%d{green} @ {lightblue}%d%%{green}, {lightblue}%d{green}", + g_PlayerStates[client][fPrestrafe], g_PlayerStates[client][nStrafes], RoundFloat(g_PlayerStates[client][fSync]), RoundFloat(g_PlayerStates[client][fMaxSpeed])); + + StrCat(strOutput, sizeof(strOutput), buf); + } + else if(g_nVerbosity > 0) + { + Format(buf, sizeof(buf), " ({lightblue}%.2f{green}, {lightblue}%d{green} @ {lightblue}%d%%{green}", + g_PlayerStates[client][fPrestrafe], g_PlayerStates[client][nStrafes], RoundFloat(g_PlayerStates[client][fSync])); + + StrCat(strOutput, sizeof(strOutput), buf); + } + + if(g_PlayerStates[client][bBlockMode] && g_PlayerStates[client][fBlockDistance] != -1.0 && g_PlayerStates[client][fEdge] != -1.0) + { + Format(buf, sizeof(buf), ", edge: {lightblue}%.2f{default}", g_PlayerStates[client][fEdge]); + + StrCat(strOutput, sizeof(strOutput), buf); + } + + StrCat(strOutput, sizeof(strOutput), ")"); + + if(bPrintToAll) + { + CPrintToChatAll("%s", strOutput); + } + else + { + CPrintToChat(client, "%s", strOutput); + } + } + else + { + decl String:strOutput[512]; + + if(g_PlayerStates[client][fJumpDistance] < (g_PlayerStates[client][JumpType] == JT_LONGJUMP ? 265.0 : g_PlayerStates[client][JumpType] == JT_LADDERJUMP ? 155.0 : 285.0)) + { + strcopy(strOutput, sizeof(strOutput), "{white}"); + } + else if(g_PlayerStates[client][fJumpDistance] < (g_PlayerStates[client][JumpType] == JT_LONGJUMP ? 268.0 : g_PlayerStates[client][JumpType] == JT_LADDERJUMP ? 165.0 : 295.0)) + { + strcopy(strOutput, sizeof(strOutput), "{green}"); + } + else + { + strcopy(strOutput, sizeof(strOutput), "{red}"); + } + + decl String:strName[64]; + GetClientName(client, strName, sizeof(strName)); + + Format(buf, sizeof(buf), "%s jumped %.2f units", + strName, g_PlayerStates[client][fJumpDistance]); + + StrCat(strOutput, sizeof(strOutput), buf); + + if(g_PlayerStates[client][JumpType]) + { + Format(buf, sizeof(buf), " with %s%s", + g_PlayerStates[client][JumpType] == JT_BHOPJUMP && g_PlayerStates[client][bStamina] ? "easy" : "", + g_strJumpTypeLwr[g_PlayerStates[client][JumpType]]); + + StrCat(strOutput, sizeof(strOutput), buf); + } + + if(g_PlayerStates[client][JumpDir] != JD_FORWARDS) + { + if(g_PlayerStates[client][JumpDir] == JD_SIDEWAYS) + { + StrCat(strOutput, sizeof(strOutput), " sideways"); + } + else if(g_PlayerStates[client][JumpDir] == JD_BACKWARDS) + { + StrCat(strOutput, sizeof(strOutput), " backwards"); + } + } + + if(!g_PlayerStates[client][bDuck] && !g_PlayerStates[client][bLastDuckState]) + { + StrCat(strOutput, sizeof(strOutput), " no duck"); + } + + if(g_PlayerStates[client][bBlockMode]) + { + if(g_PlayerStates[client][fBlockDistance] != -1.0) + { + Format(buf, sizeof(buf), " @ %.1f block%s", g_PlayerStates[client][fBlockDistance], g_PlayerStates[client][bFailedBlock] ? " (failed)" : ""); + + StrCat(strOutput, sizeof(strOutput), buf); + } + else if(g_PlayerStates[client][bFailedBlock]) + { + StrCat(strOutput, sizeof(strOutput), " @ ? block (failed)"); + } + } + + StrCat(strOutput, sizeof(strOutput), "!"); + + if(g_nVerbosity > 2) + { + Format(buf, sizeof(buf), " (%.2f, %d @ %d%%, %d", + g_PlayerStates[client][fPrestrafe], g_PlayerStates[client][nStrafes], RoundFloat(g_PlayerStates[client][fSync]), RoundFloat(g_PlayerStates[client][fMaxSpeed])); + + StrCat(strOutput, sizeof(strOutput), buf); + } + else if(g_nVerbosity > 1) + { + Format(buf, sizeof(buf), " (%.2f, %d @ %d%%", + g_PlayerStates[client][fPrestrafe], g_PlayerStates[client][nStrafes], RoundFloat(g_PlayerStates[client][fSync])); + + StrCat(strOutput, sizeof(strOutput), buf); + } + + if(g_PlayerStates[client][bBlockMode] && g_PlayerStates[client][fBlockDistance] != -1.0 && g_PlayerStates[client][fEdge] != -1.0) + { + Format(buf, sizeof(buf), ", edge: %.2f", g_PlayerStates[client][fEdge]); + + StrCat(strOutput, sizeof(strOutput), buf); + } + + StrCat(strOutput, sizeof(strOutput), ")"); + + if(bPrintToAll) + { + CPrintToChatAll("%s", strOutput); + } + else + { + CPrintToChat(client, "%s", strOutput); + } + } } @@ -3922,419 +4237,419 @@ OutputJump(client, String:buf[1024]) public bool:WorldFilter(entity, mask) { - if (entity >= 1 && entity <= MaxClients) - return false; - - return true; + if (entity >= 1 && entity <= MaxClients) + return false; + + return true; } bool:TracePlayer(Float:vEndPos[3], Float:vNormal[3], const Float:vTraceOrigin[3], const Float:vEndPoint[3], bool:bCorrectError = true) { - new Float:vMins[3] = {-16.0, -16.0, 0.0}, Float:vMaxs[3] = {16.0, 16.0, 0.0}; - - TR_TraceHullFilter(vTraceOrigin, vEndPoint, vMins, vMaxs, MASK_PLAYERSOLID, WorldFilter); - - if(!TR_DidHit()) // although tracehull does not ever seem to not hit (merely returning a hit at the end of the line), I'm keeping this here just in case, I guess - { - return false; - } - - TR_GetEndPosition(vEndPos); - TR_GetPlaneNormal(INVALID_HANDLE, vNormal); - - // correct slopes - if(vNormal[2]) - { - vNormal[2] = 0.0; - NormalizeVector(vNormal, vNormal); - } - - #if defined DEBUG - new Float:v1[3], Float:v2[3]; - v1 = vEndPos; - v2 = vEndPos; - - v1[0] += 16.0; - v1[1] += 16.0; - v2[0] += 16.0; - v2[1] -= 16.0; - - CreateBeam2(v1, v2, 0, 255, 0); - - v1[0] -= 32.0; - v1[1] -= 32.0; - - CreateBeam2(v1, v2, 0, 255, 0); - - v2[0] -= 32.0; - v2[1] += 32.0; - - CreateBeam2(v1, v2, 0, 255, 0); - - v1[0] += 32.0; - v1[1] += 32.0; - - CreateBeam2(v1, v2, 0, 255, 0); - #endif - - Adjust(vEndPos, vNormal); - - // dunno where this error comes from - if(bCorrectError) - { - vEndPos[0] -= vNormal[0] * 0.03125; - vEndPos[1] -= vNormal[1] * 0.03125; - } - - new Float:fDist = GetVectorDistance(vTraceOrigin, vEndPos); - return fDist != 0.0 && fDist < GetVectorDistance(vTraceOrigin, vEndPoint); + new Float:vMins[3] = {-16.0, -16.0, 0.0}, Float:vMaxs[3] = {16.0, 16.0, 0.0}; + + TR_TraceHullFilter(vTraceOrigin, vEndPoint, vMins, vMaxs, MASK_PLAYERSOLID, WorldFilter); + + if(!TR_DidHit()) // although tracehull does not ever seem to not hit (merely returning a hit at the end of the line), I'm keeping this here just in case, I guess + { + return false; + } + + TR_GetEndPosition(vEndPos); + TR_GetPlaneNormal(INVALID_HANDLE, vNormal); + + // correct slopes + if(vNormal[2]) + { + vNormal[2] = 0.0; + NormalizeVector(vNormal, vNormal); + } + + #if defined DEBUG + new Float:v1[3], Float:v2[3]; + v1 = vEndPos; + v2 = vEndPos; + + v1[0] += 16.0; + v1[1] += 16.0; + v2[0] += 16.0; + v2[1] -= 16.0; + + CreateBeam2(v1, v2, 0, 255, 0); + + v1[0] -= 32.0; + v1[1] -= 32.0; + + CreateBeam2(v1, v2, 0, 255, 0); + + v2[0] -= 32.0; + v2[1] += 32.0; + + CreateBeam2(v1, v2, 0, 255, 0); + + v1[0] += 32.0; + v1[1] += 32.0; + + CreateBeam2(v1, v2, 0, 255, 0); + #endif + + Adjust(vEndPos, vNormal); + + // dunno where this error comes from + if(bCorrectError) + { + vEndPos[0] -= vNormal[0] * 0.03125; + vEndPos[1] -= vNormal[1] * 0.03125; + } + + new Float:fDist = GetVectorDistance(vTraceOrigin, vEndPos); + return fDist != 0.0 && fDist < GetVectorDistance(vTraceOrigin, vEndPoint); } // no function overloading... @__@ bool:TracePlayer2(Float:vEndPos[3], const Float:vTraceOrigin[3], const Float:vEndPoint[3], bool:bCorrectError = true) { - new Float:vNormal[3]; - - return TracePlayer(vEndPos, vNormal, vTraceOrigin, vEndPoint, bCorrectError); + new Float:vNormal[3]; + + return TracePlayer(vEndPos, vNormal, vTraceOrigin, vEndPoint, bCorrectError); } bool:TraceRay(Float:vEndPos[3], Float:vNormal[3], const Float:vTraceOrigin[3], const Float:vEndPoint[3], bool:bCorrectError = true) { - TR_TraceRayFilter(vTraceOrigin, vEndPoint, MASK_PLAYERSOLID, RayType_EndPoint, WorldFilter); - - if(!TR_DidHit()) - { - return false; - } - - TR_GetEndPosition(vEndPos); - TR_GetPlaneNormal(INVALID_HANDLE, vNormal); - - // correct slopes - if(vNormal[2]) - { - vNormal[2] = 0.0; - NormalizeVector(vNormal, vNormal); - } - - if(bCorrectError) - { - vEndPos[0] -= vNormal[0] * 0.03125; - vEndPos[1] -= vNormal[1] * 0.03125; - } - - new Float:fDist = GetVectorDistance(vTraceOrigin, vEndPos); - return fDist != 0.0 && fDist < GetVectorDistance(vTraceOrigin, vEndPoint); + TR_TraceRayFilter(vTraceOrigin, vEndPoint, MASK_PLAYERSOLID, RayType_EndPoint, WorldFilter); + + if(!TR_DidHit()) + { + return false; + } + + TR_GetEndPosition(vEndPos); + TR_GetPlaneNormal(INVALID_HANDLE, vNormal); + + // correct slopes + if(vNormal[2]) + { + vNormal[2] = 0.0; + NormalizeVector(vNormal, vNormal); + } + + if(bCorrectError) + { + vEndPos[0] -= vNormal[0] * 0.03125; + vEndPos[1] -= vNormal[1] * 0.03125; + } + + new Float:fDist = GetVectorDistance(vTraceOrigin, vEndPos); + return fDist != 0.0 && fDist < GetVectorDistance(vTraceOrigin, vEndPoint); } bool:TraceRay2(Float:vEndPos[3], const Float:vTraceOrigin[3], const Float:vEndPoint[3], bool:bCorrectError = true) { - new Float:vNormal[3]; - - return TraceRay(vEndPos, vNormal, vTraceOrigin, vEndPoint, bCorrectError); + new Float:vNormal[3]; + + return TraceRay(vEndPos, vNormal, vTraceOrigin, vEndPoint, bCorrectError); } bool:IsLeft(const Float:vDir[3], const Float:vNormal[3]) { - if(vNormal[1] > 0) - { - if(vDir[0] > vNormal[0]) - { - return true; - } - else - { - return false; - } - } - else - { - if(vDir[0] > vNormal[0]) - { - return false; - } - else - { - return true; - } - } + if(vNormal[1] > 0) + { + if(vDir[0] > vNormal[0]) + { + return true; + } + else + { + return false; + } + } + else + { + if(vDir[0] > vNormal[0]) + { + return false; + } + else + { + return true; + } + } } // align with normal Align(Float:vOut[3], const Float:v1[3], const Float:v2[3], const Float:vNormal[3]) { - // cardinal - if(!vNormal[0] || !vNormal[1]) - { - if(vNormal[0]) - { - vOut[0] = v2[0]; - vOut[1] = v1[1]; - } - else - { - vOut[0] = v1[0]; - vOut[1] = v2[1]; - } - - return; - } - - // noncardinal - // rotate to cardinal, perform the same operation, rotate the result back - - // [ cos(t) -sin(t) 0 ] - // Rz = [ sin(t) cos(t) 0 ] - // [ 0 0 1 ] - - new Float:vTo[3] = {1.0, 0.0}, Float:fAngle = ArcCosine(GetVectorDotProduct(vNormal, vTo)), Float:fRotatedOriginY, Float:vRotatedEndPos[2]; - - if(IsLeft(vTo, vNormal)) - { - fAngle = -fAngle; - } - - fRotatedOriginY = v1[0] * Sine(fAngle) + v1[1] * Cosine(fAngle); - - vRotatedEndPos[0] = v2[0] * Cosine(fAngle) - v2[1] * Sine(fAngle); - vRotatedEndPos[1] = fRotatedOriginY; - - fAngle = -fAngle; - - vOut[0] = vRotatedEndPos[0] * Cosine(fAngle) - vRotatedEndPos[1] * Sine(fAngle); - vOut[1] = vRotatedEndPos[0] * Sine(fAngle) + vRotatedEndPos[1] * Cosine(fAngle); + // cardinal + if(!vNormal[0] || !vNormal[1]) + { + if(vNormal[0]) + { + vOut[0] = v2[0]; + vOut[1] = v1[1]; + } + else + { + vOut[0] = v1[0]; + vOut[1] = v2[1]; + } + + return; + } + + // noncardinal + // rotate to cardinal, perform the same operation, rotate the result back + + // [ cos(t) -sin(t) 0 ] + // Rz = [ sin(t) cos(t) 0 ] + // [ 0 0 1 ] + + new Float:vTo[3] = {1.0, 0.0}, Float:fAngle = ArcCosine(GetVectorDotProduct(vNormal, vTo)), Float:fRotatedOriginY, Float:vRotatedEndPos[2]; + + if(IsLeft(vTo, vNormal)) + { + fAngle = -fAngle; + } + + fRotatedOriginY = v1[0] * Sine(fAngle) + v1[1] * Cosine(fAngle); + + vRotatedEndPos[0] = v2[0] * Cosine(fAngle) - v2[1] * Sine(fAngle); + vRotatedEndPos[1] = fRotatedOriginY; + + fAngle = -fAngle; + + vOut[0] = vRotatedEndPos[0] * Cosine(fAngle) - vRotatedEndPos[1] * Sine(fAngle); + vOut[1] = vRotatedEndPos[0] * Sine(fAngle) + vRotatedEndPos[1] * Cosine(fAngle); } // Adjust collision hitbox center to periphery (the furthest point you could be from the edge as inferred by the normal) Adjust(Float:vOrigin[3], const Float:vNormal[3]) { - // cardinal - if(!vNormal[0] || !vNormal[1]) - { - vOrigin[0] -= vNormal[0] * 16.0; - vOrigin[1] -= vNormal[1] * 16.0; - - return; - } - - // noncardinal - // since the corner will always be the furthest point, set it to the corner of the normal's quadrant - if(vNormal[0] > 0.0) - { - vOrigin[0] -= 16.0; - } - else - { - vOrigin[0] += 16.0; - } - - if(vNormal[1] > 0.0) - { - vOrigin[1] -= 16.0; - } - else - { - vOrigin[1] += 16.0; - } + // cardinal + if(!vNormal[0] || !vNormal[1]) + { + vOrigin[0] -= vNormal[0] * 16.0; + vOrigin[1] -= vNormal[1] * 16.0; + + return; + } + + // noncardinal + // since the corner will always be the furthest point, set it to the corner of the normal's quadrant + if(vNormal[0] > 0.0) + { + vOrigin[0] -= 16.0; + } + else + { + vOrigin[0] += 16.0; + } + + if(vNormal[1] > 0.0) + { + vOrigin[1] -= 16.0; + } + else + { + vOrigin[1] += 16.0; + } } Float:GetEdge(client) { - new Float:vOrigin[3], Float:vTraceOrigin[3], Float:vDir[3]; - GetClientAbsOrigin(client, vOrigin); - - GetEntPropVector(client, Prop_Data, "m_vecVelocity", vDir); - - NormalizeVector(vDir, vDir); - - vTraceOrigin = vOrigin; - vTraceOrigin[0] += vDir[0] * 64.0; - vTraceOrigin[1] += vDir[1] * 64.0; - vTraceOrigin[2] += RAYTRACE_Z_DELTA; - - new Float:vEndPoint[3]; - vEndPoint = vOrigin; - vEndPoint[0] -= vDir[0] * 16.0 * 1.414214; - vEndPoint[1] -= vDir[1] * 16.0 * 1.414214; - vEndPoint[2] += RAYTRACE_Z_DELTA; - - new Float:vEndPos[3], Float:vNormal[3]; - if(!TracePlayer(vEndPos, vNormal, vTraceOrigin, vEndPoint)) - { - return -1.0; - } - - #if defined DEBUG - CreateLightglow("0 255 0", vOrigin); - #endif - - Adjust(vOrigin, vNormal); - - #if defined DEBUG - CreateLightglow("255 255 255", vEndPos); - CreateLightglow("255 0 0", vOrigin); - #endif - - Align(vEndPos, vOrigin, vEndPos, vNormal); - - #if defined DEBUG - CreateLightglow("0 0 255", vEndPos); - #endif - - // Correct Z -- the trace ray is a bit lower - vEndPos[2] = vOrigin[2]; - - return GetVectorDistance(vEndPos, vOrigin); + new Float:vOrigin[3], Float:vTraceOrigin[3], Float:vDir[3]; + GetClientAbsOrigin(client, vOrigin); + + GetEntPropVector(client, Prop_Data, "m_vecVelocity", vDir); + + NormalizeVector(vDir, vDir); + + vTraceOrigin = vOrigin; + vTraceOrigin[0] += vDir[0] * 64.0; + vTraceOrigin[1] += vDir[1] * 64.0; + vTraceOrigin[2] += RAYTRACE_Z_DELTA; + + new Float:vEndPoint[3]; + vEndPoint = vOrigin; + vEndPoint[0] -= vDir[0] * 16.0 * 1.414214; + vEndPoint[1] -= vDir[1] * 16.0 * 1.414214; + vEndPoint[2] += RAYTRACE_Z_DELTA; + + new Float:vEndPos[3], Float:vNormal[3]; + if(!TracePlayer(vEndPos, vNormal, vTraceOrigin, vEndPoint)) + { + return -1.0; + } + + #if defined DEBUG + CreateLightglow("0 255 0", vOrigin); + #endif + + Adjust(vOrigin, vNormal); + + #if defined DEBUG + CreateLightglow("255 255 255", vEndPos); + CreateLightglow("255 0 0", vOrigin); + #endif + + Align(vEndPos, vOrigin, vEndPos, vNormal); + + #if defined DEBUG + CreateLightglow("0 0 255", vEndPos); + #endif + + // Correct Z -- the trace ray is a bit lower + vEndPos[2] = vOrigin[2]; + + return GetVectorDistance(vEndPos, vOrigin); } Float:GetBlockDistance(client) { - decl Float:vOrigin[3], Float:vTraceOrigin[3], Float:vDir[3], Float:vEndPoint[3]; - GetClientAbsOrigin(client, vOrigin); - - GetEntPropVector(client, Prop_Data, "m_vecVelocity", vDir); - - NormalizeVector(vDir, vDir); - - vTraceOrigin = vOrigin; - vTraceOrigin[0] += vDir[0] * 64.0; - vTraceOrigin[1] += vDir[1] * 64.0; - vTraceOrigin[2] += RAYTRACE_Z_DELTA; - - vEndPoint = vOrigin; - vEndPoint[0] -= vDir[0] * 16.0 * 1.414214; - vEndPoint[1] -= vDir[1] * 16.0 * 1.414214; - vEndPoint[2] += RAYTRACE_Z_DELTA; - - new Float:vBlockStart[3], Float:vNormal[3]; - if(!TracePlayer(vBlockStart, vNormal, vTraceOrigin, vEndPoint)) - { - return -1.0; - } - - new Float:vBlockEnd[3]; - - Array_Copy(vNormal, g_PlayerStates[client][vBlockNormal], 2); - - vEndPoint = vBlockStart; - vEndPoint[0] += vNormal[0] * 300.0; - vEndPoint[1] += vNormal[1] * 300.0; - - if(TracePlayer2(vBlockEnd, vBlockStart, vEndPoint)) - { - Array_Copy(vBlockEnd, g_PlayerStates[client][vBlockEndPos], 3); - - Align(vBlockEnd, vBlockStart, vBlockEnd, vNormal); - - if(vNormal[0] == 0.0 || vNormal[1] == 0.0) - { - return GetVectorDistance(vBlockStart, vBlockEnd); - } - else - { - return GetVectorDistance(vBlockStart, vBlockEnd) - 32.0 * (FloatAbs(vNormal[0]) + FloatAbs(vNormal[1]) - 1.0); - } - } - else - { - // Trace the other direction - - // rotate normal da way opposite da direction - new bool:bLeft = IsLeft(vDir, vNormal); - - vDir = vNormal; - - new Float:fTempSwap = vDir[0]; - - vDir[0] = vDir[1]; - vDir[1] = fTempSwap; - - if(bLeft) - { - vDir[0] = -vDir[0]; - } - else - { - vDir[1] = -vDir[1]; - } - - vTraceOrigin = vOrigin; - vTraceOrigin[0] += vDir[0] * 48.0; - vTraceOrigin[1] += vDir[1] * 48.0; - vTraceOrigin[2] += RAYTRACE_Z_DELTA; - - vEndPoint = vTraceOrigin; - vEndPoint[0] += vNormal[0] * 300.0; - vEndPoint[1] += vNormal[1] * 300.0; - - if(!TracePlayer2(vBlockEnd, vTraceOrigin, vEndPoint)) - { - return -1.0; - } - - Array_Copy(vBlockEnd, g_PlayerStates[client][vBlockEndPos], 3); - - // adjust vBlockStart -- the second trace was on a different axis - Align(vBlockStart, vBlockStart, vBlockEnd, vNormal); - - if(vNormal[0] == 0.0 || vNormal[1] == 0.0) - { - return GetVectorDistance(vBlockStart, vBlockEnd); - } - else - { - return GetVectorDistance(vBlockStart, vBlockEnd) - 32.0 * (FloatAbs(vNormal[0]) + FloatAbs(vNormal[1]) - 1.0); - } - } + decl Float:vOrigin[3], Float:vTraceOrigin[3], Float:vDir[3], Float:vEndPoint[3]; + GetClientAbsOrigin(client, vOrigin); + + GetEntPropVector(client, Prop_Data, "m_vecVelocity", vDir); + + NormalizeVector(vDir, vDir); + + vTraceOrigin = vOrigin; + vTraceOrigin[0] += vDir[0] * 64.0; + vTraceOrigin[1] += vDir[1] * 64.0; + vTraceOrigin[2] += RAYTRACE_Z_DELTA; + + vEndPoint = vOrigin; + vEndPoint[0] -= vDir[0] * 16.0 * 1.414214; + vEndPoint[1] -= vDir[1] * 16.0 * 1.414214; + vEndPoint[2] += RAYTRACE_Z_DELTA; + + new Float:vBlockStart[3], Float:vNormal[3]; + if(!TracePlayer(vBlockStart, vNormal, vTraceOrigin, vEndPoint)) + { + return -1.0; + } + + new Float:vBlockEnd[3]; + + Array_Copy(vNormal, g_PlayerStates[client][vBlockNormal], 2); + + vEndPoint = vBlockStart; + vEndPoint[0] += vNormal[0] * 300.0; + vEndPoint[1] += vNormal[1] * 300.0; + + if(TracePlayer2(vBlockEnd, vBlockStart, vEndPoint)) + { + Array_Copy(vBlockEnd, g_PlayerStates[client][vBlockEndPos], 3); + + Align(vBlockEnd, vBlockStart, vBlockEnd, vNormal); + + if(vNormal[0] == 0.0 || vNormal[1] == 0.0) + { + return GetVectorDistance(vBlockStart, vBlockEnd); + } + else + { + return GetVectorDistance(vBlockStart, vBlockEnd) - 32.0 * (FloatAbs(vNormal[0]) + FloatAbs(vNormal[1]) - 1.0); + } + } + else + { + // Trace the other direction + + // rotate normal da way opposite da direction + new bool:bLeft = IsLeft(vDir, vNormal); + + vDir = vNormal; + + new Float:fTempSwap = vDir[0]; + + vDir[0] = vDir[1]; + vDir[1] = fTempSwap; + + if(bLeft) + { + vDir[0] = -vDir[0]; + } + else + { + vDir[1] = -vDir[1]; + } + + vTraceOrigin = vOrigin; + vTraceOrigin[0] += vDir[0] * 48.0; + vTraceOrigin[1] += vDir[1] * 48.0; + vTraceOrigin[2] += RAYTRACE_Z_DELTA; + + vEndPoint = vTraceOrigin; + vEndPoint[0] += vNormal[0] * 300.0; + vEndPoint[1] += vNormal[1] * 300.0; + + if(!TracePlayer2(vBlockEnd, vTraceOrigin, vEndPoint)) + { + return -1.0; + } + + Array_Copy(vBlockEnd, g_PlayerStates[client][vBlockEndPos], 3); + + // adjust vBlockStart -- the second trace was on a different axis + Align(vBlockStart, vBlockStart, vBlockEnd, vNormal); + + if(vNormal[0] == 0.0 || vNormal[1] == 0.0) + { + return GetVectorDistance(vBlockStart, vBlockEnd); + } + else + { + return GetVectorDistance(vBlockStart, vBlockEnd) - 32.0 * (FloatAbs(vNormal[0]) + FloatAbs(vNormal[1]) - 1.0); + } + } } bool:GetGapPoint(Float:vOut[3], Float:vNormal[3], client) { - decl Float:vAngles[3], Float:vTraceOrigin[3], Float:vDir[3], Float:vEndPoint[3]; - GetClientEyePosition(client, vTraceOrigin); - GetClientEyeAngles(client, vAngles); - - TBAnglesToUV(vDir, vAngles); - - vEndPoint = vTraceOrigin; - vEndPoint[0] += vDir[0] * GAP_TRACE_LENGTH; - vEndPoint[1] += vDir[1] * GAP_TRACE_LENGTH; - vEndPoint[2] += vDir[2] * GAP_TRACE_LENGTH; - - if(!TraceRay(vOut, vNormal, vTraceOrigin, vEndPoint)) - { - return false; - } - - #if defined DEBUG - CreateBeam(vTraceOrigin, vEndPoint); - #endif - - return true; + decl Float:vAngles[3], Float:vTraceOrigin[3], Float:vDir[3], Float:vEndPoint[3]; + GetClientEyePosition(client, vTraceOrigin); + GetClientEyeAngles(client, vAngles); + + TBAnglesToUV(vDir, vAngles); + + vEndPoint = vTraceOrigin; + vEndPoint[0] += vDir[0] * GAP_TRACE_LENGTH; + vEndPoint[1] += vDir[1] * GAP_TRACE_LENGTH; + vEndPoint[2] += vDir[2] * GAP_TRACE_LENGTH; + + if(!TraceRay(vOut, vNormal, vTraceOrigin, vEndPoint)) + { + return false; + } + + #if defined DEBUG + CreateBeam(vTraceOrigin, vEndPoint); + #endif + + return true; } bool:GetOppositePoint(Float:vOut[3], const Float:vTraceOrigin[3], const Float:vNormal[3]) { - decl Float:vDir[3], Float:vEndPoint[3]; - - vDir = vNormal; - - if(vDir[2]) - { - vDir[2] = 0.0; - NormalizeVector(vDir, vDir); - } - - vEndPoint = vTraceOrigin; - vEndPoint[0] += vDir[0] * 10000.0; - vEndPoint[1] += vDir[1] * 10000.0; - - if(!TraceRay2(vOut, vTraceOrigin, vEndPoint)) - { - return false; - } - - return true; + decl Float:vDir[3], Float:vEndPoint[3]; + + vDir = vNormal; + + if(vDir[2]) + { + vDir[2] = 0.0; + NormalizeVector(vDir, vDir); + } + + vEndPoint = vTraceOrigin; + vEndPoint[0] += vDir[0] * 10000.0; + vEndPoint[1] += vDir[1] * 10000.0; + + if(!TraceRay2(vOut, vTraceOrigin, vEndPoint)) + { + return false; + } + + return true; } @@ -4344,114 +4659,114 @@ bool:GetOppositePoint(Float:vOut[3], const Float:vTraceOrigin[3], const Float:vN Float:GetSpeed(client) { - new Float:vVelocity[3]; - GetEntPropVector(client, Prop_Data, "m_vecVelocity", vVelocity); - vVelocity[2] = 0.0; - - return GetVectorLength(vVelocity); + new Float:vVelocity[3]; + GetEntPropVector(client, Prop_Data, "m_vecVelocity", vVelocity); + vVelocity[2] = 0.0; + + return GetVectorLength(vVelocity); } Float:GetVSpeed(const Float:v[3]) { - new Float:vVelocity[3]; - vVelocity = v; - vVelocity[2] = 0.0; - - return GetVectorLength(vVelocity); + new Float:vVelocity[3]; + vVelocity = v; + vVelocity[2] = 0.0; + + return GetVectorLength(vVelocity); } SendPanelMsg(client, const String:strFormat[], any:...) { - new Handle:hPanel = CreatePanel(); - - decl String:buf[512]; - - VFormat(buf, sizeof(buf), strFormat, 3); - - SetPanelTitle(hPanel, buf); - - SendPanelToClient(hPanel, client, EmptyPanelHandler, 10); - - CloseHandle(hPanel); + new Handle:hPanel = CreatePanel(); + + decl String:buf[512]; + + VFormat(buf, sizeof(buf), strFormat, 3); + + SetPanelTitle(hPanel, buf); + + SendPanelToClient(hPanel, client, EmptyPanelHandler, 10); + + CloseHandle(hPanel); } DrawPanelTextF(Handle:hPanel, const String:strFormat[], any:...) { - decl String:buf[512]; - - VFormat(buf, sizeof(buf), strFormat, 3); - - DrawPanelText(hPanel, buf); + decl String:buf[512]; + + VFormat(buf, sizeof(buf), strFormat, 3); + + DrawPanelText(hPanel, buf); } Append(String:sOutput[], maxlen, const String:sFormat[], any:...) { - decl String:buf[1024]; - - VFormat(buf, sizeof(buf), sFormat, 4); - - StrCat(sOutput, maxlen, buf); + decl String:buf[1024]; + + VFormat(buf, sizeof(buf), sFormat, 4); + + StrCat(sOutput, maxlen, buf); } // undefined for negative numbers Float:fmod(Float:a, Float:b) { - while(a > b) - a -= b; - - return a; + while(a > b) + a -= b; + + return a; } stock Float:round(Float:a, b, Float:Base = 10.0) { - new Float:f = Pow(Base, float(b)); - return RoundFloat(a * f) / f; + new Float:f = Pow(Base, float(b)); + return RoundFloat(a * f) / f; } CreateBeamClient(client, const Float:v1[3], const Float:v2[3], r = 255, g = 255, b = 255, Float:fLifetime = 10.0) { - new color[4]; - color[0] = r; - color[1] = g; - color[2] = b; - color[3] = 100; - TE_SetupBeamPoints(v1, v2, g_BeamModel, 0, 0, 0, fLifetime, 10.0, 10.0, 10, 0.0, color, 0); - TE_SendToClient(client); + new color[4]; + color[0] = r; + color[1] = g; + color[2] = b; + color[3] = 100; + TE_SetupBeamPoints(v1, v2, g_BeamModel, 0, 0, 0, fLifetime, 10.0, 10.0, 10, 0.0, color, 0); + TE_SendToClient(client); } #if defined DEBUG CreateLightglow(const String:sColor[], const Float:vOrigin[3]) { - new Lightglow = CreateEntityByName("env_lightglow"); - SetEntPropVector(Lightglow, Prop_Data, "m_vecOrigin", vOrigin); - DispatchKeyValue(Lightglow,"rendercolor", sColor); - DispatchKeyValue(Lightglow,"GlowProxySize", "5"); - DispatchKeyValue(Lightglow,"VerticalGlowSize", "5"); - DispatchKeyValue(Lightglow,"HorizontalGlowSize", "5"); - DispatchSpawn(Lightglow); - CreateTimer(10.0, KillEntity, Lightglow); + new Lightglow = CreateEntityByName("env_lightglow"); + SetEntPropVector(Lightglow, Prop_Data, "m_vecOrigin", vOrigin); + DispatchKeyValue(Lightglow,"rendercolor", sColor); + DispatchKeyValue(Lightglow,"GlowProxySize", "5"); + DispatchKeyValue(Lightglow,"VerticalGlowSize", "5"); + DispatchKeyValue(Lightglow,"HorizontalGlowSize", "5"); + DispatchSpawn(Lightglow); + CreateTimer(10.0, KillEntity, Lightglow); } CreateBeam(const Float:v1[3], const Float:v2[3]) { - new color[4] = {255, 255, 255, 100}; - TE_SetupBeamPoints(v1, v2, g_BeamModel, 0, 0, 0, 10.0, 3.0, 3.0, 10, 0.0, color, 0); - TE_SendToAll(); + new color[4] = {255, 255, 255, 100}; + TE_SetupBeamPoints(v1, v2, g_BeamModel, 0, 0, 0, 10.0, 3.0, 3.0, 10, 0.0, color, 0); + TE_SendToAll(); } CreateBeam2(const Float:v1[3], const Float:v2[3], r, g, b) { - new color[4]; - color[0] = r; - color[1] = g; - color[2] = b; - color[3] = 255; - TE_SetupBeamPoints(v1, v2, g_BeamModel, 0, 0, 0, 10.0, 10.0, 10.0, 10, 0.0, color, 0); - TE_SendToAll(); + new color[4]; + color[0] = r; + color[1] = g; + color[2] = b; + color[3] = 255; + TE_SetupBeamPoints(v1, v2, g_BeamModel, 0, 0, 0, 10.0, 10.0, 10.0, 10, 0.0, color, 0); + TE_SendToAll(); } public Action:KillEntity(Handle:timer, any:entity) { - AcceptEntityInput(entity, "Kill"); + AcceptEntityInput(entity, "Kill"); } #endif
\ No newline at end of file diff --git a/sourcemod/scripting/game_manager.sp b/sourcemod/scripting/game_manager.sp index 3fcd3c7..73d3a2d 100644 --- a/sourcemod/scripting/game_manager.sp +++ b/sourcemod/scripting/game_manager.sp @@ -4,6 +4,7 @@ #include <cstrike> #include <sdkhooks> #include <smlib> +#include <morecolors> #define PLUGIN_VERSION "1.0.0" #define MAX_FILE_LEN 80 @@ -25,6 +26,7 @@ new Handle:g_h_mp_startmoney = INVALID_HANDLE; new Handle:g_h_mp_maxrounds = INVALID_HANDLE; new Handle:g_h_mp_buytime = INVALID_HANDLE; new Handle:g_h_nh_warmup = INVALID_HANDLE; +new Handle:g_h_nh_buytime = INVALID_HANDLE; new Handle:g_h_nh_teamlimit = INVALID_HANDLE; new Handle:g_h_mp_ignoreconditions = INVALID_HANDLE; new g_mp_startmoney; @@ -32,8 +34,12 @@ new bool:g_doReset = false; new g_CtScore, g_TScore; new Handle:g_h_roundExtentTimer = INVALID_HANDLE; new Handle:g_h_execServerCfgTimer = INVALID_HANDLE; -new Float:g_buytime = 0.5; new g_lastDmMode = 0; +new Float:g_botVoteEnd = -1.0; +new Float:g_voteTime = 20.0; +new bool:g_hasVoted[MAXPLAYERS + 1] = {false, ...}; +new g_voteCount[9] = {0, ...}; +new bool:g_botVoteDone = false; /* forwards */ new Handle:g_f_on_ht = INVALID_HANDLE; @@ -48,10 +54,13 @@ public OnMapStart(){ g_mp_startmoney = GetConVarInt( g_h_mp_startmoney ); g_maxrounds = GetConVarInt( g_h_mp_maxrounds ); - g_buytime = GetConVarFloat( g_h_mp_buytime ); g_lastDmMode = 0; OnDmModeChanged( g_h_nh_warmup, "", "" ); + + g_botVoteEnd = -1.0; + SetConVarInt( g_h_nh_warmup, 60 ); + CreateTimer( 20.0, BotVoteCreateTimer, _ ); } public OnConfigsExecuted() { @@ -71,6 +80,7 @@ public OnPluginStart() { g_h_mp_buytime = FindConVar( "mp_buytime"); g_h_mp_ignoreconditions = FindConVar( "mp_ignore_round_win_conditions" ); g_h_nh_warmup = CreateConVar( "nh_warmup", "0", "set warmup time. -1 for infinite.", 0 ); + g_h_nh_buytime = CreateConVar( "nh_buytime", "0.5", "buytime outside of warmup.", 0 ); g_h_nh_teamlimit = CreateConVar( "nh_teamlimit", "5", "player limit per team", 0 ); if( g_h_nh_warmup != INVALID_HANDLE ) { HookConVarChange( g_h_nh_warmup, OnDmModeChanged ); @@ -78,6 +88,8 @@ public OnPluginStart() { g_f_on_ht = CreateGlobalForward( "nthvnHalftime", ET_Ignore ); + RegAdminCmd("sm_admbotvote", CreateBotVote, ADMFLAG_RCON); + RegConsoleCmd("sm_botvote", CreateBotVotePlayer); // Finding offset for CS cash g_iAccount = FindSendPropOffs("CCSPlayer", "m_iAccount"); @@ -103,7 +115,7 @@ public OnDmModeChanged( Handle:cvar, const String:oldVal[], const String:newVal[ } if( !dm ) { - SetConVarFloat( g_h_mp_buytime, g_buytime ); + SetConVarFloat( g_h_mp_buytime, GetConVarFloat( g_h_nh_buytime ) ); if( g_h_roundExtentTimer ) { KillTimer( g_h_roundExtentTimer ); g_h_roundExtentTimer = INVALID_HANDLE; @@ -113,9 +125,7 @@ public OnDmModeChanged( Handle:cvar, const String:oldVal[], const String:newVal[ } else { if( g_h_roundExtentTimer == INVALID_HANDLE ) { - g_buytime = GetConVarFloat( g_h_mp_buytime ); g_h_roundExtentTimer = CreateTimer( 1.0, WarmupTimer, 0, TIMER_REPEAT ); - SetConVarFloat( g_h_mp_buytime, 420.0 ); } } @@ -132,6 +142,7 @@ public Action:WarmupTimer( Handle:timer, any:userid ) { SetConVarInt( g_h_nh_warmup, dm - 1 ); } + SetConVarFloat( g_h_mp_buytime, 420.0 ); new time = GameRules_GetProp( "m_iRoundTime" ); if( time < 420 * 60 ) time = 420 * 60 + 1; @@ -142,17 +153,19 @@ public Action:WarmupTimer( Handle:timer, any:userid ) { if( !IsValidEdict(i) || !IsValidEntity(i) ) continue; - if( i < MaxClients && IsClientConnected( i ) && IsClientInGame( i ) ) { - if( dm > 0 ) { - new secs = dm % 60; - new mins = (dm - secs) / 60; - PrintHintText( i, "---[ WARMUP %d:%02d ]---", mins, secs ); - } - else { - PrintHintText( i, "---[ WARMUP ]---" ); + if( GetGameTime() > g_botVoteEnd ) { + if( i < MaxClients && IsClientConnected( i ) && IsClientInGame( i ) ) { + if( dm > 0 ) { + new secs = dm % 60; + new mins = (dm - secs) / 60; + PrintHintText( i, "---[ WARMUP %d:%02d ]---", mins, secs ); + } + else { + PrintHintText( i, "---[ WARMUP ]---" ); + } + + continue; } - - continue; } GetEdictClassname( i, name, sizeof(name) ); @@ -167,11 +180,18 @@ public OnClientPutInServer( client ) { KillTimer( g_h_execServerCfgTimer ); g_h_execServerCfgTimer = INVALID_HANDLE; } - + SDKHook( client, SDKHook_PostThinkPost, Hook_PostThinkPost ); + + for( new i = 1; i < MaxClients; ++i ) { + if( i != client && IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) ) + return; + } + + SetConVarInt( g_h_nh_warmup, 60 ); + CreateTimer( 20.0, BotVoteCreateTimer, _ ); } - public Hook_PostThinkPost( entity ) { new dm = GetConVarInt( g_h_nh_warmup ); @@ -179,6 +199,156 @@ public Hook_PostThinkPost( entity ) { SetEntProp( entity, Prop_Send, "m_bInBuyZone", 1 ); } +public ShowBotVoteMenu( client ) { + new Handle:hPanel = CreateMenu(BotVoteHandler); + + AddMenuItem( hPanel, "0", "vote for the amount of bots!" ); + AddMenuItem( hPanel, "1", "" ); + AddMenuItem( hPanel, "2", "" ); + AddMenuItem( hPanel, "3", "no bots" ); + AddMenuItem( hPanel, "4", "3v3 bots" ); + AddMenuItem( hPanel, "5", "5v5 bots" ); + AddMenuItem( hPanel, "6", "no choice" ); + + DisplayMenu(hPanel, client, MENU_TIME_FOREVER); +} + +public BotVoteHandler( Handle:hMenu, MenuAction:ma, client, nItem ) { + switch( ma ) { + case MenuAction_Select: + { + if( nItem == 6 ) { + g_hasVoted[client] = true; + } + else if( nItem < 3 && GetGameTime() < g_botVoteEnd ) { + ShowBotVoteMenu( client ); + } + else { + g_voteCount[nItem - 3]++; + g_hasVoted[client] = true; + } + } + + case MenuAction_End: + { + CloseHandle( hMenu ); + } + } +} + +public FinishBotVote() { + new winner = -1; + new maxvotes = 0; + for( new i = 0; i < 9; ++i ) { + if( g_voteCount[i] > maxvotes ) + winner = i; + } + + switch( winner ) { + case 0: + { + ServerCommand( "bot_kick; bot_quota 0" ); + PrintToChatAll( "Vote for no bots won, kicking all bots." ); + } + case 1: + { + ServerCommand( "bot_quota 6" ); + PrintToChatAll( "Vote for 3v3 bots won, setting quota to 6 bots." ); + } + case 2: { + ServerCommand( "bot_quota 10" ); + PrintToChatAll( "Vote for 3v3 bots won, setting quota to 10 bots." ); + } + } + + for( new i = 0; i < 9; ++i ) { + g_voteCount[i] = 0; + } + + for( new i = 0; i < MAXPLAYERS; ++i ) { + g_hasVoted[i] = false; + } +} + +public Action:BotVoteTimer( Handle:timer, any:unused ) { + new dm = GetConVarInt( g_h_nh_warmup ); + new String:hintStr[256]; + new Float:diff = g_botVoteEnd - GetGameTime(); + + if( diff <= 0 ) { + FinishBotVote(); + KillTimer( timer ); + return; + } + + for( new i = 1; i < MaxClients; ++i ) { + if( !IsClientConnected(i) || !IsClientInGame(i) || IsFakeClient(i) ) + continue; + + Format( + hintStr, + sizeof(hintStr), + "bot vote [%.0f sec left]:\nno bots: %d\n3v3 bots: %d\n5v5 bots: %d", + diff, + g_voteCount[0], + g_voteCount[1], + g_voteCount[2] + ); + + if( dm > 0 ) { + new secs = dm % 60; + new mins = (dm - secs) / 60; + Format( hintStr, sizeof(hintStr), "%s\n---[ WARMUP %d:%02d ]---", hintStr, mins, secs ); + } + else if( dm < 0 ) { + Format( hintStr, sizeof(hintStr), "%s\n---[ WARMUP ]---", hintStr ); + } + + PrintHintText( i, hintStr ); + if( !g_hasVoted[i] ) + ShowBotVoteMenu( i ); + } +} + +public Action:CreateBotVote( client, args ) { + if( GetGameTime() < g_botVoteEnd ) + return Plugin_Handled; + + g_botVoteDone = true; + g_botVoteEnd = GetGameTime() + g_voteTime; + + for( new i = 0; i < 9; ++i ) { + g_voteCount[i] = 0; + } + + for( new i = 0; i < MAXPLAYERS; ++i ) { + g_hasVoted[i] = false; + } + + BotVoteTimer( INVALID_HANDLE, 0 ); + CreateTimer( 1.0, BotVoteTimer, 0, TIMER_REPEAT ); + return Plugin_Handled; +} + +public Action:CreateBotVotePlayer( client, args ) { + if( GetGameTime() < g_botVoteEnd ) { + g_hasVoted[client] = false; + ShowBotVoteMenu( client ); + } + + if( g_botVoteDone ) { + CPrintToChat( client, "{fuchsia}A bot vote has already concluded this round." ); + return Plugin_Handled; + } + + CreateBotVote( client, args ); + return Plugin_Handled; +} + +public Action:BotVoteCreateTimer( Handle: timer, any:unused ) { + CreateBotVote( 0, 0 ); +} + public OnClientDisconnect( client ) { if( IsFakeClient( client ) ) return; @@ -198,6 +368,7 @@ public OnClientDisconnect( client ) { } public Action:ExecServerCfg( Handle:timer, any:unused ) { + g_botVoteDone = false; ServerCommand( "exec server.cfg" ); g_h_execServerCfgTimer = INVALID_HANDLE; } @@ -304,8 +475,33 @@ public Action:Listener_JoinTeam( id, const String: command[], args ) { return Plugin_Continue; } +public Action:RespawnPlayerDelay( Handle: timer, any: userid ) { + new id = GetClientOfUserId( userid ); + + if( id <= 0 ) + return Plugin_Handled; + + if( !IsClientConnected( id ) || !IsClientInGame( id ) ) + return Plugin_Handled; + + if( IsPlayerAlive( id ) ) + return Plugin_Handled; + + new team = GetClientTeam( id ); + if( team < 2 ) + return Plugin_Handled; + + CS_RespawnPlayer( id ); +} + public Action:Event_PlayerTeam( Handle:event, const String:name[], bool dontBroadcast ) { CreateTimer( 0.2, VerifyTeamCounts, 0, 0 ); + new uid = GetEventInt( event, "userid" ); + + if( GetConVarInt( g_h_nh_warmup ) != 0 ) { + CreateTimer( 0.5, RespawnPlayerDelay, uid ); + } + return Plugin_Continue; } @@ -380,7 +576,7 @@ public Event_RoundStart( Handle:event, const String:name[], bool:dontBroadcast ) g_CtScore = GetTeamScore( CS_TEAM_CT ); g_TScore = GetTeamScore( CS_TEAM_T ); - new newRoundCount = g_CtScore = g_TScore + 1; + new newRoundCount = g_CtScore + g_TScore + 1; if( newRoundCount < g_roundCount ) { halftime = false; g_CtScore = 0; @@ -430,6 +626,7 @@ public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) new reason = GetEventInt(event, "reason"); new winner = GetEventInt(event, "winner"); + g_botVoteDone = false; g_mp_startmoney = GetConVarInt(g_h_mp_startmoney); g_maxrounds = GetConVarInt(g_h_mp_maxrounds); diff --git a/sourcemod/scripting/sm_speedometer.sp b/sourcemod/scripting/sm_speedometer.sp index ed60167..a52d742 100644 --- a/sourcemod/scripting/sm_speedometer.sp +++ b/sourcemod/scripting/sm_speedometer.sp @@ -56,7 +56,7 @@ public OnPluginStart() HookConVarChange(g_hMethod, Action_OnSettingsChange); g_hFactor = CreateConVar("sm_speedometer_factor", "0.0", "Optional numerical value that can be used to derive real world units from in-game velocity.", FCVAR_NONE, true, 0.0); HookConVarChange(g_hFactor, Action_OnSettingsChange); - g_hDisplay = CreateConVar("sm_speedometer_area", "0", "Determines printing area functionality. (0 = Hint, 1 = Center, 2 = Hud Hint)", FCVAR_NONE, true, 0.0, true, 2.0); + g_hDisplay = CreateConVar("sm_speedometer_area", "0", "Determines printing area functionality. (0 = Hint, 1 = Center, 2 = Hud Hint, 3 = hud panel)", FCVAR_NONE, true, 0.0, true, 3.0); HookConVarChange(g_hDisplay, Action_OnSettingsChange); g_hFastest = CreateConVar("sm_speedometer_fastest", "1", "If enabled, the player with the highest velocity will be displayed at the end of the round.", FCVAR_NONE, true, 0.0, true, 1.0); HookConVarChange(g_hFastest, Action_OnSettingsChange); @@ -336,6 +336,13 @@ public Action:OnPlayerRunCmd(iClient, &buttons, &impulse, Float:vel[3], Float:an BfWriteString(hTemp, sBuffer); EndMessage(); } + case 3: + { + Format(sBuffer, sizeof(sBuffer), "%T", "Phrase_Velocity_Display", i, _fVelocity); + + SetHudTextParams(-1.0, 0.85, 0.05, 255, 255, 255, 255, 0, 0.0, 0.0, 0.0); + ShowHudText(i, 1, sBuffer); + } } if(g_bShowFastest && _fVelocity > g_fFastestVelocity) |
