/* * 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 . * */ #include #include #include #include #undef REQUIRE_PLUGIN #include #include #pragma semicolon 1 #pragma dynamic 131072 #pragma newdecls required #define PLACEHOLDER 32767 EngineVersion gEV_Type = Engine_Unknown; Database gH_SQL = null; bool gB_MySQL = false; char gS_Map[128]; char gS_ZoneNames[MAX_ZONES][] = { "Start Zone", // starts timer "End Zone", // stops timer "Glitch Zone (Respawn Player)", // respawns the player "Glitch Zone (Stop Timer)", // stops the player's timer "Slay Player", // slays (kills) players which come to this zone "Freestyle Zone", // ignores style physics when at this zone. e.g. WASD when SWing "No Speed Limit", // ignores velocity limit in that zone "Teleport Zone" // teleports to a defined point }; enum { sBeamSprite, sHaloSprite, ZONESPRITES_SIZE } enum { bVisible, iRed, iGreen, iBlue, iAlpha, ZONESETTINGS_SIZE } any gA_ZoneSettings[MAX_ZONES*8][ZONESETTINGS_SIZE]; MapZones gMZ_Type[MAXPLAYERS+1]; // 0 - nothing // 1 - wait for E tap to setup first coord // 2 - wait for E tap to setup second coord // 3 - confirm int gI_MapStep[MAXPLAYERS+1]; float gF_Modifier[MAXPLAYERS+1]; int gI_GridSnap[MAXPLAYERS+1]; // I suck float gV_Point1[MAXPLAYERS+1][3]; float gV_Point2[MAXPLAYERS+1][3]; float gV_Teleport[MAXPLAYERS+1][3]; bool gB_Button[MAXPLAYERS+1]; float gV_MapZones[MAX_ZONES][2][3]; float gV_FreestyleZones[MULTIPLEZONES_LIMIT][2][3]; MapZones gMZ_FreestyleTypes[MULTIPLEZONES_LIMIT]; float gV_TeleportZoneDestination[MULTIPLEZONES_LIMIT][3]; // Sorry for adding too many variables: zone rotations float gV_MapZonesFixes[MAX_ZONES][2][2]; float gV_FreeStyleZonesFixes[MULTIPLEZONES_LIMIT][2][2]; // ofir's pull request float gF_ConstSin[MAX_ZONES]; float gF_MinusConstSin[MAX_ZONES]; float gF_ConstCos[MAX_ZONES]; float gF_MinusConstCos[MAX_ZONES]; float gF_FreeStyleConstSin[MULTIPLEZONES_LIMIT]; float gF_FreeStyleMinusConstSin[MULTIPLEZONES_LIMIT]; float gF_FreeStyleConstCos[MULTIPLEZONES_LIMIT]; float gF_FreeStyleMinusConstCos[MULTIPLEZONES_LIMIT]; float gF_CustomSpawn[3]; float gF_RotateAngle[MAXPLAYERS+1]; float gV_Fix1[MAXPLAYERS+1][2]; float gV_Fix2[MAXPLAYERS+1][2]; // beamsprite, used to draw the zone char gS_Sprites[ZONESPRITES_SIZE][PLATFORM_MAX_PATH]; int gI_BeamSprite = -1; int gI_HaloSprite = -1; // admin menu Handle gH_AdminMenu = INVALID_HANDLE; // late load? bool gB_Late; // cvars ConVar gCV_ZoneStyle = null; ConVar gCV_Interval = null; ConVar gCV_TeleportToStart = null; ConVar gCV_TeleportToEnd = null; ConVar gCV_UseCustomSprite = null; // cached cvars int gI_ZoneStyle = 0; float gF_Interval = 1.0; bool gB_TeleportToStart = true; bool gB_TeleportToEnd = true; bool gB_UseCustomSprite = true; // table prefix char gS_MySQLPrefix[32]; // chat settings char gS_ChatStrings[CHATSETTINGS_SIZE][128]; public Plugin myinfo = { name = "[shavit] Map Zones", author = "shavit", description = "Map zones for shavit's bhop timer.", version = SHAVIT_VERSION, url = "https://github.com/shavitush/bhoptimer" } public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) { // zone natives CreateNative("Shavit_ZoneExists", Native_ZoneExists); CreateNative("Shavit_InsideZone", Native_InsideZone); CreateNative("Shavit_IsClientCreatingZone", Native_IsClientCreatingZone); // registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins RegPluginLibrary("shavit-zones"); gB_Late = late; return APLRes_Success; } public void OnAllPluginsLoaded() { if(gB_Late) { OnAdminMenuReady(null); } } public void OnPluginStart() { LoadTranslations("shavit-zones.phrases"); // game specific gEV_Type = GetEngineVersion(); // 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 all mapzones"); RegAdminCmd("sm_modifier", Command_Modifier, ADMFLAG_RCON, "Changes the axis modifier for the zone editor. Usage: sm_modifier "); RegAdminCmd("sm_addspawn", Command_AddSpawn, ADMFLAG_RCON, "Adds a custom spawn location"); RegAdminCmd("sm_delspawn", Command_DelSpawn, ADMFLAG_RCON, "Deletes a custom spawn location"); // cvars and stuff gCV_ZoneStyle = CreateConVar("shavit_zones_style", "0", "Style for mapzone drawing.\n0 - 3D box\n1 - 2D box", 0, true, 0.0, true, 1.0); gCV_Interval = CreateConVar("shavit_zones_interval", "1.0", "Interval between each time a mapzone is being drawn to the players.", 0, true, 0.5, true, 5.0); gCV_TeleportToStart = CreateConVar("shavit_zones_teleporttostart", "1", "Teleport players to the start zone on timer restart?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); gCV_TeleportToEnd = CreateConVar("shavit_zones_teleporttoend", "1", "Teleport players to the end zone on sm_end?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); gCV_UseCustomSprite = CreateConVar("shavit_zones_usecustomsprite", "1", "Use custom sprite for zone drawing?\nSee `configs/shavit-zones.cfg`.\nRestart server after change.\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); gCV_ZoneStyle.AddChangeHook(OnConVarChanged); gCV_Interval.AddChangeHook(OnConVarChanged); gCV_TeleportToStart.AddChangeHook(OnConVarChanged); gCV_TeleportToEnd.AddChangeHook(OnConVarChanged); gCV_UseCustomSprite.AddChangeHook(OnConVarChanged); AutoExecConfig(); Shavit_GetDB(gH_SQL); SQL_SetPrefix(); SetSQLInfo(); } public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue) { gI_ZoneStyle = gCV_ZoneStyle.IntValue; gF_Interval = gCV_Interval.FloatValue; gB_TeleportToStart = gCV_TeleportToStart.BoolValue; gB_UseCustomSprite = gCV_UseCustomSprite.BoolValue; gB_TeleportToEnd = gCV_TeleportToEnd.BoolValue; } public Action CheckForSQLInfo(Handle Timer) { return SetSQLInfo(); } Action SetSQLInfo() { if(gH_SQL == null) { Shavit_GetDB(gH_SQL); CreateTimer(0.5, CheckForSQLInfo); } else { SQL_DBConnect(); return Plugin_Stop; } return Plugin_Continue; } 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, "%T:", "TimerCommands", param); } else if(action == TopMenuAction_DisplayOption) { FormatEx(buffer, maxlength, "%T", "TimerCommands", param); } } public void AdminMenu_Zones(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) { if(action == TopMenuAction_DisplayOption) { FormatEx(buffer, maxlength, "%T", "AddMapZone", param); } 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, "%T", "DeleteMapZone", param); } 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, "%T", "DeleteAllMapZone", param); } else if(action == TopMenuAction_SelectOption) { Command_DeleteAllZones(param, 0); } } public int Native_ZoneExists(Handle handler, int numParams) { MapZones type = GetNativeCell(1); return view_as(!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); if(type >= Zone_Freestyle && type != Zone_Teleport) { for(int i = 0; i < MULTIPLEZONES_LIMIT; i++) { if((i == 0 && InsideZone(client, -PLACEHOLDER)) || InsideZone(client, -i)) { return true; } } } return view_as(InsideZone(client, view_as(type))); } public int Native_IsClientCreatingZone(Handle handler, int numParams) { return (gI_MapStep[GetNativeCell(1)] != 0); } bool LoadZonesConfig() { char[] sPath = new char[PLATFORM_MAX_PATH]; BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-zones.cfg"); Dynamic dZones = Dynamic(); if(!dZones.ReadKeyValues(sPath)) { dZones.Dispose(); return false; } Dynamic dSprites = dZones.GetDynamicByIndex((gEV_Type == Engine_CSS)? 0:1); dSprites.GetString("beam", gS_Sprites[sBeamSprite], PLATFORM_MAX_PATH); dSprites.GetString("halo", gS_Sprites[sHaloSprite], PLATFORM_MAX_PATH); char[] sDownloads = new char[PLATFORM_MAX_PATH * 8]; dSprites.GetString("downloads", sDownloads, PLATFORM_MAX_PATH * 8); char[][] sDownloadsExploded = new char[PLATFORM_MAX_PATH][PLATFORM_MAX_PATH]; // we don't need more than 8 sprites ever int iDownloads = ExplodeString(sDownloads, ";", sDownloadsExploded, PLATFORM_MAX_PATH, PLATFORM_MAX_PATH, false); for(int i = 0; i < iDownloads; i++) { if(strlen(sDownloadsExploded[i]) > 0) { TrimString(sDownloadsExploded[i]); AddFileToDownloadsTable(sDownloadsExploded[i]); } } Dynamic dColors = dZones.GetDynamicByIndex(2); int iCount = dColors.MemberCount; for(int i = 0; i < iCount; i++) { Dynamic dZoneSettings = dColors.GetDynamicByIndex(i); gA_ZoneSettings[i][bVisible] = dZoneSettings.GetBool("visible", true); gA_ZoneSettings[i][iRed] = dZoneSettings.GetInt("red", 255); gA_ZoneSettings[i][iGreen] = dZoneSettings.GetInt("green", 255); gA_ZoneSettings[i][iBlue] = dZoneSettings.GetInt("blue", 255); gA_ZoneSettings[i][iAlpha] = dZoneSettings.GetInt("alpha", 255); // debug /* char[] sName = new char[32]; dZoneSettings.GetName(sName, 32); PrintToServer("-- [DEBUG] [%s] [visible %d] [r %d] [g %d] [b %d] [a %d]", sName, gA_ZoneSettings[i][bVisible], gA_ZoneSettings[i][iRed], gA_ZoneSettings[i][iGreen], gA_ZoneSettings[i][iBlue], gA_ZoneSettings[i][iAlpha]); */ } dZones.Dispose(true); return true; } public void OnMapStart() { GetCurrentMap(gS_Map, 128); UnloadZones(0); if(gH_SQL != null) { RefreshZones(); } if(!LoadZonesConfig()) { SetFailState("Cannot open \"configs/shavit-zones.cfg\". Make sure this file exists and that the server has read permissions to it."); } if(gB_UseCustomSprite) { gI_BeamSprite = PrecacheModel(gS_Sprites[sBeamSprite], true); gI_HaloSprite = (StrEqual(gS_Sprites[sHaloSprite], "none"))? 0:PrecacheModel(gS_Sprites[sHaloSprite], true); } else { if(gEV_Type == Engine_CSS) { gI_BeamSprite = PrecacheModel("sprites/laser.vmt", true); gI_HaloSprite = PrecacheModel("sprites/halo01.vmt", true); } else { gI_BeamSprite = PrecacheModel("sprites/laserbeam.vmt", true); gI_HaloSprite = PrecacheModel("sprites/glow01.vmt", true); } } // PrecacheModel("models/props/cs_office/vending_machine.mdl"); // placeholder model // draw // start drawing mapzones here CreateTimer(gF_Interval, Timer_DrawEverything, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); if(gB_Late) { Shavit_OnChatConfigLoaded(); } } public void Shavit_OnChatConfigLoaded() { for(int i = 0; i < CHATSETTINGS_SIZE; i++) { Shavit_GetChatStrings(i, gS_ChatStrings[i], 128); } } // 0 - all zones 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; } } for(int i = 0; i < MULTIPLEZONES_LIMIT; i++) { for(int j = 0; j < 3; j++) { gV_FreestyleZones[i][0][j] = 0.0; gV_FreestyleZones[i][1][j] = 0.0; gMZ_FreestyleTypes[i] = view_as(-1); } } ClearCustomSpawn(); return; } if(zone < view_as(Zone_Freestyle)) { for(int i = 0; i < 3; i++) { gV_MapZones[zone][0][i] = 0.0; gV_MapZones[zone][1][i] = 0.0; } } else if(zone == view_as(Zone_CustomSpawn)) { ClearCustomSpawn(); } else { for(int i = 0; i < MULTIPLEZONES_LIMIT; i++) { for(int j = 0; j < 3; j++) { gV_FreestyleZones[i][0][j] = 0.0; gV_FreestyleZones[i][1][j] = 0.0; gMZ_FreestyleTypes[i] = view_as(-1); } } } } void RefreshZones() { char[] sQuery = new char[512]; FormatEx(sQuery, 512, "SELECT type, corner1_x, corner1_y, corner1_z, corner2_x, corner2_y, corner2_z, rot_ang, fix1_x, fix1_y, fix2_x, fix2_y, destination_x, destination_y, destination_z FROM %smapzones WHERE map = '%s';", gS_MySQLPrefix, gS_Map); if(gH_SQL != null) { gH_SQL.Query(SQL_RefreshZones_Callback, sQuery, DBPrio_High); } else { Shavit_GetDB(gH_SQL); } } public void SQL_RefreshZones_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { LogError("Timer (zone refresh) SQL query failed. Reason: %s", error); return; } int iFreestyleRow = 0; while(results.FetchRow()) { MapZones type = view_as(results.FetchInt(0)); if(type == Zone_CustomSpawn) { gF_CustomSpawn[0] = results.FetchFloat(12); gF_CustomSpawn[1] = results.FetchFloat(13); gF_CustomSpawn[2] = results.FetchFloat(14); } else if(type >= Zone_Freestyle) { gV_FreestyleZones[iFreestyleRow][0][0] = results.FetchFloat(1); gV_FreestyleZones[iFreestyleRow][0][1] = results.FetchFloat(2); gV_FreestyleZones[iFreestyleRow][0][2] = results.FetchFloat(3); gV_FreestyleZones[iFreestyleRow][1][0] = results.FetchFloat(4); gV_FreestyleZones[iFreestyleRow][1][1] = results.FetchFloat(5); gV_FreestyleZones[iFreestyleRow][1][2] = results.FetchFloat(6); gMZ_FreestyleTypes[iFreestyleRow] = type; float ang = results.FetchFloat(7); float radian = DegToRad(ang); gF_FreeStyleConstSin[iFreestyleRow] = Sine(radian); gF_FreeStyleConstCos[iFreestyleRow] = Cosine(radian); radian = DegToRad(-ang); gF_FreeStyleMinusConstSin[iFreestyleRow] = Sine(radian); gF_FreeStyleMinusConstCos[iFreestyleRow] = Cosine(radian); gV_FreeStyleZonesFixes[iFreestyleRow][0][0] = results.FetchFloat(8); gV_FreeStyleZonesFixes[iFreestyleRow][0][1] = results.FetchFloat(9); gV_FreeStyleZonesFixes[iFreestyleRow][1][0] = results.FetchFloat(10); gV_FreeStyleZonesFixes[iFreestyleRow][1][1] = results.FetchFloat(11); if(type == Zone_Teleport) { gV_TeleportZoneDestination[iFreestyleRow][0] = results.FetchFloat(12); gV_TeleportZoneDestination[iFreestyleRow][1] = results.FetchFloat(13); gV_TeleportZoneDestination[iFreestyleRow][2] = results.FetchFloat(14); } iFreestyleRow++; } else { if(view_as(type) >= MAX_ZONES || view_as(type) < 0) { continue; } gV_MapZones[type][0][0] = results.FetchFloat(1); gV_MapZones[type][0][1] = results.FetchFloat(2); gV_MapZones[type][0][2] = results.FetchFloat(3); gV_MapZones[type][1][0] = results.FetchFloat(4); gV_MapZones[type][1][1] = results.FetchFloat(5); gV_MapZones[type][1][2] = results.FetchFloat(6); float ang = results.FetchFloat(7); float radian = DegToRad(ang); gF_ConstSin[type] = Sine(radian); gF_ConstCos[type] = Cosine(radian); radian = DegToRad(-ang); gF_MinusConstSin[type] = Sine(radian); gF_MinusConstCos[type] = Cosine(radian); gV_MapZonesFixes[type][0][0] = results.FetchFloat(8); gV_MapZonesFixes[type][0][1] = results.FetchFloat(9); gV_MapZonesFixes[type][1][0] = results.FetchFloat(10); gV_MapZonesFixes[type][1][1] = results.FetchFloat(11); } } } public void OnClientPutInServer(int client) { Reset(client); } public void OnClientDisconnect(int client) { Reset(client); } public Action Command_Modifier(int client, int args) { if(!IsValidClient(client)) { return Plugin_Handled; } if(!args) { Shavit_PrintToChat(client, "%T", "ModifierCommandNoArgs", client); return Plugin_Handled; } char[] sArg1 = new char[16]; GetCmdArg(1, sArg1, 16); float fArg1 = StringToFloat(sArg1); if(fArg1 <= 0.0) { Shavit_PrintToChat(client, "%T", "ModifierTooLow", client); return Plugin_Handled; } gF_Modifier[client] = fArg1; Shavit_PrintToChat(client, "%T %s%.01f%s.", "ModifierSet", client, gS_ChatStrings[sMessageVariable], fArg1, gS_ChatStrings[sMessageText]); return Plugin_Handled; } //Krypt Custom Spawn Functions (https://github.com/Kryptanyte) public Action Command_AddSpawn(int client, int args) { if(!IsValidClient(client)) { return Plugin_Handled; } if(!IsPlayerAlive(client)) { Shavit_PrintToChat(client, "%T", "ZoneDead", client); return Plugin_Handled; } if(!EmptyZone(gF_CustomSpawn)) { Shavit_PrintToChat(client, "%T", "ZoneCustomSpawnExists", client); return Plugin_Handled; } gMZ_Type[client] = Zone_CustomSpawn; GetClientAbsOrigin(client, gV_Point1[client]); InsertZone(client); return Plugin_Handled; } public Action Command_DelSpawn(int client, int args) { if(!IsValidClient(client)) { return Plugin_Handled; } char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE type = '%d' AND map = '%s';", gS_MySQLPrefix, Zone_CustomSpawn, gS_Map); gH_SQL.Query(SQL_DeleteCustom_Spawn_Callback, sQuery, GetClientSerial(client)); return Plugin_Handled; } public void SQL_DeleteCustom_Spawn_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { LogError("Timer (custom spawn delete) SQL query failed. Reason: %s", error); return; } int client = GetClientFromSerial(data); if(client == 0) { return; } ClearCustomSpawn(); Shavit_PrintToChat(client, "%T", "ZoneCustomSpawnDelete", client); } void ClearCustomSpawn() { for(int i = 0; i < 3; i++) { gF_CustomSpawn[i] = 0.0; } } public Action Command_Zones(int client, int args) { if(!IsValidClient(client)) { return Plugin_Handled; } if(!IsPlayerAlive(client)) { Shavit_PrintToChat(client, "%T", "ZonesCommand", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]); return Plugin_Handled; } Reset(client); Menu menu = new Menu(Select_Type_MenuHandler); menu.SetTitle("%T", "ZoneMenuTitle", client); for(int i = 0; i < sizeof(gS_ZoneNames); i++) { char[] sInfo = new char[8]; IntToString(i, sInfo, 8); menu.AddItem(sInfo, gS_ZoneNames[i]); } menu.ExitButton = true; menu.Display(client, 20); return Plugin_Handled; } public Action Command_DeleteZone(int client, int args) { if(!IsValidClient(client)) { return Plugin_Handled; } Menu menu = new Menu(DeleteZone_MenuHandler); menu.SetTitle("%T", "ZoneMenuDeleteTitle", client); for(int i = 0; i < MAX_ZONES; i++) { if(i >= view_as(Zone_Freestyle)) { if(!EmptyZone(gV_FreestyleZones[0][0]) && !EmptyZone(gV_FreestyleZones[0][1])) { char[] sInfo = new char[8]; IntToString(i, sInfo, 8); menu.AddItem(sInfo, gS_ZoneNames[i]); } } if(!EmptyZone(gV_MapZones[i][0]) && !EmptyZone(gV_MapZones[i][1])) { char[] sInfo = new char[8]; IntToString(i, sInfo, 8); menu.AddItem(sInfo, gS_ZoneNames[i]); } } if(menu.ItemCount == 0) { char[] sMenuItem = new char[64]; FormatEx(sMenuItem, 64, "%T", "ZonesMenuNoneFound", client); menu.AddItem("-1", sMenuItem); } menu.ExitButton = true; menu.Display(client, 20); return Plugin_Handled; } public int DeleteZone_MenuHandler(Menu menu, MenuAction action, int param1, int param2) { if(action == MenuAction_Select) { char[] info = new char[8]; menu.GetItem(param2, info, 8); int iInfo = StringToInt(info); if(iInfo == -1) { return 0; } char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE map = '%s' AND type = '%d';", gS_MySQLPrefix, gS_Map, iInfo); DataPack hDatapack = new DataPack(); hDatapack.WriteCell(GetClientSerial(param1)); hDatapack.WriteCell(iInfo); gH_SQL.Query(SQL_DeleteZone_Callback, sQuery, hDatapack); } else if(action == MenuAction_End) { delete menu; } return 0; } public void SQL_DeleteZone_Callback(Database db, DBResultSet results, const char[] error, any data) { ResetPack(data); int client = GetClientFromSerial(ReadPackCell(data)); int type = ReadPackCell(data); delete view_as(data); if(results == null) { LogError("Timer (single zone delete) SQL query failed. Reason: %s", error); return; } UnloadZones(type); RefreshZones(); if(client == 0) { return; } Shavit_PrintToChat(client, "%T", "ZoneDeleteSuccessful", client, gS_ChatStrings[sMessageVariable], gS_ZoneNames[type], gS_ChatStrings[sMessageText]); } public Action Command_DeleteAllZones(int client, int args) { if(!IsValidClient(client)) { return Plugin_Handled; } Menu menu = new Menu(DeleteAllZones_MenuHandler); menu.SetTitle("%T", "ZoneMenuDeleteALLTitle", client); char[] sMenuItem = new char[64]; for(int i = 1; i <= GetRandomInt(1, 4); i++) { FormatEx(sMenuItem, 64, "%T", "ZoneMenuNo", client); menu.AddItem("-1", sMenuItem); } FormatEx(sMenuItem, 64, "%T", "ZoneMenuYes", client); menu.AddItem("yes", sMenuItem); for(int i = 1; i <= GetRandomInt(1, 3); i++) { FormatEx(sMenuItem, 64, "%T", "ZoneMenuNo", client); menu.AddItem("-1", sMenuItem); } menu.ExitButton = true; menu.Display(client, 20); return Plugin_Handled; } public int DeleteAllZones_MenuHandler(Menu menu, MenuAction action, int param1, int param2) { if(action == MenuAction_Select) { char[] info = new char[8]; menu.GetItem(param2, info, 8); int iInfo = StringToInt(info); if(iInfo == -1) { return; } char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE map = '%s';", gS_MySQLPrefix, gS_Map); gH_SQL.Query(SQL_DeleteAllZones_Callback, sQuery, GetClientSerial(param1)); } else if(action == MenuAction_End) { delete menu; } } public void SQL_DeleteAllZones_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { LogError("Timer (single zone delete) SQL query failed. Reason: %s", error); return; } UnloadZones(0); int client = GetClientFromSerial(data); if(client == 0) { return; } Shavit_PrintToChat(client, "%T", "ZoneDeleteAllSuccessful", client); } public int Select_Type_MenuHandler(Menu menu, MenuAction action, int param1, int param2) { if(action == MenuAction_Select) { char[] info = new char[8]; menu.GetItem(param2, info, 8); gMZ_Type[param1] = view_as(StringToInt(info)); ShowPanel(param1, 1); } else if(action == MenuAction_End) { delete menu; } return 0; } void Reset(int client) { gF_Modifier[client] = 10.0; gI_MapStep[client] = 0; gI_GridSnap[client] = 16; gF_RotateAngle[client] = 0.0; for(int i = 0; i < 2; i++) { gV_Fix1[client][i] = 0.0; gV_Fix2[client][i] = 0.0; } for(int i = 0; i < 3; i++) { gV_Point1[client][i] = 0.0; gV_Point2[client][i] = 0.0; gV_Teleport[client][i] = 0.0; } } // neat idea for this part is by alongub, you have a cool way of thinking. :) void ShowPanel(int client, int step) { gI_MapStep[client] = step; if(step == 1) { // not gonna use gF_Interval here as we need percision when setting up zones CreateTimer(0.1, Timer_Draw, GetClientSerial(client), TIMER_REPEAT); } Panel pPanel = new Panel(); char[] sPanelText = new char[128]; char[] sFirst = new char[64]; char[] sSecond = new char[64]; FormatEx(sFirst, 64, "%T", "ZoneFirst", client); FormatEx(sSecond, 64, "%T", "ZoneSecond", client); FormatEx(sPanelText, 128, "%T", "ZonePlaceText", client, (step == 1)? sFirst:sSecond); pPanel.DrawItem(sPanelText, ITEMDRAW_RAWLINE); char[] sPanelItem = new char[64]; FormatEx(sPanelItem, 64, "%T", "AbortZoneCreation", client); pPanel.DrawItem(sPanelItem); char[] sDisplay = new char[64]; FormatEx(sDisplay, 64, "%T", "GridSnap", client, gI_GridSnap[client]); pPanel.DrawItem(sDisplay); pPanel.Send(client, ZoneCreation_Handler, 600); delete pPanel; } public int ZoneCreation_Handler(Menu menu, MenuAction action, int param1, int param2) { if(action == MenuAction_Select) { if(param2 == 1) { Reset(param1); } else { gI_GridSnap[param1] *= 2; if(gI_GridSnap[param1] > 64) { gI_GridSnap[param1] = 1; } ShowPanel(param1, gI_MapStep[param1]); } } else if(action == MenuAction_End) { delete menu; } return 0; } public Action OnPlayerRunCmd(int client, int &buttons) { if(!IsPlayerAlive(client) || IsFakeClient(client)) { return Plugin_Continue; } if(gI_MapStep[client] > 0 && gI_MapStep[client] != 3) { if((buttons & IN_USE) > 0) { if(!gB_Button[client]) { float vOrigin[3]; GetClientAbsOrigin(client, vOrigin); // grid snapping vOrigin[0] = float(RoundToNearest(vOrigin[0] / gI_GridSnap[client]) * gI_GridSnap[client]); vOrigin[1] = float(RoundToNearest(vOrigin[1] / gI_GridSnap[client]) * gI_GridSnap[client]); if(gI_MapStep[client] == 1) { gV_Point1[client] = vOrigin; 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]++; CreateEditMenu(client); } } gB_Button[client] = true; } else { gB_Button[client] = false; } } if(InsideZone(client, view_as(Zone_Respawn))) { CS_RespawnPlayer(client); return Plugin_Continue; } for(int i = 0; i < MULTIPLEZONES_LIMIT; i++) { if(gMZ_FreestyleTypes[i] == Zone_Teleport && !EmptyZone(gV_TeleportZoneDestination[i]) && InsideTeleportZone(client, i)) { TeleportEntity(client, gV_TeleportZoneDestination[i], NULL_VECTOR, NULL_VECTOR); } } if(InsideZone(client, view_as(Zone_Start))) { Shavit_ResumeTimer(client); Shavit_StartTimer(client); return Plugin_Continue; } if(InsideZone(client, view_as(Zone_Slay))) { Shavit_StopTimer(client); ForcePlayerSuicide(client); } if(Shavit_GetTimerStatus(client) == Timer_Running) { if(InsideZone(client, view_as(Zone_Stop))) { Shavit_StopTimer(client); } if(InsideZone(client, view_as(Zone_End))) { Shavit_FinishMap(client); } } return Plugin_Continue; } public int CreateZoneConfirm_Handler(Menu menu, MenuAction action, int param1, int param2) { if(action == MenuAction_Select) { char[] info = new char[8]; menu.GetItem(param2, info, 8); if(StrEqual(info, "yes")) { InsertZone(param1); gI_MapStep[param1] = 0; } else if(StrEqual(info, "no")) { Reset(param1); } else if(StrEqual(info, "adjust")) { CreateAdjustMenu(param1, 0); } else if(StrEqual(info, "rotate")) { CreateRotateMenu(param1); } else if(StrEqual(info, "wl")) { CreateWidthLengthMenu(param1, 0); } else if(StrEqual(info, "tpzone")) { float vTeleport[3]; GetClientAbsOrigin(param1, vTeleport); vTeleport[2] += 2.0; float vPoints[8][3]; vPoints[0] = gV_Point1[param1]; vPoints[7] = gV_Point2[param1]; CreateZonePoints(vPoints, gF_RotateAngle[param1], gV_Fix1[param1], gV_Fix2[param1], PLACEHOLDER, false, true); bool bInside = true; for(int i = 0; i < 3; i++) { if(vPoints[0][i] >= vTeleport[i] == vPoints[7][i] >= vTeleport[i]) { bInside = false; } } if(bInside) { Shavit_PrintToChat(param1, "%T", "ZoneTeleportInsideZone", param1); } else { gV_Teleport[param1] = vTeleport; Shavit_PrintToChat(param1, "%T", "ZoneTeleportUpdated", param1); } CreateEditMenu(param1); } } else if(action == MenuAction_End) { delete menu; } return 0; } void CreateEditMenu(int client) { Menu menu = new Menu(CreateZoneConfirm_Handler, MENU_ACTIONS_DEFAULT|MenuAction_DisplayItem); menu.SetTitle("%T", "ZoneEditConfirm", client); char[] sMenuItem = new char[64]; if(gMZ_Type[client] == Zone_Teleport) { if(EmptyZone(gV_Teleport[client])) { FormatEx(sMenuItem, 64, "%T", "ZoneSetTP", client); menu.AddItem("-1", sMenuItem, ITEMDRAW_DISABLED); } else { FormatEx(sMenuItem, 64, "%T", "ZoneSetYes", client); menu.AddItem("yes", sMenuItem); } FormatEx(sMenuItem, 64, "%T", "ZoneSetTPZone", client); menu.AddItem("tpzone", sMenuItem); } else { FormatEx(sMenuItem, 64, "%T", "ZoneSetYes", client); menu.AddItem("yes", sMenuItem); } FormatEx(sMenuItem, 64, "%T", "ZoneSetNo", client); menu.AddItem("no", sMenuItem); FormatEx(sMenuItem, 64, "%T", "ZoneSetAdjust", client); menu.AddItem("adjust", sMenuItem); FormatEx(sMenuItem, 64, "%T", "ZoneSetRotate", client); menu.AddItem("rotate", sMenuItem); FormatEx(sMenuItem, 64, "%T", "ZoneSetSize", client); menu.AddItem("wl", sMenuItem); menu.ExitButton = true; menu.Display(client, 600); } void CreateAdjustMenu(int client, int page) { Menu hMenu = new Menu(ZoneAdjuster_Handler); char[] sMenuItem = new char[64]; hMenu.SetTitle("%T", "ZoneAdjustPosition", client); FormatEx(sMenuItem, 64, "%T", "ZoneAdjustDone", client); hMenu.AddItem("done", sMenuItem); FormatEx(sMenuItem, 64, "%T", "ZoneAdjustCancel", client); hMenu.AddItem("cancel", sMenuItem); char[] sAxis = new char[4]; strcopy(sAxis, 4, "XYZ"); char[] sDisplay = new char[32]; char[] sInfo = new char[16]; for(int iPoint = 1; iPoint <= 2; iPoint++) { for(int iAxis = 0; iAxis < 3; iAxis++) { for(int iState = 1; iState <= 2; iState++) { FormatEx(sDisplay, 32, "%T %c%.01f", "ZonePoint", client, iPoint, sAxis[iAxis], (iState == 1)? '+':'-', gF_Modifier[client]); FormatEx(sInfo, 16, "%d;%d;%d", iPoint, iAxis, iState); hMenu.AddItem(sInfo, sDisplay); } } } hMenu.ExitButton = false; hMenu.DisplayAt(client, page, MENU_TIME_FOREVER); } public int ZoneAdjuster_Handler(Menu menu, MenuAction action, int param1, int param2) { if(action == MenuAction_Select) { char[] sInfo = new char[16]; menu.GetItem(param2, sInfo, 16); if(StrEqual(sInfo, "done")) { CreateEditMenu(param1); } else if(StrEqual(sInfo, "cancel")) { Reset(param1); } else { char[] sAxis = new char[4]; strcopy(sAxis, 4, "XYZ"); char[][] sExploded = new char[3][8]; ExplodeString(sInfo, ";", sExploded, 3, 8); int iPoint = StringToInt(sExploded[0]); int iAxis = StringToInt(sExploded[1]); bool bIncrease = view_as(StringToInt(sExploded[2]) == 1); ((iPoint == 1)? gV_Point1:gV_Point2)[param1][iAxis] += ((bIncrease)? gF_Modifier[param1]:-gF_Modifier[param1]); Shavit_PrintToChat(param1, "%T", (bIncrease)? "ZoneSizeIncrease":"ZoneSizeDecrease", param1, gS_ChatStrings[sMessageVariable2], sAxis[iAxis], gS_ChatStrings[sMessageText], iPoint, gS_ChatStrings[sMessageVariable], gF_Modifier[param1], gS_ChatStrings[sMessageText]); CreateAdjustMenu(param1, GetMenuSelectionPosition()); } } else if(action == MenuAction_End) { delete menu; } return 0; } void CreateRotateMenu(int client) { Menu hMenu = new Menu(ZoneRotate_Handler); char[] sMenuItem = new char[64]; hMenu.SetTitle("%T", "ZoneRotate", client); FormatEx(sMenuItem, 64, "%T", "ZoneAdjustDone", client); hMenu.AddItem("done", sMenuItem); FormatEx(sMenuItem, 64, "%T", "ZoneAdjustCancel", client); hMenu.AddItem("cancel", sMenuItem); char[] sDisplay = new char[64]; FormatEx(sDisplay, 64, "%T", "ZoneRotatePlus", client, gF_Modifier[client]); hMenu.AddItem("1", sDisplay); FormatEx(sDisplay, 64, "%T", "ZoneRotateNegative", client, gF_Modifier[client]); hMenu.AddItem("2", sDisplay); hMenu.Display(client, 40); } public int ZoneRotate_Handler(Menu menu, MenuAction action, int param1, int param2) { if(action == MenuAction_Select) { char[] sInfo = new char[16]; menu.GetItem(param2, sInfo, 16); if(StrEqual(sInfo, "done")) { CreateEditMenu(param1); } else if(StrEqual(sInfo, "cancel")) { Reset(param1); } else { bool bIncrease = view_as(StringToInt(sInfo) == 1); gF_RotateAngle[param1] += (bIncrease? gF_Modifier[param1]:-gF_Modifier[param1]); Shavit_PrintToChat(param1, "%T", "ZoneRotateSuccessful", param1, gS_ChatStrings[sMessageVariable], ((bIncrease)? gF_Modifier[param1]:-gF_Modifier[param1]), gS_ChatStrings[sMessageText]); CreateRotateMenu(param1); } } else if(action == MenuAction_End) { delete menu; } } void CreateWidthLengthMenu(int client, int page) { Menu hMenu = new Menu(ZoneEdge_Handler); hMenu.SetTitle("%T", "ZoneRotate", client); char[] sMenuItem = new char[64]; FormatEx(sMenuItem, 64, "%T", "ZoneAdjustDone", client); hMenu.AddItem("done", sMenuItem); FormatEx(sMenuItem, 64, "%T", "ZoneAdjustCancel", client); hMenu.AddItem("cancel", sMenuItem); char sEdges[4][64]; FormatEx(sEdges[0], 64, "%T", "Edge_Right", client); FormatEx(sEdges[1], 64, "%T", "Edge_Back", client); FormatEx(sEdges[2], 64, "%T", "Edge_Left", client); FormatEx(sEdges[3], 64, "%T", "Edge_Front", client); char[] sDisplay = new char[32]; char[] sInfo = new char[8]; for(int iEdge = 0; iEdge < 4; iEdge++) { for(int iState = 1; iState <= 2; iState++) { FormatEx(sDisplay, 32, "%s %T | %c%.01f", sEdges[iEdge], "ZoneEdge", client, (iState == 1)? "+":"-", gF_Modifier[client]); FormatEx(sInfo, 8, "%d;%d", iEdge, iState); hMenu.AddItem(sInfo, sDisplay); } } hMenu.DisplayAt(client, page, MENU_TIME_FOREVER); } public int ZoneEdge_Handler(Menu menu, MenuAction action, int param1, int param2) { if(action == MenuAction_Select) { char[] sInfo = new char[16]; menu.GetItem(param2, sInfo, 16); if(StrEqual(sInfo, "done")) { CreateEditMenu(param1); } else if(StrEqual(sInfo, "cancel")) { Reset(param1); } else { char sEdges[4][64]; FormatEx(sEdges[0], 64, "%T", "Edge_Right", param1); FormatEx(sEdges[1], 64, "%T", "Edge_Back", param1); FormatEx(sEdges[2], 64, "%T", "Edge_Left", param1); FormatEx(sEdges[3], 64, "%T", "Edge_Front", param1); char[][] sExploded = new char[2][8]; ExplodeString(sInfo, ";", sExploded, 2, 8); int iEdge = StringToInt(sExploded[0]); bool bIncrease = view_as(StringToInt(sExploded[1]) == 1); if(iEdge >= 2) { iEdge -= 2; gV_Fix1[param1][iEdge] += (bIncrease? gF_Modifier[param1]:-gF_Modifier[param1]); } else { gV_Fix2[param1][iEdge] += (bIncrease? gF_Modifier[param1]:-gF_Modifier[param1]); } char changeText[64]; Format(changeText, sizeof(changeText), "%T", (bIncrease)? "ZoneIncreased":"ZoneDecreased", param1); Shavit_PrintToChat(param1, "%T", "ZoneEdgeChange", param1, sEdges[iEdge], gS_ChatStrings[sMessageVariable2], changeText, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], gF_Modifier[param1], gS_ChatStrings[sMessageText]); CreateWidthLengthMenu(param1, GetMenuSelectionPosition()); } } else if(action == MenuAction_End) { delete menu; } } bool EmptyZone(float vZone[3]) { if(vZone[0] == 0.0 && vZone[1] == 0.0 && vZone[2] == 0.0) { return true; } return false; } void InsertZone(int client) { MapZones type = gMZ_Type[client]; char[] sQuery = new char[512]; if(type == Zone_CustomSpawn) { FormatEx(sQuery, 512, "INSERT INTO %smapzones (map, type, destination_x, destination_y, destination_z) VALUES ('%s', '%d', '%.03f', '%.03f', '%.03f');", gS_MySQLPrefix, gS_Map, type, gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2]); } else if((EmptyZone(gV_MapZones[type][0]) && EmptyZone(gV_MapZones[type][1])) || type >= Zone_Freestyle) // insert { if(type != Zone_Teleport) { FormatEx(sQuery, 512, "INSERT INTO %smapzones (map, type, corner1_x, corner1_y, corner1_z, corner2_x, corner2_y, corner2_z, rot_ang, fix1_x, fix1_y, fix2_x, fix2_y) VALUES ('%s', '%d', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f');", gS_MySQLPrefix, gS_Map, type, gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2], gV_Point2[client][0], gV_Point2[client][1], gV_Point2[client][2], gF_RotateAngle[client], gV_Fix1[client][0], gV_Fix1[client][1], gV_Fix2[client][0], gV_Fix2[client][1]); } else { FormatEx(sQuery, 512, "INSERT INTO %smapzones (map, type, corner1_x, corner1_y, corner1_z, corner2_x, corner2_y, corner2_z, rot_ang, fix1_x, fix1_y, fix2_x, fix2_y, destination_x, destination_y, destination_z) VALUES ('%s', '%d', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f');", gS_MySQLPrefix, gS_Map, type, gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2], gV_Point2[client][0], gV_Point2[client][1], gV_Point2[client][2], gF_RotateAngle[client], gV_Fix1[client][0], gV_Fix1[client][1], gV_Fix2[client][0], gV_Fix2[client][1], gV_Teleport[client][0], gV_Teleport[client][1], gV_Teleport[client][2]); } } else // update { FormatEx(sQuery, 512, "UPDATE %smapzones SET corner1_x = '%.03f', corner1_y = '%.03f', corner1_z = '%.03f', corner2_x = '%.03f', corner2_y = '%.03f', corner2_z = '%.03f', rot_ang = '%.03f', fix1_x = '%.03f', fix1_y = '%.03f', fix2_x = '%.03f', fix2_y = '%.03f' WHERE map = '%s' AND type = '%d';", gS_MySQLPrefix, gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2], gV_Point2[client][0], gV_Point2[client][1], gV_Point2[client][2], gF_RotateAngle[client], gV_Fix1[client][0], gV_Fix1[client][1], gV_Fix2[client][0], gV_Fix2[client][1], gS_Map, type); } gH_SQL.Query(SQL_InsertZone_Callback, sQuery, GetClientSerial(client)); } public void SQL_InsertZone_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { LogError("Timer (zone insert) SQL query failed. Reason: %s", error); return; } int client = GetClientFromSerial(data); if(client == 0) { return; } if(gMZ_Type[client] == Zone_CustomSpawn) { Shavit_PrintToChat(client, "%T", "ZoneCustomSpawnSuccess", client); } UnloadZones((gMZ_Type[client] >= Zone_Freestyle && gMZ_Type[client] != Zone_CustomSpawn)? 0:view_as(gMZ_Type[client])); RefreshZones(); Reset(client); } public Action Timer_DrawEverything(Handle Timer) { for(int i = 0; i < view_as(Zone_Freestyle); i++) { if(gA_ZoneSettings[i][bVisible] && !EmptyZone(gV_MapZones[i][0]) || !EmptyZone(gV_MapZones[i][1])) { DrawToAll(gV_MapZones[i][0], gV_MapZones[i][1], gV_MapZonesFixes[i][0], gV_MapZonesFixes[i][1], view_as(i)); } } for(int i = 0; i < MULTIPLEZONES_LIMIT; i++) { MapZones type = gMZ_FreestyleTypes[i] + view_as(1); if(0 <= view_as(type) <= MAX_ZONES && gA_ZoneSettings[type][bVisible] && (!EmptyZone(gV_FreestyleZones[i][0]) || !EmptyZone(gV_FreestyleZones[i][1]))) { DrawToAll(gV_FreestyleZones[i][0], gV_FreestyleZones[i][1], gV_FreeStyleZonesFixes[i][0], gV_FreeStyleZonesFixes[i][1], type); } } return Plugin_Continue; } int[] GetZoneColors(MapZones type) { int colors[4]; colors[0] = gA_ZoneSettings[type][iRed]; colors[1] = gA_ZoneSettings[type][iGreen]; colors[2] = gA_ZoneSettings[type][iBlue]; colors[3] = gA_ZoneSettings[type][iAlpha]; return colors; } void DrawToAll(float point1[3], float point2[3], float fix1[2], float fix2[2], MapZones type) { float vPoints[8][3]; vPoints[0] = point1; vPoints[7] = point2; if(gEV_Type == Engine_CSS) { vPoints[0][2] += 2.0; vPoints[7][2] += 2.0; } if(gI_ZoneStyle == 1) { vPoints[7][2] = vPoints[0][2]; } CreateZonePoints(vPoints, 0.0, fix1, fix2, (type >= Zone_Freestyle)? -PLACEHOLDER:view_as(type), false, true); DrawZone(vPoints, gI_BeamSprite, gI_HaloSprite, GetZoneColors(type), gF_Interval + 0.2); } public Action Timer_Draw(Handle Timer, any data) { int client = GetClientFromSerial(data); if(client == 0 || gI_MapStep[client] == 0) { Reset(client); return Plugin_Stop; } float vPlayerOrigin[3]; GetClientAbsOrigin(client, vPlayerOrigin); float vOrigin[3]; vOrigin[0] = float(RoundToNearest(vPlayerOrigin[0] / gI_GridSnap[client]) * gI_GridSnap[client]); vOrigin[1] = float(RoundToNearest(vPlayerOrigin[1] / gI_GridSnap[client]) * gI_GridSnap[client]); if(gI_MapStep[client] == 1 || (gV_Point2[client][0] == 0.0)) { vOrigin[2] = (vPlayerOrigin[2] + 144.0); } else { vOrigin = gV_Point2[client]; } if(!EmptyZone(gV_Point1[client]) || !EmptyZone(gV_Point2[client])) { float vPoints[8][3]; vPoints[0] = gV_Point1[client]; vPoints[7] = vOrigin; if(gEV_Type == Engine_CSS) { vPoints[0][2] += 2.0; vPoints[7][2] += 2.0; } CreateZonePoints(vPoints, gF_RotateAngle[client], gV_Fix1[client], gV_Fix2[client], PLACEHOLDER, false, true); int iColors[4]; iColors[0] = gA_ZoneSettings[gMZ_Type[client]][iRed]; iColors[1] = gA_ZoneSettings[gMZ_Type[client]][iGreen]; iColors[2] = gA_ZoneSettings[gMZ_Type[client]][iBlue]; iColors[3] = 255; DrawZone(vPoints, gI_BeamSprite, gI_HaloSprite, iColors, 0.1); if(gMZ_Type[client] == Zone_Teleport && !EmptyZone(gV_Teleport[client])) { TE_SetupEnergySplash(gV_Teleport[client], NULL_VECTOR, false); TE_SendToAll(0.0); } } if(gI_MapStep[client] != 3 && !EmptyZone(vOrigin)) { vOrigin[2] -= 144.0; TE_SetupBeamPoints(vPlayerOrigin, vOrigin, gI_BeamSprite, gI_HaloSprite, 0, 0, 0.1, 3.5, 3.5, 0, 0.0, {230, 83, 124, 175}, 0); TE_SendToAll(0.0); } return Plugin_Continue; } bool UsedFixes(float[2][2] fixes) { for(int a = 0; a < 2; a++) { for(int b = 0; b < 2; b++) { if(fixes[a][b] > 0.0) { return true; } } } return false; } // by blacky https://forums.alliedmods.net/showthread.php?t=222822 // Some of those functions are by ofir753. Thanks <3 // I just remade it for SM 1.7, that's it. /* * * @param client - client to check * @param zone - zone to check (-PLACEHOLDER for freestyle 0, -zone for freestyle) * * returns true if a player is inside the given zone * returns false if they aren't in it */ bool InsideZone(int client, int zone) { float playerPos[3]; GetEntPropVector(client, Prop_Send, "m_vecOrigin", playerPos); playerPos[2] += 5.0; float vPoints[8][3]; if(zone >= 0) { vPoints[0] = gV_MapZones[zone][0]; vPoints[7] = gV_MapZones[zone][1]; if(UsedFixes(gV_MapZonesFixes[zone])) { // Getting the original zone points with the fixes CreateZonePoints(vPoints, 0.0, gV_MapZonesFixes[zone][0], gV_MapZonesFixes[zone][1], zone, true, false); } if(gF_MinusConstSin[zone] != 0.0 || gF_MinusConstCos[zone] != 0.0) { // Rotating the player so the box and the player will be on the same axis PointConstRotate(gF_MinusConstSin[zone], gF_MinusConstCos[zone], vPoints[0], playerPos); } } else { // Explanation above if(zone == -PLACEHOLDER) { vPoints[0] = gV_FreestyleZones[0][0]; vPoints[7] = gV_FreestyleZones[0][1]; if(UsedFixes(gV_FreeStyleZonesFixes[0])) { CreateZonePoints(vPoints, 0.0, gV_FreeStyleZonesFixes[0][0], gV_FreeStyleZonesFixes[0][1], zone, true, false); } if(gF_FreeStyleMinusConstSin[0] != 0.0 || gF_FreeStyleMinusConstCos[0] != 0.0) { PointConstRotate(gF_FreeStyleMinusConstSin[0], gF_FreeStyleMinusConstCos[0], vPoints[0], playerPos); } } else { vPoints[0] = gV_FreestyleZones[-zone][0]; vPoints[7] = gV_FreestyleZones[-zone][1]; if(UsedFixes(gV_FreeStyleZonesFixes[-zone])) { CreateZonePoints(vPoints, 0.0, gV_FreeStyleZonesFixes[-zone][0], gV_FreeStyleZonesFixes[-zone][1], zone, true, false); } if(gF_FreeStyleMinusConstSin[-zone] != 0.0 || gF_FreeStyleMinusConstCos[-zone] != 0.0) { PointConstRotate(gF_FreeStyleMinusConstSin[-zone], gF_FreeStyleMinusConstCos[-zone], vPoints[0], playerPos); } } } // Checking if player is inside the box after rotation for(int i = 0; i < 3; i++) { if(vPoints[0][i] >= playerPos[i] == vPoints[7][i] >= playerPos[i]) { return false; } } return true; } // like InsideZone but for teleport zones bool InsideTeleportZone(int client, int zone) { float fPlayerPos[3]; GetEntPropVector(client, Prop_Send, "m_vecOrigin", fPlayerPos); fPlayerPos[2] += 5.0; float vPoints[8][3]; vPoints[0] = gV_FreestyleZones[zone][0]; vPoints[7] = gV_FreestyleZones[zone][1]; if(UsedFixes(gV_FreeStyleZonesFixes[zone])) { CreateZonePoints(vPoints, 0.0, gV_FreeStyleZonesFixes[zone][0], gV_FreeStyleZonesFixes[zone][1], zone, true, false); } if(gF_FreeStyleMinusConstSin[zone] != 0.0 || gF_FreeStyleMinusConstCos[zone] != 0.0) { PointConstRotate(gF_FreeStyleMinusConstSin[zone], gF_FreeStyleMinusConstCos[zone], vPoints[0], fPlayerPos); } // Checking if player is inside the box after rotation for(int i = 0; i < 3; i++) { if(vPoints[0][i] >= fPlayerPos[i] == vPoints[7][i] >= fPlayerPos[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 */ void DrawZone(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); TE_SendToAll(0.0); } } } } // Rotating point around 2d axis void PointRotate(float angle, float axis[3], float point[3]) { /* a - rotation degree as radians x - old X x' - new X y - old Y y' - new Y Rotation Transformation formula: x' = x cos(a) - y sin(a) y' = y cos(a) + x sin(a) */ float transTmp[3]; transTmp[0] = point[0]; transTmp[1] = point[1]; // Moving point for axis = (0, 0) transTmp[0] -= axis[0]; transTmp[1] -= axis[1]; float radian = DegToRad(angle); float rotTmp[3]; // Rotating point (0, 0) as axis rotTmp[0] = transTmp[0] * Cosine(radian) - transTmp[1] * Sine(radian); rotTmp[1] = transTmp[1] * Cosine(radian) + transTmp[0] * Sine(radian); // Moving point back rotTmp[0] += axis[0]; rotTmp[1] += axis[1]; point[0] = rotTmp[0]; point[1] = rotTmp[1]; } // Rotating point around 2d axis with constant sin and cos void PointConstRotate(float sin, float cos, float axis[3], float point[3]) { /* a - rotation degree as radians x - old X x' - new X y - old Y y' - new Y Rotation Transformation formula: x' = x cos(a) - y sin(a) y' = y cos(a) + x sin(a) */ float transTmp[3]; transTmp[0] = point[0]; transTmp[1] = point[1]; // Moving point for axis = (0, 0) transTmp[0] -= axis[0]; transTmp[1] -= axis[1]; float rotTmp[3]; // Rotating point (0, 0) as axis rotTmp[0] = transTmp[0] * cos - transTmp[1] * sin; rotTmp[1] = transTmp[1] * cos + transTmp[0] * sin; // Moving point back rotTmp[0] += axis[0]; rotTmp[1] += axis[1]; point[0] = rotTmp[0]; point[1] = rotTmp[1]; } // Translate 2D Point void PointTranslate(float point[3], float t[2]) { point[0] += t[0]; point[1] += t[1]; } /* * Generates 8 points of a zone given just 2 of its points * angle - rotated angle for not constant zone (preview zone) * fix1 - edge fixes * fix2 - edge fixes * zone - PLACEHOLDER for not constant zone, -PLACEHOLDER for index 0 freestyle zone, zone id (- for free style zone) * norotate - don't rotate zone points * all - calculate all 8 zone points */ void CreateZonePoints(float point[8][3], float angle, float fix1[2], float fix2[2], int zone, bool norotate, bool all) { if(all) { for(int i = 1; i < 7; i++) { for(int j = 0; j < 3; j++) { point[i][j] = point[((i >> (2-j)) & 1) * 7][j]; } } } if(fix1[0] != 0.0 || fix2[0] != 0.0 || fix1[1] != 0.0 || fix2[1] != 0.0) { TranslateZone(point, fix1, fix2); } if(zone == PLACEHOLDER) { for(int i = 1; i < 8; i++) { if(zone == PLACEHOLDER) { PointRotate(angle, point[0], point[i]); } } } else if(!norotate) { if(zone >= 0 && zone != -PLACEHOLDER) { RotateZone(point, gF_ConstSin[zone], gF_ConstCos[zone]); } else { if(zone == -PLACEHOLDER) { RotateZone(point, gF_FreeStyleConstSin[0], gF_FreeStyleConstCos[0]); } else { RotateZone(point, gF_FreeStyleConstSin[-zone], gF_FreeStyleConstCos[-zone]); } } } } // Translating Zone void TranslateZone(float point[8][3], float fix1[2], float fix2[2]) { float fix[2]; // X Translate fix[1] = 0.0; fix[0] = fix1[0]; PointTranslate(point[0], fix); PointTranslate(point[1], fix); PointTranslate(point[2], fix); PointTranslate(point[3], fix); fix[0] = fix2[0]; PointTranslate(point[4], fix); PointTranslate(point[5], fix); PointTranslate(point[6], fix); PointTranslate(point[7], fix); // Y Translate fix[0] = 0.0; fix[1] = fix1[1]; PointTranslate(point[0], fix); PointTranslate(point[1], fix); PointTranslate(point[4], fix); PointTranslate(point[5], fix); fix[1] = fix2[1]; PointTranslate(point[2], fix); PointTranslate(point[3], fix); PointTranslate(point[6], fix); PointTranslate(point[7], fix); } //Rotating Zone by constant sin and cos void RotateZone(float point[8][3], float sin, float cos) { for(int i = 1; i < 8; i++) { PointConstRotate(sin, cos, point[0], point[i]); } } // thanks a lot for those stuff, I couldn't do it without you blacky! void SQL_SetPrefix() { char[] sFile = new char[PLATFORM_MAX_PATH]; BuildPath(Path_SM, sFile, PLATFORM_MAX_PATH, "configs/shavit-prefix.txt"); File fFile = OpenFile(sFile, "r"); if(fFile == null) { SetFailState("Cannot open \"configs/shavit-prefix.txt\". Make sure this file exists and that the server has read permissions to it."); } char[] sLine = new char[PLATFORM_MAX_PATH*2]; while(fFile.ReadLine(sLine, PLATFORM_MAX_PATH*2)) { TrimString(sLine); strcopy(gS_MySQLPrefix, 32, sLine); break; } delete fFile; } void SQL_DBConnect() { if(gH_SQL != null) { char[] sDriver = new char[8]; gH_SQL.Driver.GetIdentifier(sDriver, 8); gB_MySQL = StrEqual(sDriver, "mysql", false); char[] sQuery = new char[1024]; FormatEx(sQuery, 1024, "CREATE TABLE IF NOT EXISTS `%smapzones` (`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, `rot_ang` FLOAT NOT NULL default 0, `fix1_x` FLOAT NOT NULL default 0, `fix1_y` FLOAT NOT NULL default 0, `fix2_x` FLOAT NOT NULL default 0, `fix2_y` FLOAT NOT NULL default 0, `destination_x` FLOAT NOT NULL default 0, `destination_y` FLOAT NOT NULL default 0, `destination_z` FLOAT NOT NULL default 0, PRIMARY KEY (`id`));", gS_MySQLPrefix); gH_SQL.Query(SQL_CreateTable_Callback, sQuery); } } public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { LogError("Timer (zones module) error! Map zones' table creation failed. Reason: %s", error); return; } char[] sQuery = new char[64]; FormatEx(sQuery, 64, "SELECT rot_ang FROM %smapzones LIMIT 1;", gS_MySQLPrefix); gH_SQL.Query(SQL_TableMigration1_Callback, sQuery); FormatEx(sQuery, 64, "SELECT destination_x FROM %smapzones LIMIT 1;", gS_MySQLPrefix); gH_SQL.Query(SQL_TableMigration2_Callback, sQuery); } public void SQL_TableMigration1_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { char[] sQuery = new char[256]; if(gB_MySQL) { FormatEx(sQuery, 256, "ALTER TABLE `%smapzones` ADD (`rot_ang` FLOAT NOT NULL default 0, `fix1_x` FLOAT NOT NULL default 0, `fix1_y` FLOAT NOT NULL default 0, `fix2_x` FLOAT NOT NULL default 0, `fix2_y` FLOAT NOT NULL default 0);", gS_MySQLPrefix); gH_SQL.Query(SQL_AlterTable1_Callback, sQuery); } else { FormatEx(sQuery, 256, "ALTER TABLE `%smapzones` ADD COLUMN `rot_ang` FLOAT NOT NULL default 0;", gS_MySQLPrefix); gH_SQL.Query(SQL_AlterTable1_Callback, sQuery); for(int i = 1; i <= 2; i++) { FormatEx(sQuery, 256, "ALTER TABLE `%smapzones` ADD COLUMN `fix%d_x` FLOAT NOT NULL default 0;", gS_MySQLPrefix, i); gH_SQL.Query(SQL_AlterTable1_Callback, sQuery); FormatEx(sQuery, 256, "ALTER TABLE `%smapzones` ADD COLUMN `fix%d_y` FLOAT NOT NULL default 0;", gS_MySQLPrefix, i); gH_SQL.Query(SQL_AlterTable1_Callback, sQuery); } } } } public void SQL_AlterTable1_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { LogError("Timer (zones module) error! Map zones' table migration (1) failed. Reason: %s", error); return; } } public void SQL_TableMigration2_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { char[] sQuery = new char[256]; FormatEx(sQuery, 256, "ALTER TABLE `%smapzones` ADD (`destination_x` FLOAT NOT NULL default 0, `destination_y` FLOAT NOT NULL default 0, `destination_z` FLOAT NOT NULL default 0);", gS_MySQLPrefix); gH_SQL.Query(SQL_AlterTable2_Callback, sQuery); } } public void SQL_AlterTable2_Callback(Database db, DBResultSet results, const char[] error, any data) { if(results == null) { LogError("Timer (zones module) error! Map zones' table migration (2) failed. Reason: %s", error); return; } // we have a database, time to load zones RefreshZones(); } public void Shavit_OnRestart(int client) { if(gB_TeleportToStart && !EmptyZone(gV_MapZones[Zone_Start][0]) && !EmptyZone(gV_MapZones[Zone_Start][1])) { Shavit_StartTimer(client); if(!EmptyZone(gF_CustomSpawn)) { TeleportEntity(client, gF_CustomSpawn, NULL_VECTOR, view_as({0.0, 0.0, 0.0})); } else { float vCenter[3]; MakeVectorFromPoints(gV_MapZones[0][0], gV_MapZones[0][1], vCenter); vCenter[0] /= 2.0; vCenter[1] /= 2.0; AddVectors(gV_MapZones[0][0], vCenter, vCenter); vCenter[2] = gV_MapZones[0][0][2]; TeleportEntity(client, vCenter, NULL_VECTOR, view_as({0.0, 0.0, 0.0})); } } } public void Shavit_OnEnd(int client) { if(gB_TeleportToEnd && !EmptyZone(gV_MapZones[Zone_End][0]) && !EmptyZone(gV_MapZones[Zone_End][1])) { float vCenter[3]; MakeVectorFromPoints(gV_MapZones[1][0], gV_MapZones[1][1], vCenter); vCenter[0] /= 2.0; vCenter[1] /= 2.0; AddVectors(gV_MapZones[1][0], vCenter, vCenter); vCenter[2] = gV_MapZones[1][0][2]; TeleportEntity(client, vCenter, NULL_VECTOR, view_as({0.0, 0.0, 0.0})); } } public void Shavit_OnDatabaseLoaded(Database db) { gH_SQL = db; }