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