· 9 years ago · Oct 22, 2016, 04:58 PM
1/*
2 * shavit's Timer - Map Zones
3 * by: shavit
4 *
5 * This file is part of shavit's Timer.
6 *
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, version 3.0, as published by the
9 * Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19*/
20
21#include <sourcemod>
22#include <sdktools>
23#include <cstrike>
24#include <dynamic>
25
26#undef REQUIRE_PLUGIN
27#include <shavit>
28#include <adminmenu>
29
30#pragma semicolon 1
31#pragma dynamic 131072
32#pragma newdecls required
33
34#define PLACEHOLDER 32767
35
36EngineVersion gEV_Type = Engine_Unknown;
37
38Database gH_SQL = null;
39bool gB_MySQL = false;
40
41char gS_Map[128];
42
43char gS_ZoneNames[MAX_ZONES][] =
44{
45 "Start Zone", // starts timer
46 "End Zone", // stops timer
47 "Glitch Zone (Respawn Player)", // respawns the player
48 "Glitch Zone (Stop Timer)", // stops the player's timer
49 "Slay Player", // slays (kills) players which come to this zone
50 "Freestyle Zone", // ignores style physics when at this zone. e.g. WASD when SWing
51 "No Speed Limit", // ignores velocity limit in that zone
52 "Teleport Zone" // teleports to a defined point
53};
54
55enum
56{
57 sBeamSprite,
58 sHaloSprite,
59 ZONESPRITES_SIZE
60}
61
62enum
63{
64 bVisible,
65 iRed,
66 iGreen,
67 iBlue,
68 iAlpha,
69 ZONESETTINGS_SIZE
70}
71
72any gA_ZoneSettings[MAX_ZONES*8][ZONESETTINGS_SIZE];
73
74MapZones gMZ_Type[MAXPLAYERS+1];
75
76// 0 - nothing
77// 1 - wait for E tap to setup first coord
78// 2 - wait for E tap to setup second coord
79// 3 - confirm
80int gI_MapStep[MAXPLAYERS+1];
81
82float gF_Modifier[MAXPLAYERS+1];
83int gI_GridSnap[MAXPLAYERS+1];
84
85// I suck
86float gV_Point1[MAXPLAYERS+1][3];
87float gV_Point2[MAXPLAYERS+1][3];
88float gV_Teleport[MAXPLAYERS+1][3];
89
90bool gB_Button[MAXPLAYERS+1];
91
92float gV_MapZones[MAX_ZONES][2][3];
93float gV_FreestyleZones[MULTIPLEZONES_LIMIT][2][3];
94MapZones gMZ_FreestyleTypes[MAXPLAYERS+1];
95float gV_TeleportZoneDestination[MULTIPLEZONES_LIMIT][3];
96
97// Sorry for adding too many variables: zone rotations
98float gV_MapZonesFixes[MAX_ZONES][2][2];
99float gV_FreeStyleZonesFixes[MULTIPLEZONES_LIMIT][2][2];
100
101// ofir's pull request
102float gF_ConstSin[MAX_ZONES];
103float gF_MinusConstSin[MAX_ZONES];
104float gF_ConstCos[MAX_ZONES];
105float gF_MinusConstCos[MAX_ZONES];
106
107float gF_FreeStyleConstSin[MULTIPLEZONES_LIMIT];
108float gF_FreeStyleMinusConstSin[MULTIPLEZONES_LIMIT];
109float gF_FreeStyleConstCos[MULTIPLEZONES_LIMIT];
110float gF_FreeStyleMinusConstCos[MULTIPLEZONES_LIMIT];
111
112float gF_CustomSpawn[3];
113
114float gF_RotateAngle[MAXPLAYERS+1];
115float gV_Fix1[MAXPLAYERS+1][2];
116float gV_Fix2[MAXPLAYERS+1][2];
117
118// beamsprite, used to draw the zone
119char gS_Sprites[ZONESPRITES_SIZE][PLATFORM_MAX_PATH];
120int gI_BeamSprite = -1;
121int gI_HaloSprite = -1;
122
123// admin menu
124Handle gH_AdminMenu = INVALID_HANDLE;
125
126// late load?
127bool gB_Late;
128
129// cvars
130ConVar gCV_ZoneStyle = null;
131ConVar gCV_Interval = null;
132ConVar gCV_TeleportToStart = null;
133ConVar gCV_UseCustomSprite = null;
134
135// cached cvars
136int gI_ZoneStyle = 0;
137float gF_Interval = 1.0;
138bool gB_TeleportToStart = true;
139bool gB_UseCustomSprite = true;
140
141// table prefix
142char gS_MySQLPrefix[32];
143
144// chat settings
145char gS_ChatStrings[CHATSETTINGS_SIZE][128];
146
147public Plugin myinfo =
148{
149 name = "[shavit] Map Zones",
150 author = "shavit",
151 description = "Map zones for shavit's bhop timer.",
152 version = SHAVIT_VERSION,
153 url = "https://github.com/shavitush/bhoptimer"
154}
155
156public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
157{
158 // zone natives
159 CreateNative("Shavit_ZoneExists", Native_ZoneExists);
160 CreateNative("Shavit_InsideZone", Native_InsideZone);
161 CreateNative("Shavit_IsClientCreatingZone", Native_IsClientCreatingZone);
162
163 // registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins
164 RegPluginLibrary("shavit-zones");
165
166 gB_Late = late;
167
168 return APLRes_Success;
169}
170
171public void OnAllPluginsLoaded()
172{
173 if(gB_Late)
174 {
175 OnAdminMenuReady(null);
176 }
177}
178
179public void OnPluginStart()
180{
181 // game specific
182 gEV_Type = GetEngineVersion();
183
184 // menu
185 RegAdminCmd("sm_zones", Command_Zones, ADMFLAG_RCON, "Opens the mapzones menu");
186 RegAdminCmd("sm_mapzones", Command_Zones, ADMFLAG_RCON, "Opens the mapzones menu");
187
188 RegAdminCmd("sm_deletezone", Command_DeleteZone, ADMFLAG_RCON, "Delete a mapzone");
189 RegAdminCmd("sm_deleteallzones", Command_DeleteAllZones, ADMFLAG_RCON, "Delete all mapzones");
190
191 RegAdminCmd("sm_modifier", Command_Modifier, ADMFLAG_RCON, "Changes the axis modifier for the zone editor. Usage: sm_modifier <number>");
192
193 RegAdminCmd("sm_addspawn", Command_AddSpawn, ADMFLAG_RCON, "Adds a custom spawn location");
194 RegAdminCmd("sm_delspawn", Command_DelSpawn, ADMFLAG_RCON, "Deletes a custom spawn location");
195
196 // cvars and stuff
197 gCV_ZoneStyle = CreateConVar("shavit_zones_style", "0", "Style for mapzone drawing.\n0 - 3D box\n1 - 2D box", 0, true, 0.0, true, 1.0);
198 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);
199 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);
200 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);
201
202 gCV_ZoneStyle.AddChangeHook(OnConVarChanged);
203 gCV_Interval.AddChangeHook(OnConVarChanged);
204 gCV_TeleportToStart.AddChangeHook(OnConVarChanged);
205 gCV_UseCustomSprite.AddChangeHook(OnConVarChanged);
206
207 AutoExecConfig();
208
209 Shavit_GetDB(gH_SQL);
210 SQL_SetPrefix();
211 SetSQLInfo();
212}
213
214public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
215{
216 gI_ZoneStyle = gCV_ZoneStyle.IntValue;
217 gF_Interval = gCV_Interval.FloatValue;
218 gB_TeleportToStart = gCV_TeleportToStart.BoolValue;
219 gB_UseCustomSprite = gCV_UseCustomSprite.BoolValue;
220}
221
222public Action CheckForSQLInfo(Handle Timer)
223{
224 return SetSQLInfo();
225}
226
227Action SetSQLInfo()
228{
229 if(gH_SQL == null)
230 {
231 Shavit_GetDB(gH_SQL);
232
233 CreateTimer(0.5, CheckForSQLInfo);
234 }
235
236 else
237 {
238 SQL_DBConnect();
239
240 return Plugin_Stop;
241 }
242
243 return Plugin_Continue;
244}
245
246public void OnAdminMenuReady(Handle topmenu)
247{
248 if(LibraryExists("adminmenu") && ((gH_AdminMenu = GetAdminTopMenu()) != null))
249 {
250 TopMenuObject tmoTimer = FindTopMenuCategory(gH_AdminMenu, "Timer Commands");
251
252 if(tmoTimer != INVALID_TOPMENUOBJECT)
253 {
254 AddToTopMenu(gH_AdminMenu, "sm_zones", TopMenuObject_Item, AdminMenu_Zones, tmoTimer, "sm_zones", ADMFLAG_RCON);
255 AddToTopMenu(gH_AdminMenu, "sm_deletezone", TopMenuObject_Item, AdminMenu_DeleteZone, tmoTimer, "sm_deletezone", ADMFLAG_RCON);
256 AddToTopMenu(gH_AdminMenu, "sm_deleteallzones", TopMenuObject_Item, AdminMenu_DeleteAllZones, tmoTimer, "sm_deleteallzones", ADMFLAG_RCON);
257 }
258 }
259}
260
261public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
262{
263 if(action == TopMenuAction_DisplayTitle)
264 {
265 strcopy(buffer, maxlength, "Timer Commands:");
266 }
267
268 else if(action == TopMenuAction_DisplayOption)
269 {
270 strcopy(buffer, maxlength, "Timer Commands");
271 }
272}
273
274public void AdminMenu_Zones(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
275{
276 if(action == TopMenuAction_DisplayOption)
277 {
278 strcopy(buffer, maxlength, "Add map zone");
279 }
280
281 else if(action == TopMenuAction_SelectOption)
282 {
283 Command_Zones(param, 0);
284 }
285}
286
287public void AdminMenu_DeleteZone(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
288{
289 if(action == TopMenuAction_DisplayOption)
290 {
291 strcopy(buffer, maxlength, "Delete map zone");
292 }
293
294 else if(action == TopMenuAction_SelectOption)
295 {
296 Command_DeleteZone(param, 0);
297 }
298}
299
300public void AdminMenu_DeleteAllZones(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
301{
302 if(action == TopMenuAction_DisplayOption)
303 {
304 strcopy(buffer, maxlength, "Delete ALL map zones");
305 }
306
307 else if(action == TopMenuAction_SelectOption)
308 {
309 Command_DeleteAllZones(param, 0);
310 }
311}
312
313public int Native_ZoneExists(Handle handler, int numParams)
314{
315 MapZones type = GetNativeCell(1);
316
317 return view_as<int>(!EmptyZone(gV_MapZones[type][0]) && !EmptyZone(gV_MapZones[type][1]));
318}
319
320public int Native_InsideZone(Handle handler, int numParams)
321{
322 int client = GetNativeCell(1);
323 MapZones type = GetNativeCell(2);
324
325 if(type >= Zone_Freestyle && type != Zone_Teleport)
326 {
327 for(int i = 0; i < MULTIPLEZONES_LIMIT; i++)
328 {
329 if((i == 0 && InsideZone(client, -PLACEHOLDER)) || InsideZone(client, -i))
330 {
331 return true;
332 }
333 }
334 }
335
336 return view_as<int>(InsideZone(client, view_as<int>(type)));
337}
338
339public int Native_IsClientCreatingZone(Handle handler, int numParams)
340{
341 return (gI_MapStep[GetNativeCell(1)] != 0);
342}
343
344bool LoadZonesConfig()
345{
346 char[] sPath = new char[PLATFORM_MAX_PATH];
347 BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-zones.cfg");
348
349 Dynamic dZones = Dynamic();
350
351 if(!dZones.ReadKeyValues(sPath))
352 {
353 dZones.Dispose();
354
355 return false;
356 }
357
358 Dynamic dSprites = dZones.GetDynamicByIndex((gEV_Type == Engine_CSS)? 0:1);
359 dSprites.GetString("beam", gS_Sprites[sBeamSprite], PLATFORM_MAX_PATH);
360 dSprites.GetString("halo", gS_Sprites[sHaloSprite], PLATFORM_MAX_PATH);
361
362 char[] sDownloads = new char[PLATFORM_MAX_PATH * 8];
363 dSprites.GetString("downloads", sDownloads, PLATFORM_MAX_PATH * 8);
364
365 char[][] sDownloadsExploded = new char[PLATFORM_MAX_PATH][PLATFORM_MAX_PATH]; // we don't need more than 8 sprites ever
366 int iDownloads = ExplodeString(sDownloads, ";", sDownloadsExploded, PLATFORM_MAX_PATH, PLATFORM_MAX_PATH, false);
367
368 for(int i = 0; i < iDownloads; i++)
369 {
370 if(strlen(sDownloadsExploded[i]) > 0)
371 {
372 TrimString(sDownloadsExploded[i]);
373 AddFileToDownloadsTable(sDownloadsExploded[i]);
374 }
375 }
376
377 Dynamic dColors = dZones.GetDynamicByIndex(2);
378 int iCount = dColors.MemberCount;
379
380 for(int i = 0; i < iCount; i++)
381 {
382 Dynamic dZoneSettings = dColors.GetDynamicByIndex(i);
383 gA_ZoneSettings[i][bVisible] = dZoneSettings.GetBool("visible", true);
384 gA_ZoneSettings[i][iRed] = dZoneSettings.GetInt("red", 255);
385 gA_ZoneSettings[i][iGreen] = dZoneSettings.GetInt("green", 255);
386 gA_ZoneSettings[i][iBlue] = dZoneSettings.GetInt("blue", 255);
387 gA_ZoneSettings[i][iAlpha] = dZoneSettings.GetInt("alpha", 255);
388 }
389
390 dZones.Dispose(true);
391
392 return true;
393}
394
395public void OnMapStart()
396{
397 GetCurrentMap(gS_Map, 128);
398
399 UnloadZones(0);
400
401 if(gH_SQL != null)
402 {
403 RefreshZones();
404 }
405
406 if(!LoadZonesConfig())
407 {
408 SetFailState("Cannot open \"configs/shavit-zones.cfg\". Make sure this file exists and that the server has read permissions to it.");
409 }
410
411 if(gB_UseCustomSprite)
412 {
413 gI_BeamSprite = PrecacheModel(gS_Sprites[sBeamSprite], true);
414 gI_HaloSprite = (StrEqual(gS_Sprites[sHaloSprite], "none"))? 0:PrecacheModel(gS_Sprites[sHaloSprite], true);
415 }
416
417 else
418 {
419 if(gEV_Type == Engine_CSS)
420 {
421 gI_BeamSprite = PrecacheModel("sprites/laser.vmt", true);
422 gI_HaloSprite = PrecacheModel("sprites/halo01.vmt", true);
423 }
424
425 else
426 {
427 gI_BeamSprite = PrecacheModel("sprites/laserbeam.vmt", true);
428 gI_HaloSprite = PrecacheModel("sprites/glow01.vmt", true);
429 }
430 }
431
432 // PrecacheModel("models/props/cs_office/vending_machine.mdl"); // placeholder model
433
434 // draw
435 // start drawing mapzones here
436 CreateTimer(gF_Interval, Timer_DrawEverything, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
437
438 if(gB_Late)
439 {
440 Shavit_OnChatConfigLoaded();
441 }
442}
443
444public void Shavit_OnChatConfigLoaded()
445{
446 for(int i = 0; i < CHATSETTINGS_SIZE; i++)
447 {
448 Shavit_GetChatStrings(i, gS_ChatStrings[i], 128);
449 }
450}
451
452// 0 - all zones
453void UnloadZones(int zone)
454{
455 if(!zone)
456 {
457 for(int i = 0; i < MAX_ZONES; i++)
458 {
459 for(int j = 0; j < 3; j++)
460 {
461 gV_MapZones[i][0][j] = 0.0;
462 gV_MapZones[i][1][j] = 0.0;
463 }
464 }
465
466 for(int i = 0; i < MULTIPLEZONES_LIMIT; i++)
467 {
468 for(int j = 0; j < 3; j++)
469 {
470 gV_FreestyleZones[i][0][j] = 0.0;
471 gV_FreestyleZones[i][1][j] = 0.0;
472 gMZ_FreestyleTypes[i] = view_as<MapZones>(-1);
473 }
474 }
475
476 ClearCustomSpawn();
477
478 return;
479 }
480
481 if(zone < view_as<int>(Zone_Freestyle))
482 {
483 for(int i = 0; i < 3; i++)
484 {
485 gV_MapZones[zone][0][i] = 0.0;
486 gV_MapZones[zone][1][i] = 0.0;
487 }
488 }
489
490 else if(zone == view_as<int>(Zone_CustomSpawn))
491 {
492 ClearCustomSpawn();
493 }
494
495 else
496 {
497 for(int i = 0; i < MULTIPLEZONES_LIMIT; i++)
498 {
499 for(int j = 0; j < 3; j++)
500 {
501 gV_FreestyleZones[i][0][j] = 0.0;
502 gV_FreestyleZones[i][1][j] = 0.0;
503 gMZ_FreestyleTypes[i] = view_as<MapZones>(-1);
504 }
505 }
506 }
507}
508
509void RefreshZones()
510{
511 char[] sQuery = new char[512];
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);
513
514 if(gH_SQL != null)
515 {
516 gH_SQL.Query(SQL_RefreshZones_Callback, sQuery, DBPrio_High);
517 }
518
519 else
520 {
521 Shavit_GetDB(gH_SQL);
522 }
523}
524
525public void SQL_RefreshZones_Callback(Database db, DBResultSet results, const char[] error, any data)
526{
527 if(results == null)
528 {
529 LogError("Timer (zone refresh) SQL query failed. Reason: %s", error);
530
531 return;
532 }
533
534 int iFreestyleRow = 0;
535
536 while(results.FetchRow())
537 {
538 MapZones type = view_as<MapZones>(results.FetchInt(0));
539
540 if(type == Zone_CustomSpawn)
541 {
542 gF_CustomSpawn[0] = results.FetchFloat(12);
543 gF_CustomSpawn[1] = results.FetchFloat(13);
544 gF_CustomSpawn[2] = results.FetchFloat(14);
545 }
546
547 else if(type >= Zone_Freestyle)
548 {
549 gV_FreestyleZones[iFreestyleRow][0][0] = results.FetchFloat(1);
550 gV_FreestyleZones[iFreestyleRow][0][1] = results.FetchFloat(2);
551 gV_FreestyleZones[iFreestyleRow][0][2] = results.FetchFloat(3);
552 gV_FreestyleZones[iFreestyleRow][1][0] = results.FetchFloat(4);
553 gV_FreestyleZones[iFreestyleRow][1][1] = results.FetchFloat(5);
554 gV_FreestyleZones[iFreestyleRow][1][2] = results.FetchFloat(6);
555
556 gMZ_FreestyleTypes[iFreestyleRow] = type;
557
558 float ang = results.FetchFloat(7);
559
560 float radian = DegToRad(ang);
561 gF_FreeStyleConstSin[iFreestyleRow] = Sine(radian);
562 gF_FreeStyleConstCos[iFreestyleRow] = Cosine(radian);
563
564 radian = DegToRad(-ang);
565 gF_FreeStyleMinusConstSin[iFreestyleRow] = Sine(radian);
566 gF_FreeStyleMinusConstCos[iFreestyleRow] = Cosine(radian);
567
568 gV_FreeStyleZonesFixes[iFreestyleRow][0][0] = results.FetchFloat(8);
569 gV_FreeStyleZonesFixes[iFreestyleRow][0][1] = results.FetchFloat(9);
570 gV_FreeStyleZonesFixes[iFreestyleRow][1][0] = results.FetchFloat(10);
571 gV_FreeStyleZonesFixes[iFreestyleRow][1][1] = results.FetchFloat(11);
572
573 if(type == Zone_Teleport)
574 {
575 gV_TeleportZoneDestination[iFreestyleRow][0] = results.FetchFloat(12);
576 gV_TeleportZoneDestination[iFreestyleRow][1] = results.FetchFloat(13);
577 gV_TeleportZoneDestination[iFreestyleRow][2] = results.FetchFloat(14);
578 }
579
580 iFreestyleRow++;
581 }
582
583 else
584 {
585 if(view_as<int>(type) >= MAX_ZONES || view_as<int>(type) < 0)
586 {
587 continue;
588 }
589
590 gV_MapZones[type][0][0] = results.FetchFloat(1);
591 gV_MapZones[type][0][1] = results.FetchFloat(2);
592 gV_MapZones[type][0][2] = results.FetchFloat(3);
593 gV_MapZones[type][1][0] = results.FetchFloat(4);
594 gV_MapZones[type][1][1] = results.FetchFloat(5);
595 gV_MapZones[type][1][2] = results.FetchFloat(6);
596
597 float ang = results.FetchFloat(7);
598
599 float radian = DegToRad(ang);
600 gF_ConstSin[type] = Sine(radian);
601 gF_ConstCos[type] = Cosine(radian);
602
603 radian = DegToRad(-ang);
604 gF_MinusConstSin[type] = Sine(radian);
605 gF_MinusConstCos[type] = Cosine(radian);
606
607 gV_MapZonesFixes[type][0][0] = results.FetchFloat(8);
608 gV_MapZonesFixes[type][0][1] = results.FetchFloat(9);
609 gV_MapZonesFixes[type][1][0] = results.FetchFloat(10);
610 gV_MapZonesFixes[type][1][1] = results.FetchFloat(11);
611 }
612 }
613}
614
615public void OnClientPutInServer(int client)
616{
617 Reset(client);
618}
619
620public void OnClientDisconnect(int client)
621{
622 Reset(client);
623}
624
625public Action Command_Modifier(int client, int args)
626{
627 if(!IsValidClient(client))
628 {
629 return Plugin_Handled;
630 }
631
632 if(!args)
633 {
634 Shavit_PrintToChat(client, "Usage: sm_modifier <decimal number>");
635
636 return Plugin_Handled;
637 }
638
639 char[] sArg1 = new char[16];
640 GetCmdArg(1, sArg1, 16);
641
642 float fArg1 = StringToFloat(sArg1);
643
644 if(fArg1 <= 0.0)
645 {
646 Shavit_PrintToChat(client, "Modifier must be higher than 0.");
647
648 return Plugin_Handled;
649 }
650
651 gF_Modifier[client] = fArg1;
652
653 Shavit_PrintToChat(client, "Modifier set to %s%.01f%s.", gS_ChatStrings[sMessageVariable], fArg1, gS_ChatStrings[sMessageText]);
654
655 return Plugin_Handled;
656}
657
658//Krypt Custom Spawn Functions (https://github.com/Kryptanyte)
659public Action Command_AddSpawn(int client, int args)
660{
661 if(!IsValidClient(client))
662 {
663 return Plugin_Handled;
664 }
665
666 if(!IsPlayerAlive(client))
667 {
668 Shavit_PrintToChat(client, "You can't place zones when you're dead.");
669
670 return Plugin_Handled;
671 }
672
673 if(!EmptyZone(gF_CustomSpawn))
674 {
675 Shavit_PrintToChat(client, "Custom Spawn already exists. Please delete it before placing a new one.");
676
677 return Plugin_Handled;
678 }
679
680 gMZ_Type[client] = Zone_CustomSpawn;
681
682 GetClientAbsOrigin(client, gV_Point1[client]);
683 InsertZone(client);
684
685 return Plugin_Handled;
686}
687
688public Action Command_DelSpawn(int client, int args)
689{
690 if(!IsValidClient(client))
691 {
692 return Plugin_Handled;
693 }
694
695 char[] sQuery = new char[256];
696 FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE type = '%d' AND map = '%s';", gS_MySQLPrefix, Zone_CustomSpawn, gS_Map);
697
698 gH_SQL.Query(SQL_DeleteCustom_Spawn_Callback, sQuery, GetClientSerial(client));
699
700 return Plugin_Handled;
701}
702
703public void SQL_DeleteCustom_Spawn_Callback(Database db, DBResultSet results, const char[] error, any data)
704{
705 if(results == null)
706 {
707 LogError("Timer (custom spawn delete) SQL query failed. Reason: %s", error);
708
709 return;
710 }
711
712 int client = GetClientFromSerial(data);
713
714 if(client == 0)
715 {
716 return;
717 }
718
719 ClearCustomSpawn();
720
721 Shavit_PrintToChat(client, "Deleted Custom Spawn sucessfully.");
722}
723
724void ClearCustomSpawn()
725{
726 for(int i = 0; i < 3; i++)
727 {
728 gF_CustomSpawn[i] = 0.0;
729 }
730}
731
732public Action Command_Zones(int client, int args)
733{
734 if(!IsValidClient(client))
735 {
736 return Plugin_Handled;
737 }
738
739 if(!IsPlayerAlive(client))
740 {
741 Shavit_PrintToChat(client, "You %scannot%s setup mapzones when you're dead.", gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
742
743 return Plugin_Handled;
744 }
745
746 Reset(client);
747
748 Menu menu = new Menu(Select_Type_MenuHandler);
749 menu.SetTitle("Select a zone type:");
750
751 for(int i = 0; i < sizeof(gS_ZoneNames); i++)
752 {
753 char[] sInfo = new char[8];
754 IntToString(i, sInfo, 8);
755
756 menu.AddItem(sInfo, gS_ZoneNames[i]);
757 }
758
759 menu.ExitButton = true;
760 menu.Display(client, 20);
761
762 return Plugin_Handled;
763}
764
765public Action Command_DeleteZone(int client, int args)
766{
767 if(!IsValidClient(client))
768 {
769 return Plugin_Handled;
770 }
771
772 Menu menu = new Menu(DeleteZone_MenuHandler);
773 menu.SetTitle("Delete a zone:\nPressing a zone will delete it. This action CANNOT BE REVERTED!");
774
775 for(int i = 0; i < MAX_ZONES; i++)
776 {
777 if(i >= view_as<int>(Zone_Freestyle))
778 {
779 if(!EmptyZone(gV_FreestyleZones[0][0]) && !EmptyZone(gV_FreestyleZones[0][1]))
780 {
781 char[] sInfo = new char[8];
782 IntToString(i, sInfo, 8);
783 menu.AddItem(sInfo, gS_ZoneNames[i]);
784 }
785 }
786
787 if(!EmptyZone(gV_MapZones[i][0]) && !EmptyZone(gV_MapZones[i][1]))
788 {
789 char[] sInfo = new char[8];
790 IntToString(i, sInfo, 8);
791 menu.AddItem(sInfo, gS_ZoneNames[i]);
792 }
793 }
794
795 if(menu.ItemCount == 0)
796 {
797 menu.AddItem("-1", "No zones found.");
798 }
799
800 menu.ExitButton = true;
801 menu.Display(client, 20);
802
803 return Plugin_Handled;
804}
805
806public int DeleteZone_MenuHandler(Menu menu, MenuAction action, int param1, int param2)
807{
808 if(action == MenuAction_Select)
809 {
810 char[] info = new char[8];
811 menu.GetItem(param2, info, 8);
812
813 int iInfo = StringToInt(info);
814
815 if(iInfo == -1)
816 {
817 return 0;
818 }
819
820 char[] sQuery = new char[256];
821 FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE map = '%s' AND type = '%d';", gS_MySQLPrefix, gS_Map, iInfo);
822
823 DataPack hDatapack = new DataPack();
824 hDatapack.WriteCell(GetClientSerial(param1));
825 hDatapack.WriteCell(iInfo);
826
827 gH_SQL.Query(SQL_DeleteZone_Callback, sQuery, hDatapack);
828 }
829
830 else if(action == MenuAction_End)
831 {
832 delete menu;
833 }
834
835 return 0;
836}
837
838public void SQL_DeleteZone_Callback(Database db, DBResultSet results, const char[] error, any data)
839{
840 ResetPack(data);
841 int client = GetClientFromSerial(ReadPackCell(data));
842 int type = ReadPackCell(data);
843
844 delete view_as<DataPack>(data);
845
846 if(results == null)
847 {
848 LogError("Timer (single zone delete) SQL query failed. Reason: %s", error);
849
850 return;
851 }
852
853 UnloadZones(type);
854 RefreshZones();
855
856 if(client == 0)
857 {
858 return;
859 }
860
861 Shavit_PrintToChat(client, "Deleted %s%s%s sucessfully.", gS_ChatStrings[sMessageVariable], gS_ZoneNames[type], gS_ChatStrings[sMessageText]);
862}
863
864public Action Command_DeleteAllZones(int client, int args)
865{
866 if(!IsValidClient(client))
867 {
868 return Plugin_Handled;
869 }
870
871 Menu menu = new Menu(DeleteAllZones_MenuHandler);
872 menu.SetTitle("Delete ALL mapzones?\nPressing \"Yes\" will delete all the existing mapzones for this map.\nThis action CANNOT BE REVERTED!");
873
874 for(int i = 1; i <= GetRandomInt(1, 4); i++)
875 {
876 menu.AddItem("-1", "NO!");
877 }
878
879 menu.AddItem("yes", "YES!!! DELETE ALL THE MAPZONES!!!");
880
881 for(int i = 1; i <= GetRandomInt(1, 3); i++)
882 {
883 menu.AddItem("-1", "NO!");
884 }
885
886 menu.ExitButton = true;
887
888 menu.Display(client, 20);
889
890 return Plugin_Handled;
891}
892
893public int DeleteAllZones_MenuHandler(Menu menu, MenuAction action, int param1, int param2)
894{
895 if(action == MenuAction_Select)
896 {
897 char[] info = new char[8];
898 menu.GetItem(param2, info, 8);
899
900 int iInfo = StringToInt(info);
901
902 if(iInfo == -1)
903 {
904 return;
905 }
906
907 char[] sQuery = new char[256];
908 FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE map = '%s';", gS_MySQLPrefix, gS_Map);
909
910 gH_SQL.Query(SQL_DeleteAllZones_Callback, sQuery, GetClientSerial(param1));
911 }
912
913 else if(action == MenuAction_End)
914 {
915 delete menu;
916 }
917}
918
919public void SQL_DeleteAllZones_Callback(Database db, DBResultSet results, const char[] error, any data)
920{
921 if(results == null)
922 {
923 LogError("Timer (single zone delete) SQL query failed. Reason: %s", error);
924
925 return;
926 }
927
928 UnloadZones(0);
929
930 int client = GetClientFromSerial(data);
931
932 if(client == 0)
933 {
934 return;
935 }
936
937 Shavit_PrintToChat(client, "Deleted all map zones sucessfully.");
938}
939
940public int Select_Type_MenuHandler(Menu menu, MenuAction action, int param1, int param2)
941{
942 if(action == MenuAction_Select)
943 {
944 char[] info = new char[8];
945 menu.GetItem(param2, info, 8);
946
947 gMZ_Type[param1] = view_as<MapZones>(StringToInt(info));
948
949 ShowPanel(param1, 1);
950 }
951
952 else if(action == MenuAction_End)
953 {
954 delete menu;
955 }
956
957 return 0;
958}
959
960void Reset(int client)
961{
962 gF_Modifier[client] = 10.0;
963 gI_MapStep[client] = 0;
964 gI_GridSnap[client] = 16;
965 gF_RotateAngle[client] = 0.0;
966
967 for(int i = 0; i < 2; i++)
968 {
969 gV_Fix1[client][i] = 0.0;
970 gV_Fix2[client][i] = 0.0;
971 }
972
973 for(int i = 0; i < 3; i++)
974 {
975 gV_Point1[client][i] = 0.0;
976 gV_Point2[client][i] = 0.0;
977 gV_Teleport[client][i] = 0.0;
978 }
979}
980
981// neat idea for this part is by alongub, you have a cool way of thinking. :)
982void ShowPanel(int client, int step)
983{
984 gI_MapStep[client] = step;
985
986 if(step == 1)
987 {
988 // not gonna use gF_Interval here as we need percision when setting up zones
989 CreateTimer(0.1, Timer_Draw, GetClientSerial(client), TIMER_REPEAT);
990 }
991
992 Panel pPanel = new Panel();
993
994 char[] sPanelText = new char[128];
995 FormatEx(sPanelText, 128, "Press USE (default \"E\") to set the %s corner in your current position.", (step == 1)? "FIRST":"SECOND");
996
997 pPanel.DrawItem(sPanelText, ITEMDRAW_RAWLINE);
998 pPanel.DrawItem("Abort zone creation");
999
1000 char[] sDisplay = new char[16];
1001 FormatEx(sDisplay, 16, "Grid snap: x%d", gI_GridSnap[client]);
1002 pPanel.DrawItem(sDisplay);
1003
1004 pPanel.Send(client, ZoneCreation_Handler, 600);
1005
1006 delete pPanel;
1007}
1008
1009public int ZoneCreation_Handler(Menu menu, MenuAction action, int param1, int param2)
1010{
1011 if(action == MenuAction_Select)
1012 {
1013 if(param2 == 1)
1014 {
1015 Reset(param1);
1016 }
1017
1018 else
1019 {
1020 gI_GridSnap[param1] *= 2;
1021
1022 if(gI_GridSnap[param1] > 64)
1023 {
1024 gI_GridSnap[param1] = 1;
1025 }
1026
1027 ShowPanel(param1, gI_MapStep[param1]);
1028 }
1029 }
1030
1031 else if(action == MenuAction_End)
1032 {
1033 delete menu;
1034 }
1035
1036 return 0;
1037}
1038
1039public Action OnPlayerRunCmd(int client, int &buttons)
1040{
1041 if(!IsPlayerAlive(client) || IsFakeClient(client))
1042 {
1043 return Plugin_Continue;
1044 }
1045
1046 if(gI_MapStep[client] > 0 && gI_MapStep[client] != 3)
1047 {
1048 if((buttons & IN_USE) > 0)
1049 {
1050 if(!gB_Button[client])
1051 {
1052 float vOrigin[3];
1053 GetClientAbsOrigin(client, vOrigin);
1054
1055 // grid snapping
1056 vOrigin[0] = float(RoundToNearest(vOrigin[0] / gI_GridSnap[client]) * gI_GridSnap[client]);
1057 vOrigin[1] = float(RoundToNearest(vOrigin[1] / gI_GridSnap[client]) * gI_GridSnap[client]);
1058
1059 if(gI_MapStep[client] == 1)
1060 {
1061 gV_Point1[client] = vOrigin;
1062
1063 ShowPanel(client, 2);
1064 }
1065
1066 else if(gI_MapStep[client] == 2)
1067 {
1068 //vOrigin[2] += 72; // was requested to make it higher
1069 vOrigin[2] += 144;
1070 gV_Point2[client] = vOrigin;
1071
1072 gI_MapStep[client]++;
1073
1074 CreateEditMenu(client);
1075 }
1076 }
1077
1078 gB_Button[client] = true;
1079 }
1080
1081 else
1082 {
1083 gB_Button[client] = false;
1084 }
1085 }
1086
1087 if(InsideZone(client, view_as<int>(Zone_Respawn)))
1088 {
1089 CS_RespawnPlayer(client);
1090
1091 return Plugin_Continue;
1092 }
1093
1094 for(int i = 0; i < MULTIPLEZONES_LIMIT; i++)
1095 {
1096 if(gMZ_FreestyleTypes[i] == Zone_Teleport && !EmptyZone(gV_TeleportZoneDestination[i]) && InsideTeleportZone(client, i))
1097 {
1098 TeleportEntity(client, gV_TeleportZoneDestination[i], NULL_VECTOR, NULL_VECTOR);
1099 }
1100 }
1101
1102 // temp variables
1103 static float fTime;
1104 static int iJumps;
1105 static BhopStyle bsStyle;
1106 bool bStarted;
1107 Shavit_GetTimer(client, fTime, iJumps, bsStyle, bStarted);
1108
1109 if(InsideZone(client, view_as<int>(Zone_Start)))
1110 {
1111 Shavit_ResumeTimer(client);
1112 Shavit_StartTimer(client);
1113
1114 return Plugin_Continue;
1115 }
1116
1117 if(InsideZone(client, view_as<int>(Zone_Slay)))
1118 {
1119 Shavit_StopTimer(client);
1120
1121 ForcePlayerSuicide(client);
1122 }
1123
1124 if(bStarted)
1125 {
1126 if(InsideZone(client, view_as<int>(Zone_Stop)))
1127 {
1128 Shavit_StopTimer(client);
1129 }
1130
1131 if(InsideZone(client, view_as<int>(Zone_End)))
1132 {
1133 Shavit_FinishMap(client);
1134 }
1135 }
1136
1137 return Plugin_Continue;
1138}
1139
1140public int CreateZoneConfirm_Handler(Menu menu, MenuAction action, int param1, int param2)
1141{
1142 if(action == MenuAction_Select)
1143 {
1144 char[] info = new char[8];
1145 menu.GetItem(param2, info, 8);
1146
1147 if(StrEqual(info, "yes"))
1148 {
1149 InsertZone(param1);
1150
1151 gI_MapStep[param1] = 0;
1152 }
1153
1154 else if(StrEqual(info, "no"))
1155 {
1156 Reset(param1);
1157 }
1158
1159 else if(StrEqual(info, "adjust"))
1160 {
1161 CreateAdjustMenu(param1, 0);
1162 }
1163
1164 else if(StrEqual(info, "rotate"))
1165 {
1166 CreateRotateMenu(param1);
1167 }
1168
1169 else if(StrEqual(info, "wl"))
1170 {
1171 CreateWidthLengthMenu(param1, 0);
1172 }
1173
1174 else if(StrEqual(info, "tpzone"))
1175 {
1176 GetClientAbsOrigin(param1, gV_Teleport[param1]);
1177 Shavit_PrintToChat(param1, "Teleport zone destination updated.");
1178
1179 CreateEditMenu(param1);
1180 }
1181 }
1182
1183 else if(action == MenuAction_End)
1184 {
1185 delete menu;
1186 }
1187
1188 return 0;
1189}
1190
1191void CreateEditMenu(int client)
1192{
1193 Menu menu = new Menu(CreateZoneConfirm_Handler, MENU_ACTIONS_DEFAULT|MenuAction_DisplayItem);
1194 menu.SetTitle("Confirm?");
1195
1196 if(gMZ_Type[client] == Zone_Teleport)
1197 {
1198 if(EmptyZone(gV_Teleport[client]))
1199 {
1200 menu.AddItem("-1", "Yes (choose teleport destination first)", ITEMDRAW_DISABLED);
1201 }
1202
1203 else
1204 {
1205 menu.AddItem("yes", "Yes");
1206 }
1207
1208 menu.AddItem("tpzone", "Update teleport destination");
1209 }
1210
1211 else
1212 {
1213 menu.AddItem("yes", "Yes");
1214 }
1215
1216 menu.AddItem("no", "No");
1217 menu.AddItem("adjust", "Adjust position");
1218 menu.AddItem("rotate", "Rotate zone");
1219 menu.AddItem("wl", "Modify width/length");
1220
1221 menu.ExitButton = true;
1222
1223 menu.Display(client, 600);
1224}
1225
1226void CreateAdjustMenu(int client, int page)
1227{
1228 Menu hMenu = new Menu(ZoneAdjuster_Handler);
1229 hMenu.SetTitle("Adjust the zone's position.\nUse \"sm_modifier <number>\" to set a new modifier.");
1230
1231 hMenu.AddItem("done", "Done!");
1232 hMenu.AddItem("cancel", "Cancel");
1233
1234 char[] sAxis = new char[4];
1235 strcopy(sAxis, 4, "XYZ");
1236
1237 char[] sDisplay = new char[32];
1238 char[] sInfo = new char[16];
1239
1240 for(int iPoint = 1; iPoint <= 2; iPoint++)
1241 {
1242 for(int iAxis = 0; iAxis < 3; iAxis++)
1243 {
1244 for(int iState = 1; iState <= 2; iState++)
1245 {
1246 FormatEx(sDisplay, 32, "Point %d | %c axis %c%.01f", iPoint, sAxis[iAxis], (iState == 1)? '+':'-', gF_Modifier[client]);
1247 FormatEx(sInfo, 16, "%d;%d;%d", iPoint, iAxis, iState);
1248 hMenu.AddItem(sInfo, sDisplay);
1249 }
1250 }
1251 }
1252
1253 hMenu.ExitButton = false;
1254 hMenu.DisplayAt(client, page, MENU_TIME_FOREVER);
1255}
1256
1257public int ZoneAdjuster_Handler(Menu menu, MenuAction action, int param1, int param2)
1258{
1259 if(action == MenuAction_Select)
1260 {
1261 char[] sInfo = new char[16];
1262 menu.GetItem(param2, sInfo, 16);
1263
1264 if(StrEqual(sInfo, "done"))
1265 {
1266 CreateEditMenu(param1);
1267 }
1268
1269 else if(StrEqual(sInfo, "cancel"))
1270 {
1271 Reset(param1);
1272 }
1273
1274 else
1275 {
1276 char[] sAxis = new char[4];
1277 strcopy(sAxis, 4, "XYZ");
1278
1279 char[][] sExploded = new char[3][8];
1280 ExplodeString(sInfo, ";", sExploded, 3, 8);
1281
1282 int iPoint = StringToInt(sExploded[0]);
1283 int iAxis = StringToInt(sExploded[1]);
1284 bool bIncrease = view_as<bool>(StringToInt(sExploded[2]) == 1);
1285
1286 ((iPoint == 1)? gV_Point1:gV_Point2)[param1][iAxis] += ((bIncrease)? gF_Modifier[param1]:-gF_Modifier[param1]);
1287
1288 if(bIncrease)
1289 {
1290 Shavit_PrintToChat(param1, "%s%c axis%s (point %d) increased by %s%.01f%s.", gS_ChatStrings[sMessageVariable2], sAxis[iAxis], gS_ChatStrings[sMessageText], iPoint, gS_ChatStrings[sMessageVariable], gF_Modifier[param1], gS_ChatStrings[sMessageText]);
1291 }
1292
1293 else
1294 {
1295 Shavit_PrintToChat(param1, "%s%c axis%s (point %d) decreased by %s%.01f%s.", gS_ChatStrings[sMessageVariable2], sAxis[iAxis], gS_ChatStrings[sMessageText], iPoint, gS_ChatStrings[sMessageVariable], gF_Modifier[param1], gS_ChatStrings[sMessageText]);
1296 }
1297
1298 CreateAdjustMenu(param1, GetMenuSelectionPosition());
1299 }
1300 }
1301
1302 else if(action == MenuAction_End)
1303 {
1304 delete menu;
1305 }
1306
1307 return 0;
1308}
1309
1310void CreateRotateMenu(int client)
1311{
1312 Menu hMenu = new Menu(ZoneRotate_Handler);
1313 hMenu.SetTitle("Rotate the zone.\nUse \"sm_modifier <number>\" to set a new modifier.");
1314
1315 hMenu.AddItem("done", "Done!");
1316 hMenu.AddItem("cancel", "Cancel");
1317
1318 char[] sDisplay = new char[64];
1319 FormatEx(sDisplay, 64, "Rotate by +%.01f degrees", gF_Modifier[client]);
1320 hMenu.AddItem("1", sDisplay);
1321
1322 FormatEx(sDisplay, 64, "Rotate by -%.01f degrees", gF_Modifier[client]);
1323 hMenu.AddItem("2", sDisplay);
1324
1325 hMenu.Display(client, 40);
1326}
1327
1328public int ZoneRotate_Handler(Menu menu, MenuAction action, int param1, int param2)
1329{
1330 if(action == MenuAction_Select)
1331 {
1332 char[] sInfo = new char[16];
1333 menu.GetItem(param2, sInfo, 16);
1334
1335 if(StrEqual(sInfo, "done"))
1336 {
1337 CreateEditMenu(param1);
1338 }
1339
1340 else if(StrEqual(sInfo, "cancel"))
1341 {
1342 Reset(param1);
1343 }
1344
1345 else
1346 {
1347 bool bIncrease = view_as<bool>(StringToInt(sInfo) == 1);
1348 gF_RotateAngle[param1] += (bIncrease? gF_Modifier[param1]:-gF_Modifier[param1]);
1349
1350 Shavit_PrintToChat(param1, "Zone rotated by %s%.01f%s degrees.", gS_ChatStrings[sMessageVariable], ((bIncrease)? gF_Modifier[param1]:-gF_Modifier[param1]), gS_ChatStrings[sMessageText]);
1351
1352 CreateRotateMenu(param1);
1353 }
1354 }
1355
1356 else if(action == MenuAction_End)
1357 {
1358 delete menu;
1359 }
1360}
1361
1362void CreateWidthLengthMenu(int client, int page)
1363{
1364 Menu hMenu = new Menu(ZoneEdge_Handler);
1365 hMenu.SetTitle("Rotate the zone.\nUse \"sm_modifier <number>\" to set a new modifier.");
1366
1367 hMenu.AddItem("done", "Done!");
1368 hMenu.AddItem("cancel", "Cancel");
1369
1370 char sEdges[][] =
1371 {
1372 "Right",
1373 "Back",
1374 "Left",
1375 "Front"
1376 };
1377
1378 char[] sDisplay = new char[32];
1379 char[] sInfo = new char[8];
1380
1381 for(int iEdge = 0; iEdge < 4; iEdge++)
1382 {
1383 for(int iState = 1; iState <= 2; iState++)
1384 {
1385 FormatEx(sDisplay, 32, "%s edge | %c%.01f", sEdges[iEdge], (iState == 1)? "+":"-", gF_Modifier[client]);
1386 FormatEx(sInfo, 8, "%d;%d", iEdge, iState);
1387 hMenu.AddItem(sInfo, sDisplay);
1388 }
1389 }
1390
1391 hMenu.DisplayAt(client, page, MENU_TIME_FOREVER);
1392}
1393
1394public int ZoneEdge_Handler(Menu menu, MenuAction action, int param1, int param2)
1395{
1396 if(action == MenuAction_Select)
1397 {
1398 char[] sInfo = new char[16];
1399 menu.GetItem(param2, sInfo, 16);
1400
1401 if(StrEqual(sInfo, "done"))
1402 {
1403 CreateEditMenu(param1);
1404 }
1405
1406 else if(StrEqual(sInfo, "cancel"))
1407 {
1408 Reset(param1);
1409 }
1410
1411 else
1412 {
1413 char sEdges[][] =
1414 {
1415 "Right",
1416 "Back",
1417 "Left",
1418 "Front"
1419 };
1420
1421 char[][] sExploded = new char[2][8];
1422 ExplodeString(sInfo, ";", sExploded, 2, 8);
1423
1424 int iEdge = StringToInt(sExploded[0]);
1425 bool bIncrease = view_as<bool>(StringToInt(sExploded[1]) == 1);
1426
1427 if(iEdge >= 2)
1428 {
1429 iEdge -= 2;
1430
1431 gV_Fix1[param1][iEdge] += (bIncrease? gF_Modifier[param1]:-gF_Modifier[param1]);
1432 }
1433
1434 else
1435 {
1436 gV_Fix2[param1][iEdge] += (bIncrease? gF_Modifier[param1]:-gF_Modifier[param1]);
1437 }
1438
1439 Shavit_PrintToChat(param1, "%s edge %s%s%s by %s%.01f degrees%s.", sEdges[iEdge], gS_ChatStrings[sMessageVariable2], (bIncrease)? "increased":"decreased", gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], gF_Modifier[param1], gS_ChatStrings[sMessageText]);
1440
1441 CreateWidthLengthMenu(param1, GetMenuSelectionPosition());
1442 }
1443 }
1444
1445 else if(action == MenuAction_End)
1446 {
1447 delete menu;
1448 }
1449}
1450
1451bool EmptyZone(float vZone[3])
1452{
1453 if(vZone[0] == 0.0 && vZone[1] == 0.0 && vZone[2] == 0.0)
1454 {
1455 return true;
1456 }
1457
1458 return false;
1459}
1460
1461void InsertZone(int client)
1462{
1463 MapZones type = gMZ_Type[client];
1464
1465 char[] sQuery = new char[512];
1466
1467 if(type == Zone_CustomSpawn)
1468 {
1469 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]);
1470 }
1471
1472 else if((EmptyZone(gV_MapZones[type][0]) && EmptyZone(gV_MapZones[type][1])) || type >= Zone_Freestyle) // insert
1473 {
1474 if(type != Zone_Teleport)
1475 {
1476 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]);
1477 }
1478
1479 else
1480 {
1481 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]);
1482 }
1483 }
1484
1485 else // update
1486 {
1487 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);
1488 }
1489
1490 gH_SQL.Query(SQL_InsertZone_Callback, sQuery, GetClientSerial(client));
1491}
1492
1493public void SQL_InsertZone_Callback(Database db, DBResultSet results, const char[] error, any data)
1494{
1495 if(results == null)
1496 {
1497 LogError("Timer (zone insert) SQL query failed. Reason: %s", error);
1498
1499 return;
1500 }
1501
1502 int client = GetClientFromSerial(data);
1503
1504 if(client == 0)
1505 {
1506 return;
1507 }
1508
1509 if(gMZ_Type[client] == Zone_CustomSpawn)
1510 {
1511 Shavit_PrintToChat(client, "Successfully placed custom spawn!.");
1512 }
1513
1514 UnloadZones((gMZ_Type[client] >= Zone_Freestyle && gMZ_Type[client] != Zone_CustomSpawn)? 0:view_as<int>(gMZ_Type[client]));
1515 RefreshZones();
1516 Reset(client);
1517}
1518
1519public Action Timer_DrawEverything(Handle Timer, any data)
1520{
1521 for(int i = 0; i < MAX_ZONES; i++)
1522 {
1523 float vPoints[8][3];
1524
1525 if(i >= view_as<int>(Zone_Freestyle))
1526 {
1527 for(int j = 0; j < MULTIPLEZONES_LIMIT; j++)
1528 {
1529 if(gMZ_FreestyleTypes[j] >= Zone_Freestyle && gA_ZoneSettings[gMZ_FreestyleTypes[j]][bVisible] && !EmptyZone(gV_FreestyleZones[j][0]) && !EmptyZone(gV_FreestyleZones[j][1]))
1530 {
1531 vPoints[0] = gV_FreestyleZones[j][0];
1532 vPoints[7] = gV_FreestyleZones[j][1];
1533
1534 if(gEV_Type == Engine_CSS)
1535 {
1536 vPoints[0][2] += 2.0;
1537 vPoints[7][2] += 2.0;
1538 }
1539
1540 if(gI_ZoneStyle == 1)
1541 {
1542 vPoints[7][2] = vPoints[0][2];
1543 }
1544
1545 if(j == 0)
1546 {
1547 CreateZonePoints(vPoints, 0.0, gV_FreeStyleZonesFixes[j][0], gV_FreeStyleZonesFixes[j][1], -PLACEHOLDER, false, true);
1548 }
1549
1550 else
1551 {
1552 CreateZonePoints(vPoints, 0.0, gV_FreeStyleZonesFixes[j][0], gV_FreeStyleZonesFixes[j][1], -j, false, true);
1553 }
1554
1555 int iColors[4];
1556 iColors[0] = gA_ZoneSettings[gMZ_FreestyleTypes[j]][iRed];
1557 iColors[1] = gA_ZoneSettings[gMZ_FreestyleTypes[j]][iGreen];
1558 iColors[2] = gA_ZoneSettings[gMZ_FreestyleTypes[j]][iBlue];
1559 iColors[3] = gA_ZoneSettings[gMZ_FreestyleTypes[j]][iAlpha];
1560
1561 DrawZone(vPoints, gI_BeamSprite, gI_HaloSprite, iColors, gF_Interval + 0.2);
1562 }
1563 }
1564 }
1565
1566 else
1567 {
1568 if(!gA_ZoneSettings[i][bVisible] || (EmptyZone(gV_MapZones[i][0]) && EmptyZone(gV_MapZones[i][1])))
1569 {
1570 continue;
1571 }
1572
1573 vPoints[0] = gV_MapZones[i][0];
1574 vPoints[7] = gV_MapZones[i][1];
1575
1576 if(gEV_Type == Engine_CSS)
1577 {
1578 vPoints[0][2] += 2.0;
1579 vPoints[7][2] += 2.0;
1580 }
1581
1582 if(gI_ZoneStyle == 1)
1583 {
1584 vPoints[7][2] = vPoints[0][2];
1585 }
1586
1587 CreateZonePoints(vPoints, 0.0, gV_MapZonesFixes[i][0], gV_MapZonesFixes[i][1], i, false, true);
1588
1589 int iColors[4];
1590 iColors[0] = gA_ZoneSettings[i][iRed];
1591 iColors[1] = gA_ZoneSettings[i][iGreen];
1592 iColors[2] = gA_ZoneSettings[i][iBlue];
1593 iColors[3] = gA_ZoneSettings[i][iAlpha];
1594
1595 DrawZone(vPoints, gI_BeamSprite, gI_HaloSprite, iColors, gF_Interval + 0.2);
1596 }
1597 }
1598}
1599
1600public Action Timer_Draw(Handle Timer, any data)
1601{
1602 int client = GetClientFromSerial(data);
1603
1604 if(client == 0 || gI_MapStep[client] == 0)
1605 {
1606 Reset(client);
1607
1608 return Plugin_Stop;
1609 }
1610
1611 float vPlayerOrigin[3];
1612 GetClientAbsOrigin(client, vPlayerOrigin);
1613
1614 float vOrigin[3];
1615 vOrigin[0] = float(RoundToNearest(vPlayerOrigin[0] / gI_GridSnap[client]) * gI_GridSnap[client]);
1616 vOrigin[1] = float(RoundToNearest(vPlayerOrigin[1] / gI_GridSnap[client]) * gI_GridSnap[client]);
1617
1618 if(gI_MapStep[client] == 1 || (gV_Point2[client][0] == 0.0))
1619 {
1620 vOrigin[2] = (vPlayerOrigin[2] + 144.0);
1621 }
1622
1623 else
1624 {
1625 vOrigin = gV_Point2[client];
1626 }
1627
1628 if(!EmptyZone(gV_Point1[client]) || !EmptyZone(gV_Point2[client]))
1629 {
1630 float vPoints[8][3];
1631 vPoints[0] = gV_Point1[client];
1632 vPoints[7] = vOrigin;
1633
1634 if(gEV_Type == Engine_CSS)
1635 {
1636 vPoints[0][2] += 2.0;
1637 vPoints[7][2] += 2.0;
1638 }
1639
1640 CreateZonePoints(vPoints, gF_RotateAngle[client], gV_Fix1[client], gV_Fix2[client], PLACEHOLDER, false, true);
1641
1642 int iColors[4];
1643 iColors[0] = gA_ZoneSettings[gMZ_Type[client]][iRed];
1644 iColors[1] = gA_ZoneSettings[gMZ_Type[client]][iGreen];
1645 iColors[2] = gA_ZoneSettings[gMZ_Type[client]][iBlue];
1646 iColors[3] = 255;
1647
1648 DrawZone(vPoints, gI_BeamSprite, gI_HaloSprite, iColors, 0.1);
1649
1650 if(gMZ_Type[client] == Zone_Teleport && !EmptyZone(gV_Teleport[client]))
1651 {
1652 TE_SetupEnergySplash(gV_Teleport[client], NULL_VECTOR, false);
1653 TE_SendToAll(0.0);
1654 }
1655 }
1656
1657 if(gI_MapStep[client] != 3 && !EmptyZone(vOrigin))
1658 {
1659 vOrigin[2] -= 144.0;
1660
1661 TE_SetupBeamPoints(vPlayerOrigin, vOrigin, gI_BeamSprite, gI_HaloSprite, 0, 0, 0.1, 3.5, 3.5, 0, 0.0, {230, 83, 124, 175}, 0);
1662 TE_SendToAll(0.0);
1663 }
1664
1665 return Plugin_Continue;
1666}
1667
1668bool UsedFixes(float[2][2] fixes)
1669{
1670 for(int a = 0; a < 2; a++)
1671 {
1672 for(int b = 0; b < 2; b++)
1673 {
1674 if(fixes[a][b] > 0.0)
1675 {
1676 return true;
1677 }
1678 }
1679 }
1680
1681 return false;
1682}
1683
1684// by blacky https://forums.alliedmods.net/showthread.php?t=222822
1685// Some of those functions are by ofir753. Thanks <3
1686// I just remade it for SM 1.7, that's it.
1687/*
1688*
1689* @param client - client to check
1690* @param zone - zone to check (-PLACEHOLDER for freestyle 0, -zone for freestyle)
1691*
1692* returns true if a player is inside the given zone
1693* returns false if they aren't in it
1694*/
1695bool InsideZone(int client, int zone)
1696{
1697 float playerPos[3];
1698 GetEntPropVector(client, Prop_Send, "m_vecOrigin", playerPos);
1699
1700 playerPos[2] += 5.0;
1701
1702 float vPoints[8][3];
1703
1704 if(zone >= 0)
1705 {
1706 vPoints[0] = gV_MapZones[zone][0];
1707 vPoints[7] = gV_MapZones[zone][1];
1708
1709 if(UsedFixes(gV_MapZonesFixes[zone]))
1710 {
1711 // Getting the original zone points with the fixes
1712 CreateZonePoints(vPoints, 0.0, gV_MapZonesFixes[zone][0], gV_MapZonesFixes[zone][1], zone, true, false);
1713 }
1714
1715 if(gF_MinusConstSin[zone] != 0.0 || gF_MinusConstCos[zone] != 0.0)
1716 {
1717 // Rotating the player so the box and the player will be on the same axis
1718 PointConstRotate(gF_MinusConstSin[zone], gF_MinusConstCos[zone], vPoints[0], playerPos);
1719 }
1720 }
1721
1722 else
1723 {
1724 // Explanation above
1725 if(zone == -PLACEHOLDER)
1726 {
1727 vPoints[0] = gV_FreestyleZones[0][0];
1728 vPoints[7] = gV_FreestyleZones[0][1];
1729
1730 if(UsedFixes(gV_FreeStyleZonesFixes[0]))
1731 {
1732 CreateZonePoints(vPoints, 0.0, gV_FreeStyleZonesFixes[0][0], gV_FreeStyleZonesFixes[0][1], zone, true, false);
1733 }
1734
1735 if(gF_FreeStyleMinusConstSin[0] != 0.0 || gF_FreeStyleMinusConstCos[0] != 0.0)
1736 {
1737 PointConstRotate(gF_FreeStyleMinusConstSin[0], gF_FreeStyleMinusConstCos[0], vPoints[0], playerPos);
1738 }
1739 }
1740
1741 else
1742 {
1743 vPoints[0] = gV_FreestyleZones[-zone][0];
1744 vPoints[7] = gV_FreestyleZones[-zone][1];
1745
1746 if(UsedFixes(gV_FreeStyleZonesFixes[-zone]))
1747 {
1748 CreateZonePoints(vPoints, 0.0, gV_FreeStyleZonesFixes[-zone][0], gV_FreeStyleZonesFixes[-zone][1], zone, true, false);
1749 }
1750
1751 if(gF_FreeStyleMinusConstSin[-zone] != 0.0 || gF_FreeStyleMinusConstCos[-zone] != 0.0)
1752 {
1753 PointConstRotate(gF_FreeStyleMinusConstSin[-zone], gF_FreeStyleMinusConstCos[-zone], vPoints[0], playerPos);
1754 }
1755 }
1756 }
1757
1758 // Checking if player is inside the box after rotation
1759 for(int i = 0; i < 3; i++)
1760 {
1761 if(vPoints[0][i] >= playerPos[i] == vPoints[7][i] >= playerPos[i])
1762 {
1763 return false;
1764 }
1765 }
1766
1767 return true;
1768}
1769
1770// like InsideZone but for teleport zones
1771bool InsideTeleportZone(int client, int zone)
1772{
1773 float fPlayerPos[3];
1774 GetEntPropVector(client, Prop_Send, "m_vecOrigin", fPlayerPos);
1775
1776 fPlayerPos[2] += 5.0;
1777
1778 float vPoints[8][3];
1779 vPoints[0] = gV_FreestyleZones[zone][0];
1780 vPoints[7] = gV_FreestyleZones[zone][1];
1781
1782 if(UsedFixes(gV_FreeStyleZonesFixes[zone]))
1783 {
1784 CreateZonePoints(vPoints, 0.0, gV_FreeStyleZonesFixes[zone][0], gV_FreeStyleZonesFixes[zone][1], zone, true, false);
1785 }
1786
1787 if(gF_FreeStyleMinusConstSin[zone] != 0.0 || gF_FreeStyleMinusConstCos[zone] != 0.0)
1788 {
1789 PointConstRotate(gF_FreeStyleMinusConstSin[zone], gF_FreeStyleMinusConstCos[zone], vPoints[0], fPlayerPos);
1790 }
1791
1792 // Checking if player is inside the box after rotation
1793 for(int i = 0; i < 3; i++)
1794 {
1795 if(vPoints[0][i] >= fPlayerPos[i] == vPoints[7][i] >= fPlayerPos[i])
1796 {
1797 return false;
1798 }
1799 }
1800
1801 return true;
1802}
1803
1804/*
1805* Graphically draws a zone
1806* if client == 0, it draws it for all players in the game
1807* if client index is between 0 and MaxClients+1, it draws for the specified client
1808*/
1809void DrawZone(float array[8][3], int beamsprite, int halosprite, int color[4], float life)
1810{
1811 for(int i = 0, i2 = 3; i2 >= 0; i += i2--)
1812 {
1813 for(int j = 1; j <= 7; j += (j / 2) + 1)
1814 {
1815 if(j != 7 - i)
1816 {
1817 TE_SetupBeamPoints(array[i], array[j], beamsprite, halosprite, 0, 0, life, 5.0, 5.0, 0, 0.0, color, 0);
1818 TE_SendToAll(0.0);
1819 }
1820 }
1821 }
1822}
1823
1824// Rotating point around 2d axis
1825void PointRotate(float angle, float axis[3], float point[3])
1826{
1827 /*
1828 a - rotation degree as radians
1829 x - old X
1830 x' - new X
1831 y - old Y
1832 y' - new Y
1833
1834 Rotation Transformation formula:
1835 x' = x cos(a) - y sin(a)
1836 y' = y cos(a) + x sin(a)
1837 */
1838
1839 float transTmp[3];
1840 transTmp[0] = point[0];
1841 transTmp[1] = point[1];
1842
1843 // Moving point for axis = (0, 0)
1844 transTmp[0] -= axis[0];
1845 transTmp[1] -= axis[1];
1846
1847 float radian = DegToRad(angle);
1848 float rotTmp[3];
1849
1850 // Rotating point (0, 0) as axis
1851 rotTmp[0] = transTmp[0] * Cosine(radian) - transTmp[1] * Sine(radian);
1852 rotTmp[1] = transTmp[1] * Cosine(radian) + transTmp[0] * Sine(radian);
1853
1854 // Moving point back
1855 rotTmp[0] += axis[0];
1856 rotTmp[1] += axis[1];
1857
1858 point[0] = rotTmp[0];
1859 point[1] = rotTmp[1];
1860}
1861
1862// Rotating point around 2d axis with constant sin and cos
1863void PointConstRotate(float sin, float cos, float axis[3], float point[3])
1864{
1865 /*
1866 a - rotation degree as radians
1867 x - old X
1868 x' - new X
1869 y - old Y
1870 y' - new Y
1871
1872 Rotation Transformation formula:
1873 x' = x cos(a) - y sin(a)
1874 y' = y cos(a) + x sin(a)
1875 */
1876
1877 float transTmp[3];
1878 transTmp[0] = point[0];
1879 transTmp[1] = point[1];
1880
1881 // Moving point for axis = (0, 0)
1882 transTmp[0] -= axis[0];
1883 transTmp[1] -= axis[1];
1884
1885 float rotTmp[3];
1886 // Rotating point (0, 0) as axis
1887 rotTmp[0] = transTmp[0] * cos - transTmp[1] * sin;
1888 rotTmp[1] = transTmp[1] * cos + transTmp[0] * sin;
1889
1890 // Moving point back
1891 rotTmp[0] += axis[0];
1892 rotTmp[1] += axis[1];
1893
1894 point[0] = rotTmp[0];
1895 point[1] = rotTmp[1];
1896}
1897
1898// Translate 2D Point
1899void PointTranslate(float point[3], float t[2])
1900{
1901 point[0] += t[0];
1902 point[1] += t[1];
1903}
1904
1905/*
1906* Generates 8 points of a zone given just 2 of its points
1907* angle - rotated angle for not constant zone (preview zone)
1908* fix1 - edge fixes
1909* fix2 - edge fixes
1910* zone - PLACEHOLDER for not constant zone, -PLACEHOLDER for index 0 freestyle zone, zone id (- for free style zone)
1911* norotate - don't rotate zone points
1912* all - calculate all 8 zone points
1913*/
1914void CreateZonePoints(float point[8][3], float angle, float fix1[2], float fix2[2], int zone, bool norotate, bool all)
1915{
1916 if(all)
1917 {
1918 for(int i = 1; i < 7; i++)
1919 {
1920 for(int j = 0; j < 3; j++)
1921 {
1922 point[i][j] = point[((i >> (2-j)) & 1) * 7][j];
1923 }
1924 }
1925 }
1926
1927 if(fix1[0] != 0.0 || fix2[0] != 0.0 || fix1[1] != 0.0 || fix2[1] != 0.0)
1928 {
1929 TranslateZone(point, fix1, fix2);
1930 }
1931
1932 if(zone == PLACEHOLDER)
1933 {
1934 for(int i = 1; i < 8; i++)
1935 {
1936 if(zone == PLACEHOLDER)
1937 {
1938 PointRotate(angle, point[0], point[i]);
1939 }
1940 }
1941 }
1942
1943 else if(!norotate)
1944 {
1945 if(zone >= 0 && zone != -PLACEHOLDER)
1946 {
1947 RotateZone(point, gF_ConstSin[zone], gF_ConstCos[zone]);
1948 }
1949
1950 else
1951 {
1952 if(zone == -PLACEHOLDER)
1953 {
1954 RotateZone(point, gF_FreeStyleConstSin[0], gF_FreeStyleConstCos[0]);
1955 }
1956
1957 else
1958 {
1959 RotateZone(point, gF_FreeStyleConstSin[-zone], gF_FreeStyleConstCos[-zone]);
1960 }
1961 }
1962 }
1963}
1964
1965// Translating Zone
1966void TranslateZone(float point[8][3], float fix1[2], float fix2[2])
1967{
1968 float fix[2];
1969 // X Translate
1970 fix[1] = 0.0;
1971 fix[0] = fix1[0];
1972
1973 PointTranslate(point[0], fix);
1974 PointTranslate(point[1], fix);
1975 PointTranslate(point[2], fix);
1976 PointTranslate(point[3], fix);
1977
1978 fix[0] = fix2[0];
1979 PointTranslate(point[4], fix);
1980 PointTranslate(point[5], fix);
1981 PointTranslate(point[6], fix);
1982 PointTranslate(point[7], fix);
1983
1984 // Y Translate
1985 fix[0] = 0.0;
1986 fix[1] = fix1[1];
1987
1988 PointTranslate(point[0], fix);
1989 PointTranslate(point[1], fix);
1990 PointTranslate(point[4], fix);
1991 PointTranslate(point[5], fix);
1992
1993 fix[1] = fix2[1];
1994
1995 PointTranslate(point[2], fix);
1996 PointTranslate(point[3], fix);
1997 PointTranslate(point[6], fix);
1998 PointTranslate(point[7], fix);
1999}
2000
2001//Rotating Zone by constant sin and cos
2002void RotateZone(float point[8][3], float sin, float cos)
2003{
2004 for(int i = 1; i < 8; i++)
2005 {
2006 PointConstRotate(sin, cos, point[0], point[i]);
2007 }
2008}
2009
2010// thanks a lot for those stuff, I couldn't do it without you blacky!
2011void SQL_SetPrefix()
2012{
2013 char[] sFile = new char[PLATFORM_MAX_PATH];
2014 BuildPath(Path_SM, sFile, PLATFORM_MAX_PATH, "configs/shavit-prefix.txt");
2015
2016 File fFile = OpenFile(sFile, "r");
2017
2018 if(fFile == null)
2019 {
2020 SetFailState("Cannot open \"configs/shavit-prefix.txt\". Make sure this file exists and that the server has read permissions to it.");
2021 }
2022
2023 else
2024 {
2025 char[] sLine = new char[PLATFORM_MAX_PATH * 2];
2026
2027 while(fFile.ReadLine(sLine, PLATFORM_MAX_PATH * 2))
2028 {
2029 TrimString(sLine);
2030 strcopy(gS_MySQLPrefix, 32, sLine);
2031
2032 break;
2033 }
2034 }
2035
2036 delete fFile;
2037}
2038
2039void SQL_DBConnect()
2040{
2041 if(gH_SQL != null)
2042 {
2043 char[] sDriver = new char[8];
2044 gH_SQL.Driver.GetIdentifier(sDriver, 8);
2045 gB_MySQL = StrEqual(sDriver, "mysql", false);
2046
2047 char[] sQuery = new char[1024];
2048 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);
2049
2050 gH_SQL.Query(SQL_CreateTable_Callback, sQuery);
2051 }
2052}
2053
2054public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)
2055{
2056 if(results == null)
2057 {
2058 LogError("Timer (zones module) error! Map zones' table creation failed. Reason: %s", error);
2059
2060 return;
2061 }
2062
2063 char[] sQuery = new char[64];
2064 FormatEx(sQuery, 64, "SELECT rot_ang FROM %smapzones LIMIT 1;", gS_MySQLPrefix);
2065 gH_SQL.Query(SQL_TableMigration1_Callback, sQuery);
2066
2067 FormatEx(sQuery, 64, "SELECT destination_x FROM %smapzones LIMIT 1;", gS_MySQLPrefix);
2068 gH_SQL.Query(SQL_TableMigration2_Callback, sQuery);
2069}
2070
2071public void SQL_TableMigration1_Callback(Database db, DBResultSet results, const char[] error, any data)
2072{
2073 if(results == null)
2074 {
2075 char[] sQuery = new char[256];
2076
2077 if(gB_MySQL)
2078 {
2079 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);
2080 gH_SQL.Query(SQL_AlterTable1_Callback, sQuery);
2081 }
2082
2083 else
2084 {
2085 FormatEx(sQuery, 256, "ALTER TABLE `%smapzones` ADD COLUMN `rot_ang` FLOAT NOT NULL default 0;", gS_MySQLPrefix);
2086 gH_SQL.Query(SQL_AlterTable1_Callback, sQuery);
2087
2088 for(int i = 1; i <= 2; i++)
2089 {
2090 FormatEx(sQuery, 256, "ALTER TABLE `%smapzones` ADD COLUMN `fix%d_x` FLOAT NOT NULL default 0;", gS_MySQLPrefix, i);
2091 gH_SQL.Query(SQL_AlterTable1_Callback, sQuery);
2092
2093 FormatEx(sQuery, 256, "ALTER TABLE `%smapzones` ADD COLUMN `fix%d_y` FLOAT NOT NULL default 0;", gS_MySQLPrefix, i);
2094 gH_SQL.Query(SQL_AlterTable1_Callback, sQuery);
2095 }
2096 }
2097 }
2098}
2099
2100public void SQL_AlterTable1_Callback(Database db, DBResultSet results, const char[] error, any data)
2101{
2102 if(results == null)
2103 {
2104 LogError("Timer (zones module) error! Map zones' table migration (1) failed. Reason: %s", error);
2105
2106 return;
2107 }
2108}
2109
2110public void SQL_TableMigration2_Callback(Database db, DBResultSet results, const char[] error, any data)
2111{
2112 if(results == null)
2113 {
2114 char[] sQuery = new char[256];
2115 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);
2116
2117 gH_SQL.Query(SQL_AlterTable2_Callback, sQuery);
2118 }
2119}
2120
2121public void SQL_AlterTable2_Callback(Database db, DBResultSet results, const char[] error, any data)
2122{
2123 if(results == null)
2124 {
2125 LogError("Timer (zones module) error! Map zones' table migration (2) failed. Reason: %s", error);
2126
2127 return;
2128 }
2129
2130 // we have a database, time to load zones
2131 RefreshZones();
2132}
2133
2134public void Shavit_OnRestart(int client)
2135{
2136 if(gB_TeleportToStart && !IsFakeClient(client) && !EmptyZone(gV_MapZones[Zone_Start][0]) && !EmptyZone(gV_MapZones[Zone_Start][1]))
2137 {
2138 Shavit_StartTimer(client);
2139
2140 if(!EmptyZone(gF_CustomSpawn))
2141 {
2142 TeleportEntity(client, gF_CustomSpawn, NULL_VECTOR, view_as<float>({0.0, 0.0, 0.0}));
2143 }
2144
2145 else
2146 {
2147 float vCenter[3];
2148 MakeVectorFromPoints(gV_MapZones[0][0], gV_MapZones[0][1], vCenter);
2149 vCenter[0] /= 2.0;
2150 vCenter[1] /= 2.0;
2151
2152 AddVectors(gV_MapZones[0][0], vCenter, vCenter);
2153 vCenter[2] = gV_MapZones[0][0][2];
2154
2155 TeleportEntity(client, vCenter, NULL_VECTOR, view_as<float>({0.0, 0.0, 0.0}));
2156 }
2157 }
2158}
2159
2160public void Shavit_OnEnd(int client)
2161{
2162 if(gB_TeleportToStart && !IsFakeClient(client) && !EmptyZone(gV_MapZones[Zone_End][0]) && !EmptyZone(gV_MapZones[Zone_End][1]))
2163 {
2164 float vCenter[3];
2165 MakeVectorFromPoints(gV_MapZones[1][0], gV_MapZones[1][1], vCenter);
2166 vCenter[0] /= 2.0;
2167 vCenter[1] /= 2.0;
2168
2169 AddVectors(gV_MapZones[1][0], vCenter, vCenter);
2170 vCenter[2] = gV_MapZones[1][0][2];
2171
2172 TeleportEntity(client, vCenter, NULL_VECTOR, view_as<float>({0.0, 0.0, 0.0}));
2173 }
2174}
2175
2176public void Shavit_OnDatabaseLoaded(Database db)
2177{
2178 gH_SQL = db;
2179}