· 6 years ago · Aug 20, 2019, 07:32 PM
1#pragma semicolon 1
2
3//////////////////////////////
4// DEFINITIONS //
5//////////////////////////////
6
7#define PLUGIN_NAME "Store - The Resurrection"
8#define PLUGIN_AUTHOR "Zephyrus"
9#define PLUGIN_DESCRIPTION "A completely new Store system."
10#define PLUGIN_VERSION "1.0"
11#define PLUGIN_URL ""
12
13#define SERVER_LOCK_IP ""
14
15//////////////////////////////
16// INCLUDES //
17//////////////////////////////
18
19#include <sourcemod>
20#include <sdktools>
21
22#undef REQUIRE_EXTENSIONS
23#undef REQUIRE_PLUGIN
24#include <store>
25#include <zephstocks>
26#include <donate>
27#include <adminmenu>
28#if !defined STANDALONE_BUILD
29#include <sdkhooks>
30#include <cstrike>
31#include <tf2>
32#include <tf2_stocks>
33#include <tf2items>
34#include <gifts>
35#include <scp>
36#include <thirdperson>
37#include <saxtonhale>
38#endif
39
40//////////////////////////////
41// ENUMS //
42//////////////////////////////
43
44enum Client
45{
46 iId,
47 iUserId,
48 String:szAuthId[32],
49 String:szName[64],
50 String:szNameEscaped[128],
51 iCredits,
52 iOriginalCredits,
53 iDateOfJoin,
54 iDateOfLastJoin,
55 iItems,
56 aEquipment[STORE_MAX_HANDLERS*STORE_MAX_SLOTS],
57 aEquipmentSynced[STORE_MAX_HANDLERS*STORE_MAX_SLOTS],
58 Handle:hCreditTimer,
59 bool:bLoaded
60}
61
62enum Menu_Handler
63{
64 String:szIdentifier[64],
65 Handle:hPlugin,
66 Function:fnMenu,
67 Function:fnHandler
68}
69
70//////////////////////////////////
71// GLOBAL VARIABLES //
72//////////////////////////////////
73
74new GAME_CSS = false;
75new GAME_CSGO = false;
76new GAME_DOD = false;
77new GAME_TF2 = false;
78new GAME_L4D = false;
79new GAME_L4D2 = false;
80
81new String:g_szGameDir[64];
82
83new Handle:g_hDatabase = INVALID_HANDLE;
84new Handle:g_hAdminMenu = INVALID_HANDLE;
85new Handle:g_hLogFile = INVALID_HANDLE;
86
87new g_cvarDatabaseEntry = -1;
88new g_cvarDatabaseRetries = -1;
89new g_cvarDatabaseTimeout = -1;
90new g_cvarItemSource = -1;
91new g_cvarItemsTable = -1;
92new g_cvarStartCredits = -1;
93new g_cvarCreditTimer = -1;
94new g_cvarCreditAmountActive = -1;
95new g_cvarCreditAmountInactive = -1;
96new g_cvarCreditAmountKill = -1;
97new g_cvarRequiredFlag = -1;
98new g_cvarVIPFlag = -1;
99new g_cvarSellEnabled = -1;
100new g_cvarGiftEnabled = -1;
101new g_cvarCreditGiftEnabled = -1;
102new g_cvarSellRatio = -1;
103new g_cvarConfirmation = -1;
104new g_cvarAdminFlag = -1;
105new g_cvarSaveOnDeath = -1;
106new g_cvarCreditMessages = -1;
107new g_cvarShowVIP = -1;
108new g_cvarLogging = -1;
109new g_cvarSilent = -1;
110
111new g_eItems[STORE_MAX_ITEMS][Store_Item];
112new g_eClients[MAXPLAYERS+1][Client];
113new g_eClientItems[MAXPLAYERS+1][STORE_MAX_ITEMS][Client_Item];
114new g_eTypeHandlers[STORE_MAX_HANDLERS][Type_Handler];
115new g_eMenuHandlers[STORE_MAX_HANDLERS][Menu_Handler];
116new g_ePlans[STORE_MAX_ITEMS][STORE_MAX_PLANS][Item_Plan];
117
118new g_iItems = 0;
119new g_iTypeHandlers = 0;
120new g_iMenuHandlers = 0;
121new g_iMenuBack[MAXPLAYERS+1];
122new g_iLastSelection[MAXPLAYERS+1];
123new g_iSelectedItem[MAXPLAYERS+1];
124new g_iSelectedPlan[MAXPLAYERS+1];
125new g_iMenuClient[MAXPLAYERS+1];
126new g_iMenuNum[MAXPLAYERS+1];
127new g_iSpam[MAXPLAYERS+1];
128new g_iPackageHandler = -1;
129new g_iDatabaseRetries = 0;
130
131new bool:g_bInvMode[MAXPLAYERS+1];
132new bool:g_bMySQL = false;
133
134new String:g_szClientData[MAXPLAYERS+1][256];
135
136new TopMenuObject:g_eStoreAdmin;
137
138new PublicChatTrigger = 0;
139new SilentChatTrigger = 0;
140
141//////////////////////////////
142// MODULES //
143//////////////////////////////
144
145#if !defined STANDALONE_BUILD
146#include "store/hats.sp"
147#include "store/tracers.sp"
148#include "store/playerskins.sp"
149#include "store/trails.sp"
150#include "store/grenskins.sp"
151#include "store/grentrails.sp"
152#include "store/weaponcolors.sp"
153#include "store/tfsupport.sp"
154#include "store/paintball.sp"
155#include "store/betting.sp"
156#include "store/watergun.sp"
157#include "store/gifts.sp"
158#include "store/scpsupport.sp"
159#include "store/weapons.sp"
160#include "store/help.sp"
161#include "store/jetpack.sp"
162#include "store/bunnyhop.sp"
163#include "store/lasersight.sp"
164#include "store/health.sp"
165#include "store/speed.sp"
166#include "store/gravity.sp"
167#include "store/invisibility.sp"
168#include "store/commands.sp"
169#include "store/doors.sp"
170#include "store/knife.sp"
171#include "store/zrclass.sp"
172#include "store/jihad.sp"
173#include "store/godmode.sp"
174#include "store/sounds.sp"
175#include "store/attributes.sp"
176#include "store/respawn.sp"
177#include "store/pets.sp"
178#include "store/sprays.sp"
179#include "store/weaponskins.sp"
180#include "store/admin.sp"
181#endif
182
183//////////////////////////////////
184// PLUGIN DEFINITION //
185//////////////////////////////////
186
187public Plugin:myinfo =
188{
189 name = PLUGIN_NAME,
190 author = PLUGIN_AUTHOR,
191 description = PLUGIN_DESCRIPTION,
192 version = PLUGIN_VERSION,
193 url = PLUGIN_URL
194};
195
196//////////////////////////////
197// PLUGIN FORWARDS //
198//////////////////////////////
199
200public OnPluginStart()
201{
202 RegPluginLibrary("store_zephyrus");
203
204 if(strcmp(SERVER_LOCK_IP, "") != 0)
205 {
206 new String:m_szIP[64];
207 new m_unIP = GetConVarInt(FindConVar("hostip"));
208 Format(STRING(m_szIP), "%d.%d.%d.%d:%d", (m_unIP >> 24) & 0x000000FF, (m_unIP >> 16) & 0x000000FF, (m_unIP >> 8) & 0x000000FF, m_unIP & 0x000000FF, GetConVarInt(FindConVar("hostport")));
209
210 if(strcmp(SERVER_LOCK_IP, m_szIP)!=0)
211 SetFailState("GTFO");
212 }
213
214 // Identify the game
215 GetGameFolderName(STRING(g_szGameDir));
216
217 if(strcmp(g_szGameDir, "cstrike")==0)
218 GAME_CSS = true;
219 else if(strcmp(g_szGameDir, "csgo")==0)
220 GAME_CSGO = true;
221 else if(strcmp(g_szGameDir, "dod")==0)
222 GAME_DOD = true;
223 else if(strcmp(g_szGameDir, "tf")==0)
224 GAME_TF2 = true;
225 else if(strcmp(g_szGameDir, "l4d")==0)
226 GAME_L4D = true;
227 else if(strcmp(g_szGameDir, "l4d2")==0)
228 GAME_L4D2 = true;
229 else
230 {
231 SetFailState("This game is not be supported. Please contact the author for support.");
232 }
233
234 // Supress warnings about unused variables.....
235 if(GAME_DOD || GAME_L4D || GAME_L4D2 || g_bL4D || g_bL4D2 || g_bND) {}
236
237 // Setting default values
238 for(new i=1;i<=MaxClients;++i)
239 {
240 g_eClients[i][iCredits] = -1;
241 g_eClients[i][iOriginalCredits] = 0;
242 g_eClients[i][iItems] = -1;
243 g_eClients[i][hCreditTimer] = INVALID_HANDLE;
244 }
245
246 // Register ConVars
247 g_cvarDatabaseEntry = RegisterConVar("sm_store_database", "storage-local", "Name of the default store database entry", TYPE_STRING);
248 g_cvarDatabaseRetries = RegisterConVar("sm_store_database_retries", "4", "Number of retries if the connection fails to estabilish with timeout", TYPE_INT);
249 g_cvarDatabaseTimeout = RegisterConVar("sm_store_database_timeout", "10", "Timeout in seconds to wait for database connection before retry", TYPE_FLOAT);
250 g_cvarItemSource = RegisterConVar("sm_store_item_source", "flatfile", "Source of the item list, can be set to flatfile and database, sm_store_items_table must be set if database is chosen (THIS IS HIGHLY EXPERIMENTAL AND MAY NOT WORK YET)", TYPE_STRING);
251 g_cvarItemsTable = RegisterConVar("sm_store_items_table", "store_menu", "Name of the items table", TYPE_STRING);
252 g_cvarStartCredits = RegisterConVar("sm_store_startcredits", "0", "Number of credits a client starts with", TYPE_INT);
253 g_cvarCreditTimer = RegisterConVar("sm_store_credit_interval", "60", "Interval in seconds to give out credits", TYPE_FLOAT, ConVar_CreditTimer);
254 g_cvarCreditAmountActive = RegisterConVar("sm_store_credit_amount_active", "1", "Number of credits to give out for active players", TYPE_INT, ConVar_CreditTimer);
255 g_cvarCreditAmountInactive = RegisterConVar("sm_store_credit_amount_inactive", "1", "Number of credits to give out for inactive players (spectators)", TYPE_INT, ConVar_CreditTimer);
256 g_cvarCreditAmountKill = RegisterConVar("sm_store_credit_amount_kill", "1", "Number of credits to give out for killing a player", TYPE_INT, ConVar_CreditTimer);
257 g_cvarRequiredFlag = RegisterConVar("sm_store_required_flag", "", "Flag to access the !store menu", TYPE_FLAG);
258 g_cvarVIPFlag = RegisterConVar("sm_store_vip_flag", "", "Flag for VIP access (all items unlocked). Leave blank to disable.", TYPE_FLAG);
259 g_cvarAdminFlag = RegisterConVar("sm_store_admin_flag", "z", "Flag for admin access. Leave blank to disable.", TYPE_FLAG);
260 g_cvarSellEnabled = RegisterConVar("sm_store_enable_selling", "1", "Enable/disable selling of already bought items.", TYPE_INT);
261 g_cvarGiftEnabled = RegisterConVar("sm_store_enable_gifting", "1", "Enable/disable gifting of already bought items. [1=everyone, 2=admins only]", TYPE_INT);
262 g_cvarCreditGiftEnabled = RegisterConVar("sm_store_enable_credit_gifting", "1", "Enable/disable gifting of credits.", TYPE_INT);
263 g_cvarSellRatio = RegisterConVar("sm_store_sell_ratio", "0.60", "Ratio of the original price to get for selling an item.", TYPE_FLOAT);
264 g_cvarConfirmation = RegisterConVar("sm_store_confirmation_windows", "1", "Enable/disable confirmation windows.", TYPE_INT);
265 g_cvarSaveOnDeath = RegisterConVar("sm_store_save_on_death", "0", "Enable/disable client data saving on client death.", TYPE_INT);
266 g_cvarCreditMessages = RegisterConVar("sm_store_credit_messages", "1", "Enable/disable messages when a player earns credits.", TYPE_INT);
267 g_cvarChatTag = RegisterConVar("sm_store_chat_tag", "[Store] ", "The chat tag to use for displaying messages.", TYPE_STRING);
268 g_cvarShowVIP = RegisterConVar("sm_store_show_vip_items", "0", "If you enable this VIP items will be shown in grey.", TYPE_INT);
269 g_cvarLogging = RegisterConVar("sm_store_logging", "0", "Set this to 1 for file logging and 2 to SQL logging (only MySQL). Leaving on 0 means disabled.", TYPE_INT);
270 g_cvarSilent = RegisterConVar("sm_store_silent_givecredits", "0", "Controls the give credits message visibility. 0 = public 1 = private 2 = no message", TYPE_INT);
271
272 // Register Commands
273 RegConsoleCmd("sm_sklepik", Command_Store);
274 RegConsoleCmd("sm_shop", Command_Store);
275 RegConsoleCmd("sm_inv", Command_Inventory);
276 RegConsoleCmd("sm_inventory", Command_Inventory);
277 RegConsoleCmd("sm_gift", Command_Gift);
278 RegConsoleCmd("sm_dajkredyty", Command_GiveCredits);
279 RegConsoleCmd("sm_resetplayer", Command_ResetPlayer);
280 RegConsoleCmd("sm_kredyty", Command_Credits);
281
282 // Hook events
283 HookEvent("player_death", Event_PlayerDeath);
284 HookEvent("player_spawn", Event_PlayerSpawn);
285
286 // Load the translations file
287 LoadTranslations("store.phrases");
288
289 // Initiaze the fake package handler
290 g_iPackageHandler = Store_RegisterHandler("package", "", INVALID_FUNCTION, INVALID_FUNCTION, INVALID_FUNCTION, INVALID_FUNCTION, INVALID_FUNCTION);
291
292 // Initialize the modules
293#if !defined STANDALONE_BUILD
294 Hats_OnPluginStart();
295 Tracers_OnPluginStart();
296 Trails_OnPluginStart();
297 PlayerSkins_OnPluginStart();
298 GrenadeSkins_OnPluginStart();
299 GrenadeTrails_OnPluginStart();
300 WeaponColors_OnPluginStart();
301 TFSupport_OnPluginStart();
302 Paintball_OnPluginStart();
303 Watergun_OnPluginStart();
304 Betting_OnPluginStart();
305 Gifts_OnPluginStart();
306 SCPSupport_OnPluginStart();
307 Weapons_OnPluginStart();
308 Help_OnPluginStart();
309 Jetpack_OnPluginStart();
310 Bunnyhop_OnPluginStart();
311 LaserSight_OnPluginStart();
312 Health_OnPluginStart();
313 Gravity_OnPluginStart();
314 Speed_OnPluginStart();
315 Invisibility_OnPluginStart();
316 Commands_OnPluginStart();
317 Doors_OnPluginStart();
318 ZRClass_OnPluginStart();
319 Jihad_OnPluginStart();
320 Knives_OnPluginStart();
321 Godmode_OnPluginStart();
322 Sounds_OnPluginStart();
323 Attributes_OnPluginStart();
324 Respawn_OnPluginStart();
325 Pets_OnPluginStart();
326 Sprays_OnPluginStart();
327 WeaponSkins_OnPluginStart();
328 AdminGroup_OnPluginStart();
329#endif
330
331 new Handle:topmenu;
332 if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != INVALID_HANDLE))
333 OnAdminMenuReady(topmenu);
334
335 // Load the config file
336 Store_ReloadConfig();
337
338 // After every module was loaded we are ready to generate the cfg
339 AutoExecConfig();
340
341 // Read core.cfg for chat triggers
342 ReadCoreCFG();
343
344 // Add a say command listener for shortcuts
345 AddCommandListener(Command_Say, "say");
346
347 LoopIngamePlayers(client)
348 {
349 OnClientConnected(client);
350 OnClientPostAdminCheck(client);
351 OnClientPutInServer(client);
352 }
353
354}
355
356public OnAllPluginsLoaded()
357{
358 CreateTimer(1.0, LoadConfig);
359
360 if(GetFeatureStatus(FeatureType_Native, "Donate_RegisterHandler")==FeatureStatus_Available)
361 Donate_RegisterHandler("Store", Store_OnPaymentReceived);
362}
363
364public Action:LoadConfig(Handle:timer, any:data)
365{
366 // Load the config file
367 Store_ReloadConfig();
368}
369
370public OnPluginEnd()
371{
372 LoopIngamePlayers(i)
373 if(g_eClients[i][bLoaded])
374 OnClientDisconnect(i);
375
376 if(GetFeatureStatus(FeatureType_Native, "Donate_RemoveHandler")==FeatureStatus_Available)
377 Donate_RemoveHandler("Store");
378}
379
380public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
381{
382 CreateNative("Store_RegisterHandler", Native_RegisterHandler);
383 CreateNative("Store_RegisterMenuHandler", Native_RegisterMenuHandler);
384 CreateNative("Store_SetDataIndex", Native_SetDataIndex);
385 CreateNative("Store_GetDataIndex", Native_GetDataIndex);
386 CreateNative("Store_GetEquippedItem", Native_GetEquippedItem);
387 CreateNative("Store_IsClientLoaded", Native_IsClientLoaded);
388 CreateNative("Store_DisplayPreviousMenu", Native_DisplayPreviousMenu);
389 CreateNative("Store_SetClientMenu", Native_SetClientMenu);
390 CreateNative("Store_GetClientCredits", Native_GetClientCredits);
391 CreateNative("Store_SetClientCredits", Native_SetClientCredits);
392 CreateNative("Store_IsClientVIP", Native_IsClientVIP);
393 CreateNative("Store_IsItemInBoughtPackage", Native_IsItemInBoughtPackage);
394 CreateNative("Store_DisplayConfirmMenu", Native_DisplayConfirmMenu);
395 CreateNative("Store_ShouldConfirm", Native_ShouldConfirm);
396 CreateNative("Store_GetItem", Native_GetItem);
397 CreateNative("Store_GetHandler", Native_GetHandler);
398 CreateNative("Store_GiveItem", Native_GiveItem);
399 CreateNative("Store_RemoveItem", Native_RemoveItem);
400 CreateNative("Store_GetClientItem", Native_GetClientItem);
401 CreateNative("Store_GetClientTarget", Native_GetClientTarget);
402 CreateNative("Store_GiveClientItem", Native_GiveClientItem);
403 CreateNative("Store_HasClientItem", Native_HasClientItem);
404 CreateNative("Store_IterateEquippedItems", Native_IterateEquippedItems);
405
406#if !defined STANDALONE_BUILD
407 MarkNativeAsOptional("ZR_IsClientZombie");
408 MarkNativeAsOptional("ZR_IsClientHuman");
409 MarkNativeAsOptional("ZR_GetClassByName");
410 MarkNativeAsOptional("ZR_SelectClientClass");
411 MarkNativeAsOptional("HideTrails_ShouldHide");
412#endif
413 return APLRes_Success;
414}
415
416#if !defined STANDALONE_BUILD
417public OnLibraryAdded(const String:name[])
418{
419 PlayerSkins_OnLibraryAdded(name);
420 ZRClass_OnLibraryAdded(name);
421}
422#endif
423
424//////////////////////////////
425// ADMIN MENUS //
426//////////////////////////////
427
428public OnAdminMenuReady(Handle:topmenu)
429{
430 if (topmenu == g_hAdminMenu)
431 return;
432 g_hAdminMenu = topmenu;
433
434 g_eStoreAdmin = AddToTopMenu(g_hAdminMenu, "Store Admin", TopMenuObject_Category, CategoryHandler_StoreAdmin, INVALID_TOPMENUOBJECT);
435 AddToTopMenu(g_hAdminMenu, "sm_store_resetdb", TopMenuObject_Item, AdminMenu_ResetDb, g_eStoreAdmin, "sm_store_resetdb", g_eCvars[g_cvarAdminFlag][aCache]);
436 AddToTopMenu(g_hAdminMenu, "sm_store_resetplayer", TopMenuObject_Item, AdminMenu_ResetPlayer, g_eStoreAdmin, "sm_store_resetplayer", g_eCvars[g_cvarAdminFlag][aCache]);
437 AddToTopMenu(g_hAdminMenu, "sm_store_givecredits", TopMenuObject_Item, AdminMenu_GiveCredits, g_eStoreAdmin, "sm_store_givecredits", g_eCvars[g_cvarAdminFlag][aCache]);
438 AddToTopMenu(g_hAdminMenu, "sm_store_viewinventory", TopMenuObject_Item, AdminMenu_ViewInventory, g_eStoreAdmin, "sm_store_viewinventory", g_eCvars[g_cvarAdminFlag][aCache]);
439}
440
441public CategoryHandler_StoreAdmin(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
442{
443 if (action == TopMenuAction_DisplayTitle || action == TopMenuAction_DisplayOption)
444 Format(buffer, maxlength, "Store Admin");
445}
446
447//////////////////////////////
448// Reset database //
449//////////////////////////////
450
451public AdminMenu_ResetDb(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, client, String:buffer[], maxlength)
452{
453 if (action == TopMenuAction_DisplayOption)
454 {
455 Format(buffer, maxlength, "Reset database");
456 }
457 else if (action == TopMenuAction_SelectOption)
458 {
459 g_iMenuNum[client] = 0;
460 Store_DisplayConfirmMenu(client, "Do you want to reset database?\nServer will be restarted!", FakeMenuHandler_ResetDatabase, 0);
461 }
462}
463
464public FakeMenuHandler_ResetDatabase(Handle:menu, MenuAction:action, client, param2)
465{
466 SQL_TVoid(g_hDatabase, "DROP TABLE store_players");
467 SQL_TVoid(g_hDatabase, "DROP TABLE store_items");
468 SQL_TVoid(g_hDatabase, "DROP TABLE store_equipment");
469 ServerCommand("_restart");
470}
471
472//////////////////////////////
473// Reset player //
474//////////////////////////////
475
476public AdminMenu_ResetPlayer(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, client, String:buffer[], maxlength)
477{
478 if (action == TopMenuAction_DisplayOption)
479 {
480 Format(buffer, maxlength, "Reset player");
481 }
482 else if (action == TopMenuAction_SelectOption)
483 {
484 g_iMenuNum[client] = 4;
485 new Handle:m_hMenu = CreateMenu(MenuHandler_ResetPlayer);
486 SetMenuTitle(m_hMenu, "Choose a player to reset");
487 SetMenuExitBackButton(m_hMenu, true);
488 LoopAuthorizedPlayers(i)
489 {
490 decl String:m_szName[64];
491 decl String:m_szAuthId[32];
492 GetClientName(i, STRING(m_szName));
493 GetLegacyAuthString(i, STRING(m_szAuthId));
494 AddMenuItem(m_hMenu, m_szAuthId, m_szName);
495 }
496 DisplayMenu(m_hMenu, client, 0);
497 }
498}
499
500public MenuHandler_ResetPlayer(Handle:menu, MenuAction:action, client, param2)
501{
502 if (action == MenuAction_End)
503 CloseHandle(menu);
504 else if (action == MenuAction_Select)
505 {
506 if(menu == INVALID_HANDLE)
507 FakeClientCommandEx(client, "sm_resetplayer \"%s\"", g_szClientData[client]);
508 else
509 {
510 decl style;
511 decl String:m_szName[64];
512 GetMenuItem(menu, param2, g_szClientData[client], sizeof(g_szClientData[]), style, STRING(m_szName));
513
514 decl String:m_szTitle[256];
515 Format(STRING(m_szTitle), "Do you want to reset %s?", m_szName);
516 Store_DisplayConfirmMenu(client, m_szTitle, MenuHandler_ResetPlayer, 0);
517 }
518 }
519 else if (action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
520 RedisplayAdminMenu(g_hAdminMenu, client);
521}
522
523//////////////////////////////
524// Give credits //
525//////////////////////////////
526
527public AdminMenu_GiveCredits(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, client, String:buffer[], maxlength)
528{
529 if (action == TopMenuAction_DisplayOption)
530 {
531 Format(buffer, maxlength, "Give credits");
532 }
533 else if (action == TopMenuAction_SelectOption)
534 {
535 g_iMenuNum[client] = 5;
536 new Handle:m_hMenu = CreateMenu(MenuHandler_GiveCredits);
537 SetMenuTitle(m_hMenu, "Choose a player to give credits to");
538 SetMenuExitBackButton(m_hMenu, true);
539 LoopAuthorizedPlayers(i)
540 {
541 decl String:m_szName[64];
542 decl String:m_szAuthId[32];
543 GetClientName(i, STRING(m_szName));
544 GetLegacyAuthString(i, STRING(m_szAuthId));
545 AddMenuItem(m_hMenu, m_szAuthId, m_szName);
546 }
547 DisplayMenu(m_hMenu, client, 0);
548 }
549}
550
551public MenuHandler_GiveCredits(Handle:menu, MenuAction:action, client, param2)
552{
553 if (action == MenuAction_End)
554 CloseHandle(menu);
555 else if (action == MenuAction_Select)
556 {
557 if(param2 != -1)
558 GetMenuItem(menu, param2, g_szClientData[client], sizeof(g_szClientData[]));
559 new Handle:m_hMenu = CreateMenu(MenuHandler_GiveCredits2);
560
561 new target = GetClientBySteamID(g_szClientData[client]);
562 if(target == 0)
563 {
564 AdminMenu_GiveCredits(g_hAdminMenu, TopMenuAction_SelectOption, g_eStoreAdmin, client, "", 0);
565 return;
566 }
567
568 SetMenuTitle(m_hMenu, "Choose the amount of credits\n%N - %d credits", target, g_eClients[target][iCredits]);
569 SetMenuExitBackButton(m_hMenu, true);
570 AddMenuItem(m_hMenu, "-1000", "-1000");
571 AddMenuItem(m_hMenu, "-100", "-100");
572 AddMenuItem(m_hMenu, "-10", "-10");
573 AddMenuItem(m_hMenu, "10", "10");
574 AddMenuItem(m_hMenu, "100", "100");
575 AddMenuItem(m_hMenu, "1000", "1000");
576 DisplayMenu(m_hMenu, client, 0);
577 }
578 else if (action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
579 RedisplayAdminMenu(g_hAdminMenu, client);
580}
581
582public MenuHandler_GiveCredits2(Handle:menu, MenuAction:action, client, param2)
583{
584 if (action == MenuAction_End)
585 CloseHandle(menu);
586 else if (action == MenuAction_Select)
587 {
588 decl String:m_szData[11];
589 GetMenuItem(menu, param2, STRING(m_szData));
590 FakeClientCommand(client, "sm_dajkredyty \"%s\" %s", g_szClientData[client], m_szData);
591 MenuHandler_GiveCredits(INVALID_HANDLE, MenuAction_Select, client, -1);
592 }
593 else if (action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
594 AdminMenu_GiveCredits(g_hAdminMenu, TopMenuAction_SelectOption, g_eStoreAdmin, client, "", 0);
595}
596
597//////////////////////////////
598// View inventory //
599//////////////////////////////
600
601public AdminMenu_ViewInventory(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, client, String:buffer[], maxlength)
602{
603 if (action == TopMenuAction_DisplayOption)
604 {
605 Format(buffer, maxlength, "View inventory");
606 }
607 else if (action == TopMenuAction_SelectOption)
608 {
609 g_iMenuNum[client] = 4;
610 new Handle:m_hMenu = CreateMenu(MenuHandler_ViewInventory);
611 SetMenuTitle(m_hMenu, "Choose a player");
612 SetMenuExitBackButton(m_hMenu, true);
613 LoopAuthorizedPlayers(i)
614 {
615 decl String:m_szName[64];
616 decl String:m_szAuthId[32];
617 GetClientName(i, STRING(m_szName));
618 GetLegacyAuthString(i, STRING(m_szAuthId));
619 AddMenuItem(m_hMenu, m_szAuthId, m_szName);
620 }
621 DisplayMenu(m_hMenu, client, 0);
622 }
623}
624
625public MenuHandler_ViewInventory(Handle:menu, MenuAction:action, client, param2)
626{
627 if (action == MenuAction_End)
628 CloseHandle(menu);
629 else if (action == MenuAction_Select)
630 {
631 GetMenuItem(menu, param2, g_szClientData[client], sizeof(g_szClientData[]));
632 new target = GetClientBySteamID(g_szClientData[client]);
633 if(target == 0)
634 {
635 AdminMenu_ViewInventory(g_hAdminMenu, TopMenuAction_SelectOption, g_eStoreAdmin, client, "", 0);
636 return;
637 }
638
639 g_bInvMode[client]=true;
640 g_iMenuClient[client]=target;
641 DisplayStoreMenu(client);
642 }
643 else if (action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
644 RedisplayAdminMenu(g_hAdminMenu, client);
645}
646
647//////////////////////////////////////
648// REST OF PLUGIN FORWARDS //
649//////////////////////////////////////
650
651public OnMapStart()
652{
653 for(new i=0;i<g_iTypeHandlers;++i)
654 {
655 if(g_eTypeHandlers[i][fnMapStart] != INVALID_FUNCTION)
656 {
657 Call_StartFunction(g_eTypeHandlers[i][hPlugin], g_eTypeHandlers[i][fnMapStart]);
658 Call_Finish();
659 }
660 }
661}
662
663public OnConfigsExecuted()
664{
665 Jetpack_OnConfigsExecuted();
666 Jihad_OnConfigsExecuted();
667
668 // Connect to the database
669 if(g_hDatabase == INVALID_HANDLE)
670 SQL_TConnect(SQLCallback_Connect, g_eCvars[g_cvarDatabaseEntry][sCache]);
671 if(g_eCvars[g_cvarDatabaseRetries][aCache] > 0)
672 CreateTimer(Float:g_eCvars[g_cvarDatabaseTimeout][aCache], Timer_DatabaseTimeout);
673
674 if(g_eCvars[g_cvarLogging][aCache] == 1)
675 if(g_hLogFile == INVALID_HANDLE)
676 {
677 new String:m_szPath[PLATFORM_MAX_PATH];
678 BuildPath(Path_SM, STRING(m_szPath), "logs/store.log.txt");
679 g_hLogFile = OpenFile(m_szPath, "w+");
680 }
681}
682
683#if !defined STANDALONE_BUILD
684public OnGameFrame()
685{
686 Trails_OnGameFrame();
687 TFWeapon_OnGameFrame();
688 TFHead_OnGameFrame();
689}
690#endif
691
692#if !defined STANDALONE_BUILD
693public OnEntityCreated(entity, const String:classname[])
694{
695 GrenadeSkins_OnEntityCreated(entity, classname);
696 GrenadeTrails_OnEntityCreated(entity, classname);
697}
698#endif
699
700//////////////////////////////
701// NATIVES //
702//////////////////////////////
703
704public Native_RegisterHandler(Handle:plugin, numParams)
705{
706 if(g_iTypeHandlers == STORE_MAX_HANDLERS)
707 return -1;
708
709 decl String:m_szType[32];
710 GetNativeString(1, STRING(m_szType));
711 new m_iHandler = Store_GetTypeHandler(m_szType);
712 new m_iId = g_iTypeHandlers;
713
714 if(m_iHandler != -1)
715 m_iId = m_iHandler;
716 else
717 ++g_iTypeHandlers;
718
719 g_eTypeHandlers[m_iId][hPlugin] = plugin;
720 g_eTypeHandlers[m_iId][fnMapStart] = GetNativeCell(3);
721 g_eTypeHandlers[m_iId][fnReset] = GetNativeCell(4);
722 g_eTypeHandlers[m_iId][fnConfig] = GetNativeCell(5);
723 g_eTypeHandlers[m_iId][fnUse] = GetNativeCell(6);
724 g_eTypeHandlers[m_iId][fnRemove] = GetNativeCell(7);
725 g_eTypeHandlers[m_iId][bEquipable] = GetNativeCell(8);
726 g_eTypeHandlers[m_iId][bRaw] = GetNativeCell(9);
727 strcopy(g_eTypeHandlers[m_iId][szType], 32, m_szType);
728 GetNativeString(2, g_eTypeHandlers[m_iId][szUniqueKey], 32);
729
730 return m_iId;
731}
732
733public Native_RegisterMenuHandler(Handle:plugin, numParams)
734{
735 if(g_iMenuHandlers == STORE_MAX_HANDLERS)
736 return -1;
737
738 decl String:m_szIdentifier[64];
739 GetNativeString(1, STRING(m_szIdentifier));
740 new m_iHandler = Store_GetMenuHandler(m_szIdentifier);
741 new m_iId = g_iMenuHandlers;
742
743 if(m_iHandler != -1)
744 m_iId = m_iHandler;
745 else
746 ++g_iMenuHandlers;
747
748 g_eMenuHandlers[m_iId][hPlugin] = plugin;
749 g_eMenuHandlers[m_iId][fnMenu] = GetNativeCell(2);
750 g_eMenuHandlers[m_iId][fnHandler] = GetNativeCell(3);
751 strcopy(g_eMenuHandlers[m_iId][szIdentifier], 64, m_szIdentifier);
752
753 return m_iId;
754}
755
756public Native_SetDataIndex(Handle:plugin, numParams)
757{
758 g_eItems[GetNativeCell(1)][iData] = GetNativeCell(2);
759}
760
761public Native_GetDataIndex(Handle:plugin, numParams)
762{
763 return g_eItems[GetNativeCell(1)][iData];
764}
765
766public Native_GetEquippedItem(Handle:plugin, numParams)
767{
768 decl String:m_szType[16];
769 GetNativeString(2, STRING(m_szType));
770
771 new m_iHandler = Store_GetTypeHandler(m_szType);
772 if(m_iHandler == -1)
773 return -1;
774
775 return Store_GetEquippedItemFromHandler(GetNativeCell(1), m_iHandler, GetNativeCell(3));
776}
777
778public Native_IsClientLoaded(Handle:plugin, numParams)
779{
780 return g_eClients[GetNativeCell(1)][bLoaded];
781}
782
783public Native_DisplayPreviousMenu(Handle:plugin, numParams)
784{
785 new client = GetNativeCell(1);
786 if(g_iMenuNum[client] == 1)
787 DisplayStoreMenu(client, g_iMenuBack[client], g_iLastSelection[client]);
788 else if(g_iMenuNum[client] == 2)
789 DisplayItemMenu(client, g_iSelectedItem[client]);
790 else if(g_iMenuNum[client] == 3)
791 DisplayPlayerMenu(client);
792 else if(g_iMenuNum[client] == 4)
793 AdminMenu_ResetPlayer(g_hAdminMenu, TopMenuAction_SelectOption, g_eStoreAdmin, client, "", 0);
794 else if(g_iMenuNum[client] == 5)
795 DisplayPlanMenu(client, g_iSelectedItem[client]);
796 else if(g_iMenuNum[client] == 0)
797 RedisplayAdminMenu(g_hAdminMenu, client);
798}
799
800public Native_SetClientMenu(Handle:plugin, numParams)
801{
802 g_iMenuNum[GetNativeCell(1)] = GetNativeCell(2);
803}
804
805public Native_GetClientCredits(Handle:plugin, numParams)
806{
807 return g_eClients[GetNativeCell(1)][iCredits];
808}
809
810public Native_SetClientCredits(Handle:plugin, numParams)
811{
812 new client = GetNativeCell(1);
813 new m_iCredits = GetNativeCell(2);
814 Store_LogMessage(client, m_iCredits-g_eClients[client][iCredits], "Set by external plugin");
815 g_eClients[client][iCredits] = m_iCredits;
816 return 1;
817}
818
819public Native_IsClientVIP(Handle:plugin, numParams)
820{
821 return (g_eCvars[g_cvarVIPFlag][aCache] != 0 && GetClientPrivilege(GetNativeCell(1), g_eCvars[g_cvarVIPFlag][aCache]));
822}
823
824public Native_IsItemInBoughtPackage(Handle:plugin, numParams)
825{
826 new client = GetNativeCell(1);
827 new itemid = GetNativeCell(2);
828 new uid = GetNativeCell(3);
829
830 decl m_iParent;
831 if(itemid<0)
832 m_iParent = g_eItems[itemid][iParent];
833 else
834 m_iParent = g_eItems[itemid][iParent];
835
836 while(m_iParent != -1)
837 {
838 for(new i=0;i<g_eClients[client][iItems];++i)
839 if(((uid == -1 && g_eClientItems[client][i][iUniqueId] == m_iParent) || (uid != -1 && g_eClientItems[client][i][iUniqueId] == uid)) && !g_eClientItems[client][i][bDeleted])
840 return true;
841 m_iParent = g_eItems[m_iParent][iParent];
842 }
843 return false;
844}
845
846public Native_DisplayConfirmMenu(Handle:plugin, numParams)
847{
848 new client = GetNativeCell(1);
849 decl String:title[255];
850 GetNativeString(2, STRING(title));
851 new callback = GetNativeCell(3);
852 new data = GetNativeCell(4);
853
854 new Handle:m_hMenu = CreateMenu(MenuHandler_Confirm);
855 SetMenuTitle(m_hMenu, title);
856 SetMenuExitButton(m_hMenu, false);
857 new String:m_szCallback[32];
858 new String:m_szData[11];
859 Format(STRING(m_szCallback), "%d.%d", plugin, callback);
860 IntToString(data, STRING(m_szData));
861 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, m_szCallback, "%t", "Confirm_Yes");
862 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, m_szData, "%t", "Confirm_No");
863 DisplayMenu(m_hMenu, client, 0);
864}
865
866public Native_ShouldConfirm(Handle:plugin, numParams)
867{
868 return g_eCvars[g_cvarConfirmation][aCache];
869}
870
871public Native_GetItem(Handle:plugin, numParams)
872{
873 SetNativeArray(2, _:g_eItems[GetNativeCell(1)], sizeof(g_eItems[]));
874}
875
876public Native_GetHandler(Handle:plugin, numParams)
877{
878 SetNativeArray(2, _:g_eTypeHandlers[GetNativeCell(1)], sizeof(g_eTypeHandlers[]));
879}
880
881public Native_GetClientItem(Handle:plugin, numParams)
882{
883 new client = GetNativeCell(1);
884 new itemid = GetNativeCell(2);
885
886 new uid = Store_GetClientItemId(client, itemid);
887 if(uid<0)
888 return 0;
889
890 SetNativeArray(3, _:g_eClientItems[client][uid], sizeof(g_eClientItems[][]));
891
892 return 1;
893}
894
895public Native_GiveItem(Handle:plugin, numParams)
896{
897 new client = GetNativeCell(1);
898 new itemid = GetNativeCell(2);
899 new purchase = GetNativeCell(3);
900 new expiration = GetNativeCell(4);
901 new price = GetNativeCell(5);
902
903 new m_iDateOfPurchase = (purchase==0?GetTime():purchase);
904 new m_iDateOfExpiration = expiration;
905
906 new m_iId = g_eClients[client][iItems]++;
907 g_eClientItems[client][m_iId][iId] = -1;
908 g_eClientItems[client][m_iId][iUniqueId] = itemid;
909 g_eClientItems[client][m_iId][iDateOfPurchase] = m_iDateOfPurchase;
910 g_eClientItems[client][m_iId][iDateOfExpiration] = m_iDateOfExpiration;
911 g_eClientItems[client][m_iId][iPriceOfPurchase] = price;
912 g_eClientItems[client][m_iId][bSynced] = false;
913 g_eClientItems[client][m_iId][bDeleted] = false;
914}
915
916public Native_RemoveItem(Handle:plugin, numParams)
917{
918 new client = GetNativeCell(1);
919 new itemid = GetNativeCell(2);
920 if(itemid>0 && g_eTypeHandlers[g_eItems[itemid][iHandler]][fnRemove] != INVALID_FUNCTION)
921 {
922 Call_StartFunction(g_eTypeHandlers[g_eItems[itemid][iHandler]][hPlugin], g_eTypeHandlers[g_eItems[itemid][iHandler]][fnRemove]);
923 Call_PushCell(client);
924 Call_PushCell(itemid);
925 Call_Finish();
926 }
927
928 Store_UnequipItem(client, itemid, false);
929
930 new m_iId = Store_GetClientItemId(client, itemid);
931 if(m_iId != -1)
932 g_eClientItems[client][m_iId][bDeleted] = true;
933}
934
935public Native_GetClientTarget(Handle:plugin, numParams)
936{
937 return g_iMenuClient[GetNativeCell(1)];
938}
939
940public Native_GiveClientItem(Handle:plugin, numParams)
941{
942 new client = GetNativeCell(1);
943 new receiver = GetNativeCell(2);
944 new itemid = GetNativeCell(3);
945
946 new item = Store_GetClientItemId(client, itemid);
947 if(item == -1)
948 return 1;
949
950 new m_iId = g_eClientItems[client][item][iUniqueId];
951 new target = g_iMenuClient[client];
952 g_eClientItems[client][item][bDeleted] = true;
953 Store_UnequipItem(client, m_iId);
954
955 g_eClientItems[receiver][g_eClients[receiver][iItems]][iId] = -1;
956 g_eClientItems[receiver][g_eClients[receiver][iItems]][iUniqueId] = m_iId;
957 g_eClientItems[receiver][g_eClients[receiver][iItems]][bSynced] = false;
958 g_eClientItems[receiver][g_eClients[receiver][iItems]][bDeleted] = false;
959 g_eClientItems[receiver][g_eClients[receiver][iItems]][iDateOfPurchase] = g_eClientItems[target][item][iDateOfPurchase];
960 g_eClientItems[receiver][g_eClients[receiver][iItems]][iDateOfExpiration] = g_eClientItems[target][item][iDateOfExpiration];
961 g_eClientItems[receiver][g_eClients[receiver][iItems]][iPriceOfPurchase] = g_eClientItems[target][item][iPriceOfPurchase];
962
963 ++g_eClients[receiver][iItems];
964
965 return 1;
966}
967
968public Native_HasClientItem(Handle:plugin, numParams)
969{
970 new client = GetNativeCell(1);
971 new itemid = GetNativeCell(2);
972
973 // Can he even have it?
974 if(!GetClientPrivilege(client, g_eItems[itemid][iFlagBits]))
975 return false;
976
977 // Is the item free (available for everyone)?
978 if(g_eItems[itemid][iPrice] <= 0 && g_eItems[itemid][iPlans]==0)
979 return true;
980
981 // Is the client a VIP therefore has access to all the items already?
982 if(Store_IsClientVIP(client) && !g_eItems[itemid][bIgnoreVIP])
983 return true;
984
985 // Can he even have it?
986 if(!GetClientPrivilege(client, g_eItems[itemid][iFlagBits]))
987 return false;
988
989 // Check if the client actually has the item
990 for(new i=0;i<g_eClients[client][iItems];++i)
991 {
992 if(g_eClientItems[client][i][iUniqueId] == itemid && !g_eClientItems[client][i][bDeleted])
993 if(g_eClientItems[client][i][iDateOfExpiration]==0 || (g_eClientItems[client][i][iDateOfExpiration] && GetTime()<g_eClientItems[client][i][iDateOfExpiration]))
994 return true;
995 else
996 return false;
997 }
998
999 // Check if the item is part of a group the client already has
1000 if(Store_IsItemInBoughtPackage(client, itemid))
1001 return true;
1002
1003 return false;
1004}
1005
1006public Native_IterateEquippedItems(Handle:plugin, numParams)
1007{
1008 new client = GetNativeCell(1);
1009 new start = GetNativeCellRef(2);
1010 new bool:attributes = GetNativeCell(3);
1011
1012 for(new i=start+1;i<STORE_MAX_HANDLERS*STORE_MAX_SLOTS;++i)
1013 {
1014 if(g_eClients[client][aEquipment][i] >= 0 && (attributes==false || (attributes && g_eItems[g_eClients[client][aEquipment][i]][hAttributes]!=INVALID_HANDLE)))
1015 {
1016 SetNativeCellRef(2, i);
1017 return g_eClients[client][aEquipment][i];
1018 }
1019 }
1020
1021 return -1;
1022}
1023
1024//////////////////////////////
1025// CLIENT FORWARDS //
1026//////////////////////////////
1027
1028public OnClientConnected(client)
1029{
1030 g_iSpam[client] = 0;
1031 g_eClients[client][iUserId] = GetClientUserId(client);
1032 g_eClients[client][iCredits] = -1;
1033 g_eClients[client][iOriginalCredits] = 0;
1034 g_eClients[client][iItems] = -1;
1035 g_eClients[client][bLoaded] = false;
1036 for(new i=0;i<STORE_MAX_HANDLERS;++i)
1037 {
1038 for(new a=0;a<STORE_MAX_SLOTS;++a)
1039 {
1040 g_eClients[client][aEquipment][i*STORE_MAX_SLOTS+a] = -2;
1041 g_eClients[client][aEquipmentSynced][i*STORE_MAX_SLOTS+a] = -2;
1042 }
1043 }
1044
1045#if !defined STANDALONE_BUILD
1046 PlayerSkins_OnClientConnected(client);
1047 Jetpack_OnClientConnected(client);
1048 ZRClass_OnClientConnected(client);
1049 Pets_OnClientConnected(client);
1050 Sprays_OnClientConnected(client);
1051#endif
1052}
1053
1054public OnClientPostAdminCheck(client)
1055{
1056 if(IsFakeClient(client))
1057 return;
1058 Store_LoadClientInventory(client);
1059}
1060
1061#if !defined STANDALONE_BUILD
1062public OnClientPutInServer(client)
1063{
1064 if(IsFakeClient(client))
1065 return;
1066 WeaponColors_OnClientPutInServer(client);
1067 Knives_OnClientPutInServer(client);
1068 WeaponSkins_OnClientPutInServer(client);
1069}
1070#endif
1071
1072public OnClientDisconnect(client)
1073{
1074 if(IsFakeClient(client))
1075 return;
1076
1077#if !defined STANDALONE_BUILD
1078 Betting_OnClientDisconnect(client);
1079 Pets_OnClientDisconnect(client);
1080#endif
1081
1082 Store_SaveClientData(client);
1083 Store_SaveClientInventory(client);
1084 Store_SaveClientEquipment(client);
1085 Store_DisconnectClient(client);
1086}
1087
1088public OnClientSettingsChanged(client)
1089{
1090 GetClientName(client, g_eClients[client][szName], 64);
1091 if(g_hDatabase)
1092 SQL_EscapeString(g_hDatabase, g_eClients[client][szName], g_eClients[client][szNameEscaped], 128);
1093}
1094
1095#if !defined STANDALONE_BUILD
1096public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2])
1097{
1098 if(!IsClientInGame(client))
1099 return Plugin_Continue;
1100
1101 new Action:m_iRet = Plugin_Continue;
1102
1103 Jetpack_OnPlayerRunCmd(client, buttons);
1104 LaserSight_OnPlayerRunCmd(client);
1105 Pets_OnPlayerRunCmd(client, tickcount);
1106 Sprays_OnPlayerRunCmd(client, buttons);
1107 m_iRet = Bunnyhop_OnPlayerRunCmd(client, buttons);
1108
1109 return m_iRet;
1110}
1111#endif
1112
1113//////////////////////////////
1114// EVENTS //
1115//////////////////////////////
1116
1117public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
1118{
1119 new victim = GetClientOfUserId(GetEventInt(event, "userid"));
1120 new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
1121
1122 if(g_eCvars[g_cvarSaveOnDeath][aCache])
1123 {
1124 Store_SaveClientData(victim);
1125 Store_SaveClientInventory(victim);
1126 Store_SaveClientEquipment(victim);
1127 }
1128
1129 if(!attacker || victim == attacker || !IsClientInGame(attacker) || IsFakeClient(attacker))
1130 return Plugin_Continue;
1131
1132 if(g_eCvars[g_cvarCreditAmountKill][aCache])
1133 {
1134 g_eClients[attacker][iCredits] += g_eCvars[g_cvarCreditAmountKill][aCache];
1135 if(g_eCvars[g_cvarCreditMessages][aCache])
1136 Chat(attacker, "%t", "Credits Earned For Killing", g_eCvars[g_cvarCreditAmountKill][aCache], g_eClients[victim][szName]);
1137 Store_LogMessage(attacker, g_eCvars[g_cvarCreditAmountKill][aCache], "Earned for killing");
1138 }
1139
1140 return Plugin_Continue;
1141}
1142
1143public Action:Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast)
1144{
1145 new client = GetClientOfUserId(GetEventInt(event, "userid"));
1146
1147 if(!IsClientInGame(client))
1148 return Plugin_Continue;
1149
1150#if !defined STANDALONE_BUILD
1151 Health_OnPlayerSpawn(client);
1152#endif
1153
1154 return Plugin_Continue;
1155}
1156
1157
1158//////////////////////////////////
1159// COMMANDS //
1160//////////////////////////////////
1161
1162public Action:Command_Say(client, const String:command[], argc)
1163{
1164 if(argc > 0)
1165 {
1166 decl String:m_szArg[65];
1167 GetCmdArg(1, STRING(m_szArg));
1168 if(m_szArg[0] == PublicChatTrigger)
1169 {
1170 for(new i=0;i<g_iItems;++i)
1171 if(strcmp(g_eItems[i][szShortcut], m_szArg[1])==0 && g_eItems[i][szShortcut][0] != 0)
1172 {
1173 g_bInvMode[client]=false;
1174 g_iMenuClient[client]=client;
1175 DisplayStoreMenu(client, i);
1176 break;
1177 }
1178 }
1179 }
1180 return Plugin_Continue;
1181}
1182
1183public Action:Command_Store(client, params)
1184{
1185 if(g_eCvars[g_cvarRequiredFlag][aCache] && !GetClientPrivilege(client, g_eCvars[g_cvarRequiredFlag][aCache]))
1186 {
1187 Chat(client, "%t", "You dont have permission");
1188 return Plugin_Handled;
1189 }
1190
1191 if((g_eClients[client][iCredits] == -1 && g_eClients[client][iItems] == -1) || !g_eClients[client][bLoaded])
1192 {
1193 Chat(client, "%t", "Inventory hasnt been fetched");
1194 return Plugin_Handled;
1195 }
1196
1197 g_bInvMode[client]=false;
1198 g_iMenuClient[client]=client;
1199 DisplayStoreMenu(client);
1200
1201 return Plugin_Handled;
1202}
1203
1204public Action:Command_Inventory(client, params)
1205{
1206 if(g_eCvars[g_cvarRequiredFlag][aCache] && !GetClientPrivilege(client, g_eCvars[g_cvarRequiredFlag][aCache]))
1207 {
1208 Chat(client, "%t", "You dont have permission");
1209 return Plugin_Handled;
1210 }
1211
1212 if((g_eClients[client][iCredits] == -1 && g_eClients[client][iItems] == -1) || !g_eClients[client][bLoaded])
1213 {
1214 Chat(client, "%t", "Inventory hasnt been fetched");
1215 return Plugin_Handled;
1216 }
1217
1218 g_bInvMode[client]=true;
1219 g_iMenuClient[client]=client;
1220 DisplayStoreMenu(client);
1221
1222 return Plugin_Handled;
1223}
1224
1225public Action:Command_Gift(client, params)
1226{
1227 if(!g_eCvars[g_cvarCreditGiftEnabled][aCache])
1228 {
1229 Chat(client, "%t", "Credit Gift Disabled");
1230 return Plugin_Handled;
1231 }
1232
1233 decl String:m_szTmp[64];
1234 GetCmdArg(2, STRING(m_szTmp));
1235
1236 new m_iCredits = StringToInt(m_szTmp);
1237 if(g_eClients[client][iCredits]<m_iCredits || m_iCredits<=0)
1238 {
1239 Chat(client, "%t", "Credit Invalid Amount");
1240 return Plugin_Handled;
1241 }
1242
1243 decl bool:m_bTmp;
1244 decl m_iTargets[1];
1245 GetCmdArg(1, STRING(m_szTmp));
1246
1247 new m_iClients = ProcessTargetString(m_szTmp, 0, m_iTargets, 1, 0, STRING(m_szTmp), m_bTmp);
1248 if(m_iClients>2)
1249 {
1250 Chat(client, "%t", "Credit Too Many Matches");
1251 return Plugin_Handled;
1252 }
1253
1254 if(m_iClients != 1)
1255 {
1256 Chat(client, "%t", "Credit No Match");
1257 return Plugin_Handled;
1258 }
1259
1260 new m_iReceiver = m_iTargets[0];
1261
1262 g_eClients[client][iCredits] -= m_iCredits;
1263 g_eClients[m_iReceiver][iCredits] += m_iCredits;
1264
1265 Chat(client, "%t", "Credit Gift Sent", m_iCredits, g_eClients[m_iReceiver][szName]);
1266 Chat(m_iReceiver, "%t", "Credit Gift Received", m_iCredits, g_eClients[client][szName]);
1267
1268 Store_LogMessage(m_iReceiver, m_iCredits, "Gifted by %N", client);
1269 Store_LogMessage(client, -m_iCredits, "Gifted to %N", m_iReceiver);
1270
1271 return Plugin_Handled;
1272}
1273
1274public Action:Command_GiveCredits(client, params)
1275{
1276 if(client && !GetClientPrivilege(client, g_eCvars[g_cvarAdminFlag][aCache]))
1277 {
1278 Chat(client, "%t", "You dont have permission");
1279 return Plugin_Handled;
1280 }
1281
1282 decl String:m_szTmp[64];
1283 GetCmdArg(2, STRING(m_szTmp));
1284
1285 new m_iCredits = StringToInt(m_szTmp);
1286
1287 decl bool:m_bTmp;
1288 decl m_iTargets[1];
1289 GetCmdArg(1, STRING(m_szTmp));
1290
1291 new m_iReceiver = -1;
1292 if(strncmp(m_szTmp, "STEAM_", 6)==0)
1293 {
1294 m_iReceiver = GetClientBySteamID(m_szTmp);
1295 // SteamID is not ingame
1296 if(m_iReceiver == 0)
1297 {
1298 decl String:m_szQuery[512];
1299 if(g_bMySQL)
1300 Format(STRING(m_szQuery), "INSERT IGNORE INTO store_players (authid, credits) VALUES (\"%s\", %d) ON DUPLICATE KEY UPDATE credits=credits+%d", m_szTmp[8], m_iCredits, m_iCredits);
1301 else
1302 {
1303 Format(STRING(m_szQuery), "INSERT OR IGNORE INTO store_players (authid) VALUES (\"%s\")", m_szTmp[8]);
1304 SQL_TVoid(g_hDatabase, m_szQuery);
1305 Format(STRING(m_szQuery), "UPDATE store_players SET credits=credits+%d WHERE authid=\"%s\"", m_iCredits, m_szTmp[8]);
1306 }
1307 SQL_TVoid(g_hDatabase, m_szQuery);
1308 ChatAll("%t", "Credits Given", m_szTmp[8], m_iCredits);
1309 m_iReceiver = -1;
1310 }
1311 } else if(strcmp(m_szTmp, "@all")==0)
1312 {
1313 LoopIngamePlayers(i)
1314 FakeClientCommandEx(client, "sm_dajkredyty \"%N\" %d", i, m_iCredits);
1315 } else if(strcmp(m_szTmp, "@t")==0 || strcmp(m_szTmp, "@red")==0)
1316 {
1317 LoopIngamePlayers(i)
1318 if(GetClientTeam(i)==2)
1319 FakeClientCommandEx(client, "sm_dajkredyty \"%N\" %d", i, m_iCredits);
1320 } else if(strcmp(m_szTmp, "@ct")==0 || strcmp(m_szTmp, "@blu")==0)
1321 {
1322 LoopIngamePlayers(i)
1323 if(GetClientTeam(i)==3)
1324 FakeClientCommandEx(client, "sm_dajkredyty \"%N\" %d", i, m_iCredits);
1325 }
1326 else
1327 {
1328 new m_iClients = ProcessTargetString(m_szTmp, 0, m_iTargets, 1, 0, STRING(m_szTmp), m_bTmp);
1329 if(m_iClients>2)
1330 {
1331 if(client)
1332 Chat(client, "%t", "Credit Too Many Matches");
1333 else
1334 ReplyToCommand(client, "%t", "Credit Too Many Matches");
1335 return Plugin_Handled;
1336 } else if(m_iClients != 1)
1337 {
1338 if(client)
1339 Chat(client, "%t", "Credit No Match");
1340 else
1341 ReplyToCommand(client, "%t", "Credit No Match");
1342 return Plugin_Handled;
1343 }
1344
1345 m_iReceiver = m_iTargets[0];
1346 }
1347
1348 // The player is on the server
1349 if(m_iReceiver != -1)
1350 {
1351 g_eClients[m_iReceiver][iCredits] += m_iCredits;
1352 if(g_eCvars[g_cvarSilent][aCache] == 1)
1353 {
1354 if(client)
1355 Chat(client, "%t", "Credits Given", g_eClients[m_iReceiver][szName], m_iCredits);
1356 else
1357 ReplyToCommand(client, "%t", "Credits Given", g_eClients[m_iReceiver][szName], m_iCredits);
1358 Chat(m_iReceiver, "%t", "Credits Given", g_eClients[m_iReceiver][szName], m_iCredits);
1359 }
1360 else if(g_eCvars[g_cvarSilent][aCache] == 0)
1361 ChatAll("%t", "Credits Given", g_eClients[m_iReceiver][szName], m_iCredits);
1362 Store_LogMessage(m_iReceiver, m_iCredits, "Given by Admin");
1363 }
1364
1365 return Plugin_Handled;
1366}
1367
1368public Action:Command_ResetPlayer(client, params)
1369{
1370 if(client && !GetClientPrivilege(client, g_eCvars[g_cvarAdminFlag][aCache]))
1371 {
1372 Chat(client, "%t", "You dont have permission");
1373 return Plugin_Handled;
1374 }
1375
1376 decl String:m_szTmp[64];
1377 decl bool:m_bTmp;
1378 decl m_iTargets[1];
1379 GetCmdArg(1, STRING(m_szTmp));
1380
1381 new m_iReceiver = -1;
1382 if(strncmp(m_szTmp, "STEAM_", 6)==0)
1383 {
1384 m_iReceiver = GetClientBySteamID(m_szTmp);
1385 // SteamID is not ingame
1386 if(m_iReceiver == 0)
1387 {
1388 decl String:m_szQuery[512];
1389 Format(STRING(m_szQuery), "SELECT id, authid FROM store_players WHERE authid=\"%s\"", m_szTmp[9]);
1390 SQL_TQuery(g_hDatabase, SQLCallback_ResetPlayer, m_szQuery, g_eClients[client][iUserId]);
1391 }
1392 }
1393 else
1394 {
1395 new m_iClients = ProcessTargetString(m_szTmp, 0, m_iTargets, 1, 0, STRING(m_szTmp), m_bTmp);
1396 if(m_iClients>2)
1397 {
1398 Chat(client, "%t", "Credit Too Many Matches");
1399 return Plugin_Handled;
1400 }
1401
1402 if(m_iClients != 1)
1403 {
1404 Chat(client, "%t", "Credit No Match");
1405 return Plugin_Handled;
1406 }
1407
1408 m_iReceiver = m_iTargets[0];
1409 }
1410
1411 // The player is on the server
1412 if(m_iReceiver != -1)
1413 {
1414 Store_LogMessage(client, -g_eClients[m_iReceiver][iCredits], "Player resetted");
1415 g_eClients[m_iReceiver][iCredits] = 0;
1416 for(new i=0;i<g_eClients[m_iReceiver][iItems];++i)
1417 Store_RemoveItem(m_iReceiver, g_eClientItems[m_iReceiver][i][iUniqueId]);
1418 ChatAll("%t", "Player Resetted", g_eClients[m_iReceiver][szName]);
1419 }
1420
1421 return Plugin_Handled;
1422}
1423
1424public Action:Command_Credits(client, params)
1425{
1426 if(g_eClients[client][iCredits] == -1 && g_eClients[client][iItems] == -1)
1427 {
1428 Chat(client, "%t", "Inventory hasnt been fetched");
1429 return Plugin_Handled;
1430 }
1431
1432 if(g_iSpam[client]<GetTime())
1433 {
1434 ChatAll("%t", "Player Credits", g_eClients[client][szName], g_eClients[client][iCredits]);
1435 g_iSpam[client] = GetTime()+30;
1436 }
1437
1438 return Plugin_Handled;
1439}
1440
1441//////////////////////////////
1442// MENUS //
1443//////////////////////////////
1444
1445DisplayStoreMenu(client, parent=-1, last=-1)
1446{
1447 if(!client || !IsClientInGame(client))
1448 return;
1449
1450 g_iMenuNum[client] = 1;
1451 new target = g_iMenuClient[client];
1452
1453 new Handle:m_hMenu = CreateMenu(MenuHandler_Store);
1454 if(parent!=-1)
1455 {
1456 SetMenuExitBackButton(m_hMenu, true);
1457 if(client == target)
1458 SetMenuTitle(m_hMenu, "%s\n%t", g_eItems[parent][szName], "Title Credits", g_eClients[target][iCredits]);
1459 else
1460 SetMenuTitle(m_hMenu, "%N\n%s\n%t", target, g_eItems[parent][szName], "Title Credits", g_eClients[target][iCredits]);
1461 g_iMenuBack[client] = g_eItems[parent][iParent];
1462 }
1463 else if(client == target)
1464 SetMenuTitle(m_hMenu, "%t\n%t", "Title Store", "Title Credits", g_eClients[target][iCredits]);
1465 else
1466 SetMenuTitle(m_hMenu, "%N\n%t\n%t", target, "Title Store", "Title Credits", g_eClients[target][iCredits]);
1467
1468 decl String:m_szId[11];
1469 new m_iFlags = GetUserFlagBits(target);
1470 new m_iPosition = 0;
1471
1472 g_iSelectedItem[client] = parent;
1473 if(parent != -1)
1474 {
1475 if(g_eItems[parent][iPrice]>0)
1476 {
1477 if(!Store_IsClientVIP(target) && !Store_IsItemInBoughtPackage(target, parent))
1478 {
1479 if(g_eCvars[g_cvarSellEnabled][aCache])
1480 {
1481 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, "sell_package", "%t", "Package Sell", RoundToFloor(g_eItems[parent][iPrice]*Float:g_eCvars[g_cvarSellRatio][aCache]));
1482 ++m_iPosition;
1483 }
1484 if(g_eCvars[g_cvarGiftEnabled][aCache] == 1 || (g_eCvars[g_cvarGiftEnabled][aCache] == 2 && GetUserFlagBits(client) & g_eCvars[g_cvarAdminFlag][aCache]))
1485 {
1486 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, "gift_package", "%t", "Package Gift");
1487 ++m_iPosition;
1488 }
1489
1490 for(new i=0;i<g_iMenuHandlers;++i)
1491 {
1492 if(g_eMenuHandlers[i][hPlugin] == INVALID_HANDLE)
1493 continue;
1494 Call_StartFunction(g_eMenuHandlers[i][hPlugin], g_eMenuHandlers[i][fnMenu]);
1495 Call_PushCellRef(m_hMenu);
1496 Call_PushCell(client);
1497 Call_PushCell(parent);
1498 Call_Finish();
1499 }
1500 }
1501 }
1502 }
1503
1504 for(new i=0;i<g_iItems;++i)
1505 {
1506 if(g_eItems[i][iParent]==parent && (g_eCvars[g_cvarShowVIP][aCache] == 0 && GetClientPrivilege(target, g_eItems[i][iFlagBits], m_iFlags) || g_eCvars[g_cvarShowVIP][aCache]))
1507 {
1508 new m_iPrice = Store_GetLowestPrice(i);
1509
1510 // This is a package
1511 if(g_eItems[i][iHandler] == g_iPackageHandler)
1512 {
1513 if(!Store_PackageHasClientItem(target, i, g_bInvMode[client]))
1514 continue;
1515
1516 new m_iStyle = ITEMDRAW_DEFAULT;
1517 if(g_eCvars[g_cvarShowVIP][aCache] && !GetClientPrivilege(target, g_eItems[i][iFlagBits], m_iFlags))
1518 m_iStyle = ITEMDRAW_DISABLED;
1519
1520 IntToString(i, STRING(m_szId));
1521 if(g_eItems[i][iPrice] == -1 || Store_HasClientItem(target, i))
1522 AddMenuItem(m_hMenu, m_szId, g_eItems[i][szName], m_iStyle);
1523 else if(!g_bInvMode[client] && g_eItems[i][iPlans]==0 && g_eItems[i][bBuyable])
1524 InsertMenuItemEx(m_hMenu, m_iPosition, (m_iPrice<=g_eClients[target][iCredits]?ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED), m_szId, "%t", "Item Available", g_eItems[i][szName], g_eItems[i][iPrice]);
1525 else if(!g_bInvMode[client])
1526 InsertMenuItemEx(m_hMenu, m_iPosition, (m_iPrice<=g_eClients[target][iCredits]?ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED), m_szId, "%t", "Item Plan Available", g_eItems[i][szName]);
1527 ++m_iPosition;
1528 }
1529 // This is a normal item
1530 else
1531 {
1532 IntToString(i, STRING(m_szId));
1533 if(Store_HasClientItem(target, i))
1534 {
1535 if(Store_IsEquipped(target, i))
1536 InsertMenuItemEx(m_hMenu, m_iPosition, ITEMDRAW_DEFAULT, m_szId, "%t", "Item Equipped", g_eItems[i][szName]);
1537 else
1538 InsertMenuItemEx(m_hMenu, m_iPosition, ITEMDRAW_DEFAULT, m_szId, "%t", "Item Bought", g_eItems[i][szName]);
1539 }
1540 else if(!g_bInvMode[client])
1541 {
1542 new m_iStyle = ITEMDRAW_DEFAULT;
1543 if((g_eItems[i][iPlans]==0 && g_eClients[target][iCredits]<m_iPrice) || (g_eCvars[g_cvarShowVIP][aCache] && !GetClientPrivilege(target, g_eItems[i][iFlagBits], m_iFlags)))
1544 m_iStyle = ITEMDRAW_DISABLED;
1545
1546 if(!g_eItems[i][bBuyable])
1547 continue;
1548
1549 if(g_eItems[i][iPlans]==0)
1550 AddMenuItemEx(m_hMenu, m_iStyle, m_szId, "%t", "Item Available", g_eItems[i][szName], g_eItems[i][iPrice]);
1551 else
1552 AddMenuItemEx(m_hMenu, m_iStyle, m_szId, "%t", "Item Plan Available", g_eItems[i][szName], g_eItems[i][iPrice]);
1553 }
1554 }
1555 }
1556 }
1557
1558 if(last == -1)
1559 DisplayMenu(m_hMenu, client, 0);
1560 else
1561 DisplayMenuAtItem(m_hMenu, client, (last/GetMenuPagination(m_hMenu))*GetMenuPagination(m_hMenu), 0);
1562}
1563
1564public MenuHandler_Store(Handle:menu, MenuAction:action, client, param2)
1565{
1566 if (action == MenuAction_End)
1567 CloseHandle(menu);
1568 else if (action == MenuAction_Select)
1569 {
1570 new target = g_iMenuClient[client];
1571 // Confirmation was given
1572 if(menu == INVALID_HANDLE)
1573 {
1574 if(param2 == 0)
1575 {
1576 g_iMenuBack[client]=1;
1577 new m_iPrice = 0;
1578 if(g_iSelectedPlan[client]==-1)
1579 m_iPrice = g_eItems[g_iSelectedItem[client]][iPrice];
1580 else
1581 m_iPrice = g_ePlans[g_iSelectedItem[client]][g_iSelectedPlan[client]][iPrice];
1582
1583 if(g_eClients[target][iCredits]>=m_iPrice && !Store_HasClientItem(target, g_iSelectedItem[client]))
1584 Store_BuyItem(target, g_iSelectedItem[client], g_iSelectedPlan[client]);
1585
1586 if(g_eItems[g_iSelectedItem[client]][iHandler] == g_iPackageHandler)
1587 DisplayStoreMenu(client, g_iSelectedItem[client]);
1588 else
1589 DisplayItemMenu(client, g_iSelectedItem[client]);
1590 }
1591 else if(param2 == 1)
1592 {
1593 Store_SellItem(target, g_iSelectedItem[client]);
1594 Store_DisplayPreviousMenu(client);
1595 }
1596 }
1597 else
1598 {
1599 new String:m_szId[64];
1600 GetMenuItem(menu, param2, STRING(m_szId));
1601
1602 g_iLastSelection[client]=param2;
1603
1604 // We are selling a package
1605 if(strcmp(m_szId, "sell_package")==0)
1606 {
1607 if(g_eCvars[g_cvarConfirmation][aCache])
1608 {
1609 decl String:m_szTitle[128];
1610 Format(STRING(m_szTitle), "%t", "Confirm_Sell", g_eItems[g_iSelectedItem[client]][szName], g_eTypeHandlers[g_eItems[g_iSelectedItem[client]][iHandler]][szType], RoundToFloor(g_eItems[g_iSelectedItem[client]][iPrice]*Float:g_eCvars[g_cvarSellRatio][aCache]));
1611 Store_DisplayConfirmMenu(client, m_szTitle, MenuHandler_Store, 1);
1612 return;
1613 }
1614 else
1615 {
1616 Store_SellItem(target, g_iSelectedItem[client]);
1617 Store_DisplayPreviousMenu(client);
1618 }
1619 }
1620 // We are gifting a package
1621 else if(strcmp(m_szId, "gift_package")==0)
1622 {
1623 DisplayPlayerMenu(client);
1624 }
1625 // This is menu handler stuff
1626 else if(!(48 <= m_szId[0] <= 57))
1627 {
1628 decl ret;
1629 for(new i=0;i<g_iMenuHandlers;++i)
1630 {
1631 Call_StartFunction(g_eMenuHandlers[i][hPlugin], g_eMenuHandlers[i][fnHandler]);
1632 Call_PushCell(target);
1633 Call_PushString(m_szId);
1634 Call_PushCell(g_iSelectedItem[client]);
1635 Call_Finish(ret);
1636
1637 if(ret)
1638 break;
1639 }
1640 }
1641 // We are being boring
1642 else
1643 {
1644 new m_iId = StringToInt(m_szId);
1645 g_iMenuBack[client]=g_eItems[m_iId][iParent];
1646 g_iSelectedItem[client] = m_iId;
1647 g_iSelectedPlan[client] = -1;
1648
1649 if((g_eClients[target][iCredits]>=g_eItems[m_iId][iPrice] || g_eItems[m_iId][iPlans]>0 && g_eClients[target][iCredits]>=Store_GetLowestPrice(m_iId)) && !Store_HasClientItem(target, m_iId) && g_eItems[m_iId][iPrice] != -1) {
1650 if(g_eItems[m_iId][iPlans] > 0)
1651 {
1652 DisplayPlanMenu(client, m_iId);
1653 return;
1654 }
1655 else
1656 if(g_eCvars[g_cvarConfirmation][aCache])
1657 {
1658 decl String:m_szTitle[128];
1659 Format(STRING(m_szTitle), "%t", "Confirm_Buy", g_eItems[m_iId][szName], g_eTypeHandlers[g_eItems[m_iId][iHandler]][szType]);
1660 Store_DisplayConfirmMenu(client, m_szTitle, MenuHandler_Store, 0);
1661 return;
1662 }
1663 else
1664 Store_BuyItem(target, m_iId);
1665 }
1666
1667 if(g_eItems[m_iId][iHandler] != g_iPackageHandler)
1668 {
1669 if(Store_HasClientItem(target, m_iId))
1670 {
1671 if(g_eTypeHandlers[g_eItems[m_iId][iHandler]][bRaw])
1672 {
1673 Call_StartFunction(g_eTypeHandlers[g_eItems[m_iId][iHandler]][hPlugin], g_eTypeHandlers[g_eItems[m_iId][iHandler]][fnUse]);
1674 Call_PushCell(target);
1675 Call_PushCell(m_iId);
1676 Call_Finish();
1677 }
1678 else
1679 DisplayItemMenu(client, m_iId);
1680 }
1681 else
1682 DisplayStoreMenu(client, g_iMenuBack[client]);
1683 }
1684 else
1685 {
1686 if(Store_HasClientItem(target, m_iId) || g_eItems[m_iId][iPrice] == -1)
1687 DisplayStoreMenu(client, m_iId);
1688 else
1689 DisplayStoreMenu(client, g_eItems[m_iId][iParent]);
1690 }
1691 }
1692 }
1693 }
1694 else if(action==MenuAction_Cancel)
1695 if (param2 == MenuCancel_ExitBack)
1696 Store_DisplayPreviousMenu(client);
1697}
1698
1699public DisplayItemMenu(client, itemid)
1700{
1701 g_iMenuNum[client] = 1;
1702 g_iMenuBack[client] = g_eItems[itemid][iParent];
1703 new target = g_iMenuClient[client];
1704
1705 new Handle:m_hMenu = CreateMenu(MenuHandler_Item);
1706 SetMenuExitBackButton(m_hMenu, true);
1707
1708 new bool:m_bEquipped = Store_IsEquipped(target, itemid);
1709 new String:m_szTitle[256];
1710 new idx = 0;
1711 if(m_bEquipped)
1712 idx = Format(STRING(m_szTitle), "%t\n%t", "Item Equipped", g_eItems[itemid][szName], "Title Credits", g_eClients[target][iCredits]);
1713 else
1714 idx = Format(STRING(m_szTitle), "%s\n%t", g_eItems[itemid][szName], "Title Credits", g_eClients[target][iCredits]);
1715
1716 new m_iExpiration = Store_GetExpiration(target, itemid);
1717 if(m_iExpiration != 0)
1718 {
1719 m_iExpiration = m_iExpiration-GetTime();
1720 new m_iDays = m_iExpiration/(24*60*60);
1721 new m_iHours = (m_iExpiration-m_iDays*24*60*60)/(60*60);
1722 Format(m_szTitle[idx-1], sizeof(m_szTitle)-idx-1, "\n%t", "Title Expiration", m_iDays, m_iHours);
1723 }
1724
1725 SetMenuTitle(m_hMenu, m_szTitle);
1726
1727 if(g_eTypeHandlers[g_eItems[itemid][iHandler]][bEquipable])
1728 if(!m_bEquipped)
1729 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, "0", "%t", "Item Equip");
1730 else
1731 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, "3", "%t", "Item Unequip");
1732 else
1733 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, "0", "%t", "Item Use");
1734
1735 if(!Store_IsClientVIP(target) && !Store_IsItemInBoughtPackage(target, itemid))
1736 {
1737 new m_iCredits = RoundToFloor(Store_GetClientItemPrice(client, itemid)*Float:g_eCvars[g_cvarSellRatio][aCache]);
1738 if(m_iCredits!=0)
1739 {
1740 new uid = Store_GetClientItemId(client, itemid);
1741 if(g_eClientItems[client][uid][iDateOfExpiration] != 0)
1742 {
1743 new m_iLength = g_eClientItems[client][uid][iDateOfExpiration]-g_eClientItems[client][uid][iDateOfPurchase];
1744 new m_iLeft = g_eClientItems[client][uid][iDateOfExpiration]-GetTime();
1745 if(m_iLeft < 0)
1746 m_iLeft = 0;
1747 m_iCredits = RoundToCeil(m_iCredits*float(m_iLeft)/float(m_iLength));
1748 }
1749
1750 if(g_eCvars[g_cvarSellEnabled][aCache])
1751 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, "1", "%t", "Item Sell", m_iCredits);
1752 if(g_eCvars[g_cvarGiftEnabled][aCache] == 1 || (g_eCvars[g_cvarGiftEnabled][aCache] == 2 && GetUserFlagBits(client) & g_eCvars[g_cvarAdminFlag][aCache]))
1753 AddMenuItemEx(m_hMenu, ITEMDRAW_DEFAULT, "2", "%t", "Item Gift");
1754 }
1755 }
1756
1757 for(new i=0;i<g_iMenuHandlers;++i)
1758 {
1759 if(g_eMenuHandlers[i][hPlugin] == INVALID_HANDLE)
1760 continue;
1761 Call_StartFunction(g_eMenuHandlers[i][hPlugin], g_eMenuHandlers[i][fnMenu]);
1762 Call_PushCellRef(m_hMenu);
1763 Call_PushCell(client);
1764 Call_PushCell(itemid);
1765 Call_Finish();
1766 }
1767
1768 DisplayMenu(m_hMenu, client, 0);
1769}
1770
1771public DisplayPlanMenu(client, itemid)
1772{
1773 g_iMenuNum[client] = 1;
1774 new target = g_iMenuClient[client];
1775
1776 new Handle:m_hMenu = CreateMenu(MenuHandler_Plan);
1777 SetMenuExitBackButton(m_hMenu, true);
1778
1779 SetMenuTitle(m_hMenu, "%s\n%t", g_eItems[itemid][szName], "Title Credits", g_eClients[target][iCredits]);
1780
1781 for(new i=0;i<g_eItems[itemid][iPlans];++i)
1782 {
1783 AddMenuItemEx(m_hMenu, (g_eClients[target][iCredits]>=g_ePlans[itemid][i][iPrice]?ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED), "", "%t", "Item Available", g_ePlans[itemid][i][szName], g_ePlans[itemid][i][iPrice]);
1784 }
1785
1786 DisplayMenu(m_hMenu, client, 0);
1787}
1788
1789public MenuHandler_Plan(Handle:menu, MenuAction:action, client, param2)
1790{
1791 if (action == MenuAction_End)
1792 CloseHandle(menu);
1793 else if (action == MenuAction_Select)
1794 {
1795 new target = g_iMenuClient[client];
1796 g_iSelectedPlan[client]=param2;
1797 g_iMenuNum[client]=5;
1798
1799 if(g_eCvars[g_cvarConfirmation][aCache])
1800 {
1801 decl String:m_szTitle[128];
1802 Format(STRING(m_szTitle), "%t", "Confirm_Buy", g_eItems[g_iSelectedItem[client]][szName], g_eTypeHandlers[g_eItems[g_iSelectedItem[client]][iHandler]][szType]);
1803 Store_DisplayConfirmMenu(client, m_szTitle, MenuHandler_Store, 0);
1804 return;
1805 }
1806 else
1807 {
1808 Store_BuyItem(target, g_iSelectedItem[client], param2);
1809 DisplayItemMenu(client, g_iSelectedItem[client]);
1810 }
1811 }
1812 else if(action==MenuAction_Cancel)
1813 if (param2 == MenuCancel_ExitBack)
1814 Store_DisplayPreviousMenu(client);
1815}
1816
1817public MenuHandler_Item(Handle:menu, MenuAction:action, client, param2)
1818{
1819 if (action == MenuAction_End)
1820 CloseHandle(menu);
1821 else if (action == MenuAction_Select)
1822 {
1823 new target = g_iMenuClient[client];
1824 // Confirmation was sent
1825 if(menu == INVALID_HANDLE)
1826 {
1827 if(param2 == 0)
1828 {
1829 g_iMenuNum[client] = 1;
1830 Store_SellItem(target, g_iSelectedItem[client]);
1831 Store_DisplayPreviousMenu(client);
1832 }
1833 }
1834 else
1835 {
1836 decl String:m_szId[64];
1837 GetMenuItem(menu, param2, STRING(m_szId));
1838
1839 new m_iId = StringToInt(m_szId);
1840
1841 // Menu handlers
1842 if(!(48 <= m_szId[0] <= 57))
1843 {
1844 decl ret;
1845 for(new i=0;i<g_iMenuHandlers;++i)
1846 {
1847 if(g_eMenuHandlers[i][hPlugin] == INVALID_HANDLE)
1848 continue;
1849 Call_StartFunction(g_eMenuHandlers[i][hPlugin], g_eMenuHandlers[i][fnHandler]);
1850 Call_PushCell(client);
1851 Call_PushString(m_szId);
1852 Call_PushCell(g_iSelectedItem[client]);
1853 Call_Finish(ret);
1854
1855 if(ret)
1856 break;
1857 }
1858 }
1859 // Player wants to equip this item
1860 else if(m_iId == 0)
1861 {
1862 new m_iRet = Store_UseItem(target, g_iSelectedItem[client]);
1863 if(GetClientMenu(client)==MenuSource_None && m_iRet == 0)
1864 DisplayItemMenu(client, g_iSelectedItem[client]);
1865 }
1866 // Player wants to sell this item
1867 else if(m_iId == 1)
1868 {
1869 if(g_eCvars[g_cvarConfirmation][aCache])
1870 {
1871 new m_iCredits = RoundToFloor(Store_GetClientItemPrice(client, g_iSelectedItem[client])*Float:g_eCvars[g_cvarSellRatio][aCache]);
1872 new uid = Store_GetClientItemId(client, g_iSelectedItem[client]);
1873 if(g_eClientItems[client][uid][iDateOfExpiration] != 0)
1874 {
1875 new m_iLength = g_eClientItems[client][uid][iDateOfExpiration]-g_eClientItems[client][uid][iDateOfPurchase];
1876 new m_iLeft = g_eClientItems[client][uid][iDateOfExpiration]-GetTime();
1877 if(m_iLeft < 0)
1878 m_iLeft = 0;
1879 m_iCredits = RoundToCeil(m_iCredits*float(m_iLeft)/float(m_iLength));
1880 }
1881
1882 decl String:m_szTitle[128];
1883 Format(STRING(m_szTitle), "%t", "Confirm_Sell", g_eItems[g_iSelectedItem[client]][szName], g_eTypeHandlers[g_eItems[g_iSelectedItem[client]][iHandler]][szType], m_iCredits);
1884 g_iMenuNum[client] = 2;
1885 Store_DisplayConfirmMenu(client, m_szTitle, MenuHandler_Item, 0);
1886 }
1887 else
1888 {
1889 Store_SellItem(target, g_iSelectedItem[client]);
1890 Store_DisplayPreviousMenu(client);
1891 }
1892 }
1893 // Player wants to gift this item
1894 else if(m_iId == 2)
1895 {
1896 g_iMenuNum[client] = 2;
1897 DisplayPlayerMenu(client);
1898 }
1899 // Player wants to unequip this item
1900 else if(m_iId == 3)
1901 {
1902 Store_UnequipItem(target, g_iSelectedItem[client]);
1903 DisplayItemMenu(client, g_iSelectedItem[client]);
1904 }
1905 }
1906 }
1907 else if(action==MenuAction_Cancel)
1908 if (param2 == MenuCancel_ExitBack)
1909 Store_DisplayPreviousMenu(client);
1910}
1911
1912public DisplayPlayerMenu(client)
1913{
1914 g_iMenuNum[client] = 3;
1915 new target = g_iMenuClient[client];
1916
1917 new m_iCount = 0;
1918 new Handle:m_hMenu = CreateMenu(MenuHandler_Gift);
1919 SetMenuExitBackButton(m_hMenu, true);
1920 SetMenuTitle(m_hMenu, "%t\n%t", "Title Gift", "Title Credits", g_eClients[client][iCredits]);
1921
1922 decl String:m_szID[11];
1923 decl m_iFlags;
1924 LoopIngamePlayers(i)
1925 {
1926 m_iFlags = GetUserFlagBits(i);
1927 if(!GetClientPrivilege(i, g_eItems[g_iSelectedItem[client]][iFlagBits], m_iFlags))
1928 continue;
1929 if(i != target && IsClientInGame(i) && !Store_HasClientItem(i, g_iSelectedItem[client]))
1930 {
1931 IntToString(g_eClients[i][iUserId], STRING(m_szID));
1932 AddMenuItem(m_hMenu, m_szID, g_eClients[i][szName]);
1933 ++m_iCount;
1934 }
1935 }
1936
1937 if(m_iCount == 0)
1938 {
1939 CloseHandle(m_hMenu);
1940 g_iMenuNum[client] = 1;
1941 DisplayItemMenu(client, g_iSelectedItem[client]);
1942 Chat(client, "%t", "Gift No Players");
1943 }
1944 else
1945 DisplayMenu(m_hMenu, client, 0);
1946}
1947
1948public MenuHandler_Gift(Handle:menu, MenuAction:action, client, param2)
1949{
1950 if (action == MenuAction_End)
1951 CloseHandle(menu);
1952 else if (action == MenuAction_Select)
1953 {
1954 decl m_iItem, m_iReceiver;
1955 new target = g_iMenuClient[client];
1956
1957 // Confirmation was given
1958 if(menu == INVALID_HANDLE)
1959 {
1960 m_iItem = Store_GetClientItemId(target, g_iSelectedItem[client]);
1961 m_iReceiver = GetClientOfUserId(param2);
1962 if(!m_iReceiver)
1963 {
1964 Chat(client, "%t", "Gift Player Left");
1965 return;
1966 }
1967 Store_GiftItem(target, m_iReceiver, m_iItem);
1968 g_iMenuNum[client] = 1;
1969 Store_DisplayPreviousMenu(client);
1970 }
1971 else
1972 {
1973 decl String:m_szId[11];
1974 GetMenuItem(menu, param2, STRING(m_szId));
1975
1976 new m_iId = StringToInt(m_szId);
1977 m_iReceiver = GetClientOfUserId(m_iId);
1978 if(!m_iReceiver)
1979 {
1980 Chat(client, "%t", "Gift Player Left");
1981 return;
1982 }
1983
1984 m_iItem = Store_GetClientItemId(target, g_iSelectedItem[client]);
1985
1986 if(g_eCvars[g_cvarConfirmation][aCache])
1987 {
1988 decl String:m_szTitle[128];
1989 Format(STRING(m_szTitle), "%t", "Confirm_Gift", g_eItems[g_iSelectedItem[client]][szName], g_eTypeHandlers[g_eItems[g_iSelectedItem[client]][iHandler]][szType], g_eClients[m_iReceiver][szName]);
1990 Store_DisplayConfirmMenu(client, m_szTitle, MenuHandler_Gift, m_iId);
1991 return;
1992 }
1993 else
1994 Store_GiftItem(target, m_iReceiver, m_iItem);
1995 Store_DisplayPreviousMenu(client);
1996 }
1997 }
1998 else if(action==MenuAction_Cancel)
1999 if (param2 == MenuCancel_ExitBack)
2000 DisplayItemMenu(client, g_iSelectedItem[client]);
2001}
2002
2003public MenuHandler_Confirm(Handle:menu, MenuAction:action, client, param2)
2004{
2005 if (action == MenuAction_End)
2006 CloseHandle(menu);
2007 else if (action == MenuAction_Select)
2008 {
2009 if(param2 == 0)
2010 {
2011 decl String:m_szCallback[32];
2012 decl String:m_szData[11];
2013 GetMenuItem(menu, 0, STRING(m_szCallback));
2014 GetMenuItem(menu, 1, STRING(m_szData));
2015 new m_iPos = FindCharInString(m_szCallback, '.');
2016 m_szCallback[m_iPos] = 0;
2017 new Handle:m_hPlugin = Handle:StringToInt(m_szCallback);
2018 new Function:fnMenuCallback = Function:StringToInt(m_szCallback[m_iPos+1]);
2019 if(fnMenuCallback != INVALID_FUNCTION)
2020 {
2021 Call_StartFunction(m_hPlugin, fnMenuCallback);
2022 Call_PushCell(INVALID_HANDLE);
2023 Call_PushCell(MenuAction_Select);
2024 Call_PushCell(client);
2025 Call_PushCell(StringToInt(m_szData));
2026 Call_Finish();
2027 }
2028 else
2029 Store_DisplayPreviousMenu(client);
2030 }
2031 else
2032 {
2033 Store_DisplayPreviousMenu(client);
2034 }
2035 }
2036}
2037
2038//////////////////////////////
2039// CONVARS //
2040//////////////////////////////
2041
2042public ConVar_CreditTimer(index)
2043{
2044 new m_bTimer = (FloatCompare(g_eCvars[g_cvarCreditTimer][aCache], 0.0)==0 || g_eCvars[g_cvarCreditAmountActive][aCache]==0);
2045 for(new i=1;i<=MaxClients;++i)
2046 {
2047 ClearTimer(g_eClients[i][hCreditTimer]);
2048 if(m_bTimer && IsClientInGame(i))
2049 g_eClients[i][hCreditTimer] = Store_CreditTimer(i);
2050 }
2051}
2052
2053//////////////////////////////
2054// TIMERS //
2055//////////////////////////////
2056
2057public Action:Timer_CreditTimer(Handle:timer, any:userid)
2058{
2059 new client = GetClientOfUserId(userid);
2060 if(!client || !IsClientInGame(client))
2061 return Plugin_Continue;
2062
2063 decl m_iCredits;
2064
2065 if(2<=GetClientTeam(client)<=3)
2066 m_iCredits = g_eCvars[g_cvarCreditAmountActive][aCache];
2067 else
2068 m_iCredits = g_eCvars[g_cvarCreditAmountInactive][aCache];
2069
2070 if(m_iCredits)
2071 {
2072 g_eClients[client][iCredits] += m_iCredits;
2073 if(g_eCvars[g_cvarCreditMessages][aCache])
2074 Chat(client, "%t", "Credits Earned For Playing", m_iCredits);
2075 Store_LogMessage(client, m_iCredits, "Earned for playing");
2076 }
2077
2078 return Plugin_Continue;
2079}
2080
2081public Action:Timer_DatabaseTimeout(Handle:timer, any:userid)
2082{
2083 // Database is connected successfully
2084 if(g_hDatabase != INVALID_HANDLE)
2085 return Plugin_Stop;
2086
2087 if(g_iDatabaseRetries < g_eCvars[g_cvarDatabaseRetries][aCache])
2088 {
2089 SQL_TConnect(SQLCallback_Connect, g_eCvars[g_cvarDatabaseEntry][sCache]);
2090 CreateTimer(Float:g_eCvars[g_cvarDatabaseTimeout][aCache], Timer_DatabaseTimeout);
2091 ++g_iDatabaseRetries;
2092 }
2093 else
2094 {
2095 SetFailState("Database connection failed to initialize after %d retrie(s)", g_eCvars[g_cvarDatabaseRetries][aCache]);
2096 }
2097
2098
2099 return Plugin_Stop;
2100}
2101
2102//////////////////////////////
2103// SQL CALLBACKS //
2104//////////////////////////////
2105
2106public SQLCallback_Connect(Handle:owner, Handle:hndl, const String:error[], any:data)
2107{
2108 if(hndl==INVALID_HANDLE)
2109 {
2110 SetFailState("Failed to connect to SQL database. Error: %s", error);
2111 }
2112 else
2113 {
2114 // If it's already connected we are good to go
2115 if(g_hDatabase != INVALID_HANDLE)
2116 return;
2117
2118 g_hDatabase = hndl;
2119 decl String:m_szDriver[2];
2120 SQL_ReadDriver(g_hDatabase, STRING(m_szDriver));
2121 if(m_szDriver[0] == 'm')
2122 {
2123 g_bMySQL = true;
2124 SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_players` (\
2125 `id` int(11) NOT NULL AUTO_INCREMENT,\
2126 `authid` varchar(32) NOT NULL,\
2127 `name` varchar(64) NOT NULL,\
2128 `credits` int(11) NOT NULL,\
2129 `date_of_join` int(11) NOT NULL,\
2130 `date_of_last_join` int(11) NOT NULL,\
2131 PRIMARY KEY (`id`),\
2132 UNIQUE KEY `id` (`id`),\
2133 UNIQUE KEY `authid` (`authid`)\
2134 )");
2135 SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_items` (\
2136 `id` int(11) NOT NULL AUTO_INCREMENT,\
2137 `player_id` int(11) NOT NULL,\
2138 `type` varchar(16) NOT NULL,\
2139 `unique_id` varchar(256) NOT NULL,\
2140 `date_of_purchase` int(11) NOT NULL,\
2141 `date_of_expiration` int(11) NOT NULL,\
2142 PRIMARY KEY (`id`)\
2143 )");
2144 SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_equipment` (\
2145 `player_id` int(11) NOT NULL,\
2146 `type` varchar(16) NOT NULL,\
2147 `unique_id` varchar(256) NOT NULL,\
2148 `slot` int(11) NOT NULL\
2149 )");
2150 SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_logs` (\
2151 `id` int(11) NOT NULL AUTO_INCREMENT,\
2152 `player_id` int(11) NOT NULL,\
2153 `credits` int(11) NOT NULL,\
2154 `reason` varchar(256) NOT NULL,\
2155 `date` int(11) NOT NULL,\
2156 PRIMARY KEY (`id`)\
2157 )");
2158 SQL_TQuery(g_hDatabase, SQLCallback_NoError, "ALTER TABLE store_items ADD COLUMN price_of_purchase int(11)");
2159 decl String:m_szQuery[512];
2160 Format(STRING(m_szQuery), "CREATE TABLE IF NOT EXISTS `%s` (\
2161 `id` int(11) NOT NULL AUTO_INCREMENT,\
2162 `parent_id` int(11) NOT NULL DEFAULT '-1',\
2163 `item_price` int(32) NOT NULL,\
2164 `item_type` varchar(64) NOT NULL,\
2165 `item_flag` varchar(64) NOT NULL,\
2166 `item_name` varchar(64) NOT NULL,\
2167 `additional_info` text NOT NULL,\
2168 `item_status` tinyint(1) NOT NULL,\
2169 `supported_game` varchar(64) NOT NULL,\
2170 PRIMARY KEY (`id`)\
2171 )", g_eCvars[g_cvarItemsTable][sCache]);
2172 SQL_TVoid(g_hDatabase, m_szQuery);
2173 }
2174 else
2175 {
2176 SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_players` (\
2177 `id` INTEGER PRIMARY KEY AUTOINCREMENT,\
2178 `authid` varchar(32) NOT NULL,\
2179 `name` varchar(64) NOT NULL,\
2180 `credits` int(11) NOT NULL,\
2181 `date_of_join` int(11) NOT NULL,\
2182 `date_of_last_join` int(11) NOT NULL\
2183 )");
2184 SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_items` (\
2185 `id` INTEGER PRIMARY KEY AUTOINCREMENT,\
2186 `player_id` int(11) NOT NULL,\
2187 `type` varchar(16) NOT NULL,\
2188 `unique_id` varchar(256) NOT NULL,\
2189 `date_of_purchase` int(11) NOT NULL,\
2190 `date_of_expiration` int(11) NOT NULL\
2191 )");
2192 SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_equipment` (\
2193 `player_id` int(11) NOT NULL,\
2194 `type` varchar(16) NOT NULL,\
2195 `unique_id` varchar(256) NOT NULL,\
2196 `slot` int(11) NOT NULL\
2197 )");
2198 SQL_TQuery(g_hDatabase, SQLCallback_NoError, "ALTER TABLE store_items ADD COLUMN price_of_purchase int(11)");
2199 if(strcmp(g_eCvars[g_cvarItemSource][sCache], "database")==0)
2200 {
2201
2202 SetFailState("Database item source can only be used with MySQL databases");
2203 }
2204 }
2205
2206 // Do some housekeeping
2207 decl String:m_szQuery[256];
2208 Format(STRING(m_szQuery), "DELETE FROM store_items WHERE `date_of_expiration` <> 0 AND `date_of_expiration` < %d", GetTime());
2209 SQL_TVoid(g_hDatabase, m_szQuery);
2210 }
2211}
2212
2213public SQLCallback_LoadClientInventory_Credits(Handle:owner, Handle:hndl, const String:error[], any:userid)
2214{
2215 if(hndl==INVALID_HANDLE)
2216 LogError("Error happened. Error: %s", error);
2217 else
2218 {
2219 new client = GetClientOfUserId(userid);
2220 if(!client)
2221 return;
2222
2223 decl String:m_szQuery[256];
2224 decl String:m_szSteamID[32];
2225 new m_iTime = GetTime();
2226 g_eClients[client][iUserId] = userid;
2227 g_eClients[client][iItems] = -1;
2228 GetLegacyAuthString(client, STRING(m_szSteamID), false);
2229 strcopy(g_eClients[client][szAuthId], 32, m_szSteamID[8]);
2230 GetClientName(client, g_eClients[client][szName], 64);
2231 SQL_EscapeString(g_hDatabase, g_eClients[client][szName], g_eClients[client][szNameEscaped], 128);
2232
2233 if(SQL_FetchRow(hndl))
2234 {
2235 g_eClients[client][iId] = SQL_FetchInt(hndl, 0);
2236 g_eClients[client][iCredits] = SQL_FetchInt(hndl, 3);
2237 g_eClients[client][iOriginalCredits] = SQL_FetchInt(hndl, 3);
2238 g_eClients[client][iDateOfJoin] = SQL_FetchInt(hndl, 4);
2239 g_eClients[client][iDateOfLastJoin] = m_iTime;
2240
2241 Format(STRING(m_szQuery), "SELECT * FROM store_items WHERE `player_id`=%d", g_eClients[client][iId]);
2242 SQL_TQuery(g_hDatabase, SQLCallback_LoadClientInventory_Items, m_szQuery, userid);
2243
2244 Store_LogMessage(client, g_eClients[client][iCredits], "Amount of credits when the player joined");
2245
2246 Store_SaveClientData(client);
2247 }
2248 else
2249 {
2250 Format(STRING(m_szQuery), "INSERT INTO store_players (`authid`, `name`, `credits`, `date_of_join`, `date_of_last_join`) VALUES(\"%s\", '%s', %d, %d, %d)",
2251 g_eClients[client][szAuthId], g_eClients[client][szNameEscaped], g_eCvars[g_cvarStartCredits][aCache], m_iTime, m_iTime);
2252 SQL_TQuery(g_hDatabase, SQLCallback_InsertClient, m_szQuery, userid);
2253 g_eClients[client][iCredits] = g_eCvars[g_cvarStartCredits][aCache];
2254 g_eClients[client][iOriginalCredits] = g_eCvars[g_cvarStartCredits][aCache];
2255 g_eClients[client][iDateOfJoin] = m_iTime;
2256 g_eClients[client][iDateOfLastJoin] = m_iTime;
2257 g_eClients[client][bLoaded] = true;
2258 g_eClients[client][iItems] = 0;
2259
2260 if(g_eCvars[g_cvarStartCredits][aCache] > 0)
2261 Store_LogMessage(client, g_eCvars[g_cvarStartCredits][aCache], "Start credits");
2262 }
2263
2264 g_eClients[client][hCreditTimer] = Store_CreditTimer(client);
2265 }
2266}
2267
2268public SQLCallback_LoadClientInventory_Items(Handle:owner, Handle:hndl, const String:error[], any:userid)
2269{
2270 if(hndl==INVALID_HANDLE)
2271 LogError("Error happened. Error: %s", error);
2272 else
2273 {
2274 new client = GetClientOfUserId(userid);
2275 if(!client)
2276 return;
2277
2278 decl String:m_szQuery[256];
2279 Format(STRING(m_szQuery), "SELECT * FROM store_equipment WHERE `player_id`=%d", g_eClients[client][iId]);
2280 SQL_TQuery(g_hDatabase, SQLCallback_LoadClientInventory_Equipment, m_szQuery, userid);
2281
2282 if(!SQL_GetRowCount(hndl))
2283 {
2284 g_eClients[client][bLoaded] = true;
2285 g_eClients[client][iItems] = 0;
2286 return;
2287 }
2288
2289 decl String:m_szUniqueId[PLATFORM_MAX_PATH];
2290 decl String:m_szType[16];
2291 decl m_iExpiration;
2292 decl m_iUniqueId;
2293 new m_iTime = GetTime();
2294
2295 new i = 0;
2296 while(SQL_FetchRow(hndl))
2297 {
2298 m_iUniqueId = -1;
2299 m_iExpiration = SQL_FetchInt(hndl, 5);
2300 if(m_iExpiration && m_iExpiration<=m_iTime)
2301 continue;
2302
2303 SQL_FetchString(hndl, 2, STRING(m_szType));
2304 SQL_FetchString(hndl, 3, STRING(m_szUniqueId));
2305 while((m_iUniqueId = Store_GetItemId(m_szType, m_szUniqueId, m_iUniqueId))!=-1)
2306 {
2307 g_eClientItems[client][i][iId] = SQL_FetchInt(hndl, 0);
2308 g_eClientItems[client][i][iUniqueId] = m_iUniqueId;
2309 g_eClientItems[client][i][bSynced] = true;
2310 g_eClientItems[client][i][bDeleted] = false;
2311 g_eClientItems[client][i][iDateOfPurchase] = SQL_FetchInt(hndl, 4);
2312 g_eClientItems[client][i][iDateOfExpiration] = m_iExpiration;
2313 g_eClientItems[client][i][iPriceOfPurchase] = SQL_FetchInt(hndl, 6);
2314
2315 ++i;
2316 }
2317 }
2318 g_eClients[client][iItems] = i;
2319 }
2320}
2321
2322public SQLCallback_LoadClientInventory_Equipment(Handle:owner, Handle:hndl, const String:error[], any:userid)
2323{
2324 if(hndl==INVALID_HANDLE)
2325 LogError("Error happened. Error: %s", error);
2326 else
2327 {
2328 new client = GetClientOfUserId(userid);
2329 if(!client)
2330 return;
2331
2332 decl String:m_szUniqueId[PLATFORM_MAX_PATH];
2333 decl String:m_szType[16];
2334 decl m_iUniqueId;
2335
2336 while(SQL_FetchRow(hndl))
2337 {
2338 SQL_FetchString(hndl, 1, STRING(m_szType));
2339 SQL_FetchString(hndl, 2, STRING(m_szUniqueId));
2340 m_iUniqueId = Store_GetItemId(m_szType, m_szUniqueId);
2341 if(m_iUniqueId == -1)
2342 continue;
2343
2344 if(!Store_HasClientItem(client, m_iUniqueId))
2345 Store_UnequipItem(client, m_iUniqueId);
2346 else
2347 Store_UseItem(client, m_iUniqueId, true, SQL_FetchInt(hndl, 3));
2348 }
2349 g_eClients[client][bLoaded] = true;
2350 }
2351}
2352
2353public SQLCallback_RefreshCredits(Handle:owner, Handle:hndl, const String:error[], any:userid)
2354{
2355 if(hndl==INVALID_HANDLE)
2356 LogError("Error happened. Error: %s", error);
2357 else
2358 {
2359 new client = GetClientOfUserId(userid);
2360 if(!client)
2361 return;
2362
2363 if(SQL_FetchRow(hndl))
2364 {
2365 g_eClients[client][iCredits] = SQL_FetchInt(hndl, 3);
2366 g_eClients[client][iOriginalCredits] = SQL_FetchInt(hndl, 3);
2367 }
2368 }
2369}
2370
2371public SQLCallback_InsertClient(Handle:owner, Handle:hndl, const String:error[], any:userid)
2372{
2373 if(hndl==INVALID_HANDLE)
2374 LogError("Error happened. Error: %s", error);
2375 else
2376 {
2377 new client = GetClientOfUserId(userid);
2378 if(!client)
2379 return;
2380
2381 g_eClients[client][iId] = SQL_GetInsertId(hndl);
2382 }
2383}
2384
2385public SQLCallback_ReloadConfig(Handle:owner, Handle:hndl, const String:error[], any:userid)
2386{
2387 if(hndl==INVALID_HANDLE)
2388 {
2389 SetFailState("Error happened reading the config table. The plugin cannot continue.", error);
2390 }
2391 else
2392 {
2393 decl String:m_szType[64];
2394 decl String:m_szFlag[64];
2395 decl String:m_szInfo[2048];
2396 decl String:m_szKey[64];
2397 decl String:m_szValue[256];
2398
2399 decl Handle:m_hKV;
2400
2401 decl bool:m_bSuccess;
2402
2403 decl m_iLength;
2404 decl m_iHandler;
2405 new m_iIndex = 0;
2406
2407 while(SQL_FetchRow(hndl))
2408 {
2409 if(g_iItems == STORE_MAX_ITEMS)
2410 return;
2411
2412 if(!SQL_FetchInt(hndl, 7))
2413 continue;
2414
2415 g_eItems[g_iItems][iId] = SQL_FetchInt(hndl, 0);
2416 g_eItems[g_iItems][iParent] = SQL_FetchInt(hndl, 1);
2417 g_eItems[g_iItems][iPrice] = SQL_FetchInt(hndl, 2);
2418
2419 IntToString(g_eItems[g_iItems][iId], g_eItems[g_iItems][szUniqueId], PLATFORM_MAX_PATH);
2420
2421 SQL_FetchString(hndl, 3, STRING(m_szType));
2422 m_iHandler = Store_GetTypeHandler(m_szType);
2423 if(m_iHandler == -1)
2424 continue;
2425
2426 g_eItems[g_iItems][iHandler] = m_iHandler;
2427
2428 SQL_FetchString(hndl, 4, STRING(m_szFlag));
2429 g_eItems[g_iItems][iFlagBits] = ReadFlagString(m_szFlag);
2430
2431 SQL_FetchString(hndl, 5, g_eItems[g_iItems][szName], ITEM_NAME_LENGTH);
2432 SQL_FetchString(hndl, 6, STRING(m_szInfo));
2433
2434 m_hKV = CreateKeyValues("Additional Info");
2435
2436 m_iLength = strlen(m_szInfo);
2437 while(m_iIndex != m_iLength)
2438 {
2439 m_iIndex += strcopy(m_szKey, StrContains(m_szInfo[m_iIndex], "="), m_szInfo[m_iIndex])+2;
2440 m_iIndex += strcopy(m_szValue, StrContains(m_szInfo[m_iIndex], "\";"), m_szInfo[m_iIndex])+2; // \"
2441
2442 KvJumpToKey(m_hKV, m_szKey, true);
2443 KvSetString(m_hKV, m_szKey, m_szValue);
2444
2445 m_bSuccess = true;
2446 if(g_eTypeHandlers[m_iHandler][fnConfig]!=INVALID_FUNCTION)
2447 {
2448 Call_StartFunction(g_eTypeHandlers[m_iHandler][hPlugin], g_eTypeHandlers[m_iHandler][fnConfig]);
2449 Call_PushCellRef(m_hKV);
2450 Call_PushCell(g_iItems);
2451 Call_Finish(m_bSuccess);
2452 }
2453
2454 if(m_bSuccess)
2455 ++g_iItems;
2456 }
2457 CloseHandle(m_hKV);
2458 }
2459 }
2460}
2461
2462public SQLCallback_ResetPlayer(Handle:owner, Handle:hndl, const String:error[], any:userid)
2463{
2464 if(hndl==INVALID_HANDLE)
2465 LogError("Error happened. Error: %s", error);
2466 else
2467 {
2468 new client = GetClientOfUserId(userid);
2469
2470 if(SQL_GetRowCount(hndl))
2471 {
2472 SQL_FetchRow(hndl);
2473 new id = SQL_FetchInt(hndl, 0);
2474 decl String:m_szAuthId[32];
2475 SQL_FetchString(hndl, 1, STRING(m_szAuthId));
2476
2477 decl String:m_szQuery[512];
2478 Format(STRING(m_szQuery), "DELETE FROM store_players WHERE id=%d", id);
2479 SQL_TVoid(g_hDatabase, m_szQuery);
2480 Format(STRING(m_szQuery), "DELETE FROM store_items WHERE player_id=%d", id);
2481 SQL_TVoid(g_hDatabase, m_szQuery);
2482 Format(STRING(m_szQuery), "DELETE FROM store_equipment WHERE player_id=%d", id);
2483 SQL_TVoid(g_hDatabase, m_szQuery);
2484
2485 ChatAll("%t", "Player Resetted", m_szAuthId);
2486
2487 }
2488 else
2489 if(client)
2490 Chat(client, "%t", "Credit No Match");
2491 }
2492}
2493
2494//////////////////////////////
2495// STOCKS //
2496//////////////////////////////
2497
2498public Store_LoadClientInventory(client)
2499{
2500 if(g_hDatabase == INVALID_HANDLE)
2501 {
2502 LogError("Database connection is lost or not yet initialized.");
2503 return;
2504 }
2505
2506 decl String:m_szQuery[256];
2507 decl String:m_szAuthId[32];
2508
2509 GetLegacyAuthString(client, STRING(m_szAuthId));
2510 if(m_szAuthId[0] == 0)
2511 return;
2512
2513 Format(STRING(m_szQuery), "SELECT * FROM store_players WHERE `authid`=\"%s\"", m_szAuthId[8]);
2514
2515 SQL_TQuery(g_hDatabase, SQLCallback_LoadClientInventory_Credits, m_szQuery, g_eClients[client][iUserId]);
2516}
2517
2518public Store_SaveClientInventory(client)
2519{
2520 if(g_hDatabase == INVALID_HANDLE)
2521 {
2522 LogError("Database connection is lost or not yet initialized.");
2523 return;
2524 }
2525
2526 // Player disconnected before his inventory was even fetched
2527 if(g_eClients[client][iCredits]==-1 && g_eClients[client][iItems]==-1)
2528 return;
2529
2530 decl String:m_szQuery[256];
2531 decl String:m_szType[16];
2532 decl String:m_szUniqueId[PLATFORM_MAX_PATH];
2533
2534 for(new i=0;i<g_eClients[client][iItems];++i)
2535 {
2536 strcopy(STRING(m_szType), g_eTypeHandlers[g_eItems[g_eClientItems[client][i][iUniqueId]][iHandler]][szType]);
2537 strcopy(STRING(m_szUniqueId), g_eItems[g_eClientItems[client][i][iUniqueId]][szUniqueId]);
2538
2539 if(!g_eClientItems[client][i][bSynced] && !g_eClientItems[client][i][bDeleted])
2540 {
2541 g_eClientItems[client][i][bSynced] = true;
2542 Format(STRING(m_szQuery), "INSERT INTO store_items (`player_id`, `type`, `unique_id`, `date_of_purchase`, `date_of_expiration`, `price_of_purchase`) VALUES(%d, \"%s\", \"%s\", %d, %d, %d)", g_eClients[client][iId], m_szType, m_szUniqueId, g_eClientItems[client][i][iDateOfPurchase], g_eClientItems[client][i][iDateOfExpiration], g_eClientItems[client][i][iPriceOfPurchase]);
2543 SQL_TVoid(g_hDatabase, m_szQuery);
2544 } else if(g_eClientItems[client][i][bSynced] && g_eClientItems[client][i][bDeleted])
2545 {
2546 // Might have been synced already but ID wasn't acquired
2547 if(g_eClientItems[client][i][iId]==-1)
2548 Format(STRING(m_szQuery), "DELETE FROM store_items WHERE `player_id`=%d AND `type`=\"%s\" AND `unique_id`=\"%s\"", g_eClients[client][iId], m_szType, m_szUniqueId);
2549 else
2550 Format(STRING(m_szQuery), "DELETE FROM store_items WHERE `id`=%d", g_eClientItems[client][i][iId]);
2551 SQL_TVoid(g_hDatabase, m_szQuery);
2552 }
2553 }
2554}
2555
2556public Store_SaveClientEquipment(client)
2557{
2558 decl String:m_szQuery[256];
2559 decl m_iId;
2560 for(new i=0;i<STORE_MAX_HANDLERS;++i)
2561 {
2562 for(new a=0;a<STORE_MAX_SLOTS;++a)
2563 {
2564 m_iId = i*STORE_MAX_SLOTS+a;
2565 if(g_eClients[client][aEquipmentSynced][m_iId] == g_eClients[client][aEquipment][m_iId])
2566 continue;
2567 else if(g_eClients[client][aEquipmentSynced][m_iId] != -2)
2568 if(g_eClients[client][aEquipment][m_iId]==-1)
2569 Format(STRING(m_szQuery), "DELETE FROM store_equipment WHERE `player_id`=%d AND `type`=\"%s\" AND `slot`=%d", g_eClients[client][iId], g_eTypeHandlers[i][szType], a);
2570 else
2571 Format(STRING(m_szQuery), "UPDATE store_equipment SET `unique_id`=\"%s\" WHERE `player_id`=%d AND `type`=\"%s\" AND `slot`=%d", g_eItems[g_eClients[client][aEquipment][m_iId]][szUniqueId], g_eClients[client][iId], g_eTypeHandlers[i][szType], a);
2572
2573 else
2574 Format(STRING(m_szQuery), "INSERT INTO store_equipment (`player_id`, `type`, `unique_id`, `slot`) VALUES(%d, \"%s\", \"%s\", %d)", g_eClients[client][iId], g_eTypeHandlers[i][szType], g_eItems[g_eClients[client][aEquipment][m_iId]][szUniqueId], a);
2575
2576 SQL_TVoid(g_hDatabase, m_szQuery);
2577 g_eClients[client][aEquipmentSynced][m_iId] = g_eClients[client][aEquipment][m_iId];
2578 }
2579 }
2580}
2581
2582public Store_SaveClientData(client)
2583{
2584 if(g_hDatabase == INVALID_HANDLE)
2585 {
2586 LogError("Database connection is lost or not yet initialized.");
2587 return;
2588 }
2589
2590 if((g_eClients[client][iCredits]==-1 && g_eClients[client][iItems]==-1) || !g_eClients[client][bLoaded])
2591 return;
2592
2593 decl String:m_szQuery[256];
2594 if(g_bMySQL)
2595 Format(STRING(m_szQuery), "UPDATE store_players SET `credits`=GREATEST(`credits`+%d,0), `date_of_last_join`=%d, `name`='%s' WHERE `id`=%d", g_eClients[client][iCredits]-g_eClients[client][iOriginalCredits], g_eClients[client][iDateOfLastJoin], g_eClients[client][szNameEscaped], g_eClients[client][iId]);
2596 else
2597 Format(STRING(m_szQuery), "UPDATE store_players SET `credits`=MAX(`credits`+%d,0), `date_of_last_join`=%d, `name`='%s' WHERE `id`=%d", g_eClients[client][iCredits]-g_eClients[client][iOriginalCredits], g_eClients[client][iDateOfLastJoin], g_eClients[client][szNameEscaped], g_eClients[client][iId]);
2598
2599 g_eClients[client][iOriginalCredits] = g_eClients[client][iCredits];
2600
2601 SQL_TVoid(g_hDatabase, m_szQuery);
2602}
2603
2604public Store_DisconnectClient(client)
2605{
2606 Store_LogMessage(client, g_eClients[client][iCredits], "Amount of credits when the player left");
2607 g_eClients[client][iCredits] = -1;
2608 g_eClients[client][iOriginalCredits] = -1;
2609 g_eClients[client][iItems] = -1;
2610 g_eClients[client][bLoaded] = false;
2611 ClearTimer(g_eClients[client][hCreditTimer]);
2612}
2613
2614Store_GetItemId(String:type[], String:uid[], start=-1)
2615{
2616 for(new i=start+1;i<g_iItems;++i)
2617 if(strcmp(g_eTypeHandlers[g_eItems[i][iHandler]][szType], type)==0 && strcmp(g_eItems[i][szUniqueId], uid)==0 && g_eItems[i][iPrice] >= 0)
2618 return i;
2619 return -1;
2620}
2621
2622Store_BuyItem(client, itemid, plan=-1)
2623{
2624 if(Store_HasClientItem(client, itemid))
2625 return;
2626
2627 new m_iPrice = 0;
2628 if(plan==-1)
2629 m_iPrice = g_eItems[itemid][iPrice];
2630 else
2631 m_iPrice = g_ePlans[itemid][plan][iPrice];
2632
2633 if(g_eClients[client][iCredits]<m_iPrice)
2634 return;
2635
2636 new m_iId = g_eClients[client][iItems]++;
2637 g_eClientItems[client][m_iId][iId] = -1;
2638 g_eClientItems[client][m_iId][iUniqueId] = itemid;
2639 g_eClientItems[client][m_iId][iDateOfPurchase] = GetTime();
2640 g_eClientItems[client][m_iId][iDateOfExpiration] = (plan==-1?0:(g_ePlans[itemid][plan][iTime]?GetTime()+g_ePlans[itemid][plan][iTime]:0));
2641 g_eClientItems[client][m_iId][iPriceOfPurchase] = m_iPrice;
2642 g_eClientItems[client][m_iId][bSynced] = false;
2643 g_eClientItems[client][m_iId][bDeleted] = false;
2644
2645 g_eClients[client][iCredits] -= m_iPrice;
2646
2647 Store_LogMessage(client, -g_eItems[itemid][iPrice], "Bought a %s %s", g_eItems[itemid][szName], g_eTypeHandlers[g_eItems[itemid][iHandler]][szType]);
2648
2649 Chat(client, "%t", "Chat Bought Item", g_eItems[itemid][szName], g_eTypeHandlers[g_eItems[itemid][iHandler]][szType]);
2650}
2651
2652public Store_SellItem(client, itemid)
2653{
2654 new m_iCredits = RoundToFloor(Store_GetClientItemPrice(client, itemid)*Float:g_eCvars[g_cvarSellRatio][aCache]);
2655 new uid = Store_GetClientItemId(client, itemid);
2656 if(g_eClientItems[client][uid][iDateOfExpiration] != 0)
2657 {
2658 new m_iLength = g_eClientItems[client][uid][iDateOfExpiration]-g_eClientItems[client][uid][iDateOfPurchase];
2659 new m_iLeft = g_eClientItems[client][uid][iDateOfExpiration]-GetTime();
2660 if(m_iLeft<0)
2661 m_iLeft = 0;
2662 m_iCredits = RoundToCeil(m_iCredits*float(m_iLeft)/float(m_iLength));
2663 }
2664
2665 g_eClients[client][iCredits] += m_iCredits;
2666 Chat(client, "%t", "Chat Sold Item", g_eItems[itemid][szName], g_eTypeHandlers[g_eItems[itemid][iHandler]][szType]);
2667
2668 Store_LogMessage(client, m_iCredits, "Sold a %s %s", g_eItems[itemid][szName], g_eTypeHandlers[g_eItems[itemid][iHandler]][szType]);
2669
2670 Store_RemoveItem(client, itemid);
2671}
2672
2673public Store_GiftItem(client, receiver, item)
2674{
2675 new m_iId = g_eClientItems[client][item][iUniqueId];
2676 new target = g_iMenuClient[client];
2677 g_eClientItems[client][item][bDeleted] = true;
2678 Store_UnequipItem(client, m_iId);
2679
2680 g_eClientItems[receiver][g_eClients[receiver][iItems]][iId] = -1;
2681 g_eClientItems[receiver][g_eClients[receiver][iItems]][iUniqueId] = m_iId;
2682 g_eClientItems[receiver][g_eClients[receiver][iItems]][bSynced] = false;
2683 g_eClientItems[receiver][g_eClients[receiver][iItems]][bDeleted] = false;
2684 g_eClientItems[receiver][g_eClients[receiver][iItems]][iDateOfPurchase] = g_eClientItems[target][item][iDateOfPurchase];
2685 g_eClientItems[receiver][g_eClients[receiver][iItems]][iDateOfExpiration] = g_eClientItems[target][item][iDateOfExpiration];
2686 g_eClientItems[receiver][g_eClients[receiver][iItems]][iPriceOfPurchase] = g_eClientItems[target][item][iPriceOfPurchase];
2687
2688 ++g_eClients[receiver][iItems];
2689
2690 Chat(client, "%t", "Chat Gift Item Sent", g_eClients[receiver][szName], g_eItems[m_iId][szName], g_eTypeHandlers[g_eItems[m_iId][iHandler]][szType]);
2691 Chat(receiver, "%t", "Chat Gift Item Received", g_eClients[target][szName], g_eItems[m_iId][szName], g_eTypeHandlers[g_eItems[m_iId][iHandler]][szType]);
2692
2693 Store_LogMessage(client, 0, "Gifted a %s to %N", g_eItems[m_iId][szName], receiver);
2694}
2695
2696public Store_GetClientItemId(client, itemid)
2697{
2698 for(new i=0;i<g_eClients[client][iItems];++i)
2699 {
2700 if(g_eClientItems[client][i][iUniqueId] == itemid && !g_eClientItems[client][i][bDeleted])
2701 return i;
2702 }
2703
2704 return -1;
2705}
2706
2707public Handle:Store_CreditTimer(client)
2708{
2709 return CreateTimer(g_eCvars[g_cvarCreditTimer][aCache], Timer_CreditTimer, g_eClients[client][iUserId], TIMER_REPEAT);
2710}
2711
2712public ReadCoreCFG()
2713{
2714 new String:m_szFile[PLATFORM_MAX_PATH];
2715 BuildPath(Path_SM, STRING(m_szFile), "configs/core.cfg");
2716
2717 new Handle:hParser = SMC_CreateParser();
2718 new String:error[128];
2719 new line = 0;
2720 new col = 0;
2721
2722 SMC_SetReaders(hParser, Config_NewSection, Config_KeyValue, Config_EndSection);
2723 SMC_SetParseEnd(hParser, Config_End);
2724
2725 new SMCError:result = SMC_ParseFile(hParser, m_szFile, line, col);
2726 CloseHandle(hParser);
2727
2728 if (result != SMCError_Okay)
2729 {
2730 SMC_GetErrorString(result, error, sizeof(error));
2731 LogError("%s on line %d, col %d of %s", error, line, col, m_szFile);
2732 }
2733
2734}
2735
2736public SMCResult:Config_NewSection(Handle:parser, const String:section[], bool:quotes)
2737{
2738 if (StrEqual(section, "Core"))
2739 {
2740 return SMCParse_Continue;
2741 }
2742 return SMCParse_Continue;
2743}
2744
2745public SMCResult:Config_KeyValue(Handle:parser, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
2746{
2747 if(StrEqual(key, "PublicChatTrigger", false))
2748 PublicChatTrigger = value[0];
2749 else if(StrEqual(key, "SilentChatTrigger", false))
2750 SilentChatTrigger = value[0];
2751
2752 return SMCParse_Continue;
2753}
2754
2755public SMCResult:Config_EndSection(Handle:parser)
2756{
2757 return SMCParse_Continue;
2758}
2759
2760public Config_End(Handle:parser, bool:halted, bool:failed)
2761{
2762}
2763
2764public Store_ReloadConfig()
2765{
2766 g_iItems = 0;
2767
2768 for(new i=0;i<g_iTypeHandlers;++i)
2769 {
2770 if(g_eTypeHandlers[i][fnReset] != INVALID_FUNCTION)
2771 {
2772 Call_StartFunction(g_eTypeHandlers[i][hPlugin], g_eTypeHandlers[i][fnReset]);
2773 Call_Finish();
2774 }
2775 }
2776
2777 if(strcmp(g_eCvars[g_cvarItemSource][sCache], "database")==0)
2778 {
2779 decl String:m_szQuery[64];
2780 Format(STRING(m_szQuery), "SELECT * FROM %s WHERE supported_games LIKE \"%%%s%%\" OR supported_games = \"\"", g_eCvars[g_cvarItemsTable][sCache], g_szGameDir);
2781 SQL_TQuery(g_hDatabase, SQLCallback_ReloadConfig, m_szQuery);
2782 }
2783 else
2784 {
2785 new String:m_szFile[PLATFORM_MAX_PATH];
2786 BuildPath(Path_SM, STRING(m_szFile), "configs/store/items.txt");
2787 new Handle:m_hKV = CreateKeyValues("Store");
2788 FileToKeyValues(m_hKV, m_szFile);
2789 if (!KvGotoFirstSubKey(m_hKV))
2790 {
2791
2792 SetFailState("Failed to read configs/store/items.txt");
2793 }
2794 Store_WalkConfig(m_hKV);
2795 CloseHandle(m_hKV);
2796 }
2797}
2798
2799Store_WalkConfig(&Handle:kv, parent=-1)
2800{
2801 decl String:m_szType[32];
2802 decl String:m_szGame[64];
2803 decl String:m_szFlags[64];
2804 decl m_iHandler;
2805 decl bool:m_bSuccess;
2806 do
2807 {
2808 if(g_iItems == STORE_MAX_ITEMS)
2809 continue;
2810 if (KvGetNum(kv, "enabled", 1) && KvGetNum(kv, "type", -1)==-1 && KvGotoFirstSubKey(kv))
2811 {
2812 KvGoBack(kv);
2813 KvGetSectionName(kv, g_eItems[g_iItems][szName], 64);
2814 KvGetSectionName(kv, g_eItems[g_iItems][szUniqueId], 64);
2815 ReplaceString(g_eItems[g_iItems][szName], 64, "\\n", "\n");
2816 KvGetString(kv, "shortcut", g_eItems[g_iItems][szShortcut], 64);
2817 KvGetString(kv, "flag", STRING(m_szFlags));
2818 KvGetString(kv, "games", STRING(m_szGame));
2819 if(m_szGame[0] != 0 && StrContains(m_szGame, g_szGameDir)==-1)
2820 continue;
2821 g_eItems[g_iItems][iFlagBits] = ReadFlagString(m_szFlags);
2822 g_eItems[g_iItems][iPrice] = KvGetNum(kv, "price", -1);
2823 g_eItems[g_iItems][bBuyable] = (KvGetNum(kv, "buyable", 1)?true:false);
2824 g_eItems[g_iItems][bIgnoreVIP] = (KvGetNum(kv, "ignore_vip", 0)?true:false);
2825 g_eItems[g_iItems][iHandler] = g_iPackageHandler;
2826 KvGotoFirstSubKey(kv);
2827
2828 g_eItems[g_iItems][iParent] = parent;
2829
2830 Store_WalkConfig(kv, g_iItems++);
2831 KvGoBack(kv);
2832 }
2833 else
2834 {
2835 if(!KvGetNum(kv, "enabled", 1))
2836 continue;
2837
2838 KvGetString(kv, "games", STRING(m_szGame));
2839 if(m_szGame[0] != 0 && StrContains(m_szGame, g_szGameDir)==-1)
2840 continue;
2841
2842 g_eItems[g_iItems][iParent] = parent;
2843 KvGetSectionName(kv, g_eItems[g_iItems][szName], ITEM_NAME_LENGTH);
2844 g_eItems[g_iItems][iPrice] = KvGetNum(kv, "price");
2845 g_eItems[g_iItems][bBuyable] = KvGetNum(kv, "buyable", 1)?true:false;
2846 g_eItems[g_iItems][bIgnoreVIP] = (KvGetNum(kv, "ignore_vip", 0)?true:false);
2847
2848
2849 KvGetString(kv, "type", STRING(m_szType));
2850 m_iHandler = Store_GetTypeHandler(m_szType);
2851 if(m_iHandler == -1)
2852 continue;
2853
2854 KvGetString(kv, "flag", STRING(m_szFlags));
2855 g_eItems[g_iItems][iFlagBits] = ReadFlagString(m_szFlags);
2856 g_eItems[g_iItems][iHandler] = m_iHandler;
2857
2858 if(KvGetNum(kv, "unique_id", -1)==-1)
2859 KvGetString(kv, g_eTypeHandlers[m_iHandler][szUniqueKey], g_eItems[g_iItems][szUniqueId], PLATFORM_MAX_PATH);
2860 else
2861 KvGetString(kv, "unique_id", g_eItems[g_iItems][szUniqueId], PLATFORM_MAX_PATH);
2862
2863 if(KvJumpToKey(kv, "Plans"))
2864 {
2865 KvGotoFirstSubKey(kv);
2866 new index=0;
2867 do
2868 {
2869 KvGetSectionName(kv, g_ePlans[g_iItems][index][szName], ITEM_NAME_LENGTH);
2870 g_ePlans[g_iItems][index][iPrice] = KvGetNum(kv, "price");
2871 g_ePlans[g_iItems][index][iTime] = KvGetNum(kv, "time");
2872 ++index;
2873 } while (KvGotoNextKey(kv));
2874
2875 g_eItems[g_iItems][iPlans]=index;
2876
2877 KvGoBack(kv);
2878 KvGoBack(kv);
2879 }
2880
2881 if(g_eItems[g_iItems][hAttributes])
2882 CloseHandle(g_eItems[g_iItems][hAttributes]);
2883 g_eItems[g_iItems][hAttributes] = INVALID_HANDLE;
2884 if(KvJumpToKey(kv, "Attributes"))
2885 {
2886 g_eItems[g_iItems][hAttributes] = CreateTrie();
2887
2888 KvGotoFirstSubKey(kv, false);
2889
2890 new String:m_szAttribute[64];
2891 new String:m_szValue[64];
2892 do
2893 {
2894 KvGetSectionName(kv, STRING(m_szAttribute));
2895 KvGetString(kv, NULL_STRING, STRING(m_szValue));
2896 SetTrieString(g_eItems[g_iItems][hAttributes], m_szAttribute, m_szValue);
2897 } while (KvGotoNextKey(kv, false));
2898
2899 KvGoBack(kv);
2900 KvGoBack(kv);
2901 }
2902
2903 m_bSuccess = true;
2904 if(g_eTypeHandlers[m_iHandler][fnConfig]!=INVALID_FUNCTION)
2905 {
2906 Call_StartFunction(g_eTypeHandlers[m_iHandler][hPlugin], g_eTypeHandlers[m_iHandler][fnConfig]);
2907 Call_PushCellRef(kv);
2908 Call_PushCell(g_iItems);
2909 Call_Finish(m_bSuccess);
2910 }
2911
2912 if(m_bSuccess)
2913 ++g_iItems;
2914 }
2915 } while (KvGotoNextKey(kv));
2916}
2917
2918public Store_GetTypeHandler(String:type[])
2919{
2920 for(new i=0;i<g_iTypeHandlers;++i)
2921 {
2922 if(strcmp(g_eTypeHandlers[i][szType], type)==0)
2923 return i;
2924 }
2925 return -1;
2926}
2927
2928public Store_GetMenuHandler(String:id[])
2929{
2930 for(new i=0;i<g_iMenuHandlers;++i)
2931 {
2932 if(strcmp(g_eMenuHandlers[i][szIdentifier], id)==0)
2933 return i;
2934 }
2935 return -1;
2936}
2937
2938public bool:Store_IsEquipped(client, itemid)
2939{
2940 for(new i=0;i<STORE_MAX_SLOTS;++i)
2941 if(g_eClients[client][aEquipment][g_eItems[itemid][iHandler]*STORE_MAX_SLOTS+i] == itemid)
2942 return true;
2943 return false;
2944}
2945
2946public Store_GetExpiration(client, itemid)
2947{
2948 new uid = Store_GetClientItemId(client, itemid);
2949 if(uid<0)
2950 return 0;
2951 return g_eClientItems[client][uid][iDateOfExpiration];
2952}
2953
2954Store_UseItem(client, itemid, bool:synced=false, slot=0)
2955{
2956 new m_iSlot = slot;
2957 if(g_eTypeHandlers[g_eItems[itemid][iHandler]][fnUse] != INVALID_FUNCTION)
2958 {
2959 new m_iReturn = -1;
2960 Call_StartFunction(g_eTypeHandlers[g_eItems[itemid][iHandler]][hPlugin], g_eTypeHandlers[g_eItems[itemid][iHandler]][fnUse]);
2961 Call_PushCell(client);
2962 Call_PushCell(itemid);
2963 Call_Finish(m_iReturn);
2964
2965 if(m_iReturn != -1)
2966 m_iSlot = m_iReturn;
2967 }
2968
2969 if(g_eTypeHandlers[g_eItems[itemid][iHandler]][bEquipable])
2970 {
2971 g_eClients[client][aEquipment][g_eItems[itemid][iHandler]*STORE_MAX_SLOTS+m_iSlot]=itemid;
2972 if(synced)
2973 g_eClients[client][aEquipmentSynced][g_eItems[itemid][iHandler]*STORE_MAX_SLOTS+m_iSlot]=itemid;
2974 }
2975 else if(m_iSlot == 0)
2976 {
2977 Store_RemoveItem(client, itemid);
2978 return 1;
2979 }
2980 return 0;
2981}
2982
2983Store_UnequipItem(client, itemid, bool:fn=true)
2984{
2985 new m_iSlot = 0;
2986 if(fn && itemid > 0 && g_eTypeHandlers[g_eItems[itemid][iHandler]][fnRemove] != INVALID_FUNCTION)
2987 {
2988 Call_StartFunction(g_eTypeHandlers[g_eItems[itemid][iHandler]][hPlugin], g_eTypeHandlers[g_eItems[itemid][iHandler]][fnRemove]);
2989 Call_PushCell(client);
2990 Call_PushCell(itemid);
2991 Call_Finish(m_iSlot);
2992 }
2993
2994 decl m_iId;
2995 if(g_eItems[itemid][iHandler] != g_iPackageHandler)
2996 {
2997 m_iId = g_eItems[itemid][iHandler]*STORE_MAX_SLOTS+m_iSlot;
2998 if(g_eClients[client][aEquipmentSynced][m_iId]==-2)
2999 g_eClients[client][aEquipment][m_iId]=-2;
3000 else
3001 g_eClients[client][aEquipment][m_iId]=-1;
3002 }
3003 else
3004 {
3005 for(new i=0;i<STORE_MAX_HANDLERS;++i)
3006 {
3007 for(new a=0;i<STORE_MAX_SLOTS;++i)
3008 {
3009 if(g_eClients[client][aEquipment][i+a] < 0)
3010 continue;
3011 m_iId = i*STORE_MAX_SLOTS+a;
3012 if(Store_IsItemInBoughtPackage(client, g_eClients[client][aEquipment][m_iId], itemid))
3013 if(g_eClients[client][aEquipmentSynced][m_iId]==-2)
3014 g_eClients[client][aEquipment][m_iId]=-2;
3015 else
3016 g_eClients[client][aEquipment][m_iId]=-1;
3017 }
3018 }
3019 }
3020}
3021
3022Store_GetEquippedItemFromHandler(client, handler, slot=0)
3023{
3024 return g_eClients[client][aEquipment][handler*STORE_MAX_SLOTS+slot];
3025}
3026
3027Store_PackageHasClientItem(client, packageid, bool:invmode=false)
3028{
3029 new m_iFlags = GetUserFlagBits(client);
3030 if(!g_eCvars[g_cvarShowVIP][aCache] && !GetClientPrivilege(client, g_eItems[packageid][iFlagBits], m_iFlags))
3031 return false;
3032 for(new i=0;i<g_iItems;++i)
3033 if(g_eItems[i][iParent] == packageid && (g_eCvars[g_cvarShowVIP][aCache] || GetClientPrivilege(client, g_eItems[i][iFlagBits], m_iFlags)) && (invmode && Store_HasClientItem(client, i) || !invmode))
3034 if((g_eItems[i][iHandler] == g_iPackageHandler && Store_PackageHasClientItem(client, i, invmode)) || g_eItems[i][iHandler] != g_iPackageHandler)
3035 return true;
3036 return false;
3037}
3038
3039Store_LogMessage(client, credits, const String:message[], ...)
3040{
3041 if(!g_eCvars[g_cvarLogging][aCache])
3042 return;
3043
3044 decl String:m_szReason[256];
3045 VFormat(STRING(m_szReason), message, 4);
3046
3047 if(g_eCvars[g_cvarLogging][aCache] == 1)
3048 {
3049 LogToOpenFileEx(g_hLogFile, "%N's credits have changed by %d. Reason: %s", client, credits, m_szReason);
3050 } else if(g_eCvars[g_cvarLogging][aCache] == 2)
3051 {
3052 decl String:m_szQuery[256];
3053 Format(STRING(m_szQuery), "INSERT INTO store_logs (player_id, credits, reason, date) VALUES(%d, %d, \"%s\", %d)", g_eClients[client][iId], credits, m_szReason, GetTime());
3054 SQL_TVoid(g_hDatabase, m_szQuery);
3055 }
3056}
3057
3058Store_GetLowestPrice(itemid)
3059{
3060 if(g_eItems[itemid][iPlans]==0)
3061 return g_eItems[itemid][iPrice];
3062
3063 new m_iLowest=g_ePlans[itemid][0][iPrice];
3064 for(new i=1;i<g_eItems[itemid][iPlans];++i)
3065 {
3066 if(m_iLowest>g_ePlans[itemid][i][iPrice])
3067 m_iLowest = g_ePlans[itemid][i][iPrice];
3068 }
3069 return m_iLowest;
3070}
3071
3072Store_GetClientItemPrice(client, itemid)
3073{
3074 new uid = Store_GetClientItemId(client, itemid);
3075 if(uid<0)
3076 return 0;
3077
3078 if(g_eClientItems[client][uid][iPriceOfPurchase]==0)
3079 return g_eItems[itemid][iPrice];
3080
3081 return g_eClientItems[client][uid][iPriceOfPurchase];
3082}
3083
3084public Store_OnPaymentReceived(FriendID, quanity, Handle:data)
3085{
3086 LoopIngamePlayers(i)
3087 {
3088 if(GetFriendID(i)==FriendID)
3089 {
3090 Store_SaveClientData(i);
3091
3092 new m_unMod = FriendID % 2;
3093 new m_unAccountID = (FriendID-m_unMod)/2;
3094
3095 decl String:m_szQuery[256];
3096 Format(STRING(m_szQuery), "SELECT * FROM store_players WHERE `authid`=\"%d:%d\"", m_unMod, m_unAccountID);
3097 SQL_TQuery(g_hDatabase, SQLCallback_LoadClientInventory_Credits, m_szQuery, GetClientUserId(i));
3098 break;
3099 }
3100 }
3101}