Guest User

Untitled

a guest
Nov 2nd, 2017
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Generated by CoffeeScript 1.12.2
  2.  
  3.  
  4.   var Cloud_replay_ids, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_players_banned, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, Room, _, addCallback, ban_user, bunyan, cppversion, crypto, date, defaultconfig, execFile, fs, geoip, get_memory_usage, http, http_server, https, https_server, list, load_dialogues, load_tips, log, moment, nconf, net, options, os, path, pgClient, pg_client, pg_query, redis, redisdb, request, requestListener, roomlist, settings, spawn, spawnSync, url, users_cache, wait_room_start, windbot_process, ygopro, zlib;
  5.   var server = {};
  6.  
  7. server.restartAI = function (){
  8.     windbot_process.kill('SIGINT');
  9.     windbot_process = spawn('WindBot.exe', [settings.modules.windbot.port], {
  10.       cwd: 'windbot'
  11.     });
  12.     windbot_process.on('error', function(err) {
  13.       write('WindBot ERROR '+ err);
  14.       log.warn('WindBot ERROR', err);
  15.     });
  16.     windbot_process.on('exit', function(code) {
  17.       log.warn('WindBot EXIT', code);
  18.     });
  19.     windbot_process.stdout.setEncoding('utf8');
  20.     windbot_process.stdout.on('data', function(data) {
  21.       log.info('WindBot:', data);
  22.     });
  23.     windbot_process.stderr.setEncoding('utf8');
  24.     windbot_process.stderr.on('data', function(data) {
  25.       write("Windbot Error: " + data);
  26.       log.warn('WindBot Error:', data);
  27.     });
  28. }
  29.  
  30. server.start = function() {
  31.  
  32.   net = require('net');
  33.  
  34.   http = require('http');
  35.  
  36.   url = require('url');
  37.  
  38.   path = require('path');
  39.  
  40.   fs = require('fs');
  41.  
  42.   os = require('os');
  43.  
  44.   crypto = require('crypto');
  45.  
  46.   execFile = require('child_process').execFile;
  47.  
  48.   spawn = require('child_process').spawn;
  49.  
  50.   spawnSync = require('child_process').spawnSync;
  51.  
  52.   _ = require('underscore');
  53.  
  54.   _.str = require('underscore.string');
  55.  
  56.   _.mixin(_.str.exports());
  57.  
  58.   request = require('request');
  59.  
  60.   bunyan = require('bunyan');
  61.  
  62.   log = bunyan.createLogger({
  63.     name: "mycard"
  64.   });
  65.  
  66.   moment = require('moment');
  67.  
  68.   moment.locale('zh-cn', {
  69.     relativeTime: {
  70.       future: '%s内',
  71.       past: '%s前',
  72.       s: '%d秒',
  73.       m: '1分钟',
  74.       mm: '%d分钟',
  75.       h: '1小时',
  76.       hh: '%d小时',
  77.       d: '1天',
  78.       dd: '%d天',
  79.       M: '1个月',
  80.       MM: '%d个月',
  81.       y: '1年',
  82.       yy: '%d年'
  83.     }
  84.   });
  85.  
  86.   nconf = require('nconf');
  87.  
  88.   nconf.file('./config.user.json');
  89.  
  90.   defaultconfig = require('./config.json');
  91.  
  92.   nconf.defaults(defaultconfig);
  93.  
  94.   settings = global.settings = nconf.get();
  95.  
  96.   nconf.myset = function(settings, path, val) {
  97.     var key, target;
  98.     nconf.set(path, val);
  99.     nconf.save();
  100.     if (_.isString(val)) {
  101.       log.info("setting changed", path, val);
  102.     }
  103.     path = path.split(':');
  104.     if (path.length === 0) {
  105.       settings[path[0]] = val;
  106.     } else {
  107.       target = settings;
  108.       while (path.length > 1) {
  109.         key = path.shift();
  110.         target = target[key];
  111.       }
  112.       key = path.shift();
  113.       target[key] = val;
  114.     }
  115.   };
  116.  
  117.   try {
  118.     cppversion = parseInt(fs.readFileSync('ygopro/gframe/game.cpp', 'utf8').match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16');
  119.     nconf.myset(settings, "version", cppversion);
  120.     write("ygopro version 0x" + settings.version.toString(16) + "(from source code)"); 
  121.     log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)");
  122.   } catch (error1) {
  123.     write("ygopro version 0x" + settings.version.toString(16), "(from config)");   
  124.     log.info("ygopro version 0x" + settings.version.toString(16), "(from config)");
  125.   }
  126.  
  127.   settings.lflist = (function() {
  128.     var j, len, ref, results;
  129.     ref = fs.readFileSync('ygopro/lflist.conf', 'utf8').match(/!.*/g);
  130.     results = [];
  131.     for (j = 0, len = ref.length; j < len; j++) {
  132.       list = ref[j];
  133.       date = list.match(/!([\d\.]+)/);
  134.       if (!date) {
  135.         continue;
  136.       }
  137.       results.push({
  138.         date: moment(list.match(/!([\d\.]+)/)[1], 'YYYY.MM.DD').utcOffset("-08:00"),
  139.         tcg: list.indexOf('TCG') !== -1
  140.       });
  141.     }
  142.     return results;
  143.   })();
  144.  
  145.   if (settings.modules.cloud_replay.enabled) {
  146.     redis = require('redis');
  147.     zlib = require('zlib');
  148.     redisdb = redis.createClient({
  149.       host: "127.0.0.1",
  150.       port: settings.modules.cloud_replay.redis_port
  151.     });
  152.     redisdb.on('error', function(err) {
  153.       log.warn(err);
  154.     });
  155.   }
  156.  
  157.   if (settings.modules.windbot.enabled) {
  158.     settings.modules.windbots = require(settings.modules.windbot.botlist).windbots;
  159.   }
  160.  
  161.   ygopro = require('./ygopro.js');
  162.  
  163.   if (settings.modules.http.websocket_roomlist) {
  164.     roomlist = require('./roomlist.js');
  165.   }
  166.  
  167.   if (settings.modules.i18n.auto_pick) {
  168.     geoip = require('geoip-country-lite');
  169.   }
  170.  
  171.   users_cache = {};
  172.  
  173.   if (settings.modules.mycard.enabled) {
  174.     pgClient = require('pg').Client;
  175.     pg_client = new pgClient(settings.modules.mycard.auth_database);
  176.     pg_client.on('error', function(err) {
  177.       log.warn("PostgreSQL ERROR: ", err);
  178.     });
  179.     pg_query = pg_client.query('SELECT username, id from users');
  180.     pg_query.on('error', function(err) {
  181.       log.warn("PostgreSQL Query ERROR: ", err);
  182.     });
  183.     pg_query.on('row', function(row) {
  184.       users_cache[row.username] = row.id;
  185.     });
  186.     pg_query.on('end', function(result) {
  187.       log.info("users loaded", result.rowCount);
  188.     });
  189.     pg_client.on('drain', pg_client.end.bind(pg_client));
  190.     log.info("loading mycard user...");
  191.     pg_client.connect();
  192.   }
  193.  
  194.   get_memory_usage = function() {
  195.     var actualFree, buffers, cached, free, line, lines, percentUsed, prc_free, total;
  196.     prc_free = spawnSync("free", []);
  197.     if (prc_free.stdout) {
  198.       lines = prc_free.stdout.toString().split(/\n/g);
  199.       line = lines[1].split(/\s+/);
  200.       total = parseInt(line[1], 10);
  201.       free = parseInt(line[3], 10);
  202.       buffers = parseInt(line[5], 10);
  203.       cached = parseInt(line[6], 10);
  204.       actualFree = free + buffers + cached;
  205.       percentUsed = parseFloat(((1 - (actualFree / total)) * 100).toFixed(2));
  206.     } else {
  207.       percentUsed = 0;
  208.     }
  209.     return percentUsed;
  210.   };
  211.  
  212.   Cloud_replay_ids = [];
  213.  
  214.   ROOM_all = [];
  215.  
  216.  
  217.   ROOM_players_oppentlist = {};
  218.  
  219.   ROOM_players_banned = [];
  220.  
  221.   ROOM_connected_ip = {};
  222.  
  223.   ROOM_bad_ip = {};
  224.  
  225.   ban_user = function(name) {
  226.     var bad_ip, j, k, len, len1, player, ref, room;
  227.     settings.ban.banned_user.push(name);
  228.     nconf.myset(settings, "ban:banned_user", settings.ban.banned_user);
  229.     bad_ip = 0;
  230.     for (j = 0, len = ROOM_all.length; j < len; j++) {
  231.       room = ROOM_all[j];
  232.       if (room && room.established) {
  233.         ref = room.players;
  234.         for (k = 0, len1 = ref.length; k < len1; k++) {
  235.           player = ref[k];
  236.           if (player && (player.name === name || player.ip === bad_ip)) {
  237.             bad_ip = player.ip;
  238.             ROOM_bad_ip[bad_ip] = 99;
  239.             settings.ban.banned_ip.push(player.ip);
  240.             ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
  241.             player.destroy();
  242.             continue;
  243.           }
  244.         }
  245.       }
  246.     }
  247.   };
  248.  
  249.   ROOM_ban_player = function(name, ip, reason, countadd) {
  250.     var bannedplayer, bantime;
  251.     if (countadd == null) {
  252.       countadd = 1;
  253.     }
  254.     bannedplayer = _.find(ROOM_players_banned, function(bannedplayer) {
  255.       return ip === bannedplayer.ip;
  256.     });
  257.     if (bannedplayer) {
  258.       bannedplayer.count = bannedplayer.count + countadd;
  259.       bantime = bannedplayer.count > 3 ? Math.pow(2, bannedplayer.count - 3) * 2 : 0;
  260.       bannedplayer.time = moment() < bannedplayer.time ? moment(bannedplayer.time).add(bantime, 'm') : moment().add(bantime, 'm');
  261.       if (!_.find(bannedplayer.reasons, function(bannedreason) {
  262.         return bannedreason === reason;
  263.       })) {
  264.         bannedplayer.reasons.push(reason);
  265.       }
  266.       bannedplayer.need_tip = true;
  267.     } else {
  268.       bannedplayer = {
  269.         "ip": ip,
  270.         "time": moment(),
  271.         "count": countadd,
  272.         "reasons": [reason],
  273.         "need_tip": true
  274.       };
  275.       ROOM_players_banned.push(bannedplayer);
  276.     }
  277.   };
  278.  
  279.   ROOM_find_or_create_by_name = function(name, player_ip) {
  280.     var room, uname;
  281.     uname = name.toUpperCase();
  282.     if (settings.modules.windbot.enabled && (uname.slice(0, 2) === 'AI' || (!settings.modules.random_duel.enabled && uname === ''))) {
  283.       return ROOM_find_or_create_ai(name);
  284.     }
  285.     if (settings.modules.random_duel.enabled && (uname === '' || uname === 'S' || uname === 'M' || uname === 'T')) {
  286.       return ROOM_find_or_create_random(uname, player_ip);
  287.     }
  288.     if (room = ROOM_find_by_name(name)) {
  289.       return room;
  290.     } else if (get_memory_usage() >= 90) {
  291.       return null;
  292.     } else {
  293.       return new Room(name);
  294.     }
  295.   };
  296.  
  297.   ROOM_find_or_create_random = function(type, player_ip) {
  298.     var bannedplayer, max_player, name, playerbanned, result;
  299.     bannedplayer = _.find(ROOM_players_banned, function(bannedplayer) {
  300.       return player_ip === bannedplayer.ip;
  301.     });
  302.     if (bannedplayer) {
  303.       if (bannedplayer.count > 6 && moment() < bannedplayer.time) {
  304.         return {
  305.           "error": "${random_banned_part1}" + (bannedplayer.reasons.join('${random_ban_reason_separator}')) + "${random_banned_part2}" + (moment(bannedplayer.time).fromNow(true)) + "${random_banned_part3}"
  306.         };
  307.       }
  308.       if (bannedplayer.count > 3 && moment() < bannedplayer.time && bannedplayer.need_tip) {
  309.         bannedplayer.need_tip = false;
  310.         return {
  311.           "error": "${random_deprecated_part1}" + (bannedplayer.reasons.join('${random_ban_reason_separator}')) + "${random_deprecated_part2}" + (moment(bannedplayer.time).fromNow(true)) + "${random_deprecated_part3}"
  312.         };
  313.       } else if (bannedplayer.need_tip) {
  314.         bannedplayer.need_tip = false;
  315.         return {
  316.           "error": "${random_warn_part1}" + (bannedplayer.reasons.join('${random_ban_reason_separator}')) + "${random_warn_part2}"
  317.         };
  318.       } else if (bannedplayer.count > 2) {
  319.         bannedplayer.need_tip = true;
  320.       }
  321.     }
  322.     max_player = type === 'T' ? 4 : 2;
  323.     playerbanned = bannedplayer && bannedplayer.count > 3 && moment() < bannedplayer.time;
  324.     result = _.find(ROOM_all, function(room) {
  325.       return room && room.random_type !== '' && !room.started && ((type === '' && room.random_type !== 'T') || room.random_type === type) && room.get_playing_player().length < max_player && (room.get_host() === null || room.get_host().ip !== ROOM_players_oppentlist[player_ip]) && (playerbanned === room.deprecated);
  326.     });
  327.     if (result) {
  328.       result.welcome = '${random_duel_enter_room_waiting}';
  329.     } else if (get_memory_usage() < 90) {
  330.       type = type ? type : 'S';
  331.       name = type + ',RANDOM#' + Math.floor(Math.random() * 100000);
  332.       result = new Room(name);
  333.       result.random_type = type;
  334.       result.max_player = max_player;
  335.       result.welcome = '${random_duel_enter_room_new}';
  336.       result.deprecated = playerbanned;
  337.     } else {
  338.       return null;
  339.     }
  340.     if (result.random_type === 'M') {
  341.       result.welcome = result.welcome + '\n${random_duel_enter_room_match}';
  342.     }
  343.     return result;
  344.   };
  345.  
  346.   ROOM_find_or_create_ai = function(name) {
  347.     var ainame, namea, result, room, uname, windbot;
  348.     if (name === '') {
  349.       name = 'AI';
  350.     }
  351.     namea = name.split('#');
  352.     uname = name.toUpperCase();
  353.     if (room = ROOM_find_by_name(name)) {
  354.       return room;
  355.     } else if (uname === 'AI') {
  356.       windbot = _.sample(settings.modules.windbots);
  357.       name = 'AI#' + Math.floor(Math.random() * 100000);
  358.     } else if (namea.length > 1) {
  359.       ainame = namea[namea.length - 1];
  360.       windbot = _.sample(_.filter(settings.modules.windbots, function(w) {
  361.         return w.name === ainame || w.deck === ainame;
  362.       }));
  363.       if (!windbot) {
  364.         return {
  365.           "error": "${windbot_deck_not_found}"
  366.         };
  367.       }
  368.       name = name + ',' + Math.floor(Math.random() * 100000);
  369.     } else {
  370.       windbot = _.sample(settings.modules.windbots);
  371.       name = name + '#' + Math.floor(Math.random() * 100000);
  372.     }
  373.     if (name.replace(/[^\x00-\xff]/g, "00").length > 20) {
  374.       log.info("long ai name", name);
  375.       return {
  376.         "error": "${windbot_name_too_long}"
  377.       };
  378.     }
  379.     result = new Room(name);
  380.     result.windbot = windbot;
  381.     result["private"] = true;
  382.     return result;
  383.   };
  384.  
  385.   ROOM_find_by_name = function(name) {
  386.     var result;
  387.     result = _.find(ROOM_all, function(room) {
  388.       return room && room.name === name;
  389.     });
  390.     return result;
  391.   };
  392.  
  393.   ROOM_find_by_title = function(title) {
  394.     var result;
  395.     result = _.find(ROOM_all, function(room) {
  396.       return room && room.title === title;
  397.     });
  398.     return result;
  399.   };
  400.  
  401.   ROOM_find_by_port = function(port) {
  402.     return _.find(ROOM_all, function(room) {
  403.       return room && room.port === port;
  404.     });
  405.   };
  406.  
  407.   ROOM_validate = function(name) {
  408.     var client_name, client_name_and_pass, client_pass;
  409.     client_name_and_pass = name.split('$', 2);
  410.     client_name = client_name_and_pass[0];
  411.     client_pass = client_name_and_pass[1];
  412.     if (!client_pass) {
  413.       return true;
  414.     }
  415.     return !_.find(ROOM_all, function(room) {
  416.       var room_name, room_name_and_pass, room_pass;
  417.       if (!room) {
  418.         return false;
  419.       }
  420.       room_name_and_pass = room.name.split('$', 2);
  421.       room_name = room_name_and_pass[0];
  422.       room_pass = room_name_and_pass[1];
  423.       return client_name === room_name && client_pass !== room_pass;
  424.     });
  425.   };
  426.  
  427.   ROOM_unwelcome = function(room, bad_player, reason) {
  428.     var j, len, player, ref;
  429.     if (!room) {
  430.       return;
  431.     }
  432.     ref = room.players;
  433.     for (j = 0, len = ref.length; j < len; j++) {
  434.       player = ref[j];
  435.       if (player && player === bad_player) {
  436.         ygopro.stoc_send_chat(player, "${unwelcome_warn_part1}" + reason + "${unwelcome_warn_part2}", ygopro.constants.COLORS.RED);
  437.       } else if (player && player.pos !== 7 && player !== bad_player) {
  438.         player.flee_free = true;
  439.         ygopro.stoc_send_chat(player, "${unwelcome_tip_part1}" + reason + "${unwelcome_tip_part2}", ygopro.constants.COLORS.BABYBLUE);
  440.       }
  441.     }
  442.   };
  443.  
  444.   Room = (function() {
  445.     function Room(name, hostinfo) {
  446.       var draw_count, lflist, param, rule, start_hand, start_lp, time_limit;
  447.       this.hostinfo = hostinfo;
  448.       this.name = name;
  449.       this.alive = true;
  450.       this.players = [];
  451.       this.player_datas = [];
  452.       this.status = 'starting';
  453.       this.started = false;
  454.       this.established = false;
  455.       this.watcher_buffers = [];
  456.       this.recorder_buffers = [];
  457.       this.cloud_replay_id = Math.floor(Math.random() * 100000000);
  458.       this.watchers = [];
  459.       this.random_type = '';
  460.       this.welcome = '';
  461.       this.scores = {};
  462.       ROOM_all.push(this);
  463.       this.hostinfo || (this.hostinfo = JSON.parse(JSON.stringify(settings.hostinfo)));
  464.       if (settings.lflist.length) {
  465.         if (this.hostinfo.rule === 1 && this.hostinfo.lflist === 0) {
  466.           this.hostinfo.lflist = _.findIndex(settings.lflist, function(list) {
  467.             return list.tcg;
  468.           });
  469.         }
  470.       } else {
  471.         this.hostinfo.lflist = -1;
  472.       }
  473.       this.hostinfo.replay_mode = settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe ? 1 : 0;
  474.       if (name.slice(0, 2) === 'M#') {
  475.         this.hostinfo.mode = 1;
  476.       } else if (name.slice(0, 2) === 'T#') {
  477.         this.hostinfo.mode = 2;
  478.         this.hostinfo.start_lp = 16000;
  479.       } else if (name.slice(0, 3) === 'AI#') {
  480.         this.hostinfo.rule = 2;
  481.         this.hostinfo.lflist = -1;
  482.       } else if ((param = name.match(/^(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i))) {
  483.         this.hostinfo.rule = parseInt(param[1]);
  484.         this.hostinfo.mode = parseInt(param[2]);
  485.         this.hostinfo.enable_priority = param[3] === 'T';
  486.         this.hostinfo.no_check_deck = param[4] === 'T';
  487.         this.hostinfo.no_shuffle_deck = param[5] === 'T';
  488.         this.hostinfo.start_lp = parseInt(param[6]);
  489.         this.hostinfo.start_hand = parseInt(param[7]);
  490.         this.hostinfo.draw_count = parseInt(param[8]);
  491.       } else if ((param = name.match(/(.+)#/)) !== null) {
  492.         rule = param[1].toUpperCase();
  493.         if (rule.match(/(^|,|,)(M|MATCH)(,|,|$)/)) {
  494.           this.hostinfo.mode = 1;
  495.         }
  496.         if (rule.match(/(^|,|,)(T|TAG)(,|,|$)/)) {
  497.           this.hostinfo.mode = 2;
  498.           this.hostinfo.start_lp = 16000;
  499.         }
  500.         if (rule.match(/(^|,|,)(TCGONLY|TO)(,|,|$)/)) {
  501.           this.hostinfo.rule = 1;
  502.           this.hostinfo.lflist = _.findIndex(settings.lflist, function(list) {
  503.             return list.tcg;
  504.           });
  505.         }
  506.         if (rule.match(/(^|,|,)(OCGONLY|OO)(,|,|$)/)) {
  507.           this.hostinfo.rule = 0;
  508.         }
  509.         if (rule.match(/(^|,|,)(OT|TCG)(,|,|$)/)) {
  510.           this.hostinfo.rule = 2;
  511.         }
  512.         if ((param = rule.match(/(^|,|,)LP(\d+)(,|,|$)/))) {
  513.           start_lp = parseInt(param[2]);
  514.           if (start_lp <= 0) {
  515.             start_lp = 1;
  516.           }
  517.           if (start_lp >= 99999) {
  518.             start_lp = 99999;
  519.           }
  520.           this.hostinfo.start_lp = start_lp;
  521.         }
  522.         if ((param = rule.match(/(^|,|,)(TIME|TM|TI)(\d+)(,|,|$)/))) {
  523.           time_limit = parseInt(param[3]);
  524.           if (time_limit < 0) {
  525.             time_limit = 180;
  526.           }
  527.           if (time_limit >= 1 && time_limit <= 60) {
  528.             time_limit = time_limit * 60;
  529.           }
  530.           if (time_limit >= 999) {
  531.             time_limit = 999;
  532.           }
  533.           this.hostinfo.time_limit = time_limit;
  534.         }
  535.         if ((param = rule.match(/(^|,|,)(START|ST)(\d+)(,|,|$)/))) {
  536.           start_hand = parseInt(param[3]);
  537.           if (start_hand <= 0) {
  538.             start_hand = 1;
  539.           }
  540.           if (start_hand >= 40) {
  541.             start_hand = 40;
  542.           }
  543.           this.hostinfo.start_hand = start_hand;
  544.         }
  545.         if ((param = rule.match(/(^|,|,)(DRAW|DR)(\d+)(,|,|$)/))) {
  546.           draw_count = parseInt(param[3]);
  547.           if (draw_count >= 35) {
  548.             draw_count = 35;
  549.           }
  550.           this.hostinfo.draw_count = draw_count;
  551.         }
  552.         if ((param = rule.match(/(^|,|,)(LFLIST|LF)(\d+)(,|,|$)/))) {
  553.           lflist = parseInt(param[3]) - 1;
  554.           this.hostinfo.lflist = lflist;
  555.         }
  556.         if (rule.match(/(^|,|,)(NOLFLIST|NF)(,|,|$)/)) {
  557.           this.hostinfo.lflist = -1;
  558.         }
  559.         if (rule.match(/(^|,|,)(NOUNIQUE|NU)(,|,|$)/)) {
  560.           this.hostinfo.rule = 3;
  561.         }
  562.         if (rule.match(/(^|,|,)(NOCHECK|NC)(,|,|$)/)) {
  563.           this.hostinfo.no_check_deck = true;
  564.         }
  565.         if (rule.match(/(^|,|,)(NOSHUFFLE|NS)(,|,|$)/)) {
  566.           this.hostinfo.no_shuffle_deck = true;
  567.         }
  568.         if (rule.match(/(^|,|,)(IGPRIORITY|PR)(,|,|$)/)) {
  569.           this.hostinfo.enable_priority = true;
  570.         }
  571.       }
  572.       param = [0, this.hostinfo.lflist, this.hostinfo.rule, this.hostinfo.mode, (this.hostinfo.enable_priority ? 'T' : 'F'), (this.hostinfo.no_check_deck ? 'T' : 'F'), (this.hostinfo.no_shuffle_deck ? 'T' : 'F'), this.hostinfo.start_lp, this.hostinfo.start_hand, this.hostinfo.draw_count, this.hostinfo.time_limit, this.hostinfo.replay_mode];
  573.       try {
  574.         this.process = spawn('./ygopro', param, {
  575.           cwd: 'ygopro'
  576.         });
  577.         this.process.on('error', (function(_this) {
  578.           return function(err) {
  579.             _.each(_this.players, function(player) {
  580.               return ygopro.stoc_die(player, "${create_room_failed}");
  581.             });
  582.             _this["delete"]();
  583.           };
  584.         })(this));
  585.         this.process.on('exit', (function(_this) {
  586.           return function(code) {
  587.             if (!_this.disconnector) {
  588.               _this.disconnector = 'server';
  589.             }
  590.             _this["delete"]();
  591.           };
  592.         })(this));
  593.         this.process.stdout.setEncoding('utf8');
  594.         this.process.stdout.once('data', (function(_this) {
  595.           return function(data) {
  596.             _this.established = true;
  597.             if (!_this.windbot && settings.modules.http.websocket_roomlist) {
  598.               roomlist.create(_this);
  599.             }
  600.             _this.port = parseInt(data);
  601.             _.each(_this.players, function(player) {
  602.               player.server.connect(_this.port, '127.0.0.1', function() {
  603.                 var buffer, j, len, ref;
  604.                 ref = player.pre_establish_buffers;
  605.                 for (j = 0, len = ref.length; j < len; j++) {
  606.                   buffer = ref[j];
  607.                   player.server.write(buffer);
  608.                 }
  609.                 player.established = true;
  610.                 player.pre_establish_buffers = [];
  611.               });
  612.             });
  613.             if (_this.windbot) {
  614.               setTimeout(function() {
  615.                 return _this.add_windbot(_this.windbot);
  616.               }, 200);
  617.             }
  618.           };
  619.         })(this));
  620.         this.process.stderr.on('data', (function(_this) {
  621.           return function(data) {
  622.             data = "Debug: " + data;
  623.             data = data.replace(/\n$/, "");
  624.             log.info("YGOPRO " + data);
  625.             write2(data);
  626.             ygopro.stoc_send_chat_to_room(_this, data, ygopro.constants.COLORS.RED);
  627.             _this.has_ygopro_error = true;
  628.           };
  629.         })(this));
  630.       } catch (error1) {
  631.         this.error = "${create_room_failed}";
  632.       }
  633.     }
  634.  
  635.     Room.prototype["delete"] = function() {
  636.       var index, log_rep_id, name, player_ips, player_names, recorder_buffer, ref, replay_id, score, score_array;
  637.       if (this.deleted) {
  638.         return;
  639.       }
  640.       if (this.started && settings.modules.arena_mode.enabled && this.arena) {
  641.         score_array = [];
  642.         ref = this.scores;
  643.         for (name in ref) {
  644.           score = ref[name];
  645.           score_array.push({
  646.             name: name,
  647.             score: score
  648.           });
  649.         }
  650.         if (score_array.length === 2) {
  651.           request.post({
  652.             url: settings.modules.arena_mode.post_score,
  653.             form: {
  654.               accesskey: settings.modules.arena_mode.accesskey,
  655.               usernameA: score_array[0].name,
  656.               usernameB: score_array[1].name,
  657.               userscoreA: score_array[0].score,
  658.               userscoreB: score_array[1].score,
  659.               start: this.start_time,
  660.               end: moment().format(),
  661.               arena: this.arena
  662.             }
  663.           }, (function(_this) {
  664.             return function(error, response, body) {
  665.               if (error) {
  666.                 log.warn('SCORE POST ERROR', error);
  667.               } else {
  668.                 if (response.statusCode !== 204 && response.statusCode !== 200) {
  669.                   log.warn('SCORE POST FAIL', response.statusCode, response.statusMessage, _this.name, body);
  670.                 }
  671.               }
  672.             };
  673.           })(this));
  674.         }
  675.       }
  676.       if (this.player_datas.length && settings.modules.cloud_replay.enabled) {
  677.         replay_id = this.cloud_replay_id;
  678.         if (this.has_ygopro_error) {
  679.           log_rep_id = true;
  680.         }
  681.         player_names = this.player_datas[0].name + (this.player_datas[2] ? "+" + this.player_datas[2].name : "") + " VS " + (this.player_datas[1] ? this.player_datas[1].name : "AI") + (this.player_datas[3] ? "+" + this.player_datas[3].name : "");
  682.         player_ips = [];
  683.         _.each(this.player_datas, function(player) {
  684.           player_ips.push(player.ip);
  685.         });
  686.         recorder_buffer = Buffer.concat(this.recorder_buffers);
  687.         zlib.deflate(recorder_buffer, function(err, replay_buffer) {
  688.           var date_time, recorded_ip;
  689.           replay_buffer = replay_buffer.toString('binary');
  690.           date_time = moment().format('YYYY-MM-DD HH:mm:ss');
  691.           redisdb.hmset("replay:" + replay_id, "replay_id", replay_id, "replay_buffer", replay_buffer, "player_names", player_names, "date_time", date_time);
  692.           if (!log_rep_id) {
  693.             redisdb.expire("replay:" + replay_id, 60 * 60 * 24);
  694.           }
  695.           recorded_ip = [];
  696.           _.each(player_ips, function(player_ip) {
  697.             if (_.contains(recorded_ip, player_ip)) {
  698.               return;
  699.             }
  700.             recorded_ip.push(player_ip);
  701.             redisdb.lpush(player_ip + ":replays", replay_id);
  702.           });
  703.           if (log_rep_id) {
  704.             log.info("error replay: R#" + replay_id);
  705.           }
  706.         });
  707.       }
  708.       this.watcher_buffers = [];
  709.       this.recorder_buffers = [];
  710.       this.players = [];
  711.       if (this.watcher) {
  712.         this.watcher.destroy();
  713.       }
  714.       if (this.recorder) {
  715.         this.recorder.destroy();
  716.       }
  717.       this.deleted = true;
  718.       index = _.indexOf(ROOM_all, this);
  719.       if (index !== -1) {
  720.         ROOM_all[index] = null;
  721.       }
  722.       if (!this.windbot && this.established && settings.modules.http.websocket_roomlist) {
  723.         roomlist["delete"](this);
  724.       }
  725.     };
  726.  
  727.     Room.prototype.get_playing_player = function() {
  728.       var playing_player;
  729.       playing_player = [];
  730.       _.each(this.players, function(player) {
  731.         if (player.pos < 4) {
  732.           playing_player.push(player);
  733.         }
  734.       });
  735.       return playing_player;
  736.     };
  737.  
  738.     Room.prototype.get_host = function() {
  739.       var host_player;
  740.       host_player = null;
  741.       _.each(this.players, function(player) {
  742.         if (player.is_host) {
  743.           host_player = player;
  744.         }
  745.       });
  746.       return host_player;
  747.     };
  748.  
  749.     Room.prototype.add_windbot = function(botdata) {
  750.       this.windbot = botdata;
  751.       request({
  752.         url: "http://127.0.0.1:" + settings.modules.windbot.port + "/?name=" + (encodeURIComponent(botdata.name)) + "&deck=" + (encodeURIComponent(botdata.deck)) + "&host=127.0.0.1&port=" + settings.port + "&dialog=" + (encodeURIComponent(botdata.dialog)) + "&version=" + settings.version + "&password=" + (encodeURIComponent(this.name))
  753.       }, (function(_this) {
  754.         return function(error, response, body) {
  755.           if (error) {
  756.             log.warn('windbot add error', error, _this.name);
  757.             ygopro.stoc_send_chat_to_room(_this, "${add_windbot_failed}", ygopro.constants.COLORS.RED);
  758.           }
  759.         };
  760.       })(this));
  761.     };
  762.  
  763.     Room.prototype.connect = function(client) {
  764.       var host_player;
  765.       this.players.push(client);
  766.       if (this.random_type) {
  767.         client.abuse_count = 0;
  768.         host_player = this.get_host();
  769.         if (host_player && (host_player !== client)) {
  770.           ROOM_players_oppentlist[host_player.ip] = client.ip;
  771.           ROOM_players_oppentlist[client.ip] = host_player.ip;
  772.         } else {
  773.           ROOM_players_oppentlist[client.ip] = null;
  774.         }
  775.       }
  776.       if (this.established) {
  777.         if (!this.windbot && !this.started && settings.modules.http.websocket_roomlist) {
  778.           roomlist.update(this);
  779.         }
  780.         client.server.connect(this.port, '127.0.0.1', function() {
  781.           var buffer, j, len, ref;
  782.           ref = client.pre_establish_buffers;
  783.           for (j = 0, len = ref.length; j < len; j++) {
  784.             buffer = ref[j];
  785.             client.server.write(buffer);
  786.           }
  787.           client.established = true;
  788.           client.pre_establish_buffers = [];
  789.         });
  790.       }
  791.     };
  792.  
  793.     Room.prototype.disconnect = function(client, error) {
  794.       var index;
  795.       if (client.is_post_watcher) {
  796.         ygopro.stoc_send_chat_to_room(this, (client.name + " ${quit_watch}") + (error ? ": " + error : ''));
  797.         index = _.indexOf(this.watchers, client);
  798.         if (index !== -1) {
  799.           this.watchers.splice(index, 1);
  800.         }
  801.       } else {
  802.         index = _.indexOf(this.players, client);
  803.         if (index !== -1) {
  804.           this.players.splice(index, 1);
  805.         }
  806.         if (this.started && this.disconnector !== 'server' && (client.pos < 4 || client.is_host)) {
  807.           this.finished = true;
  808.           this.scores[client.name] = -1;
  809.           if (this.random_type && !client.flee_free) {
  810.             ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}");
  811.           }
  812.         }
  813.         if (this.players.length && !(this.windbot && client.is_host)) {
  814.           ygopro.stoc_send_chat_to_room(this, (client.name + " ${left_game}") + (error ? ": " + error : ''));
  815.           if (!this.windbot && !this.started && settings.modules.http.websocket_roomlist) {
  816.             roomlist.update(this);
  817.           }
  818.         } else {
  819.           this.process.kill();
  820.           this["delete"]();
  821.         }
  822.       }
  823.     };
  824.  
  825.     return Room;
  826.  
  827.   })();
  828.  
  829.   net.createServer(function(client) {
  830.     var connect_count, server;
  831.     client.ip = client.remoteAddress;
  832.     connect_count = ROOM_connected_ip[client.ip] || 0;
  833.     if (client.ip !== '::ffff:127.0.0.1') {
  834.       connect_count++;
  835.     }
  836.     ROOM_connected_ip[client.ip] = connect_count;
  837.     server = new net.Socket();
  838.     client.server = server;
  839.     client.setTimeout(2000);
  840.     client.on('close', function(had_error) {
  841.       var room;
  842.       room = ROOM_all[client.rid];
  843.       connect_count = ROOM_connected_ip[client.ip];
  844.       if (connect_count > 0) {
  845.         connect_count--;
  846.       }
  847.       ROOM_connected_ip[client.ip] = connect_count;
  848.       if (!client.closed) {
  849.         client.closed = true;
  850.         if (room) {
  851.           room.disconnect(client);
  852.         }
  853.       }
  854.       server.destroy();
  855.     });
  856.     client.on('error', function(error) {
  857.       var room;
  858.       room = ROOM_all[client.rid];
  859.       connect_count = ROOM_connected_ip[client.ip];
  860.       if (connect_count > 0) {
  861.         connect_count--;
  862.       }
  863.       ROOM_connected_ip[client.ip] = connect_count;
  864.       if (!client.closed) {
  865.         client.closed = error;
  866.         if (room) {
  867.           room.disconnect(client, error);
  868.         }
  869.       }
  870.       server.destroy();
  871.     });
  872.     client.on('timeout', function() {
  873.       server.destroy();
  874.     });
  875.     server.on('close', function(had_error) {
  876.       var room;
  877.       room = ROOM_all[client.rid];
  878.       if (room) {
  879.         room.disconnector = 'server';
  880.       }
  881.       if (!server.closed) {
  882.         server.closed = true;
  883.       }
  884.       if (!client.closed) {
  885.         ygopro.stoc_send_chat(client, "${server_closed}", ygopro.constants.COLORS.RED);
  886.         client.destroy();
  887.       }
  888.     });
  889.     server.on('error', function(error) {
  890.       var room;
  891.       room = ROOM_all[client.rid];
  892.       if (room) {
  893.         room.disconnector = 'server';
  894.       }
  895.       server.closed = error;
  896.       if (!client.closed) {
  897.         ygopro.stoc_send_chat(client, "${server_error}: " + error, ygopro.constants.COLORS.RED);
  898.         client.destroy();
  899.       }
  900.     });
  901.     if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
  902.       log.info('BAD IP', client.ip);
  903.       client.destroy();
  904.       return;
  905.     }
  906.     if (settings.modules.cloud_replay.enabled) {
  907.       client.open_cloud_replay = function(err, replay) {
  908.         var buffer;
  909.         if (err || !replay) {
  910.           ygopro.stoc_die(client, "${cloud_replay_no}");
  911.           return;
  912.         }
  913.         redisdb.expire("replay:" + replay.replay_id, 60 * 60 * 48);
  914.         buffer = new Buffer(replay.replay_buffer, 'binary');
  915.         zlib.unzip(buffer, function(err, replay_buffer) {
  916.           if (err) {
  917.             log.info("cloud replay unzip error: " + err);
  918.             ygopro.stoc_send_chat(client, "${cloud_replay_error}", ygopro.constants.COLORS.RED);
  919.             client.destroy();
  920.             return;
  921.           }
  922.           ygopro.stoc_send_chat(client, "${cloud_replay_playing} R#" + replay.replay_id + " " + replay.player_names + " " + replay.date_time, ygopro.constants.COLORS.BABYBLUE);
  923.           client.write(replay_buffer, function() {
  924.             client.destroy();
  925.           });
  926.         });
  927.       };
  928.     }
  929.     client.pre_establish_buffers = new Array();
  930.     client.on('data', function(ctos_buffer) {
  931.       var b, bad_ip_count, buffer, cancel, ctos_message_length, ctos_proto, datas, info, j, k, len, len1, looplimit, room, struct;
  932.       if (client.is_post_watcher) {
  933.         room = ROOM_all[client.rid];
  934.         if (room) {
  935.           room.watcher.write(ctos_buffer);
  936.         }
  937.       } else {
  938.         ctos_message_length = 0;
  939.         ctos_proto = 0;
  940.         datas = [];
  941.         looplimit = 0;
  942.         while (true) {
  943.           if (ctos_message_length === 0) {
  944.             if (ctos_buffer.length >= 2) {
  945.               ctos_message_length = ctos_buffer.readUInt16LE(0);
  946.             } else {
  947.               if (ctos_buffer.length !== 0) {
  948.                 log.warn("bad ctos_buffer length", client.ip);
  949.               }
  950.               break;
  951.             }
  952.           } else if (ctos_proto === 0) {
  953.             if (ctos_buffer.length >= 3) {
  954.               ctos_proto = ctos_buffer.readUInt8(2);
  955.             } else {
  956.               log.warn("bad ctos_proto length", client.ip);
  957.               break;
  958.             }
  959.           } else {
  960.             if (ctos_buffer.length >= 2 + ctos_message_length) {
  961.               cancel = false;
  962.               if (ygopro.ctos_follows[ctos_proto]) {
  963.                 b = ctos_buffer.slice(3, ctos_message_length - 1 + 3);
  964.                 info = null;
  965.                 if (struct = ygopro.structs[ygopro.proto_structs.CTOS[ygopro.constants.CTOS[ctos_proto]]]) {
  966.                   struct._setBuff(b);
  967.                   info = _.clone(struct.fields);
  968.                 }
  969.                 if (ygopro.ctos_follows[ctos_proto].synchronous) {
  970.                   cancel = ygopro.ctos_follows[ctos_proto].callback(b, info, client, server);
  971.                 } else {
  972.                   ygopro.ctos_follows[ctos_proto].callback(b, info, client, server);
  973.                 }
  974.               }
  975.               if (!cancel) {
  976.                 datas.push(ctos_buffer.slice(0, 2 + ctos_message_length));
  977.               }
  978.               ctos_buffer = ctos_buffer.slice(2 + ctos_message_length);
  979.               ctos_message_length = 0;
  980.               ctos_proto = 0;
  981.             } else {
  982.               if (ctos_message_length !== 17735) {
  983.                 log.warn("bad ctos_message length", client.ip, ctos_buffer.length, ctos_message_length, ctos_proto);
  984.               }
  985.               break;
  986.             }
  987.           }
  988.           looplimit++;
  989.           if (looplimit > 800 || ROOM_bad_ip[client.ip] > 5) {
  990.             log.info("error ctos", client.name, client.ip);
  991.             bad_ip_count = ROOM_bad_ip[client.ip];
  992.             if (bad_ip_count) {
  993.               ROOM_bad_ip[client.ip] = bad_ip_count + 1;
  994.             } else {
  995.               ROOM_bad_ip[client.ip] = 1;
  996.             }
  997.             client.destroy();
  998.             break;
  999.           }
  1000.         }
  1001.         if (client.established) {
  1002.           for (j = 0, len = datas.length; j < len; j++) {
  1003.             buffer = datas[j];
  1004.             server.write(buffer);
  1005.           }
  1006.         } else {
  1007.           for (k = 0, len1 = datas.length; k < len1; k++) {
  1008.             buffer = datas[k];
  1009.             client.pre_establish_buffers.push(buffer);
  1010.           }
  1011.         }
  1012.       }
  1013.     });
  1014.     server.on('data', function(stoc_buffer) {
  1015.       var b, buffer, cancel, datas, info, j, len, looplimit, stanzas, stoc_message_length, stoc_proto, struct;
  1016.       stoc_message_length = 0;
  1017.       stoc_proto = 0;
  1018.       datas = [];
  1019.       looplimit = 0;
  1020.       while (true) {
  1021.         if (stoc_message_length === 0) {
  1022.           if (stoc_buffer.length >= 2) {
  1023.             stoc_message_length = stoc_buffer.readUInt16LE(0);
  1024.           } else {
  1025.             if (stoc_buffer.length !== 0) {
  1026.               log.warn("bad stoc_buffer length", client.ip);
  1027.             }
  1028.             break;
  1029.           }
  1030.         } else if (stoc_proto === 0) {
  1031.           if (stoc_buffer.length >= 3) {
  1032.             stoc_proto = stoc_buffer.readUInt8(2);
  1033.           } else {
  1034.             log.warn("bad stoc_proto length", client.ip);
  1035.             break;
  1036.           }
  1037.         } else {
  1038.           if (stoc_buffer.length >= 2 + stoc_message_length) {
  1039.             cancel = false;
  1040.             stanzas = stoc_proto;
  1041.             if (ygopro.stoc_follows[stoc_proto]) {
  1042.               b = stoc_buffer.slice(3, stoc_message_length - 1 + 3);
  1043.               info = null;
  1044.               if (struct = ygopro.structs[ygopro.proto_structs.STOC[ygopro.constants.STOC[stoc_proto]]]) {
  1045.                 struct._setBuff(b);
  1046.                 info = _.clone(struct.fields);
  1047.               }
  1048.               if (ygopro.stoc_follows[stoc_proto].synchronous) {
  1049.                 cancel = ygopro.stoc_follows[stoc_proto].callback(b, info, client, server);
  1050.               } else {
  1051.                 ygopro.stoc_follows[stoc_proto].callback(b, info, client, server);
  1052.               }
  1053.             }
  1054.             if (!cancel) {
  1055.               datas.push(stoc_buffer.slice(0, 2 + stoc_message_length));
  1056.             }
  1057.             stoc_buffer = stoc_buffer.slice(2 + stoc_message_length);
  1058.             stoc_message_length = 0;
  1059.             stoc_proto = 0;
  1060.           } else {
  1061.             log.warn("bad stoc_message length", client.ip);
  1062.             break;
  1063.           }
  1064.         }
  1065.         looplimit++;
  1066.         if (looplimit > 800) {
  1067.           log.info("error stoc", client.name);
  1068.           server.destroy();
  1069.           break;
  1070.         }
  1071.       }
  1072.       for (j = 0, len = datas.length; j < len; j++) {
  1073.         buffer = datas[j];
  1074.         client.write(buffer);
  1075.       }
  1076.     });
  1077.   }).listen(settings.port, function() {
  1078.     log.info("server started", settings.port);
  1079.   });
  1080.  
  1081.   ygopro.ctos_follow('PLAYER_INFO', true, function(buffer, info, client, server) {
  1082.     var geo, lang, name, struct;
  1083.     name = info.name.split("$")[0];
  1084.     if (_.any(settings.ban.illegal_id, function(badid) {
  1085.       var matchs, regexp;
  1086.       regexp = new RegExp(badid, 'i');
  1087.       matchs = name.match(regexp);
  1088.       if (matchs) {
  1089.         name = matchs[1];
  1090.         return true;
  1091.       }
  1092.       return false;
  1093.     }, name)) {
  1094.       client.rag = true;
  1095.     }
  1096.     struct = ygopro.structs["CTOS_PlayerInfo"];
  1097.     struct._setBuff(buffer);
  1098.     struct.set("name", name);
  1099.     buffer = struct.buffer;
  1100.     client.name = name;
  1101.     if (!settings.modules.i18n.auto_pick || client.ip === "::ffff:127.0.0.1") {
  1102.       client.lang = settings.modules.i18n["default"];
  1103.     } else {
  1104.       geo = geoip.lookup(client.ip);
  1105.       if (!geo) {
  1106.         log.warn("fail to locate ip", client.name, client.ip);
  1107.         client.lang = settings.modules.i18n.fallback;
  1108.       } else {
  1109.         if (lang = settings.modules.i18n.map[geo.country]) {
  1110.           client.lang = lang;
  1111.         } else {
  1112.           client.lang = settings.modules.i18n.fallback;
  1113.         }
  1114.       }
  1115.     }
  1116.     return false;
  1117.   });
  1118.  
  1119.   ygopro.ctos_follow('JOIN_GAME', false, function(buffer, info, client, server) {
  1120.     var check, decrypted_buffer, finish, i, id, j, k, len, len1, name, ref, ref1, replay_id, room, secret, struct;
  1121.     if (settings.modules.stop) {
  1122.       ygopro.stoc_die(client, settings.modules.stop);
  1123.     } else if (info.pass.toUpperCase() === "R" && settings.modules.cloud_replay.enabled) {
  1124.       ygopro.stoc_send_chat(client, "${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE);
  1125.       redisdb.lrange(client.ip + ":replays", 0, 2, function(err, result) {
  1126.         _.each(result, function(replay_id, id) {
  1127.           redisdb.hgetall("replay:" + replay_id, function(err, replay) {
  1128.             if (err || !replay) {
  1129.               if (err) {
  1130.                 log.info("cloud replay getall error: " + err);
  1131.               }
  1132.               return;
  1133.             }
  1134.             ygopro.stoc_send_chat(client, "<" + (id - 0 + 1) + "> R#" + replay_id + " " + replay.player_names + " " + replay.date_time, ygopro.constants.COLORS.BABYBLUE);
  1135.           });
  1136.         });
  1137.       });
  1138.       setTimeout((function() {
  1139.         ygopro.stoc_send(client, 'ERROR_MSG', {
  1140.           msg: 1,
  1141.           code: 9
  1142.         });
  1143.         client.destroy();
  1144.       }), 500);
  1145.     } else if (info.pass.slice(0, 2).toUpperCase() === "R#" && settings.modules.cloud_replay.enabled) {
  1146.       replay_id = info.pass.split("#")[1];
  1147.       if (replay_id > 0 && replay_id <= 9) {
  1148.         redisdb.lindex(client.ip + ":replays", replay_id - 1, function(err, replay_id) {
  1149.           if (err || !replay_id) {
  1150.             if (err) {
  1151.               log.info("cloud replay replayid error: " + err);
  1152.             }
  1153.             ygopro.stoc_die(client, "${cloud_replay_no}");
  1154.             return;
  1155.           }
  1156.           redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
  1157.         });
  1158.       } else if (replay_id) {
  1159.         redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
  1160.       } else {
  1161.         ygopro.stoc_die(client, "${cloud_replay_no}");
  1162.       }
  1163.     } else if (info.pass.toUpperCase() === "W" && settings.modules.cloud_replay.enabled) {
  1164.       replay_id = Cloud_replay_ids[Math.floor(Math.random() * Cloud_replay_ids.length)];
  1165.       redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
  1166.     } else if (info.version !== settings.version && (info.version !== 9018 || settings.version !== 9019 || client.name !== "Knight of Hanoi")) {
  1167.       ygopro.stoc_send_chat(client, settings.modules.update, ygopro.constants.COLORS.RED);
  1168.       ygopro.stoc_send(client, 'ERROR_MSG', {
  1169.         msg: 4,
  1170.         code: settings.version
  1171.       });
  1172.       client.destroy();
  1173.     } else if (!info.pass.length && !settings.modules.random_duel.enabled && !settings.modules.windbot.enabled) {
  1174.       ygopro.stoc_die(client, "${blank_room_name}");
  1175.     } else if (info.pass.length && settings.modules.mycard.enabled && info.pass.slice(0, 3) !== 'AI#') {
  1176.       ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
  1177.       if (info.pass.length <= 8) {
  1178.         ygopro.stoc_die(client, '${invalid_password_length}');
  1179.         return;
  1180.       }
  1181.       buffer = new Buffer(info.pass.slice(0, 8), 'base64');
  1182.       if (buffer.length !== 6) {
  1183.         ygopro.stoc_die(client, '${invalid_password_payload}');
  1184.         return;
  1185.       }
  1186.       check = function(buf) {
  1187.         var checksum, i, j, ref;
  1188.         checksum = 0;
  1189.         for (i = j = 0, ref = buf.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
  1190.           checksum += buf.readUInt8(i);
  1191.         }
  1192.         return (checksum & 0xFF) === 0;
  1193.       };
  1194.       finish = function(buffer) {
  1195.         var action, j, len, name, opt1, opt2, opt3, options, ref, room, title;
  1196.         action = buffer.readUInt8(1) >> 4;
  1197.         if (buffer !== decrypted_buffer && (action === 1 || action === 2 || action === 4)) {
  1198.           ygopro.stoc_die(client, '${invalid_password_unauthorized}');
  1199.           return;
  1200.         }
  1201.         switch (action) {
  1202.           case 1:
  1203.           case 2:
  1204.             name = crypto.createHash('md5').update(info.pass + client.name).digest('base64').slice(0, 10).replace('+', '-').replace('/', '_');
  1205.             if (ROOM_find_by_name(name)) {
  1206.               ygopro.stoc_die(client, '${invalid_password_existed}');
  1207.               return;
  1208.             }
  1209.             opt1 = buffer.readUInt8(2);
  1210.             opt2 = buffer.readUInt16LE(3);
  1211.             opt3 = buffer.readUInt8(5);
  1212.             options = {
  1213.               lflist: 0,
  1214.               time_limit: 180,
  1215.               rule: (opt1 >> 5) & 3,
  1216.               mode: (opt1 >> 3) & 3,
  1217.               enable_priority: !!((opt1 >> 2) & 1),
  1218.               no_check_deck: !!((opt1 >> 1) & 1),
  1219.               no_shuffle_deck: !!(opt1 & 1),
  1220.               start_lp: opt2,
  1221.               start_hand: opt3 >> 4,
  1222.               draw_count: opt3 & 0xF
  1223.             };
  1224.             options.lflist = _.findIndex(settings.lflist, function(list) {
  1225.               return ((options.rule === 1) === list.tcg) && list.date.isBefore();
  1226.             });
  1227.             room = new Room(name, options);
  1228.             room.title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
  1229.             room["private"] = action === 2;
  1230.             break;
  1231.           case 3:
  1232.             name = info.pass.slice(8);
  1233.             room = ROOM_find_by_name(name);
  1234.             if (!room) {
  1235.               ygopro.stoc_die(client, '${invalid_password_not_found}');
  1236.               return;
  1237.             }
  1238.             break;
  1239.           case 4:
  1240.             room = ROOM_find_or_create_by_name('M#' + info.pass.slice(8));
  1241.             room["private"] = true;
  1242.             room.arena = settings.modules.arena_mode.mode;
  1243.             break;
  1244.           case 5:
  1245.             title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
  1246.             room = ROOM_find_by_title(title);
  1247.             if (!room) {
  1248.               ygopro.stoc_die(client, '${invalid_password_not_found}');
  1249.               return;
  1250.             }
  1251.             break;
  1252.           default:
  1253.             ygopro.stoc_die(client, '${invalid_password_action}');
  1254.             return;
  1255.         }
  1256.         if (!room) {
  1257.           ygopro.stoc_die(client, "${server_full}");
  1258.         } else if (room.error) {
  1259.           ygopro.stoc_die(client, room.error);
  1260.         } else if (room.started) {
  1261.           if (settings.modules.cloud_replay.enable_halfway_watch) {
  1262.             client.setTimeout(300000);
  1263.             client.rid = _.indexOf(ROOM_all, room);
  1264.             client.is_post_watcher = true;
  1265.             ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
  1266.             room.watchers.push(client);
  1267.             ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
  1268.             ref = room.watcher_buffers;
  1269.             for (j = 0, len = ref.length; j < len; j++) {
  1270.               buffer = ref[j];
  1271.               client.write(buffer);
  1272.             }
  1273.           } else {
  1274.             ygopro.stoc_die(client, "${watch_denied}");
  1275.           }
  1276.         } else {
  1277.           client.setTimeout(300000);
  1278.           client.rid = _.indexOf(ROOM_all, room);
  1279.           room.connect(client);
  1280.         }
  1281.       };
  1282.       if (id = users_cache[client.name]) {
  1283.         secret = id % 65535 + 1;
  1284.         decrypted_buffer = new Buffer(6);
  1285.         ref = [0, 2, 4];
  1286.         for (j = 0, len = ref.length; j < len; j++) {
  1287.           i = ref[j];
  1288.           decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
  1289.         }
  1290.         if (check(decrypted_buffer)) {
  1291.           return finish(decrypted_buffer);
  1292.         }
  1293.       }
  1294.       request({
  1295.         baseUrl: settings.modules.mycard.auth_base_url,
  1296.         url: '/users/' + encodeURIComponent(client.name) + '.json',
  1297.         qs: {
  1298.           api_key: settings.modules.mycard.auth_key,
  1299.           api_username: client.name,
  1300.           skip_track_visit: true
  1301.         },
  1302.         json: true
  1303.       }, function(error, response, body) {
  1304.         var k, len1, ref1;
  1305.         if (body && body.user) {
  1306.           users_cache[client.name] = body.user.id;
  1307.           secret = body.user.id % 65535 + 1;
  1308.           decrypted_buffer = new Buffer(6);
  1309.           ref1 = [0, 2, 4];
  1310.           for (k = 0, len1 = ref1.length; k < len1; k++) {
  1311.             i = ref1[k];
  1312.             decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
  1313.           }
  1314.           if (check(decrypted_buffer)) {
  1315.             buffer = decrypted_buffer;
  1316.           }
  1317.         }
  1318.         if (!check(buffer)) {
  1319.           ygopro.stoc_die(client, '${invalid_password_checksum}');
  1320.           return;
  1321.         }
  1322.         return finish(buffer);
  1323.       });
  1324.     } else if (!client.name || client.name === "") {
  1325.       ygopro.stoc_die(client, "${bad_user_name}");
  1326.     } else if (ROOM_connected_ip[client.ip] > 5) {
  1327.       log.warn("MULTI LOGIN", client.name, client.ip);
  1328.       ygopro.stoc_die(client, "${too_much_connection}" + client.ip);
  1329.     } else if (_.indexOf(settings.ban.banned_user, client.name) > -1) {
  1330.       settings.ban.banned_ip.push(client.ip);
  1331.       log.warn("BANNED USER LOGIN", client.name, client.ip);
  1332.       ygopro.stoc_die(client, "${banned_user_login}");
  1333.     } else if (_.indexOf(settings.ban.banned_ip, client.ip) > -1) {
  1334.       log.warn("BANNED IP LOGIN", client.name, client.ip);
  1335.       ygopro.stoc_die(client, "${banned_ip_login}");
  1336.     } else if (_.any(settings.ban.badword_level3, function(badword) {
  1337.       var regexp;
  1338.       regexp = new RegExp(badword, 'i');
  1339.       return name.match(regexp);
  1340.     }, name = client.name)) {
  1341.       log.warn("BAD NAME LEVEL 3", client.name, client.ip);
  1342.       ygopro.stoc_die(client, "${bad_name_level3}");
  1343.     } else if (_.any(settings.ban.badword_level2, function(badword) {
  1344.       var regexp;
  1345.       regexp = new RegExp(badword, 'i');
  1346.       return name.match(regexp);
  1347.     }, name = client.name)) {
  1348.       log.warn("BAD NAME LEVEL 2", client.name, client.ip);
  1349.       ygopro.stoc_die(client, "${bad_name_level2}");
  1350.     } else if (_.any(settings.ban.badword_level1, function(badword) {
  1351.       var regexp;
  1352.       regexp = new RegExp(badword, 'i');
  1353.       return name.match(regexp);
  1354.     }, name = client.name)) {
  1355.       log.warn("BAD NAME LEVEL 1", client.name, client.ip);
  1356.       ygopro.stoc_die(client, "${bad_name_level1}");
  1357.     } else if (info.pass.length && !ROOM_validate(info.pass)) {
  1358.       ygopro.stoc_die(client, "${invalid_password_room}");
  1359.     } else {
  1360.       if (info.version === 9018 && settings.version === 9019 && client.name === "Knight of Hanoi") {
  1361.         info.version = settings.version;
  1362.         struct = ygopro.structs["CTOS_JoinGame"];
  1363.         struct._setBuff(buffer);
  1364.         struct.set("version", info.version);
  1365.         buffer = struct.buffer;
  1366.         ygopro.stoc_send_chat(client, "看起来你是YGOMobile的用户,请记得更新先行卡补丁,否则会看到白卡", ygopro.constants.COLORS.GREEN);
  1367.       }
  1368.       room = ROOM_find_or_create_by_name(info.pass, client.ip);
  1369.       if (!room) {
  1370.         ygopro.stoc_die(client, "${server_full}");
  1371.       } else if (room.error) {
  1372.         ygopro.stoc_die(client, room.error);
  1373.       } else if (room.started) {
  1374.         if (settings.modules.cloud_replay.enable_halfway_watch) {
  1375.           client.setTimeout(300000);
  1376.           client.rid = _.indexOf(ROOM_all, room);
  1377.           client.is_post_watcher = true;
  1378.           ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
  1379.           room.watchers.push(client);
  1380.           ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
  1381.           ref1 = room.watcher_buffers;
  1382.           for (k = 0, len1 = ref1.length; k < len1; k++) {
  1383.             buffer = ref1[k];
  1384.             client.write(buffer);
  1385.           }
  1386.         } else {
  1387.           ygopro.stoc_die(client, "${watch_denied}");
  1388.         }
  1389.       } else {
  1390.         client.setTimeout(300000);
  1391.         client.rid = _.indexOf(ROOM_all, room);
  1392.         room.connect(client);
  1393.       }
  1394.     }
  1395.   });
  1396.  
  1397.   ygopro.stoc_follow('JOIN_GAME', false, function(buffer, info, client, server) {
  1398.     var recorder, room, watcher;
  1399.     room = ROOM_all[client.rid];
  1400.     if (!room) {
  1401.       return;
  1402.     }
  1403.     if (settings.modules.welcome) {
  1404.       ygopro.stoc_send_chat(client, settings.modules.welcome, ygopro.constants.COLORS.GREEN);
  1405.     }
  1406.     if (room.welcome) {
  1407.       ygopro.stoc_send_chat(client, room.welcome, ygopro.constants.COLORS.BABYBLUE);
  1408.     }
  1409.     if (settings.modules.arena_mode.enabled && client.ip !== '::ffff:127.0.0.1') {
  1410.       request({
  1411.         url: settings.modules.arena_mode.get_score + encodeURIComponent(client.name),
  1412.         json: true
  1413.       }, function(error, response, body) {
  1414.         var rank_txt;
  1415.         if (error) {
  1416.           log.warn('LOAD SCORE ERROR', client.name, error);
  1417.         } else if (!body || _.isString(body)) {
  1418.           log.warn('LOAD SCORE FAIL', client.name, response.statusCode, response.statusMessage, body);
  1419.         } else {
  1420.           rank_txt = body.arena_rank > 0 ? "${rank_arena}" + body.arena_rank : "${rank_blank}";
  1421.           ygopro.stoc_send_chat(client, client.name + "${exp_value_part1}" + body.exp + "${exp_value_part2}${exp_value_part3}" + (Math.round(body.pt)) + rank_txt + "${exp_value_part4}", ygopro.constants.COLORS.BABYBLUE);
  1422.         }
  1423.       });
  1424.     }
  1425.     if (!room.recorder) {
  1426.       room.recorder = recorder = net.connect(room.port, function() {
  1427.         ygopro.ctos_send(recorder, 'PLAYER_INFO', {
  1428.           name: "Marshtomp"
  1429.         });
  1430.         ygopro.ctos_send(recorder, 'JOIN_GAME', {
  1431.           version: settings.version,
  1432.           pass: ""
  1433.         });
  1434.         ygopro.ctos_send(recorder, 'HS_TOOBSERVER');
  1435.       });
  1436.       recorder.on('data', function(data) {
  1437.         room = ROOM_all[client.rid];
  1438.         if (!(room && settings.modules.cloud_replay.enabled)) {
  1439.           return;
  1440.         }
  1441.         room.recorder_buffers.push(data);
  1442.       });
  1443.       recorder.on('error', function(error) {});
  1444.     }
  1445.     if (settings.modules.cloud_replay.enable_halfway_watch && !room.watcher) {
  1446.       room.watcher = watcher = net.connect(room.port, function() {
  1447.         ygopro.ctos_send(watcher, 'PLAYER_INFO', {
  1448.           name: "the Big Brother"
  1449.         });
  1450.         ygopro.ctos_send(watcher, 'JOIN_GAME', {
  1451.           version: settings.version,
  1452.           pass: ""
  1453.         });
  1454.         ygopro.ctos_send(watcher, 'HS_TOOBSERVER');
  1455.       });
  1456.       watcher.on('data', function(data) {
  1457.         var j, len, ref, w;
  1458.         room = ROOM_all[client.rid];
  1459.         if (!room) {
  1460.           return;
  1461.         }
  1462.         room.watcher_buffers.push(data);
  1463.         ref = room.watchers;
  1464.         for (j = 0, len = ref.length; j < len; j++) {
  1465.           w = ref[j];
  1466.           if (w) {
  1467.             w.write(data);
  1468.           }
  1469.         }
  1470.       });
  1471.       watcher.on('error', function(error) {});
  1472.     }
  1473.   });
  1474.  
  1475.   load_dialogues = function() {
  1476.     request({
  1477.       url: settings.modules.dialogues.get,
  1478.       json: true
  1479.     }, function(error, response, body) {
  1480.       if (_.isString(body)) {
  1481.         log.warn("dialogues bad json", body);
  1482.       } else if (error || !body) {
  1483.         log.warn('dialogues error', error, response);
  1484.       } else {
  1485.         nconf.myset(settings, "dialogues", body);
  1486.         log.info("dialogues loaded", _.size(body));
  1487.       }
  1488.     });
  1489.   };
  1490.  
  1491.   if (settings.modules.dialogues.get) {
  1492.     load_dialogues();
  1493.   }
  1494.  
  1495.   ygopro.stoc_follow('GAME_MSG', false, function(buffer, info, client, server) {
  1496.     var card, j, len, line, msg, playertype, pos, reason, ref, ref1, ref2, room, val;
  1497.     room = ROOM_all[client.rid];
  1498.     if (!room) {
  1499.       return;
  1500.     }
  1501.     msg = buffer.readInt8(0);
  1502.     if (msg >= 10 && msg < 30) {
  1503.       room.waiting_for_player = client;
  1504.       room.last_active_time = moment();
  1505.     }
  1506.     if (ygopro.constants.MSG[msg] === 'START') {
  1507.       playertype = buffer.readUInt8(1);
  1508.       client.is_first = !(playertype & 0xf);
  1509.       client.lp = room.hostinfo.start_lp;
  1510.       if (client.is_host) {
  1511.         room.turn = 0;
  1512.       }
  1513.     }
  1514.     if (ygopro.constants.MSG[msg] === 'NEW_TURN') {
  1515.       if (client.is_host) {
  1516.         room.turn = room.turn + 1;
  1517.       }
  1518.       if (client.surrend_confirm) {
  1519.         client.surrend_confirm = false;
  1520.         ygopro.stoc_send_chat(client, "${surrender_canceled}", ygopro.constants.COLORS.BABYBLUE);
  1521.       }
  1522.     }
  1523.     if (ygopro.constants.MSG[msg] === 'WIN' && client.is_host) {
  1524.       pos = buffer.readUInt8(1);
  1525.       if (!(client.is_first || pos === 2)) {
  1526.         pos = 1 - pos;
  1527.       }
  1528.       reason = buffer.readUInt8(2);
  1529.       room.winner = pos;
  1530.       if (room && !room.finished && room.dueling_players[pos]) {
  1531.         room.winner_name = room.dueling_players[pos].name;
  1532.         room.scores[room.winner_name] = room.scores[room.winner_name] + 1;
  1533.       }
  1534.     }
  1535.     if (ygopro.constants.MSG[msg] === 'DAMAGE' && client.is_host) {
  1536.       pos = buffer.readUInt8(1);
  1537.       if (!client.is_first) {
  1538.         pos = 1 - pos;
  1539.       }
  1540.       val = buffer.readInt32LE(2);
  1541.       room.dueling_players[pos].lp -= val;
  1542.       if ((0 < (ref = room.dueling_players[pos].lp) && ref <= 100)) {
  1543.         ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK);
  1544.       }
  1545.     }
  1546.     if (ygopro.constants.MSG[msg] === 'RECOVER' && client.is_host) {
  1547.       pos = buffer.readUInt8(1);
  1548.       if (!client.is_first) {
  1549.         pos = 1 - pos;
  1550.       }
  1551.       val = buffer.readInt32LE(2);
  1552.       room.dueling_players[pos].lp += val;
  1553.     }
  1554.     if (ygopro.constants.MSG[msg] === 'LPUPDATE' && client.is_host) {
  1555.       pos = buffer.readUInt8(1);
  1556.       if (!client.is_first) {
  1557.         pos = 1 - pos;
  1558.       }
  1559.       val = buffer.readInt32LE(2);
  1560.       room.dueling_players[pos].lp = val;
  1561.     }
  1562.     if (ygopro.constants.MSG[msg] === 'PAY_LPCOST' && client.is_host) {
  1563.       pos = buffer.readUInt8(1);
  1564.       if (!client.is_first) {
  1565.         pos = 1 - pos;
  1566.       }
  1567.       val = buffer.readInt32LE(2);
  1568.       room.dueling_players[pos].lp -= val;
  1569.       if ((0 < (ref1 = room.dueling_players[pos].lp) && ref1 <= 100)) {
  1570.         ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK);
  1571.       }
  1572.     }
  1573.     if (settings.modules.dialogues.enabled) {
  1574.       if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING') {
  1575.         card = buffer.readUInt32LE(1);
  1576.         if (settings.dialogues[card]) {
  1577.           ref2 = _.lines(settings.dialogues[card][Math.floor(Math.random() * settings.dialogues[card].length)]);
  1578.           for (j = 0, len = ref2.length; j < len; j++) {
  1579.             line = ref2[j];
  1580.             ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK);
  1581.           }
  1582.         }
  1583.       }
  1584.     }
  1585.   });
  1586.  
  1587.   ygopro.ctos_follow('HS_KICK', true, function(buffer, info, client, server) {
  1588.     var j, len, player, ref, room;
  1589.     room = ROOM_all[client.rid];
  1590.     if (!room) {
  1591.       return;
  1592.     }
  1593.     ref = room.players;
  1594.     for (j = 0, len = ref.length; j < len; j++) {
  1595.       player = ref[j];
  1596.       if (player && player.pos === info.pos && player !== client) {
  1597.         client.kick_count = client.kick_count ? client.kick_count + 1 : 1;
  1598.         if (client.kick_count >= 5 && room.random_type) {
  1599.           ygopro.stoc_send_chat_to_room(room, client.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
  1600.           ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
  1601.           client.destroy();
  1602.           return true;
  1603.         }
  1604.         ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_player}", ygopro.constants.COLORS.RED);
  1605.       }
  1606.     }
  1607.     return false;
  1608.   });
  1609.  
  1610.   ygopro.stoc_follow('TYPE_CHANGE', false, function(buffer, info, client, server) {
  1611.     var is_host, selftype;
  1612.     selftype = info.type & 0xf;
  1613.     is_host = ((info.type >> 4) & 0xf) !== 0;
  1614.     client.is_host = is_host;
  1615.     client.pos = selftype;
  1616.   });
  1617.  
  1618.   ygopro.stoc_follow('HS_PLAYER_CHANGE', false, function(buffer, info, client, server) {
  1619.     var is_ready, j, len, player, pos, ref, room;
  1620.     room = ROOM_all[client.rid];
  1621.     if (!(room && room.max_player && client.is_host)) {
  1622.       return;
  1623.     }
  1624.     pos = info.status >> 4;
  1625.     is_ready = (info.status & 0xf) === 9;
  1626.     if (pos < room.max_player) {
  1627.       room.ready_player_count_without_host = 0;
  1628.       ref = room.players;
  1629.       for (j = 0, len = ref.length; j < len; j++) {
  1630.         player = ref[j];
  1631.         if (player.pos === pos) {
  1632.           player.is_ready = is_ready;
  1633.         }
  1634.         if (!player.is_host) {
  1635.           room.ready_player_count_without_host += player.is_ready;
  1636.         }
  1637.       }
  1638.       if (room.ready_player_count_without_host >= room.max_player - 1) {
  1639.         setTimeout((function() {
  1640.           wait_room_start(ROOM_all[client.rid], 20);
  1641.         }), 1000);
  1642.       }
  1643.     }
  1644.   });
  1645.  
  1646.   wait_room_start = function(room, time) {
  1647.     var j, len, player, ref;
  1648.     if (!(!room || room.started || room.ready_player_count_without_host < room.max_player - 1)) {
  1649.       time -= 1;
  1650.       if (time) {
  1651.         if (!(time % 5)) {
  1652.           ygopro.stoc_send_chat_to_room(room, "" + (time <= 9 ? ' ' : '') + time + "${kick_count_down}", time <= 9 ? ygopro.constants.COLORS.RED : ygopro.constants.COLORS.LIGHTBLUE);
  1653.         }
  1654.         setTimeout((function() {
  1655.           wait_room_start(room, time);
  1656.         }), 1000);
  1657.       } else {
  1658.         ref = room.players;
  1659.         for (j = 0, len = ref.length; j < len; j++) {
  1660.           player = ref[j];
  1661.           if (player && player.is_host) {
  1662.             ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
  1663.             ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
  1664.             player.destroy();
  1665.           }
  1666.         }
  1667.       }
  1668.     }
  1669.   };
  1670.  
  1671.   ygopro.stoc_send_random_tip = function(client) {
  1672.     if (settings.modules.tips.enabled && settings.tips.length) {
  1673.       ygopro.stoc_send_chat(client, "Tip: " + settings.tips[Math.floor(Math.random() * settings.tips.length)]);
  1674.     }
  1675.   };
  1676.  
  1677.   ygopro.stoc_send_random_tip_to_room = function(room) {
  1678.     if (settings.modules.tips.enabled && settings.tips.length) {
  1679.       ygopro.stoc_send_chat_to_room(room, "Tip: " + settings.tips[Math.floor(Math.random() * settings.tips.length)]);
  1680.     }
  1681.   };
  1682.  
  1683.   load_tips = function() {
  1684.     request({
  1685.       url: settings.modules.tips.get,
  1686.       json: true
  1687.     }, function(error, response, body) {
  1688.       if (_.isString(body)) {
  1689.         log.warn("tips bad json", body);
  1690.       } else if (error || !body) {
  1691.         log.warn('tips error', error, response);
  1692.       } else {
  1693.         nconf.myset(settings, "tips", body);
  1694.         log.info("tips loaded", settings.tips.length);
  1695.       }
  1696.     });
  1697.   };
  1698.  
  1699.   if (settings.modules.tips.get) {
  1700.     load_tips();
  1701.     setInterval(function() {
  1702.       var j, len, room;
  1703.       for (j = 0, len = ROOM_all.length; j < len; j++) {
  1704.         room = ROOM_all[j];
  1705.         if (room && room.established) {
  1706.           if (!room.started || room.changing_side) {
  1707.             ygopro.stoc_send_random_tip_to_room(room);
  1708.           }
  1709.         }
  1710.       }
  1711.     }, 30000);
  1712.   }
  1713.  
  1714.   ygopro.stoc_follow('DUEL_START', false, function(buffer, info, client, server) {
  1715.     var deck_arena, deck_name, deck_text, j, len, player, ref, room;
  1716.     room = ROOM_all[client.rid];
  1717.     if (!room) {
  1718.       return;
  1719.     }
  1720.     if (!room.started) {
  1721.       room.started = true;
  1722.       room.start_time = moment().format();
  1723.       if (!room.windbot && settings.modules.http.websocket_roomlist) {
  1724.         roomlist.start(room);
  1725.       }
  1726.       room.dueling_players = [];
  1727.       ref = room.players;
  1728.       for (j = 0, len = ref.length; j < len; j++) {
  1729.         player = ref[j];
  1730.         if (!(player.pos !== 7)) {
  1731.           continue;
  1732.         }
  1733.         room.dueling_players[player.pos] = player;
  1734.         room.scores[player.name] = 0;
  1735.         room.player_datas.push({
  1736.           ip: player.ip,
  1737.           name: player.name
  1738.         });
  1739.       }
  1740.     }
  1741.     if (settings.modules.tips.enabled) {
  1742.       ygopro.stoc_send_random_tip(client);
  1743.     }
  1744.     if (settings.modules.deck_log.enabled && client.main && client.main.length && !client.deck_saved && !room.windbot) {
  1745.       deck_text = '#ygopro-server deck log\n#main\n' + client.main.join('\n') + '\n!side\n' + client.side.join('\n') + '\n';
  1746.       deck_arena = settings.modules.deck_log.arena + '-';
  1747.       if (room.arena) {
  1748.         deck_arena = deck_arena + room.arena;
  1749.       } else if (room.hostinfo.mode === 2) {
  1750.         deck_arena = deck_arena + 'tag';
  1751.       } else if (room.random_type === 'S') {
  1752.         deck_arena = deck_arena + 'entertain';
  1753.       } else if (room.random_type === 'M') {
  1754.         deck_arena = deck_arena + 'athletic';
  1755.       } else {
  1756.         deck_arena = deck_arena + 'custom';
  1757.       }
  1758.       if (settings.modules.deck_log.local) {
  1759.         deck_name = moment().format('YYYY-MM-DD HH-mm-ss') + ' ' + room.port + ' ' + client.pos + ' ' + client.name.replace(/[\/\\\?\*]/g, '_');
  1760.         fs.writeFile(settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', function(err) {
  1761.           if (err) {
  1762.             return log.warn('DECK SAVE ERROR', err);
  1763.           }
  1764.         });
  1765.       }
  1766.       if (settings.modules.deck_log.post) {
  1767.         request.post({
  1768.           url: settings.modules.deck_log.post,
  1769.           form: {
  1770.             accesskey: settings.modules.deck_log.accesskey,
  1771.             deck: deck_text,
  1772.             playername: client.name,
  1773.             arena: deck_arena
  1774.           }
  1775.         }, function(error, response, body) {
  1776.           if (error) {
  1777.             log.warn('DECK POST ERROR', error);
  1778.           } else {
  1779.             if (response.statusCode !== 200) {
  1780.               log.warn('DECK POST FAIL', response.statusCode, client.name, body);
  1781.             }
  1782.           }
  1783.         });
  1784.       }
  1785.       client.deck_saved = true;
  1786.     }
  1787.   });
  1788.  
  1789.   ygopro.ctos_follow('SURRENDER', true, function(buffer, info, client, server) {
  1790.     var room;
  1791.     room = ROOM_all[client.rid];
  1792.     if (!room) {
  1793.       return;
  1794.     }
  1795.     if (!room.started || room.hostinfo.mode === 2) {
  1796.       return true;
  1797.     }
  1798.     if (room.random_type && room.turn < 3 && !client.flee_free) {
  1799.       ygopro.stoc_send_chat(client, "${surrender_denied}", ygopro.constants.COLORS.BABYBLUE);
  1800.       return true;
  1801.     }
  1802.     return false;
  1803.   });
  1804.  
  1805.   ygopro.ctos_follow('CHAT', true, function(buffer, info, client, server) {
  1806.     var cancel, cmd, msg, name, oldmsg, room, struct, windbot;
  1807.     room = ROOM_all[client.rid];
  1808.     if (!room) {
  1809.       return;
  1810.     }
  1811.     msg = _.trim(info.msg);
  1812.     cancel = _.startsWith(msg, "/");
  1813.     if (!(cancel || !room.random_type)) {
  1814.       room.last_active_time = moment();
  1815.     }
  1816.     cmd = msg.split(' ');
  1817.     switch (cmd[0]) {
  1818.       case '/投降':
  1819.       case '/surrender':
  1820.         if (!room.started || room.hostinfo.mode === 2) {
  1821.           return cancel;
  1822.         }
  1823.         if (room.random_type && room.turn < 3) {
  1824.           ygopro.stoc_send_chat(client, "${surrender_denied}", ygopro.constants.COLORS.BABYBLUE);
  1825.           return cancel;
  1826.         }
  1827.         if (client.surrend_confirm) {
  1828.           ygopro.ctos_send(client.server, 'SURRENDER');
  1829.         } else {
  1830.           ygopro.stoc_send_chat(client, "${surrender_confirm}", ygopro.constants.COLORS.BABYBLUE);
  1831.           client.surrend_confirm = true;
  1832.         }
  1833.         break;
  1834.       case '/help':
  1835.         ygopro.stoc_send_chat(client, "${chat_order_main}");
  1836.         ygopro.stoc_send_chat(client, "${chat_order_help}");
  1837.         if (!settings.modules.mycard.enabled) {
  1838.           ygopro.stoc_send_chat(client, "${chat_order_roomname}");
  1839.         }
  1840.         if (settings.modules.windbot.enabled) {
  1841.           ygopro.stoc_send_chat(client, "${chat_order_windbot}");
  1842.         }
  1843.         if (settings.modules.tips.enabled) {
  1844.           ygopro.stoc_send_chat(client, "${chat_order_tip}");
  1845.         }
  1846.         break;
  1847.       case '/tip':
  1848.         if (settings.modules.tips.enabled) {
  1849.           ygopro.stoc_send_random_tip(client);
  1850.         }
  1851.         break;
  1852.       case '/ai':
  1853.         if (settings.modules.windbot.enabled) {
  1854.           if (name = cmd[1]) {
  1855.             windbot = _.sample(_.filter(settings.modules.windbots, function(w) {
  1856.               return w.name === name || w.deck === name;
  1857.             }));
  1858.             if (!windbot) {
  1859.               ygopro.stoc_send_chat(client, "${windbot_deck_not_found}", ygopro.constants.COLORS.RED);
  1860.               return;
  1861.             }
  1862.           } else {
  1863.             windbot = _.sample(settings.modules.windbots);
  1864.           }
  1865.           room.add_windbot(windbot);
  1866.         }
  1867.         break;
  1868.       case '/roomname':
  1869.         if (room) {
  1870.           ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE);
  1871.         }
  1872.     }
  1873.     if (msg.length > 100) {
  1874.       log.warn("SPAM WORD", client.name, client.ip, msg);
  1875.       if (client.abuse_count) {
  1876.         client.abuse_count = client.abuse_count + 2;
  1877.       }
  1878.       ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
  1879.       cancel = true;
  1880.     }
  1881.     if (!(room && room.random_type)) {
  1882.       return cancel;
  1883.     }
  1884.     if (client.abuse_count >= 5) {
  1885.       log.warn("BANNED CHAT", client.name, client.ip, msg);
  1886.       ygopro.stoc_send_chat(client, "${banned_chat_tip}", ygopro.constants.COLORS.RED);
  1887.       return true;
  1888.     }
  1889.     oldmsg = msg;
  1890.     if (_.any(settings.ban.badword_level3, function(badword) {
  1891.       var regexp;
  1892.       regexp = new RegExp(badword, 'i');
  1893.       return msg.match(regexp);
  1894.     }, msg)) {
  1895.       log.warn("BAD WORD LEVEL 3", client.name, client.ip, oldmsg);
  1896.       cancel = true;
  1897.       if (client.abuse_count > 0) {
  1898.         ygopro.stoc_send_chat(client, "${banned_duel_tip}", ygopro.constants.COLORS.RED);
  1899.         ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}");
  1900.         ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}", 3);
  1901.         client.destroy();
  1902.         return true;
  1903.       } else {
  1904.         client.abuse_count = client.abuse_count + 4;
  1905.         ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
  1906.       }
  1907.     } else if (client.rag && room.started) {
  1908.       client.rag = false;
  1909.       cancel = true;
  1910.     } else if (_.any(settings.ban.spam_word, function(badword) {
  1911.       var regexp;
  1912.       regexp = new RegExp(badword, 'i');
  1913.       return msg.match(regexp);
  1914.     }, msg)) {
  1915.       client.abuse_count = client.abuse_count + 2;
  1916.       ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
  1917.       cancel = true;
  1918.     } else if (_.any(settings.ban.badword_level2, function(badword) {
  1919.       var regexp;
  1920.       regexp = new RegExp(badword, 'i');
  1921.       return msg.match(regexp);
  1922.     }, msg)) {
  1923.       log.warn("BAD WORD LEVEL 2", client.name, client.ip, oldmsg);
  1924.       client.abuse_count = client.abuse_count + 3;
  1925.       ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
  1926.       cancel = true;
  1927.     } else {
  1928.       _.each(settings.ban.badword_level1, function(badword) {
  1929.         var regexp;
  1930.         regexp = new RegExp(badword, "ig");
  1931.         msg = msg.replace(regexp, "**");
  1932.       }, msg);
  1933.       if (oldmsg !== msg) {
  1934.         log.warn("BAD WORD LEVEL 1", client.name, client.ip, oldmsg);
  1935.         client.abuse_count = client.abuse_count + 1;
  1936.         ygopro.stoc_send_chat(client, "${chat_warn_level1}");
  1937.         struct = ygopro.structs["chat"];
  1938.         struct._setBuff(buffer);
  1939.         struct.set("msg", msg);
  1940.         buffer = struct.buffer;
  1941.       } else if (_.any(settings.ban.badword_level0, function(badword) {
  1942.         var regexp;
  1943.         regexp = new RegExp(badword, 'i');
  1944.         return msg.match(regexp);
  1945.       }, msg)) {
  1946.         log.info("BAD WORD LEVEL 0", client.name, client.ip, oldmsg);
  1947.       }
  1948.     }
  1949.     if (client.abuse_count >= 2) {
  1950.       ROOM_unwelcome(room, client, "${random_ban_reason_abuse}");
  1951.     }
  1952.     if (client.abuse_count >= 5) {
  1953.       ygopro.stoc_send_chat_to_room(room, client.name + " ${chat_banned}", ygopro.constants.COLORS.RED);
  1954.       ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}");
  1955.     }
  1956.     return cancel;
  1957.   });
  1958.  
  1959.   ygopro.ctos_follow('UPDATE_DECK', true, function(buffer, info, client, server) {
  1960.     var buff_main, buff_side, card, current_deck, deck, deck_array, deck_main, deck_side, deck_text, deckbuf, decks, found_deck, i, j, k, len, len1, line, room, struct;
  1961.     room = ROOM_all[client.rid];
  1962.     if (!room) {
  1963.       return false;
  1964.     }
  1965.     buff_main = (function() {
  1966.       var j, ref, results;
  1967.       results = [];
  1968.       for (i = j = 0, ref = info.mainc; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
  1969.         results.push(info.deckbuf[i]);
  1970.       }
  1971.       return results;
  1972.     })();
  1973.     buff_side = (function() {
  1974.       var j, ref, ref1, results;
  1975.       results = [];
  1976.       for (i = j = ref = info.mainc, ref1 = info.mainc + info.sidec; ref <= ref1 ? j < ref1 : j > ref1; i = ref <= ref1 ? ++j : --j) {
  1977.         results.push(info.deckbuf[i]);
  1978.       }
  1979.       return results;
  1980.     })();
  1981.     client.main = buff_main;
  1982.     client.side = buff_side;
  1983.     if (room.random_type || room.arena) {
  1984.       if (client.is_host) {
  1985.         room.waiting_for_player = room.waiting_for_player2;
  1986.       }
  1987.       room.last_active_time = moment();
  1988.     } else if (!room.started && room.hostinfo.mode === 1 && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.deck_check) {
  1989.       struct = ygopro.structs["deck"];
  1990.       struct._setBuff(buffer);
  1991.       struct.set("mainc", 1);
  1992.       struct.set("sidec", 1);
  1993.       struct.set("deckbuf", [4392470, 4392470]);
  1994.       buffer = struct.buffer;
  1995.       found_deck = false;
  1996.       decks = fs.readdirSync(settings.modules.tournament_mode.deck_path);
  1997.       for (j = 0, len = decks.length; j < len; j++) {
  1998.         deck = decks[j];
  1999.         if (_.endsWith(deck, client.name + ".ydk")) {
  2000.           found_deck = deck;
  2001.         }
  2002.         if (_.endsWith(deck, client.name + ".ydk.ydk")) {
  2003.           found_deck = deck;
  2004.         }
  2005.       }
  2006.       if (found_deck) {
  2007.         deck_text = fs.readFileSync(settings.modules.tournament_mode.deck_path + found_deck, {
  2008.           encoding: "ASCII"
  2009.         });
  2010.         deck_array = deck_text.split("\n");
  2011.         deck_main = [];
  2012.         deck_side = [];
  2013.         current_deck = deck_main;
  2014.         for (k = 0, len1 = deck_array.length; k < len1; k++) {
  2015.           line = deck_array[k];
  2016.           if (line.indexOf("!side") >= 0) {
  2017.             current_deck = deck_side;
  2018.           }
  2019.           card = parseInt(line);
  2020.           if (!isNaN(card)) {
  2021.             current_deck.push(card);
  2022.           }
  2023.         }
  2024.         if (_.isEqual(buff_main, deck_main) && _.isEqual(buff_side, deck_side)) {
  2025.           deckbuf = deck_main.concat(deck_side);
  2026.           struct.set("mainc", deck_main.length);
  2027.           struct.set("sidec", deck_side.length);
  2028.           struct.set("deckbuf", deckbuf);
  2029.           buffer = struct.buffer;
  2030.           ygopro.stoc_send_chat(client, "${deck_correct_part1} " + found_deck + " ${deck_correct_part2}", ygopro.constants.COLORS.BABYBLUE);
  2031.         } else {
  2032.           ygopro.stoc_send_chat(client, "${deck_incorrect_part1} " + found_deck + " ${deck_incorrect_part2}", ygopro.constants.COLORS.RED);
  2033.         }
  2034.       } else {
  2035.         ygopro.stoc_send_chat(client, client.name + "${deck_not_found}", ygopro.constants.COLORS.RED);
  2036.       }
  2037.     }
  2038.     return false;
  2039.   });
  2040.  
  2041.   ygopro.ctos_follow('RESPONSE', false, function(buffer, info, client, server) {
  2042.     var room;
  2043.     room = ROOM_all[client.rid];
  2044.     if (!(room && (room.random_type || room.arena))) {
  2045.       return;
  2046.     }
  2047.     room.last_active_time = moment();
  2048.   });
  2049.  
  2050.   ygopro.ctos_follow('HAND_RESULT', false, function(buffer, info, client, server) {
  2051.     var room;
  2052.     room = ROOM_all[client.rid];
  2053.     if (!(room && room.random_type)) {
  2054.       return;
  2055.     }
  2056.     if (client.is_host) {
  2057.       room.waiting_for_player = room.waiting_for_player2;
  2058.     }
  2059.     room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
  2060.   });
  2061.  
  2062.   ygopro.ctos_follow('TP_RESULT', false, function(buffer, info, client, server) {
  2063.     var room;
  2064.     room = ROOM_all[client.rid];
  2065.     if (!(room && room.random_type)) {
  2066.       return;
  2067.     }
  2068.     room.last_active_time = moment();
  2069.   });
  2070.  
  2071.   ygopro.stoc_follow('SELECT_HAND', false, function(buffer, info, client, server) {
  2072.     var room;
  2073.     room = ROOM_all[client.rid];
  2074.     if (!(room && room.random_type)) {
  2075.       return;
  2076.     }
  2077.     if (client.is_host) {
  2078.       room.waiting_for_player = client;
  2079.     } else {
  2080.       room.waiting_for_player2 = client;
  2081.     }
  2082.     room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
  2083.   });
  2084.  
  2085.   ygopro.stoc_follow('SELECT_TP', false, function(buffer, info, client, server) {
  2086.     var room;
  2087.     room = ROOM_all[client.rid];
  2088.     if (!room) {
  2089.       return;
  2090.     }
  2091.     room.changing_side = false;
  2092.     if (room.random_type) {
  2093.       room.waiting_for_player = client;
  2094.       room.last_active_time = moment();
  2095.     }
  2096.   });
  2097.  
  2098.   ygopro.stoc_follow('CHANGE_SIDE', false, function(buffer, info, client, server) {
  2099.     var room;
  2100.     room = ROOM_all[client.rid];
  2101.     if (!room) {
  2102.       return;
  2103.     }
  2104.     room.changing_side = true;
  2105.     if (room.random_type || room.arena) {
  2106.       if (client.is_host) {
  2107.         room.waiting_for_player = client;
  2108.       } else {
  2109.         room.waiting_for_player2 = client;
  2110.       }
  2111.       room.last_active_time = moment();
  2112.     }
  2113.   });
  2114.  
  2115.   ygopro.stoc_follow('REPLAY', true, function(buffer, info, client, server) {
  2116.     var duellog, dueltime, i, j, len, player, ref, replay_filename, room;
  2117.     room = ROOM_all[client.rid];
  2118.     if (!room) {
  2119.       return settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe;
  2120.     }
  2121.     if (settings.modules.cloud_replay.enabled && room.random_type) {
  2122.       Cloud_replay_ids.push(room.cloud_replay_id);
  2123.     }
  2124.     if (settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe) {
  2125.       if (client.is_host) {
  2126.         dueltime = moment().format('YYYY-MM-DD HH:mm:ss');
  2127.         replay_filename = dueltime;
  2128.         ref = room.dueling_players;
  2129.         for (i = j = 0, len = ref.length; j < len; i = ++j) {
  2130.           player = ref[i];
  2131.           replay_filename = replay_filename + (i > 0 ? " VS " : " ") + player.name;
  2132.         }
  2133.         replay_filename = replay_filename.replace(/[\/\\\?\*]/g, '_') + ".yrp";
  2134.         duellog = {
  2135.           time: dueltime,
  2136.           name: room.name,
  2137.           roomid: room.port.toString(),
  2138.           cloud_replay_id: "R#" + room.cloud_replay_id,
  2139.           replay_filename: replay_filename,
  2140.           players: (function() {
  2141.             var k, len1, ref1, results;
  2142.             ref1 = room.dueling_players;
  2143.             results = [];
  2144.             for (k = 0, len1 = ref1.length; k < len1; k++) {
  2145.               player = ref1[k];
  2146.               results.push({
  2147.                 name: player.name,
  2148.                 winner: player.pos === room.winner
  2149.               });
  2150.             }
  2151.             return results;
  2152.           })()
  2153.         };
  2154.         settings.modules.tournament_mode.duel_log.unshift(duellog);
  2155.         nconf.myset(settings, "modules:tournament_mode:duel_log", settings.modules.tournament_mode.duel_log);
  2156.         fs.writeFile(settings.modules.tournament_mode.replay_path + replay_filename, buffer, function(err) {
  2157.           if (err) {
  2158.             return log.warn("SAVE REPLAY ERROR", replay_filename, err);
  2159.           }
  2160.         });
  2161.       }
  2162.       if (settings.modules.cloud_replay.enabled) {
  2163.         ygopro.stoc_send_chat(client, "${cloud_replay_delay_part1}R#" + room.cloud_replay_id + "${cloud_replay_delay_part2}", ygopro.constants.COLORS.BABYBLUE);
  2164.       }
  2165.       return true;
  2166.     } else {
  2167.       return false;
  2168.     }
  2169.   });
  2170.  
  2171.   if (settings.modules.random_duel.enabled) {
  2172.     setInterval(function() {
  2173.       var j, len, room, time_passed;
  2174.       for (j = 0, len = ROOM_all.length; j < len; j++) {
  2175.         room = ROOM_all[j];
  2176.         if (!(room && room.started && room.random_type && room.last_active_time && room.waiting_for_player)) {
  2177.           continue;
  2178.         }
  2179.         time_passed = Math.floor((moment() - room.last_active_time) / 1000);
  2180.         if (time_passed >= settings.modules.random_duel.hang_timeout) {
  2181.           room.last_active_time = moment();
  2182.           ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}");
  2183.           ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
  2184.           room.waiting_for_player.server.destroy();
  2185.         } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
  2186.           ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${afk_warn_part1}" + (settings.modules.random_duel.hang_timeout - time_passed) + "${afk_warn_part2}", ygopro.constants.COLORS.RED);
  2187.           ROOM_unwelcome(room, room.waiting_for_player, "${random_ban_reason_AFK}");
  2188.         }
  2189.       }
  2190.     }, 1000);
  2191.   }
  2192.  
  2193.   if (settings.modules.mycard.enabled) {
  2194.     setInterval(function() {
  2195.       var j, len, room, time_passed;
  2196.       for (j = 0, len = ROOM_all.length; j < len; j++) {
  2197.         room = ROOM_all[j];
  2198.         if (!(room && room.started && room.arena && room.changing_side && room.last_active_time && room.waiting_for_player)) {
  2199.           continue;
  2200.         }
  2201.         time_passed = Math.floor((moment() - room.last_active_time) / 1000);
  2202.         if (time_passed >= settings.modules.random_duel.hang_timeout) {
  2203.           room.last_active_time = moment();
  2204.           ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
  2205.           room.scores[room.waiting_for_player.name] = -1;
  2206.           room.waiting_for_player.server.destroy();
  2207.         } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
  2208.           ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${afk_warn_part1}" + (settings.modules.random_duel.hang_timeout - time_passed) + "${afk_warn_part2}", ygopro.constants.COLORS.RED);
  2209.         }
  2210.       }
  2211.     }, 1000);
  2212.   }
  2213.  
  2214.   if (settings.modules.windbot.spawn) {
  2215.     windbot_process = spawn('WindBot.exe', [settings.modules.windbot.port], {
  2216.       cwd: 'windbot'
  2217.     });
  2218.     windbot_process.on('error', function(err) {
  2219.       write('WindBot ERROR '+ err);
  2220.       log.warn('WindBot ERROR', err);
  2221.     });
  2222.     windbot_process.on('exit', function(code) {
  2223.       log.warn('WindBot EXIT', code);
  2224.     });
  2225.     windbot_process.stdout.setEncoding('utf8');
  2226.     windbot_process.stdout.on('data', function(data) {
  2227.       log.info('WindBot:', data);
  2228.     });
  2229.     windbot_process.stderr.setEncoding('utf8');
  2230.     windbot_process.stderr.on('data', function(data) {
  2231.       write("Windbot Error: " + data);
  2232.       log.warn('WindBot Error:', data);
  2233.     });
  2234.   }
  2235.  
  2236.   if (settings.modules.http) {
  2237.     addCallback = function(callback, text) {
  2238.       if (!callback) {
  2239.         return text;
  2240.       }
  2241.       return callback + "( " + text + " );";
  2242.     };
  2243.     requestListener = function(request, response) {
  2244.       var duellog, filename, getpath, j, len, parseQueryString, pass_validated, player, room, roomsjson, u;
  2245.       parseQueryString = true;
  2246.       u = url.parse(request.url, parseQueryString);
  2247.       pass_validated = u.query.pass === settings.modules.http.password;
  2248.       if (u.pathname === '/api/getrooms') {
  2249.         if (!pass_validated && !settings.modules.http.public_roomlist) {
  2250.           response.writeHead(200);
  2251.           response.end(addCallback(u.query.callback, '{"rooms":[{"roomid":"0","roomname":"密码错误","needpass":"true"}]}'));
  2252.         } else {
  2253.           response.writeHead(200);
  2254.           roomsjson = JSON.stringify({
  2255.             rooms: (function() {
  2256.               var j, len, results;
  2257.               results = [];
  2258.               for (j = 0, len = ROOM_all.length; j < len; j++) {
  2259.                 room = ROOM_all[j];
  2260.                 if (room && room.established) {
  2261.                   results.push({
  2262.                     pid: room.process.pid.toString(),
  2263.                     roomid: room.port.toString(),
  2264.                     roomname: pass_validated ? room.name : room.name.split('$', 2)[0],
  2265.                     needpass: (room.name.indexOf('$') !== -1).toString(),
  2266.                     users: (function() {
  2267.                       var k, len1, ref, results1;
  2268.                       ref = room.players;
  2269.                       results1 = [];
  2270.                       for (k = 0, len1 = ref.length; k < len1; k++) {
  2271.                         player = ref[k];
  2272.                         if (player.pos != null) {
  2273.                           results1.push({
  2274.                             id: (-1).toString(),
  2275.                             name: player.name,
  2276.                             pos: player.pos
  2277.                           });
  2278.                         }
  2279.                       }
  2280.                       return results1;
  2281.                     })(),
  2282.                     istart: room.started ? 'start' : 'wait'
  2283.                   });
  2284.                 }
  2285.               }
  2286.               return results;
  2287.             })()
  2288.           }, null, 2);
  2289.           response.end(addCallback(u.query.callback, roomsjson));
  2290.         }
  2291.       } else if (u.pathname === '/api/duellog' && settings.modules.tournament_mode.enabled) {
  2292.         if (!(u.query.pass === settings.modules.tournament_mode.password)) {
  2293.           response.writeHead(200);
  2294.           response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"));
  2295.           return;
  2296.         } else {
  2297.           response.writeHead(200);
  2298.           duellog = JSON.stringify(settings.modules.tournament_mode.duel_log, null, 2);
  2299.           response.end(addCallback(u.query.callback, duellog));
  2300.         }
  2301.       } else if (_.startsWith(u.pathname, '/api/replay') && settings.modules.tournament_mode.enabled) {
  2302.         if (!(u.query.pass === settings.modules.tournament_mode.password)) {
  2303.           response.writeHead(403);
  2304.           response.end("密码错误");
  2305.           return;
  2306.         } else {
  2307.           getpath = u.pathname.split("/");
  2308.           filename = decodeURIComponent(getpath.pop());
  2309.           fs.readFile(settings.modules.tournament_mode.replay_path + filename, function(error, buffer) {
  2310.             if (error) {
  2311.               response.writeHead(404);
  2312.               return response.end("未找到文件 " + filename);
  2313.             } else {
  2314.               response.writeHead(200, {
  2315.                 "Content-Type": "application/octet-stream",
  2316.                 "Content-Disposition": "attachment"
  2317.               });
  2318.               return response.end(buffer);
  2319.             }
  2320.           });
  2321.         }
  2322.       } else if (u.pathname === '/api/message') {
  2323.         if (!pass_validated) {
  2324.           response.writeHead(200);
  2325.           response.end(addCallback(u.query.callback, "['密码错误', 0]"));
  2326.           return;
  2327.         }
  2328.         if (u.query.shout) {
  2329.           for (j = 0, len = ROOM_all.length; j < len; j++) {
  2330.             room = ROOM_all[j];
  2331.             if (room && room.established) {
  2332.               ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW);
  2333.             }
  2334.           }
  2335.           response.writeHead(200);
  2336.           response.end(addCallback(u.query.callback, "['shout ok', '" + u.query.shout + "']"));
  2337.         } else if (u.query.stop) {
  2338.           if (u.query.stop === 'false') {
  2339.             u.query.stop = false;
  2340.           }
  2341.           settings.modules.stop = u.query.stop;
  2342.           response.writeHead(200);
  2343.           response.end(addCallback(u.query.callback, "['stop ok', '" + u.query.stop + "']"));
  2344.         } else if (u.query.welcome) {
  2345.           nconf.myset(settings, 'modules:welcome', u.query.welcome);
  2346.           response.writeHead(200);
  2347.           response.end(addCallback(u.query.callback, "['welcome ok', '" + u.query.welcome + "']"));
  2348.         } else if (u.query.getwelcome) {
  2349.           response.writeHead(200);
  2350.           response.end(addCallback(u.query.callback, "['get ok', '" + settings.modules.welcome + "']"));
  2351.         } else if (u.query.loadtips) {
  2352.           load_tips();
  2353.           response.writeHead(200);
  2354.           response.end(addCallback(u.query.callback, "['loading tip', '" + settings.modules.tips.get + "']"));
  2355.         } else if (u.query.loaddialogues) {
  2356.           load_dialogues();
  2357.           response.writeHead(200);
  2358.           response.end(addCallback(u.query.callback, "['loading dialogues', '" + settings.modules.dialogues.get + "']"));
  2359.         } else if (u.query.ban) {
  2360.           ban_user(u.query.ban);
  2361.           response.writeHead(200);
  2362.           response.end(addCallback(u.query.callback, "['ban ok', '" + u.query.ban + "']"));
  2363.         } else {
  2364.           response.writeHead(400);
  2365.           response.end();
  2366.         }
  2367.       } else {
  2368.         response.writeHead(400);
  2369.         response.end();
  2370.       }
  2371.     };
  2372.     http_server = http.createServer(requestListener);
  2373.     http_server.listen(settings.modules.http.port);
  2374.     if (settings.modules.http.ssl.enabled) {
  2375.       https = require('https');
  2376.       options = {
  2377.         cert: fs.readFileSync(settings.modules.http.ssl.cert),
  2378.         key: fs.readFileSync(settings.modules.http.ssl.key)
  2379.       };
  2380.       https_server = https.createServer(options, requestListener);
  2381.       roomlist.init(https_server, ROOM_all);
  2382.       https_server.listen(settings.modules.http.ssl.port);
  2383.     }
  2384.   }
  2385.  
  2386. }
  2387.  
  2388. exports = module.exports = server
Add Comment
Please, Sign In to add comment