Create a repository

This commit is contained in:
Shavitush 2015-07-09 20:32:19 +03:00
parent 60f7a6ac76
commit 6720d7d3a6
7 changed files with 3403 additions and 0 deletions

77
README.md Normal file
View File

@ -0,0 +1,77 @@
[Download](https://github.com/Shavitush/bhoptimer/releases)
# shavit's simple bhop timer
a bhop server should be simple
I
[Mapzones' setup demonstration](https://www.youtube.com/watch?v=oPKso2hoLw0)
# Requirements:
* [SourceMod 1.7 and above](http://www.sourcemod.net/downloads.php)
# Optional requirements:
* [DHooks](http://users.alliedmods.net/~drifter/builds/dhooks/2.0/) - required for static 250 prestrafe (bhoptimer 1.2b and above)
[AlliedModders thread](https://forums.alliedmods.net/showthread.php?t=265456)
Use it to troubleshoot errors without needing my help!
# Installation:
1. Add a database entry in addons/sourcemod/configs/databases.cfg, call it "shavit"
```
"Databases"
{
"driver_default" "mysql"
// When specifying "host", you may use an IP address, a hostname, or a socket file path
"default"
{
"driver" "default"
"host" "localhost"
"database" "sourcemod"
"user" "root"
"pass" ""
//"timeout" "0"
//"port" "0"
}
"shavit"
{
"driver" "mysql"
"host" "localhost"
"database" "shavit"
"user" "root"
"pass" ""
}
}
```
2. Copy the desired .smx files to your plugins (addons/sourcemod/plugins) folder
3. Restart your server.
# Required plugins:
shavit-core - no other plugin will work without it.
shavit-zones - wouldn't really call it required but it's actually needed to get your timer to start/finish.
# Todo for 1.2b release
- [x] + create a github repo
shavit-core:
- [ ] * make a better check of game engine instead of using a directory
- [ ] + sm_pause
- [ ] + sm_resume
shavit-misc:
- [ ] + cvar "shavit_misc_godmode"
0 - nothing
1 - only world damage
2 - only player damage
3 - full godmode
- [ ] + 250 maxspeed for every pistol
shavit-zones:
- [ ] + player slaying zone
- [ ] + cvar "shavit_zones_style"
0 - 3d (default)
1 - 2d

303
include/shavit.inc Normal file
View File

@ -0,0 +1,303 @@
/*
* Shavit's Timer - .inc file
* by: shavit
*
* This file is part of Shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#if defined _shavit_included
#endinput
#endif
#define _shavit_included
#define SHAVIT_VERSION "1.1b"
#define PREFIX " \x04[Timer]\x01"
#define MAX_STYLES 2 // I could probably do sizeof(BhopStyle) but I suck
#define MAX_ZONES 4
// game types
enum ServerGame(+=1)
{
Game_CSS = 0,
Game_CSGO = 1,
Game_Unknown = 2
};
// bhop styles
enum BhopStyle(+=1)
{
Style_Forwards = 0,
Style_Sideways = 1
};
// map zones
enum MapZones
{
Zone_Start = 0,
Zone_End = 1,
Zone_Respawn = 2,
Zone_Stop = 3
};
// let's not throw errors k?
stock bool IsValidClient(int client, bool bAlive = false) // when bAlive is false = technical checks, when it's true = gameplay checks
{
return (client >= 1 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client) && !IsClientSourceTV(client) && (!bAlive || IsPlayerAlive(client)));
}
// time formatting!
stock FormatSeconds(float time, char[] newtime, int newtimesize, bool precise = true)
{
int iTemp = RoundToFloor(time);
int iHours;
if(iTemp > 3600)
{
iHours = RoundToFloor(iTemp / 3600.0);
iTemp %= 3600;
}
char sHours[8];
if(iHours < 10)
{
FormatEx(sHours, 8, "0%d", iHours);
}
else
{
FormatEx(sHours, 8, "%d", iHours);
}
int iMinutes;
if(iTemp >= 60)
{
iMinutes = RoundToFloor(iTemp / 60.0);
iTemp %= 60;
}
char sMinutes[8];
if(iMinutes < 10)
{
FormatEx(sMinutes, 8, "0%d", iMinutes);
}
else
{
FormatEx(sMinutes, 8, "%d", iMinutes);
}
float fSeconds = ((iTemp) + time - RoundToFloor(time))
char sSeconds[16];
if(fSeconds < 10)
{
FormatEx(sSeconds, 16, "0%.03f", fSeconds);
}
else
{
FormatEx(sSeconds, 16, "%.03f", fSeconds);
}
if(iHours > 0)
{
FormatEx(newtime, newtimesize, "%s:%s:%ss", sHours, sMinutes, sSeconds);
}
else if(iMinutes > 0)
{
FormatEx(newtime, newtimesize, "%s:%ss", sMinutes, sSeconds);
}
else
{
if(precise)
{
FormatEx(newtime, newtimesize, "%.03fs", fSeconds);
}
else
{
FormatEx(newtime, newtimesize, "%.01fs", fSeconds);
}
}
}
/**
* Called when a player's timer starts.
* (WARNING: Will be called every tick when the player stands at the start zone!)
*
* @param client Client index.
* @noreturn
*/
forward void Shavit_OnStart(int client);
/**
* Called when a player uses the restart command.
*
* @param client Client index.
* @noreturn
*/
forward void Shavit_OnRestart(int client);
/**
* Called when a player's timer stops. (stop =/= finish a map)
*
* @param client Client index.
* @noreturn
*/
forward void Shavit_OnStop(int client);
/**
* Called when a player finishes a map. (touches the end zone)
*
* @param client Client index.
* @param style Style the record was done on.
* @param time Record time.
* @param jumps Jumps amount.
* @noreturn
*/
forward void Shavit_OnFinish(int client, int style, float time, int jumps);
/**
* Called when there's a new WR on the map.
*
* @param client Client index.
* @param style Style the record was done on.
* @param time Record time.
* @param jumps Jumps amount.
* @param jumps Jumps amount.
* @noreturn
*/
forward void Shavit_OnWorldRecord(int client, BhopStyle style, float time, int jumps);
/**
* Returns the game type the server is running.
*
* @return Game type. (See "enum ServerGame")
*/
native ServerGame Shavit_GetGameType();
/**
* Returns the database handle the timer is using.
*
* @param hSQL Handle to store the database on.
* @noreturn
*/
native Shavit_GetDB(Handle &hSQL);
/**
* (re)Starts the timer for a player.
* Will not teleport the player to anywhere, it's handled inside the mapzones plugin.
*
* @param client Client index.
* @noreturn
*/
native Shavit_StartTimer(int client);
/**
* Stops the timer for a player.
* Will not teleport the player to anywhere, it's handled inside the mapzones plugin.
*
* @param client Client index.
* @noreturn
*/
native Shavit_StopTimer(int client);
/**
* Finishes the map for a player, with his current timer stats.
* Will not teleport the player to anywhere, it's handled inside the mapzones plugin.
*
* @param client Client index.
* @noreturn
*/
native Shavit_FinishMap(int client);
/**
* Stores the player's timer stats on variables
*
* @param client Client index.
* @param time Time passed since the player started.
* @param jumps How many times the player jumped since he started.
* @param style Style, check "enum BhopStyle"
* @param started Timer started?
* @noreturn
*/
native Shavit_GetTimer(int client, float &time, int &jumps, BhopStyle &style, bool &started);
/**
* Saves the WR time on the map on a variable.
*
* @param style Style to get the WR for.
* @param time Reference to the time variable. 0.0 will be returned if no records.
* @noreturn
*/
native Shavit_GetWRTime(BhopStyle style, float &time);
/**
* Saves the WR's player name on the map on a variable.
*
* @param style Style to get the WR for.
* @param wrname Reference to the name variable.
* @param wrmaxlength Max length for the string.
* @noreturn
*/
native Shavit_GetWRName(BhopStyle style, char[] wrname, int wrmaxlength);
/**
* Saves the player's personal best time on a variable.
*
* @param client Client index.
* @param style Style to get the PB for.
* @param time Reference to the time variable. 0.0 will be returned if no personal record.
* @noreturn
*/
native Shavit_GetPlayerPB(int client, BhopStyle style, float &time);
/**
* Checks if a mapzone exists.
*
* @param type Mapzone type. (Check "enum MapZones")
* @return 1 if exists, 0 if doesn't exist.
*/
native int Shavit_ZoneExists(MapZones type);
// ^ I could make it return a boolean instead, but I blame SM 1.7 for not letting me :/. You can use view_as<bool> though :D
/**
* Checks if a player is inside a mapzone
*
* @param client Client index.
* @param type Mapzone type. (Check "enum MapZones")
* @return 1 if is in the mapzone, 0 if isn't.
*/
native int Shavit_InsideZone(int client, MapZones type);
public SharedPlugin:__pl_shavit =
{
name = "shavit",
file = "shavit-core.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};

590
shavit-core.sp Normal file
View File

@ -0,0 +1,590 @@
/*
* shavit's Timer - Core
* by: shavit
*
* This file is part of Shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sourcemod>
#include <sdktools>
#include <geoip>
#include <shavit>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma semicolon 1
#pragma dynamic 131072 // let's make stuff faster
#pragma newdecls required // We're at 2015 :D
//#define DEBUG
// game type (CS:S/CS:GO)
ServerGame gSG_Type = Game_Unknown;
// database handle
Handle gH_SQL = null;
// forwards
Handle gH_Forwards_Start = null;
Handle gH_Forwards_Stop = null;
Handle gH_Forwards_Finish = null;
Handle gH_Forwards_OnRestart = null;
// timer variables
bool gB_TimerEnabled[MAXPLAYERS+1];
float gF_StartTime[MAXPLAYERS+1];
int gI_Jumps[MAXPLAYERS+1];
BhopStyle gBS_Style[MAXPLAYERS+1];
// late load
bool gB_Late;
// zones lateload support
bool gB_Zones;
public Plugin myinfo =
{
name = "[shavit] Core",
author = "shavit",
description = "The core for shavit's bhop timer.",
version = SHAVIT_VERSION,
url = "http://forums.alliedmods.net/member.php?u=163134"
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
// get game type
CreateNative("Shavit_GetGameType", Native_GetGameType);
// get database handle
CreateNative("Shavit_GetDB", Native_GetDB);
// timer natives
CreateNative("Shavit_StartTimer", Native_StartTimer);
CreateNative("Shavit_StopTimer", Native_StopTimer);
CreateNative("Shavit_FinishMap", Native_FinishMap);
CreateNative("Shavit_GetTimer", Native_GetTimer);
MarkNativeAsOptional("Shavit_GetGameType");
MarkNativeAsOptional("Shavit_GetDB");
MarkNativeAsOptional("Shavit_StartTimer");
MarkNativeAsOptional("Shavit_StopTimer");
MarkNativeAsOptional("Shavit_FinishMap");
MarkNativeAsOptional("Shavit_GetTimer");
// prevent errors from shavit-zones
MarkNativeAsOptional("Shavit_InsideZone");
// registers library, check "LibraryExists(const String:name[])" in order to use with other plugins
RegPluginLibrary("shavit");
gB_Late = late;
return APLRes_Success;
}
public void OnPluginStart()
{
// forwards
gH_Forwards_Start = CreateGlobalForward("Shavit_OnStart", ET_Event, Param_Cell);
gH_Forwards_Stop = CreateGlobalForward("Shavit_OnStop", ET_Event, Param_Cell);
gH_Forwards_Finish = CreateGlobalForward("Shavit_OnFinish", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
gH_Forwards_OnRestart = CreateGlobalForward("Shavit_OnRestart", ET_Event, Param_Cell);
// game types
char sGameName[64];
GetGameFolderName(sGameName, 64);
if(StrEqual(sGameName, "cstrike"))
{
gSG_Type = Game_CSS;
}
else if(StrEqual(sGameName, "csgo"))
{
gSG_Type = Game_CSGO;
}
if(gSG_Type == Game_Unknown)
{
SetFailState("This plugin was meant to be used in CS:S and CS:GO *only*.");
}
// database connections
SQL_DBConnect();
// hooks
HookEvent("player_jump", Player_Jump);
HookEvent("player_death", Player_Death);
HookEvent("player_team", Player_Death);
HookEvent("player_spawn", Player_Death);
// commands START
// style
RegConsoleCmd("sm_style", Command_Style, "Choose your bhop style.");
RegConsoleCmd("sm_styles", Command_Style, "Choose your bhop style.");
RegConsoleCmd("sm_s", Command_Style, "Choose your bhop style.");
RegConsoleCmd("sm_diff", Command_Style, "Choose your bhop style.");
RegConsoleCmd("sm_difficulty", Command_Style, "Choose your bhop style.");
// forwards
RegConsoleCmd("sm_n", Command_Forwards, "Style shortcut: Forwards");
RegConsoleCmd("sm_forwards", Command_Forwards, "Style shortcut: Forwards");
RegConsoleCmd("sm_normal", Command_Forwards, "Style shortcut: Forwards");
// sideways
RegConsoleCmd("sm_sw", Command_Sideways, "Style shortcut: Sideways");
RegConsoleCmd("sm_sideways", Command_Sideways, "Style shortcut: Sideways");
// timer start
RegConsoleCmd("sm_s", Command_StartTimer, "Start your timer.");
RegConsoleCmd("sm_start", Command_StartTimer, "Start your timer.");
RegConsoleCmd("sm_r", Command_StartTimer, "Start your timer.");
RegConsoleCmd("sm_restart", Command_StartTimer, "Start your timer.");
// timer stop
RegConsoleCmd("sm_stop", Command_StopTimer, "Stop your timer.");
// commands END
#if defined DEBUG
RegConsoleCmd("sm_finishtest", Command_FinishTest);
#endif
CreateConVar("shavit_version", SHAVIT_VERSION, "Plugin version.", FCVAR_PLUGIN|FCVAR_NOTIFY|FCVAR_DONTRECORD);
// late
if(gB_Late)
{
OnAdminMenuReady(null);
for(int i = 1; i <= MaxClients; i++)
{
OnClientPutInServer(i);
}
}
gB_Zones = LibraryExists("shavit-zones");
}
public void OnLibraryAdded(const char[] name)
{
if(StrEqual(name, "shavit-zones"))
{
gB_Zones = true;
}
}
public void OnLibraryRemoved(const char[] name)
{
if(StrEqual(name, "shavit-zones"))
{
gB_Zones = false;
}
}
public void OnAdminMenuReady(Handle topmenu)
{
Handle hTopMenu = INVALID_HANDLE;
if(LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE))
{
AddToTopMenu(hTopMenu, "Timer Commands", TopMenuObject_Category, CategoryHandler, INVALID_TOPMENUOBJECT);
}
}
public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
if(action == TopMenuAction_DisplayTitle)
{
FormatEx(buffer, maxlength, "Timer Commands:");
}
else if (action == TopMenuAction_DisplayOption)
{
FormatEx(buffer, maxlength, "Timer Commands");
}
}
public void OnMapStart()
{
// cvar forcing
ConVar cvBhopping = FindConVar("sv_enablebunnyhopping");
SetConVarBool(cvBhopping, true);
ConVar cvAA = FindConVar("sv_airaccelerate");
SetConVarInt(cvAA, 2000);
}
public Action Command_StartTimer(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
Call_StartForward(gH_Forwards_OnRestart);
Call_PushCell(client);
Call_Finish();
StartTimer(client);
return Plugin_Handled;
}
public Action Command_StopTimer(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
StopTimer(client);
return Plugin_Handled;
}
#if defined DEBUG
public Action Command_FinishTest(int client, int args)
{
Shavit_FinishMap(client);
return Plugin_Handled;
}
#endif
public Action Command_Style(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
Handle menu = CreateMenu(StyleMenu_Handler);
SetMenuTitle(menu, "Choose a style:");
AddMenuItem(menu, "forwards", "Forwards");
AddMenuItem(menu, "sideways", "Sideways");
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
return Plugin_Handled;
}
public int StyleMenu_Handler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[16];
GetMenuItem(menu, param2, info, 16);
if(StrEqual(info, "forwards"))
{
Command_Forwards(param1, 0);
}
else if(StrEqual(info, "sideways"))
{
Command_Sideways(param1, 0);
}
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public Action Command_Forwards(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
gBS_Style[client] = Style_Forwards;
ReplyToCommand(client, "%s You have selected to play \x03Forwards", PREFIX);
Command_StartTimer(client, 0);
return Plugin_Handled;
}
public Action Command_Sideways(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
gBS_Style[client] = Style_Sideways;
ReplyToCommand(client, "%s You have selected to play \x03Sideways", PREFIX);
Command_StartTimer(client, 0);
return Plugin_Handled;
}
public void Player_Jump(Handle event, const char[] name, bool dontBroadcast)
{
int userid = GetEventInt(event, "userid");
int client = GetClientOfUserId(userid);
if(gB_TimerEnabled[client])
{
gI_Jumps[client]++;
}
SetEntPropFloat(client, Prop_Send, "m_flStamina", 0.0);
}
public void Player_Death(Handle event, const char[] name, bool dontBroadcast)
{
int userid = GetEventInt(event, "userid");
int client = GetClientOfUserId(userid);
StopTimer(client);
}
public int Native_GetGameType(Handle handler, int numParams)
{
return view_as<int>gSG_Type;
}
public int Native_GetDB(Handle handler, int numParams)
{
SetNativeCellRef(1, gH_SQL);
}
// I can't return booleans :/
public int Native_GetTimer(Handle handler, int numParams)
{
// 1 - client
int client = GetNativeCell(1);
// 2 - time
float time = GetEngineTime() - gF_StartTime[client];
SetNativeCellRef(2, time);
// 3 - jumps
SetNativeCellRef(3, gI_Jumps[client]);
// 4 - style
SetNativeCellRef(4, gBS_Style[client]);
// 5 - style
SetNativeCellRef(5, gB_TimerEnabled[client]);
}
public int Native_StartTimer(Handle handler, int numParams)
{
int client = GetNativeCell(1);
StartTimer(client);
Call_StartForward(gH_Forwards_Start);
Call_PushCell(client);
Call_Finish();
}
public int Native_StopTimer(Handle handler, int numParams)
{
int client = GetNativeCell(1);
StopTimer(client);
Call_StartForward(gH_Forwards_Stop);
Call_PushCell(client);
Call_Finish();
}
public int Native_FinishMap(Handle handler, int numParams)
{
int client = GetNativeCell(1);
Call_StartForward(gH_Forwards_Finish);
Call_PushCell(client);
Call_PushCell(view_as<int>gBS_Style[client]);
Call_PushCell(GetEngineTime() - gF_StartTime[client]);
Call_PushCell(gI_Jumps[client]);
Call_Finish();
StopTimer(client);
}
public void StartTimer(int client)
{
if(!IsValidClient(client) || IsFakeClient(client))
{
return;
}
gB_TimerEnabled[client] = true;
gI_Jumps[client] = 0;
gF_StartTime[client] = GetEngineTime();
}
public void StopTimer(int client)
{
if(!IsValidClient(client))
{
return;
}
gB_TimerEnabled[client] = false;
gI_Jumps[client] = 0;
gF_StartTime[client] = 0.0;
}
public void OnClientDisconnect(int client)
{
StopTimer(client);
}
public void OnClientPutInServer(int client)
{
StopTimer(client);
gBS_Style[client] = Style_Forwards;
if(!IsValidClient(client) || IsFakeClient(client) || gH_SQL == null)
{
return;
}
// SteamID3 is cool, 2015 B O Y S
char sAuthID3[32];
GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32);
char sName[MAX_NAME_LENGTH];
GetClientName(client, sName, MAX_NAME_LENGTH);
int iLength = ((strlen(sName) * 2) + 1);
char[] sEscapedName = new char[iLength]; // dynamic arrays! I love you, SourcePawn 1.7!
SQL_EscapeString(gH_SQL, sName, sEscapedName, iLength);
char sIP[32];
GetClientIP(client, sIP, 32);
char sCountry[45];
GeoipCountry(sIP, sCountry, 45);
if(StrEqual(sCountry, ""))
{
FormatEx(sCountry, 45, "Local Area Network");
}
// too lazy to calculate if it can go over 256 so let's not take risks and use 512, because #pragma dynamic <3
char sQuery[512];
FormatEx(sQuery, 512, "REPLACE INTO users (auth, name, country, ip) VALUES ('%s', '%s', '%s', '%s');", sAuthID3, sEscapedName, sCountry, sIP);
SQL_TQuery(gH_SQL, SQL_InsertUser_Callback, sQuery, GetClientSerial(client));
}
public void SQL_InsertUser_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
int client = GetClientFromSerial(data);
if(!client)
{
LogError("Timer error! Failed to insert a disconnected player's data to the table. Reason: %s", error);
}
else
{
LogError("Timer error! Failed to insert \"%N\"'s data to the table. Reason: %s", client, error);
}
return;
}
}
public void SQL_DBConnect()
{
if(gH_SQL != null)
{
CloseHandle(gH_SQL);
}
if(SQL_CheckConfig("shavit"))
{
char sError[255];
if(!(gH_SQL = SQL_Connect("shavit", true, sError, 255)))
{
SetFailState("Timer startup failed. Reason: %s", sError);
}
// let's not mess with shit and make it non-English characters work properly before we do any stupid crap rite?
SQL_LockDatabase(gH_SQL);
SQL_FastQuery(gH_SQL, "SET NAMES 'utf8';");
SQL_UnlockDatabase(gH_SQL);
// CREATE TABLE IF NOT EXISTS
SQL_TQuery(gH_SQL, SQL_CreateTable_Callback, "CREATE TABLE IF NOT EXISTS `users` (`auth` VARCHAR(32) NOT NULL, `name` VARCHAR(32), `country` VARCHAR(45), `ip` VARCHAR(32), PRIMARY KEY (`auth`));");
}
else
{
SetFailState("Timer startup failed. Reason: %s", "\"shavit\" is not a specified entry in databases.cfg.");
}
}
public void SQL_CreateTable_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer error! Users' data table creation failed. Reason: %s", error);
return;
}
}
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3])
{
if(!IsValidClient(client, true))
{
return Plugin_Continue;
}
bool bOnLadder = (GetEntityMoveType(client) == MOVETYPE_LADDER);
if(gB_Zones && gB_TimerEnabled[client] && !Shavit_InsideZone(client, Zone_Start) && (buttons & IN_LEFT || buttons & IN_RIGHT))
{
StopTimer(client);
PrintToChat(client, "%s I've stopped your timer for using +left/+right. No cheating!", PREFIX);
}
// SW cheat blocking
if(gBS_Style[client] == Style_Sideways && !bOnLadder && (vel[1] != 0.0 || buttons & IN_MOVELEFT || buttons & IN_MOVERIGHT))
{
vel[1] = 0.0;
}
// autobhop
if(buttons & IN_JUMP && !(GetEntityFlags(client) & FL_ONGROUND) && !bOnLadder && GetEntProp(client, Prop_Send, "m_nWaterLevel") <= 1)
{
buttons &= ~IN_JUMP;
}
return Plugin_Continue;
}

199
shavit-hud.sp Normal file
View File

@ -0,0 +1,199 @@
/*
* shavit's Timer - HUD
* by: shavit
*
* This file is part of Shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sourcemod>
#include <sdktools>
#include <shavit>
#pragma semicolon 1
#pragma dynamic 131072 // let's make stuff faster
#pragma newdecls required // We're at 2015 :D
// game type (CS:S/CS:GO)
ServerGame gSG_Type = Game_Unknown;
public Plugin myinfo =
{
name = "[shavit] HUD",
author = "shavit",
description = "HUD for shavit's bhop timer.",
version = SHAVIT_VERSION,
url = "http://forums.alliedmods.net/member.php?u=163134"
}
public void OnPluginStart()
{
gSG_Type = Shavit_GetGameType();
CreateTimer(0.1, UpdateHUD_Timer, INVALID_HANDLE, TIMER_REPEAT);
}
public Action UpdateHUD_Timer(Handle Timer)
{
for(int i = 1; i <= MaxClients; i++)
{
if(!IsValidClient(i))
{
continue;
}
UpdateHUD(i);
}
return Plugin_Continue;
}
public void UpdateHUD(int client)
{
int target = client;
bool bSpectating;
if(IsClientObserver(client))
{
if(GetEntProp(client, Prop_Send, "m_iObserverMode") >= 3)
{
int iTarget = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget");
if(IsValidClient(iTarget, true))
{
target = iTarget;
}
}
}
float fTime;
int iJumps;
BhopStyle bsStyle;
bool bStarted;
Shavit_GetTimer(target, fTime, iJumps, bsStyle, bStarted);
float fWR;
Shavit_GetWRTime(bsStyle, fWR);
//PrintToChat(client, "Time: %.02f WR: %.02f", fTime, fWR);
char sHintText[256];
if(gSG_Type == Game_CSGO)
{
FormatEx(sHintText, 256, "<font size=\"18\">");
float fPB;
Shavit_GetPlayerPB(target, bsStyle, fPB);
char sPB[32];
FormatSeconds(fPB, sPB, 32);
Format(sHintText, 256, "%sPB: %s\t", sHintText, sPB);
if(fPB != 0.0)
{
Format(sHintText, 256, "%s\t", sHintText);
}
if(bStarted)
{
char sTime[32];
FormatSeconds(fTime, sTime, 32, false);
char sColor[16];
if(fTime < fWR || fWR == 0.0)
{
FormatEx(sColor, 16, "00FF00");
}
else if(fPB != 0.0 && fTime < fPB)
{
FormatEx(sColor, 16, "FFA500");
}
else
{
FormatEx(sColor, 16, "FF0000");
}
Format(sHintText, 256, "%sTime: <font color=\"#%s\">%s</font>", sHintText, sColor, sTime);
}
float fSpeed[3];
GetEntPropVector(target, Prop_Data, "m_vecVelocity", fSpeed);
float fSpeed_New = SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0));
Format(sHintText, 256, "%s\nSpeed: %.02f", sHintText, fSpeed_New);
if(bStarted)
{
Format(sHintText, 256, "%s\tJumps: %d", sHintText, iJumps);
}
Format(sHintText, 256, "%s\nStyle: <font color=\"%s</font>", sHintText, bsStyle == Style_Forwards? "#797FD4\">Forwards":"#B54CB3\">Sideways");
if(!bSpectating)
{
Format(sHintText, 256, "%s\tPlayer: <font color=\"#BF6821\">%N</font>", sHintText, target);
}
Format(sHintText, 256, "%s</font>", sHintText);
}
else
{
float fPB;
Shavit_GetPlayerPB(target, bsStyle, fPB);
char sPB[32];
FormatSeconds(fPB, sPB, 32);
Format(sHintText, 256, "%sPB: %s\t", sHintText, sPB);
if(bStarted)
{
char sTime[32];
FormatSeconds(fTime, sTime, 32);
Format(sHintText, 256, "%sTime: %s", sHintText, sTime);
}
float fSpeed[3];
GetEntPropVector(target, Prop_Data, "m_vecVelocity", fSpeed);
float fSpeed_New = SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0));
Format(sHintText, 256, "%s\nSpeed: %.02f", sHintText, fSpeed_New);
if(bStarted)
{
Format(sHintText, 256, "%s\tJumps: %d", sHintText, iJumps);
}
Format(sHintText, 256, "%s\nStyle: %s", sHintText, bsStyle == Style_Forwards? "Forwards":"Sideways");
if(!bSpectating)
{
Format(sHintText, 256, "%s\tPlayer: %N", sHintText, target);
}
}
PrintHintText(client, sHintText);
if(gSG_Type == Game_CSS)
{
StopSound(client, SNDCHAN_STATIC, "UI/hint.wav");
}
}

372
shavit-misc.sp Normal file
View File

@ -0,0 +1,372 @@
/*
* shavit's Timer - Miscellaneous
* by: shavit
*
* This file is part of Shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sourcemod>
#include <cstrike>
#include <sdktools>
#include <sdkhooks>
#include <shavit>
#pragma semicolon 1
#pragma dynamic 131072 // let's make stuff faster
#pragma newdecls required // We're at 2015 :D
bool gB_Hide[MAXPLAYERS+1];
bool gB_Late;
public Plugin myinfo =
{
name = "[shavit] Miscellaneous",
author = "shavit",
description = "Miscellaneous stuff for shavit's bhop timer.",
version = SHAVIT_VERSION,
url = "http://forums.alliedmods.net/member.php?u=163134"
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
gB_Late = late;
}
public void OnPluginStart()
{
// spectator list
RegConsoleCmd("sm_specs", Command_Specs, "Show a list of spectators.");
RegConsoleCmd("sm_spectators", Command_Specs, "Show a list of spectators.");
// spec
RegConsoleCmd("sm_spec", Command_Spec, "Moves you to the spectators' team. Usage: sm_spec [target]");
RegConsoleCmd("sm_spectate", Command_Spec, "Moves you to the spectators' team. Usage: sm_spec [target]");
// hide
RegConsoleCmd("sm_hide", Command_Hide, "Toggle players' hiding.");
RegConsoleCmd("sm_unhide", Command_Hide, "Toggle players' hiding.");
// message
CreateTimer(600.0, Timer_Message, INVALID_HANDLE, TIMER_REPEAT);
// hooks
HookEvent("player_spawn", Player_Spawn);
// let's fix issues with phrases :D
LoadTranslations("common.phrases");
// CS:GO weapon cleanup
if(Shavit_GetGameType() == Game_CSGO)
{
Handle hDeathDropGun = FindConVar("mp_death_drop_gun");
if(hDeathDropGun != null)
{
SetConVarBool(hDeathDropGun, false);
}
else
{
LogError("idk what's wrong but for some reason, your CS:GO server is missing the \"mp_death_drop_gun\" cvar. go find what's causing it because I dunno");
}
}
// late load
if(gB_Late)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i))
{
OnClientPutInServer(i);
}
}
}
}
public Action Timer_Message(Handle Timer)
{
PrintToChatAll("%s You may write !hide to hide other players.", PREFIX);
return Plugin_Continue;
}
public Action OnPlayerRunCmd(int client)
{
if(!IsValidClient(client, true))
{
return Plugin_Continue;
}
if(GetEntityMoveType(client) == MOVETYPE_NOCLIP)
{
// I'm horrible so I couldn't make it to not require so many variables :S
float fTime;
int iJumps;
BhopStyle bsStyle;
bool bStarted;
Shavit_GetTimer(client, fTime, iJumps, bsStyle, bStarted);
if(bStarted)
{
Shavit_StopTimer(client);
}
}
if(Shavit_InsideZone(client, Zone_Start))
{
float fSpeed[3];
GetEntPropVector(client, Prop_Data, "m_vecVelocity", fSpeed);
float fSpeed_New = SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0));
float fScale = FloatDiv(280.0, fSpeed_New);
if(fScale < 1.0) // 280 / 281 = below 1 | 280 / 279 = above 1
{
fSpeed[0] *= fScale;
fSpeed[1] *= fScale;
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, fSpeed);
}
return Plugin_Continue;
}
return Plugin_Continue;
}
public void OnClientPutInServer(int client)
{
gB_Hide[client] = false;
SDKHook(client, SDKHook_SetTransmit, OnSetTransmit);
SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
}
public Action OnTakeDamage(int victim)
{
return Plugin_Handled;
}
// hide
public Action OnSetTransmit(int entity, int client)
{
if(IsClientObserver(client))
{
return Plugin_Continue;
}
if(gB_Hide[client] && client != entity)
{
return Plugin_Handled;
}
return Plugin_Continue;
}
// hide commands
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs)
{
// let's hope this works
if(IsChatTrigger())
{
return Plugin_Handled;
}
return Plugin_Continue;
}
public Action Command_Hide(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
gB_Hide[client] = !gB_Hide[client];
// I use PTC instead of RTC there because I have an sm_hide bind just like many people :)
PrintToChat(client, "%s You are now %shiding players.", PREFIX, gB_Hide[client]? "":"not ");
return Plugin_Handled;
}
public Action Command_Spec(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
ChangeClientTeam(client, CS_TEAM_SPECTATOR);
if(args > 0)
{
char sArgs[MAX_TARGET_LENGTH];
GetCmdArgString(sArgs, MAX_TARGET_LENGTH);
int iTarget = FindTarget(client, sArgs, false, false);
if(iTarget == -1)
{
return Plugin_Handled;
}
SetEntPropEnt(client, Prop_Send, "m_hObserverTarget", iTarget);
}
return Plugin_Handled;
}
public Action Command_Specs(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
if(!IsPlayerAlive(client) && !IsClientObserver(client))
{
ReplyToCommand(client, "%s You should be alive or spectate someone to see your/their spectators.", PREFIX);
return Plugin_Handled;
}
int iSpecTarget = client;
if(IsClientObserver(client))
{
iSpecTarget = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget");
}
if(args > 0)
{
char sTarget[MAX_TARGET_LENGTH];
GetCmdArgString(sTarget, MAX_TARGET_LENGTH);
int iNewTarget = FindTarget(client, sTarget, false, false);
if(iNewTarget == -1)
{
return Plugin_Handled;
}
if(!IsPlayerAlive(iNewTarget))
{
ReplyToCommand(client, "%s You can't target a dead player.", PREFIX);
return Plugin_Handled;
}
iSpecTarget = iNewTarget;
}
int iCount;
char sSpecs[256];
for(int i = 1; i <= MaxClients; i++)
{
if(!IsValidClient(i) || !IsClientObserver(i))
{
continue;
}
if(GetEntPropEnt(i, Prop_Send, "m_hObserverTarget") == iSpecTarget)
{
iCount++;
if(iCount == 1)
{
FormatEx(sSpecs, 256, "%N", i);
}
else
{
Format(sSpecs, 256, "%s, %N", sSpecs);
}
}
}
if(iCount > 0)
{
ReplyToCommand(client, "%s \x03%N\x01 has %d spectators: %s", PREFIX, iSpecTarget, iCount, sSpecs);
}
else
{
ReplyToCommand(client, "%s No one is spectating \x03%N\x01.", PREFIX, iSpecTarget);
}
return Plugin_Handled;
}
public void Shavit_OnWorldRecord(int client, BhopStyle style, float time, int jumps)
{
for(int i = 1; i <= 3; i++)
{
PrintToChatAll(" \x02NEW %s WR!!!", style == Style_Forwards? "FORWARDS":"SIDEWAYS");
}
}
public void Shavit_OnRestart(int client)
{
if(!IsPlayerAlive(client))
{
if(GetClientTeam(client) <= 1)
{
if(FindEntityByClassname(-1, "info_player_terrorist") != -1)
{
ChangeClientTeam(client, CS_TEAM_T);
}
else
{
ChangeClientTeam(client, CS_TEAM_CT);
}
CreateTimer(0.1, Respawn, client);
}
}
}
public void RestartTimer(int client)
{
if(Shavit_ZoneExists(Zone_Start))
{
// I won't be adding a timer restart native, so I'll do this :S
FakeClientCommand(client, "sm_r");
}
}
public Action Respawn(Handle Timer, any client)
{
if(IsValidClient(client) && !IsPlayerAlive(client))
{
CS_RespawnPlayer(client);
RestartTimer(client);
}
return Plugin_Handled;
}
public void Player_Spawn(Handle event, const char[] name, bool dontBroadcast)
{
int userid = GetEventInt(event, "userid");
int client = GetClientOfUserId(userid);
RestartTimer(client);
}

992
shavit-wr.sp Normal file
View File

@ -0,0 +1,992 @@
/*
* shavit's Timer - World Records
* by: shavit
*
* This file is part of Shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sourcemod>
#include <shavit>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma semicolon 1
#pragma dynamic 131072 // let's make stuff faster
#pragma newdecls required // We're at 2015 :D
//#define DEBUG
bool gB_Late;
// forwards
Handle gH_OnWorldRecord = null;
// database handle
Handle gH_SQL = null;
BhopStyle gBS_LastWR[MAXPLAYERS+1];
char gS_Map[128]; // blame workshop paths to be so fkn long
// current wr stats
float gF_WRTime[MAX_STYLES];
char gS_WRName[MAX_STYLES][MAX_NAME_LENGTH];
float gF_PlayerRecord[MAXPLAYERS+1][MAX_STYLES];
// admin menu
Handle gH_AdminMenu = null;
public Plugin myinfo =
{
name = "[shavit] World Records",
author = "shavit",
description = "World records for shavit's bhop timer.",
version = SHAVIT_VERSION,
url = "http://forums.alliedmods.net/member.php?u=163134"
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
// get wr
CreateNative("Shavit_GetWRTime", Native_GetWRTime);
CreateNative("Shavit_GetWRName", Native_GetWRName);
// get pb
CreateNative("Shavit_GetPlayerPB", Native_GetPlayerPB);
MarkNativeAsOptional("Shavit_GetWRTime");
MarkNativeAsOptional("Shavit_GetWRName");
MarkNativeAsOptional("Shavit_GetPlayerPB");
// registers library, check "LibraryExists(const String:name[])" in order to use with other plugins
RegPluginLibrary("shavit-wr");
gB_Late = late;
return APLRes_Success;
}
public void OnPluginStart()
{
// database connections
Shavit_GetDB(gH_SQL);
SQL_DBConnect();
// debug because I was making this all by myself and no one wanted to help me *sniff*
#if defined DEBUG
RegConsoleCmd("sm_junk", Command_Junk);
#endif
// forwards
gH_OnWorldRecord = CreateGlobalForward("Shavit_OnWorldRecord", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
// WR command
RegConsoleCmd("sm_wr", Command_WR);
RegConsoleCmd("sm_worldrecord", Command_WR);
// WRSW command
RegConsoleCmd("sm_wrsw", Command_WRSW);
RegConsoleCmd("sm_worldrecordsw", Command_WRSW);
// delete records
RegAdminCmd("sm_delete", Command_Delete, ADMFLAG_RCON, "Opens a record deletion menu interface");
RegAdminCmd("sm_deleterecord", Command_Delete, ADMFLAG_RCON, "Opens a record deletion menu interface");
RegAdminCmd("sm_deleterecords", Command_Delete, ADMFLAG_RCON, "Opens a record deletion menu interface");
RegAdminCmd("sm_deleteall", Command_DeleteAll, ADMFLAG_RCON, "Deletes all the records");
// late load
if(gB_Late)
{
for(int i = 1; i <= MaxClients; i++)
{
OnClientPutInServer(i);
}
OnAdminMenuReady(null);
}
}
public void OnAdminMenuReady(Handle topmenu)
{
if(LibraryExists("adminmenu") && ((gH_AdminMenu = GetAdminTopMenu()) != null))
{
TopMenuObject tmoTimer = FindTopMenuCategory(gH_AdminMenu, "Timer Commands");
if(tmoTimer != INVALID_TOPMENUOBJECT)
{
AddToTopMenu(gH_AdminMenu, "sm_deleteall", TopMenuObject_Item, AdminMenu_DeleteAll, tmoTimer, "sm_deleteall", ADMFLAG_RCON);
AddToTopMenu(gH_AdminMenu, "sm_delete", TopMenuObject_Item, AdminMenu_Delete, tmoTimer, "sm_delete", ADMFLAG_RCON);
}
}
}
public void AdminMenu_Delete(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
if(action == TopMenuAction_DisplayOption)
{
FormatEx(buffer, maxlength, "Delete a single record");
}
else if(action == TopMenuAction_SelectOption)
{
Command_Delete(param, 0);
}
}
public void AdminMenu_DeleteAll(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
if(action == TopMenuAction_DisplayOption)
{
FormatEx(buffer, maxlength, "Delete ALL map records");
}
else if(action == TopMenuAction_SelectOption)
{
Command_DeleteAll(param, 0);
}
}
public void OnLibraryAdded(const char[] name)
{
if(StrEqual(name, "shavit"))
{
Shavit_GetDB(gH_SQL);
}
}
public void OnLibraryRemoved(const char[] name)
{
if(StrEqual(name, "shavit"))
{
Shavit_GetDB(gH_SQL);
}
else if(StrEqual(name, "adminmenu"))
{
gH_AdminMenu = null;
}
}
public void OnMapStart()
{
GetCurrentMap(gS_Map, 128);
if(gH_SQL != null)
{
UpdateWRCache();
}
}
public void OnClientPutInServer(int client)
{
for(int i = 0; i < MAX_STYLES; i++)
{
gF_PlayerRecord[client][i] = 0.0;
}
if(!IsClientConnected(client) || IsFakeClient(client) || gH_SQL == null)
{
return;
}
// when I test this plugin, I late load. and it won't return any rows if I don't delay it when I late load so idk ;-;
if(gB_Late)
{
CreateTimer(0.01, Timer_DelayedCache, GetClientSerial(client));
}
else
{
UpdateClientCache(client);
}
}
public Action Timer_DelayedCache(Handle Timer, any data)
{
int client = GetClientFromSerial(data);
if(!client)
{
return Plugin_Handled;
}
UpdateClientCache(client);
return Plugin_Handled;
}
public void UpdateClientCache(int client)
{
char sAuthID[32];
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
char sQuery[256];
FormatEx(sQuery, 256, "SELECT time, style FROM playertimes WHERE map = '%s' AND auth = '%s';", gS_Map, sAuthID);
SQL_TQuery(gH_SQL, SQL_UpdateCache_Callback, sQuery, GetClientSerial(client), DBPrio_High);
}
public void SQL_UpdateCache_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (PB cache update) SQL query failed. Reason: %s", error);
return;
}
int client = GetClientFromSerial(data);
if(!client)
{
return;
}
while(SQL_FetchRow(hndl))
{
gF_PlayerRecord[client][SQL_FetchInt(hndl, 1)] = SQL_FetchFloat(hndl, 0);
}
}
public void UpdateWRCache()
{
char sQuery[256];
FormatEx(sQuery, 256, "SELECT u.name, p.time FROM playertimes p JOIN users u ON p.auth = u.auth WHERE map = '%s' AND style = '0' ORDER BY time ASC LIMIT 1;", gS_Map);
SQL_TQuery(gH_SQL, SQL_UpdateWRCache_Forwards_Callback, sQuery, 0, DBPrio_High);
// I FUCKING KNOW THERE'S A WAY TO DO THIS IN 1 QUERY BUT I SUCK AT SQL SO FORGIVE PLS ;-;
FormatEx(sQuery, 256, "SELECT u.name, p.time FROM playertimes p JOIN users u ON p.auth = u.auth WHERE map = '%s' AND style = '1' ORDER BY time ASC LIMIT 1;", gS_Map);
SQL_TQuery(gH_SQL, SQL_UpdateWRCache_Sideways_Callback, sQuery, 0, DBPrio_High);
}
public void SQL_UpdateWRCache_Forwards_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (WR forwards cache update) SQL query failed. Reason: %s", error);
return;
}
if(!SQL_FetchRow(hndl))
{
FormatEx(gS_WRName[0], MAX_NAME_LENGTH, "invalid");
gF_WRTime[0] = 0.0;
}
else
{
SQL_FetchString(hndl, 0, gS_WRName[0], MAX_NAME_LENGTH);
gF_WRTime[0] = SQL_FetchFloat(hndl, 1);
}
}
public void SQL_UpdateWRCache_Sideways_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (WR sideways cache update) SQL query failed. Reason: %s", error);
return;
}
if(!SQL_FetchRow(hndl))
{
FormatEx(gS_WRName[1], MAX_NAME_LENGTH, "invalid");
gF_WRTime[1] = 0.0;
}
else
{
SQL_FetchString(hndl, 0, gS_WRName[1], MAX_NAME_LENGTH);
gF_WRTime[1] = SQL_FetchFloat(hndl, 1);
}
}
public int Native_GetWRTime(Handle handler, int numParams)
{
BhopStyle style = GetNativeCell(1);
SetNativeCellRef(2, gF_WRTime[style]);
}
public int Native_GetWRName(Handle handler, int numParams)
{
BhopStyle style = GetNativeCell(1);
int maxlength = GetNativeCell(3);
SetNativeString(2, gS_WRName[style], maxlength);
}
public int Native_GetPlayerPB(Handle handler, int numParams)
{
int client = GetNativeCell(1);
BhopStyle style = GetNativeCell(2);
SetNativeCellRef(3, gF_PlayerRecord[client][style]);
}
#if defined DEBUG
// debug
public Action Command_Junk(int client, int args)
{
char sQuery[256];
char sAuth[32];
GetClientAuthId(client, AuthId_Steam3, sAuth, 32);
FormatEx(sQuery, 256, "INSERT INTO playertimes (auth, map, time, jumps, date, style) VALUES ('%s', '%s', %.03f, %d, CURRENT_TIMESTAMP(), 0);", sAuth, gS_Map, GetRandomFloat(10.0, 20.0), GetRandomInt(5, 15));
SQL_LockDatabase(gH_SQL);
SQL_FastQuery(gH_SQL, sQuery);
SQL_UnlockDatabase(gH_SQL);
return Plugin_Handled;
}
#endif
public Action Command_Delete(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
Handle menu = CreateMenu(MenuHandler_Delete);
SetMenuTitle(menu, "Delete a record from:");
AddMenuItem(menu, "forwards", "Forwards");
AddMenuItem(menu, "sideways", "Sideways");
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
return Plugin_Handled;
}
public Action Command_DeleteAll(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
Handle menu = CreateMenu(MenuHandler_DeleteAll);
SetMenuTitle(menu, "Delete ALL the records for \"%s\"?", gS_Map);
for(int i = 1; i <= GetRandomInt(1, 4); i++)
{
AddMenuItem(menu, "-1", "NO!");
}
AddMenuItem(menu, "yes", "YES!!! DELETE ALL THE RECORDS!!! THIS ACTION CANNOT BE REVERTED!!!");
for(int i = 1; i <= GetRandomInt(1, 3); i++)
{
AddMenuItem(menu, "-1", "NO!");
}
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
return Plugin_Handled;
}
public int MenuHandler_DeleteAll(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[16];
GetMenuItem(menu, param2, info, 16);
if(StringToInt(info) == -1)
{
PrintToChat(param1, "%s Aborted deletion.", PREFIX);
return;
}
char sQuery[256];
FormatEx(sQuery, 256, "DELETE FROM playertimes WHERE map = '%s';", gS_Map);
SQL_TQuery(gH_SQL, DeleteAll_Callback, sQuery, GetClientSerial(param1), DBPrio_High);
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public int MenuHandler_Delete(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[16];
GetMenuItem(menu, param2, info, 16);
if(StrEqual(info, "forwards"))
{
OpenDelete(param1, Style_Forwards);
}
else if(StrEqual(info, "sideways"))
{
OpenDelete(param1, Style_Sideways);
}
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public void OpenDelete(int client, BhopStyle style)
{
char sQuery[512];
FormatEx(sQuery, 512, "SELECT p.id, u.name, p.time, p.jumps FROM playertimes p JOIN users u ON p.auth = u.auth WHERE map = '%s' AND style = '%d' ORDER BY time ASC LIMIT 1000;", gS_Map, style);
Handle datapack = CreateDataPack();
WritePackCell(datapack, GetClientSerial(client));
WritePackCell(datapack, style);
SQL_TQuery(gH_SQL, SQL_OpenDelete_Callback, sQuery, datapack, DBPrio_High);
}
public void SQL_OpenDelete_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
ResetPack(data);
int client = GetClientFromSerial(ReadPackCell(data));
BhopStyle style = ReadPackCell(data);
CloseHandle(data);
if(hndl == null)
{
LogError("Timer (WR OpenDelete) SQL query failed. Reason: %s", error);
return;
}
if(!client)
{
return;
}
Handle menu = CreateMenu(OpenDelete_Handler);
SetMenuTitle(menu, "Records for %s:\n(%s)", gS_Map, style == Style_Forwards? "Forwards":"Sideways");
int iCount = 0;
while(SQL_FetchRow(hndl))
{
iCount++;
// 0 - record id, for statistic purposes.
int id = SQL_FetchInt(hndl, 0);
char sID[8];
IntToString(id, sID, 8);
// 1 - player name
char sName[MAX_NAME_LENGTH];
SQL_FetchString(hndl, 1, sName, MAX_NAME_LENGTH);
// 2 - time
float fTime = SQL_FetchFloat(hndl, 2);
char sTime[16];
FormatSeconds(fTime, sTime, 16);
// 3 - jumps
int iJumps = SQL_FetchInt(hndl, 3);
char sDisplay[128];
FormatEx(sDisplay, 128, "#%d - %s - %s (%d Jumps)", iCount, sName, sTime, iJumps);
AddMenuItem(menu, sID, sDisplay);
}
if(!iCount)
{
AddMenuItem(menu, "-1", "No records found.");
}
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
}
public int OpenDelete_Handler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[16];
GetMenuItem(menu, param2, info, 16);
if(StringToInt(info) == -1)
{
return;
}
Handle hMenu = CreateMenu(DeleteConfirm_Handler);
SetMenuTitle(hMenu, "Are you sure?");
for(int i = 1; i <= GetRandomInt(1, 4); i++)
{
AddMenuItem(hMenu, "-1", "NO!");
}
AddMenuItem(hMenu, info, "YES!!! DELETE THE RECORD!!!");
for(int i = 1; i <= GetRandomInt(1, 3); i++)
{
AddMenuItem(hMenu, "-1", "NO!");
}
SetMenuExitButton(hMenu, true);
DisplayMenu(hMenu, param1, 20);
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public int DeleteConfirm_Handler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[16];
GetMenuItem(menu, param2, info, 16);
if(StringToInt(info) == -1)
{
PrintToChat(param1, "%s Aborted deletion.", PREFIX);
return;
}
char sQuery[256];
FormatEx(sQuery, 256, "DELETE FROM playertimes WHERE id = '%s';", info);
SQL_TQuery(gH_SQL, DeleteConfirm_Callback, sQuery, GetClientSerial(param1), DBPrio_High);
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public void DeleteConfirm_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (WR DeleteConfirm) SQL query failed. Reason: %s", error);
return;
}
UpdateWRCache();
for(int i = 1; i <= MaxClients; i++)
{
OnClientPutInServer(i);
}
int client = GetClientFromSerial(data);
if(!client)
{
return;
}
PrintToChat(client, "%s Deleted record.", PREFIX);
}
public void DeleteAll_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (WR DeleteAll) SQL query failed. Reason: %s", error);
return;
}
UpdateWRCache();
for(int i = 1; i <= MaxClients; i++)
{
OnClientPutInServer(i);
}
int client = GetClientFromSerial(data);
if(!client)
{
return;
}
PrintToChat(client, "%s Deleted ALL records for \"%s\".", PREFIX, gS_Map);
}
public Action Command_WR(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
char sQuery[512];
FormatEx(sQuery, 512, "SELECT p.id, u.name, p.time, p.jumps FROM playertimes p JOIN users u ON p.auth = u.auth WHERE map = '%s' AND style = '0' ORDER BY time ASC LIMIT 50;", gS_Map);
SQL_TQuery(gH_SQL, SQL_WR_Callback, sQuery, GetClientSerial(client), DBPrio_High);
gBS_LastWR[client] = Style_Forwards;
return Plugin_Handled;
}
public Action Command_WRSW(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
char sQuery[512];
FormatEx(sQuery, 512, "SELECT p.id, u.name, p.time, p.jumps FROM playertimes p JOIN users u ON p.auth = u.auth WHERE map = '%s' AND style = '1' ORDER BY time ASC LIMIT 100;", gS_Map);
SQL_TQuery(gH_SQL, SQL_WR_Callback, sQuery, GetClientSerial(client), DBPrio_High);
gBS_LastWR[client] = Style_Sideways;
return Plugin_Handled;
}
public void SQL_WR_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (WR SELECT) SQL query failed. Reason: %s", error);
return;
}
int client = GetClientFromSerial(data);
if(!client)
{
return;
}
Handle menu = CreateMenu(WRMenu_Handler);
SetMenuTitle(menu, "Records for %s:", gS_Map);
int iCount = 0;
while(SQL_FetchRow(hndl))
{
iCount++;
// 0 - record id, for statistic purposes.
int id = SQL_FetchInt(hndl, 0);
char sID[8];
IntToString(id, sID, 8);
// 1 - player name
char sName[MAX_NAME_LENGTH];
SQL_FetchString(hndl, 1, sName, MAX_NAME_LENGTH);
// 2 - time
float fTime = SQL_FetchFloat(hndl, 2);
char sTime[16];
FormatSeconds(fTime, sTime, 16);
// 3 - jumps
int iJumps = SQL_FetchInt(hndl, 3);
char sDisplay[128];
FormatEx(sDisplay, 128, "#%d - %s - %s (%d Jumps)", iCount, sName, sTime, iJumps);
AddMenuItem(menu, sID, sDisplay);
}
if(!iCount)
{
AddMenuItem(menu, "-1", "No records found.");
}
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
}
public int WRMenu_Handler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[16];
GetMenuItem(menu, param2, info, 16);
int id = StringToInt(info);
OpenSubMenu(param1, id);
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public void OpenSubMenu(int client, int id)
{
char sQuery[512];
FormatEx(sQuery, 512, "SELECT u.name, p.time, p.jumps, p.style, u.auth, p.date FROM playertimes p JOIN users u ON p.auth = u.auth WHERE p.id = '%d' LIMIT 1;", id);
SQL_TQuery(gH_SQL, SQL_SubMenu_Callback, sQuery, GetClientSerial(client));
}
public void SQL_SubMenu_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (WR SUBMENU) SQL query failed. Reason: %s", error);
return;
}
int client = GetClientFromSerial(data);
if(!client)
{
return;
}
Handle menu = CreateMenu(SubMenu_Handler);
char sName[MAX_NAME_LENGTH];
char sAuthID[32];
int iCount = 0;
while(SQL_FetchRow(hndl))
{
iCount++;
// 0 - name
SQL_FetchString(hndl, 0, sName, MAX_NAME_LENGTH);
// 1 - time
float fTime = SQL_FetchFloat(hndl, 1);
char sDisplay[128];
FormatEx(sDisplay, 128, "Time: %.03f", fTime);
AddMenuItem(menu, "-1", sDisplay);
// 2 - jumps
int iJumps = SQL_FetchInt(hndl, 2);
FormatEx(sDisplay, 128, "Jumps: %d", iJumps);
AddMenuItem(menu, "-1", sDisplay);
// 3 - style
int iStyle = SQL_FetchInt(hndl, 3);
char sStyle[16];
FormatEx(sStyle, 16, "%s", iStyle == view_as<int>Style_Forwards? "Forwards":"Sideways");
FormatEx(sDisplay, 128, "Style: %s", sStyle);
AddMenuItem(menu, "-1", sDisplay);
// 4 - steamid3
SQL_FetchString(hndl, 4, sAuthID, 32);
// 5 - date
char sDate[32];
SQL_FetchString(hndl, 5, sDate, 32);
FormatEx(sDisplay, 128, "Date: %s", sDate);
AddMenuItem(menu, "-1", sDisplay);
}
SetMenuTitle(menu, "%s %s\n--- %s:", sName, sAuthID, gS_Map);
SetMenuExitBackButton(menu, true);
DisplayMenu(menu, client, 20);
}
public int SubMenu_Handler(Handle menu, MenuAction action, int param1, int param2)
{
if((action == MenuAction_Cancel && (param2 == MenuCancel_ExitBack && param2 != MenuCancel_Exit)) || action == MenuAction_Select)
{
OpenWR(param1);
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public void OpenWR(int client)
{
if(!IsValidClient(client))
{
return;
}
if(gBS_LastWR[client] == Style_Forwards)
{
Command_WR(client, 0);
}
else
{
Command_WRSW(client, 0);
}
}
public void SQL_DBConnect()
{
if(SQL_CheckConfig("shavit"))
{
if(gH_SQL != null)
{
SQL_TQuery(gH_SQL, SQL_CreateTable_Callback, "CREATE TABLE IF NOT EXISTS `playertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` VARCHAR(32), `map` VARCHAR(128), `time` FLOAT, `jumps` VARCHAR(32), `style` VARCHAR(32), `date` DATE, PRIMARY KEY (`id`));");
}
}
else
{
SetFailState("Timer (WR module) startup failed. Reason: %s", "\"shavit\" is not a specified entry in databases.cfg.");
}
}
public void SQL_CreateTable_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (WR module) error! Users' times table creation failed. Reason: %s", error);
return;
}
}
public any abs(any thing)
{
if(thing < 0)
{
return thing * -1;
}
return thing;
}
public void Shavit_OnFinish(int client, int style, float time, int jumps)
{
BhopStyle bsStyle = view_as<BhopStyle>style;
char sTime[32];
FormatSeconds(time, sTime, 32);
// k people I made this forward so I'll use it to make cool text messages on WR (check timer-misc soon)
if(time < gF_WRTime[style] || gF_WRTime[style] == 0.0) // WR?
{
Call_StartForward(gH_OnWorldRecord);
Call_PushCell(client);
Call_PushCell(style);
Call_PushCell(time);
Call_PushCell(jumps);
Call_Finish();
UpdateWRCache();
}
// 0 - no query
// 1 - insert
// 2 - update
int overwrite;
if(gF_PlayerRecord[client][style] == 0.0)
{
overwrite = 1;
}
else if(time < gF_PlayerRecord[client][style])
{
overwrite = 2;
}
float fDifference = (gF_PlayerRecord[client][style] - time) * -1.0;
char sDifference[16];
FormatSeconds(fDifference, sDifference, 16, true);
if(overwrite > 0)
{
char sAuthID[32];
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
char sQuery[256];
if(overwrite == 1) // insert
{
PrintToChatAll("%s \x03%N\x01 finished (%s) on \x07%s\x01 with %d jumps.", PREFIX, client, bsStyle == Style_Forwards? "Forwards":"Sideways", sTime, jumps);
FormatEx(sQuery, 256, "INSERT INTO playertimes (auth, map, time, jumps, date, style) VALUES ('%s', '%s', %.03f, %d, CURRENT_TIMESTAMP(), '%d');", sAuthID, gS_Map, time, jumps, style);
}
else // update
{
PrintToChatAll("%s \x03%N\x01 finished (%s) on \x07%s\x01 with %d jumps. \x0C(%s)", PREFIX, client, bsStyle == Style_Forwards? "Forwards":"Sideways", sTime, jumps, sDifference);
FormatEx(sQuery, 256, "UPDATE playertimes SET time = '%.03f', jumps = '%d', date = CURRENT_TIMESTAMP() WHERE map = '%s' AND auth = '%s' AND style = '%d';", time, jumps, gS_Map, sAuthID, style);
}
SQL_TQuery(gH_SQL, SQL_OnFinish_Callback, sQuery, GetClientSerial(client));
}
else
{
if(!overwrite)
{
PrintToChat(client, "%s You have finished (%s) on \x07%s\x01 with %d jumps. \x08(+%s)", PREFIX, bsStyle == Style_Forwards? "Forwards":"Sideways", sTime, jumps, sDifference);
}
else
{
PrintToChat(client, "%s You have finished (%s) on \x07%s\x01 with %d jumps.", PREFIX, bsStyle == Style_Forwards? "Forwards":"Sideways", sTime, jumps);
}
}
}
public void SQL_OnFinish_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (WR OnFinish) SQL query failed. Reason: %s", error);
return;
}
int client = GetClientFromSerial(data);
if(!client)
{
return;
}
UpdateWRCache();
UpdateClientCache(client);
}

870
shavit-zones.sp Normal file
View File

@ -0,0 +1,870 @@
/*
* shavit's Timer - Map Zones
* by: shavit
*
* This file is part of Shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sourcemod>
#include <sdktools>
#include <cstrike>
#include <shavit>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#pragma semicolon 1
#pragma dynamic 131072 // let's make stuff faster
#pragma newdecls required // yay for SM 1.7 :D
Handle gH_SQL = null;
char gS_Map[128];
char gS_ZoneNames[MAX_ZONES][] =
{
"Start Zone",
"End Zone",
"Glitch Zone (Respawn Player)",
"Glitch Zone (Stop Timer)"
};
MapZones gMZ_Type[MAXPLAYERS+1];
// 0 - nothing
// 1 - needs to press E to setup first coord
// 2 - needs to press E to setup second coord
// 3 - confirm
int gI_MapStep[MAXPLAYERS+1];
// I suck
float gV_Point1[MAXPLAYERS+1][3];
float gV_Point2[MAXPLAYERS+1][3];
bool gB_Button[MAXPLAYERS+1];
float gV_MapZones[MAX_ZONES][2][3];
int gI_BeamSprite = -1;
int gI_Colors[MAX_ZONES][4];
// admin menu
Handle gH_AdminMenu = INVALID_HANDLE;
bool gB_Late;
public Plugin myinfo =
{
name = "[shavit] Map Zones",
author = "shavit", // reminder: add ~big big big~ HUGE thanks to blacky
description = "Map zones for shavit's bhop timer.",
version = SHAVIT_VERSION,
url = "http://forums.alliedmods.net/member.php?u=163134"
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
// zone natives
CreateNative("Shavit_ZoneExists", Native_ZoneExists);
CreateNative("Shavit_InsideZone", Native_InsideZone);
MarkNativeAsOptional("Shavit_ZoneExists");
// MarkNativeAsOptional("Shavit_InsideZone"); // called in shavit-core
// registers library, check "LibraryExists(const String:name[])" in order to use with other plugins
RegPluginLibrary("shavit-zones");
gB_Late = late;
return APLRes_Success;
}
public void OnPluginStart()
{
// database shit
Shavit_GetDB(gH_SQL);
SQL_DBConnect();
// menu
RegAdminCmd("sm_zones", Command_Zones, ADMFLAG_RCON, "Opens the mapzones menu");
RegAdminCmd("sm_mapzones", Command_Zones, ADMFLAG_RCON, "Opens the mapzones menu");
RegAdminCmd("sm_deletezone", Command_DeleteZone, ADMFLAG_RCON, "Delete a mapzone");
RegAdminCmd("sm_deleteallzones", Command_DeleteAllZones, ADMFLAG_RCON, "Delete a mapzone");
// colors
SetupColors();
// draw
// start drawing timer here
CreateTimer(0.10, Timer_DrawEverything, INVALID_HANDLE, TIMER_REPEAT);
if(gB_Late)
{
OnAdminMenuReady(null);
}
}
public void OnAdminMenuReady(Handle topmenu)
{
if(LibraryExists("adminmenu") && ((gH_AdminMenu = GetAdminTopMenu()) != null))
{
TopMenuObject tmoTimer = FindTopMenuCategory(gH_AdminMenu, "Timer Commands");
if(tmoTimer != INVALID_TOPMENUOBJECT)
{
AddToTopMenu(gH_AdminMenu, "sm_zones", TopMenuObject_Item, AdminMenu_Zones, tmoTimer, "sm_zones", ADMFLAG_RCON);
AddToTopMenu(gH_AdminMenu, "sm_deletezone", TopMenuObject_Item, AdminMenu_DeleteZone, tmoTimer, "sm_deletezone", ADMFLAG_RCON);
AddToTopMenu(gH_AdminMenu, "sm_deleteallzones", TopMenuObject_Item, AdminMenu_DeleteAllZones, tmoTimer, "sm_deleteallzones", ADMFLAG_RCON);
}
}
}
public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
if(action == TopMenuAction_DisplayTitle)
{
FormatEx(buffer, maxlength, "Timer Commands:");
}
else if (action == TopMenuAction_DisplayOption)
{
FormatEx(buffer, maxlength, "Timer Commands");
}
}
public void AdminMenu_Zones(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
if(action == TopMenuAction_DisplayOption)
{
FormatEx(buffer, maxlength, "Add map zone");
}
else if(action == TopMenuAction_SelectOption)
{
Command_Zones(param, 0);
}
}
public void AdminMenu_DeleteZone(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
if(action == TopMenuAction_DisplayOption)
{
FormatEx(buffer, maxlength, "Delete map zone");
}
else if(action == TopMenuAction_SelectOption)
{
Command_DeleteZone(param, 0);
}
}
public void AdminMenu_DeleteAllZones(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
if(action == TopMenuAction_DisplayOption)
{
FormatEx(buffer, maxlength, "Delete ALL map zones");
}
else if(action == TopMenuAction_SelectOption)
{
Command_DeleteAllZones(param, 0);
}
}
public int Native_ZoneExists(Handle handler, int numParams)
{
MapZones type = GetNativeCell(1);
return view_as<int>(!EmptyZone(gV_MapZones[type][0]) && !EmptyZone(gV_MapZones[type][1]));
}
public int Native_InsideZone(Handle handler, int numParams)
{
int client = GetNativeCell(1);
MapZones type = GetNativeCell(2);
return view_as<int>(InsideZone(client, gV_MapZones[type][0], gV_MapZones[type][1]));
}
public void SetupColors()
{
// start - cyan
gI_Colors[Zone_Start] = {67, 210, 230, 255};
// end - purple
gI_Colors[Zone_End] = {165, 19, 194, 255};
// glitches - invisible but orange for placement
gI_Colors[Zone_Respawn] = {255, 200, 0, 255};
gI_Colors[Zone_Stop] = {255, 200, 0, 255};
}
public void OnMapStart()
{
GetCurrentMap(gS_Map, 128);
UnloadZones(0);
gI_BeamSprite = PrecacheModel("materials/sprites/laserbeam.vmt");
RefreshZones();
}
// 0 - all zones
public void UnloadZones(int zone)
{
if(!zone)
{
for(int i = 0; i < MAX_ZONES; i++)
{
for(int j = 0; j < 3; j++)
{
gV_MapZones[i][0][j] = 0.0;
gV_MapZones[i][1][j] = 0.0;
}
}
}
else
{
for(int i = 0; i < 3; i++)
{
gV_MapZones[zone][0][i] = 0.0;
gV_MapZones[zone][1][i] = 0.0;
}
}
}
public void RefreshZones()
{
char sQuery[256];
FormatEx(sQuery, 256, "SELECT type, corner1_x, corner1_y, corner1_z, corner2_x, corner2_y, corner2_z FROM mapzones WHERE map = '%s';", gS_Map);
SQL_TQuery(gH_SQL, SQL_RefreshZones_Callback, sQuery, DBPrio_High);
}
public void SQL_RefreshZones_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (zone refresh) SQL query failed. Reason: %s", error);
return;
}
while(SQL_FetchRow(hndl))
{
int type = SQL_FetchInt(hndl, 0);
gV_MapZones[type][0][0] = SQL_FetchFloat(hndl, 1);
gV_MapZones[type][0][1] = SQL_FetchFloat(hndl, 2);
gV_MapZones[type][0][2] = SQL_FetchFloat(hndl, 3);
gV_MapZones[type][1][0] = SQL_FetchFloat(hndl, 4);
gV_MapZones[type][1][1] = SQL_FetchFloat(hndl, 5);
gV_MapZones[type][1][2] = SQL_FetchFloat(hndl, 6);
}
}
public void OnClientPutInServer(int client)
{
Reset(client);
}
public void OnClientDisconnect(int client)
{
Reset(client);
}
public Action Command_Zones(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
if(!IsPlayerAlive(client))
{
ReplyToCommand(client, "%s You can't setup mapzones when you're dead.", PREFIX);
return Plugin_Handled;
}
Reset(client);
Handle menu = CreateMenu(Select_Type_MenuHandler);
SetMenuTitle(menu, "Select a zone type:");
AddMenuItem(menu, "0", "Start Zone");
AddMenuItem(menu, "1", "End Zone");
AddMenuItem(menu, "2", "Glitch Zone (Respawn Player)");
AddMenuItem(menu, "3", "Glitch Zone (Stop Timer)");
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
return Plugin_Handled;
}
public Action Command_DeleteZone(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
Handle menu = CreateMenu(DeleteZone_MenuHandler);
SetMenuTitle(menu, "Delete a zone:\nPressing a zone will delete it. This action CANNOT BE REVERTED!");
for (int i = 0; i < MAX_ZONES; i++)
{
if(!EmptyZone(gV_MapZones[i][0]) && !EmptyZone(gV_MapZones[i][1]))
{
char sInfo[8];
IntToString(i, sInfo, 8);
AddMenuItem(menu, sInfo, gS_ZoneNames[i]);
}
}
if(!GetMenuItemCount(menu))
{
AddMenuItem(menu, "-1", "No zones found.");
}
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
return Plugin_Handled;
}
public int DeleteZone_MenuHandler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[8];
GetMenuItem(menu, param2, info, 8);
int iInfo = StringToInt(info);
if(iInfo == -1)
{
return;
}
char sQuery[256];
FormatEx(sQuery, 256, "DELETE FROM mapzones WHERE map = '%s' AND type = '%d';", gS_Map, iInfo);
Handle hDatapack = CreateDataPack();
WritePackCell(hDatapack, GetClientSerial(param1));
WritePackCell(hDatapack, iInfo);
SQL_TQuery(gH_SQL, SQL_DeleteZone_Callback, sQuery, hDatapack);
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public void SQL_DeleteZone_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
ResetPack(data);
int client = GetClientFromSerial(ReadPackCell(data));
int type = ReadPackCell(data);
CloseHandle(data);
if(hndl == null)
{
LogError("Timer (single zone delete) SQL query failed. Reason: %s", error);
return;
}
UnloadZones(type);
RefreshZones();
if(!client)
{
return;
}
PrintToChat(client, "%s Deleted \"%s\" sucessfully.", PREFIX, gS_ZoneNames[type]);
}
public Action Command_DeleteAllZones(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
Handle menu = CreateMenu(DeleteAllZones_MenuHandler);
SetMenuTitle(menu, "Delete ALL mapzones?\nPressing \"Yes\" will delete all the existing mapzones for this map.\nThis action CANNOT BE REVERTED!");
for(int i = 1; i <= GetRandomInt(1, 4); i++)
{
AddMenuItem(menu, "-1", "NO!");
}
AddMenuItem(menu, "yes", "YES!!! DELETE ALL THE MAPZONES!!!");
for(int i = 1; i <= GetRandomInt(1, 3); i++)
{
AddMenuItem(menu, "-1", "NO!");
}
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
return Plugin_Handled;
}
public int DeleteAllZones_MenuHandler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[8];
GetMenuItem(menu, param2, info, 8);
int iInfo = StringToInt(info);
if(iInfo == -1)
{
return;
}
char sQuery[256];
FormatEx(sQuery, 256, "DELETE FROM mapzones WHERE map = '%s';", gS_Map);
SQL_TQuery(gH_SQL, SQL_DeleteAllZones_Callback, sQuery, GetClientSerial(param1));
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public void SQL_DeleteAllZones_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (single zone delete) SQL query failed. Reason: %s", error);
return;
}
UnloadZones(0);
int client = GetClientFromSerial(data);
if(!client)
{
return;
}
PrintToChat(client, "%s Deleted all map zones sucessfully.", PREFIX);
}
public int Select_Type_MenuHandler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[8];
GetMenuItem(menu, param2, info, 8);
gMZ_Type[param1] = view_as<MapZones>StringToInt(info);
ShowPanel(param1, 1);
}
else if(action == MenuAction_End)
{
CloseHandle(menu);
}
}
public void Reset(int client)
{
gI_MapStep[client] = 0;
for(int i = 0; i < 3; i++)
{
gV_Point1[client][i] = 0.0;
gV_Point2[client][i] = 0.0;
}
}
// neat idea for this part is by alongub, you have a cool way of thinking. :)
public void ShowPanel(int client, int step)
{
gI_MapStep[client] = step;
Handle hPanel = CreatePanel();
char sPanelText[128];
FormatEx(sPanelText, 128, "Press USE (default \"E\") to set the %s corner in your current position.", step == 1? "FIRST":"SECOND");
DrawPanelItem(hPanel, sPanelText, ITEMDRAW_RAWLINE);
DrawPanelItem(hPanel, "Abort zone creation");
SendPanelToClient(hPanel, client, ZoneCreation_Handler, 540);
CloseHandle(hPanel);
}
public int ZoneCreation_Handler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
Reset(param1);
}
else if (action == MenuAction_End)
{
CloseHandle(menu);
}
}
public Action OnPlayerRunCmd(int client, int &buttons)
{
if(!IsValidClient(client, true))
{
return Plugin_Continue;
}
if(buttons & IN_USE)
{
if(!gB_Button[client] && gI_MapStep[client] > 0 && gI_MapStep[client] != 3)
{
float vOrigin[3];
GetClientAbsOrigin(client, vOrigin);
if(gI_MapStep[client] == 1)
{
gV_Point1[client] = vOrigin;
CreateTimer(0.1, Timer_Draw, client, TIMER_REPEAT);
ShowPanel(client, 2);
}
else if(gI_MapStep[client] == 2)
{
//vOrigin[2] += 72; // was requested to make it higher
vOrigin[2] += 144;
gV_Point2[client] = vOrigin;
gI_MapStep[client]++;
Handle menu = CreateMenu(CreateZoneConfirm_Handler);
SetMenuTitle(menu, "Confirm?");
AddMenuItem(menu, "yes", "Yes");
AddMenuItem(menu, "no", "No");
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 20);
}
}
gB_Button[client] = true;
}
else
{
gB_Button[client] = false;
}
if(InsideZone(client, gV_MapZones[Zone_Respawn][0], gV_MapZones[Zone_Respawn][1]))
{
CS_RespawnPlayer(client);
return Plugin_Continue;
}
// temp variables
static float fTime;
static int iJumps;
static BhopStyle bsStyle;
bool bStarted;
Shavit_GetTimer(client, fTime, iJumps, bsStyle, bStarted);
if(InsideZone(client, gV_MapZones[Zone_Start][0], gV_MapZones[Zone_Start][1]))
{
Shavit_StartTimer(client);
return Plugin_Continue;
}
if(bStarted)
{
if(InsideZone(client, gV_MapZones[Zone_Stop][0], gV_MapZones[Zone_Stop][1]))
{
Shavit_StopTimer(client);
}
if(InsideZone(client, gV_MapZones[Zone_End][0], gV_MapZones[Zone_End][1]))
{
Shavit_FinishMap(client);
}
}
return Plugin_Continue;
}
public int CreateZoneConfirm_Handler(Handle menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char info[8];
GetMenuItem(menu, param2, info, 8);
if(StrEqual(info, "yes"))
{
InsertZone(param1);
gI_MapStep[param1] = 0;
}
}
else if(action == MenuAction_End)
{
Reset(param1);
CloseHandle(menu);
}
}
public bool EmptyZone(float vZone[3])
{
if(vZone[0] == 0.0 && vZone[1] == 0.0 && vZone[2] == 0.0)
{
return true;
}
return false;
}
public void InsertZone(int client)
{
char sQuery[256];
if(EmptyZone(gV_MapZones[gMZ_Type[client]][0]) && EmptyZone(gV_MapZones[gMZ_Type[client]][1])) // insert
{
FormatEx(sQuery, 256, "INSERT INTO mapzones (map, type, corner1_x, corner1_y, corner1_z, corner2_x, corner2_y, corner2_z) VALUES ('%s', '%d', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f');", gS_Map, gMZ_Type[client], gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2], gV_Point2[client][0], gV_Point2[client][1], gV_Point2[client][2]);
}
else // update
{
FormatEx(sQuery, 256, "UPDATE mapzones SET corner1_x = '%.03f', corner1_y = '%.03f', corner1_z = '%.03f', corner2_x = '%.03f', corner2_y = '%.03f', corner2_z = '%.03f' WHERE map = '%s' AND type = '%d';", gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2], gV_Point2[client][0], gV_Point2[client][1], gV_Point2[client][2], gS_Map, gMZ_Type[client]);
}
SQL_TQuery(gH_SQL, SQL_InsertZone_Callback, sQuery, GetClientSerial(client));
gV_MapZones[gMZ_Type[client]][0] = gV_Point1[client];
gV_MapZones[gMZ_Type[client]][1] = gV_Point2[client];
Reset(client);
}
public void SQL_InsertZone_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (zone insert) SQL query failed. Reason: %s", error);
return;
}
}
public Action Timer_DrawEverything(Handle Timer, any data)
{
for(int i = 0; i < MAX_ZONES; i++)
{
// check shavit.inc, blacklisting glitch zones from being drawn
if(i == 2 || i == 3)
{
continue;
}
//PrintToChatAll("%d", i);
if(!EmptyZone(gV_MapZones[i][0]) && !EmptyZone(gV_MapZones[i][1]))
{
float vPoints[8][3];
vPoints[0] = gV_MapZones[i][0];
vPoints[7] = gV_MapZones[i][1];
CreateZonePoints(vPoints);
DrawZone(0, vPoints, gI_BeamSprite, 0, gI_Colors[i], 0.10);
}
}
}
public Action Timer_Draw(Handle Timer, any data)
{
if(!IsValidClient(data, true) || gI_MapStep[data] == 0)
{
Reset(data);
return Plugin_Stop;
}
float vOrigin[3];
if(gI_MapStep[data] == 1 || gV_Point2[data][0] == 0.0)
{
GetClientAbsOrigin(data, vOrigin);
vOrigin[2] += 144;
}
else
{
vOrigin = gV_Point2[data];
}
float vPoints[8][3];
vPoints[0] = gV_Point1[data];
vPoints[7] = vOrigin;
CreateZonePoints(vPoints);
DrawZone(0, vPoints, gI_BeamSprite, 0, gI_Colors[gMZ_Type[data]], 0.1);
return Plugin_Continue;
}
// by blacky https://forums.alliedmods.net/showthread.php?t=222822
// I just remade it for SM 1.7, that's it.
/*
* returns true if a player is inside the given zone
* returns false if they aren't in it
*/
public bool InsideZone(int client, float point1[3], float point2[3])
{
float playerPos[3];
GetEntPropVector(client, Prop_Send, "m_vecOrigin", playerPos);
playerPos[2] += 5.0;
for(int i = 0; i < 3; i++)
{
if(point1[i] >= playerPos[i] == point2[i] >= playerPos[i])
{
return false;
}
}
return true;
}
/*
* Graphically draws a zone
* if client == 0, it draws it for all players in the game
* if client index is between 0 and MaxClients+1, it draws for the specified client
*/
public void DrawZone(int client, float array[8][3], int beamsprite, int halosprite, int color[4], float life)
{
for(int i = 0, i2 = 3; i2 >= 0; i += i2--)
{
for(int j = 1; j <= 7; j += (j / 2) + 1)
{
if(j != 7 - i)
{
TE_SetupBeamPoints(array[i], array[j], beamsprite, halosprite, 0, 0, life, 5.0, 5.0, 0, 0.0, color, 0);
if(0 < client <= MaxClients)
{
TE_SendToClient(client, 0.0);
}
else
{
TE_SendToAll(0.0);
}
}
}
}
}
/*
* Generates all 8 points of a zone given just 2 of its points
*/
public void CreateZonePoints(float point[8][3])
{
for(int i = 1; i < 7; i++)
{
for(int j = 0; j < 3; j++)
{
point[i][j] = point[((i >> (2-j)) & 1) * 7][j];
}
}
}
// thanks a lot for those stuff, I couldn't do it without you blacky!
public void SQL_DBConnect()
{
if(SQL_CheckConfig("shavit"))
{
if(gH_SQL != null)
{
SQL_TQuery(gH_SQL, SQL_CreateTable_Callback, "CREATE TABLE IF NOT EXISTS `mapzones` (`id` INT AUTO_INCREMENT, `map` VARCHAR(128), `type` INT, `corner1_x` FLOAT, `corner1_y` FLOAT, `corner1_z` FLOAT, `corner2_x` FLOAT, `corner2_y` FLOAT, `corner2_z` FLOAT, PRIMARY KEY (`id`));");
}
}
else
{
SetFailState("Timer (zones module) startup failed. Reason: %s", "\"shavit\" is not a specified entry in databases.cfg.");
}
}
public void SQL_CreateTable_Callback(Handle owner, Handle hndl, const char[] error, any data)
{
if(hndl == null)
{
LogError("Timer (zones module) error! Map zones' table creation failed. Reason: %s", error);
return;
}
}
public void Shavit_OnRestart(int client)
{
if(!EmptyZone(gV_MapZones[0][0]) && !EmptyZone(gV_MapZones[0][1]))
{
float vCenter[3];
MakeVectorFromPoints(gV_MapZones[0][0], gV_MapZones[0][1], vCenter);
vCenter[0] /= 2;
vCenter[1] /= 2;
vCenter[2] /= 2;
vCenter[2] -= 20;
AddVectors(gV_MapZones[0][0], vCenter, vCenter);
TeleportEntity(client, vCenter, NULL_VECTOR, view_as<float>{0.0, 0.0, 0.0});
}
}