mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-06 18:08:26 +00:00
Create a repository
This commit is contained in:
parent
60f7a6ac76
commit
6720d7d3a6
77
README.md
Normal file
77
README.md
Normal 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
303
include/shavit.inc
Normal 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
590
shavit-core.sp
Normal 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
199
shavit-hud.sp
Normal 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
372
shavit-misc.sp
Normal 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
992
shavit-wr.sp
Normal 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
870
shavit-zones.sp
Normal 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});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user