A Twitch.tv viewer reward and games system.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1355 lines
54 KiB

12 years ago
12 years ago
12 years ago
  1. /**
  2. * api:
  3. * Currency(irc object, database object, [required options])
  4. *
  5. * example:
  6. * var Currency = require('./lib/plugins/currency.js')(irc, db, {
  7. * currency : 'currency name',
  8. * subscribers : 'google doc spreadsheet until it's available from twitch api'
  9. * });
  10. *
  11. * commands:
  12. * !<currency>
  13. * reply with currency amount
  14. *
  15. * !<currency> on/[off repeat on/off]
  16. * toggle currency request status,
  17. * repeat status only available when
  18. * turning off requests
  19. *
  20. * !<currency> auction open
  21. * open a new auction
  22. *
  23. * !<currency> auction close
  24. * close current auction
  25. *
  26. * !<currency> auction cancel
  27. * cancel current auction
  28. *
  29. * !<currency> auction draw
  30. * draw the next highest bidder
  31. *
  32. * !bid <amount>
  33. * place a bid on an open auction,
  34. * only valid amounts will be accepted
  35. *
  36. * !<currency> raffle open <price> <max>
  37. * open a new raffle
  38. * price and max is optional
  39. * default price: 10
  40. * default max: 10
  41. *
  42. * !<currency> raffle close
  43. * draw the another ticket from raffle
  44. *
  45. * !<currency> raffle cancel
  46. * cancel the open raffle
  47. *
  48. * !<currency> raffle draw
  49. * open a new auction
  50. *
  51. * !<currency> raffle restore
  52. * restores a previous raffle if a new
  53. * one is accidentally opened
  54. *
  55. * !ticket <amount>
  56. * place a bid on an open auction,
  57. * only valid amounts will be accepted
  58. */
  59. var https = require('https'),
  60. http = require('http'),
  61. utils = require('./utils.js');
  62. //-------- Construct ---------
  63. function Currency(irc, db, options) {
  64. var __self = this;
  65. __self.irc = irc;
  66. __self.db = db;
  67. // config
  68. __self.config = options || {};
  69. __self.config.currency = options.currency || 'coins';
  70. __self.config.subscribers_json = options.subscribers || '';
  71. __self.config.website = options.website || '';
  72. __self.config.modpowers = options.modpowers || false;
  73. // general settings
  74. __self.pre_text = '> ' + __self.config.currency + ': ';
  75. __self.max_requests = 10;//response after 10 request
  76. __self.temp = {};
  77. // currency request settings
  78. __self.coin_flood = [];
  79. __self.coin_response = null;
  80. __self.coin_response_timer = 3000;
  81. __self.coin_response_reset = true;
  82. __self.coin_toggle = false;
  83. __self.coin_toggle_msg = null;
  84. __self.coin_toggle_timer = 180000;//milliseconds
  85. // auction settings
  86. __self.auction_status = false;
  87. __self.auction_bids = [];
  88. __self.auction_previous_bid = {};
  89. __self.auction_bid_response = null;
  90. __self.auction_bid_response_long = null;
  91. // handout coins settings
  92. __self.viewer_list = [];
  93. __self.streaming = false;
  94. __self.streaming_check = 4;//minutes
  95. __self.give_coins = false;
  96. __self.give_coins_timer = options.payrate || 30;//minutes
  97. __self.subscriber_check = 4;//minutes
  98. __self.subscribers = [];
  99. // raffle settings
  100. __self.raffle_status = false;
  101. __self.raffle_ticket_requests = [];
  102. __self.raffle_tickets = [];
  103. __self.raffle_ticket_cost = 10;//currency cost per ticket
  104. __self.raffle_max_tickets = 10;
  105. // raffle restoration
  106. __self.raffle_restore_ticket_requests = [];
  107. __self.raffle_restore_tickets = [];
  108. // gambling settings
  109. __self.bets_status = false;
  110. __self.bets_board = [];
  111. __self.bets_viewers = [];
  112. __self.bets_payout = false;
  113. }
  114. //-------- Methods ---------
  115. Currency.prototype.start = function () {
  116. var __self = this;
  117. __self.handout_coins();
  118. };
  119. Currency.prototype.commands = function (data) {
  120. var __self = this,
  121. broadcaster_bot_initiated = __self.irc.caller(data[0]).toLowerCase() === __self.irc.config.broadcaster.toLowerCase() || __self.irc.caller(data[0]).toLowerCase() === __self.irc.config.name.toLowerCase(),
  122. moderator_initiated = __self.irc.mods.indexOf(__self.irc.caller(data[0])) > 0;
  123. // handle !<currency> commands
  124. if (data[3].slice(1) === '!' + __self.config.currency.toLowerCase()) {
  125. // public commands
  126. if (!__self.coin_toggle && data[4] === undefined) {
  127. __self.get_coins(__self.irc.caller(data[0]));
  128. }
  129. // broadcaster only commands
  130. if (broadcaster_bot_initiated || (__self.config.modpowers && moderator_initiated)) {
  131. //open / close auction system
  132. if (data[4] === 'auction') {
  133. switch (data[5]) {
  134. case 'open':
  135. __self.auction(true);
  136. break;
  137. case 'close':
  138. __self.auction(false);
  139. break;
  140. case 'draw':
  141. __self.next_auction_winner();
  142. break;
  143. case 'cancel':
  144. __self.auction('cancel');
  145. break;
  146. }
  147. }
  148. // open / close raffle system
  149. if (data[4] === 'raffle') {
  150. switch (data[5]) {
  151. case 'open':
  152. if (data[6] && data[7] && !__self.raffle_status) {
  153. if(parseInt(data[6], 10) > 0 && parseInt(data[7], 10) > 0) {
  154. // save default values
  155. __self.temp.raffle_ticket_cost = __self.raffle_ticket_cost;
  156. __self.temp.raffle_max_tickets = __self.raffle_max_tickets;
  157. // set new raffle cost / amount
  158. __self.raffle_ticket_cost = data[6];
  159. __self.raffle_max_tickets = data[7];
  160. }
  161. } else if (__self.temp.raffle_ticket_cost && __self.temp.raffle_max_tickets && !__self.raffle_status){
  162. __self.raffle_ticket_cost = __self.temp.raffle_ticket_cost;
  163. __self.raffle_max_tickets = __self.temp.raffle_max_tickets;
  164. delete __self.temp.raffle_ticket_cost;
  165. delete __self.temp.raffle_max_tickets;
  166. }
  167. __self.raffle(true);
  168. break;
  169. case 'close':
  170. __self.raffle(false);
  171. break;
  172. case 'draw':
  173. __self.next_raffle_winner();
  174. break;
  175. case 'cancel':
  176. __self.raffle('cancel');
  177. break;
  178. case 'restore':
  179. __self.raffle('restore');
  180. break;
  181. }
  182. }
  183. // open / close betting system
  184. if (data[4] === 'bet') {
  185. switch (data[5]) {
  186. case 'open':
  187. if (data[5] && data[6]) {
  188. __self.bets(true, data);
  189. } else {
  190. __self.irc.emit('message', {message:__self.pre_text + 'Unable to open betting, need at least two items to bet against'});
  191. }
  192. break;
  193. case 'close':
  194. __self.bets(false, null);
  195. break;
  196. case 'winner':
  197. //__self.bets('winner');
  198. break;
  199. }
  200. }
  201. // add currency
  202. if (data[4] === 'add') {
  203. if(parseInt(data[5], 10) > 0 && data[6]) {
  204. __self.adjust_currency('add', data[5], data[6]);
  205. }
  206. }
  207. // remove currency
  208. if (data[4] === 'remove') {
  209. if(parseInt(data[5], 10) > 0 && data[6]) {
  210. __self.adjust_currency('remove', data[5], data[6]);
  211. }
  212. }
  213. // push currency to new viewer
  214. if (data[4] === 'push') {
  215. if(parseInt(data[5], 10) > 0 && data[6]) {
  216. __self.adjust_currency('push', data[5], data[6]);
  217. }
  218. }
  219. }
  220. // moderator commands
  221. if (broadcaster_bot_initiated || moderator_initiated) {
  222. // enable/disable currency requests
  223. switch (data[4]) {
  224. case 'on':
  225. if (!__self.auction_status && !__self.raffle_status) {
  226. __self.coin_toggle = false;
  227. // output currency request status
  228. __self.irc.emit('message', {message:__self.pre_text + 'Currency requests are now enabled. Type !' + __self.config.currency.toLowerCase() + ' to view your total'});
  229. // stop periodic message
  230. clearInterval(__self.coin_toggle_msg);
  231. }
  232. break;
  233. case 'off':
  234. if (!__self.auction_status && !__self.raffle_status) {
  235. var msg;
  236. if (!__self.coin_toggle) {
  237. // output message depending on if an offsite is provided
  238. if (__self.config.website !== '') {
  239. msg = __self.pre_text + 'Currency requests have been disabled. To view your ' + __self.config.currency + ' please visit ' + __self.config.website;
  240. __self.irc.emit('message', {message:msg});
  241. } else {
  242. msg = __self.pre_text + 'Currency requests have been disabled';
  243. __self.irc.emit('message', {message:msg});
  244. }
  245. }
  246. // start the periodic message
  247. if (data[5] !== undefined && data[6] !== undefined) {
  248. // manually enable / disable repeat
  249. if (data[5] === 'repeat') {
  250. switch (data[6]) {
  251. case 'on':
  252. __self.irc.emit('message', {message:'+ Periodic notification enabled'});
  253. __self.coin_toggle_msg = setInterval(function () {
  254. if (__self.coin_toggle) {
  255. msg = __self.pre_text + 'To view your ' + __self.config.currency + ' please visit ' + __self.config.website;
  256. __self.irc.emit('message', {message:msg});
  257. }
  258. }, __self.coin_toggle_timer);
  259. break;
  260. case 'off':
  261. __self.irc.emit('message', {message:'+ Periodic notification disabled'});
  262. clearInterval(__self.coin_toggle_msg);
  263. }
  264. }
  265. }
  266. __self.coin_toggle = true;
  267. }
  268. break;
  269. }
  270. // adjust currency response rate
  271. if (data[4] === 'timer') {
  272. if (isNaN(parseInt(data[5], 10)) === false) {
  273. if (data[5] >= 3 && data[5] % 1 === 0) {
  274. __self.coin_response_timer = data[5] * 1000;
  275. __self.irc.emit('message', {message:__self.pre_text + 'Currency totals will now show ' + data[5] + ' seconds after request'});
  276. if (data[6] && data[7]) {
  277. if (data[6] === 'reset') {
  278. switch(data[7]) {
  279. case 'on':
  280. __self.irc.emit('message', {message:'+ Timer will now reset after each new request'});
  281. __self.coin_response_reset = true;
  282. break;
  283. case 'off':
  284. __self.irc.emit('message', {message:'+ Timer will not reset after each new request'});
  285. __self.coin_response_reset = false;
  286. break;
  287. }
  288. }
  289. }
  290. } else if (data[5] < 3) {
  291. __self.irc.emit('message', {message:__self.pre_text + 'Timer cannot be less than 2 seconds'});
  292. }
  293. }
  294. }
  295. }
  296. }
  297. // public commands related to !<currency>
  298. switch (data[3].slice(1)) {
  299. // submit bid for the auction
  300. case '!bid':
  301. if (isNaN(parseInt(data[4], 10)) === false) {
  302. if (data[4] > 0 && data[4] % 1 === 0) {
  303. __self.bid(__self.irc.caller(data[0]), parseInt(data[4], 10));
  304. }
  305. }
  306. break;
  307. // purchase a ticket for raffle
  308. case '!ticket':
  309. if (isNaN(parseInt(data[4], 10)) === false) {
  310. if (data[4] >= 0 && data[4] % 1 === 0) {
  311. __self.collect_tickets(__self.irc.caller(data[0]), parseInt(data[4], 10));
  312. }
  313. }
  314. break;
  315. }
  316. // place a bet
  317. if (__self.bets_status === true) {
  318. for (var i = 0; i < __self.bets_board.length; i++) {
  319. if (data[3].slice(1) === '!' + __self.bets_board[i]) {
  320. if (isNaN(parseInt(data[4], 10)) === false) {
  321. if (data[4] >= 0 && data[4] % 1 === 0) {
  322. __self.collect_bets(__self.irc.caller(data[0]), __self.bets_board[i], parseInt(data[4], 10));
  323. break;
  324. }
  325. }
  326. }
  327. }
  328. }
  329. };
  330. /**
  331. * ============================================
  332. * CURRENCY REQUESTS
  333. * --------------------------------------------
  334. */
  335. Currency.prototype.get_coins = function (caller) {
  336. var __self = this;
  337. function fill_request(viewer, points) {
  338. var request = '(' + points + ')';
  339. if (__self.raffle_status) {
  340. for (var i = 0; i < __self.raffle_ticket_requests.length; i++){
  341. if (__self.raffle_ticket_requests[i].viewer.toLowerCase() === viewer.toLowerCase() && (__self.raffle_ticket_requests[i].tickets * __self.raffle_ticket_cost) <= points) {
  342. request = '(' + (points - (__self.raffle_ticket_requests[i].tickets * __self.raffle_ticket_cost)) + ') [' + __self.raffle_ticket_requests[i].tickets + ']';
  343. break;
  344. }
  345. }
  346. return request;
  347. } else {
  348. return request;
  349. }
  350. }
  351. function do_work() {
  352. var multi_response = '';
  353. if (__self.coin_flood.length > 1) {// send flood requests
  354. __self.query_coins(__self.coin_flood, function (rows) {
  355. for (var i = 0; i < rows.length; i++) {
  356. var currency_request = fill_request(rows[i].user, rows[i].points);
  357. // setup currency response
  358. if (i !== rows.length - 1) {
  359. multi_response += rows[i].user + ' ' + currency_request + ', ';
  360. } else {
  361. multi_response += rows[i].user + ' ' + currency_request;
  362. }
  363. }
  364. __self.irc.emit('message', {message:__self.pre_text + multi_response, timer: 1});
  365. });
  366. } else if (__self.coin_flood.length === 1) {// send single request
  367. __self.query_coins(caller, function (rows) {
  368. var currency_request = fill_request(rows[0].user, rows[0].points);
  369. __self.irc.emit('message', {message:__self.pre_text + caller + ' ' + currency_request, timer: 1});
  370. });
  371. }
  372. // clear flood requests
  373. __self.coin_flood = [];
  374. }
  375. // add flood users to array
  376. if (__self.coin_flood.indexOf(caller) < 0) {
  377. __self.coin_flood.push(caller);
  378. }
  379. // clear timer on flood
  380. if (__self.coin_response_reset) {
  381. clearTimeout(__self.coin_response);
  382. }
  383. // check if flood has a set amount of requests and output
  384. // if not, set the output timer
  385. if (__self.coin_flood.length === __self.max_requests) {
  386. do_work();
  387. } else {
  388. if (__self.coin_response_reset) {
  389. __self.coin_response = setTimeout(function () {do_work();}, __self.coin_response_timer);
  390. } else {
  391. setTimeout(function () {do_work();}, __self.coin_response_timer);
  392. }
  393. }
  394. };
  395. Currency.prototype.query_coins = function (data, callback) {
  396. var __self = this, sql = '';
  397. // build sql conditions
  398. if (typeof data === 'string') {
  399. sql = 'SELECT * FROM viewers WHERE ' + 'user = \'' + data.toLowerCase() + '\'';
  400. } else {
  401. for (var i = 0; i < data.length; i++) {
  402. if (i !== data.length - 1) {
  403. sql += 'SELECT * FROM viewers WHERE ' + 'user = \'' + data[i].toLowerCase() + '\'' + ';';
  404. } else {
  405. sql += 'SELECT * FROM viewers WHERE ' + 'user = \'' + data[i].toLowerCase() + '\'';
  406. }
  407. }
  408. }
  409. // execute query
  410. __self.db.execute(sql, function (rows) {
  411. var temp = [], newrows = [];
  412. if (typeof data !== 'string') {
  413. // get rid of the nested arrays
  414. for (var i = 0; i < rows.length; i++) {
  415. if (rows[i].length > 0) {
  416. newrows.push(rows[i][0]);
  417. }
  418. }
  419. // separate users into their own array
  420. for (var i = 0; i < newrows.length; i++) {
  421. temp.push(newrows[i].user.charAt(0).toUpperCase() + newrows[i].user.slice(1));
  422. }
  423. // compare the users in the data array against the temp array
  424. // if not found, push them to rows with 0 points
  425. for (var i = 0; i < data.length; i++) {
  426. if (temp.indexOf(data[i]) < 0) {
  427. newrows.push({'user' : data[i], 'points' : 0});
  428. }
  429. }
  430. // capitalize usernames on rows
  431. for (var key in newrows) {
  432. if (newrows.hasOwnProperty(key)) {
  433. newrows[key].user = newrows[key].user.charAt(0).toUpperCase() + newrows[key].user.slice(1);
  434. }
  435. }
  436. rows = newrows;
  437. } else {
  438. if (rows.length === 0) {
  439. rows = [{'user' : data, 'points' : 0}];
  440. } else {
  441. rows[0].user = rows[0].user.charAt(0).toUpperCase() + rows[0].user.slice(1);
  442. }
  443. }
  444. callback(rows);
  445. });
  446. };
  447. /**
  448. * ============================================
  449. * HANDOUT CURRENCY
  450. * --------------------------------------------
  451. */
  452. Currency.prototype.handout_coins = function () {
  453. var __self = this;
  454. // check stream status
  455. function stream_status() {
  456. var time = utils.make_interval(__self.streaming_check);
  457. if (time === 0) {
  458. // get stream status
  459. https.get('https://api.twitch.tv/kraken/streams/' + __self.irc.config.channel.slice(1), function (response) {
  460. var body = '';
  461. // put together response
  462. response.on('data', function (chunk) {
  463. body += chunk;
  464. });
  465. // start / stop handing out coins based on stream status
  466. response.on('end', function () {
  467. var json = JSON.parse(body);
  468. __self.streaming = json.stream !== null;
  469. if (__self.streaming && __self.give_coins === false) {
  470. insert_coins();
  471. }
  472. __self.irc.emit('data', 'DATA - Online Status Check - Returned: ' + __self.streaming);
  473. setTimeout(stream_status, 1000);
  474. });
  475. });
  476. } else {
  477. setTimeout(stream_status, time);
  478. }
  479. }
  480. // get subscribers
  481. function subscribers() {
  482. var time = utils.make_interval(__self.subscriber_check);
  483. if (time === 0) {
  484. // get stream status
  485. http.get(__self.config.subscribers_json, function (response) {
  486. var body = '';
  487. // put together response
  488. response.on('data', function (chunk) {
  489. body += chunk;
  490. });
  491. // start / stop handing out coins based on stream status
  492. response.on('end', function () {
  493. var json = JSON.parse(body);
  494. var entries = json.feed.entry, subs = '';
  495. __self.subscribers = [];
  496. for (var i = 0; i < entries.length; i++) {
  497. __self.subscribers.push(entries[i].title['$t']);
  498. subs += entries[i].title['$t'] + ' ';
  499. }
  500. __self.irc.emit('data', 'DATA - Subscriber Check - Returned: ' + subs);
  501. setTimeout(subscribers, 1000);
  502. });
  503. });
  504. } else {
  505. setTimeout(subscribers, time);
  506. }
  507. }
  508. // trigger coin handout
  509. function insert_coins() {
  510. __self.give_coins = __self.streaming;
  511. if (__self.give_coins) {
  512. var time = utils.make_interval(__self.give_coins_timer);
  513. if (time === 0) {
  514. __self.irc.raw('WHO ' + __self.irc.config.channel);
  515. setTimeout(insert_coins, 1000);
  516. } else {
  517. setTimeout(insert_coins, time);
  518. }
  519. }
  520. }
  521. // monitor viewers in irc
  522. __self.irc.on('data', function (data) {
  523. if (__self.streaming) {
  524. var data_split = data.split(' '), viewer = '';
  525. // viewers from \who
  526. if (data_split[3] == '352') {
  527. if (data_split[6] !== undefined) {
  528. viewer = data_split[6].toLowerCase();
  529. if (__self.viewer_list.indexOf(viewer) < 0) {
  530. __self.viewer_list.push(viewer);
  531. }
  532. }
  533. }
  534. // viewers chatting
  535. if (data_split[3] == 'PRIVMSG') {
  536. var servernick = data_split[2].toLowerCase().split('!');
  537. viewer = servernick[0];
  538. if (viewer != __self.irc.config.name.toLowerCase()) {
  539. viewer = viewer.slice(1);
  540. }
  541. if (__self.viewer_list.indexOf(viewer) < 0) {
  542. __self.viewer_list.push(viewer);
  543. }
  544. }
  545. // give coins after \who and handout_coins is true
  546. if (__self.give_coins && data_split[3] == '315') {
  547. var clone_viewer_list = __self.viewer_list;
  548. // clear old list and start recording
  549. __self.viewer_list = [];
  550. // build sql from the saved viewer list
  551. var sql = '';
  552. for (var i = 0; i < clone_viewer_list.length; i++) {
  553. var currency_amount = __self.subscribers.indexOf(clone_viewer_list[i]) >= 0 ? 2 : 1;
  554. if (clone_viewer_list[i] !== '') {
  555. if (i != clone_viewer_list.length - 1) {
  556. sql += 'INSERT INTO viewers (user, points) ';
  557. sql += 'VALUES (\'' + clone_viewer_list[i] + '\', ' + currency_amount + ') ';
  558. sql += 'ON DUPLICATE KEY UPDATE points = points + ' + currency_amount + '; ';
  559. } else {
  560. sql += 'INSERT INTO viewers (user, points) ';
  561. sql += 'VALUES (\'' + clone_viewer_list[i] + '\', ' + currency_amount + ') ';
  562. sql += 'ON DUPLICATE KEY UPDATE points = points + ' + currency_amount;
  563. }
  564. }
  565. }
  566. // execute query
  567. __self.db.execute(sql, function () {});
  568. }
  569. } else {
  570. __self.viewer_list = [];
  571. }
  572. });
  573. stream_status();
  574. // only start subscribers if gdoc is available
  575. if (__self.config.subscribers_json !== '') {
  576. subscribers();
  577. }
  578. };
  579. /**
  580. * ============================================
  581. * Adjust Currency
  582. * --------------------------------------------
  583. */
  584. Currency.prototype.adjust_currency = function (method, amount, viewer) {
  585. var __self = this;
  586. viewer = viewer.toLowerCase();
  587. __self.db.execute('SELECT * FROM viewers WHERE user=\'' + viewer + '\'', function(rows){
  588. if (rows.length > 0 || method === 'push') {
  589. var check = rows.length > 0 ? rows[0].user : rows.push({user: viewer});
  590. if (check === viewer || method === 'push') {
  591. var sql = '', settings = [];
  592. // push settings for message
  593. if (method === 'add' || method === 'push') {
  594. settings.push('+');
  595. settings.push('Added');
  596. settings.push('to');
  597. } else if (method === 'remove') {
  598. settings.push('-');
  599. settings.push('Removed');
  600. settings.push('from');
  601. }
  602. settings.push(rows[0].user.charAt(0).toUpperCase() + rows[0].user.slice(1));
  603. // create sql
  604. if (method === 'add' || method === 'remove') {
  605. sql += 'UPDATE viewers ';
  606. sql += 'SET points = points ' + settings[0] + ' ' + amount + ' ';
  607. sql += 'WHERE user = \'' + rows[0].user + '\'; ';
  608. } else if (method === 'push') {
  609. sql += 'INSERT INTO viewers (user, points) ';
  610. sql += 'VALUES (\'' + viewer + '\', ' + amount + ') ';
  611. sql += 'ON DUPLICATE KEY UPDATE points = points + ' + amount + '; ';
  612. }
  613. //execute adjustment
  614. __self.db.execute(sql, function(){
  615. __self.irc.emit('message', {message:__self.pre_text + settings[1] + ' ' + amount + ' ' + __self.config.currency + ' ' + settings[2] + ' ' + settings[3]});
  616. });
  617. }
  618. } else {
  619. __self.irc.emit('message', {message:__self.pre_text + 'User was not found, use the push command to add a new user'});
  620. }
  621. });
  622. };
  623. /**
  624. * ============================================
  625. * AUCTION SYSTEM
  626. * --------------------------------------------
  627. */
  628. Currency.prototype.auction = function (status) {
  629. var __self = this;
  630. switch (status) {
  631. case true:
  632. if (!__self.bets_status) {
  633. if (!__self.raffle_status) {
  634. if (!__self.auction_status) {
  635. // open up the auction
  636. __self.auction_status = true;
  637. // request toggle
  638. if (__self.temp.raffle_toggle) {
  639. __self.temp.auction_toggle = __self.temp.raffle_toggle;
  640. } else {
  641. __self.temp.auction_toggle = __self.coin_toggle;
  642. }
  643. __self.coin_toggle = false;
  644. // default request timer
  645. if (__self.temp.raffle_timer && __self.temp.raffle_timer_reset) {
  646. __self.temp.auction_timer = __self.temp.raffle_timer;
  647. __self.temp.auction_timer_reset = __self.temp.raffle_timer_reset;
  648. } else {
  649. __self.temp.auction_timer = __self.coin_response_timer;
  650. __self.temp.auction_timer_reset = __self.coin_response_reset;
  651. }
  652. __self.coin_response_timer = 3000;
  653. __self.coin_response_reset = true;
  654. // clear previous bids
  655. __self.auction_bids = [];
  656. __self.auction_previous_bid = {};
  657. // auction open response
  658. __self.irc.emit('message', {message:__self.pre_text + 'Auction opened, accepting bids'})
  659. } else {
  660. // auction is already open response
  661. __self.irc.emit('message', {message:__self.pre_text + 'Auction already in progress'});
  662. }
  663. } else {
  664. // raffle currently running
  665. __self.irc.emit('message', {message:__self.pre_text + 'You must close the raffle before you can open an auction'});
  666. }
  667. } else {
  668. // gambling currently running
  669. __self.irc.emit('message', {message:__self.pre_text + 'Betting must be closed before you can open an auction'});
  670. }
  671. break;
  672. case false:
  673. if (__self.auction_status) {
  674. // close the auction
  675. __self.auction_status = false;
  676. // request toggle
  677. __self.coin_toggle = __self.temp.auction_toggle;
  678. delete __self.temp.auction_toggle;
  679. // default request timer
  680. __self.coin_response_timer = __self.temp.auction_timer;
  681. __self.coin_response_reset = __self.temp.auction_timer_reset;
  682. delete __self.temp.auction_timer;
  683. delete __self.temp.auction_timer_reset;
  684. // clear response timers
  685. clearTimeout(__self.auction_bid_response);
  686. clearInterval(__self.auction_bid_response_long);
  687. if (__self.auction_bids.length > 0) {
  688. // pick a winner response
  689. for (var i = 0; i < __self.auction_bids.length; i++) {
  690. if (__self.auction_bids[i].bid === utils.max(__self.auction_bids)) {
  691. __self.irc.emit('message', {message:__self.pre_text + 'Auction closed, Winner: ' + __self.auction_bids[i].viewer + ' @ ' + __self.auction_bids[i].bid});
  692. // save the winners info for draw refund
  693. __self.auction_previous_bid.viewer = __self.auction_bids[i].viewer;
  694. __self.auction_previous_bid.bid = __self.auction_bids[i].bid;
  695. // remove winners money
  696. var sql = '';
  697. sql += 'UPDATE viewers ';
  698. sql += 'SET points = points - ' + __self.auction_bids[i].bid + ' ';
  699. sql += 'WHERE user = \'' + __self.auction_bids[i].viewer + '\'';
  700. __self.db.execute(sql, function() {});
  701. // remove winner from main list
  702. __self.auction_bids.splice(i, 1);
  703. break;
  704. }
  705. }
  706. } else {
  707. // no bidders to pick from response
  708. __self.irc.emit('message', {message:__self.pre_text + 'Auction closed, no bidders to pick a winner'});
  709. }
  710. } else {
  711. // auction is already open response
  712. __self.irc.emit('message', {message:__self.pre_text + 'Auction is already closed'});
  713. }
  714. break;
  715. case 'cancel':
  716. if (__self.auction_status) {
  717. // close the auction
  718. __self.auction_status = false;
  719. // request toggle
  720. __self.coin_toggle = __self.temp.auction_toggle;
  721. delete __self.temp.auction_toggle;
  722. // default request timer
  723. __self.coin_response_timer = __self.temp.auction_timer;
  724. __self.coin_response_reset = __self.temp.auction_timer_reset;
  725. delete __self.temp.auction_timer;
  726. delete __self.temp.auction_timer_reset;
  727. // clear response timers
  728. clearTimeout(__self.auction_bid_response);
  729. clearInterval(__self.auction_bid_response_long);
  730. // clear previous bids
  731. __self.auction_bids = [];
  732. __self.auction_previous_bid = {};
  733. // auction cancelled notification
  734. __self.irc.emit('message', {message:__self.pre_text + 'Auction has been cancelled'});
  735. } else {
  736. // auction cancelled notification
  737. __self.irc.emit('message', {message:__self.pre_text + 'Auction is not opened'});
  738. }
  739. break;
  740. }
  741. };
  742. Currency.prototype.bid = function (caller, amount) {
  743. var __self = this;
  744. function find_duplicate(amount) {
  745. var duplicate = false;
  746. for (var i = 0; i < __self.auction_bids.length; i++) {
  747. if (__self.auction_bids[i].bid === amount) {
  748. duplicate = true;
  749. break;
  750. }
  751. }
  752. return duplicate;
  753. }
  754. if (__self.auction_status) {
  755. // verify that bidder has the coins for bidding
  756. __self.query_coins(caller, function (rows) {
  757. var has_tickets = false;
  758. // only add bid if they have the enough to pay
  759. if (rows[0].points >= amount) {
  760. if (__self.auction_bids.length > 0) {
  761. // check if an existing bid exists and modify it
  762. for (var i = 0; i < __self.auction_bids.length; i++) {
  763. if (__self.auction_bids[i].viewer === caller) {
  764. has_tickets = true;
  765. // check if bid is higher then original and not a duplicate
  766. if (__self.auction_bids[i].bid < amount && !find_duplicate(amount)) {
  767. __self.auction_bids[i].bid = amount;
  768. }
  769. break;
  770. }
  771. }
  772. // add new bids to list if they are not a duplicate
  773. if (!has_tickets && !find_duplicate(amount)) {
  774. __self.auction_bids.push({viewer: caller, bid: amount});
  775. }
  776. } else {
  777. // push first bid
  778. __self.auction_bids.push({viewer: caller, bid: amount});
  779. }
  780. }
  781. // clear timers on flood
  782. clearTimeout(__self.auction_bid_response);
  783. clearInterval(__self.auction_bid_response_long);
  784. // reply after set amount of bids
  785. if ((__self.auction_bids.length % __self.max_requests) === 0) {
  786. // bulk flood response
  787. for (var i = 0; i < __self.auction_bids.length; i++) {
  788. if (__self.auction_bids[i].bid === utils.max(__self.auction_bids)) {
  789. __self.irc.msg(__self.pre_text + 'Highest bid, ' + __self.auction_bids[i].viewer + ' @ ' + __self.auction_bids[i].bid);
  790. }
  791. }
  792. } else {
  793. // response after time without flood has passed
  794. var viewer, bid;
  795. for (var i = 0; i < __self.auction_bids.length; i++) {
  796. if (__self.auction_bids[i].bid === utils.max(__self.auction_bids)) {
  797. viewer = __self.auction_bids[i].viewer;
  798. bid = __self.auction_bids[i].bid;
  799. }
  800. }
  801. if (viewer !== undefined && bid !== undefined && __self.auction_status) {
  802. var msg = __self.pre_text + 'Highest bid, ' + viewer + ' @ ' + bid;
  803. __self.auction_bid_response = setTimeout(function () {__self.irc.emit('message', {message:msg, timer: 1});}, 5000);
  804. __self.auction_bid_response_long = setInterval(function () {__self.irc.emit('message', {message:msg, timer: 1});}, 30000);
  805. }
  806. }
  807. });
  808. }
  809. };
  810. Currency.prototype.next_auction_winner = function () {
  811. var __self = this, empty_list = [];
  812. // custom dialog when the bidder list is empty
  813. empty_list.push('Hey, I just met you and this is crazy, but there\'s no more bidders, so start an new auction maybe?');
  814. empty_list.push('Are there more bidders? Well, to tell you the truth, in all this excitement I kind of lost track myself.');
  815. empty_list.push('Heyyyyyy there\'s no more bidders, Op, op, op, op, Open Auction Style.');
  816. empty_list.push('Da bids! Da bids! Where are all da bids, boss?');
  817. if (!__self.auction_status) {
  818. // get next highest bidder or prompt to open new auction
  819. if (__self.auction_bids.length > 0) {
  820. for (var i = 0; i < __self.auction_bids.length; i++) {
  821. if (__self.auction_bids[i].bid === utils.max(__self.auction_bids)) {
  822. __self.irc.emit('message',{message:__self.pre_text + 'Drawing the next highest bid: ' + __self.auction_bids[i].viewer + ' @ ' + __self.auction_bids[i].bid});
  823. // refund previous winner's money
  824. var sql = '';
  825. sql += 'UPDATE viewers ';
  826. sql += 'SET points = points + ' + __self.auction_previous_bid.bid + ' ';
  827. sql += 'WHERE user = \'' + __self.auction_previous_bid.viewer + '\'';
  828. __self.db.execute(sql, function() {});
  829. // save the new winner's info for next draw
  830. __self.auction_previous_bid.viewer = __self.auction_bids[i].viewer;
  831. __self.auction_previous_bid.bid = __self.auction_bids[i].bid;
  832. // remove winners money
  833. sql = '';
  834. sql += 'UPDATE viewers ';
  835. sql += 'SET points = points - ' + __self.auction_bids[i].bid + ' ';
  836. sql += 'WHERE user = \'' + __self.auction_bids[i].viewer + '\'';
  837. __self.db.execute(sql, function() {});
  838. // remove winner from main list
  839. __self.auction_bids.splice(i, 1);
  840. break;
  841. }
  842. }
  843. } else {
  844. // check if a previous viewer is saved
  845. if (__self.auction_previous_bid.viewer !== null) {
  846. // refund previous winner's money
  847. var sql = '';
  848. sql += 'UPDATE viewers ';
  849. sql += 'SET points = points + ' + __self.auction_previous_bid.bid + ' ';
  850. sql += 'WHERE user = \'' + __self.auction_previous_bid.viewer + '\'';
  851. __self.db.execute(sql, function() {});
  852. // clear previous bid
  853. __self.auction_previous_bid = {};
  854. }
  855. // notify that there's no more bids
  856. __self.irc.emit('message',{message:__self.pre_text + utils.selectRandomArrayItem(empty_list)});
  857. }
  858. }
  859. };
  860. /**
  861. * ============================================
  862. * RAFFLE SYSTEM
  863. * --------------------------------------------
  864. */
  865. Currency.prototype.raffle = function (status) {
  866. var __self = this;
  867. switch (status) {
  868. case true:
  869. if (!__self.bets_status) {
  870. if (!__self.auction_status) {
  871. if (!__self.raffle_status) {
  872. // open up a raffle
  873. __self.raffle_status = true;
  874. // request toggle
  875. if (__self.temp.auction_toggle) {
  876. __self.temp.raffle_toggle = __self.temp.auction_toggle;
  877. } else {
  878. __self.temp.raffle_toggle = __self.coin_toggle;
  879. }
  880. __self.coin_toggle = false;
  881. // default request timer
  882. if (__self.temp.auction_timer && __self.temp.auction_timer_reset) {
  883. __self.temp.raffle_timer = __self.temp.auction_timer;
  884. __self.temp.raffle_timer_reset = __self.temp.auction_timer_reset;
  885. } else {
  886. __self.temp.raffle_timer = __self.coin_response_timer;
  887. __self.temp.raffle_timer_reset = __self.coin_response_reset;
  888. }
  889. __self.coin_response_timer = 3000;
  890. __self.coin_response_reset = true;
  891. // save previous raffle settings in case
  892. // a new one is opened on accident
  893. __self.raffle_restore_ticket_requests = __self.raffle_ticket_requests;
  894. __self.raffle_restore_tickets = __self.raffle_tickets;
  895. // clear previous tickets
  896. __self.raffle_ticket_requests = [];
  897. __self.raffle_tickets = [];
  898. // raffle open response
  899. __self.irc.emit('message',{message:__self.pre_text + 'Raffle opened'});
  900. __self.irc.emit('message',{message:'+ Tickets cost ' + __self.raffle_ticket_cost + ' ' + __self.config.currency.toLowerCase() + ' / Maximum of ' + __self.raffle_max_tickets + ' tickets per viewer'});
  901. } else {
  902. // raffle in progress response
  903. __self.irc.emit('message',{message:__self.pre_text + 'Raffle already in progress'});
  904. }
  905. } else {
  906. // auction in progress
  907. __self.irc.emit('message', {message:__self.pre_text + 'You must close the auction before you can open an a raffle'});
  908. }
  909. } else {
  910. // gambling currently running
  911. __self.irc.emit('message', {message:__self.pre_text + 'Betting must be closed before you can open a raffle'});
  912. }
  913. break;
  914. case false:
  915. if (__self.raffle_status) {
  916. // close the raffle
  917. __self.raffle_status = false;
  918. // request toggle
  919. __self.coin_toggle = __self.temp.raffle_toggle;
  920. delete __self.temp.raffle_toggle;
  921. // default request timer
  922. __self.coin_response_timer = __self.temp.raffle_timer;
  923. __self.coin_response_reset = __self.temp.raffle_timer_reset;
  924. delete __self.temp.raffle_timer;
  925. delete __self.temp.raffle_timer_reset;
  926. // validation / winner / deduction
  927. __self.raffle_winner();
  928. } else {
  929. // raffle is already open response
  930. __self.irc.emit('message',{message:__self.pre_text + 'Raffle is already closed'});
  931. }
  932. break;
  933. case 'cancel':
  934. if (__self.raffle_status) {
  935. // close the raffle
  936. __self.raffle_status = false;
  937. // request toggle
  938. __self.coin_toggle = __self.temp.raffle_toggle;
  939. delete __self.temp.raffle_toggle;
  940. // default request timer
  941. __self.coin_response_timer = __self.temp.raffle_timer;
  942. __self.coin_response_reset = __self.temp.raffle_timer_reset;
  943. delete __self.temp.raffle_timer;
  944. delete __self.temp.raffle_timer_reset;
  945. // clear previous tickets
  946. __self.raffle_ticket_requests = [];
  947. __self.raffle_tickets = [];
  948. // raffle cancelled notification
  949. __self.irc.emit('message', {message:__self.pre_text + 'Raffle has been cancelled'});
  950. } else {
  951. // raffle cancelled notification
  952. __self.irc.emit('message', {message:__self.pre_text + 'Raffle is not opened'});
  953. }
  954. break;
  955. case 'restore':
  956. if (__self.raffle_status) {
  957. // close raffle
  958. __self.raffle_status = false;
  959. // restore previous raffle tickets
  960. __self.raffle_ticket_requests = __self.raffle_restore_ticket_requests;
  961. __self.raffle_tickets = __self.raffle_restore_tickets;
  962. __self.irc.emit('message', {message:__self.pre_text + 'Previous raffle has been restored'});
  963. } else {
  964. // raffle restore failed notification
  965. __self.irc.emit('message', {message:__self.pre_text + 'Raffle is closed, unable to restore'});
  966. }
  967. break;
  968. }
  969. };
  970. Currency.prototype.collect_tickets = function (caller, amount) {
  971. var __self = this, has_tickets = false;
  972. if (__self.raffle_ticket_requests.length > 0) {
  973. // check if viewer already has tickets
  974. for (var i = 0; i < __self.raffle_ticket_requests.length; i++) {
  975. if (__self.raffle_ticket_requests[i].viewer === caller) {
  976. has_tickets = true;
  977. if (amount <= __self.raffle_max_tickets && amount >= 1) {
  978. __self.raffle_ticket_requests[i].tickets = amount;
  979. } else if (amount === 0) {
  980. __self.raffle_ticket_requests.splice(i, 1);
  981. }
  982. break;
  983. }
  984. }
  985. // if viewer doesn't have tickets and meets > 1 < max req add their request
  986. if (!has_tickets && amount <= __self.raffle_max_tickets && amount >= 1 && amount !== 0) {
  987. __self.raffle_ticket_requests.push({viewer: caller, tickets: amount});
  988. }
  989. } else {
  990. // push first ticket if > 1 < max
  991. if (amount <= __self.raffle_max_tickets && amount >= 1 && amount !== 0) {
  992. __self.raffle_ticket_requests.push({viewer: caller, tickets: amount});
  993. }
  994. }
  995. };
  996. Currency.prototype.raffle_winner = function () {
  997. var __self = this, sql = '';
  998. if (__self.raffle_ticket_requests.length > 0) {
  999. // setup sql to grab all viewers that request coins from the database
  1000. sql += 'SELECT * FROM viewers WHERE ';
  1001. for (var i = 0; i < __self.raffle_ticket_requests.length; i++) {
  1002. if (i !== __self.raffle_ticket_requests.length - 1) {
  1003. sql += 'user=\'' + __self.raffle_ticket_requests[i].viewer.toLowerCase() + '\' OR ';
  1004. } else {
  1005. sql += 'user=\'' + __self.raffle_ticket_requests[i].viewer.toLowerCase() + '\'';
  1006. }
  1007. }
  1008. // execute viewer search query
  1009. __self.db.execute(sql, function(rows) {
  1010. // currency validation
  1011. // - this takes the results of the query and uses the names from the database
  1012. // to filter through the viewers that requested tickets (since they have to be in the
  1013. // database in the first place)
  1014. // - during the filtering process the viewers requested tickets are multiplied by the
  1015. // ticket cost and compared against their currency amount
  1016. // - if the viewer has the funds, their tickets are added and the sql is updated to include their
  1017. // deduction
  1018. sql = '';
  1019. for (var i = 0; i < rows.length; i++) {
  1020. for (var j = 0; j < __self.raffle_ticket_requests.length; j++) {
  1021. if (__self.raffle_ticket_requests[j].viewer.toLowerCase() === rows[i].user) {
  1022. var money = __self.raffle_ticket_requests[j].tickets * __self.raffle_ticket_cost;
  1023. if (rows[i].points >= money) {
  1024. for (var k = 1; k <= __self.raffle_ticket_requests[j].tickets; k++) {
  1025. __self.raffle_tickets.push(__self.raffle_ticket_requests[j].viewer);
  1026. }
  1027. if (i !== rows.length - 1) {
  1028. sql += 'UPDATE viewers ';
  1029. sql += 'SET points = points - ' + money + ' ';
  1030. sql += 'WHERE user = \'' + rows[i].user + '\'; ';
  1031. } else {
  1032. sql += 'UPDATE viewers ';
  1033. sql += 'SET points = points - ' + money + ' ';
  1034. sql += 'WHERE user = \'' + rows[i].user + '\'';
  1035. }
  1036. }
  1037. break;
  1038. }
  1039. }
  1040. }
  1041. // randomize array before selecting a random winner
  1042. __self.raffle_tickets.sort(function () {return 0.5 - Math.random();});
  1043. // select random ticket from array
  1044. var winner = utils.selectRandomArrayItem(__self.raffle_tickets);
  1045. // count winner's tickets
  1046. var winning_ticket_amount;
  1047. for (var i = 0; i < __self.raffle_ticket_requests.length; i++) {
  1048. if (__self.raffle_ticket_requests[i].viewer === winner) {
  1049. winning_ticket_amount = __self.raffle_ticket_requests[i].tickets;
  1050. break;
  1051. }
  1052. }
  1053. // output winner to chat
  1054. __self.irc.emit('message', {message:__self.pre_text + 'Raffle closed, ' + __self.raffle_tickets.length + ' tickets purchased!'});
  1055. __self.irc.emit('message', {message:'+ Winner: ' + winner + ' (' + winning_ticket_amount + ' tickets purchased)'});
  1056. // remove one ticket from raffle bowl
  1057. if (__self.raffle_tickets.indexOf(winner) >= 0 ) {
  1058. __self.raffle_tickets.splice(__self.raffle_tickets.indexOf(winner), 1);
  1059. }
  1060. // execute query
  1061. __self.db.execute(sql, function () {});
  1062. });
  1063. } else {
  1064. // no tickets to pick from response
  1065. __self.irc.emit('message', {message:__self.pre_text + 'Raffle closed, no tickets to draw a winner'});
  1066. }
  1067. };
  1068. Currency.prototype.next_raffle_winner = function () {
  1069. var __self = this, empty_list = [];
  1070. // custom dialog when there are no more raffle tickets
  1071. empty_list.push('Hey, I just met you and this is crazy, but there\'s no more tickets, so start an new raffle maybe?');
  1072. empty_list.push('Are there more tickets? Well, to tell you the truth, in all this excitement I kind of lost track myself.');
  1073. empty_list.push('Heyyyyyy there\'s no more tickets, Op, op, op, op, Open Raffle Style.');
  1074. empty_list.push('Da tickets! Da tickets! Where are all da tickets, boss?');
  1075. if (!__self.raffle_status) {
  1076. // draw next ticket or prompt to open new raffle
  1077. if (__self.raffle_tickets.length > 0) {
  1078. // randomize array before selecting a random winner
  1079. __self.raffle_tickets.sort(function () {return 0.5 - Math.random();});
  1080. // select random ticket from array
  1081. var winner = utils.selectRandomArrayItem(__self.raffle_tickets);
  1082. // count next winner's tickets
  1083. var winning_ticket_amount;
  1084. for (var i = 0; i < __self.raffle_ticket_requests.length; i++) {
  1085. if (__self.raffle_ticket_requests[i].viewer === winner) {
  1086. winning_ticket_amount = __self.raffle_ticket_requests[i].tickets;
  1087. break;
  1088. }
  1089. }
  1090. // output winner to chat
  1091. __self.irc.emit('message', {message:__self.pre_text + 'Drawing next ticket'});
  1092. __self.irc.emit('message', {message:'+ Winner: ' + winner + ' (' + winning_ticket_amount + ' tickets purchased)'});
  1093. // remove one ticket from raffle bowl
  1094. if (__self.raffle_tickets.indexOf(winner) >= 0 ) {
  1095. __self.raffle_tickets.splice(__self.raffle_tickets.indexOf(winner), 1);
  1096. }
  1097. } else {
  1098. __self.irc.emit('message', {message:__self.pre_text + utils.selectRandomArrayItem(empty_list)});
  1099. }
  1100. }
  1101. };
  1102. /**
  1103. * ============================================
  1104. * BETTING SYSTEM
  1105. * --------------------------------------------
  1106. */
  1107. Currency.prototype.bets = function(status, data) {
  1108. var __self = this;
  1109. switch(status){
  1110. case true:
  1111. if (!__self.auction_status) {
  1112. if (!__self.raffle_status) {
  1113. if (!__self.bets_status && !__self.bets_payout) {
  1114. var wager_msg = '';
  1115. // open up bets
  1116. __self.bets_status = true;
  1117. __self.bets_payout = true;
  1118. // clear previous board / bets
  1119. __self.bets_board = [];
  1120. __self.bets_viewers = [];
  1121. // create new betting board
  1122. __self.bets_board = data.join().split(',').filter(function(n){return n}).slice(6);
  1123. // create chat message on how to place a bet
  1124. for (var i = 0; i < __self.bets_board.length; i++) {
  1125. if (i !== __self.bets_board.length - 1) {
  1126. wager_msg += '"!' + __self.bets_board[i] + '" / ';
  1127. } else {
  1128. wager_msg += '"!' + __self.bets_board[i] + '"';
  1129. }
  1130. }
  1131. // output to chat
  1132. __self.irc.emit('message', {message:__self.pre_text + 'Betting is now open'});
  1133. __self.irc.emit('message', {message:'+ Type ' + wager_msg + ' and the bet amount to enter'});
  1134. } else {
  1135. if (__self.bets_payout) {
  1136. // payout pending message
  1137. __self.irc.emit('message', {message:__self.pre_text + 'Unable to take new bets until previous have been paid out'});
  1138. } else {
  1139. // gambling is already open response
  1140. __self.irc.emit('message', {message:__self.pre_text + 'Betting already in progress'});
  1141. }
  1142. }
  1143. } else {
  1144. // raffle in progress
  1145. __self.irc.emit('message', {message:__self.pre_text + 'Betting must be closed before you can open a raffle'});
  1146. }
  1147. } else {
  1148. // auction currently running
  1149. __self.irc.emit('message', {message:__self.pre_text + 'Betting must be closed before you can open an auction'});
  1150. }
  1151. break;
  1152. case false:
  1153. if (__self.bets_status && __self.bets_payout) {
  1154. // close out bets
  1155. __self.bets_status = false;
  1156. // output to chat
  1157. if (__self.bets_viewers.length > 0) {
  1158. __self.irc.emit('message', {message:__self.pre_text + 'Betting is now closed'});
  1159. } else {
  1160. __self.irc.emit('message', {message:__self.pre_text + 'Betting closed, no bets were placed'});
  1161. }
  1162. // deduct bets from viewers amounts
  1163. __self.bets_deduct_bets();
  1164. }
  1165. break;
  1166. case 'winner':
  1167. // set payout to complete
  1168. __self.bets_payout = false;
  1169. break;
  1170. }
  1171. };
  1172. Currency.prototype.collect_bets = function (caller, bet, amount) {
  1173. var __self = this, has_bet = false;
  1174. if (__self.bets_viewers.length > 0) {
  1175. for (var i = 0; i < __self.bets_viewers.length; i++) {
  1176. if (__self.bets_viewers[i].viewer === caller) {
  1177. has_bet = true;
  1178. if (amount >= 1) {
  1179. __self.bets_viewers[i].bet = bet;
  1180. __self.bets_viewers[i].amount = amount;
  1181. } else if (amount === 0 && bet === __self.bets_viewers[i].bet) {
  1182. __self.bets_viewers.splice(i, 1);
  1183. }
  1184. break;
  1185. }
  1186. }
  1187. if (!has_bet && amount >= 1 && amount !== 0) {
  1188. __self.bets_viewers.push({viewer: caller, bet: bet, amount: amount});
  1189. }
  1190. } else {
  1191. if (amount >= 1 && amount !== 0) {
  1192. __self.bets_viewers.push({viewer: caller, bet: bet, amount: amount});
  1193. }
  1194. }
  1195. console.log(__self.bets_viewers);
  1196. };
  1197. Currency.prototype.bets_deduct_bets = function () {
  1198. };
  1199. module.exports = function (irc, db, options) {
  1200. return new Currency(irc, db, options);
  1201. };