Advertisement
Guest User

Untitled

a guest
Nov 12th, 2018
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. registerPlugin({
  2.     name: 'SConomy NG',
  3.     version: '1.7.2',
  4.     description: 'This plugin will give you a currency system',
  5.     author: 'Mmoi <mmoi.addic7ed@gmail.com>',
  6.     vars: [
  7.         /*** General ***/
  8.         {
  9.             name:  'unused0',
  10.             title: 'General'
  11.         },
  12.         {
  13.             name:  'useMinute',
  14.             title: 'Use minutes instead of seconds as interval unit (reduce CPU / disk usage)',
  15.             type:  'checkbox',
  16.             indent: 3
  17.         },
  18.         {
  19.             name:  'tick',
  20.             title: 'Currency generation interval (in seconds)',
  21.             type:  'number',
  22.             placeholder: 1,
  23.             indent: 3
  24.         },
  25.         {
  26.             name:  'currencyAmount',
  27.             title: 'Currency amount generated per interval',
  28.             type:  'number',
  29.             placeholder: 1,
  30.             indent: 3
  31.         },
  32.         {
  33.             name:  'maxCurrency',
  34.             title: 'Maximum generated currency (no other currency will be generated after the user reaches this value)',
  35.             type:  'string',
  36.             placeholder: 9007199254740991,
  37.             indent: 3
  38.         },
  39.         {
  40.             name:  'viewDistance',
  41.             title: 'Number of digits to be shown after the comma',
  42.             type:  'number',
  43.             placeholder: 0,
  44.             indent: 3
  45.         },
  46.         {
  47.             name:  'diskIOLimit',
  48.             title: 'User progress [progress only, not wallet amount] save to disk interval (in seconds, bigger = better | reduce disk load) [0 = disabled, max = Currency generation interval]',
  49.             type:  'number',
  50.             placeholder: 10,
  51.             indent: 3
  52.         },
  53.         {
  54.             name: 'blacklistedChannels',
  55.             title: 'Don\'t generate currency for users within those channels:',
  56.             type: 'array',
  57.             vars: [{
  58.                 name:  'channel',
  59.                 title: 'Channel',
  60.                 type:  'channel'
  61.             }],
  62.             indent: 3
  63.         },
  64.         {
  65.             name:  'storageProvider',
  66.             title: 'Storage provider (default: internal - private)',
  67.             type: 'select',
  68.             options: [
  69.                 'Internal / Private',
  70.                 'Internal / Public'
  71.             ],
  72.             indent: 3
  73.         },
  74.         {
  75.             name:  'allowDumbBuy',
  76.             title: 'Allow user to buy a group even if the user already has the group',
  77.             type:  'checkbox',
  78.             indent: 3
  79.         },
  80.         {
  81.             name:  'enableGiving',
  82.             title: 'Allow user to give other money',
  83.             type:  'checkbox',
  84.             indent: 3
  85.         },
  86.         {
  87.             name:  'donationFee',
  88.             title: 'Donation fees (in percent)',
  89.             type:  'number',
  90.             placeholder: 10,
  91.             indent: 6,
  92.             conditions: [{
  93.                 field: 'enableGiving',
  94.                 value: true
  95.             }]
  96.         },
  97.         {
  98.             name:  'givingOnlineOnly',
  99.             title: 'Only allow to give to online users (exception to admins)',
  100.             type:  'checkbox',
  101.             indent: 6,
  102.             conditions: [{
  103.                 field: 'enableGiving',
  104.                 value: true
  105.             }]
  106.         },
  107.         {
  108.             name:  'limitGN',
  109.             title: 'Limit maximum group number per user (does not sell to user who have too many groups)',
  110.             type:  'checkbox',
  111.             indent: 3
  112.         },
  113.         {
  114.             name:  'limitGNOnlySold',
  115.             title: 'Limitation only applied to groups that are in the store',
  116.             type:  'checkbox',
  117.             indent: 6,
  118.             conditions: [{
  119.                 field: 'limitGN',
  120.                 value: true
  121.             }]
  122.         },
  123.         {
  124.             name:  'limitGNValue',
  125.             title: 'Maximum of allowed groups',
  126.             type:  'number',
  127.             placeholder: 2,
  128.             indent: 6,
  129.             conditions: [{
  130.                 field: 'limitGN',
  131.                 value: true
  132.             }]
  133.         },
  134.         {
  135.             name:  'historyEnable',
  136.             title: 'Enable the store history (who bought something, when. Display in channel desciption)',
  137.             type:  'checkbox',
  138.             indent: 3
  139.         },
  140.         {
  141.             name:  'historyIncludeSell',
  142.             title: 'Include refunds in the store history',
  143.             type:  'checkbox',
  144.             indent: 6,
  145.             conditions: [{
  146.                 field: 'historyEnable',
  147.                 value: true
  148.             }]
  149.         },
  150.         {
  151.             name:  'historyChannel',
  152.             title: 'Channel in which the history will be placed (channel description)',
  153.             type:  'channel',
  154.             indent: 6,
  155.             conditions: [{
  156.                 field: 'historyEnable',
  157.                 value: true
  158.             }]
  159.         },
  160.         {
  161.             name:  'historyLimit',
  162.             title: 'Number of entry in the history (200 should be the maximum)',
  163.             type:  'number',
  164.             placeholder: 10,
  165.             indent: 6,
  166.             conditions: [{
  167.                 field: 'historyEnable',
  168.                 value: true
  169.             }]
  170.         },
  171.  
  172.         /*** Commands ***/
  173.         {
  174.             name:  'unused1',
  175.             title: 'Command customization'
  176.         },
  177.         {
  178.             name:  'helpCommand',
  179.             title: 'Help for users',
  180.             type:  'string',
  181.             placeholder: '!schelp',
  182.             indent: 3
  183.         },
  184.         {
  185.             name:  'command',
  186.             title: 'Check wallet',
  187.             type:  'string',
  188.             placeholder: '!money',
  189.             indent: 3
  190.         },
  191.         {
  192.             name:  'storeCommand',
  193.             title: 'Check available servergroup in the store',
  194.             type:  'string',
  195.             placeholder: '!store',
  196.             indent: 3
  197.         },
  198.         {
  199.             name:  'buyCommand',
  200.             title: 'Buy a servergroup from the store',
  201.             type:  'string',
  202.             placeholder: '!buy',
  203.             indent: 3
  204.         },
  205.         {
  206.             name:  'sellCommand',
  207.             title: 'Sell a servergroup',
  208.             type:  'string',
  209.             placeholder: '!sell',
  210.             indent: 3
  211.         },
  212.         {
  213.             name:  'giveCommand',
  214.             title: 'Give user money',
  215.             type:  'string',
  216.             placeholder: '!give',
  217.             indent: 3,
  218.             conditions: [{
  219.                 field: 'enableGiving',
  220.                 value: true
  221.             }],
  222.         },
  223.         {
  224.             name:  'getUserCommand',
  225.             title: 'See the specified user wallet',
  226.             type:  'string',
  227.             placeholder: '!seemoney',
  228.             indent: 3
  229.         },
  230.         {
  231.             name:  'setUserCommand',
  232.             title: 'Set the specified user wallet',
  233.             type:  'string',
  234.             placeholder: '!setmoney',
  235.             indent: 3
  236.         },
  237.         {
  238.             name:  'addUserCommand',
  239.             title: 'Add amount to the specified user wallet',
  240.             type:  'string',
  241.             placeholder: '!addmoney <user> <amount>',
  242.             indent: 3
  243.         },
  244.         {
  245.             name:  'removeUserCommand',
  246.             title: 'Remove amount from the specified user wallet',
  247.             type:  'string',
  248.             placeholder: '!removemoney <user> <amount>',
  249.             indent: 3
  250.         },
  251.         {
  252.             name:  'setAllUserCommand',
  253.             title: 'Set all user wallet',
  254.             type:  'string',
  255.             placeholder: '!setallmoney <amount>',
  256.             indent: 3
  257.         },
  258.         {
  259.             name:  'setStoreQuantity',
  260.             title: 'Set an item quantity in the store (/!\\ Once an item has been bought, changing the quantity in the settings doesn\'t affect the actual count)',
  261.             type:  'string',
  262.             placeholder: '!setquantity <group ID> <amount>',
  263.             indent: 3
  264.         },
  265.  
  266.         /*** I18N ***/
  267.         {
  268.             name:  'unused2',
  269.             title: 'Customization'
  270.         },
  271.         {
  272.             name:  'helpOutput',
  273.             title: 'Help for users (put %give for the give command, %f for the fees in percent, for the oder ones please see the placeholder)',
  274.             type:  'multiline',
  275.             placeholder: '[b]SConomy NG by Mmoi.[/b]\nCommands:\n- %money | Shows the current wallet amount\n- %store | Display the store\n- %buy <serverGroup ID> | Buy a serverGroup\n- %sell <serverGroup ID> | Sell a serverGroup',
  276.             indent: 3
  277.         },
  278.         {
  279.             name:  'output',
  280.             title: 'Check wallet output (put %d for the current wallet value)',
  281.             type:  'string',
  282.             placeholder: 'You have %d coin(s)',
  283.             indent: 3
  284.         },
  285.         {
  286.             name:  'storeOutputHeader',
  287.             title: 'Store command output [Header] (put %x for the buy command and \\n for line feed)',
  288.             type:  'string',
  289.             placeholder: 'Groups available in the store:\\n(You can buy them with "%x <ID>")',
  290.             indent: 3
  291.         },
  292.         {
  293.             name:  'storeOutputBody',
  294.             title: 'Store command output [Body] (put %s for the group name, %d for the ID, %x for the price, %c for the remove otions [see below] and %q for the quantity option [see below])',
  295.             type:  'string',
  296.             placeholder: '(ID) %d / %s for %x coin(s) [%c] --- %q',
  297.             indent: 3
  298.         },
  299.         {
  300.             name:  'storeOutputBodySI',
  301.             title: 'Store command output, remove option [Not soldable]',
  302.             type:  'string',
  303.             placeholder: 'No possible refund',
  304.             indent: 3
  305.         },
  306.         {
  307.             name:  'storeOutputBodySP',
  308.             title: 'Store command output, remove option [Refund] (put %d for the sell price)',
  309.             type:  'string',
  310.             placeholder: 'Refund for %d coin(s)',
  311.             indent: 3
  312.         },
  313.         {
  314.             name:  'storeOutputBodySN',
  315.             title: 'Store command output, remove option [Pay to remove] (put %d for the sell price)',
  316.             type:  'string',
  317.             placeholder: 'Remove price: %d coin(s)',
  318.             indent: 3
  319.         },
  320.         {
  321.             name:  'storeOutputBodyIQU',
  322.             title: 'Store command output, quantity option [Unlimited]',
  323.             type:  'string',
  324.             placeholder: 'Unlimited quantity',
  325.             indent: 3
  326.         },
  327.         {
  328.             name:  'storeOutputBodyIQL',
  329.             title: 'Store command output, quantity option [Limited] (put %d for the available quantity and %c for the total qantity)',
  330.             type:  'string',
  331.             placeholder: 'Available: %d of %c',
  332.             indent: 3
  333.         },
  334.         {
  335.             name:  'storeOutputBodyIQLOUT',
  336.             title: 'Store command output, quantity option [Limited, out of order] (put %d for the total qantity)',
  337.             type:  'string',
  338.             placeholder: 'Out of order',
  339.             indent: 3
  340.         },
  341.         {
  342.             name:  'groupNotFoud',
  343.             title: 'Text for group not found by the bot (the group is for sale but the bot can\'t get its name because sinusbot only update the group list on connection)',
  344.             type:  'string',
  345.             placeholder: 'N/A',
  346.             indent: 3
  347.         },
  348.         {
  349.             name:  'tooManyGroups',
  350.             title: 'Text for too many groups',
  351.             type:  'string',
  352.             placeholder: 'You have too many groups',
  353.             indent: 3
  354.         },
  355.         {
  356.             name:  'buyNotInStore',
  357.             title: 'Text for not in store item',
  358.             type:  'string',
  359.             placeholder: 'Item not available in the store',
  360.             indent: 3
  361.         },
  362.         {
  363.             name:  'buyTooExpensive',
  364.             title: 'Text for too expensive item',
  365.             type:  'string',
  366.             placeholder: 'Not enough coins',
  367.             indent: 3
  368.         },
  369.         {
  370.             name:  'buyAlreadyAssigned',
  371.             title: 'Text for already purchased item',
  372.             type:  'string',
  373.             placeholder: 'You already have this item',
  374.             indent: 3
  375.         },
  376.  
  377.         {
  378.             name:  'buyOutOfStock',
  379.             title: 'Text for item out of stock',
  380.             type:  'string',
  381.             placeholder: 'The item is out of stock',
  382.             indent: 3
  383.         },{
  384.             name:  'buyPerformed',
  385.             title: 'Text for successfully purchased item',
  386.             type:  'string',
  387.             placeholder: 'Item successfully bought',
  388.             indent: 3
  389.         },
  390.         {
  391.             name:  'sellNotSoldable',
  392.             title: 'Text for refund when the group isn\'t refundable / soldable',
  393.             type:  'string',
  394.             placeholder: 'This item can\'t be sold',
  395.             indent: 3
  396.         },
  397.         {
  398.             name:  'sellNotInStore',
  399.             title: 'Text for not in store item at sell time',
  400.             type:  'string',
  401.             placeholder: 'Items that aren\'t in the store can\'t be sold',
  402.             indent: 3
  403.         },
  404.         {
  405.             name:  'sellNotInGroup',
  406.             title: 'Text for refund when the user doesn\'t belong to the group',
  407.             type:  'string',
  408.             placeholder: 'You can\'t sell an item you don\'t have',
  409.             indent: 3
  410.         },
  411.         {
  412.             name:  'sellPerformed',
  413.             title: 'Text for successfully refunded item',
  414.             type:  'string',
  415.             placeholder: 'Item successfully sold',
  416.             indent: 3
  417.         },
  418.         {
  419.             name:  'notEnoughtArgument',
  420.             title: 'Text when a command don\'t have all the requested arguments (put %h for help command)',
  421.             type:  'string',
  422.             placeholder: 'The command isn\'t full, please see help (%h)',
  423.             indent: 3
  424.         },
  425.         {
  426.             name:  'userNotFound',
  427.             title: 'Text when a user is not found',
  428.             type:  'string',
  429.             placeholder: 'User not found',
  430.             indent: 3
  431.         },
  432.         {
  433.             name:  'notValidNumber',
  434.             title: 'Text when a number isn\'t a valid one (put %d for the user input)',
  435.             type:  'string',
  436.             placeholder: '%d is not a valid number',
  437.             indent: 3
  438.         },
  439.         {
  440.             name:  'tooPoorForDonation',
  441.             title: 'Text for requested donation is too expensive',
  442.             type:  'string',
  443.             placeholder: 'You don\'t have the money to donate that amount',
  444.             indent: 3,
  445.             conditions: [{
  446.                 field: 'enableGiving',
  447.                 value: true
  448.             }]
  449.         },
  450.         {
  451.             name:  'transactionSucceed',
  452.             title: 'Text when someone successfully donated money (put %d for the amount donated)',
  453.             type:  'string',
  454.             placeholder: 'You successfully donated %d coin(s)',
  455.             indent: 3,
  456.             conditions: [{
  457.                 field: 'enableGiving',
  458.                 value: true
  459.             }]
  460.         },
  461.         {
  462.             name:  'gotDonation',
  463.             title: 'Text when someone successfully donated money to you (put %d for the amount donated and %s for the donator name)',
  464.             type:  'string',
  465.             placeholder: 'You received %d coin(s) from %s',
  466.             indent: 3,
  467.             conditions: [{
  468.                 field: 'enableGiving',
  469.                 value: true
  470.             }]
  471.         },
  472.         {
  473.             name:  'historyBuyStr',
  474.             title: 'Text for the history when someone buy an item (put %name for buyer username, %group for bought group name and %date for the date)',
  475.             type:  'string',
  476.             placeholder: '%name bought %group (%date)',
  477.             indent: 3,
  478.             conditions: [{
  479.                 field: 'historyEnable',
  480.                 value: true
  481.             }]
  482.         },
  483.         {
  484.             name:  'historySellStr',
  485.             title: 'Text for the history when someone sell an item (put %name for buyer username, %group for bought group name and %date for the date)',
  486.             type:  'string',
  487.             placeholder: '%name sold %group (%date)',
  488.             indent: 3,
  489.             conditions: [{
  490.                 field: 'historyEnable',
  491.                 value: true
  492.             }]
  493.         },
  494.         {
  495.             name:  'getUserOutput',
  496.             title: 'Text for admin getting user wallet amount (%d for the amount)',
  497.             type:  'string',
  498.             placeholder: 'User has %d coin(s)',
  499.             indent: 3
  500.         },
  501.         {
  502.             name:  'setUserOutput',
  503.             title: 'Text for admin setting a wallet amount (%d for the amount)',
  504.             type:  'string',
  505.             placeholder: 'Wallet has been set to %d coin(s)',
  506.             indent: 3
  507.         },
  508.         {
  509.             name:  'setStoreOutput',
  510.             title: 'Text for admin setting a store item quantity (%d for the quantity)',
  511.             type:  'string',
  512.             placeholder: 'There is now %d of te item available in store',
  513.             indent: 3
  514.         },
  515.         {
  516.             name:  'showProgress',
  517.             title: 'Add generation progress to the check wallet command output',
  518.             type:  'checkbox',
  519.             indent: 3
  520.         },
  521.         {
  522.             name:  'outputProgress',
  523.             title: 'Check wallet output [Progress] (put %s for the current progress, %c for currency generated by tick)',
  524.             type:  'string',
  525.             placeholder: 'Your current progress for the next %c coin(s) is %s',
  526.             conditions: [{
  527.                 field: 'showProgress',
  528.                 value: true
  529.             }],
  530.             indent: 3
  531.         },
  532.  
  533.         /*** Groups ***/
  534.         {
  535.             name:  'unused3',
  536.             title: 'Admin and discount groups'
  537.         },
  538.         {
  539.             name:  'adminGroups',
  540.             title: 'Admin group IDs',
  541.             type:  'strings',
  542.             indent: 3
  543.         },
  544.         {
  545.             name: 'discountGroups',
  546.             title: 'Discount groups (negative number are valid)',
  547.             type: 'array',
  548.             vars: [{
  549.                 name:  'groups',
  550.                 title: 'Groups IDs',
  551.                 type:  'strings'
  552.             },
  553.             {
  554.                 name:  'currencyIncrease',
  555.                 title: 'Currency increase (in percent)',
  556.                 type:  'number'
  557.             },
  558.             {
  559.                 name:  'tickDecrease',
  560.                 title: 'Update interval decrease (in percent)',
  561.                 type:  'number'
  562.             }],
  563.             indent: 3
  564.         },
  565.         {
  566.             name: 'discountChannels',
  567.             title: 'Discount channels (negative number are valid)',
  568.             type: 'array',
  569.             vars: [{
  570.                 name:  'channel',
  571.                 title: 'Channel',
  572.                 type:  'channel'
  573.             },
  574.             {
  575.                 name:  'currencyIncrease',
  576.                 title: 'Currency increase (in percent)',
  577.                 type:  'number'
  578.             },
  579.             {
  580.                 name:  'tickDecrease',
  581.                 title: 'Update interval decrease (in percent)',
  582.                 type:  'number'
  583.             }],
  584.             indent: 3
  585.         },
  586.         {
  587.             name:  'unused4',
  588.             title: 'Sale groups'
  589.         },
  590.         {
  591.             name: 'forSaleGroups',
  592.             title: 'Servergroup that can be sold by the bot',
  593.             type: 'array',
  594.             vars: [{
  595.                 name:  'groups',
  596.                 title: 'Groups IDs',
  597.                 type:  'strings'
  598.             },
  599.             {
  600.                 name:  'price',
  601.                 title: 'Price',
  602.                 type:  'number'
  603.             },
  604.             {
  605.                 name:  'soldable',
  606.                 title: 'Can be sold',
  607.                 type:  'checkbox'
  608.             },
  609.             {
  610.                 name:  'soldPrice',
  611.                 title: 'Refund price (can be negative if user needs to pay to get it removed)',
  612.                 type:  'number',
  613.                 conditions: [{
  614.                     field: 'soldable',
  615.                     value: true
  616.                 }]
  617.             },
  618.             {
  619.                 name:  'isLimited',
  620.                 title: 'Limit the available item quantity',
  621.                 type:  'checkbox'
  622.             },
  623.             {
  624.                 name:  'limitedNumber',
  625.                 title: 'Item quantity',
  626.                 type:  'number',
  627.                 conditions: [{
  628.                     field: 'isLimited',
  629.                     value: true
  630.                 }]
  631.             }],
  632.             indent: 3
  633.         },
  634.         {
  635.             name:  'unused5',
  636.             title: 'Group number increase groups',
  637.             conditions: [{
  638.                 field: 'limitGN',
  639.                 value: true
  640.             }]
  641.         },
  642.         {
  643.             name: 'increaseGN',
  644.             title: 'Groups that increase the maximum group number (negative are valid)',
  645.             type: 'array',
  646.             vars: [{
  647.                 name:  'groups',
  648.                 title: 'Groups IDs',
  649.                 type:  'strings'
  650.             },
  651.             {
  652.                 name:  'increase',
  653.                 title: 'Group number increase',
  654.                 type:  'number'
  655.             }],
  656.             indent: 3,
  657.             conditions: [{
  658.                 field: 'limitGN',
  659.                 value: true
  660.             }]
  661.         },
  662.     ]
  663. },
  664. function(sinusbot, config, info)
  665. {
  666.     // Adds the startsWith method
  667.     if (typeof String.prototype.startsWith === 'undefined')
  668.     {
  669.         String.prototype.startsWith = function(substring)
  670.         {
  671.             return this.substr(0, substring.length) === substring;
  672.         };
  673.     }
  674.  
  675.     // Includes and global objects
  676.     var engine  = require('engine'),
  677.         backend = require('backend'),
  678.         store   = require('store'),
  679.         event   = require('event'),
  680.         sconomyDB = null;
  681.  
  682.     var migrationProvider = {confirmation: false},
  683.         antiIOProvider    = {progress: [], flush: null};
  684.  
  685.  
  686. /* ============================ Default Settings ============================ */
  687.  
  688.     config = config === null ? {} : config;
  689.  
  690.     config.tick                 = config.tick                 || 1;
  691.     config.currencyAmount       = config.currencyAmount       || 1;
  692.     config.maxCurrency          = config.maxCurrency          || 9007199254740991;
  693.     config.limitGNValue         = config.limitGNValue         || 2;
  694.     config.historyLimit         = config.historyLimit         || 10;
  695.     config.helpCommand          = config.helpCommand          || '!schelp';
  696.     config.command              = config.command              || '!money';
  697.     config.storeCommand         = config.storeCommand         || '!store';
  698.     config.getUserCommand       = config.getUserCommand       || '!see';
  699.     config.setUserCommand       = config.setUserCommand       || '!set';
  700.     config.buyCommand           = config.buyCommand           || '!buy';
  701.     config.sellCommand          = config.sellCommand          || '!sell';
  702.     config.giveCommand          = config.giveCommand          || '!give';
  703.     config.addUserCommand       = config.addUserCommand       || '!addmoney';
  704.     config.removeUserCommand    = config.removeUserCommand    || '!removemoney';
  705.     config.setAllUserCommand    = config.setAllUserCommand    || '!setallmoney';
  706.     config.setStoreQuantity     = config.setStoreQuantity     || '!setquantity';
  707.     config.output               = config.output               || 'You have %d coin(s)';
  708.     config.outputProgress       = config.outputProgress       || 'Your current progress for the next %c coin(s) is %s';
  709.     config.getUserOutput        = config.getUserOutput        || 'User has %d coin(s)';
  710.     config.setUserOutput        = config.setUserOutput        || 'Wallet has been set to %d coin(s)';
  711.     config.setStoreOutput       = config.setStoreOutput       || 'There is now %d of te item available in store';
  712.     config.blacklistedChannels  = config.blacklistedChannels  || [];
  713.     config.adminGroups          = config.adminGroups          || [];
  714.     config.discountGroups       = config.discountGroups       || [];
  715.     config.discountChannels     = config.discountChannels     || [];
  716.     config.forSaleGroups        = config.forSaleGroups        || [];
  717.     config.increaseGN           = config.increaseGN           || [];
  718.     config.storeOutputHeader    = config.storeOutputHeader    || 'Groups available in the store:\\n(You can buy them with "%x <ID>")';
  719.     config.storeOutputBody      = config.storeOutputBody      || '(ID) %d / %s for %x coin(s) [%c] --- %q';
  720.     config.storeOutputBodySI    = config.storeOutputBodySI    || 'No possible refund';
  721.     config.storeOutputBodySP    = config.storeOutputBodySP    || 'Refund for %d coin(s)';
  722.     config.storeOutputBodySN    = config.storeOutputBodySN    || 'Remove price: %d coin(s)';
  723.     config.storeOutputBodyIQU   = config.storeOutputBodyIQU   || 'Unlimited quantity';
  724.     config.storeOutputBodyIQL   = config.storeOutputBodyIQL   || 'Available: %d of %c';
  725.     config.storeOutputBodyIQLOUT= config.storeOutputBodyIQLOUT|| 'Out of order';
  726.     config.groupNotFoud         = config.groupNotFoud         || 'N/A';
  727.     config.tooManyGroups        = config.tooManyGroups        || 'You have too many groups';
  728.     config.buyNotInStore        = config.buyNotInStore        || 'Item not available in the store';
  729.     config.buyTooExpensive      = config.buyTooExpensive      || 'Not enough coins';
  730.     config.buyOutOfStock        = config.buyOutOfStock        || 'The item is out of stock';
  731.     config.buyAlreadyAssigned   = config.buyAlreadyAssigned   || 'You already have this item';
  732.     config.buyPerformed         = config.buyPerformed         || 'Item successfully bought';
  733.     config.sellNotInStore       = config.sellNotInStore       || 'Items that aren\'t in the store can\'t be sold';
  734.     config.sellNotSoldable      = config.sellNotSoldable      || 'This item can\'t be sold';
  735.     config.sellNotInGroup       = config.sellNotInGroup       || 'You can\'t sell an item you don\'t have';
  736.     config.sellPerformed        = config.sellPerformed        || 'Item successfully sold';
  737.     config.userNotFound         = config.userNotFound         || 'User not found';
  738.     config.helpOutput           = config.helpOutput           || '[b]SConomy NG by Mmoi.[/b]\nCommands:\n- %money | Shows the current wallet amount\n- %store | Display the store\n- %buy <serverGroup ID> | Buy a serverGroup\n- %sell <serverGroup ID> | Sell a serverGroup';
  739.     config.notEnoughtArgument   = config.notEnoughtArgument   || 'The command isn\'t full, please see help (%h)';
  740.     config.tooPoorForDonation   = config.tooPoorForDonation   || 'You don\'t have the money to donate that amount';
  741.     config.notValidNumber       = config.notValidNumber       || '%d is not a valid number';
  742.     config.transactionSucceed   = config.transactionSucceed   || 'You successfully donated %d coin(s)';
  743.     config.gotDonation          = config.gotDonation          || 'You received %d coin(s) from %s';
  744.     config.historyBuyStr        = config.historyBuyStr        || '%name bought %group (%date)';
  745.     config.historySellStr       = config.historySellStr       || '%name sold %group (%date)';
  746.  
  747.     config.viewDistance       = typeof config.viewDistance       === 'undefined' ? 0   : config.viewDistance;
  748.     config.diskIOLimit        = typeof config.diskIOLimit        === 'undefined' ? 10  : config.diskIOLimit;
  749.     config.donationFee        = typeof config.donationFee        === 'undefined' ? 10  : config.donationFee;
  750.     config.storageProvider    = typeof config.storageProvider    === 'undefined' ? '0' : config.storageProvider;
  751.  
  752.     config.useMinute          = typeof config.useMinute          === 'undefined' ? false : config.useMinute;
  753.     config.allowDumbBuy       = typeof config.allowDumbBuy       === 'undefined' ? false : config.allowDumbBuy;
  754.     config.enableGiving       = typeof config.enableGiving       === 'undefined' ? false : config.enableGiving;
  755.     config.givingOnlineOnly   = typeof config.givingOnlineOnly   === 'undefined' ? true  : config.givingOnlineOnly;
  756.     config.limitGN            = typeof config.limitGN            === 'undefined' ? false : config.limitGN;
  757.     config.limitGNOnlySold    = typeof config.limitGNOnlySold    === 'undefined' ? false : config.limitGNOnlySold;
  758.     config.historyEnable      = typeof config.historyEnable      === 'undefined' ? false : config.historyEnable;
  759.     config.historyIncludeSell = typeof config.historyIncludeSell === 'undefined' ? false : config.historyIncludeSell;
  760.     config.showProgress       = typeof config.showProgress       === 'undefined' ? false : config.showProgress;
  761.  
  762.  
  763. /* ======================= Storage provider functions ======================= */
  764.  
  765.     /**
  766.     * @fn sconomySet Set a key in the storage
  767.     * @param params Object with following members:
  768.     * - userUID: user UID
  769.     * - type: storage field type
  770.     * - value: value to be stored
  771.     */
  772.     function sconomySet(params)
  773.     {
  774.         if (sconomyDB !== null)
  775.         {
  776.             sconomyDB.setData(params.userUID, params.type, params.value);
  777.         }
  778.         else
  779.         {
  780.             // Default
  781.             if (config.storageProvider === '0')
  782.             {
  783.                 store.set(params.userUID + params.type, params.value);
  784.             }
  785.             // Public
  786.             else
  787.             {
  788.                 store.setGlobal(params.userUID + params.type, params.value);
  789.             }
  790.         }
  791.     }
  792.  
  793.     /**
  794.     * @fn sconomySetAll Set all key in the storage
  795.     * @param params Object with following members:
  796.     * - type: storage field type
  797.     * - value: value to be stored
  798.     */
  799.     function sconomySetAll(params)
  800.     {
  801.         if (sconomyDB !== null)
  802.         {
  803.             sconomyDB.setAllData(params.type, params.value);
  804.         }
  805.         else
  806.         {
  807.             // Default
  808.             if (config.storageProvider === '0')
  809.             {
  810.                 store.getKeys().forEach(function(storedKey)
  811.                 {
  812.                     // Search sconomy currency keys
  813.                     if (storedKey.match(new RegExpr('.*' + params.type + '$')))
  814.                     {
  815.                         store.set(storedKey, params.value);
  816.                     }
  817.                 });
  818.             }
  819.             // Public
  820.             else
  821.             {
  822.                 store.getKeysGlobal().forEach(function(storedKey)
  823.                 {
  824.                     // Search sconomy currency keys
  825.                     if (storedKey.match(new RegExp('.*' + params.type + '$')))
  826.                     {
  827.                         store.setGlobal(storedKey, params.value);
  828.                     }
  829.                 });
  830.             }
  831.         }
  832.     }
  833.  
  834.     /**
  835.     * @fn sconomyGet Get a key from the storage
  836.     * @param params Object with following members:
  837.     * - userUID: user UID
  838.     * - type: storage field type
  839.     * @return requested value or undefined
  840.     */
  841.     function sconomyGet(params)
  842.     {
  843.         if (sconomyDB !== null)
  844.         {
  845.             return sconomyDB.getData(params.userUID, params.type);
  846.         }
  847.         else
  848.         {
  849.             // Default
  850.             if (config.storageProvider === '0')
  851.             {
  852.                 return store.get(params.userUID + params.type);
  853.             }
  854.             // Public
  855.             else
  856.             {
  857.                 return store.getGlobal(params.userUID + params.type);
  858.             }
  859.         }
  860.     }
  861.  
  862.  
  863.     // Fonctions that flushes the user in-RAM progress (and store it on disk)
  864.     antiIOProvider.flush = function(uid, removeKey)
  865.     {
  866.         if (antiIOProvider.progress[uid])
  867.         {
  868.             // Get the user total progress (disk + RAM)
  869.             var progress = sconomyGet({userUID: uid, type: 'progress'});
  870.             progress = progress ? progress : 1;
  871.             progress += antiIOProvider.progress[uid];
  872.  
  873.             // Store it on dsk
  874.             sconomySet({
  875.                 userUID: uid,
  876.                 type: 'progress',
  877.                 value: parseFloat(progress)
  878.             });
  879.  
  880.             // Resets the RAM-progress
  881.             antiIOProvider.progress[uid] = 0;
  882.  
  883.             if (removeKey)
  884.             {
  885.                 delete antiIOProvider.progress[uid];
  886.             }
  887.         }
  888.     };
  889.  
  890.  
  891.     // Migration functions
  892.     migrationProvider.private_public = function(storage, startingIndex)
  893.     {
  894.         var i = typeof startingIndex === 'undefined' ? 0 : startingIndex,
  895.             date = (new Date()).getTime() + 4000,
  896.             list = storage.getKeys(),
  897.             len = list.length,
  898.             storedKey;
  899.  
  900.  
  901.         for (; i < len && (new Date()).getTime() < date; i++)
  902.         {
  903.             storedKey = list[i];
  904.  
  905.             // Copy the keys
  906.             storage.setGlobal(storedKey, storage.get(storedKey));
  907.         }
  908.  
  909.         // Migration not finished yet
  910.         if (i !== len)
  911.         {
  912.             setTimeout(function()
  913.             {
  914.                 migrationProvider.public_private(storage, i);
  915.             }, 10);
  916.             engine.log('Migration tool: still working...');
  917.         }
  918.         else
  919.         {
  920.             engine.log('Migration tool: work done.');
  921.         }
  922.  
  923.         return true;
  924.     };
  925.  
  926.     migrationProvider.public_private = function(storage, startingIndex)
  927.     {
  928.         var i = typeof startingIndex === 'undefined' ? 0 : startingIndex,
  929.             date = (new Date()).getTime() + 4000,
  930.             list = storage.getKeysGlobal(),
  931.             len = list.length,
  932.             storedKey;
  933.  
  934.  
  935.         for (; i < len && (new Date()).getTime() < date; i++)
  936.         {
  937.             storedKey = list[i];
  938.  
  939.             // Search sconomy keys
  940.             if (storedKey.match(new RegExp('^(.{27}=(sconomy|progress)|SCO_GRP_\\d+quantity)$')))
  941.             {
  942.                 storage.set(storedKey, storage.getGlobal(storedKey));
  943.             }
  944.         }
  945.  
  946.         // Migration not finished yet
  947.         if (i !== len)
  948.         {
  949.             setTimeout(function()
  950.             {
  951.                 migrationProvider.public_private(storage, i);
  952.             }, 10);
  953.             engine.log('Migration tool: still working...');
  954.         }
  955.         else
  956.         {
  957.             engine.log('Migration tool: work done.');
  958.         }
  959.  
  960.         return true;
  961.     };
  962.  
  963.     migrationProvider.unset_private = function(storage)
  964.     {
  965.         storage.getKeys().forEach(function(storedKey)
  966.         {
  967.             storage.unset(storedKey);
  968.         });
  969.  
  970.         return true;
  971.     };
  972.  
  973.     migrationProvider.unset_public = function(storage)
  974.     {
  975.         storage.getKeysGlobal().forEach(function(storedKey)
  976.         {
  977.             // Search sconomy keys
  978.             if (storedKey.match(new RegExp('^(.{27}=(sconomy|progress)|SCO_GRP_\\d+quantity)$')))
  979.             {
  980.                 storage.unsetGlobal(storedKey);
  981.             }
  982.         });
  983.  
  984.         return true;
  985.     };
  986.  
  987.     /*
  988.     * @fn sconomyDBIntegration Adds the database support for sconomy-ng
  989.     */
  990.     function sconomyDBIntegration()
  991.     {
  992.         sconomyDB = require('sconomy-ng-db.js');
  993.  
  994.         if (!sconomyDB || !sconomyDB.isEnabled())
  995.         {
  996.             // Disable the support
  997.             engine.log('SConomy NG DB Plugin not found, database support is disabled');
  998.             sconomyDB = null;
  999.         }
  1000.         else
  1001.         {
  1002.             engine.log('SConomy NG DB loaded');
  1003.  
  1004.             // Connects to the database
  1005.             sconomyDB.start();
  1006.  
  1007.             // Adds the migrations methods
  1008.             sconomyDB.getMigrationFunctions().forEach(function(migrationFunction)
  1009.             {
  1010.                 migrationProvider[migrationFunction.name] = migrationFunction.func;
  1011.             });
  1012.         }
  1013.     }
  1014.  
  1015.  
  1016. /* ============================= Main function ============================= */
  1017.  
  1018.     /**
  1019.     * @fn computeTick Increase each connected client progress
  1020.     *                 and the wallet value if the tick is reached
  1021.     */
  1022.     function computeTick()
  1023.     {
  1024.         // Re-schedule the next tick
  1025.         if      (sconomyDB !== null) setTimeout(computeTick, sconomyDB.getTick() * 1000);
  1026.         else if (config.useMinute)   setTimeout(computeTick, 60 * 1000);
  1027.         else                         setTimeout(computeTick, 1000);
  1028.  
  1029.         backend.getChannels().forEach(function(channel)
  1030.         {
  1031.             // Ignore blacklisted channels
  1032.             var blacklisted = config.blacklistedChannels.some(function(blacklistChannel)
  1033.             {
  1034.                 return channel.id() === blacklistChannel.channel;
  1035.             });
  1036.  
  1037.             if (blacklisted) return;
  1038.  
  1039.             // Load the base discount for the channel
  1040.             var channelDiscount = getChannelDiscount(channel, config.discountChannels);
  1041.  
  1042.             // Process the clients
  1043.             channel.getClients().forEach(function(client)
  1044.             {
  1045.                 // Compute the increase and decrease factors for the groups
  1046.                 var discount = getDiscount(client, config.discountGroups);
  1047.  
  1048.                 // Adds the channel discount to the user one
  1049.                 discount.currencyIncreaseSum += channelDiscount.currencyIncreaseSum;
  1050.                 discount.tickDecreaseSum     += channelDiscount.tickDecreaseSum;
  1051.                 if (discount.tickDecreaseSum > 90) discount.tickDecreaseSum = 90;
  1052.  
  1053.                 // For each connected client
  1054.                 var uid      = client.uid(),
  1055.                     progress = sconomyGet({userUID: uid, type: 'progress'}),
  1056.                     sconomy  = sconomyGet({userUID: uid, type: 'sconomy'});
  1057.  
  1058.                 // Maximum currency not reached yet
  1059.                 if (sconomy < config.maxCurrency || sconomy === undefined)
  1060.                 {
  1061.                     // If IO reducer is enabled
  1062.                     if (config.diskIOLimit > 0)
  1063.                     {
  1064.                         // Create the user RAM-progress
  1065.                         if (antiIOProvider.progress[uid] === undefined)
  1066.                         {
  1067.                             antiIOProvider.progress[uid] = 0;
  1068.                         }
  1069.  
  1070.                         // Adds the RAM-stored progress to the disk-stored one
  1071.                         progress += antiIOProvider.progress[uid];
  1072.                     }
  1073.  
  1074.                     // No money for that user
  1075.                     if (sconomy === undefined)
  1076.                     {
  1077.                         sconomy = 0;
  1078.                         progress = 1;
  1079.  
  1080.                         if (config.diskIOLimit > 0) antiIOProvider.progress[uid] = 0;
  1081.                     }
  1082.                     // User has reached the end of a tick
  1083.                     else if (progress >= config.tick * (1 - discount.tickDecreaseSum / 100))
  1084.                     {
  1085.                         sconomy += config.currencyAmount * ((100 + discount.currencyIncreaseSum) / 100);
  1086.                         progress = 1;
  1087.  
  1088.                         if (config.diskIOLimit > 0) antiIOProvider.progress[uid] = 0;
  1089.                     }
  1090.                     // User is in a tick
  1091.                     else
  1092.                     {
  1093.                         // Progress is only incremented for the possible storage
  1094.                         progress++;
  1095.  
  1096.                         // Adds user progress for the next check
  1097.                         if (config.diskIOLimit > 0) antiIOProvider.progress[uid]++;
  1098.                     }
  1099.  
  1100.                     // Save the updated currency amount (only on modification)
  1101.                     if (progress === 1)
  1102.                     {
  1103.                         // Maximum currency reached
  1104.                         if (sconomy > config.maxCurrency) sconomy = config.maxCurrency;
  1105.  
  1106.                         sconomySet({
  1107.                             userUID: uid,
  1108.                             type: 'sconomy',
  1109.                             value: parseFloat(sconomy)
  1110.                         });
  1111.                     }
  1112.  
  1113.                     // Save, when needed, the new user progress
  1114.                     if (config.diskIOLimit <= 0 || progress === 1 || antiIOProvider.progress[uid] >= config.diskIOLimit)
  1115.                     {
  1116.                         if (config.diskIOLimit > 0) antiIOProvider.progress[uid] = 0;
  1117.  
  1118.                         sconomySet({
  1119.                             userUID: uid,
  1120.                             type: 'progress',
  1121.                             value: parseFloat(progress)
  1122.                         });
  1123.                     }
  1124.                 }
  1125.             });
  1126.         });
  1127.     }
  1128.  
  1129.  
  1130. /* =========================== Utility functions =========================== */
  1131.  
  1132.     /**
  1133.     * @fn getDiscount Get Discount for the user
  1134.     * @param client Client
  1135.     * @param discountGroups Parameters discountGroups
  1136.     * @return Object with currencyIncreaseSum, tickDecreaseSum members
  1137.     */
  1138.     function getDiscount(client, discountGroups)
  1139.     {
  1140.         var currencyIncreaseSum = 0,
  1141.             tickDecreaseSum = 0;
  1142.  
  1143.         client.getServerGroups().forEach(function(userServergroup)
  1144.         {
  1145.             discountGroups.forEach(function(discountGroup)
  1146.             {
  1147.                 discountGroup.groups.forEach(function(group)
  1148.                 {
  1149.                     // User has the discount
  1150.                     if (group === userServergroup.id())
  1151.                     {
  1152.                         currencyIncreaseSum += discountGroup.currencyIncrease;
  1153.                         tickDecreaseSum += discountGroup.tickDecrease;
  1154.                     }
  1155.                 });
  1156.             });
  1157.         });
  1158.  
  1159.         // Set bondaries
  1160.         tickDecreaseSum = tickDecreaseSum >= 90 ? 90 : tickDecreaseSum;
  1161.  
  1162.         return {
  1163.             currencyIncreaseSum: currencyIncreaseSum,
  1164.             tickDecreaseSum: tickDecreaseSum
  1165.         };
  1166.     }
  1167.  
  1168.     /**
  1169.     * @fn getChannelDiscount Get Discount for a specific channel
  1170.     * @param channel Channel
  1171.     * @param discountChannels Parameters discountChannels
  1172.     * @return Object with currencyIncreaseSum, tickDecreaseSum members
  1173.     */
  1174.     function getChannelDiscount(channel, discountChannels)
  1175.     {
  1176.         var currencyIncreaseSum = 0,
  1177.             tickDecreaseSum = 0;
  1178.  
  1179.         discountChannels.forEach(function(discountChannel)
  1180.         {
  1181.             if (discountChannel.channel === channel.id())
  1182.             {
  1183.                 currencyIncreaseSum += discountChannel.currencyIncrease;
  1184.                 tickDecreaseSum     += discountChannel.tickDecrease;
  1185.             }
  1186.         });
  1187.  
  1188.         // Set bondaries
  1189.         tickDecreaseSum = tickDecreaseSum >= 90 ? 90 : tickDecreaseSum;
  1190.  
  1191.         return {
  1192.             currencyIncreaseSum: currencyIncreaseSum,
  1193.             tickDecreaseSum: tickDecreaseSum
  1194.         };
  1195.     }
  1196.  
  1197.     /**
  1198.     * @fn getUserUID Get user UID based on multiple possible inputs
  1199.     * @param input string of the client identifier (UID, name etc)
  1200.     * @param allowOffline boolean to validate offline user too
  1201.     * @return UID or null if not found
  1202.     */
  1203.     function getUserUID(input, allowOffline)
  1204.     {
  1205.         var regexRes = null,
  1206.             client   = null;
  1207.  
  1208.         /*
  1209.         * CLient URL
  1210.         * ^\[URL=client://\d+/.{27}=~[^\]]*\](\\\[|[^\[])*\[/URL\]$
  1211.         * ^\[URL=client:\/\/\d+\/(.{27}=)~[^\]]*\](\\\[|[^\[])*\[\/URL\]$ (escaped)
  1212.         */
  1213.         regexRes = input.match(/^\[URL=client:\/\/\d+\/(.{27}=)~[^\]]*\](\\\[|[^\[])*\[\/URL\]$/);
  1214.         if (regexRes)
  1215.         {
  1216.             if (allowOffline || backend.getClientByUniqueID(regexRes[1]))
  1217.             {
  1218.                 return regexRes[1];
  1219.             }
  1220.             else
  1221.             {
  1222.                 return null;
  1223.             }
  1224.         }
  1225.  
  1226.         /*
  1227.         * CLient UID
  1228.         * ^.{27}=$
  1229.         * ^(.{27}=)$
  1230.         */
  1231.         regexRes = input.match(/^(.{27}=)$/);
  1232.         if (regexRes)
  1233.         {
  1234.             if (allowOffline || backend.getClientByUniqueID(regexRes[1]))
  1235.             {
  1236.                 return regexRes[1];
  1237.             }
  1238.             else
  1239.             {
  1240.                 return null;
  1241.             }
  1242.         }
  1243.  
  1244.         /*
  1245.         * Client Nickname
  1246.         */
  1247.         client = backend.getClientByName(input);
  1248.         if (client)
  1249.         {
  1250.             return client.uid();
  1251.         }
  1252.  
  1253.         return null;
  1254.     }
  1255.  
  1256.     /**
  1257.     * @fn isAdmin Checks if the user is an Admin
  1258.     * @param client client
  1259.     * @return Boolean
  1260.     */
  1261.     function isAdmin(client)
  1262.     {
  1263.         return config.adminGroups.some(function(adminGroup)
  1264.         {
  1265.              return client.getServerGroups().some(function(userServergroup)
  1266.              {
  1267.                   return adminGroup === userServergroup.id();
  1268.              });
  1269.         });
  1270.     }
  1271.  
  1272.     /**
  1273.     * @fn clientGroupNumber Return the number of groups the client is in
  1274.     * @param client client
  1275.     * @return Number of groups
  1276.     * @warning May be number of sold groups only based on config.limitGNOnlySold
  1277.     */
  1278.     function clientGroupNumber(client)
  1279.     {
  1280.         var clientGroups = client.getServerGroups();
  1281.  
  1282.         // Group number limitation (heavy but process only on buy)
  1283.         if (config.limitGNOnlySold)
  1284.         {
  1285.             var clientGroupNumberValue = 0;
  1286.  
  1287.             // Check for each sales plan if the groups are possessed by the user
  1288.             config.forSaleGroups.forEach(function(saleGroup)
  1289.             {
  1290.                 saleGroup.groups.forEach(function(group)
  1291.                 {
  1292.                     clientGroups.forEach(function(userServergroup)
  1293.                     {
  1294.                         if (userServergroup.id() === group)
  1295.                         {
  1296.                             clientGroupNumberValue++;
  1297.                         }
  1298.                     });
  1299.                 });
  1300.             });
  1301.  
  1302.             return clientGroupNumberValue;
  1303.         }
  1304.         else
  1305.         {
  1306.             return clientGroups.length;
  1307.         }
  1308.     }
  1309.  
  1310.     /**
  1311.     * @fn clientAllowedGroupNumber Return the number of groups the client allowed to have
  1312.     * @param client client
  1313.     * @return Number of groups
  1314.     */
  1315.     function clientAllowedGroupNumber(client)
  1316.     {
  1317.         var clientGroups = client.getServerGroups(),
  1318.             maxAllowed   = config.limitGNValue;
  1319.  
  1320.         // Group number limitation (heavy but process only on buy)
  1321.         // Check for each sales plan if the groups are possessed by the user
  1322.         config.increaseGN.forEach(function(incGNGroup)
  1323.         {
  1324.             incGNGroup.groups.forEach(function(group)
  1325.             {
  1326.                 clientGroups.forEach(function(userServergroup)
  1327.                 {
  1328.                     if (userServergroup.id() === group)
  1329.                     {
  1330.                         maxAllowed += incGNGroup.increase;
  1331.                     }
  1332.                 });
  1333.             });
  1334.         });
  1335.  
  1336.         return maxAllowed;
  1337.     }
  1338.  
  1339.     /**
  1340.     * @fn userFound Return the client UID or flase and message the client about not found UID
  1341.     * @param userUID UID returned by getUserUID() function
  1342.     * @param client client
  1343.     * @return false or UID
  1344.     */
  1345.     function userFound(userUID, client)
  1346.     {
  1347.         if (userUID === null)
  1348.         {
  1349.             client.chat(config.userNotFound);
  1350.         }
  1351.  
  1352.         return userUID !== null;
  1353.     }
  1354.  
  1355.     /**
  1356.     * @fn addToHistory Adds to store history the provided entry
  1357.     * @param params Object with members:
  1358.     *   name: name of the client who performed the action
  1359.     *   groupID: servergroup ID
  1360.     *   action: action (buy or sell)
  1361.     */
  1362.     function addToHistory(params)
  1363.     {
  1364.         // Handle the channel
  1365.         var channel = backend.getChannelByID(config.historyChannel);
  1366.         if (!channel)
  1367.         {
  1368.             engine.log('SConomy: history channel not found');
  1369.             return;
  1370.         }
  1371.  
  1372.         // Handle the provided serverGroup
  1373.         var serverGrp = backend.getServerGroupByID(params.groupID);
  1374.         if (!serverGrp)
  1375.         {
  1376.             serverGrp = {name: function(){return config.groupNotFoud;}};
  1377.         }
  1378.  
  1379.         // Handle the output
  1380.         var baseOutput = '';
  1381.         switch (params.action)
  1382.         {
  1383.             case 'buy':
  1384.                 baseOutput = config.historyBuyStr;
  1385.                 break;
  1386.  
  1387.             case 'sell':
  1388.                 baseOutput = config.historySellStr;
  1389.                 break;
  1390.  
  1391.             default:
  1392.                 // Should never be called...
  1393.                 engine.log('SConomy: unknown action in addToHistory()');
  1394.                 break;
  1395.         }
  1396.  
  1397.         // Adds to the description
  1398.         var oldDesc = channel.description(),
  1399.             descArray = oldDesc.split('\n');
  1400.  
  1401.         if (descArray.length >= config.historyLimit)
  1402.         {
  1403.             // Remove oldest
  1404.             descArray.splice(0, 1);
  1405.         }
  1406.  
  1407.         descArray.push(baseOutput.replace(/%group/g, serverGrp.name())
  1408.                                  .replace(/%name/g, params.name)
  1409.                                  .replace(/%date/g, (new Date()).toLocaleString())
  1410.         );
  1411.  
  1412.         channel.setDescription(descArray.join('\n'));
  1413.     }
  1414.  
  1415.  
  1416. /* ============================= Chat functions ============================= */
  1417.  
  1418.     /**
  1419.     * @fn getHelp Send to client the help message
  1420.     * @param client client to send the info
  1421.     */
  1422.     function getHelp(client)
  1423.     {
  1424.         client.chat(
  1425.             config.helpOutput.replace(
  1426.                 /%money/g,
  1427.                 config.command
  1428.             ).replace(
  1429.                 /%store/g,
  1430.                 config.storeCommand
  1431.             ).replace(
  1432.                 /%buy/g,
  1433.                 config.buyCommand
  1434.             ).replace(
  1435.                 /%sell/g,
  1436.                 config.sellCommand
  1437.             ).replace(
  1438.                 /%give/g,
  1439.                 config.giveCommand
  1440.             ).replace(
  1441.                 /%f/g,
  1442.                 config.donationFee
  1443.             )
  1444.         );
  1445.     }
  1446.  
  1447.     /**
  1448.     * @fn getCurrency Send to client its current wallet amount
  1449.     * @param client client to send the info
  1450.     */
  1451.     function getCurrency(client)
  1452.     {
  1453.         var sconomy = sconomyGet({userUID: client.uid(), type: 'sconomy'});
  1454.         sconomy = sconomy ? sconomy : 0;
  1455.  
  1456.         client.chat(config.output.replace(/%d/g, sconomy.toFixed(config.viewDistance)));
  1457.  
  1458.         if (config.showProgress)
  1459.         {
  1460.             // Compute the increase and decrease factors for the groups
  1461.             var discount     = getDiscount(client, config.discountGroups),
  1462.                 chanDiscount = getChannelDiscount(client.getChannels()[0], config.discountChannels),
  1463.                 progress     = sconomyGet({userUID: client.uid(), type: 'progress'});
  1464.             progress = progress ? progress : 1;
  1465.  
  1466.             // Adds the channel discount to the user one
  1467.             discount.currencyIncreaseSum += chanDiscount.currencyIncreaseSum;
  1468.             discount.tickDecreaseSum     += chanDiscount.tickDecreaseSum;
  1469.             if (discount.tickDecreaseSum > 90) discount.tickDecreaseSum = 90;
  1470.  
  1471.             client.chat(
  1472.                 config.outputProgress.replace(
  1473.                     /%s/g,
  1474.                     progress + '/' + (config.tick * (1 - discount.tickDecreaseSum / 100)).toFixed(0)
  1475.                 ).replace(
  1476.                     /%c/g,
  1477.                     (config.currencyAmount * ((100 + discount.currencyIncreaseSum) / 100)).toFixed(config.viewDistance)
  1478.                 )
  1479.             );
  1480.         }
  1481.     }
  1482.  
  1483.     /**
  1484.     * @fn getStore Send to client the available purchase items (servergroups)
  1485.     * @param client client to send the info
  1486.     */
  1487.     function getStore(client)
  1488.     {
  1489.         // Header
  1490.         config.storeOutputHeader.split('\\n').forEach(function(line)
  1491.         {
  1492.             client.chat(line.replace(/%x/g, config.buyCommand));
  1493.         });
  1494.  
  1495.         // Body
  1496.         config.forSaleGroups.forEach(function(saleGroup)
  1497.         {
  1498.             saleGroup.groups.forEach(function(group)
  1499.             {
  1500.                 var backendGroup = backend.getServerGroupByID(group),
  1501.                     soldTypeString,
  1502.                     quantityString;
  1503.  
  1504.                 // Handle soldability strings
  1505.                 if (saleGroup.soldable)
  1506.                 {
  1507.                     if (saleGroup.soldPrice >= 0)
  1508.                     {
  1509.                         soldTypeString = config.storeOutputBodySP.replace(/%d/g, saleGroup.soldPrice.toFixed(config.viewDistance));
  1510.                     }
  1511.                     else
  1512.                     {
  1513.                         soldTypeString = config.storeOutputBodySN.replace(/%d/g, (-saleGroup.soldPrice).toFixed(config.viewDistance));
  1514.                     }
  1515.                 }
  1516.                 else
  1517.                 {
  1518.                     soldTypeString = config.storeOutputBodySI;
  1519.                 }
  1520.  
  1521.                 // Handle quantity string
  1522.                 if (saleGroup.isLimited)
  1523.                 {
  1524.                     var quantity = sconomyGet({userUID: 'SCO_GRP_' + group, type: 'quantity'});
  1525.                     if (typeof quantity === 'undefined') quantity = saleGroup.limitedNumber;
  1526.  
  1527.                     if (quantity === 0)
  1528.                     {
  1529.                         quantityString = config.storeOutputBodyIQLOUT.replace(/%d/g, saleGroup.limitedNumber);
  1530.                     }
  1531.                     else
  1532.                     {
  1533.                         quantityString = config.storeOutputBodyIQL.replace(/%d/g, quantity)
  1534.                                                                   .replace(/%c/g, saleGroup.limitedNumber);
  1535.                     }
  1536.                 }
  1537.                 else
  1538.                 {
  1539.                     quantityString = config.storeOutputBodyIQU;
  1540.                 }
  1541.  
  1542.                 // Adds the final item string to the output
  1543.                 client.chat(config.storeOutputBody.replace(/%s/g, backendGroup ? backendGroup.name() : config.groupNotFoud)
  1544.                                                   .replace(/%d/g, group)
  1545.                                                   .replace(/%x/g, saleGroup.price.toFixed(config.viewDistance))
  1546.                                                   .replace(/%c/g, soldTypeString)
  1547.                                                   .replace(/%q/g, quantityString)
  1548.                 );
  1549.             });
  1550.         });
  1551.     }
  1552.  
  1553.     /**
  1554.     * @fn buyServergroup Try to performe a sale based on the buyer message
  1555.     * @param message The full message sent by the buyer
  1556.     */
  1557.     function buyServergroup(message)
  1558.     {
  1559.         var requestedGroup = message.text.substr(config.buyCommand.length + 1).trim(),
  1560.             groupFound = false,
  1561.             alreadyAssigned = false;
  1562.  
  1563.         // Group number limitation
  1564.         if (config.limitGN && clientGroupNumber(message.client) >= clientAllowedGroupNumber(message.client))
  1565.         {
  1566.             message.client.chat(config.tooManyGroups);
  1567.         }
  1568.         else
  1569.         {
  1570.             // Proces all the groups of sales plans
  1571.             config.forSaleGroups.forEach(function(saleGroup)
  1572.             {
  1573.                 // Search the requested group
  1574.                 saleGroup.groups.forEach(function(group)
  1575.                 {
  1576.                     if (group === requestedGroup)
  1577.                     {
  1578.                         groupFound = true;
  1579.  
  1580.                         var quantity = 0;
  1581.                         if (saleGroup.isLimited)
  1582.                         {
  1583.                             // Check the availibility of the requested group
  1584.                             quantity = sconomyGet({userUID: 'SCO_GRP_' + group, type: 'quantity'});
  1585.                             if (typeof quantity === 'undefined') quantity = saleGroup.limitedNumber;
  1586.                         }
  1587.  
  1588.                         if (!saleGroup.isLimited || quantity > 0)
  1589.                         {
  1590.                             // Check if the user can buy
  1591.                             var sconomy = sconomyGet({userUID: message.client.uid(), type: 'sconomy'});
  1592.                             sconomy = sconomy ? sconomy : 0;
  1593.                             if (sconomy >= saleGroup.price)
  1594.                             {
  1595.                                 // Check if already assigned
  1596.                                 if (!config.allowDumbBuy)
  1597.                                 {
  1598.                                     alreadyAssigned = message.client.getServerGroups().some(function(userServergroup)
  1599.                                     {
  1600.                                         return group === userServergroup.id();
  1601.                                     });
  1602.                                 }
  1603.  
  1604.                                 // If user don't have the group or allowDumbBuy is on
  1605.                                 if (alreadyAssigned === false)
  1606.                                 {
  1607.                                     if (saleGroup.isLimited)
  1608.                                     {
  1609.                                         // Reduce the available quantity
  1610.                                         sconomySet({
  1611.                                             userUID: 'SCO_GRP_' + group,
  1612.                                             type: 'quantity',
  1613.                                             value: parseFloat(quantity - 1)
  1614.                                         });
  1615.                                     }
  1616.  
  1617.                                     // Take the price requested for the group
  1618.                                     sconomy -= saleGroup.price;
  1619.                                     sconomySet({
  1620.                                         userUID: message.client.uid(),
  1621.                                         type: 'sconomy',
  1622.                                         value: parseFloat(sconomy)
  1623.                                     });
  1624.  
  1625.                                     message.client.addToServerGroup(group);
  1626.                                     message.client.chat(config.buyPerformed);
  1627.  
  1628.                                     if (config.historyEnable)
  1629.                                     {
  1630.                                         addToHistory({
  1631.                                             name: message.client.name(),
  1632.                                             groupID: group,
  1633.                                             action: 'buy'
  1634.                                         });
  1635.                                     }
  1636.                                 }
  1637.                                 else
  1638.                                 {
  1639.                                     message.client.chat(config.buyAlreadyAssigned);
  1640.                                 }
  1641.                             }
  1642.                             else
  1643.                             {
  1644.                                 message.client.chat(config.buyTooExpensive);
  1645.                             }
  1646.                         }
  1647.                         else
  1648.                         {
  1649.                             message.client.chat(config.buyOutOfStock);
  1650.                         }
  1651.                     }
  1652.                 });
  1653.             });
  1654.  
  1655.             // Group not found
  1656.             if (!groupFound)
  1657.             {
  1658.                 message.client.chat(config.buyNotInStore);
  1659.             }
  1660.         }
  1661.     }
  1662.  
  1663.     /**
  1664.     * @fn sellServergroup Try to performe a refund based on the buyer message
  1665.     * @param message The full message sent by the buyer
  1666.     */
  1667.     function sellServergroup(message)
  1668.     {
  1669.         var requestedGroup = message.text.substr(config.sellCommand.length + 1).trim(),
  1670.             groupFound = false,
  1671.             userIsInGroup = false;
  1672.  
  1673.         config.forSaleGroups.forEach(function(saleGroup)
  1674.         {
  1675.             // Search the requested group
  1676.             saleGroup.groups.forEach(function(group)
  1677.             {
  1678.                 if (group === requestedGroup)
  1679.                 {
  1680.                     groupFound = true;
  1681.  
  1682.                     // Check the soldability
  1683.                     if (saleGroup.soldable)
  1684.                     {
  1685.                         // Check if the user has the group
  1686.                         userIsInGroup = message.client.getServerGroups().some(function(userServergroup)
  1687.                         {
  1688.                             return group === userServergroup.id();
  1689.                         });
  1690.  
  1691.                         // If user has the group
  1692.                         if (userIsInGroup)
  1693.                         {
  1694.                             var sconomy = sconomyGet({userUID: message.client.uid(), type: 'sconomy'});
  1695.                             sconomy = sconomy ? sconomy : 0;
  1696.  
  1697.                             // Check if user needs to pay to get the group removed
  1698.                             if (saleGroup.soldPrice < 0 && sconomy < (-saleGroup.soldPrice))
  1699.                             {
  1700.                                 message.client.chat(config.buyTooExpensive);
  1701.                             }
  1702.                             else
  1703.                             {
  1704.                                 if (saleGroup.isLimited)
  1705.                                 {
  1706.                                     // Get back the item in the circuit
  1707.                                     quantity = sconomyGet({userUID: 'SCO_GRP_' + group, type: 'quantity'});
  1708.                                     if (typeof quantity === 'undefined') quantity = saleGroup.limitedNumber;
  1709.                                     quantity++;
  1710.                                     if (quantity > saleGroup.limitedNumber) quantity = saleGroup.limitedNumber;
  1711.                                     sconomySet({
  1712.                                         userUID: 'SCO_GRP_' + group,
  1713.                                         type: 'quantity',
  1714.                                         value: parseFloat(quantity)
  1715.                                     });
  1716.                                 }
  1717.  
  1718.                                 // Refund the wallet
  1719.                                 sconomy += saleGroup.soldPrice;
  1720.                                 sconomySet({
  1721.                                     userUID: message.client.uid(),
  1722.                                     type: 'sconomy',
  1723.                                     value: parseFloat(sconomy)
  1724.                                 });
  1725.  
  1726.                                 message.client.removeFromServerGroup(group, group);
  1727.                                 message.client.chat(config.sellPerformed);
  1728.  
  1729.                                 if (config.historyEnable && config.historyIncludeSell)
  1730.                                 {
  1731.                                     addToHistory({
  1732.                                         name: message.client.name(),
  1733.                                         groupID: group,
  1734.                                         action: 'sell'
  1735.                                     });
  1736.                                 }
  1737.                             }
  1738.                         }
  1739.                         else
  1740.                         {
  1741.                             message.client.chat(config.sellNotInGroup);
  1742.                         }
  1743.                     }
  1744.                     else
  1745.                     {
  1746.                         message.client.chat(config.sellNotSoldable);
  1747.                     }
  1748.                 }
  1749.             });
  1750.         });
  1751.  
  1752.         // Message the result to the client
  1753.         if (!groupFound)
  1754.         {
  1755.             message.client.chat(config.sellNotInStore);
  1756.         }
  1757.     }
  1758.  
  1759.     /**
  1760.     * @fn giveCurrency Try to give money based on the client full message
  1761.     * @param message The full message sent by the client
  1762.     */
  1763.     function giveCurrency(message)
  1764.     {
  1765.         var fullArgument = message.text.substr(config.giveCommand.length + 1).trim(),
  1766.             argSplit = fullArgument.split(' ');
  1767.  
  1768.         if (argSplit.length >= 2)
  1769.         {
  1770.             // Compute arguments
  1771.             var requestedCurrency = argSplit.splice(argSplit.length - 1, 1)[0],
  1772.                 currency = parseFloat(requestedCurrency),
  1773.                 userUID  = getUserUID(argSplit.join(' ').trim(), !config.givingOnlineOnly);
  1774.  
  1775.             if (userFound(userUID, message.client))
  1776.             {
  1777.                 if (currency && currency > 0)
  1778.                 {
  1779.                     var sconomy = sconomyGet({userUID: message.client.uid(), type: 'sconomy'});
  1780.                     sconomy = sconomy ? sconomy : 0;
  1781.  
  1782.                     if (sconomy >= currency)
  1783.                     {
  1784.                         // Taking apart the currency
  1785.                         sconomy -= currency;
  1786.                         sconomySet({
  1787.                             userUID: message.client.uid(),
  1788.                             type: 'sconomy',
  1789.                             value: parseFloat(sconomy)
  1790.                         });
  1791.  
  1792.                         // Get the amount after the fees calculations
  1793.                         var newSconomy = currency * ((100 - config.donationFee) / 100);
  1794.  
  1795.                         // Giving the currency to the receiver
  1796.                         var receiver = sconomyGet({userUID: userUID, type: 'sconomy'});
  1797.                         receiver = receiver ? receiver + newSconomy : newSconomy;
  1798.                         sconomySet({
  1799.                             userUID: userUID,
  1800.                             type: 'sconomy',
  1801.                             value: parseFloat(receiver)
  1802.                         });
  1803.  
  1804.                         // Notify the donator
  1805.                         message.client.chat(config.transactionSucceed.replace(/%d/g, currency.toFixed(config.viewDistance)));
  1806.  
  1807.                         // Notify the receiver
  1808.                         var receiverClient = backend.getClientByUniqueID(userUID);
  1809.                         if (receiverClient)
  1810.                         {
  1811.                             receiverClient.chat(
  1812.                                 config.gotDonation.replace(/%d/g, newSconomy.toFixed(config.viewDistance))
  1813.                                                   .replace(/%s/g, message.client.name())
  1814.                               );
  1815.                         }
  1816.                     }
  1817.                     else
  1818.                     {
  1819.                         message.client.chat(config.tooPoorForDonation);
  1820.                     }
  1821.                 }
  1822.                 else
  1823.                 {
  1824.                     message.client.chat(config.notValidNumber.replace(/%d/g, requestedCurrency));
  1825.                 }
  1826.             }
  1827.         }
  1828.     }
  1829.  
  1830.     /**
  1831.     * @fn getUserCurrency Try to get a user wallet amount based on the full admin request message
  1832.     * @param message The full message sent by the admin
  1833.     */
  1834.     function getUserCurrency(message)
  1835.     {
  1836.         var userUID = getUserUID(message.text.substr(config.getUserCommand.length + 1).trim(), true);
  1837.         if (userFound(userUID, message.client))
  1838.         {
  1839.             var sconomy = sconomyGet({userUID: userUID, type: 'sconomy'});
  1840.             sconomy = sconomy ? sconomy : 0;
  1841.  
  1842.             message.client.chat(config.getUserOutput.replace(/%d/g, sconomy.toFixed(config.viewDistance)));
  1843.         }
  1844.     }
  1845.  
  1846.     /**
  1847.     * @fn setUserCurrency Try to set a user wallet amount based on the full admin request message
  1848.     * @param message The full message sent by the admin
  1849.     */
  1850.     function setUserCurrency(message)
  1851.     {
  1852.         var fullArgument = message.text.substr(config.setUserCommand.length + 1).trim(),
  1853.             argSplit = fullArgument.split(' ');
  1854.  
  1855.         if (argSplit.length >= 2)
  1856.         {
  1857.             // Compute arguments
  1858.             var currency = parseFloat(argSplit.splice(argSplit.length - 1, 1)[0]),
  1859.                 userUID  = getUserUID(argSplit.join(' ').trim(), true);
  1860.  
  1861.             if (userFound(userUID, message.client) && !isNaN(currency))
  1862.             {
  1863.                 sconomySet({
  1864.                     userUID: userUID,
  1865.                     type: 'sconomy',
  1866.                     value: parseFloat(currency)
  1867.                 });
  1868.                 var sconomy = sconomyGet({userUID: userUID, type: 'sconomy'});
  1869.  
  1870.                 message.client.chat(config.setUserOutput.replace(/%d/g, sconomy.toFixed(config.viewDistance)));
  1871.             }
  1872.         }
  1873.         else
  1874.         {
  1875.             message.client.chat(config.notEnoughtArgument.replace(/%h/g, config.helpCommand));
  1876.         }
  1877.     }
  1878.  
  1879.     /**
  1880.     * @fn addUserCurrency Try to add currency to a user wallet based on the full admin request message
  1881.     * @param message The full message sent by the admin
  1882.     */
  1883.     function addUserCurrency(message)
  1884.     {
  1885.         var fullArgument = message.text.substr(config.addUserCommand.length + 1).trim(),
  1886.             argSplit = fullArgument.split(' ');
  1887.  
  1888.         if (argSplit.length >= 2)
  1889.         {
  1890.             // Compute arguments
  1891.             var currency = parseFloat(argSplit.splice(argSplit.length - 1, 1)[0]);
  1892.                 userUID  = getUserUID(argSplit.join(' ').trim(), true);
  1893.  
  1894.             if (userFound(userUID, message.client) && !isNaN(currency))
  1895.             {
  1896.                 var sconomy = sconomyGet({userUID: userUID, type: 'sconomy'});
  1897.                 sconomy = sconomy ? sconomy : 0;
  1898.                 sconomySet({
  1899.                     userUID: userUID,
  1900.                     type: 'sconomy',
  1901.                     value: parseFloat(sconomy + currency)
  1902.                 });
  1903.                 sconomy = sconomyGet({userUID: userUID, type: 'sconomy'});
  1904.  
  1905.                 message.client.chat(config.setUserOutput.replace(/%d/g, sconomy.toFixed(config.viewDistance)));
  1906.             }
  1907.         }
  1908.         else
  1909.         {
  1910.             message.client.chat(config.notEnoughtArgument.replace(/%h/g, config.helpCommand));
  1911.         }
  1912.     }
  1913.  
  1914.     /**
  1915.     * @fn removeUserCurrency Try to remove currency to a user wallet based on the full admin request message
  1916.     * @param message The full message sent by the admin
  1917.     */
  1918.     function removeUserCurrency(message)
  1919.     {
  1920.         var fullArgument = message.text.substr(config.removeUserCommand.length + 1).trim(),
  1921.             argSplit = fullArgument.split(' ');
  1922.  
  1923.         if (argSplit.length >= 2)
  1924.         {
  1925.             // Compute arguments
  1926.             var currency = parseFloat(argSplit.splice(argSplit.length - 1, 1)[0]),
  1927.                 userUID  = getUserUID(argSplit.join(' ').trim(), true);
  1928.  
  1929.             if (userFound(userUID, message.client) && !isNaN(currency))
  1930.             {
  1931.                 var sconomy = sconomyGet({userUID: userUID, type: 'sconomy'});
  1932.                 sconomy = sconomy ? sconomy : 0;
  1933.                 sconomySet({
  1934.                     userUID: userUID,
  1935.                     type: 'sconomy',
  1936.                     value: parseFloat(sconomy - currency)
  1937.                 });
  1938.                 sconomy = sconomyGet({userUID: userUID, type: 'sconomy'});
  1939.  
  1940.                 message.client.chat(config.setUserOutput.replace(/%d/g, sconomy.toFixed(config.viewDistance)));
  1941.             }
  1942.         }
  1943.         else
  1944.         {
  1945.             message.client.chat(config.notEnoughtArgument.replace(/%h/g, config.helpCommand));
  1946.         }
  1947.     }
  1948.  
  1949.     /**
  1950.     * @fn setAllUserCurrency Set all user wallet amount based on the full admin request message
  1951.     * @param message The full message sent by the admin
  1952.     */
  1953.     function setAllUserCurrency(message)
  1954.     {
  1955.         var amount = message.text.substr(config.setAllUserCommand.length + 1).trim();
  1956.  
  1957.         if ((amount = parseFloat(amount)))
  1958.         {
  1959.             sconomySetAll({type: 'sconomy', value: amount});
  1960.             message.client.chat(config.setUserOutput.replace(/%d/g, amount.toFixed(config.viewDistance)));
  1961.         }
  1962.         else
  1963.         {
  1964.             message.client.chat(config.notValidNumber.replace(/%d/g, message.text.substr(config.setAllUserCommand.length + 1).trim()));
  1965.         }
  1966.     }
  1967.  
  1968.     /**
  1969.     * @fn setStoreQuantity Set an item quantity based on the full admin request message
  1970.     * @param message The full message sent by the admin
  1971.     */
  1972.     function setStoreQuantity(message)
  1973.     {
  1974.         var args = message.text.substr(config.setStoreQuantity.length + 1).trim().split(' ');
  1975.  
  1976.         if (args.length >= 2)
  1977.         {
  1978.             var group  = parseFloat(args[0]),
  1979.                 amount = parseFloat(args[args.length - 1]);
  1980.  
  1981.             if (!isNaN(group) && !isNaN(amount))
  1982.             {
  1983.                 // Actual setting
  1984.                 sconomySet({
  1985.                     userUID: 'SCO_GRP_' + group,
  1986.                     type: 'quantity',
  1987.                     value: amount
  1988.                 });
  1989.  
  1990.                 message.client.chat(config.setStoreOutput.replace(/%d/g, amount.toFixed(config.viewDistance)));
  1991.             }
  1992.             else
  1993.             {
  1994.                 message.client.chat(config.notValidNumber.replace(/%d/g, args[0] + ' - ' + args[args.length - 1]));
  1995.             }
  1996.         }
  1997.         else
  1998.         {
  1999.             message.client.chat(config.notEnoughtArgument.replace(/%h/g, config.helpCommand));
  2000.         }
  2001.     }
  2002.  
  2003.     /**
  2004.     * @fn migrateDataFromProvider Migrate from data from one provider to another based on the full admin request message
  2005.     * @param message The full message sent by the admin
  2006.     */
  2007.     function migrateDataFromProvider(message)
  2008.     {
  2009.         /*
  2010.         * Possible arguments:
  2011.         * private_public
  2012.         * public_private
  2013.         * unset_private
  2014.         * unset_public
  2015.         * <any other argument added by the sconomy external data provider>
  2016.         */
  2017.  
  2018.         var arg = message.text.substr(29).trim();
  2019.  
  2020.         if (typeof migrationProvider[arg] === "function")
  2021.         {
  2022.             // Save users progress
  2023.             backend.getClients().forEach(function(client)
  2024.             {
  2025.                 antiIOProvider.flush(client.uid(), false);
  2026.             });
  2027.  
  2028.             // Migrate the data
  2029.             var success = migrationProvider[arg](store);
  2030.  
  2031.             message.client.chat(success ? "Should be OK, see the log for sure" : "Error");
  2032.         }
  2033.         else
  2034.         {
  2035.             message.client.chat("Unknown argument");
  2036.         }
  2037.     }
  2038.  
  2039.  
  2040. /* ============================= Start process ============================= */
  2041.  
  2042.     event.on('load', function()
  2043.     {
  2044.         // Try to link sconomy to a database
  2045.         sconomyDBIntegration();
  2046.  
  2047. /* ============================== Timer start ============================== */
  2048.  
  2049.         setTimeout(computeTick, 1000);
  2050.  
  2051.  
  2052. /* ================== Client connection events registring ================== */
  2053.  
  2054.         event.on('clientMove', function(evt)
  2055.         {
  2056.             // Client leaves
  2057.             if (typeof evt.toChannel === 'undefined')
  2058.             {
  2059.                 // Flush the RAM-proress as the main function won't be capable of
  2060.                 antiIOProvider.flush(evt.client.uid(), true);
  2061.             }
  2062.         });
  2063.  
  2064.  
  2065. /* ========================= Chat events registring ========================= */
  2066.  
  2067.         // Chat response
  2068.         event.on('chat', function(message)
  2069.         {
  2070.             // Get help
  2071.             if (message.text === config.helpCommand)
  2072.             {
  2073.                 getHelp(message.client);
  2074.             }
  2075.  
  2076.             // Get wallet amount
  2077.             else if (message.text === config.command)
  2078.             {
  2079.                 // Flush the RAM-proress (compatibility purpose)
  2080.                 antiIOProvider.flush(message.client.uid(), false);
  2081.  
  2082.                 getCurrency(message.client);
  2083.             }
  2084.  
  2085.             // Get the store
  2086.             else if (message.text === config.storeCommand)
  2087.             {
  2088.                 getStore(message.client);
  2089.             }
  2090.  
  2091.             // Buy
  2092.             else if (message.text.startsWith(config.buyCommand))
  2093.             {
  2094.                 buyServergroup(message);
  2095.             }
  2096.  
  2097.             // Sell
  2098.             else if (message.text.startsWith(config.sellCommand))
  2099.             {
  2100.                 sellServergroup(message);
  2101.             }
  2102.  
  2103.             // Give
  2104.             else if (config.enableGiving && message.text.startsWith(config.giveCommand))
  2105.             {
  2106.                 giveCurrency(message);
  2107.             }
  2108.  
  2109.             // Permission check
  2110.             else if (isAdmin(message.client))
  2111.             {
  2112.                 // Get a user sconomy
  2113.                 if (message.text.startsWith(config.getUserCommand))
  2114.                 {
  2115.                     getUserCurrency(message);
  2116.                 }
  2117.  
  2118.                 // Set a user sconomy
  2119.                 else if (message.text.startsWith(config.setUserCommand))
  2120.                 {
  2121.                     setUserCurrency(message);
  2122.                 }
  2123.  
  2124.                 // Add currency to a user
  2125.                 else if (message.text.startsWith(config.addUserCommand))
  2126.                 {
  2127.                     addUserCurrency(message);
  2128.                 }
  2129.  
  2130.                 // Remove currency to a user
  2131.                 else if (message.text.startsWith(config.removeUserCommand))
  2132.                 {
  2133.                     removeUserCurrency(message);
  2134.                 }
  2135.  
  2136.                 // Set all user sconomy
  2137.                 else if (message.text.startsWith(config.setAllUserCommand))
  2138.                 {
  2139.                     setAllUserCurrency(message);
  2140.                 }
  2141.  
  2142.                 // Set store item quantity
  2143.                 else if (message.text.startsWith(config.setStoreQuantity))
  2144.                 {
  2145.                     setStoreQuantity(message);
  2146.                 }
  2147.  
  2148.                 // Migration command
  2149.                 else if (message.text.startsWith('!sconomy-data-migration-tool '))
  2150.                 {
  2151.                     // Small confirmation that may save some people
  2152.                     if (!migrationProvider.confirmation)
  2153.                     {
  2154.                         migrationProvider.confirmation = true;
  2155.                         setTimeout(function()
  2156.                         {
  2157.                             migrationProvider.confirmation = false;
  2158.                         }, 5000);
  2159.  
  2160.                         message.client.chat("You have 5 seconds to send it again to confirm your request");
  2161.                     }
  2162.                     else
  2163.                     {
  2164.                         migrateDataFromProvider(message);
  2165.                     }
  2166.                 }
  2167.             }
  2168.         });
  2169.  
  2170.         // log info on startup
  2171.         engine.log(         info.name    +
  2172.                    ' v'   + info.version +
  2173.                    ' by ' + info.author  +
  2174.                    ' loaded successfully!'
  2175.         );
  2176.     });
  2177. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement