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