ygopro-server.js 186 KB
Newer Older
mercury233's avatar
mercury233 committed
1
// Generated by CoffeeScript 1.12.7
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2
(function() {
Yuzurisa's avatar
Yuzurisa committed
3
  var CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, Cloud_replay_ids, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, 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_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_banned, ROOM_players_oppentlist, ROOM_players_scores, ROOM_unwelcome, ROOM_validate, Room, SERVER_clear_disconnect, SOCKET_flush_data, _, addCallback, auth, badwords, ban_user, bunyan, challonge, challonge_cache, challonge_module_name, challonge_queue_callbacks, chat_color, config, cppversion, crypto, date, deck_name_match, default_config, default_data, dialogues, disconnect_list, dns, duel_log, e, exec, execFile, fs, geoip, get_callback, get_memory_usage, http, http_server, https, https_server, import_datas, imported, is_requesting, j, l, len, len1, len2, lflists, list, loadJSON, load_dialogues, load_tips, log, long_resolve_cards, m, memory_usage, merge, moment, net, oldbadwords, oldconfig, olddialogues, oldduellog, oldtips, options, os, path, pgClient, pg_client, pg_query, plugin_filename, plugin_list, plugin_path, real_windbot_server_ip, rebooted, redis, redisdb, ref, ref1, refresh_challonge_cache, release_disconnect, report_to_big_brother, request, requestListener, roomlist, setting_change, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, url, users_cache, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, ygopro, zlib;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
4

神楽坂玲奈's avatar
神楽坂玲奈 committed
5
  net = require('net');
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
6

神楽坂玲奈's avatar
神楽坂玲奈 committed
7 8 9
  http = require('http');

  url = require('url');
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
10

神楽坂玲奈's avatar
神楽坂玲奈 committed
11 12 13 14
  path = require('path');

  fs = require('fs');

mercury233's avatar
mercury233 committed
15 16
  os = require('os');

17 18
  crypto = require('crypto');

mercury233's avatar
mercury233 committed
19 20
  exec = require('child_process').exec;

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
21 22
  execFile = require('child_process').execFile;

mercury233's avatar
mercury233 committed
23 24 25 26
  spawn = require('child_process').spawn;

  spawnSync = require('child_process').spawnSync;

nanahira's avatar
nanahira committed
27
  _ = global._ = require('underscore');
神楽坂玲奈's avatar
神楽坂玲奈 committed
28

神楽坂玲奈's avatar
tip  
神楽坂玲奈 committed
29 30 31 32 33 34
  _.str = require('underscore.string');

  _.mixin(_.str.exports());

  request = require('request');

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
35 36
  bunyan = require('bunyan');

nanahira's avatar
nanahira committed
37
  log = global.log = bunyan.createLogger({
mercury233's avatar
mercury233 committed
38 39 40
    name: "mycard"
  });

nanahira's avatar
nanahira committed
41
  moment = global.moment = require('moment');
42

mercury233's avatar
mercury233 committed
43
  moment.updateLocale('zh-cn', {
mercury233's avatar
mercury233 committed
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
    relativeTime: {
      future: '%s内',
      past: '%s前',
      s: '%d秒',
      m: '1分钟',
      mm: '%d分钟',
      h: '1小时',
      hh: '%d小时',
      d: '1天',
      dd: '%d天',
      M: '1个月',
      MM: '%d个月',
      y: '1年',
      yy: '%d年'
    }
  });

nanahira's avatar
nanahira committed
61
  import_datas = global.import_datas = ["abuse_count", "ban_mc", "vpass", "rag", "rid", "is_post_watcher", "retry_count", "name", "pass", "name_vpass", "is_first", "lp", "card_count", "is_host", "pos", "surrend_confirm", "kick_count", "deck_saved", "main", "side", "side_interval", "side_tcount", "selected_preduel", "last_game_msg", "last_game_msg_title", "last_hint_msg", "start_deckbuf", "challonge_info", "ready_trap", "join_time", "arena_quit_free", "replays_sent"];
nanahira's avatar
nanahira committed
62

mercury233's avatar
mercury233 committed
63 64
  merge = require('deepmerge');

mercury233's avatar
mercury233 committed
65 66
  loadJSON = require('load-json-file').sync;

mercury233's avatar
mercury233 committed
67 68 69 70
  if (!fs.existsSync('./config')) {
    fs.mkdirSync('./config');
  }

mercury233's avatar
mercury233 committed
71
  try {
mercury233's avatar
mercury233 committed
72
    oldconfig = loadJSON('./config.user.json');
mercury233's avatar
mercury233 committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86
    if (oldconfig.tips) {
      oldtips = {};
      oldtips.file = './config/tips.json';
      oldtips.tips = oldconfig.tips;
      fs.writeFileSync(oldtips.file, JSON.stringify(oldtips, null, 2));
      delete oldconfig.tips;
    }
    if (oldconfig.dialogues) {
      olddialogues = {};
      olddialogues.file = './config/dialogues.json';
      olddialogues.dialogues = oldconfig.dialogues;
      fs.writeFileSync(olddialogues.file, JSON.stringify(olddialogues, null, 2));
      delete oldconfig.dialogues;
    }
mercury233's avatar
fix  
mercury233 committed
87 88 89 90 91 92 93 94
    if (oldconfig.modules) {
      if (oldconfig.modules.tournament_mode && oldconfig.modules.tournament_mode.duel_log) {
        oldduellog = {};
        oldduellog.file = './config/duel_log.json';
        oldduellog.duel_log = oldconfig.modules.tournament_mode.duel_log;
        fs.writeFileSync(oldduellog.file, JSON.stringify(oldduellog, null, 2));
        delete oldconfig.oldduellog;
      }
95
    }
mercury233's avatar
mercury233 committed
96
    oldbadwords = {};
mercury233's avatar
fix  
mercury233 committed
97 98 99 100 101 102 103 104 105 106 107 108 109
    if (oldconfig.ban) {
      if (oldconfig.ban.badword_level0) {
        oldbadwords.level0 = oldconfig.ban.badword_level0;
      }
      if (oldconfig.ban.badword_level1) {
        oldbadwords.level1 = oldconfig.ban.badword_level1;
      }
      if (oldconfig.ban.badword_level2) {
        oldbadwords.level2 = oldconfig.ban.badword_level2;
      }
      if (oldconfig.ban.badword_level3) {
        oldbadwords.level3 = oldconfig.ban.badword_level3;
      }
mercury233's avatar
mercury233 committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    }
    if (!_.isEmpty(oldbadwords)) {
      oldbadwords.file = './config/badwords.json';
      fs.writeFileSync(oldbadwords.file, JSON.stringify(oldbadwords, null, 2));
      delete oldconfig.ban.badword_level0;
      delete oldconfig.ban.badword_level1;
      delete oldconfig.ban.badword_level2;
      delete oldconfig.ban.badword_level3;
    }
    if (!_.isEmpty(oldconfig)) {
      fs.writeFileSync('./config/config.json', JSON.stringify(oldconfig, null, 2));
      log.info('imported old config from config.user.json');
    }
    fs.renameSync('./config.user.json', './config.user.bak');
  } catch (error1) {
    e = error1;
mercury233's avatar
mercury233 committed
126
    if (e.code !== 'ENOENT') {
mercury233's avatar
mercury233 committed
127 128 129
      log.info(e);
    }
  }
mercury233's avatar
mercury233 committed
130

nanahira's avatar
nanahira committed
131
  setting_save = global.setting_save = function(settings) {
mercury233's avatar
mercury233 committed
132 133
    fs.writeFileSync(settings.file, JSON.stringify(settings, null, 2));
  };
mercury233's avatar
mercury233 committed
134

nanahira's avatar
nanahira committed
135
  setting_change = global.setting_change = function(settings, path, val) {
mercury233's avatar
mercury233 committed
136
    var key, target;
mercury233's avatar
mercury233 committed
137 138 139
    if (_.isString(val)) {
      log.info("setting changed", path, val);
    }
mercury233's avatar
mercury233 committed
140 141 142 143 144 145 146 147 148 149 150 151
    path = path.split(':');
    if (path.length === 0) {
      settings[path[0]] = val;
    } else {
      target = settings;
      while (path.length > 1) {
        key = path.shift();
        target = target[key];
      }
      key = path.shift();
      target[key] = val;
    }
mercury233's avatar
mercury233 committed
152
    setting_save(settings);
mercury233's avatar
mercury233 committed
153
  };
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
154

mercury233's avatar
mercury233 committed
155
  default_config = loadJSON('./data/default_config.json');
mercury233's avatar
mercury233 committed
156 157

  try {
mercury233's avatar
mercury233 committed
158
    config = loadJSON('./config/config.json');
mercury233's avatar
mercury233 committed
159 160 161 162 163 164 165 166 167 168
  } catch (error1) {
    config = {};
  }

  settings = global.settings = merge(default_config, config, {
    arrayMerge: function(destination, source) {
      return source;
    }
  });

nanahira's avatar
nanahira committed
169
  auth = global.auth = require('./ygopro-auth.js');
nanahira's avatar
nanahira committed
170

nanahira's avatar
nanahira committed
171 172
  imported = false;

nanahira's avatar
nanahira committed
173 174
  if (settings.modules.http.quick_death_rule === true) {
    settings.modules.http.quick_death_rule = 1;
nanahira's avatar
nanahira committed
175 176 177 178 179 180 181 182 183
    imported = true;
  }

  if (settings.modules.cloud_replay.redis_port) {
    settings.modules.cloud_replay.redis.port = settings.modules.cloud_replay.redis_port;
    delete settings.modules.cloud_replay.redis_port;
    imported = true;
  }

nanahira's avatar
nanahira committed
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
  if (settings.modules.http.password) {
    auth.add_user("olduser", settings.modules.http.password, true, {
      "get_rooms": true,
      "shout": true,
      "stop": true,
      "change_settings": true,
      "ban_user": true,
      "kick_user": true,
      "start_death": true
    });
    delete settings.modules.http.password;
    imported = true;
  }

  if (settings.modules.tournament_mode.password) {
    auth.add_user("tournament", settings.modules.tournament_mode.password, true, {
      "duel_log": true,
      "download_replay": true,
      "clear_duel_log": true,
nanahira's avatar
fix  
nanahira committed
203
      "deck_dashboard_read": true,
nanahira's avatar
nanahira committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
      "deck_dashboard_write": true
    });
    delete settings.modules.tournament_mode.password;
    imported = true;
  }

  if (settings.modules.pre_util.password) {
    auth.add_user("pre", settings.modules.pre_util.password, true, {
      "pre_dashboard": true
    });
    delete settings.modules.pre_util.password;
    imported = true;
  }

  if (settings.modules.update_util.password) {
    auth.add_user("update", settings.modules.update_util.password, true, {
      "update_dashboard": true
    });
    delete settings.modules.update_util.password;
    imported = true;
  }

226 227 228 229 230 231 232 233 234 235
  if (settings.hostinfo.enable_priority || settings.hostinfo.enable_priority === false) {
    if (settings.hostinfo.enable_priority) {
      settings.hostinfo.duel_rule = 3;
    } else {
      settings.hostinfo.duel_rule = 4;
    }
    delete settings.hostinfo.enable_priority;
    imported = true;
  }

236 237 238 239 240 241
  if (settings.modules.challonge.api_key) {
    settings.modules.challonge.options.apiKey = settings.modules.challonge.api_key;
    delete settings.modules.challonge.api_key;
    imported = true;
  }

nanahira's avatar
nanahira committed
242
  if (imported) {
nanahira's avatar
nanahira committed
243 244 245
    setting_save(settings);
  }

mercury233's avatar
mercury233 committed
246
  default_data = loadJSON('./data/default_data.json');
mercury233's avatar
mercury233 committed
247 248

  try {
nanahira's avatar
nanahira committed
249
    tips = global.tips = loadJSON('./config/tips.json');
mercury233's avatar
mercury233 committed
250
  } catch (error1) {
nanahira's avatar
nanahira committed
251
    tips = global.tips = default_data.tips;
mercury233's avatar
mercury233 committed
252 253 254 255
    setting_save(tips);
  }

  try {
nanahira's avatar
nanahira committed
256
    dialogues = global.dialogues = loadJSON('./config/dialogues.json');
mercury233's avatar
mercury233 committed
257
  } catch (error1) {
nanahira's avatar
nanahira committed
258
    dialogues = global.dialogues = default_data.dialogues;
mercury233's avatar
mercury233 committed
259 260 261 262
    setting_save(dialogues);
  }

  try {
nanahira's avatar
nanahira committed
263
    badwords = global.badwords = loadJSON('./config/badwords.json');
mercury233's avatar
mercury233 committed
264
  } catch (error1) {
nanahira's avatar
nanahira committed
265
    badwords = global.badwords = default_data.badwords;
mercury233's avatar
mercury233 committed
266 267 268
    setting_save(badwords);
  }

269
  try {
nanahira's avatar
nanahira committed
270
    duel_log = global.duel_log = loadJSON('./config/duel_log.json');
271
  } catch (error1) {
nanahira's avatar
nanahira committed
272
    duel_log = global.duel_log = default_data.duel_log;
273 274 275
    setting_save(duel_log);
  }

nanahira's avatar
nanahira committed
276
  try {
nanahira's avatar
nanahira committed
277
    chat_color = global.chat_color = loadJSON('./config/chat_color.json');
nanahira's avatar
nanahira committed
278
  } catch (error1) {
nanahira's avatar
nanahira committed
279
    chat_color = global.chat_color = default_data.chat_color;
nanahira's avatar
nanahira committed
280 281 282
    setting_save(chat_color);
  }

283
  try {
mercury233's avatar
mercury233 committed
284
    cppversion = parseInt(fs.readFileSync('ygopro/gframe/game.cpp', 'utf8').match(/PRO_VERSION = ([x\dABCDEF]+)/)[1], '16');
mercury233's avatar
mercury233 committed
285
    setting_change(settings, "version", cppversion);
mercury233's avatar
fix  
mercury233 committed
286
    log.info("ygopro version 0x" + settings.version.toString(16), "(from source code)");
287
  } catch (error1) {
mercury233's avatar
fix  
mercury233 committed
288
    log.info("ygopro version 0x" + settings.version.toString(16), "(from config)");
289
  }
290

nanahira's avatar
nanahira committed
291
  lflists = global.lflists = [];
nanahira's avatar
nanahira committed
292 293 294

  try {
    ref = fs.readFileSync('ygopro/expansions/lflist.conf', 'utf8').match(/!.*/g);
mercury233's avatar
mercury233 committed
295 296
    for (j = 0, len = ref.length; j < len; j++) {
      list = ref[j];
mercury233's avatar
mercury233 committed
297 298 299 300
      date = list.match(/!([\d\.]+)/);
      if (!date) {
        continue;
      }
nanahira's avatar
nanahira committed
301
      lflists.push({
神楽坂玲奈's avatar
神楽坂玲奈 committed
302
        date: moment(list.match(/!([\d\.]+)/)[1], 'YYYY.MM.DD').utcOffset("-08:00"),
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
303
        tcg: list.indexOf('TCG') !== -1
神楽坂玲奈's avatar
神楽坂玲奈 committed
304 305
      });
    }
nanahira's avatar
nanahira committed
306 307 308 309 310 311
  } catch (error1) {

  }

  try {
    ref1 = fs.readFileSync('ygopro/lflist.conf', 'utf8').match(/!.*/g);
nanahira's avatar
nanahira committed
312 313
    for (l = 0, len1 = ref1.length; l < len1; l++) {
      list = ref1[l];
nanahira's avatar
nanahira committed
314 315 316 317 318 319 320 321 322 323 324 325
      date = list.match(/!([\d\.]+)/);
      if (!date) {
        continue;
      }
      lflists.push({
        date: moment(list.match(/!([\d\.]+)/)[1], 'YYYY.MM.DD').utcOffset("-08:00"),
        tcg: list.indexOf('TCG') !== -1
      });
    }
  } catch (error1) {

  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
326

mercury233's avatar
mercury233 committed
327
  if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
328 329
    redis = require('redis');
    zlib = require('zlib');
nanahira's avatar
nanahira committed
330
    redisdb = global.redisdb = redis.createClient(settings.modules.cloud_replay.redis);
mercury233's avatar
mercury233 committed
331 332 333
    redisdb.on('error', function(err) {
      log.warn(err);
    });
mercury233's avatar
mercury233 committed
334 335
  }

mercury233's avatar
mercury233 committed
336
  if (settings.modules.windbot.enabled) {
nanahira's avatar
nanahira committed
337
    windbots = global.windbots = loadJSON(settings.modules.windbot.botlist).windbots;
nanahira's avatar
fix  
nanahira committed
338
    real_windbot_server_ip = global.real_windbot_server_ip = settings.modules.windbot.server_ip;
nanahira's avatar
nanahira committed
339 340 341 342
    if (!settings.modules.windbot.server_ip.includes("127.0.0.1")) {
      dns = require('dns');
      dns.lookup(settings.modules.windbot.server_ip, function(err, addr) {
        if (!err) {
nanahira's avatar
fix  
nanahira committed
343
          return real_windbot_server_ip = global.real_windbot_server_ip = addr;
nanahira's avatar
nanahira committed
344 345 346
        }
      });
    }
mercury233's avatar
mercury233 committed
347 348
  }

nanahira's avatar
nanahira committed
349
  if (settings.modules.heartbeat_detection.enabled) {
nanahira's avatar
nanahira committed
350
    long_resolve_cards = global.long_resolve_cards = loadJSON('./data/long_resolve_cards.json');
nanahira's avatar
nanahira committed
351 352
  }

nanahira's avatar
nanahira committed
353
  ygopro = global.ygopro = require('./ygopro.js');
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
354

mercury233's avatar
mercury233 committed
355
  if (settings.modules.http.websocket_roomlist) {
nanahira's avatar
nanahira committed
356
    roomlist = global.roomlist = require('./roomlist.js');
mercury233's avatar
mercury233 committed
357
  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
358

mercury233's avatar
mercury233 committed
359 360 361 362
  if (settings.modules.i18n.auto_pick) {
    geoip = require('geoip-country-lite');
  }

神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
363 364
  users_cache = {};

mercury233's avatar
mercury233 committed
365
  if (settings.modules.mycard.enabled) {
mercury233's avatar
merge  
mercury233 committed
366
    pgClient = require('pg').Client;
nanahira's avatar
nanahira committed
367
    pg_client = global.pg_client = new pgClient(settings.modules.mycard.auth_database);
mercury233's avatar
fix  
mercury233 committed
368 369 370
    pg_client.on('error', function(err) {
      log.warn("PostgreSQL ERROR: ", err);
    });
mercury233's avatar
merge  
mercury233 committed
371
    pg_query = pg_client.query('SELECT username, id from users');
mercury233's avatar
fix  
mercury233 committed
372 373 374
    pg_query.on('error', function(err) {
      log.warn("PostgreSQL Query ERROR: ", err);
    });
mercury233's avatar
merge  
mercury233 committed
375 376 377 378 379 380 381 382 383
    pg_query.on('row', function(row) {
      users_cache[row.username] = row.id;
    });
    pg_query.on('end', function(result) {
      log.info("users loaded", result.rowCount);
    });
    pg_client.on('drain', pg_client.end.bind(pg_client));
    log.info("loading mycard user...");
    pg_client.connect();
nanahira's avatar
nanahira committed
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    if (settings.modules.arena_mode.enabled && settings.modules.arena_mode.init_post.enabled) {
      request.post({
        url: settings.modules.arena_mode.init_post.url,
        qs: {
          ak: settings.modules.arena_mode.init_post.accesskey,
          arena: settings.modules.arena_mode.mode
        }
      }, (function(_this) {
        return function(error, response, body) {
          if (error) {
            log.warn('ARENA INIT POST ERROR', error);
          } else {
            if (response.statusCode >= 400) {
              log.warn('ARENA INIT POST FAIL', response.statusCode, response.statusMessage, body);
            }
          }
        };
      })(this));
    }
mercury233's avatar
merge  
mercury233 committed
403 404
  }

nanahira's avatar
nanahira committed
405
  if (settings.modules.challonge.enabled) {
406 407 408 409
    challonge_module_name = 'challonge';
    if (settings.modules.challonge.use_custom_module) {
      challonge_module_name = settings.modules.challonge.use_custom_module;
    }
nanahira's avatar
nanahira committed
410
    challonge = global.challonge = require(challonge_module_name).createClient(settings.modules.challonge.options);
nanahira's avatar
nanahira committed
411 412 413
    if (settings.modules.challonge.cache_ttl) {
      challonge_cache = [];
    }
nanahira's avatar
nanahira committed
414
    challonge_queue_callbacks = [[], []];
nanahira's avatar
nanahira committed
415
    is_requesting = [null, null];
nanahira's avatar
nanahira committed
416 417 418
    get_callback = function(challonge_type, _callback) {
      return (function(err, data) {
        var cur_callback;
nanahira's avatar
nanahira committed
419
        if (settings.modules.challonge.cache_ttl && !err && data) {
nanahira's avatar
nanahira committed
420 421
          challonge_cache[challonge_type] = data;
        }
nanahira's avatar
nanahira committed
422
        is_requesting[challonge_type] = null;
nanahira's avatar
nanahira committed
423 424
        _callback(err, data);
        while (challonge_queue_callbacks[challonge_type].length) {
nanahira's avatar
fix  
nanahira committed
425
          cur_callback = challonge_queue_callbacks[challonge_type].splice(0, 1)[0];
nanahira's avatar
nanahira committed
426 427 428 429 430
          cur_callback(err, data);
        }
      });
    };
    challonge.participants._index = function(_data) {
nanahira's avatar
js  
nanahira committed
431
      var err;
nanahira's avatar
nanahira committed
432
      if (settings.modules.challonge.cache_ttl && challonge_cache[0]) {
nanahira's avatar
nanahira committed
433
        _data.callback(null, challonge_cache[0]);
nanahira's avatar
nanahira committed
434
      } else if (is_requesting[0] && moment() - is_requesting[0] <= 5000) {
nanahira's avatar
nanahira committed
435 436 437
        challonge_queue_callbacks[0].push(_data.callback);
      } else {
        _data.callback = get_callback(0, _data.callback);
nanahira's avatar
nanahira committed
438
        is_requesting[0] = moment();
nanahira's avatar
js  
nanahira committed
439 440 441 442 443 444
        try {
          challonge.participants.index(_data);
        } catch (error1) {
          err = error1;
          _data.callback(err, null);
        }
nanahira's avatar
nanahira committed
445 446 447
      }
    };
    challonge.matches._index = function(_data) {
nanahira's avatar
js  
nanahira committed
448
      var err;
nanahira's avatar
nanahira committed
449
      if (settings.modules.challonge.cache_ttl && challonge_cache[1]) {
nanahira's avatar
nanahira committed
450
        _data.callback(null, challonge_cache[1]);
nanahira's avatar
nanahira committed
451
      } else if (is_requesting[1] && moment() - is_requesting[1] <= 5000) {
nanahira's avatar
nanahira committed
452 453 454
        challonge_queue_callbacks[1].push(_data.callback);
      } else {
        _data.callback = get_callback(1, _data.callback);
nanahira's avatar
nanahira committed
455
        is_requesting[1] = moment();
nanahira's avatar
js  
nanahira committed
456 457 458 459 460 461
        try {
          challonge.matches.index(_data);
        } catch (error1) {
          err = error1;
          _data.callback(err, null);
        }
nanahira's avatar
nanahira committed
462 463
      }
    };
nanahira's avatar
nanahira committed
464 465 466 467 468 469 470 471 472
    challonge.matches._update = function(_data) {
      var err;
      try {
        challonge.matches.update(_data);
      } catch (error1) {
        err = error1;
        log.warn("Errored pushing scores to Challonge.", err);
      }
    };
nanahira's avatar
nanahira committed
473
    refresh_challonge_cache = global.refresh_challonge_cache = function() {
nanahira's avatar
nanahira committed
474 475 476 477
      if (settings.modules.challonge.cache_ttl) {
        challonge_cache[0] = null;
        challonge_cache[1] = null;
      }
nanahira's avatar
nanahira committed
478 479
    };
    refresh_challonge_cache();
nanahira's avatar
nanahira committed
480 481 482
    if (settings.modules.challonge.cache_ttl) {
      setInterval(refresh_challonge_cache, settings.modules.challonge.cache_ttl);
    }
nanahira's avatar
nanahira committed
483 484
  }

nanahira's avatar
nanahira committed
485
  memory_usage = global.memory_usage = 0;
mercury233's avatar
mercury233 committed
486

nanahira's avatar
nanahira committed
487
  get_memory_usage = get_memory_usage = function() {
mercury233's avatar
mercury233 committed
488 489
    var prc_free;
    prc_free = exec("free");
mercury233's avatar
fix  
mercury233 committed
490
    prc_free.stdout.on('data', function(data) {
mercury233's avatar
mercury233 committed
491 492 493 494
      var actualFree, buffers, cached, free, line, lines, new_free, percentUsed, total;
      lines = data.toString().split(/\n/g);
      line = lines[0].split(/\s+/);
      new_free = line[6] === 'available' ? true : false;
mercury233's avatar
mercury233 committed
495 496 497 498
      line = lines[1].split(/\s+/);
      total = parseInt(line[1], 10);
      free = parseInt(line[3], 10);
      buffers = parseInt(line[5], 10);
mercury233's avatar
mercury233 committed
499 500 501 502 503 504
      if (new_free) {
        actualFree = parseInt(line[6], 10);
      } else {
        cached = parseInt(line[6], 10);
        actualFree = free + buffers + cached;
      }
mercury233's avatar
mercury233 committed
505
      percentUsed = parseFloat(((1 - (actualFree / total)) * 100).toFixed(2));
nanahira's avatar
nanahira committed
506
      memory_usage = global.memory_usage = percentUsed;
mercury233's avatar
mercury233 committed
507
    });
mercury233's avatar
mercury233 committed
508 509
  };

mercury233's avatar
mercury233 committed
510 511 512 513
  get_memory_usage();

  setInterval(get_memory_usage, 3000);

nanahira's avatar
nanahira committed
514
  Cloud_replay_ids = global.Cloud_replay_ids = [];
mercury233's avatar
mercury233 committed
515

nanahira's avatar
nanahira committed
516
  ROOM_all = global.ROOM_all = [];
mercury233's avatar
mercury233 committed
517

nanahira's avatar
nanahira committed
518
  ROOM_players_oppentlist = global.ROOM_players_oppentlist = {};
mercury233's avatar
mercury233 committed
519

nanahira's avatar
nanahira committed
520
  ROOM_players_banned = global.ROOM_players_banned = [];
mercury233's avatar
mercury233 committed
521

nanahira's avatar
nanahira committed
522
  ROOM_players_scores = global.ROOM_players_scores = {};
523

nanahira's avatar
nanahira committed
524
  ROOM_connected_ip = global.ROOM_connected_ip = {};
mercury233's avatar
mercury233 committed
525

nanahira's avatar
nanahira committed
526
  ROOM_bad_ip = global.ROOM_bad_ip = {};
mercury233's avatar
mercury233 committed
527

nanahira's avatar
nanahira committed
528
  ban_user = global.ban_user = function(name) {
nanahira's avatar
nanahira committed
529
    var bad_ip, len2, len3, m, n, player, ref2, room;
mercury233's avatar
mercury233 committed
530
    settings.ban.banned_user.push(name);
mercury233's avatar
mercury233 committed
531
    setting_save(settings);
mercury233's avatar
mercury233 committed
532
    bad_ip = 0;
nanahira's avatar
nanahira committed
533 534
    for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
      room = ROOM_all[m];
mercury233's avatar
mercury233 committed
535
      if (room && room.established) {
nanahira's avatar
nanahira committed
536
        ref2 = room.players;
nanahira's avatar
nanahira committed
537 538
        for (n = 0, len3 = ref2.length; n < len3; n++) {
          player = ref2[n];
mercury233's avatar
mercury233 committed
539 540 541 542 543
          if (player && (player.name === name || player.ip === bad_ip)) {
            bad_ip = player.ip;
            ROOM_bad_ip[bad_ip] = 99;
            settings.ban.banned_ip.push(player.ip);
            ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
544
            CLIENT_send_replays(player, room);
nanahira's avatar
nanahira committed
545
            CLIENT_kick(player);
mercury233's avatar
mercury233 committed
546 547 548 549 550 551 552
            continue;
          }
        }
      }
    }
  };

nanahira's avatar
nanahira committed
553
  ROOM_ban_player = global.ROOM_ban_player = function(name, ip, reason, countadd) {
mercury233's avatar
mercury233 committed
554
    var bannedplayer, bantime;
mercury233's avatar
mercury233 committed
555 556 557
    if (countadd == null) {
      countadd = 1;
    }
558 559 560
    if (settings.modules.test_mode.no_ban_player) {
      return;
    }
mercury233's avatar
mercury233 committed
561 562 563 564
    bannedplayer = _.find(ROOM_players_banned, function(bannedplayer) {
      return ip === bannedplayer.ip;
    });
    if (bannedplayer) {
mercury233's avatar
mercury233 committed
565
      bannedplayer.count = bannedplayer.count + countadd;
mercury233's avatar
mercury233 committed
566 567 568 569 570 571 572 573 574 575 576 577
      bantime = bannedplayer.count > 3 ? Math.pow(2, bannedplayer.count - 3) * 2 : 0;
      bannedplayer.time = moment() < bannedplayer.time ? moment(bannedplayer.time).add(bantime, 'm') : moment().add(bantime, 'm');
      if (!_.find(bannedplayer.reasons, function(bannedreason) {
        return bannedreason === reason;
      })) {
        bannedplayer.reasons.push(reason);
      }
      bannedplayer.need_tip = true;
    } else {
      bannedplayer = {
        "ip": ip,
        "time": moment(),
mercury233's avatar
mercury233 committed
578
        "count": countadd,
mercury233's avatar
mercury233 committed
579 580 581 582 583 584 585
        "reasons": [reason],
        "need_tip": true
      };
      ROOM_players_banned.push(bannedplayer);
    }
  };

nanahira's avatar
nanahira committed
586
  ROOM_player_win = global.ROOM_player_win = function(name) {
587 588 589 590 591 592 593 594 595 596 597 598
    if (!ROOM_players_scores[name]) {
      ROOM_players_scores[name] = {
        win: 0,
        lose: 0,
        flee: 0,
        combo: 0
      };
    }
    ROOM_players_scores[name].win = ROOM_players_scores[name].win + 1;
    ROOM_players_scores[name].combo = ROOM_players_scores[name].combo + 1;
  };

nanahira's avatar
nanahira committed
599
  ROOM_player_lose = global.ROOM_player_lose = function(name) {
600 601 602 603 604 605 606 607 608 609 610 611
    if (!ROOM_players_scores[name]) {
      ROOM_players_scores[name] = {
        win: 0,
        lose: 0,
        flee: 0,
        combo: 0
      };
    }
    ROOM_players_scores[name].lose = ROOM_players_scores[name].lose + 1;
    ROOM_players_scores[name].combo = 0;
  };

nanahira's avatar
nanahira committed
612
  ROOM_player_flee = global.ROOM_player_flee = function(name) {
613 614 615 616 617 618 619 620 621 622 623 624
    if (!ROOM_players_scores[name]) {
      ROOM_players_scores[name] = {
        win: 0,
        lose: 0,
        flee: 0,
        combo: 0
      };
    }
    ROOM_players_scores[name].flee = ROOM_players_scores[name].flee + 1;
    ROOM_players_scores[name].combo = 0;
  };

nanahira's avatar
nanahira committed
625
  ROOM_player_get_score = global.ROOM_player_get_score = function(player) {
626 627 628 629 630 631
    var name, score, total;
    name = player.name_vpass;
    score = ROOM_players_scores[name];
    if (!score) {
      return player.name + " ${random_score_blank}";
    }
mercury233's avatar
mercury233 committed
632
    total = score.win + score.lose;
633 634 635 636 637 638 639 640 641 642
    if (score.win < 2 && total < 3) {
      return player.name + " ${random_score_not_enough}";
    }
    if (score.combo >= 2) {
      return "${random_score_part1}" + player.name + " ${random_score_part2} " + (Math.ceil(score.win / total * 100)) + "${random_score_part3} " + (Math.ceil(score.flee / total * 100)) + "${random_score_part4_combo}" + score.combo + "${random_score_part5_combo}";
    } else {
      return "${random_score_part1}" + player.name + " ${random_score_part2} " + (Math.ceil(score.win / total * 100)) + "${random_score_part3} " + (Math.ceil(score.flee / total * 100)) + "${random_score_part4}";
    }
  };

mercury233's avatar
mercury233 committed
643 644
  if (settings.modules.random_duel.post_match_scores) {
    setInterval(function() {
mercury233's avatar
mercury233 committed
645 646 647 648 649 650
      var scores, scores_by_lose, scores_by_win, scores_pair;
      scores_pair = _.pairs(ROOM_players_scores);
      scores_by_lose = _.sortBy(scores_pair, function(score) {
        return score[1].lose;
      }).reverse();
      scores_by_win = _.sortBy(scores_by_lose, function(score) {
mercury233's avatar
mercury233 committed
651
        return score[1].win;
mercury233's avatar
mercury233 committed
652 653
      }).reverse();
      scores = _.first(scores_by_win, 10);
mercury233's avatar
mercury233 committed
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
      request.post({
        url: settings.modules.random_duel.post_match_scores,
        form: {
          accesskey: settings.modules.random_duel.post_match_accesskey,
          rank: JSON.stringify(scores)
        }
      }, (function(_this) {
        return function(error, response, body) {
          if (error) {
            log.warn('RANDOM SCORE POST ERROR', error);
          } else {
            if (response.statusCode !== 204 && response.statusCode !== 200) {
              log.warn('RANDOM SCORE POST FAIL', response.statusCode, response.statusMessage, body);
            }
          }
        };
      })(this));
    }, 60000);
  }

nanahira's avatar
nanahira committed
674
  ROOM_find_or_create_by_name = global.ROOM_find_or_create_by_name = function(name, player_ip) {
mercury233's avatar
mercury233 committed
675 676
    var room, uname;
    uname = name.toUpperCase();
mercury233's avatar
mercury233 committed
677
    if (settings.modules.windbot.enabled && (uname.slice(0, 2) === 'AI' || (!settings.modules.random_duel.enabled && uname === ''))) {
mercury233's avatar
mercury233 committed
678 679
      return ROOM_find_or_create_ai(name);
    }
mercury233's avatar
mercury233 committed
680
    if (settings.modules.random_duel.enabled && (uname === '' || uname === 'S' || uname === 'M' || uname === 'T')) {
mercury233's avatar
mercury233 committed
681
      return ROOM_find_or_create_random(uname, player_ip);
mercury233's avatar
mercury233 committed
682 683 684
    }
    if (room = ROOM_find_by_name(name)) {
      return room;
mercury233's avatar
mercury233 committed
685
    } else if (memory_usage >= 90) {
mercury233's avatar
mercury233 committed
686 687 688 689 690 691
      return null;
    } else {
      return new Room(name);
    }
  };

nanahira's avatar
nanahira committed
692
  ROOM_find_or_create_random = global.ROOM_find_or_create_random = function(type, player_ip) {
mercury233's avatar
mercury233 committed
693 694 695 696 697 698 699
    var bannedplayer, max_player, name, playerbanned, result;
    bannedplayer = _.find(ROOM_players_banned, function(bannedplayer) {
      return player_ip === bannedplayer.ip;
    });
    if (bannedplayer) {
      if (bannedplayer.count > 6 && moment() < bannedplayer.time) {
        return {
mercury233's avatar
mercury233 committed
700
          "error": "${random_banned_part1}" + (bannedplayer.reasons.join('${random_ban_reason_separator}')) + "${random_banned_part2}" + (moment(bannedplayer.time).fromNow(true)) + "${random_banned_part3}"
mercury233's avatar
mercury233 committed
701 702
        };
      }
mercury233's avatar
mercury233 committed
703
      if (bannedplayer.count > 3 && moment() < bannedplayer.time && bannedplayer.need_tip && type !== 'T') {
mercury233's avatar
mercury233 committed
704 705
        bannedplayer.need_tip = false;
        return {
mercury233's avatar
mercury233 committed
706
          "error": "${random_deprecated_part1}" + (bannedplayer.reasons.join('${random_ban_reason_separator}')) + "${random_deprecated_part2}" + (moment(bannedplayer.time).fromNow(true)) + "${random_deprecated_part3}"
mercury233's avatar
mercury233 committed
707 708 709 710
        };
      } else if (bannedplayer.need_tip) {
        bannedplayer.need_tip = false;
        return {
mercury233's avatar
mercury233 committed
711
          "error": "${random_warn_part1}" + (bannedplayer.reasons.join('${random_ban_reason_separator}')) + "${random_warn_part2}"
mercury233's avatar
mercury233 committed
712 713 714 715 716 717 718 719
        };
      } else if (bannedplayer.count > 2) {
        bannedplayer.need_tip = true;
      }
    }
    max_player = type === 'T' ? 4 : 2;
    playerbanned = bannedplayer && bannedplayer.count > 3 && moment() < bannedplayer.time;
    result = _.find(ROOM_all, function(room) {
nanahira's avatar
nanahira committed
720
      return room && room.random_type !== '' && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && !room.windbot && ((type === '' && (room.random_type === 'S' || (settings.modules.random_duel.blank_pass_match && room.random_type !== 'T'))) || room.random_type === type) && room.get_playing_player().length < max_player && (settings.modules.random_duel.no_rematch_check || room.get_host() === null || room.get_host().ip !== ROOM_players_oppentlist[player_ip]) && (playerbanned === room.deprecated || type === 'T');
mercury233's avatar
mercury233 committed
721 722
    });
    if (result) {
mercury233's avatar
mercury233 committed
723
      result.welcome = '${random_duel_enter_room_waiting}';
mercury233's avatar
mercury233 committed
724
    } else if (memory_usage < 90) {
mercury233's avatar
mercury233 committed
725 726 727 728 729
      type = type ? type : 'S';
      name = type + ',RANDOM#' + Math.floor(Math.random() * 100000);
      result = new Room(name);
      result.random_type = type;
      result.max_player = max_player;
mercury233's avatar
mercury233 committed
730
      result.welcome = '${random_duel_enter_room_new}';
mercury233's avatar
mercury233 committed
731
      result.deprecated = playerbanned;
mercury233's avatar
mercury233 committed
732 733
    } else {
      return null;
mercury233's avatar
mercury233 committed
734 735
    }
    if (result.random_type === 'M') {
mercury233's avatar
mercury233 committed
736
      result.welcome = result.welcome + '\n${random_duel_enter_room_match}';
mercury233's avatar
mercury233 committed
737 738 739 740
    }
    return result;
  };

nanahira's avatar
nanahira committed
741
  ROOM_find_or_create_ai = global.ROOM_find_or_create_ai = function(name) {
742
    var ainame, namea, result, room, uname, windbot;
mercury233's avatar
mercury233 committed
743 744 745
    if (name === '') {
      name = 'AI';
    }
mercury233's avatar
mercury233 committed
746
    namea = name.split('#');
747
    uname = name.toUpperCase();
mercury233's avatar
mercury233 committed
748 749
    if (room = ROOM_find_by_name(name)) {
      return room;
750
    } else if (uname === 'AI') {
mercury233's avatar
mercury233 committed
751
      windbot = _.sample(windbots);
mercury233's avatar
mercury233 committed
752
      name = 'AI#' + Math.floor(Math.random() * 100000);
mercury233's avatar
mercury233 committed
753 754
    } else if (namea.length > 1) {
      ainame = namea[namea.length - 1];
mercury233's avatar
mercury233 committed
755
      windbot = _.sample(_.filter(windbots, function(w) {
mercury233's avatar
mercury233 committed
756 757 758 759
        return w.name === ainame || w.deck === ainame;
      }));
      if (!windbot) {
        return {
mercury233's avatar
mercury233 committed
760
          "error": "${windbot_deck_not_found}"
mercury233's avatar
mercury233 committed
761 762 763 764
        };
      }
      name = name + ',' + Math.floor(Math.random() * 100000);
    } else {
mercury233's avatar
mercury233 committed
765
      windbot = _.sample(windbots);
mercury233's avatar
mercury233 committed
766 767
      name = name + '#' + Math.floor(Math.random() * 100000);
    }
mercury233's avatar
mercury233 committed
768 769 770
    if (name.replace(/[^\x00-\xff]/g, "00").length > 20) {
      log.info("long ai name", name);
      return {
mercury233's avatar
mercury233 committed
771
        "error": "${windbot_name_too_long}"
mercury233's avatar
mercury233 committed
772 773
      };
    }
mercury233's avatar
mercury233 committed
774 775
    result = new Room(name);
    result.windbot = windbot;
mercury233's avatar
merge  
mercury233 committed
776
    result["private"] = true;
mercury233's avatar
mercury233 committed
777 778 779
    return result;
  };

nanahira's avatar
nanahira committed
780
  ROOM_find_by_name = global.ROOM_find_by_name = function(name) {
mercury233's avatar
mercury233 committed
781 782
    var result;
    result = _.find(ROOM_all, function(room) {
783
      return room && room.name === name;
mercury233's avatar
mercury233 committed
784 785 786 787
    });
    return result;
  };

nanahira's avatar
nanahira committed
788
  ROOM_find_by_title = global.ROOM_find_by_title = function(title) {
mercury233's avatar
mercury233 committed
789 790 791 792 793 794 795
    var result;
    result = _.find(ROOM_all, function(room) {
      return room && room.title === title;
    });
    return result;
  };

nanahira's avatar
nanahira committed
796
  ROOM_find_by_port = global.ROOM_find_by_port = function(port) {
mercury233's avatar
mercury233 committed
797
    return _.find(ROOM_all, function(room) {
798
      return room && room.port === port;
mercury233's avatar
mercury233 committed
799 800 801
    });
  };

nanahira's avatar
nanahira committed
802 803 804 805 806 807
  ROOM_find_by_pid = global.ROOM_find_by_pid = function(pid) {
    return _.find(ROOM_all, function(room) {
      return room && room.process_pid === pid;
    });
  };

nanahira's avatar
nanahira committed
808
  ROOM_validate = global.ROOM_validate = function(name) {
mercury233's avatar
mercury233 committed
809 810 811 812 813 814 815 816 817
    var client_name, client_name_and_pass, client_pass;
    client_name_and_pass = name.split('$', 2);
    client_name = client_name_and_pass[0];
    client_pass = client_name_and_pass[1];
    if (!client_pass) {
      return true;
    }
    return !_.find(ROOM_all, function(room) {
      var room_name, room_name_and_pass, room_pass;
818 819 820
      if (!room) {
        return false;
      }
mercury233's avatar
mercury233 committed
821 822 823 824 825 826 827
      room_name_and_pass = room.name.split('$', 2);
      room_name = room_name_and_pass[0];
      room_pass = room_name_and_pass[1];
      return client_name === room_name && client_pass !== room_pass;
    });
  };

nanahira's avatar
nanahira committed
828
  ROOM_unwelcome = global.ROOM_unwelcome = function(room, bad_player, reason) {
nanahira's avatar
nanahira committed
829
    var len2, m, player, ref2;
mercury233's avatar
mercury233 committed
830 831 832
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
833
    ref2 = room.players;
nanahira's avatar
nanahira committed
834 835
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
mercury233's avatar
mercury233 committed
836 837 838 839 840 841 842 843 844
      if (player && player === bad_player) {
        ygopro.stoc_send_chat(player, "${unwelcome_warn_part1}" + reason + "${unwelcome_warn_part2}", ygopro.constants.COLORS.RED);
      } else if (player && player.pos !== 7 && player !== bad_player) {
        player.flee_free = true;
        ygopro.stoc_send_chat(player, "${unwelcome_tip_part1}" + reason + "${unwelcome_tip_part2}", ygopro.constants.COLORS.BABYBLUE);
      }
    }
  };

nanahira's avatar
nanahira committed
845
  CLIENT_kick = global.CLIENT_kick = function(client) {
nanahira's avatar
nanahira committed
846 847 848
    if (!client) {
      return false;
    }
nanahira's avatar
nanahira committed
849
    client.system_kicked = true;
nanahira's avatar
typo  
nanahira committed
850
    if (settings.modules.reconnect.enabled && client.closed) {
nanahira's avatar
fix  
nanahira committed
851 852 853
      if (client.server && !client.had_new_reconnection) {
        client.server.destroy();
      }
nanahira's avatar
nanahira committed
854 855 856
    } else {
      client.destroy();
    }
nanahira's avatar
nanahira committed
857
    return true;
nanahira's avatar
nanahira committed
858 859
  };

nanahira's avatar
nanahira committed
860
  release_disconnect = global.release_disconnect = function(dinfo, reconnected) {
nanahira's avatar
nanahira committed
861 862 863 864 865 866 867 868 869
    if (dinfo.old_client && !reconnected) {
      dinfo.old_client.destroy();
    }
    if (dinfo.old_server && !reconnected) {
      dinfo.old_server.destroy();
    }
    clearTimeout(dinfo.timeout);
  };

nanahira's avatar
nanahira committed
870
  CLIENT_get_authorize_key = global.CLIENT_get_authorize_key = function(client) {
nanahira's avatar
js  
nanahira committed
871
    if (!settings.modules.mycard.enabled && client.vpass) {
872
      return client.name_vpass;
nanahira's avatar
js  
nanahira committed
873 874
    } else if (settings.modules.mycard.enabled || settings.modules.tournament_mode.enabled || settings.modules.challonge.enabled || client.is_local) {
      return client.name;
nanahira's avatar
nanahira committed
875
    } else {
876
      return client.ip + ":" + client.name;
nanahira's avatar
nanahira committed
877 878 879
    }
  };

nanahira's avatar
nanahira committed
880
  CLIENT_reconnect_unregister = global.CLIENT_reconnect_unregister = function(client, reconnected, exact) {
nanahira's avatar
nanahira committed
881 882 883 884
    if (!settings.modules.reconnect.enabled) {
      return false;
    }
    if (disconnect_list[CLIENT_get_authorize_key(client)]) {
nanahira's avatar
nanahira committed
885 886 887
      if (exact && disconnect_list[CLIENT_get_authorize_key(client)].old_client !== client) {
        return false;
      }
nanahira's avatar
nanahira committed
888 889 890 891 892 893 894
      release_disconnect(disconnect_list[CLIENT_get_authorize_key(client)], reconnected);
      delete disconnect_list[CLIENT_get_authorize_key(client)];
      return true;
    }
    return false;
  };

nanahira's avatar
nanahira committed
895
  CLIENT_reconnect_register = global.CLIENT_reconnect_register = function(client, room_id, error) {
nanahira's avatar
nanahira committed
896
    var dinfo, room, tmot;
nanahira's avatar
nanahira committed
897
    room = ROOM_all[room_id];
nanahira's avatar
nanahira committed
898 899 900
    if (client.had_new_reconnection) {
      return false;
    }
nanahira's avatar
nanahira committed
901
    if (!settings.modules.reconnect.enabled || !room || client.system_kicked || client.flee_free || disconnect_list[CLIENT_get_authorize_key(client)] || client.is_post_watcher || !CLIENT_is_player(client, room) || room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || room.windbot || (settings.modules.reconnect.auto_surrender_after_disconnect && room.hostinfo.mode !== 1) || (room.random_type && room.get_disconnected_count() > 1)) {
nanahira's avatar
nanahira committed
902 903 904
      return false;
    }
    dinfo = {
nanahira's avatar
nanahira committed
905
      room_id: room_id,
nanahira's avatar
nanahira committed
906 907 908 909 910 911 912 913 914 915
      old_client: client,
      old_server: client.server,
      deckbuf: client.start_deckbuf
    };
    tmot = setTimeout(function() {
      room.disconnect(client, error);
      dinfo.old_server.destroy();
    }, settings.modules.reconnect.wait_time);
    dinfo.timeout = tmot;
    disconnect_list[CLIENT_get_authorize_key(client)] = dinfo;
nanahira's avatar
js  
nanahira committed
916
    ygopro.stoc_send_chat_to_room(room, (client.name + " ${disconnect_from_game}") + (error ? ": " + error : ''));
nanahira's avatar
nanahira committed
917 918 919 920
    if (client.time_confirm_required) {
      client.time_confirm_required = false;
      ygopro.ctos_send(client.server, 'TIME_CONFIRM');
    }
nanahira's avatar
nanahira committed
921
    if (settings.modules.reconnect.auto_surrender_after_disconnect && room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) {
922 923
      ygopro.ctos_send(client.server, 'SURRENDER');
    }
nanahira's avatar
nanahira committed
924 925 926
    return true;
  };

nanahira's avatar
nanahira committed
927
  CLIENT_import_data = global.CLIENT_import_data = function(client, old_client, room) {
nanahira's avatar
nanahira committed
928
    var index, key, len2, len3, m, n, player, ref2;
nanahira's avatar
nanahira committed
929 930 931 932 933 934 935 936 937
    ref2 = room.players;
    for (index = m = 0, len2 = ref2.length; m < len2; index = ++m) {
      player = ref2[index];
      if (player === old_client) {
        room.players[index] = client;
        break;
      }
    }
    room.dueling_players[old_client.pos] = client;
nanahira's avatar
nanahira committed
938
    if (room.waiting_for_player === old_client) {
nanahira's avatar
nanahira committed
939 940
      room.waiting_for_player = client;
    }
nanahira's avatar
nanahira committed
941
    if (room.waiting_for_player2 === old_client) {
nanahira's avatar
nanahira committed
942 943
      room.waiting_for_player2 = client;
    }
nanahira's avatar
nanahira committed
944
    if (room.selecting_tp === old_client) {
nanahira's avatar
nanahira committed
945 946
      room.selecting_tp = client;
    }
nanahira's avatar
nanahira committed
947 948 949 950
    for (n = 0, len3 = import_datas.length; n < len3; n++) {
      key = import_datas[n];
      client[key] = old_client[key];
    }
nanahira's avatar
nanahira committed
951 952 953
    old_client.had_new_reconnection = true;
  };

nanahira's avatar
nanahira committed
954
  SERVER_clear_disconnect = global.SERVER_clear_disconnect = function(server) {
nanahira's avatar
nanahira committed
955 956
    var k, v;
    if (!settings.modules.reconnect.enabled) {
nanahira's avatar
nanahira committed
957
      return false;
nanahira's avatar
nanahira committed
958 959 960 961 962 963
    }
    for (k in disconnect_list) {
      v = disconnect_list[k];
      if (v && server === v.old_server) {
        release_disconnect(v);
        delete disconnect_list[k];
nanahira's avatar
nanahira committed
964
        return true;
nanahira's avatar
nanahira committed
965 966
      }
    }
nanahira's avatar
nanahira committed
967 968 969
    return false;
  };

nanahira's avatar
nanahira committed
970
  ROOM_clear_disconnect = global.ROOM_clear_disconnect = function(room_id) {
nanahira's avatar
nanahira committed
971 972 973 974 975 976 977 978 979 980 981 982 983
    var k, v;
    if (!settings.modules.reconnect.enabled) {
      return false;
    }
    for (k in disconnect_list) {
      v = disconnect_list[k];
      if (v && room_id === v.room_id) {
        release_disconnect(v);
        delete disconnect_list[k];
        return true;
      }
    }
    return false;
nanahira's avatar
nanahira committed
984 985
  };

nanahira's avatar
nanahira committed
986
  CLIENT_is_player = global.CLIENT_is_player = function(client, room) {
nanahira's avatar
nanahira committed
987 988 989 990 991 992 993 994 995 996
    var is_player, len2, m, player, ref2;
    is_player = false;
    ref2 = room.players;
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
      if (client === player) {
        is_player = true;
        break;
      }
    }
nanahira's avatar
fix  
nanahira committed
997
    return is_player && client.pos <= 3;
nanahira's avatar
nanahira committed
998 999
  };

nanahira's avatar
nanahira committed
1000
  CLIENT_is_able_to_reconnect = global.CLIENT_is_able_to_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1001
    var disconnect_info, room;
nanahira's avatar
nanahira committed
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
    if (!settings.modules.reconnect.enabled) {
      return false;
    }
    if (client.system_kicked) {
      return false;
    }
    disconnect_info = disconnect_list[CLIENT_get_authorize_key(client)];
    if (!disconnect_info) {
      return false;
    }
nanahira's avatar
nanahira committed
1012 1013 1014 1015 1016
    room = ROOM_all[disconnect_info.room_id];
    if (!room) {
      CLIENT_reconnect_unregister(client);
      return false;
    }
nanahira's avatar
nanahira committed
1017 1018 1019 1020 1021 1022
    if (deckbuf && !_.isEqual(deckbuf, disconnect_info.deckbuf)) {
      return false;
    }
    return true;
  };

nanahira's avatar
nanahira committed
1023
  CLIENT_get_kick_reconnect_target = global.CLIENT_get_kick_reconnect_target = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1024 1025 1026
    var len2, len3, m, n, player, ref2, room;
    for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
      room = ROOM_all[m];
nanahira's avatar
nanahira committed
1027
      if (room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && !room.windbot) {
nanahira's avatar
nanahira committed
1028 1029 1030
        ref2 = room.get_playing_player();
        for (n = 0, len3 = ref2.length; n < len3; n++) {
          player = ref2[n];
1031
          if (!player.closed && player.name === client.name && (settings.modules.challonge.enabled || player.pass === client.pass) && (settings.modules.mycard.enabled || settings.modules.tournament_mode.enabled || player.ip === client.ip || (client.vpass && client.vpass === player.vpass)) && (!deckbuf || _.isEqual(player.start_deckbuf, deckbuf))) {
nanahira's avatar
nanahira committed
1032 1033 1034 1035 1036 1037 1038 1039
            return player;
          }
        }
      }
    }
    return null;
  };

nanahira's avatar
nanahira committed
1040
  CLIENT_is_able_to_kick_reconnect = global.CLIENT_is_able_to_kick_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1041 1042 1043 1044 1045 1046
    if (!(settings.modules.reconnect.enabled && settings.modules.reconnect.allow_kick_reconnect)) {
      return false;
    }
    if (!CLIENT_get_kick_reconnect_target(client, deckbuf)) {
      return false;
    }
nanahira's avatar
nanahira committed
1047 1048 1049
    return true;
  };

nanahira's avatar
nanahira committed
1050
  CLIENT_send_pre_reconnect_info = global.CLIENT_send_pre_reconnect_info = function(client, room, old_client) {
nanahira's avatar
nanahira committed
1051
    var len2, m, player, ref2, req_pos;
nanahira's avatar
nanahira committed
1052
    ygopro.stoc_send_chat(client, "${pre_reconnecting_to_room}", ygopro.constants.COLORS.BABYBLUE);
1053
    ygopro.stoc_send(client, 'JOIN_GAME', room.join_game_buffer);
nanahira's avatar
nanahira committed
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
    req_pos = old_client.pos;
    if (old_client.is_host) {
      req_pos += 0x10;
    }
    ygopro.stoc_send(client, 'TYPE_CHANGE', {
      type: req_pos
    });
    ref2 = room.players;
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
nanahira's avatar
nanahira committed
1064
      ygopro.stoc_send(client, 'HS_PLAYER_ENTER', {
nanahira's avatar
nanahira committed
1065 1066
        name: player.name,
        pos: player.pos
nanahira's avatar
nanahira committed
1067
      });
nanahira's avatar
nanahira committed
1068 1069 1070
    }
  };

nanahira's avatar
nanahira committed
1071
  CLIENT_send_reconnect_info = global.CLIENT_send_reconnect_info = function(client, server, room) {
nanahira's avatar
nanahira committed
1072 1073
    client.reconnecting = true;
    ygopro.stoc_send_chat(client, "${reconnecting_to_room}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
    switch (room.duel_stage) {
      case ygopro.constants.DUEL_STAGE.FINGER:
        ygopro.stoc_send(client, 'DUEL_START');
        if ((room.hostinfo.mode !== 2 || client.pos === 0 || client.pos === 2) && !client.selected_preduel) {
          ygopro.stoc_send(client, 'SELECT_HAND');
        }
        client.reconnecting = false;
        break;
      case ygopro.constants.DUEL_STAGE.FIRSTGO:
        ygopro.stoc_send(client, 'DUEL_START');
        if (client === room.selecting_tp) {
          ygopro.stoc_send(client, 'SELECT_TP');
        }
        client.reconnecting = false;
        break;
      case ygopro.constants.DUEL_STAGE.SIDING:
        ygopro.stoc_send(client, 'DUEL_START');
        if (!client.selected_preduel) {
          ygopro.stoc_send(client, 'CHANGE_SIDE');
        }
        client.reconnecting = false;
        break;
      default:
        ygopro.ctos_send(server, 'REQUEST_FIELD');
        break;
nanahira's avatar
nanahira committed
1099 1100 1101
    }
  };

nanahira's avatar
nanahira committed
1102
  CLIENT_pre_reconnect = global.CLIENT_pre_reconnect = function(client) {
nanahira's avatar
nanahira committed
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
    var dinfo, player;
    if (CLIENT_is_able_to_reconnect(client)) {
      dinfo = disconnect_list[CLIENT_get_authorize_key(client)];
      client.pre_reconnecting = true;
      client.pos = dinfo.old_client.pos;
      client.setTimeout(300000);
      CLIENT_send_pre_reconnect_info(client, ROOM_all[dinfo.room_id], dinfo.old_client);
    } else if (CLIENT_is_able_to_kick_reconnect(client)) {
      player = CLIENT_get_kick_reconnect_target(client);
      client.pre_reconnecting = true;
      client.pos = player.pos;
      client.setTimeout(300000);
      CLIENT_send_pre_reconnect_info(client, ROOM_all[player.rid], player);
nanahira's avatar
nanahira committed
1116 1117 1118
    }
  };

nanahira's avatar
nanahira committed
1119
  CLIENT_reconnect = global.CLIENT_reconnect = function(client) {
nanahira's avatar
nanahira committed
1120
    var current_old_server, dinfo, room;
nanahira's avatar
nanahira committed
1121 1122 1123 1124 1125 1126 1127
    if (!CLIENT_is_able_to_reconnect(client)) {
      ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
      CLIENT_kick(client);
      return;
    }
    client.pre_reconnecting = false;
    dinfo = disconnect_list[CLIENT_get_authorize_key(client)];
nanahira's avatar
nanahira committed
1128
    room = ROOM_all[dinfo.room_id];
nanahira's avatar
nanahira committed
1129 1130 1131 1132 1133 1134 1135 1136 1137
    current_old_server = client.server;
    client.server = dinfo.old_server;
    client.server.client = client;
    dinfo.old_client.server = null;
    current_old_server.client = null;
    current_old_server.had_new_reconnection = true;
    current_old_server.destroy();
    client.established = true;
    client.pre_establish_buffers = [];
nanahira's avatar
nanahira committed
1138 1139 1140
    if (room.random_type || room.arena) {
      room.last_active_time = moment();
    }
nanahira's avatar
nanahira committed
1141 1142
    CLIENT_import_data(client, dinfo.old_client, room);
    CLIENT_send_reconnect_info(client, client.server, room);
nanahira's avatar
js  
nanahira committed
1143
    ygopro.stoc_send_chat_to_room(room, client.name + " ${reconnect_to_game}");
nanahira's avatar
nanahira committed
1144 1145 1146
    CLIENT_reconnect_unregister(client, true);
  };

nanahira's avatar
nanahira committed
1147
  CLIENT_kick_reconnect = global.CLIENT_kick_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
    var current_old_server, player, room;
    if (!CLIENT_is_able_to_kick_reconnect(client)) {
      ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
      CLIENT_kick(client);
      return;
    }
    client.pre_reconnecting = false;
    player = CLIENT_get_kick_reconnect_target(client, deckbuf);
    room = ROOM_all[player.rid];
    current_old_server = client.server;
    client.server = player.server;
    client.server.client = client;
    ygopro.stoc_send_chat(player, "${reconnect_kicked}", ygopro.constants.COLORS.RED);
    player.server = null;
    player.had_new_reconnection = true;
    CLIENT_kick(player);
    current_old_server.client = null;
    current_old_server.had_new_reconnection = true;
    current_old_server.destroy();
    client.established = true;
    client.pre_establish_buffers = [];
    if (room.random_type || room.arena) {
      room.last_active_time = moment();
    }
    CLIENT_import_data(client, player, room);
    CLIENT_send_reconnect_info(client, client.server, room);
    ygopro.stoc_send_chat_to_room(room, client.name + " ${reconnect_to_game}");
    CLIENT_reconnect_unregister(client, true);
  };

nanahira's avatar
nanahira committed
1178 1179 1180 1181
  if (settings.modules.reconnect.enabled) {
    disconnect_list = {};
  }

nanahira's avatar
nanahira committed
1182
  CLIENT_heartbeat_unregister = global.CLIENT_heartbeat_unregister = function(client) {
nanahira's avatar
nanahira committed
1183 1184 1185 1186 1187 1188 1189 1190
    if (!settings.modules.heartbeat_detection.enabled || !client.heartbeat_timeout) {
      return false;
    }
    clearTimeout(client.heartbeat_timeout);
    delete client.heartbeat_timeout;
    return true;
  };

nanahira's avatar
nanahira committed
1191
  CLIENT_heartbeat_register = global.CLIENT_heartbeat_register = function(client, send) {
1192
    if (!settings.modules.heartbeat_detection.enabled || client.closed || client.is_post_watcher || client.pre_reconnecting || client.reconnecting || client.waiting_for_last || client.pos > 3 || client.heartbeat_protected) {
nanahira's avatar
nanahira committed
1193 1194 1195 1196 1197 1198 1199 1200
      return false;
    }
    if (client.heartbeat_timeout) {
      CLIENT_heartbeat_unregister(client);
    }
    client.heartbeat_responsed = false;
    if (send) {
      ygopro.stoc_send(client, "TIME_LIMIT", {
nanahira's avatar
nanahira committed
1201 1202 1203 1204 1205
        player: 0,
        left_time: 0
      });
      ygopro.stoc_send(client, "TIME_LIMIT", {
        player: 1,
nanahira's avatar
nanahira committed
1206 1207 1208 1209 1210 1211 1212 1213
        left_time: 0
      });
    }
    client.heartbeat_timeout = setTimeout(function() {
      CLIENT_heartbeat_unregister(client);
      if (!(client.closed || client.heartbeat_responsed)) {
        client.destroy();
      }
1214
    }, settings.modules.heartbeat_detection.wait_time);
nanahira's avatar
nanahira committed
1215 1216 1217
    return true;
  };

nanahira's avatar
nanahira committed
1218
  CLIENT_is_banned_by_mc = global.CLIENT_is_banned_by_mc = function(client) {
nanahira's avatar
nanahira committed
1219 1220 1221
    return client.ban_mc && client.ban_mc.banned && moment().isBefore(client.ban_mc.until);
  };

nanahira's avatar
nanahira committed
1222
  CLIENT_send_replays = global.CLIENT_send_replays = function(client, room) {
nanahira's avatar
nanahira committed
1223
    var buffer, i, len2, m, ref2;
nanahira's avatar
nanahira committed
1224
    if (!(settings.modules.replay_delay && !(settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe && settings.modules.tournament_mode.block_replay_to_player) && room.replays.length && room.hostinfo.mode === 1 && !client.replays_sent && !client.closed)) {
nanahira's avatar
nanahira committed
1225 1226
      return false;
    }
nanahira's avatar
nanahira committed
1227
    client.replays_sent = true;
nanahira's avatar
nanahira committed
1228 1229 1230 1231 1232
    i = 0;
    ref2 = room.replays;
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      buffer = ref2[m];
      ++i;
nanahira's avatar
fix  
nanahira committed
1233 1234 1235 1236
      if (buffer) {
        ygopro.stoc_send_chat(client, "${replay_hint_part1}" + i + "${replay_hint_part2}", ygopro.constants.COLORS.BABYBLUE);
        ygopro.stoc_send(client, "REPLAY", buffer);
      }
nanahira's avatar
nanahira committed
1237 1238 1239 1240
    }
    return true;
  };

nanahira's avatar
nanahira committed
1241
  SOCKET_flush_data = global.SOCKET_flush_data = function(sk, datas) {
1242
    var buffer, len2, m;
nanahira's avatar
js  
nanahira committed
1243 1244 1245
    if (!sk || sk.closed) {
      return false;
    }
1246 1247 1248 1249 1250
    for (m = 0, len2 = datas.length; m < len2; m++) {
      buffer = datas[m];
      sk.write(buffer);
    }
    datas.splice(0, datas.length);
nanahira's avatar
js  
nanahira committed
1251
    return true;
1252 1253
  };

mercury233's avatar
mercury233 committed
1254 1255
  Room = (function() {
    function Room(name, hostinfo) {
1256
      var death_time, draw_count, duel_rule, lflist, param, rule, start_hand, start_lp, time_limit;
mercury233's avatar
mercury233 committed
1257 1258 1259 1260 1261 1262 1263 1264
      this.hostinfo = hostinfo;
      this.name = name;
      this.players = [];
      this.player_datas = [];
      this.status = 'starting';
      this.established = false;
      this.watcher_buffers = [];
      this.recorder_buffers = [];
1265
      this.cloud_replay_id = Math.floor(Math.random() * 100000000);
mercury233's avatar
mercury233 committed
1266 1267 1268
      this.watchers = [];
      this.random_type = '';
      this.welcome = '';
mercury233's avatar
mercury233 committed
1269
      this.scores = {};
nanahira's avatar
nanahira committed
1270
      this.decks = {};
1271
      this.duel_count = 0;
nanahira's avatar
nanahira committed
1272
      this.death = 0;
nanahira's avatar
nanahira committed
1273
      this.turn = 0;
nanahira's avatar
nanahira committed
1274
      this.duel_stage = ygopro.constants.DUEL_STAGE.BEGIN;
nanahira's avatar
nanahira committed
1275
      this.replays = [];
nanahira's avatar
nanahira committed
1276
      this.first_list = [];
mercury233's avatar
mercury233 committed
1277
      ROOM_all.push(this);
mercury233's avatar
fix  
mercury233 committed
1278
      this.hostinfo || (this.hostinfo = JSON.parse(JSON.stringify(settings.hostinfo)));
nanahira's avatar
nanahira committed
1279
      delete this.hostinfo.comment;
mercury233's avatar
mercury233 committed
1280
      if (lflists.length) {
1281
        if (this.hostinfo.rule === 1 && this.hostinfo.lflist === 0) {
mercury233's avatar
mercury233 committed
1282
          this.hostinfo.lflist = _.findIndex(lflists, function(list) {
1283 1284 1285 1286 1287 1288
            return list.tcg;
          });
        }
      } else {
        this.hostinfo.lflist = -1;
      }
mercury233's avatar
mercury233 committed
1289 1290 1291 1292 1293
      if (name.slice(0, 2) === 'M#') {
        this.hostinfo.mode = 1;
      } else if (name.slice(0, 2) === 'T#') {
        this.hostinfo.mode = 2;
        this.hostinfo.start_lp = 16000;
mercury233's avatar
mercury233 committed
1294 1295 1296
      } else if (name.slice(0, 3) === 'AI#') {
        this.hostinfo.rule = 2;
        this.hostinfo.lflist = -1;
mercury233's avatar
mercury233 committed
1297
        this.hostinfo.time_limit = 999;
mercury233's avatar
mercury233 committed
1298 1299 1300
      } else if ((param = name.match(/^(\d)(\d)(T|F)(T|F)(T|F)(\d+),(\d+),(\d+)/i))) {
        this.hostinfo.rule = parseInt(param[1]);
        this.hostinfo.mode = parseInt(param[2]);
1301
        this.hostinfo.duel_rule = (param[3] === 'T' ? 3 : 4);
mercury233's avatar
mercury233 committed
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
        this.hostinfo.no_check_deck = param[4] === 'T';
        this.hostinfo.no_shuffle_deck = param[5] === 'T';
        this.hostinfo.start_lp = parseInt(param[6]);
        this.hostinfo.start_hand = parseInt(param[7]);
        this.hostinfo.draw_count = parseInt(param[8]);
      } else if ((param = name.match(/(.+)#/)) !== null) {
        rule = param[1].toUpperCase();
        if (rule.match(/(^|,|,)(M|MATCH)(,|,|$)/)) {
          this.hostinfo.mode = 1;
        }
        if (rule.match(/(^|,|,)(T|TAG)(,|,|$)/)) {
          this.hostinfo.mode = 2;
          this.hostinfo.start_lp = 16000;
        }
        if (rule.match(/(^|,|,)(TCGONLY|TO)(,|,|$)/)) {
          this.hostinfo.rule = 1;
mercury233's avatar
mercury233 committed
1318
          this.hostinfo.lflist = _.findIndex(lflists, function(list) {
mercury233's avatar
mercury233 committed
1319
            return list.tcg;
mercury233's avatar
mercury233 committed
1320 1321 1322 1323
          });
        }
        if (rule.match(/(^|,|,)(OCGONLY|OO)(,|,|$)/)) {
          this.hostinfo.rule = 0;
1324
          this.hostinfo.lflist = 0;
mercury233's avatar
mercury233 committed
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385
        }
        if (rule.match(/(^|,|,)(OT|TCG)(,|,|$)/)) {
          this.hostinfo.rule = 2;
        }
        if ((param = rule.match(/(^|,|,)LP(\d+)(,|,|$)/))) {
          start_lp = parseInt(param[2]);
          if (start_lp <= 0) {
            start_lp = 1;
          }
          if (start_lp >= 99999) {
            start_lp = 99999;
          }
          this.hostinfo.start_lp = start_lp;
        }
        if ((param = rule.match(/(^|,|,)(TIME|TM|TI)(\d+)(,|,|$)/))) {
          time_limit = parseInt(param[3]);
          if (time_limit < 0) {
            time_limit = 180;
          }
          if (time_limit >= 1 && time_limit <= 60) {
            time_limit = time_limit * 60;
          }
          if (time_limit >= 999) {
            time_limit = 999;
          }
          this.hostinfo.time_limit = time_limit;
        }
        if ((param = rule.match(/(^|,|,)(START|ST)(\d+)(,|,|$)/))) {
          start_hand = parseInt(param[3]);
          if (start_hand <= 0) {
            start_hand = 1;
          }
          if (start_hand >= 40) {
            start_hand = 40;
          }
          this.hostinfo.start_hand = start_hand;
        }
        if ((param = rule.match(/(^|,|,)(DRAW|DR)(\d+)(,|,|$)/))) {
          draw_count = parseInt(param[3]);
          if (draw_count >= 35) {
            draw_count = 35;
          }
          this.hostinfo.draw_count = draw_count;
        }
        if ((param = rule.match(/(^|,|,)(LFLIST|LF)(\d+)(,|,|$)/))) {
          lflist = parseInt(param[3]) - 1;
          this.hostinfo.lflist = lflist;
        }
        if (rule.match(/(^|,|,)(NOLFLIST|NF)(,|,|$)/)) {
          this.hostinfo.lflist = -1;
        }
        if (rule.match(/(^|,|,)(NOUNIQUE|NU)(,|,|$)/)) {
          this.hostinfo.rule = 3;
        }
        if (rule.match(/(^|,|,)(NOCHECK|NC)(,|,|$)/)) {
          this.hostinfo.no_check_deck = true;
        }
        if (rule.match(/(^|,|,)(NOSHUFFLE|NS)(,|,|$)/)) {
          this.hostinfo.no_shuffle_deck = true;
        }
        if (rule.match(/(^|,|,)(IGPRIORITY|PR)(,|,|$)/)) {
1386 1387 1388 1389 1390 1391 1392
          this.hostinfo.duel_rule = 3;
        }
        if ((param = rule.match(/(^|,|,)(DUELRULE|MR)(\d+)(,|,|$)/))) {
          duel_rule = parseInt(param[3]);
          if (duel_rule && duel_rule > 0 && duel_rule <= 4) {
            this.hostinfo.duel_rule = duel_rule;
          }
mercury233's avatar
mercury233 committed
1393
        }
nanahira's avatar
nanahira committed
1394
        if (rule.match(/(^|,|,)(NOWATCH|NW)(,|,|$)/)) {
nanahira's avatar
nanahira committed
1395
          this.hostinfo.no_watch = true;
nanahira's avatar
nanahira committed
1396
        }
nanahira's avatar
nanahira committed
1397 1398 1399 1400 1401 1402 1403 1404
        if ((param = rule.match(/(^|,|,)(DEATH|DH)(\d*)(,|,|$)/))) {
          death_time = parseInt(param[3]);
          if (death_time && death_time > 0) {
            this.hostinfo.auto_death = death_time;
          } else {
            this.hostinfo.auto_death = 40;
          }
        }
mercury233's avatar
mercury233 committed
1405
      }
1406 1407 1408 1409 1410 1411 1412
      this.hostinfo.replay_mode = 0;
      if (settings.modules.tournament_mode.enabled) {
        this.hostinfo.replay_mode |= 0x1;
      }
      if ((settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe) || (this.hostinfo.mode === 1 && settings.modules.replay_delay)) {
        this.hostinfo.replay_mode |= 0x2;
      }
1413
      param = [0, this.hostinfo.lflist, this.hostinfo.rule, this.hostinfo.mode, this.hostinfo.duel_rule, (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];
mercury233's avatar
mercury233 committed
1414 1415
      try {
        this.process = spawn('./ygopro', param, {
mercury233's avatar
mercury233 committed
1416
          cwd: 'ygopro'
mercury233's avatar
mercury233 committed
1417
        });
nanahira's avatar
nanahira committed
1418
        this.process_pid = this.process.pid;
mercury233's avatar
fix  
mercury233 committed
1419 1420 1421
        this.process.on('error', (function(_this) {
          return function(err) {
            _.each(_this.players, function(player) {
mercury233's avatar
mercury233 committed
1422
              return ygopro.stoc_die(player, "${create_room_failed}");
mercury233's avatar
fix  
mercury233 committed
1423 1424 1425 1426
            });
            _this["delete"]();
          };
        })(this));
mercury233's avatar
mercury233 committed
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
        this.process.on('exit', (function(_this) {
          return function(code) {
            if (!_this.disconnector) {
              _this.disconnector = 'server';
            }
            _this["delete"]();
          };
        })(this));
        this.process.stdout.setEncoding('utf8');
        this.process.stdout.once('data', (function(_this) {
          return function(data) {
            _this.established = true;
mercury233's avatar
mercury233 committed
1439
            if (!_this.windbot && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1440 1441 1442 1443 1444
              roomlist.create(_this);
            }
            _this.port = parseInt(data);
            _.each(_this.players, function(player) {
              player.server.connect(_this.port, '127.0.0.1', function() {
nanahira's avatar
nanahira committed
1445
                var buffer, len2, m, ref2;
nanahira's avatar
nanahira committed
1446
                ref2 = player.pre_establish_buffers;
nanahira's avatar
nanahira committed
1447 1448
                for (m = 0, len2 = ref2.length; m < len2; m++) {
                  buffer = ref2[m];
mercury233's avatar
mercury233 committed
1449 1450 1451 1452 1453 1454 1455
                  player.server.write(buffer);
                }
                player.established = true;
                player.pre_establish_buffers = [];
              });
            });
            if (_this.windbot) {
mercury233's avatar
mercury233 committed
1456 1457 1458
              setTimeout(function() {
                return _this.add_windbot(_this.windbot);
              }, 200);
mercury233's avatar
mercury233 committed
1459 1460 1461
            }
          };
        })(this));
mercury233's avatar
mercury233 committed
1462 1463
        this.process.stderr.on('data', (function(_this) {
          return function(data) {
mercury233's avatar
mercury233 committed
1464 1465 1466 1467
            data = "Debug: " + data;
            data = data.replace(/\n$/, "");
            log.info("YGOPRO " + data);
            ygopro.stoc_send_chat_to_room(_this, data, ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1468
            _this.has_ygopro_error = true;
1469 1470
            _this.ygopro_error_length = _this.ygopro_error_length ? _this.ygopro_error_length + data.length : data.length;
            if (_this.ygopro_error_length > 10000) {
nanahira's avatar
nanahira committed
1471
              _this.send_replays();
1472 1473
              _this.process.kill();
            }
mercury233's avatar
mercury233 committed
1474 1475
          };
        })(this));
mercury233's avatar
mercury233 committed
1476
      } catch (error1) {
mercury233's avatar
mercury233 committed
1477
        this.error = "${create_room_failed}";
mercury233's avatar
mercury233 committed
1478 1479 1480 1481
      }
    }

    Room.prototype["delete"] = function() {
nanahira's avatar
fix  
nanahira committed
1482
      var end_time, formatted_replays, index, len2, log_rep_id, m, name, player_ips, player_names, recorder_buffer, ref2, ref3, repbuf, replay_id, room_name, score, score_array, score_form;
mercury233's avatar
mercury233 committed
1483 1484 1485
      if (this.deleted) {
        return;
      }
1486
      score_array = [];
nanahira's avatar
nanahira committed
1487 1488 1489
      ref2 = this.scores;
      for (name in ref2) {
        score = ref2[name];
nanahira's avatar
nanahira committed
1490
        score_form = {
1491
          name: name.split('$')[0],
nanahira's avatar
nanahira committed
1492
          score: score,
1493 1494
          deck: null,
          name_vpass: name
nanahira's avatar
nanahira committed
1495 1496 1497 1498 1499
        };
        if (this.decks[name]) {
          score_form.deck = this.decks[name];
        }
        score_array.push(score_form);
1500
      }
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
      if (settings.modules.random_duel.record_match_scores && this.random_type === 'M') {
        if (score_array.length === 2) {
          if (score_array[0].score !== score_array[1].score) {
            if (score_array[0].score > score_array[1].score) {
              ROOM_player_win(score_array[0].name_vpass);
              ROOM_player_lose(score_array[1].name_vpass);
            } else {
              ROOM_player_win(score_array[1].name_vpass);
              ROOM_player_lose(score_array[0].name_vpass);
            }
          }
        }
        if (score_array.length === 1) {
          ROOM_player_win(score_array[0].name_vpass);
          ROOM_player_lose(score_array[0].name_vpass);
        }
      }
nanahira's avatar
-5  
nanahira committed
1518 1519 1520 1521 1522 1523 1524 1525
      if (settings.modules.arena_mode.enabled && this.arena) {
        end_time = moment().format();
        if (!this.start_time) {
          this.start_time = end_time;
        }
        if (score_array.length !== 2) {
          if (!score_array[0]) {
            score_array[0] = {
nanahira's avatar
nanahira committed
1526
              name: null,
nanahira's avatar
nanahira committed
1527 1528
              score: -5,
              deck: null
nanahira's avatar
-5  
nanahira committed
1529
            };
1530
          }
nanahira's avatar
-5  
nanahira committed
1531 1532
          if (!score_array[1]) {
            score_array[1] = {
nanahira's avatar
nanahira committed
1533
              name: null,
nanahira's avatar
nanahira committed
1534 1535
              score: -5,
              deck: null
mercury233's avatar
merge  
mercury233 committed
1536
            };
nanahira's avatar
-5  
nanahira committed
1537 1538 1539
          }
          score_array[0].score = -5;
          score_array[1].score = -5;
mercury233's avatar
merge  
mercury233 committed
1540
        }
nanahira's avatar
fix  
nanahira committed
1541 1542 1543 1544 1545 1546 1547 1548
        formatted_replays = [];
        ref3 = this.replays;
        for (m = 0, len2 = ref3.length; m < len2; m++) {
          repbuf = ref3[m];
          if (repbuf) {
            formatted_replays.push(repbuf.toString("base64"));
          }
        }
nanahira's avatar
-5  
nanahira committed
1549 1550 1551 1552 1553 1554 1555 1556
        request.post({
          url: settings.modules.arena_mode.post_score,
          form: {
            accesskey: settings.modules.arena_mode.accesskey,
            usernameA: score_array[0].name,
            usernameB: score_array[1].name,
            userscoreA: score_array[0].score,
            userscoreB: score_array[1].score,
nanahira's avatar
nanahira committed
1557 1558
            userdeckA: score_array[0].deck,
            userdeckB: score_array[1].deck,
nanahira's avatar
nanahira committed
1559 1560
            first: JSON.stringify(this.first_list),
            replays: JSON.stringify(formatted_replays),
nanahira's avatar
-5  
nanahira committed
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575
            start: this.start_time,
            end: end_time,
            arena: this.arena
          }
        }, (function(_this) {
          return function(error, response, body) {
            if (error) {
              log.warn('SCORE POST ERROR', error);
            } else {
              if (response.statusCode !== 204 && response.statusCode !== 200) {
                log.warn('SCORE POST FAIL', response.statusCode, response.statusMessage, _this.name, body);
              }
            }
          };
        })(this));
mercury233's avatar
mercury233 committed
1576
      }
nanahira's avatar
nanahira committed
1577
      if (settings.modules.challonge.enabled && this.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && this.hostinfo.mode !== 2 && !this.kicked) {
nanahira's avatar
js  
nanahira committed
1578
        room_name = this.name;
nanahira's avatar
nanahira committed
1579
        challonge.matches._update({
1580
          id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
1581
          matchId: this.challonge_info.id,
nanahira's avatar
nanahira committed
1582
          match: this.get_challonge_score(),
nanahira's avatar
nanahira committed
1583 1584
          callback: function(err, data) {
            if (err) {
nanahira's avatar
js  
nanahira committed
1585
              log.warn("Errored pushing scores to Challonge.", room_name, err);
nanahira's avatar
nanahira committed
1586 1587
            } else {
              refresh_challonge_cache();
nanahira's avatar
nanahira committed
1588 1589 1590 1591
            }
          }
        });
      }
mercury233's avatar
mercury233 committed
1592
      if (this.player_datas.length && settings.modules.cloud_replay.enabled) {
1593
        replay_id = this.cloud_replay_id;
mercury233's avatar
mercury233 committed
1594 1595 1596
        if (this.has_ygopro_error) {
          log_rep_id = true;
        }
mercury233's avatar
mercury233 committed
1597 1598 1599
        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 : "");
        player_ips = [];
        _.each(this.player_datas, function(player) {
1600
          player_ips.push(player.key);
mercury233's avatar
mercury233 committed
1601 1602 1603
        });
        recorder_buffer = Buffer.concat(this.recorder_buffers);
        zlib.deflate(recorder_buffer, function(err, replay_buffer) {
1604
          var date_time, recorded_ip;
mercury233's avatar
mercury233 committed
1605 1606 1607
          replay_buffer = replay_buffer.toString('binary');
          date_time = moment().format('YYYY-MM-DD HH:mm:ss');
          redisdb.hmset("replay:" + replay_id, "replay_id", replay_id, "replay_buffer", replay_buffer, "player_names", player_names, "date_time", date_time);
nanahira's avatar
nanahira committed
1608
          if (!log_rep_id && !settings.modules.cloud_replay.never_expire) {
mercury233's avatar
mercury233 committed
1609 1610
            redisdb.expire("replay:" + replay_id, 60 * 60 * 24);
          }
mercury233's avatar
mercury233 committed
1611 1612 1613 1614 1615 1616 1617 1618
          recorded_ip = [];
          _.each(player_ips, function(player_ip) {
            if (_.contains(recorded_ip, player_ip)) {
              return;
            }
            recorded_ip.push(player_ip);
            redisdb.lpush(player_ip + ":replays", replay_id);
          });
mercury233's avatar
mercury233 committed
1619
          if (log_rep_id) {
mercury233's avatar
mercury233 committed
1620 1621
            log.info("error replay: R#" + replay_id);
          }
mercury233's avatar
mercury233 committed
1622 1623 1624 1625 1626 1627
        });
      }
      this.watcher_buffers = [];
      this.recorder_buffers = [];
      this.players = [];
      if (this.watcher) {
mercury233's avatar
mercury233 committed
1628
        this.watcher.destroy();
mercury233's avatar
mercury233 committed
1629
      }
mercury233's avatar
fix  
mercury233 committed
1630 1631 1632
      if (this.recorder) {
        this.recorder.destroy();
      }
mercury233's avatar
mercury233 committed
1633 1634
      this.deleted = true;
      index = _.indexOf(ROOM_all, this);
nanahira's avatar
nanahira committed
1635
      if (settings.modules.reconnect.enabled) {
nanahira's avatar
nanahira committed
1636
        ROOM_clear_disconnect(index);
nanahira's avatar
nanahira committed
1637
      }
mercury233's avatar
mercury233 committed
1638
      if (index !== -1) {
1639
        ROOM_all[index] = null;
mercury233's avatar
mercury233 committed
1640
      }
mercury233's avatar
mercury233 committed
1641
      if (!this.windbot && this.established && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1642
        roomlist["delete"](this);
mercury233's avatar
mercury233 committed
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
      }
    };

    Room.prototype.get_playing_player = function() {
      var playing_player;
      playing_player = [];
      _.each(this.players, function(player) {
        if (player.pos < 4) {
          playing_player.push(player);
        }
      });
      return playing_player;
    };

    Room.prototype.get_host = function() {
      var host_player;
      host_player = null;
      _.each(this.players, function(player) {
        if (player.is_host) {
          host_player = player;
        }
      });
      return host_player;
    };

1668
    Room.prototype.get_disconnected_count = function() {
1669 1670
      var found, len2, m, player, ref2;
      if (!settings.modules.reconnect.enabled) {
1671
        return 0;
1672
      }
1673
      found = 0;
1674 1675 1676
      ref2 = this.get_playing_player();
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        player = ref2[m];
1677 1678
        if (player.closed) {
          found++;
1679 1680 1681 1682 1683
        }
      }
      return found;
    };

nanahira's avatar
nanahira committed
1684 1685
    Room.prototype.get_challonge_score = function() {
      var challonge_duel_log;
nanahira's avatar
nanahira committed
1686
      if (!settings.modules.challonge.enabled || this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || this.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
1687 1688 1689
        return null;
      }
      challonge_duel_log = {};
1690
      if (this.scores[this.dueling_players[0].name_vpass] > this.scores[this.dueling_players[1].name_vpass]) {
nanahira's avatar
nanahira committed
1691
        challonge_duel_log.winnerId = this.dueling_players[0].challonge_info.id;
1692
      } else if (this.scores[this.dueling_players[0].name_vpass] < this.scores[this.dueling_players[1].name_vpass]) {
nanahira's avatar
nanahira committed
1693 1694 1695 1696 1697 1698
        challonge_duel_log.winnerId = this.dueling_players[1].challonge_info.id;
      } else {
        challonge_duel_log.winnerId = "tie";
      }
      if (settings.modules.challonge.post_detailed_score) {
        if (this.dueling_players[0].challonge_info.id === this.challonge_info.player1Id && this.dueling_players[1].challonge_info.id === this.challonge_info.player2Id) {
1699
          challonge_duel_log.scoresCsv = this.scores[this.dueling_players[0].name_vpass] + "-" + this.scores[this.dueling_players[1].name_vpass];
nanahira's avatar
nanahira committed
1700
        } else if (this.dueling_players[1].challonge_info.id === this.challonge_info.player1Id && this.dueling_players[0].challonge_info.id === this.challonge_info.player2Id) {
1701
          challonge_duel_log.scoresCsv = this.scores[this.dueling_players[1].name_vpass] + "-" + this.scores[this.dueling_players[0].name_vpass];
nanahira's avatar
nanahira committed
1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717
        } else {
          challonge_duel_log.scoresCsv = "0-0";
          log.warn("Score mismatch.", this.name);
        }
      } else {
        if (challonge_duel_log.winnerId === this.challonge_info.player1Id) {
          challonge_duel_log.scoresCsv = "1-0";
        } else if (challonge_duel_log.winnerId === this.challonge_info.player2Id) {
          challonge_duel_log.scoresCsv = "0-1";
        } else {
          challonge_duel_log.scoresCsv = "0-0";
        }
      }
      return challonge_duel_log;
    };

nanahira's avatar
nanahira committed
1718 1719 1720
    Room.prototype.get_old_hostinfo = function() {
      var ret;
      ret = _.clone(this.hostinfo);
nanahira's avatar
fix  
nanahira committed
1721
      ret.enable_priority = this.hostinfo.duel_rule !== 4;
nanahira's avatar
nanahira committed
1722 1723 1724
      return ret;
    };

nanahira's avatar
nanahira committed
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742
    Room.prototype.send_replays = function() {
      var len2, len3, m, n, player, ref2, ref3;
      if (!(settings.modules.replay_delay && this.replays.length && this.hostinfo.mode === 1)) {
        return false;
      }
      ref2 = this.players;
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        player = ref2[m];
        CLIENT_send_replays(player, this);
      }
      ref3 = this.watchers;
      for (n = 0, len3 = ref3.length; n < len3; n++) {
        player = ref3[n];
        CLIENT_send_replays(player, this);
      }
      return true;
    };

mercury233's avatar
mercury233 committed
1743 1744 1745
    Room.prototype.add_windbot = function(botdata) {
      this.windbot = botdata;
      request({
1746
        url: "http://" + settings.modules.windbot.server_ip + ":" + settings.modules.windbot.port + "/?name=" + (encodeURIComponent(botdata.name)) + "&deck=" + (encodeURIComponent(botdata.deck)) + "&host=" + settings.modules.windbot.my_ip + "&port=" + settings.port + "&dialog=" + (encodeURIComponent(botdata.dialog)) + "&version=" + settings.version + "&password=" + (encodeURIComponent(this.name))
mercury233's avatar
mercury233 committed
1747 1748 1749
      }, (function(_this) {
        return function(error, response, body) {
          if (error) {
mercury233's avatar
merge  
mercury233 committed
1750
            log.warn('windbot add error', error, _this.name);
mercury233's avatar
mercury233 committed
1751
            ygopro.stoc_send_chat_to_room(_this, "${add_windbot_failed}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1752 1753 1754 1755 1756
          }
        };
      })(this));
    };

mercury233's avatar
mercury233 committed
1757
    Room.prototype.connect = function(client) {
mercury233's avatar
mercury233 committed
1758
      var host_player;
mercury233's avatar
mercury233 committed
1759
      this.players.push(client);
nanahira's avatar
nanahira committed
1760
      client.join_time = moment();
mercury233's avatar
mercury233 committed
1761
      if (this.random_type) {
mercury233's avatar
mercury233 committed
1762
        client.abuse_count = 0;
mercury233's avatar
mercury233 committed
1763 1764
        host_player = this.get_host();
        if (host_player && (host_player !== client)) {
mercury233's avatar
mercury233 committed
1765 1766
          ROOM_players_oppentlist[host_player.ip] = client.ip;
          ROOM_players_oppentlist[client.ip] = host_player.ip;
mercury233's avatar
mercury233 committed
1767
        } else {
mercury233's avatar
mercury233 committed
1768
          ROOM_players_oppentlist[client.ip] = null;
mercury233's avatar
mercury233 committed
1769 1770 1771
        }
      }
      if (this.established) {
nanahira's avatar
nanahira committed
1772
        if (!this.windbot && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1773 1774 1775
          roomlist.update(this);
        }
        client.server.connect(this.port, '127.0.0.1', function() {
nanahira's avatar
nanahira committed
1776
          var buffer, len2, m, ref2;
nanahira's avatar
nanahira committed
1777
          ref2 = client.pre_establish_buffers;
nanahira's avatar
nanahira committed
1778 1779
          for (m = 0, len2 = ref2.length; m < len2; m++) {
            buffer = ref2[m];
mercury233's avatar
mercury233 committed
1780 1781 1782 1783 1784 1785 1786 1787 1788
            client.server.write(buffer);
          }
          client.established = true;
          client.pre_establish_buffers = [];
        });
      }
    };

    Room.prototype.disconnect = function(client, error) {
1789
      var index, left_name, len2, len3, m, n, player, ref2, ref3;
nanahira's avatar
nanahira committed
1790 1791 1792
      if (client.had_new_reconnection) {
        return;
      }
mercury233's avatar
mercury233 committed
1793
      if (client.is_post_watcher) {
mercury233's avatar
mercury233 committed
1794
        ygopro.stoc_send_chat_to_room(this, (client.name + " ${quit_watch}") + (error ? ": " + error : ''));
mercury233's avatar
mercury233 committed
1795 1796 1797 1798
        index = _.indexOf(this.watchers, client);
        if (index !== -1) {
          this.watchers.splice(index, 1);
        }
nanahira's avatar
nanahira committed
1799
        client.server.destroy();
mercury233's avatar
mercury233 committed
1800
      } else {
nanahira's avatar
nanahira committed
1801
        if (this.arena && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && this.disconnector !== 'server' && !this.arena_score_handled) {
1802 1803 1804 1805 1806 1807 1808
          if (settings.modules.arena_mode.punish_quit_before_match && this.players.length === 2 && !client.arena_quit_free) {
            ref2 = this.players;
            for (m = 0, len2 = ref2.length; m < len2; m++) {
              player = ref2[m];
              if (player.pos !== 7) {
                this.scores[player.name_vpass] = 0;
              }
1809
            }
1810
            this.scores[client.name_vpass] = -9;
1811 1812 1813 1814 1815 1816 1817 1818
          } else {
            ref3 = this.players;
            for (n = 0, len3 = ref3.length; n < len3; n++) {
              player = ref3[n];
              if (player.pos !== 7) {
                this.scores[player.name_vpass] = -5;
              }
            }
nanahira's avatar
nanahira committed
1819 1820 1821
            if (this.players.length === 2) {
              this.scores[client.name_vpass] = -9;
            }
nanahira's avatar
-5  
nanahira committed
1822
          }
nanahira's avatar
nanahira committed
1823
          this.arena_score_handled = true;
1824
        }
mercury233's avatar
mercury233 committed
1825 1826 1827 1828
        index = _.indexOf(this.players, client);
        if (index !== -1) {
          this.players.splice(index, 1);
        }
nanahira's avatar
nanahira committed
1829
        if (this.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && this.disconnector !== 'server' && client.pos < 4) {
1830
          this.finished = true;
nanahira's avatar
nanahira committed
1831
          if (!this.finished_by_death) {
1832
            this.scores[client.name_vpass] = -9;
nanahira's avatar
fix  
nanahira committed
1833
            if (this.random_type && !client.flee_free && (!settings.modules.reconnect.enabled || this.get_disconnected_count() === 0)) {
nanahira's avatar
nanahira committed
1834
              ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}");
mercury233's avatar
mercury233 committed
1835 1836 1837
              if (settings.modules.random_duel.record_match_scores && this.random_type === 'M') {
                ROOM_player_flee(client.name_vpass);
              }
nanahira's avatar
nanahira committed
1838
            }
mercury233's avatar
mercury233 committed
1839
          }
mercury233's avatar
mercury233 committed
1840
        }
nanahira's avatar
nanahira committed
1841 1842
        if (this.players.length && !(this.windbot && client.is_host) && !(this.arena && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && client.pos <= 3)) {
          left_name = (settings.modules.hide_name && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN ? "********" : client.name);
nanahira's avatar
fix  
nanahira committed
1843
          ygopro.stoc_send_chat_to_room(this, (left_name + " ${left_game}") + (error ? ": " + error : ''));
nanahira's avatar
nanahira committed
1844
          if (!this.windbot && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1845 1846 1847
            roomlist.update(this);
          }
        } else {
nanahira's avatar
nanahira committed
1848
          this.send_replays();
mercury233's avatar
mercury233 committed
1849 1850 1851
          this.process.kill();
          this["delete"]();
        }
nanahira's avatar
nanahira committed
1852
        if (!CLIENT_reconnect_unregister(client, false, true)) {
nanahira's avatar
nanahira committed
1853 1854
          client.server.destroy();
        }
mercury233's avatar
mercury233 committed
1855 1856 1857
      }
    };

nanahira's avatar
nanahira committed
1858 1859
    Room.prototype.start_death = function() {
      var oppo_pos, win_pos;
nanahira's avatar
nanahira committed
1860
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || this.death) {
nanahira's avatar
nanahira committed
1861 1862 1863
        return false;
      }
      oppo_pos = this.hostinfo.mode === 2 ? 2 : 1;
nanahira's avatar
nanahira committed
1864
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) {
nanahira's avatar
nanahira committed
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916
        switch (settings.modules.http.quick_death_rule) {
          case 3:
            this.death = -2;
            ygopro.stoc_send_chat_to_room(this, "${death_start_phase}", ygopro.constants.COLORS.BABYBLUE);
            break;
          default:
            this.death = (this.turn ? this.turn + 4 : 5);
            ygopro.stoc_send_chat_to_room(this, "${death_start}", ygopro.constants.COLORS.BABYBLUE);
        }
      } else {
        switch (settings.modules.http.quick_death_rule) {
          case 2:
          case 3:
            if (this.scores[this.dueling_players[0].name_vpass] === this.scores[this.dueling_players[oppo_pos].name_vpass]) {
              if (settings.modules.http.quick_death_rule === 3) {
                this.death = -1;
                ygopro.stoc_send_chat_to_room(this, "${death_start_quick}", ygopro.constants.COLORS.BABYBLUE);
              } else {
                this.death = 5;
                ygopro.stoc_send_chat_to_room(this, "${death_start_siding}", ygopro.constants.COLORS.BABYBLUE);
              }
            } else {
              win_pos = this.scores[this.dueling_players[0].name_vpass] > this.scores[this.dueling_players[oppo_pos].name_vpass] ? 0 : oppo_pos;
              this.finished_by_death = true;
              ygopro.stoc_send_chat_to_room(this, "${death2_finish_part1}" + this.dueling_players[win_pos].name + "${death2_finish_part2}", ygopro.constants.COLORS.BABYBLUE);
              if (this.hostinfo.mode === 1) {
                CLIENT_send_replays(this.dueling_players[oppo_pos - win_pos], this);
              }
              ygopro.stoc_send(this.dueling_players[oppo_pos - win_pos], 'DUEL_END');
              if (this.hostinfo.mode === 2) {
                ygopro.stoc_send(this.dueling_players[oppo_pos - win_pos + 1], 'DUEL_END');
              }
              this.scores[this.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
              CLIENT_kick(this.dueling_players[oppo_pos - win_pos]);
              if (this.hostinfo.mode === 2) {
                CLIENT_kick(this.dueling_players[oppo_pos - win_pos + 1]);
              }
            }
            break;
          case 1:
            this.death = -1;
            ygopro.stoc_send_chat_to_room(this, "${death_start_quick}", ygopro.constants.COLORS.BABYBLUE);
            break;
          default:
            this.death = 5;
            ygopro.stoc_send_chat_to_room(this, "${death_start_siding}", ygopro.constants.COLORS.BABYBLUE);
        }
      }
      return true;
    };

    Room.prototype.cancel_death = function() {
nanahira's avatar
nanahira committed
1917
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || !this.death) {
nanahira's avatar
nanahira committed
1918 1919 1920 1921 1922 1923 1924
        return false;
      }
      this.death = 0;
      ygopro.stoc_send_chat_to_room(this, "${death_cancel}", ygopro.constants.COLORS.BABYBLUE);
      return true;
    };

mercury233's avatar
mercury233 committed
1925 1926 1927 1928
    return Room;

  })();

神楽坂玲奈's avatar
神楽坂玲奈 committed
1929
  net.createServer(function(client) {
mercury233's avatar
mercury233 committed
1930 1931
    var connect_count, server;
    client.ip = client.remoteAddress;
nanahira's avatar
nanahira committed
1932
    client.is_local = client.ip && (client.ip.includes('127.0.0.1') || client.ip.includes(real_windbot_server_ip));
mercury233's avatar
mercury233 committed
1933
    connect_count = ROOM_connected_ip[client.ip] || 0;
1934
    if (!settings.modules.test_mode.no_connect_count_limit && !client.is_local) {
mercury233's avatar
mercury233 committed
1935 1936 1937
      connect_count++;
    }
    ROOM_connected_ip[client.ip] = connect_count;
神楽坂玲奈's avatar
神楽坂玲奈 committed
1938 1939
    server = new net.Socket();
    client.server = server;
nanahira's avatar
nanahira committed
1940
    server.client = client;
mercury233's avatar
mercury233 committed
1941
    client.setTimeout(2000);
1942
    client.on('close', function(had_error) {
mercury233's avatar
mercury233 committed
1943
      var room;
1944
      room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
1945 1946 1947 1948 1949
      connect_count = ROOM_connected_ip[client.ip];
      if (connect_count > 0) {
        connect_count--;
      }
      ROOM_connected_ip[client.ip] = connect_count;
1950
      if (!client.closed) {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1951
        client.closed = true;
nanahira's avatar
nanahira committed
1952 1953 1954
        if (settings.modules.heartbeat_detection.enabled) {
          CLIENT_heartbeat_unregister(client);
        }
1955
        if (room) {
nanahira's avatar
nanahira committed
1956
          if (!CLIENT_reconnect_register(client, client.rid)) {
nanahira's avatar
nanahira committed
1957 1958 1959 1960
            room.disconnect(client);
          }
        } else if (!client.had_new_reconnection) {
          client.server.destroy();
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1961
        }
mercury233's avatar
mercury233 committed
1962 1963
      }
    });
1964
    client.on('error', function(error) {
mercury233's avatar
mercury233 committed
1965
      var room;
1966
      room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
1967 1968 1969 1970 1971
      connect_count = ROOM_connected_ip[client.ip];
      if (connect_count > 0) {
        connect_count--;
      }
      ROOM_connected_ip[client.ip] = connect_count;
1972
      if (!client.closed) {
nanahira's avatar
nanahira committed
1973
        client.closed = true;
1974
        if (room) {
nanahira's avatar
nanahira committed
1975
          if (!CLIENT_reconnect_register(client, client.rid, error)) {
nanahira's avatar
nanahira committed
1976 1977 1978 1979
            room.disconnect(client, error);
          }
        } else if (!client.had_new_reconnection) {
          client.server.destroy();
1980
        }
神楽坂玲奈's avatar
神楽坂玲奈 committed
1981
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1982
    });
1983
    client.on('timeout', function() {
nanahira's avatar
nanahira committed
1984
      if (!(settings.modules.reconnect.enabled && (disconnect_list[CLIENT_get_authorize_key(client)] || client.had_new_reconnection))) {
nanahira's avatar
nanahira committed
1985
        client.destroy();
nanahira's avatar
nanahira committed
1986
      }
1987
    });
1988
    server.on('close', function(had_error) {
1989
      var room;
1990 1991
      if (!server.closed) {
        server.closed = true;
mercury233's avatar
mercury233 committed
1992
      }
nanahira's avatar
nanahira committed
1993 1994 1995
      if (!server.client) {
        return;
      }
nanahira's avatar
nanahira committed
1996 1997 1998 1999
      room = ROOM_all[server.client.rid];
      if (room) {
        room.disconnector = 'server';
      }
nanahira's avatar
nanahira committed
2000 2001 2002 2003
      if (!server.client.closed) {
        ygopro.stoc_send_chat(server.client, "${server_closed}", ygopro.constants.COLORS.RED);
        CLIENT_kick(server.client);
        SERVER_clear_disconnect(server);
mercury233's avatar
mercury233 committed
2004 2005
      }
    });
2006
    server.on('error', function(error) {
2007
      var room;
2008
      server.closed = error;
nanahira's avatar
nanahira committed
2009 2010 2011
      if (!server.client) {
        return;
      }
nanahira's avatar
nanahira committed
2012 2013 2014 2015
      room = ROOM_all[server.client.rid];
      if (room) {
        room.disconnector = 'server';
      }
nanahira's avatar
nanahira committed
2016 2017 2018 2019
      if (!server.client.closed) {
        ygopro.stoc_send_chat(server.client, "${server_error}: " + error, ygopro.constants.COLORS.RED);
        CLIENT_kick(server.client);
        SERVER_clear_disconnect(server);
mercury233's avatar
mercury233 committed
2020 2021
      }
    });
mercury233's avatar
mercury233 committed
2022
    if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
mercury233's avatar
mercury233 committed
2023
      log.info('BAD IP', client.ip);
nanahira's avatar
nanahira committed
2024
      CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2025 2026
      return;
    }
mercury233's avatar
mercury233 committed
2027
    if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2028 2029 2030
      client.open_cloud_replay = function(err, replay) {
        var buffer;
        if (err || !replay) {
mercury233's avatar
mercury233 committed
2031
          ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2032
          return;
mercury233's avatar
mercury233 committed
2033
        }
mercury233's avatar
mercury233 committed
2034
        redisdb.expire("replay:" + replay.replay_id, 60 * 60 * 48);
nanahira's avatar
nanahira committed
2035
        buffer = Buffer.from(replay.replay_buffer, 'binary');
mercury233's avatar
mercury233 committed
2036 2037
        zlib.unzip(buffer, function(err, replay_buffer) {
          if (err) {
mercury233's avatar
mercury233 committed
2038
            log.info("cloud replay unzip error: " + err);
mercury233's avatar
mercury233 committed
2039
            ygopro.stoc_send_chat(client, "${cloud_replay_error}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
2040
            CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2041 2042
            return;
          }
mercury233's avatar
mercury233 committed
2043
          ygopro.stoc_send_chat(client, "${cloud_replay_playing} R#" + replay.replay_id + " " + replay.player_names + " " + replay.date_time, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
2044
          client.write(replay_buffer, function() {
nanahira's avatar
nanahira committed
2045
            CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2046
          });
mercury233's avatar
mercury233 committed
2047
        });
mercury233's avatar
mercury233 committed
2048 2049
      };
    }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2050
    client.pre_establish_buffers = new Array();
mercury233's avatar
mercury233 committed
2051
    client.on('data', function(ctos_buffer) {
nanahira's avatar
nanahira committed
2052
      var b, bad_ip_count, buffer, cancel, ctos_event, ctos_message_length, ctos_proto, datas, info, len2, len3, len4, len5, looplimit, m, n, o, p, ref2, ref3, result, room, struct;
2053
      if (client.is_post_watcher) {
2054
        room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
2055
        if (room && !CLIENT_is_banned_by_mc(client)) {
mercury233's avatar
mercury233 committed
2056
          room.watcher.write(ctos_buffer);
2057
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2058
      } else {
mercury233's avatar
mercury233 committed
2059 2060
        ctos_message_length = 0;
        ctos_proto = 0;
2061
        datas = [];
mercury233's avatar
mercury233 committed
2062
        looplimit = 0;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2063
        while (true) {
2064 2065
          if (ctos_message_length === 0) {
            if (ctos_buffer.length >= 2) {
mercury233's avatar
test3  
mercury233 committed
2066
              ctos_message_length = ctos_buffer.readUInt16LE(0);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2067
            } else {
mercury233's avatar
mercury233 committed
2068 2069 2070
              if (ctos_buffer.length !== 0) {
                log.warn("bad ctos_buffer length", client.ip);
              }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2071 2072
              break;
            }
2073 2074
          } else if (ctos_proto === 0) {
            if (ctos_buffer.length >= 3) {
mercury233's avatar
test3  
mercury233 committed
2075
              ctos_proto = ctos_buffer.readUInt8(2);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2076
            } else {
mercury233's avatar
mercury233 committed
2077
              log.warn("bad ctos_proto length", client.ip);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2078
              break;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2079 2080
            }
          } else {
2081
            if (ctos_buffer.length >= 2 + ctos_message_length) {
2082
              cancel = false;
nanahira's avatar
nanahira committed
2083 2084 2085
              if (settings.modules.reconnect.enabled && client.pre_reconnecting && ygopro.constants.CTOS[ctos_proto] !== 'UPDATE_DECK') {
                cancel = true;
              }
nanahira's avatar
nanahira committed
2086 2087
              b = ctos_buffer.slice(3, ctos_message_length - 1 + 3);
              info = null;
nanahira's avatar
nanahira committed
2088 2089
              struct = ygopro.structs[ygopro.proto_structs.CTOS[ygopro.constants.CTOS[ctos_proto]]];
              if (struct && !cancel) {
nanahira's avatar
nanahira committed
2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102
                struct._setBuff(b);
                info = _.clone(struct.fields);
              }
              if (ygopro.ctos_follows_before[ctos_proto] && !cancel) {
                ref2 = ygopro.ctos_follows_before[ctos_proto];
                for (m = 0, len2 = ref2.length; m < len2; m++) {
                  ctos_event = ref2[m];
                  result = ctos_event.callback(b, info, client, client.server, datas);
                  if (result && ctos_event.synchronous) {
                    cancel = true;
                  }
                }
              }
nanahira's avatar
nanahira committed
2103 2104 2105 2106
              if (struct && !cancel) {
                struct._setBuff(b);
                info = _.clone(struct.fields);
              }
nanahira's avatar
nanahira committed
2107
              if (ygopro.ctos_follows[ctos_proto] && !cancel) {
nanahira's avatar
nanahira committed
2108 2109 2110
                result = ygopro.ctos_follows[ctos_proto].callback(b, info, client, client.server, datas);
                if (result && ygopro.ctos_follows[ctos_proto].synchronous) {
                  cancel = true;
2111
                }
nanahira's avatar
nanahira committed
2112
              }
nanahira's avatar
nanahira committed
2113 2114 2115 2116
              if (struct && !cancel) {
                struct._setBuff(b);
                info = _.clone(struct.fields);
              }
nanahira's avatar
nanahira committed
2117 2118 2119 2120 2121 2122 2123 2124
              if (ygopro.ctos_follows_after[ctos_proto] && !cancel) {
                ref3 = ygopro.ctos_follows_after[ctos_proto];
                for (n = 0, len3 = ref3.length; n < len3; n++) {
                  ctos_event = ref3[n];
                  result = ctos_event.callback(b, info, client, client.server, datas);
                  if (result && ctos_event.synchronous) {
                    cancel = true;
                  }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2125 2126
                }
              }
2127 2128 2129
              if (!cancel) {
                datas.push(ctos_buffer.slice(0, 2 + ctos_message_length));
              }
2130 2131
              ctos_buffer = ctos_buffer.slice(2 + ctos_message_length);
              ctos_message_length = 0;
mercury233's avatar
test3  
mercury233 committed
2132
              ctos_proto = 0;
mercury233's avatar
fix  
mercury233 committed
2133 2134 2135 2136
            } else {
              if (ctos_message_length !== 17735) {
                log.warn("bad ctos_message length", client.ip, ctos_buffer.length, ctos_message_length, ctos_proto);
              }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2137 2138
              break;
            }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2139
          }
mercury233's avatar
mercury233 committed
2140
          looplimit++;
mercury233's avatar
mercury233 committed
2141 2142 2143
          if (looplimit > 800 || ROOM_bad_ip[client.ip] > 5) {
            log.info("error ctos", client.name, client.ip);
            bad_ip_count = ROOM_bad_ip[client.ip];
mercury233's avatar
mercury233 committed
2144
            if (bad_ip_count) {
mercury233's avatar
mercury233 committed
2145
              ROOM_bad_ip[client.ip] = bad_ip_count + 1;
mercury233's avatar
mercury233 committed
2146
            } else {
mercury233's avatar
mercury233 committed
2147
              ROOM_bad_ip[client.ip] = 1;
mercury233's avatar
mercury233 committed
2148
            }
nanahira's avatar
nanahira committed
2149
            CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2150 2151
            break;
          }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2152
        }
nanahira's avatar
nanahira committed
2153 2154 2155
        if (!client.server) {
          return;
        }
2156
        if (client.established) {
nanahira's avatar
nanahira committed
2157 2158
          for (o = 0, len4 = datas.length; o < len4; o++) {
            buffer = datas[o];
nanahira's avatar
nanahira committed
2159
            client.server.write(buffer);
2160 2161
          }
        } else {
nanahira's avatar
nanahira committed
2162 2163
          for (p = 0, len5 = datas.length; p < len5; p++) {
            buffer = datas[p];
2164 2165 2166
            client.pre_establish_buffers.push(buffer);
          }
        }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2167 2168
      }
    });
mercury233's avatar
mercury233 committed
2169
    server.on('data', function(stoc_buffer) {
nanahira's avatar
nanahira committed
2170
      var b, buffer, cancel, datas, info, len2, len3, len4, looplimit, m, n, o, ref2, ref3, result, stoc_event, stoc_message_length, stoc_proto, struct;
mercury233's avatar
mercury233 committed
2171 2172
      stoc_message_length = 0;
      stoc_proto = 0;
2173
      datas = [];
mercury233's avatar
mercury233 committed
2174
      looplimit = 0;
神楽坂玲奈's avatar
神楽坂玲奈 committed
2175
      while (true) {
2176 2177
        if (stoc_message_length === 0) {
          if (stoc_buffer.length >= 2) {
mercury233's avatar
test3  
mercury233 committed
2178
            stoc_message_length = stoc_buffer.readUInt16LE(0);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2179
          } else {
mercury233's avatar
mercury233 committed
2180
            if (stoc_buffer.length !== 0) {
nanahira's avatar
nanahira committed
2181
              log.warn("bad stoc_buffer length", server.client.ip);
mercury233's avatar
mercury233 committed
2182
            }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2183 2184
            break;
          }
2185 2186
        } else if (stoc_proto === 0) {
          if (stoc_buffer.length >= 3) {
mercury233's avatar
test3  
mercury233 committed
2187
            stoc_proto = stoc_buffer.readUInt8(2);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2188
          } else {
nanahira's avatar
nanahira committed
2189
            log.warn("bad stoc_proto length", server.client.ip);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2190 2191 2192
            break;
          }
        } else {
2193
          if (stoc_buffer.length >= 2 + stoc_message_length) {
2194
            cancel = false;
nanahira's avatar
nanahira committed
2195 2196
            b = stoc_buffer.slice(3, stoc_message_length - 1 + 3);
            info = null;
nanahira's avatar
nanahira committed
2197 2198
            struct = ygopro.structs[ygopro.proto_structs.STOC[ygopro.constants.STOC[stoc_proto]]];
            if (struct && !cancel) {
nanahira's avatar
nanahira committed
2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209
              struct._setBuff(b);
              info = _.clone(struct.fields);
            }
            if (ygopro.stoc_follows_before[stoc_proto] && !cancel) {
              ref2 = ygopro.stoc_follows_before[stoc_proto];
              for (m = 0, len2 = ref2.length; m < len2; m++) {
                stoc_event = ref2[m];
                result = stoc_event.callback(b, info, server.client, server, datas);
                if (result && stoc_event.synchronous) {
                  cancel = true;
                }
2210
              }
nanahira's avatar
nanahira committed
2211
            }
nanahira's avatar
nanahira committed
2212 2213 2214 2215
            if (struct && !cancel) {
              struct._setBuff(b);
              info = _.clone(struct.fields);
            }
nanahira's avatar
nanahira committed
2216 2217 2218 2219 2220 2221
            if (ygopro.stoc_follows[stoc_proto] && !cancel) {
              result = ygopro.stoc_follows[stoc_proto].callback(b, info, server.client, server, datas);
              if (result && ygopro.stoc_follows[stoc_proto].synchronous) {
                cancel = true;
              }
            }
nanahira's avatar
nanahira committed
2222 2223 2224 2225
            if (struct && !cancel) {
              struct._setBuff(b);
              info = _.clone(struct.fields);
            }
nanahira's avatar
nanahira committed
2226 2227 2228 2229 2230 2231 2232 2233
            if (ygopro.stoc_follows_after[stoc_proto] && !cancel) {
              ref3 = ygopro.stoc_follows_after[stoc_proto];
              for (n = 0, len3 = ref3.length; n < len3; n++) {
                stoc_event = ref3[n];
                result = stoc_event.callback(b, info, server.client, server, datas);
                if (result && stoc_event.synchronous) {
                  cancel = true;
                }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2234 2235
              }
            }
2236 2237 2238
            if (!cancel) {
              datas.push(stoc_buffer.slice(0, 2 + stoc_message_length));
            }
2239 2240
            stoc_buffer = stoc_buffer.slice(2 + stoc_message_length);
            stoc_message_length = 0;
mercury233's avatar
test3  
mercury233 committed
2241
            stoc_proto = 0;
神楽坂玲奈's avatar
神楽坂玲奈 committed
2242
          } else {
nanahira's avatar
nanahira committed
2243
            log.warn("bad stoc_message length", server.client.ip);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2244 2245 2246
            break;
          }
        }
mercury233's avatar
mercury233 committed
2247 2248
        looplimit++;
        if (looplimit > 800) {
nanahira's avatar
nanahira committed
2249
          log.info("error stoc", server.client.name);
mercury233's avatar
mercury233 committed
2250
          server.destroy();
mercury233's avatar
mercury233 committed
2251 2252
          break;
        }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
2253
      }
nanahira's avatar
nanahira committed
2254
      if (server.client && !server.client.closed) {
nanahira's avatar
nanahira committed
2255 2256
        for (o = 0, len4 = datas.length; o < len4; o++) {
          buffer = datas[o];
nanahira's avatar
nanahira committed
2257 2258
          server.client.write(buffer);
        }
2259
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2260
    });
神楽坂玲奈's avatar
神楽坂玲奈 committed
2261
  }).listen(settings.port, function() {
mercury233's avatar
mercury233 committed
2262
    log.info("server started", settings.port);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2263
  });
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2264

mercury233's avatar
mercury233 committed
2265 2266 2267 2268
  if (settings.modules.stop) {
    log.info("NOTE: server not open due to config, ", settings.modules.stop);
  }

Yuzurisa's avatar
Yuzurisa committed
2269 2270 2271 2272 2273
  deck_name_match = global.deck_name_match = function(deck_name, player_name) {
    var parsed_deck_name;
    if (deck_name === player_name || deck_name === player_name + ".ydk" || deck_name === player_name + ".ydk.ydk") {
      return true;
    }
nanahira's avatar
js  
nanahira committed
2274
    parsed_deck_name = deck_name.match(/^([^\+ \uff0b]+)[\+ \uff0b](.+?)(\.ydk){0,2}$/);
Yuzurisa's avatar
Yuzurisa committed
2275 2276 2277
    return parsed_deck_name && (player_name === parsed_deck_name[1] || player_name === parsed_deck_name[2]);
  };

nanahira's avatar
nanahira committed
2278
  ygopro.ctos_follow('PLAYER_INFO', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
2279 2280 2281 2282 2283 2284 2285
    var geo, lang, name, name_full, struct, vpass;
    name_full = info.name.split("$");
    name = name_full[0];
    vpass = name_full[1];
    if (vpass && !vpass.length) {
      vpass = null;
    }
mercury233's avatar
mercury233 committed
2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297
    if (_.any(settings.ban.illegal_id, function(badid) {
      var matchs, regexp;
      regexp = new RegExp(badid, 'i');
      matchs = name.match(regexp);
      if (matchs) {
        name = matchs[1];
        return true;
      }
      return false;
    }, name)) {
      client.rag = true;
    }
nanahira's avatar
typo  
nanahira committed
2298
    if (settings.modules.mycard.enabled) {
nanahira's avatar
nanahira committed
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314
      request({
        url: settings.modules.mycard.ban_get,
        json: true,
        qs: {
          user: name
        }
      }, function(error, response, body) {
        if (_.isString(body)) {
          log.warn("ban get bad json", body);
        } else if (error || !body) {
          log.warn('ban get error', error, response);
        } else {
          client.ban_mc = body;
        }
      });
    }
2315 2316 2317 2318 2319
    struct = ygopro.structs["CTOS_PlayerInfo"];
    struct._setBuff(buffer);
    struct.set("name", name);
    buffer = struct.buffer;
    client.name = name;
nanahira's avatar
nanahira committed
2320
    client.vpass = vpass;
2321
    client.name_vpass = vpass ? name + "$" + vpass : name;
2322
    if (!settings.modules.i18n.auto_pick || client.is_local) {
mercury233's avatar
mercury233 committed
2323 2324 2325 2326
      client.lang = settings.modules.i18n["default"];
    } else {
      geo = geoip.lookup(client.ip);
      if (!geo) {
mercury233's avatar
mercury233 committed
2327
        log.warn("fail to locate ip", client.name, client.ip);
mercury233's avatar
mercury233 committed
2328 2329 2330 2331 2332 2333 2334 2335
        client.lang = settings.modules.i18n.fallback;
      } else {
        if (lang = settings.modules.i18n.map[geo.country]) {
          client.lang = lang;
        } else {
          client.lang = settings.modules.i18n.fallback;
        }
      }
mercury233's avatar
mercury233 committed
2336
    }
2337
    return false;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2338 2339
  });

nanahira's avatar
nanahira committed
2340
  ygopro.ctos_follow('JOIN_GAME', false, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
2341
    var buffer_handle_callback, check_buffer_indentity, len2, len3, m, match_permit_callback, n, name, pre_room, ref2, ref3, replay_id, room;
mercury233's avatar
mercury233 committed
2342
    info.pass = info.pass.trim();
nanahira's avatar
nanahira committed
2343 2344
    client.pass = info.pass;
    if (CLIENT_is_able_to_reconnect(client) || CLIENT_is_able_to_kick_reconnect(client)) {
nanahira's avatar
nanahira committed
2345 2346 2347
      CLIENT_pre_reconnect(client);
      return;
    } else if (settings.modules.stop) {
mercury233's avatar
mercury233 committed
2348
      ygopro.stoc_die(client, settings.modules.stop);
nanahira's avatar
nanahira committed
2349 2350
    } else if (info.pass === "Marshtomp" || info.pass === "the Big Brother") {
      ygopro.stoc_die(client, "${bad_user_name}");
mercury233's avatar
mercury233 committed
2351
    } else if (info.pass.toUpperCase() === "R" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2352
      ygopro.stoc_send_chat(client, "${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE);
2353
      redisdb.lrange(CLIENT_get_authorize_key(client) + ":replays", 0, 2, function(err, result) {
mercury233's avatar
mercury233 committed
2354 2355 2356
        _.each(result, function(replay_id, id) {
          redisdb.hgetall("replay:" + replay_id, function(err, replay) {
            if (err || !replay) {
mercury233's avatar
mercury233 committed
2357 2358 2359
              if (err) {
                log.info("cloud replay getall error: " + err);
              }
mercury233's avatar
mercury233 committed
2360 2361 2362
              return;
            }
            ygopro.stoc_send_chat(client, "<" + (id - 0 + 1) + "> R#" + replay_id + " " + replay.player_names + " " + replay.date_time, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
2363
          });
mercury233's avatar
mercury233 committed
2364 2365 2366 2367 2368
        });
      });
      setTimeout((function() {
        ygopro.stoc_send(client, 'ERROR_MSG', {
          msg: 1,
mercury233's avatar
mercury233 committed
2369
          code: 9
mercury233's avatar
mercury233 committed
2370
        });
nanahira's avatar
nanahira committed
2371
        CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2372
      }), 500);
mercury233's avatar
mercury233 committed
2373
    } else if (info.pass.slice(0, 2).toUpperCase() === "R#" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2374
      replay_id = info.pass.split("#")[1];
mercury233's avatar
fix  
mercury233 committed
2375
      if (replay_id > 0 && replay_id <= 9) {
mercury233's avatar
mercury233 committed
2376
        redisdb.lindex(client.ip + ":replays", replay_id - 1, function(err, replay_id) {
mercury233's avatar
mercury233 committed
2377
          if (err || !replay_id) {
mercury233's avatar
mercury233 committed
2378 2379 2380
            if (err) {
              log.info("cloud replay replayid error: " + err);
            }
mercury233's avatar
mercury233 committed
2381
            ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2382 2383 2384 2385
            return;
          }
          redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
        });
mercury233's avatar
mercury233 committed
2386 2387 2388
      } else if (replay_id) {
        redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
      } else {
mercury233's avatar
mercury233 committed
2389
        ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2390
      }
mercury233's avatar
mercury233 committed
2391
    } else if (info.pass.toUpperCase() === "W" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2392 2393
      replay_id = Cloud_replay_ids[Math.floor(Math.random() * Cloud_replay_ids.length)];
      redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
mercury233's avatar
mercury233 committed
2394
    } else if (info.version !== settings.version) {
mercury233's avatar
mercury233 committed
2395
      ygopro.stoc_send_chat(client, settings.modules.update, ygopro.constants.COLORS.RED);
mercury233's avatar
fix  
mercury233 committed
2396 2397 2398 2399
      ygopro.stoc_send(client, 'ERROR_MSG', {
        msg: 4,
        code: settings.version
      });
nanahira's avatar
nanahira committed
2400
      CLIENT_kick(client);
nanahira's avatar
nanahira committed
2401
    } else if (!info.pass.length && !settings.modules.random_duel.enabled && !settings.modules.windbot.enabled && !settings.modules.challonge.enabled) {
mercury233's avatar
mercury233 committed
2402
      ygopro.stoc_die(client, "${blank_room_name}");
mercury233's avatar
fix  
mercury233 committed
2403
    } else if (info.pass.length && settings.modules.mycard.enabled && info.pass.slice(0, 3) !== 'AI#') {
mercury233's avatar
mercury233 committed
2404
      ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2405
      if (info.pass.length <= 8) {
mercury233's avatar
mercury233 committed
2406
        ygopro.stoc_die(client, '${invalid_password_length}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2407 2408
        return;
      }
nanahira's avatar
nanahira committed
2409
      buffer = Buffer.from(info.pass.slice(0, 8), 'base64');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2410
      if (buffer.length !== 6) {
mercury233's avatar
mercury233 committed
2411
        ygopro.stoc_die(client, '${invalid_password_payload}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2412 2413
        return;
      }
nanahira's avatar
nanahira committed
2414
      check_buffer_indentity = function(buf) {
nanahira's avatar
nanahira committed
2415
        var checksum, i, m, ref2;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2416
        checksum = 0;
nanahira's avatar
nanahira committed
2417
        for (i = m = 0, ref2 = buf.length; 0 <= ref2 ? m < ref2 : m > ref2; i = 0 <= ref2 ? ++m : --m) {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2418
          checksum += buf.readUInt8(i);
2419
        }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2420 2421
        return (checksum & 0xFF) === 0;
      };
nanahira's avatar
fix  
nanahira committed
2422
      buffer_handle_callback = function(buffer, decrypted_buffer, match_permit) {
nanahira's avatar
nanahira committed
2423
        var action, len2, len3, m, n, name, opt1, opt2, opt3, options, player, ref2, ref3, room, title;
nanahira's avatar
nanahira committed
2424 2425 2426
        if (client.closed) {
          return;
        }
2427 2428
        action = buffer.readUInt8(1) >> 4;
        if (buffer !== decrypted_buffer && (action === 1 || action === 2 || action === 4)) {
mercury233's avatar
mercury233 committed
2429
          ygopro.stoc_die(client, '${invalid_password_unauthorized}');
2430 2431 2432 2433 2434 2435
          return;
        }
        switch (action) {
          case 1:
          case 2:
            name = crypto.createHash('md5').update(info.pass + client.name).digest('base64').slice(0, 10).replace('+', '-').replace('/', '_');
mercury233's avatar
mercury233 committed
2436
            if (ROOM_find_by_name(name)) {
mercury233's avatar
mercury233 committed
2437
              ygopro.stoc_die(client, '${invalid_password_existed}');
2438 2439 2440
              return;
            }
            opt1 = buffer.readUInt8(2);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2441
            opt2 = buffer.readUInt16LE(3);
2442 2443 2444 2445 2446 2447
            opt3 = buffer.readUInt8(5);
            options = {
              lflist: 0,
              time_limit: 180,
              rule: (opt1 >> 5) & 3,
              mode: (opt1 >> 3) & 3,
nanahira's avatar
fix  
nanahira committed
2448
              duel_rule: (!!((opt1 >> 2) & 1) ? 3 : 4),
2449 2450 2451 2452
              no_check_deck: !!((opt1 >> 1) & 1),
              no_shuffle_deck: !!(opt1 & 1),
              start_lp: opt2,
              start_hand: opt3 >> 4,
nanahira's avatar
nanahira committed
2453 2454 2455
              draw_count: opt3 & 0xF,
              no_watch: false,
              auto_death: false
2456
            };
mercury233's avatar
mercury233 committed
2457
            options.lflist = _.findIndex(lflists, function(list) {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2458
              return ((options.rule === 1) === list.tcg) && list.date.isBefore();
神楽坂玲奈's avatar
神楽坂玲奈 committed
2459
            });
2460
            room = new Room(name, options);
nanahira's avatar
nanahira committed
2461 2462 2463 2464
            if (room) {
              room.title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
              room["private"] = action === 2;
            }
2465 2466 2467
            break;
          case 3:
            name = info.pass.slice(8);
mercury233's avatar
mercury233 committed
2468
            room = ROOM_find_by_name(name);
2469
            if (!room) {
mercury233's avatar
mercury233 committed
2470
              ygopro.stoc_die(client, '${invalid_password_not_found}');
2471 2472 2473 2474
              return;
            }
            break;
          case 4:
nanahira's avatar
move  
nanahira committed
2475 2476 2477 2478
            if (match_permit && !match_permit.permit) {
              ygopro.stoc_die(client, '${invalid_password_unauthorized}');
              return;
            }
mercury233's avatar
mercury233 committed
2479
            room = ROOM_find_or_create_by_name('M#' + info.pass.slice(8));
nanahira's avatar
nanahira committed
2480
            if (room) {
nanahira's avatar
nanahira committed
2481 2482 2483 2484 2485 2486 2487 2488 2489
              ref2 = room.get_playing_player();
              for (m = 0, len2 = ref2.length; m < len2; m++) {
                player = ref2[m];
                if (!(player && player.name === client.name)) {
                  continue;
                }
                ygopro.stoc_die(client, '${invalid_password_unauthorized}');
                return;
              }
nanahira's avatar
nanahira committed
2490 2491 2492 2493 2494 2495
              room["private"] = true;
              room.arena = settings.modules.arena_mode.mode;
              if (room.arena === "athletic") {
                room.max_player = 2;
                room.welcome = "${athletic_arena_tip}";
              }
2496
            }
2497
            break;
mercury233's avatar
mercury233 committed
2498 2499 2500 2501 2502 2503 2504 2505
          case 5:
            title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
            room = ROOM_find_by_title(title);
            if (!room) {
              ygopro.stoc_die(client, '${invalid_password_not_found}');
              return;
            }
            break;
2506
          default:
mercury233's avatar
mercury233 committed
2507
            ygopro.stoc_die(client, '${invalid_password_action}');
2508 2509
            return;
        }
mercury233's avatar
mercury233 committed
2510
        if (!room) {
mercury233's avatar
mercury233 committed
2511
          ygopro.stoc_die(client, "${server_full}");
mercury233's avatar
mercury233 committed
2512
        } else if (room.error) {
mercury233's avatar
mercury233 committed
2513
          ygopro.stoc_die(client, room.error);
nanahira's avatar
nanahira committed
2514
        } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
2515
          if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
mercury233's avatar
mercury233 committed
2516 2517 2518 2519 2520 2521
            client.setTimeout(300000);
            client.rid = _.indexOf(ROOM_all, room);
            client.is_post_watcher = true;
            ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
            room.watchers.push(client);
            ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2522 2523 2524
            ref3 = room.watcher_buffers;
            for (n = 0, len3 = ref3.length; n < len3; n++) {
              buffer = ref3[n];
mercury233's avatar
mercury233 committed
2525 2526 2527 2528 2529
              client.write(buffer);
            }
          } else {
            ygopro.stoc_die(client, "${watch_denied}");
          }
nanahira's avatar
nanahira committed
2530
        } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
nanahira's avatar
fix  
nanahira committed
2531
          ygopro.stoc_die(client, "${watch_denied_room}");
mercury233's avatar
mercury233 committed
2532
        } else {
mercury233's avatar
mercury233 committed
2533
          client.setTimeout(300000);
2534 2535
          client.rid = _.indexOf(ROOM_all, room);
          room.connect(client);
mercury233's avatar
mercury233 committed
2536
        }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2537
      };
nanahira's avatar
nanahira committed
2538 2539 2540 2541
      match_permit_callback = function(buffer, match_permit) {
        var decrypted_buffer, i, id, len2, m, ref2, secret;
        if (client.closed) {
          return;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2542
        }
nanahira's avatar
nanahira committed
2543 2544
        if (id = users_cache[client.name]) {
          secret = id % 65535 + 1;
nanahira's avatar
nanahira committed
2545
          decrypted_buffer = Buffer.allocUnsafe(6);
nanahira's avatar
nanahira committed
2546 2547 2548
          ref2 = [0, 2, 4];
          for (m = 0, len2 = ref2.length; m < len2; m++) {
            i = ref2[m];
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2549 2550
            decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
          }
nanahira's avatar
nanahira committed
2551
          if (check_buffer_indentity(decrypted_buffer)) {
nanahira's avatar
fix  
nanahira committed
2552
            return buffer_handle_callback(decrypted_buffer, decrypted_buffer, match_permit);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2553 2554
          }
        }
nanahira's avatar
nanahira committed
2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
        request({
          baseUrl: settings.modules.mycard.auth_base_url,
          url: '/users/' + encodeURIComponent(client.name) + '.json',
          qs: {
            api_key: settings.modules.mycard.auth_key,
            api_username: client.name,
            skip_track_visit: true
          },
          json: true
        }, function(error, response, body) {
          var len3, n, ref3;
nanahira's avatar
js  
nanahira committed
2566
          if (!error && body && body.user) {
nanahira's avatar
nanahira committed
2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
            users_cache[client.name] = body.user.id;
            secret = body.user.id % 65535 + 1;
            decrypted_buffer = Buffer.allocUnsafe(6);
            ref3 = [0, 2, 4];
            for (n = 0, len3 = ref3.length; n < len3; n++) {
              i = ref3[n];
              decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
            }
            if (check_buffer_indentity(decrypted_buffer)) {
              buffer = decrypted_buffer;
            }
nanahira's avatar
js  
nanahira committed
2578 2579 2580 2581
          } else {
            log.warn("READ USER FAIL", error, body);
            ygopro.stoc_die(client, "${create_room_failed}");
            return;
nanahira's avatar
nanahira committed
2582 2583 2584 2585 2586
          }
          if (!check_buffer_indentity(buffer)) {
            ygopro.stoc_die(client, '${invalid_password_checksum}');
            return;
          }
nanahira's avatar
fix  
nanahira committed
2587
          return buffer_handle_callback(buffer, decrypted_buffer, match_permit);
nanahira's avatar
nanahira committed
2588 2589 2590 2591 2592 2593 2594 2595
        });
      };
      if (settings.modules.arena_mode.check_permit) {
        request({
          url: settings.modules.arena_mode.check_permit,
          json: true,
          qs: {
            username: client.name,
2596 2597
            password: info.pass,
            arena: settings.modules.arena_mode.mode
nanahira's avatar
nanahira committed
2598 2599 2600 2601 2602 2603 2604 2605
          }
        }, function(error, response, body) {
          if (client.closed) {
            return;
          }
          if (!error && body) {
            match_permit_callback(buffer, body);
          } else {
nanahira's avatar
log  
nanahira committed
2606
            log.warn("Match permit request error", error);
nanahira's avatar
nanahira committed
2607 2608 2609 2610 2611 2612
            match_permit_callback(buffer, null);
          }
        });
      } else {
        match_permit_callback(buffer, null);
      }
nanahira's avatar
nanahira committed
2613 2614
    } else if (settings.modules.challonge.enabled) {
      pre_room = ROOM_find_by_name(info.pass);
nanahira's avatar
nanahira committed
2615
      if (pre_room && pre_room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.cloud_replay.enable_halfway_watch && !pre_room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
2616 2617 2618 2619 2620 2621 2622
        room = pre_room;
        client.setTimeout(300000);
        client.rid = _.indexOf(ROOM_all, room);
        client.is_post_watcher = true;
        ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
        room.watchers.push(client);
        ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2623 2624 2625
        ref2 = room.watcher_buffers;
        for (m = 0, len2 = ref2.length; m < len2; m++) {
          buffer = ref2[m];
nanahira's avatar
nanahira committed
2626 2627 2628 2629
          client.write(buffer);
        }
      } else {
        ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
fix  
nanahira committed
2630
        client.setTimeout(300000);
nanahira's avatar
nanahira committed
2631
        challonge.participants._index({
2632
          id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
2633 2634
          callback: function(err, data) {
            var found, k, user;
nanahira's avatar
nanahira committed
2635 2636 2637
            if (client.closed) {
              return;
            }
nanahira's avatar
nanahira committed
2638 2639 2640 2641 2642 2643 2644 2645 2646 2647
            if (err || !data) {
              if (err) {
                log.warn("Failed loading Challonge user info", err);
              }
              ygopro.stoc_die(client, '${challonge_match_load_failed}');
              return;
            }
            found = false;
            for (k in data) {
              user = data[k];
Yuzurisa's avatar
Yuzurisa committed
2648
              if (user.participant && user.participant.name && deck_name_match(user.participant.name, client.name)) {
nanahira's avatar
nanahira committed
2649 2650 2651 2652 2653 2654 2655 2656 2657
                found = user.participant;
                break;
              }
            }
            if (!found) {
              ygopro.stoc_die(client, '${challonge_user_not_found}');
              return;
            }
            client.challonge_info = found;
nanahira's avatar
nanahira committed
2658
            challonge.matches._index({
2659
              id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
2660
              callback: function(err, data) {
nanahira's avatar
nanahira committed
2661
                var len3, len4, match, n, o, player, ref3, ref4;
nanahira's avatar
nanahira committed
2662 2663 2664
                if (client.closed) {
                  return;
                }
nanahira's avatar
nanahira committed
2665 2666 2667 2668 2669 2670 2671 2672 2673 2674
                if (err || !data) {
                  if (err) {
                    log.warn("Failed loading Challonge match info", err);
                  }
                  ygopro.stoc_die(client, '${challonge_match_load_failed}');
                  return;
                }
                found = false;
                for (k in data) {
                  match = data[k];
nanahira's avatar
nanahira committed
2675
                  if (match && match.match && !match.match.winnerId && match.match.state !== "complete" && match.match.player1Id && match.match.player2Id && (match.match.player1Id === client.challonge_info.id || match.match.player2Id === client.challonge_info.id)) {
nanahira's avatar
nanahira committed
2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692
                    found = match.match;
                    break;
                  }
                }
                if (!found) {
                  ygopro.stoc_die(client, '${challonge_match_not_found}');
                  return;
                }
                room = ROOM_find_or_create_by_name('M#' + found.id);
                if (room) {
                  room.challonge_info = found;
                  room.welcome = "${challonge_match_created}";
                }
                if (!room) {
                  ygopro.stoc_die(client, "${server_full}");
                } else if (room.error) {
                  ygopro.stoc_die(client, room.error);
nanahira's avatar
nanahira committed
2693
                } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
2694
                  if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
2695 2696 2697 2698 2699
                    client.rid = _.indexOf(ROOM_all, room);
                    client.is_post_watcher = true;
                    ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
                    room.watchers.push(client);
                    ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2700 2701 2702
                    ref3 = room.watcher_buffers;
                    for (n = 0, len3 = ref3.length; n < len3; n++) {
                      buffer = ref3[n];
nanahira's avatar
nanahira committed
2703 2704 2705 2706 2707
                      client.write(buffer);
                    }
                  } else {
                    ygopro.stoc_die(client, "${watch_denied}");
                  }
nanahira's avatar
nanahira committed
2708
                } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
nanahira's avatar
fix  
nanahira committed
2709
                  ygopro.stoc_die(client, "${watch_denied_room}");
nanahira's avatar
nanahira committed
2710
                } else {
nanahira's avatar
nanahira committed
2711 2712 2713
                  ref4 = room.get_playing_player();
                  for (o = 0, len4 = ref4.length; o < len4; o++) {
                    player = ref4[o];
nanahira's avatar
nanahira committed
2714
                    if (!(player && player !== client && player.challonge_info.id === client.challonge_info.id)) {
nanahira's avatar
nanahira committed
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727
                      continue;
                    }
                    ygopro.stoc_die(client, "${challonge_player_already_in}");
                    return;
                  }
                  client.rid = _.indexOf(ROOM_all, room);
                  room.connect(client);
                }
              }
            });
          }
        });
      }
mercury233's avatar
mercury233 committed
2728
    } else if (!client.name || client.name === "") {
mercury233's avatar
mercury233 committed
2729
      ygopro.stoc_die(client, "${bad_user_name}");
mercury233's avatar
mercury233 committed
2730 2731
    } else if (ROOM_connected_ip[client.ip] > 5) {
      log.warn("MULTI LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2732
      ygopro.stoc_die(client, "${too_much_connection}" + client.ip);
mercury233's avatar
mercury233 committed
2733
    } else if (_.indexOf(settings.ban.banned_user, client.name) > -1) {
mercury233's avatar
mercury233 committed
2734
      settings.ban.banned_ip.push(client.ip);
mercury233's avatar
mercury233 committed
2735
      setting_save(settings);
mercury233's avatar
mercury233 committed
2736
      log.warn("BANNED USER LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2737
      ygopro.stoc_die(client, "${banned_user_login}");
mercury233's avatar
mercury233 committed
2738 2739
    } else if (_.indexOf(settings.ban.banned_ip, client.ip) > -1) {
      log.warn("BANNED IP LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2740
      ygopro.stoc_die(client, "${banned_ip_login}");
mercury233's avatar
mercury233 committed
2741
    } else if (_.any(badwords.level3, function(badword) {
mercury233's avatar
mercury233 committed
2742
      var regexp;
mercury233's avatar
fix  
mercury233 committed
2743
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
2744 2745
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
2746
      log.warn("BAD NAME LEVEL 3", client.name, client.ip);
mercury233's avatar
mercury233 committed
2747
      ygopro.stoc_die(client, "${bad_name_level3}");
mercury233's avatar
mercury233 committed
2748
    } else if (_.any(badwords.level2, function(badword) {
mercury233's avatar
mercury233 committed
2749
      var regexp;
mercury233's avatar
fix  
mercury233 committed
2750
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
2751 2752
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
2753
      log.warn("BAD NAME LEVEL 2", client.name, client.ip);
mercury233's avatar
mercury233 committed
2754
      ygopro.stoc_die(client, "${bad_name_level2}");
mercury233's avatar
mercury233 committed
2755
    } else if (_.any(badwords.level1, function(badword) {
mercury233's avatar
mercury233 committed
2756
      var regexp;
mercury233's avatar
fix  
mercury233 committed
2757
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
2758 2759
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
2760
      log.warn("BAD NAME LEVEL 1", client.name, client.ip);
mercury233's avatar
mercury233 committed
2761
      ygopro.stoc_die(client, "${bad_name_level1}");
mercury233's avatar
mercury233 committed
2762
    } else if (info.pass.length && !ROOM_validate(info.pass)) {
mercury233's avatar
mercury233 committed
2763
      ygopro.stoc_die(client, "${invalid_password_room}");
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2764
    } else {
mercury233's avatar
mercury233 committed
2765
      room = ROOM_find_or_create_by_name(info.pass, client.ip);
mercury233's avatar
mercury233 committed
2766
      if (!room) {
mercury233's avatar
mercury233 committed
2767
        ygopro.stoc_die(client, "${server_full}");
mercury233's avatar
mercury233 committed
2768
      } else if (room.error) {
mercury233's avatar
mercury233 committed
2769
        ygopro.stoc_die(client, room.error);
nanahira's avatar
nanahira committed
2770
      } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
2771
        if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
mercury233's avatar
mercury233 committed
2772
          client.setTimeout(300000);
2773
          client.rid = _.indexOf(ROOM_all, room);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2774
          client.is_post_watcher = true;
mercury233's avatar
mercury233 committed
2775
          ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
2776
          room.watchers.push(client);
mercury233's avatar
mercury233 committed
2777
          ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2778 2779 2780
          ref3 = room.watcher_buffers;
          for (n = 0, len3 = ref3.length; n < len3; n++) {
            buffer = ref3[n];
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2781 2782 2783
            client.write(buffer);
          }
        } else {
mercury233's avatar
mercury233 committed
2784
          ygopro.stoc_die(client, "${watch_denied}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2785
        }
nanahira's avatar
nanahira committed
2786
      } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
nanahira's avatar
nanahira committed
2787
        ygopro.stoc_die(client, "${watch_denied_room}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2788
      } else {
mercury233's avatar
mercury233 committed
2789
        client.setTimeout(300000);
2790 2791
        client.rid = _.indexOf(ROOM_all, room);
        room.connect(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2792
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2793 2794 2795
    }
  });

nanahira's avatar
nanahira committed
2796
  ygopro.stoc_follow('JOIN_GAME', false, function(buffer, info, client, server, datas) {
2797
    var len2, m, player, recorder, ref2, room, watcher;
2798
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
2799
    if (!(room && !client.reconnecting)) {
2800 2801
      return;
    }
2802 2803 2804
    if (!room.join_game_buffer) {
      room.join_game_buffer = buffer;
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2805
    if (settings.modules.welcome) {
mercury233's avatar
mercury233 committed
2806
      ygopro.stoc_send_chat(client, settings.modules.welcome, ygopro.constants.COLORS.GREEN);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2807
    }
2808 2809
    if (room.welcome) {
      ygopro.stoc_send_chat(client, room.welcome, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
add  
mercury233 committed
2810
    }
2811
    if (settings.modules.arena_mode.enabled && !client.is_local) {
mercury233's avatar
mercury233 committed
2812 2813 2814 2815
      request({
        url: settings.modules.arena_mode.get_score + encodeURIComponent(client.name),
        json: true
      }, function(error, response, body) {
mercury233's avatar
merge  
mercury233 committed
2816
        var rank_txt;
mercury233's avatar
merge  
mercury233 committed
2817 2818 2819 2820
        if (error) {
          log.warn('LOAD SCORE ERROR', client.name, error);
        } else if (!body || _.isString(body)) {
          log.warn('LOAD SCORE FAIL', client.name, response.statusCode, response.statusMessage, body);
mercury233's avatar
mercury233 committed
2821
        } else {
mercury233's avatar
mercury233 committed
2822 2823
          rank_txt = body.arena_rank > 0 ? "${rank_arena}" + body.arena_rank : "${rank_blank}";
          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);
mercury233's avatar
mercury233 committed
2824 2825 2826
        }
      });
    }
2827 2828 2829 2830 2831 2832 2833 2834 2835 2836
    if (settings.modules.random_duel.record_match_scores && room.random_type === 'M') {
      ygopro.stoc_send_chat_to_room(room, ROOM_player_get_score(client), ygopro.constants.COLORS.GREEN);
      ref2 = room.players;
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        player = ref2[m];
        if (player.pos !== 7 && player !== client) {
          ygopro.stoc_send_chat(client, ROOM_player_get_score(player), ygopro.constants.COLORS.GREEN);
        }
      }
    }
2837 2838
    if (!room.recorder) {
      room.recorder = recorder = net.connect(room.port, function() {
mercury233's avatar
mercury233 committed
2839 2840 2841 2842 2843
        ygopro.ctos_send(recorder, 'PLAYER_INFO', {
          name: "Marshtomp"
        });
        ygopro.ctos_send(recorder, 'JOIN_GAME', {
          version: settings.version,
mercury233's avatar
mercury233 committed
2844
          pass: "Marshtomp"
mercury233's avatar
mercury233 committed
2845
        });
mercury233's avatar
mercury233 committed
2846
        ygopro.ctos_send(recorder, 'HS_TOOBSERVER');
mercury233's avatar
mercury233 committed
2847 2848
      });
      recorder.on('data', function(data) {
2849
        room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
2850
        if (!(room && settings.modules.cloud_replay.enabled)) {
mercury233's avatar
mercury233 committed
2851 2852
          return;
        }
mercury233's avatar
mercury233 committed
2853
        room.recorder_buffers.push(data);
mercury233's avatar
mercury233 committed
2854 2855 2856
      });
      recorder.on('error', function(error) {});
    }
nanahira's avatar
nanahira committed
2857
    if (settings.modules.cloud_replay.enable_halfway_watch && !room.watcher && !room.hostinfo.no_watch) {
2858
      room.watcher = watcher = settings.modules.test_mode.watch_public_hand ? room.recorder : net.connect(room.port, function() {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2859 2860 2861 2862 2863
        ygopro.ctos_send(watcher, 'PLAYER_INFO', {
          name: "the Big Brother"
        });
        ygopro.ctos_send(watcher, 'JOIN_GAME', {
          version: settings.version,
mercury233's avatar
mercury233 committed
2864
          pass: "the Big Brother"
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2865
        });
mercury233's avatar
mercury233 committed
2866
        ygopro.ctos_send(watcher, 'HS_TOOBSERVER');
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2867
      });
mercury233's avatar
fix  
mercury233 committed
2868
      watcher.on('data', function(data) {
2869
        var len3, n, ref3, w;
2870 2871
        room = ROOM_all[client.rid];
        if (!room) {
2872 2873
          return;
        }
2874
        room.watcher_buffers.push(data);
2875 2876 2877
        ref3 = room.watchers;
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          w = ref3[n];
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
2878
          if (w) {
mercury233's avatar
test3  
mercury233 committed
2879
            w.write(data);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
2880
          }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2881 2882
        }
      });
mercury233's avatar
test3  
mercury233 committed
2883
      watcher.on('error', function(error) {});
神楽坂玲奈's avatar
神楽坂玲奈 committed
2884
    }
神楽坂玲奈's avatar
tip  
神楽坂玲奈 committed
2885
  });
神楽坂玲奈's avatar
神楽坂玲奈 committed
2886

nanahira's avatar
nanahira committed
2887
  load_dialogues = global.load_dialogues = function() {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2888
    request({
mercury233's avatar
mercury233 committed
2889
      url: settings.modules.dialogues.get,
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2890 2891 2892
      json: true
    }, function(error, response, body) {
      if (_.isString(body)) {
mercury233's avatar
test3  
mercury233 committed
2893
        log.warn("dialogues bad json", body);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
2894
      } else if (error || !body) {
mercury233's avatar
test3  
mercury233 committed
2895
        log.warn('dialogues error', error, response);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2896
      } else {
mercury233's avatar
mercury233 committed
2897 2898
        setting_change(dialogues, "dialogues", body);
        log.info("dialogues loaded", _.size(dialogues.dialogues));
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2899 2900
      }
    });
mercury233's avatar
mercury233 committed
2901 2902
  };

mercury233's avatar
mercury233 committed
2903
  if (settings.modules.dialogues.get) {
mercury233's avatar
mercury233 committed
2904
    load_dialogues();
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2905 2906
  }

nanahira's avatar
nanahira committed
2907
  ygopro.stoc_follow('GAME_MSG', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
2908
    var card, chain, check, count, cpos, deck_found, found, hint_type, i, id, len2, len3, len4, len5, limbo_found, line, loc, m, max_loop, msg, n, o, oppo_pos, p, phase, player, playertype, pos, ppos, q, reason, ref2, ref3, ref4, ref5, ref6, ref7, room, trigger_location, val, win_pos;
2909
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
2910
    if (!(room && !client.reconnecting)) {
2911 2912
      return;
    }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2913
    msg = buffer.readInt8(0);
nanahira's avatar
nanahira committed
2914 2915 2916 2917 2918 2919 2920 2921 2922 2923
    if (settings.modules.retry_handle.enabled) {
      if (ygopro.constants.MSG[msg] === 'RETRY') {
        if (client.retry_count == null) {
          client.retry_count = 0;
        }
        client.retry_count++;
        log.warn("MSG_RETRY detected", client.name, client.ip, msg, client.retry_count);
        if (settings.modules.retry_handle.max_retry_count && client.retry_count >= settings.modules.retry_handle.max_retry_count) {
          ygopro.stoc_send_chat_to_room(room, client.name + "${retry_too_much_room_part1}" + settings.modules.retry_handle.max_retry_count + "${retry_too_much_room_part2}", ygopro.constants.COLORS.BABYBLUE);
          ygopro.stoc_send_chat(client, "${retry_too_much_part1}" + settings.modules.retry_handle.max_retry_count + "${retry_too_much_part2}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
2924
          CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
2925
          CLIENT_kick(client);
nanahira's avatar
nanahira committed
2926 2927 2928 2929 2930 2931 2932 2933
          return true;
        }
        if (client.last_game_msg) {
          if (settings.modules.retry_handle.max_retry_count) {
            ygopro.stoc_send_chat(client, "${retry_part1}" + client.retry_count + "${retry_part2}" + settings.modules.retry_handle.max_retry_count + "${retry_part3}", ygopro.constants.COLORS.RED);
          } else {
            ygopro.stoc_send_chat(client, "${retry_not_counted}", ygopro.constants.COLORS.BABYBLUE);
          }
nanahira's avatar
nanahira committed
2934 2935 2936
          if (client.last_hint_msg) {
            ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg);
          }
nanahira's avatar
nanahira committed
2937 2938 2939 2940 2941
          ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg);
          return true;
        }
      } else {
        client.last_game_msg = buffer;
nanahira's avatar
nanahira committed
2942
        client.last_game_msg_title = ygopro.constants.MSG[msg];
nanahira's avatar
nanahira committed
2943
      }
nanahira's avatar
nanahira committed
2944 2945 2946
    } else if (ygopro.constants.MSG[msg] !== 'RETRY') {
      client.last_game_msg = buffer;
      client.last_game_msg_title = ygopro.constants.MSG[msg];
nanahira's avatar
nanahira committed
2947
    }
nanahira's avatar
fix  
nanahira committed
2948
    if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) {
2949 2950
      room.waiting_for_player = client;
      room.last_active_time = moment();
2951
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2952 2953 2954
    if (ygopro.constants.MSG[msg] === 'START') {
      playertype = buffer.readUInt8(1);
      client.is_first = !(playertype & 0xf);
nanahira's avatar
nanahira committed
2955 2956 2957
      if (client.is_first && (room.hostinfo.mode !== 2 || client.pos === 0 || client.pos === 2)) {
        room.first_list[room.duel_count - 1] = client.name_vpass;
      }
2958
      client.lp = room.hostinfo.start_lp;
nanahira's avatar
nanahira committed
2959 2960 2961
      if (room.hostinfo.mode !== 2) {
        client.card_count = 0;
      }
nanahira's avatar
nanahira committed
2962
      room.duel_stage = ygopro.constants.DUEL_STAGE.DUELING;
nanahira's avatar
nanahira committed
2963
      if (client.pos === 0) {
2964
        room.turn = 0;
nanahira's avatar
nanahira committed
2965
        room.duel_count++;
nanahira's avatar
nanahira committed
2966 2967 2968 2969 2970 2971 2972
        if (room.death && room.duel_count > 1) {
          if (room.death === -1) {
            ygopro.stoc_send_chat_to_room(room, "${death_start_final}", ygopro.constants.COLORS.BABYBLUE);
          } else {
            ygopro.stoc_send_chat_to_room(room, "${death_start_extra}", ygopro.constants.COLORS.BABYBLUE);
          }
        }
nanahira's avatar
fix  
nanahira committed
2973
      }
nanahira's avatar
nanahira committed
2974 2975 2976 2977
      if (settings.modules.retry_handle.enabled) {
        client.retry_count = 0;
        client.last_game_msg = null;
      }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2978
    }
nanahira's avatar
nanahira committed
2979 2980
    if (ygopro.constants.MSG[msg] === 'HINT') {
      hint_type = buffer.readUInt8(1);
nanahira's avatar
typo  
nanahira committed
2981
      if (hint_type === 3) {
nanahira's avatar
nanahira committed
2982 2983 2984
        client.last_hint_msg = buffer;
      }
    }
2985
    if (ygopro.constants.MSG[msg] === 'NEW_TURN') {
nanahira's avatar
nanahira committed
2986
      if (client.pos === 0) {
nanahira's avatar
nanahira committed
2987
        room.turn++;
nanahira's avatar
nanahira committed
2988
        if (room.death && room.death !== -2) {
nanahira's avatar
nanahira committed
2989
          if (room.turn >= room.death) {
nanahira's avatar
nanahira committed
2990 2991 2992
            oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
            if (room.dueling_players[0].lp !== room.dueling_players[oppo_pos].lp && room.turn > 1) {
              win_pos = room.dueling_players[0].lp > room.dueling_players[oppo_pos].lp ? 0 : oppo_pos;
nanahira's avatar
nanahira committed
2993
              ygopro.stoc_send_chat_to_room(room, "${death_finish_part1}" + room.dueling_players[win_pos].name + "${death_finish_part2}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2994
              if (room.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
2995
                room.finished_by_death = true;
nanahira's avatar
nanahira committed
2996 2997
                ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos], 'DUEL_END');
                ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos + 1], 'DUEL_END');
2998
                room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
2999 3000
                CLIENT_kick(room.dueling_players[oppo_pos - win_pos]);
                CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]);
nanahira's avatar
nanahira committed
3001 3002 3003
              } else {
                ygopro.ctos_send(room.dueling_players[oppo_pos - win_pos].server, 'SURRENDER');
              }
nanahira's avatar
nanahira committed
3004
            } else {
nanahira's avatar
nanahira committed
3005
              room.death = -1;
nanahira's avatar
nanahira committed
3006 3007 3008 3009 3010 3011
              ygopro.stoc_send_chat_to_room(room, "${death_remain_final}", ygopro.constants.COLORS.BABYBLUE);
            }
          } else {
            ygopro.stoc_send_chat_to_room(room, "${death_remain_part1}" + (room.death - room.turn) + "${death_remain_part2}", ygopro.constants.COLORS.BABYBLUE);
          }
        }
3012 3013 3014 3015 3016
      }
      if (client.surrend_confirm) {
        client.surrend_confirm = false;
        ygopro.stoc_send_chat(client, "${surrender_canceled}", ygopro.constants.COLORS.BABYBLUE);
      }
mercury233's avatar
mercury233 committed
3017
    }
nanahira's avatar
nanahira committed
3018 3019 3020
    if (ygopro.constants.MSG[msg] === 'NEW_PHASE') {
      phase = buffer.readInt16LE(1);
      oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
nanahira's avatar
fix  
nanahira committed
3021 3022 3023 3024 3025
      if (client.pos === 0 && room.death === -2 && !(phase === 0x1 && room.turn < 2)) {
        if (room.dueling_players[0].lp !== room.dueling_players[oppo_pos].lp) {
          win_pos = room.dueling_players[0].lp > room.dueling_players[oppo_pos].lp ? 0 : oppo_pos;
          ygopro.stoc_send_chat_to_room(room, "${death_finish_part1}" + room.dueling_players[win_pos].name + "${death_finish_part2}", ygopro.constants.COLORS.BABYBLUE);
          if (room.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
3026
            room.finished_by_death = true;
nanahira's avatar
fix  
nanahira committed
3027 3028
            ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos], 'DUEL_END');
            ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos + 1], 'DUEL_END');
3029
            room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
3030 3031
            CLIENT_kick(room.dueling_players[oppo_pos - win_pos]);
            CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]);
nanahira's avatar
fix  
nanahira committed
3032 3033 3034
          } else {
            ygopro.ctos_send(room.dueling_players[oppo_pos - win_pos].server, 'SURRENDER');
          }
nanahira's avatar
nanahira committed
3035
        } else {
nanahira's avatar
fix  
nanahira committed
3036 3037
          room.death = -1;
          ygopro.stoc_send_chat_to_room(room, "${death_remain_final}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
3038 3039 3040
        }
      }
    }
nanahira's avatar
nanahira committed
3041
    if (ygopro.constants.MSG[msg] === 'WIN' && client.pos === 0) {
mercury233's avatar
mercury233 committed
3042
      pos = buffer.readUInt8(1);
nanahira's avatar
nanahira committed
3043
      if (!(client.is_first || pos === 2 || room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING)) {
mercury233's avatar
mercury233 committed
3044 3045
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3046 3047 3048
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
mercury233's avatar
mercury233 committed
3049 3050
      reason = buffer.readUInt8(2);
      room.winner = pos;
nanahira's avatar
nanahira committed
3051
      room.turn = 0;
nanahira's avatar
nanahira committed
3052
      room.duel_stage = ygopro.constants.DUEL_STAGE.END;
nanahira's avatar
nanahira committed
3053 3054 3055 3056
      if (settings.modules.heartbeat_detection.enabled) {
        ref2 = room.players;
        for (m = 0, len2 = ref2.length; m < len2; m++) {
          player = ref2[m];
3057
          player.heartbeat_protected = false;
nanahira's avatar
nanahira committed
3058
        }
nanahira's avatar
nanahira committed
3059 3060
        delete room.long_resolve_card;
        delete room.long_resolve_chain;
nanahira's avatar
nanahira committed
3061
      }
mercury233's avatar
fix  
mercury233 committed
3062
      if (room && !room.finished && room.dueling_players[pos]) {
3063
        room.winner_name = room.dueling_players[pos].name_vpass;
mercury233's avatar
mercury233 committed
3064
        room.scores[room.winner_name] = room.scores[room.winner_name] + 1;
nanahira's avatar
nanahira committed
3065 3066 3067 3068
        if (room.match_kill) {
          room.match_kill = false;
          room.scores[room.winner_name] = 99;
        }
mercury233's avatar
mercury233 committed
3069
      }
nanahira's avatar
fix  
nanahira committed
3070
      if (room.death) {
nanahira's avatar
nanahira committed
3071
        if (settings.modules.http.quick_death_rule === 1 || settings.modules.http.quick_death_rule === 3) {
nanahira's avatar
fix  
nanahira committed
3072 3073 3074 3075 3076
          room.death = -1;
        } else {
          room.death = 5;
        }
      }
mercury233's avatar
mercury233 committed
3077
    }
nanahira's avatar
nanahira committed
3078 3079 3080
    if (ygopro.constants.MSG[msg] === 'MATCH_KILL' && client.pos === 0) {
      room.match_kill = true;
    }
nanahira's avatar
nanahira committed
3081
    if (ygopro.constants.MSG[msg] === 'DAMAGE' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3082 3083 3084 3085
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3086 3087 3088
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3089
      val = buffer.readInt32LE(2);
3090
      room.dueling_players[pos].lp -= val;
nanahira's avatar
fix  
nanahira committed
3091 3092 3093
      if (room.dueling_players[pos].lp < 0) {
        room.dueling_players[pos].lp = 0;
      }
nanahira's avatar
nanahira committed
3094
      if ((0 < (ref3 = room.dueling_players[pos].lp) && ref3 <= 100)) {
mercury233's avatar
mercury233 committed
3095
        ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3096 3097
      }
    }
nanahira's avatar
nanahira committed
3098
    if (ygopro.constants.MSG[msg] === 'RECOVER' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3099 3100 3101 3102
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3103 3104 3105
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3106
      val = buffer.readInt32LE(2);
3107
      room.dueling_players[pos].lp += val;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3108
    }
nanahira's avatar
nanahira committed
3109
    if (ygopro.constants.MSG[msg] === 'LPUPDATE' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3110 3111 3112 3113
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3114 3115 3116
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3117
      val = buffer.readInt32LE(2);
3118
      room.dueling_players[pos].lp = val;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3119
    }
nanahira's avatar
nanahira committed
3120
    if (ygopro.constants.MSG[msg] === 'PAY_LPCOST' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3121 3122 3123 3124
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3125 3126 3127
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3128
      val = buffer.readInt32LE(2);
3129
      room.dueling_players[pos].lp -= val;
nanahira's avatar
fix  
nanahira committed
3130 3131 3132
      if (room.dueling_players[pos].lp < 0) {
        room.dueling_players[pos].lp = 0;
      }
nanahira's avatar
nanahira committed
3133
      if ((0 < (ref4 = room.dueling_players[pos].lp) && ref4 <= 100)) {
mercury233's avatar
mercury233 committed
3134
        ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3135 3136
      }
    }
nanahira's avatar
nanahira committed
3137
    if (ygopro.constants.MSG[msg] === 'MOVE' && room.hostinfo.mode !== 2) {
nanahira's avatar
nanahira committed
3138 3139 3140 3141 3142
      pos = buffer.readUInt8(5);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      loc = buffer.readUInt8(6);
nanahira's avatar
nanahira committed
3143 3144
      if ((loc & 0xe) && pos === 0) {
        client.card_count--;
nanahira's avatar
nanahira committed
3145 3146 3147 3148 3149 3150
      }
      pos = buffer.readUInt8(9);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      loc = buffer.readUInt8(10);
nanahira's avatar
nanahira committed
3151 3152
      if ((loc & 0xe) && pos === 0) {
        client.card_count++;
nanahira's avatar
nanahira committed
3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164
      }
    }
    if (ygopro.constants.MSG[msg] === 'DRAW' && room.hostinfo.mode !== 2) {
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      if (pos === 0) {
        count = buffer.readInt8(2);
        client.card_count += count;
      }
    }
nanahira's avatar
nanahira committed
3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183
    if (settings.modules.heartbeat_detection.enabled && ygopro.constants.MSG[msg] === 'CONFIRM_CARDS') {
      check = false;
      count = buffer.readInt8(2);
      max_loop = 3 + (count - 1) * 7;
      deck_found = 0;
      limbo_found = 0;
      for (i = n = 3, ref5 = max_loop; n <= ref5; i = n += 7) {
        loc = buffer.readInt8(i + 5);
        if ((loc & 0x41) > 0) {
          deck_found++;
        } else if (loc === 0) {
          limbo_found++;
        }
        if ((deck_found > 0 && count > 1) || limbo_found > 0) {
          check = true;
          break;
        }
      }
      if (check) {
3184
        client.heartbeat_protected = true;
nanahira's avatar
nanahira committed
3185 3186
      }
    }
nanahira's avatar
nanahira committed
3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227
    if (settings.modules.heartbeat_detection.enabled && client.pos === 0) {
      if (ygopro.constants.MSG[msg] === 'CHAINING') {
        card = buffer.readUInt32LE(1);
        found = false;
        for (o = 0, len3 = long_resolve_cards.length; o < len3; o++) {
          id = long_resolve_cards[o];
          if (!(id === card)) {
            continue;
          }
          found = true;
          break;
        }
        if (found) {
          room.long_resolve_card = card;
        } else {
          delete room.long_resolve_card;
        }
      } else if (ygopro.constants.MSG[msg] === 'CHAINED' && room.long_resolve_card) {
        chain = buffer.readInt8(1);
        if (!room.long_resolve_chain) {
          room.long_resolve_chain = [];
        }
        room.long_resolve_chain[chain] = true;
        delete room.long_resolve_card;
      } else if (ygopro.constants.MSG[msg] === 'CHAIN_SOLVING' && room.long_resolve_chain) {
        chain = buffer.readInt8(1);
        if (room.long_resolve_chain[chain]) {
          ref6 = room.get_playing_player();
          for (p = 0, len4 = ref6.length; p < len4; p++) {
            player = ref6[p];
            player.heartbeat_protected = true;
          }
        }
      } else if ((ygopro.constants.MSG[msg] === 'CHAIN_NEGATED' || ygopro.constants.MSG[msg] === 'CHAIN_DISABLED') && room.long_resolve_chain) {
        chain = buffer.readInt8(1);
        delete room.long_resolve_chain[chain];
      } else if (ygopro.constants.MSG[msg] === 'CHAIN_END') {
        delete room.long_resolve_card;
        delete room.long_resolve_chain;
      }
    }
mercury233's avatar
mercury233 committed
3228
    if (settings.modules.dialogues.enabled) {
nanahira's avatar
nanahira committed
3229
      if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING' || ygopro.constants.MSG[msg] === 'CHAINING') {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3230
        card = buffer.readUInt32LE(1);
nanahira's avatar
fix  
nanahira committed
3231
        trigger_location = buffer.readUInt8(6);
nanahira's avatar
nanahira committed
3232
        if (dialogues.dialogues[card] && (ygopro.constants.MSG[msg] !== 'CHAINING' || (trigger_location & 0x8) && client.ready_trap)) {
nanahira's avatar
nanahira committed
3233 3234 3235
          ref7 = _.lines(dialogues.dialogues[card][Math.floor(Math.random() * dialogues.dialogues[card].length)]);
          for (q = 0, len5 = ref7.length; q < len5; q++) {
            line = ref7[q];
mercury233's avatar
mercury233 committed
3236
            ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3237
          }
神楽坂玲奈's avatar
神楽坂玲奈 committed
3238
        }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
3239
      }
nanahira's avatar
nanahira committed
3240 3241 3242 3243 3244 3245 3246 3247
      if (ygopro.constants.MSG[msg] === 'POS_CHANGE') {
        loc = buffer.readUInt8(6);
        ppos = buffer.readUInt8(8);
        cpos = buffer.readUInt8(9);
        client.ready_trap = !!(loc & 0x8) && !!(ppos & 0xa) && !!(cpos & 0x5);
      } else if (ygopro.constants.MSG[msg] !== 'UPDATE_CARD' && ygopro.constants.MSG[msg] !== 'WAITING') {
        client.ready_trap = false;
      }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
3248
    }
nanahira's avatar
nanahira committed
3249
    return false;
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
3250 3251
  });

nanahira's avatar
nanahira committed
3252
  ygopro.ctos_follow('HS_TOOBSERVER', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3253
    var len2, m, player, ref2, room;
3254 3255 3256 3257
    room = ROOM_all[client.rid];
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
3258
    if (room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
3259 3260 3261
      ygopro.stoc_send_chat(client, "${watch_denied_room}", ygopro.constants.COLORS.RED);
      return true;
    }
nanahira's avatar
nanahira committed
3262
    if ((!room.arena && !settings.modules.challonge.enabled) || client.is_local) {
3263 3264
      return false;
    }
nanahira's avatar
nanahira committed
3265
    ref2 = room.players;
nanahira's avatar
nanahira committed
3266 3267
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
3268 3269 3270 3271 3272 3273 3274
      if (player === client) {
        ygopro.stoc_send_chat(client, "${cannot_to_observer}", ygopro.constants.COLORS.BABYBLUE);
        return true;
      }
    }
    return false;
  });
nanahira's avatar
js  
nanahira committed
3275

nanahira's avatar
nanahira committed
3276
  ygopro.ctos_follow('HS_KICK', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3277
    var len2, m, player, ref2, room;
3278 3279
    room = ROOM_all[client.rid];
    if (!room) {
3280 3281
      return;
    }
nanahira's avatar
nanahira committed
3282
    ref2 = room.players;
nanahira's avatar
nanahira committed
3283 3284
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
mercury233's avatar
mercury233 committed
3285
      if (player && player.pos === info.pos && player !== client) {
nanahira's avatar
nanahira committed
3286
        if (room.arena === "athletic" || settings.modules.challonge.enabled) {
3287
          ygopro.stoc_send_chat_to_room(room, client.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3288
          CLIENT_kick(client);
3289 3290
          return true;
        }
mercury233's avatar
mercury233 committed
3291
        client.kick_count = client.kick_count ? client.kick_count + 1 : 1;
mercury233's avatar
fix  
mercury233 committed
3292
        if (client.kick_count >= 5 && room.random_type) {
mercury233's avatar
mercury233 committed
3293
          ygopro.stoc_send_chat_to_room(room, client.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3294
          ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
nanahira's avatar
nanahira committed
3295
          CLIENT_kick(client);
mercury233's avatar
mercury233 committed
3296 3297
          return true;
        }
mercury233's avatar
mercury233 committed
3298
        ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_player}", ygopro.constants.COLORS.RED);
3299 3300 3301 3302 3303
      }
    }
    return false;
  });

nanahira's avatar
nanahira committed
3304
  ygopro.stoc_follow('TYPE_CHANGE', true, function(buffer, info, client, server, datas) {
神楽坂玲奈's avatar
神楽坂玲奈 committed
3305 3306 3307 3308
    var is_host, selftype;
    selftype = info.type & 0xf;
    is_host = ((info.type >> 4) & 0xf) !== 0;
    client.is_host = is_host;
mercury233's avatar
test3  
mercury233 committed
3309
    client.pos = selftype;
nanahira's avatar
nanahira committed
3310
    return false;
神楽坂玲奈's avatar
神楽坂玲奈 committed
3311 3312
  });

3313 3314 3315
  ygopro.stoc_follow('HS_PLAYER_ENTER', true, function(buffer, info, client, server, datas) {
    var pos, room, struct;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
3316
    if (!(room && settings.modules.hide_name && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN)) {
3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328
      return false;
    }
    pos = info.pos;
    if (pos < 4 && pos !== client.pos) {
      struct = ygopro.structs["STOC_HS_PlayerEnter"];
      struct._setBuff(buffer);
      struct.set("name", "********");
      buffer = struct.buffer;
    }
    return false;
  });

nanahira's avatar
nanahira committed
3329
  ygopro.stoc_follow('HS_PLAYER_CHANGE', false, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3330
    var is_ready, len2, len3, m, n, p1, p2, player, pos, ref2, ref3, room;
3331 3332
    room = ROOM_all[client.rid];
    if (!(room && room.max_player && client.is_host)) {
3333 3334 3335 3336
      return;
    }
    pos = info.status >> 4;
    is_ready = (info.status & 0xf) === 9;
3337
    if (pos < room.max_player) {
3338 3339
      if (room.arena) {
        room.ready_player_count = 0;
nanahira's avatar
nanahira committed
3340
        ref2 = room.players;
nanahira's avatar
nanahira committed
3341 3342
        for (m = 0, len2 = ref2.length; m < len2; m++) {
          player = ref2[m];
3343 3344 3345
          if (player.pos === pos) {
            player.is_ready = is_ready;
          }
3346
        }
3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368
        p1 = room.players[0];
        p2 = room.players[1];
        if (!p1 || !p2) {
          if (room.waiting_for_player_interval) {
            clearInterval(room.waiting_for_player_interval);
            room.waiting_for_player_interval = null;
          }
          return;
        }
        room.waiting_for_player2 = room.waiting_for_player;
        room.waiting_for_player = null;
        if (p1.is_ready && p2.is_ready) {
          room.waiting_for_player = p1.is_host ? p1 : p2;
        }
        if (!p1.is_ready && p2.is_ready) {
          room.waiting_for_player = p1;
        }
        if (!p2.is_ready && p1.is_ready) {
          room.waiting_for_player = p2;
        }
        if (room.waiting_for_player !== room.waiting_for_player2) {
          room.waiting_for_player2 = room.waiting_for_player;
nanahira's avatar
nanahira committed
3369
          room.waiting_for_player_time = settings.modules.arena_mode.ready_time;
3370 3371 3372 3373 3374 3375
          room.waiting_for_player_interval = setInterval((function() {
            wait_room_start_arena(ROOM_all[client.rid]);
          }), 1000);
        } else if (!room.waiting_for_player && room.waiting_for_player_interval) {
          clearInterval(room.waiting_for_player_interval);
          room.waiting_for_player_interval = null;
nanahira's avatar
nanahira committed
3376
          room.waiting_for_player_time = settings.modules.arena_mode.ready_time;
3377 3378 3379
        }
      } else {
        room.ready_player_count_without_host = 0;
nanahira's avatar
nanahira committed
3380
        ref3 = room.players;
nanahira's avatar
nanahira committed
3381 3382
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          player = ref3[n];
3383 3384 3385 3386 3387 3388 3389 3390 3391
          if (player.pos === pos) {
            player.is_ready = is_ready;
          }
          if (!player.is_host) {
            room.ready_player_count_without_host += player.is_ready;
          }
        }
        if (room.ready_player_count_without_host >= room.max_player - 1) {
          setTimeout((function() {
nanahira's avatar
nanahira committed
3392
            wait_room_start(ROOM_all[client.rid], settings.modules.random_duel.ready_time);
3393
          }), 1000);
3394 3395 3396 3397 3398
        }
      }
    }
  });

nanahira's avatar
nanahira committed
3399
  ygopro.ctos_follow('REQUEST_FIELD', true, function(buffer, info, client, server, datas) {
3400 3401 3402
    return true;
  });

nanahira's avatar
nanahira committed
3403
  ygopro.stoc_follow('FIELD_FINISH', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3404 3405
    var room;
    room = ROOM_all[client.rid];
3406
    if (!(room && settings.modules.reconnect.enabled)) {
nanahira's avatar
nanahira committed
3407 3408
      return true;
    }
3409
    client.reconnecting = false;
3410 3411 3412
    if (client.time_confirm_required) {
      client.waiting_for_last = true;
    } else if (client.last_game_msg && client.last_game_msg_title !== 'WAITING') {
3413 3414 3415 3416
      if (client.last_hint_msg) {
        ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg);
      }
      ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg);
nanahira's avatar
nanahira committed
3417 3418 3419 3420
    }
    return true;
  });

3421
  ygopro.stoc_follow('DUEL_END', false, function(buffer, info, client, server, datas) {
nanahira's avatar
js  
nanahira committed
3422
    var len2, len3, m, n, player, ref2, ref3, results, room;
nanahira's avatar
move  
nanahira committed
3423 3424 3425 3426
    room = ROOM_all[client.rid];
    if (!(room && settings.modules.replay_delay && room.hostinfo.mode === 1)) {
      return;
    }
3427
    SOCKET_flush_data(client, datas);
nanahira's avatar
move  
nanahira committed
3428
    CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
3429
    if (!room.replays_sent_to_watchers) {
nanahira's avatar
move  
nanahira committed
3430
      room.replays_sent_to_watchers = true;
nanahira's avatar
js  
nanahira committed
3431
      ref2 = room.players;
nanahira's avatar
move  
nanahira committed
3432 3433
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        player = ref2[m];
nanahira's avatar
js  
nanahira committed
3434 3435 3436 3437 3438 3439 3440 3441
        if (player && player.pos > 3) {
          CLIENT_send_replays(player, room);
        }
      }
      ref3 = room.watchers;
      results = [];
      for (n = 0, len3 = ref3.length; n < len3; n++) {
        player = ref3[n];
nanahira's avatar
move  
nanahira committed
3442 3443 3444 3445 3446 3447 3448 3449
        if (player) {
          results.push(CLIENT_send_replays(player, room));
        }
      }
      return results;
    }
  });

3450
  wait_room_start = function(room, time) {
nanahira's avatar
nanahira committed
3451
    var len2, m, player, ref2;
nanahira's avatar
nanahira committed
3452
    if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.ready_player_count_without_host >= room.max_player - 1) {
3453 3454 3455
      time -= 1;
      if (time) {
        if (!(time % 5)) {
mercury233's avatar
mercury233 committed
3456
          ygopro.stoc_send_chat_to_room(room, "" + (time <= 9 ? ' ' : '') + time + "${kick_count_down}", time <= 9 ? ygopro.constants.COLORS.RED : ygopro.constants.COLORS.LIGHTBLUE);
3457 3458 3459 3460 3461
        }
        setTimeout((function() {
          wait_room_start(room, time);
        }), 1000);
      } else {
nanahira's avatar
nanahira committed
3462
        ref2 = room.players;
nanahira's avatar
nanahira committed
3463 3464
        for (m = 0, len2 = ref2.length; m < len2; m++) {
          player = ref2[m];
mercury233's avatar
fix  
mercury233 committed
3465
          if (player && player.is_host) {
mercury233's avatar
mercury233 committed
3466
            ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
mercury233's avatar
mercury233 committed
3467
            ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3468
            CLIENT_kick(player);
3469 3470 3471 3472 3473 3474
          }
        }
      }
    }
  };

3475
  wait_room_start_arena = function(room) {
nanahira's avatar
fix  
nanahira committed
3476
    var display_name, len2, m, player, ref2;
nanahira's avatar
nanahira committed
3477
    if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.waiting_for_player) {
3478 3479 3480
      room.waiting_for_player_time = room.waiting_for_player_time - 1;
      if (room.waiting_for_player_time > 0) {
        if (!(room.waiting_for_player_time % 5)) {
nanahira's avatar
fix  
nanahira committed
3481 3482 3483 3484 3485 3486 3487 3488 3489
          ref2 = room.players;
          for (m = 0, len2 = ref2.length; m < len2; m++) {
            player = ref2[m];
            if (!(player)) {
              continue;
            }
            display_name = (settings.modules.hide_name && player !== room.waiting_for_player ? "********" : room.waiting_for_player.name);
            ygopro.stoc_send_chat(player, "" + (room.waiting_for_player_time <= 9 ? ' ' : '') + room.waiting_for_player_time + "${kick_count_down_arena_part1} " + display_name + " ${kick_count_down_arena_part2}", room.waiting_for_player_time <= 9 ? ygopro.constants.COLORS.RED : ygopro.constants.COLORS.LIGHTBLUE);
          }
3490 3491 3492
        }
      } else {
        ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3493
        CLIENT_kick(room.waiting_for_player);
3494 3495 3496 3497 3498 3499 3500 3501
        if (room.waiting_for_player_interval) {
          clearInterval(room.waiting_for_player_interval);
          room.waiting_for_player_interval = null;
        }
      }
    }
  };

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3502
  ygopro.stoc_send_random_tip = function(client) {
mercury233's avatar
mercury233 committed
3503 3504
    if (settings.modules.tips.enabled && tips.tips.length) {
      ygopro.stoc_send_chat(client, "Tip: " + tips.tips[Math.floor(Math.random() * tips.tips.length)]);
神楽坂玲奈's avatar
神楽坂玲奈 committed
3505
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3506 3507
  };

3508
  ygopro.stoc_send_random_tip_to_room = function(room) {
mercury233's avatar
mercury233 committed
3509 3510
    if (settings.modules.tips.enabled && tips.tips.length) {
      ygopro.stoc_send_chat_to_room(room, "Tip: " + tips.tips[Math.floor(Math.random() * tips.tips.length)]);
3511 3512 3513
    }
  };

nanahira's avatar
nanahira committed
3514
  load_tips = global.load_tips = function() {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3515
    request({
mercury233's avatar
mercury233 committed
3516
      url: settings.modules.tips.get,
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3517 3518
      json: true
    }, function(error, response, body) {
mercury233's avatar
mercury233 committed
3519 3520 3521 3522 3523
      if (_.isString(body)) {
        log.warn("tips bad json", body);
      } else if (error || !body) {
        log.warn('tips error', error, response);
      } else {
mercury233's avatar
mercury233 committed
3524 3525
        setting_change(tips, "tips", body);
        log.info("tips loaded", tips.tips.length);
mercury233's avatar
mercury233 committed
3526
      }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3527
    });
mercury233's avatar
mercury233 committed
3528 3529
  };

mercury233's avatar
mercury233 committed
3530
  if (settings.modules.tips.get) {
mercury233's avatar
mercury233 committed
3531 3532
    load_tips();
    setInterval(function() {
nanahira's avatar
nanahira committed
3533 3534 3535
      var len2, m, room;
      for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
        room = ROOM_all[m];
3536
        if (room && room.established) {
nanahira's avatar
nanahira committed
3537
          if (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING || room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) {
3538 3539
            ygopro.stoc_send_random_tip_to_room(room);
          }
mercury233's avatar
mercury233 committed
3540 3541 3542
        }
      }
    }, 30000);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3543
  }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3544

nanahira's avatar
nanahira committed
3545
  ygopro.stoc_follow('DUEL_START', false, function(buffer, info, client, server, datas) {
3546
    var deck_arena, deck_name, deck_text, len2, len3, m, n, player, ref2, ref3, room;
3547
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
3548
    if (!(room && !client.reconnecting)) {
3549 3550
      return;
    }
nanahira's avatar
nanahira committed
3551 3552
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) {
      room.duel_stage = ygopro.constants.DUEL_STAGE.FINGER;
mercury233's avatar
mercury233 committed
3553
      room.start_time = moment().format();
nanahira's avatar
nanahira committed
3554
      room.turn = 0;
mercury233's avatar
mercury233 committed
3555
      if (!room.windbot && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
3556
        roomlist.start(room);
神楽坂玲奈's avatar
神楽坂玲奈 committed
3557
      }
3558
      room.dueling_players = [];
nanahira's avatar
nanahira committed
3559
      ref2 = room.players;
nanahira's avatar
nanahira committed
3560 3561
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        player = ref2[m];
mercury233's avatar
mercury233 committed
3562 3563
        if (!(player.pos !== 7)) {
          continue;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3564
        }
3565
        room.dueling_players[player.pos] = player;
3566
        room.scores[player.name_vpass] = 0;
3567
        room.player_datas.push({
3568
          key: CLIENT_get_authorize_key(player),
mercury233's avatar
mercury233 committed
3569 3570
          name: player.name
        });
mercury233's avatar
mercury233 committed
3571 3572 3573
        if (room.random_type === 'T') {
          ROOM_players_oppentlist[player.ip] = null;
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3574
      }
3575 3576 3577
      if (room.hostinfo.auto_death) {
        ygopro.stoc_send_chat_to_room(room, "${auto_death_part1}" + room.hostinfo.auto_death + "${auto_death_part2}", ygopro.constants.COLORS.BABYBLUE);
      }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3578
    }
3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590
    if (settings.modules.hide_name && room.duel_count === 0) {
      ref3 = room.get_playing_player();
      for (n = 0, len3 = ref3.length; n < len3; n++) {
        player = ref3[n];
        if (player !== client) {
          ygopro.stoc_send(client, 'HS_PLAYER_ENTER', {
            name: player.name,
            pos: player.pos
          });
        }
      }
    }
mercury233's avatar
mercury233 committed
3591
    if (settings.modules.tips.enabled) {
mercury233's avatar
test3  
mercury233 committed
3592
      ygopro.stoc_send_random_tip(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3593
    }
nanahira's avatar
nanahira committed
3594 3595
    deck_text = null;
    if (client.main && client.main.length) {
mercury233's avatar
mercury233 committed
3596
      deck_text = '#ygopro-server deck log\n#main\n' + client.main.join('\n') + '\n!side\n' + client.side.join('\n') + '\n';
nanahira's avatar
nanahira committed
3597 3598 3599
      room.decks[client.name] = deck_text;
    }
    if (settings.modules.deck_log.enabled && deck_text && !client.deck_saved && !room.windbot) {
mercury233's avatar
mercury233 committed
3600 3601 3602 3603 3604 3605 3606 3607
      deck_arena = settings.modules.deck_log.arena + '-';
      if (room.arena) {
        deck_arena = deck_arena + room.arena;
      } else if (room.hostinfo.mode === 2) {
        deck_arena = deck_arena + 'tag';
      } else if (room.random_type === 'S') {
        deck_arena = deck_arena + 'entertain';
      } else if (room.random_type === 'M') {
mercury233's avatar
mercury233 committed
3608
        deck_arena = deck_arena + 'athletic';
mercury233's avatar
mercury233 committed
3609 3610 3611
      } else {
        deck_arena = deck_arena + 'custom';
      }
mercury233's avatar
mercury233 committed
3612
      if (settings.modules.deck_log.local) {
nanahira's avatar
nanahira committed
3613
        deck_name = moment().format('YYYY-MM-DD HH-mm-ss') + ' ' + room.process_pid + ' ' + client.pos + ' ' + client.ip.slice(7) + ' ' + client.name.replace(/[\/\\\?\*]/g, '_');
mercury233's avatar
mercury233 committed
3614
        fs.writeFile(settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', function(err) {
mercury233's avatar
mercury233 committed
3615 3616 3617 3618 3619
          if (err) {
            return log.warn('DECK SAVE ERROR', err);
          }
        });
      }
mercury233's avatar
mercury233 committed
3620
      if (settings.modules.deck_log.post) {
mercury233's avatar
mercury233 committed
3621
        request.post({
mercury233's avatar
mercury233 committed
3622
          url: settings.modules.deck_log.post,
mercury233's avatar
mercury233 committed
3623
          form: {
mercury233's avatar
mercury233 committed
3624
            accesskey: settings.modules.deck_log.accesskey,
mercury233's avatar
mercury233 committed
3625 3626
            deck: deck_text,
            playername: client.name,
mercury233's avatar
mercury233 committed
3627
            arena: deck_arena
mercury233's avatar
mercury233 committed
3628 3629 3630
          }
        }, function(error, response, body) {
          if (error) {
mercury233's avatar
merge  
mercury233 committed
3631
            log.warn('DECK POST ERROR', error);
mercury233's avatar
mercury233 committed
3632 3633
          } else {
            if (response.statusCode !== 200) {
mercury233's avatar
merge  
mercury233 committed
3634
              log.warn('DECK POST FAIL', response.statusCode, client.name, body);
mercury233's avatar
mercury233 committed
3635 3636 3637 3638
            }
          }
        });
      }
mercury233's avatar
mercury233 committed
3639 3640
      client.deck_saved = true;
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3641 3642
  });

nanahira's avatar
nanahira committed
3643
  ygopro.ctos_follow('SURRENDER', true, function(buffer, info, client, server, datas) {
3644 3645 3646 3647 3648
    var room;
    room = ROOM_all[client.rid];
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
3649
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || room.hostinfo.mode === 2) {
3650 3651
      return true;
    }
3652
    if (room.random_type && room.turn < 3 && !client.flee_free && !settings.modules.test_mode.surrender_anytime && !(room.random_type === 'M' && settings.modules.random_duel.record_match_scores)) {
3653 3654 3655 3656 3657 3658
      ygopro.stoc_send_chat(client, "${surrender_denied}", ygopro.constants.COLORS.BABYBLUE);
      return true;
    }
    return false;
  });

nanahira's avatar
nanahira committed
3659
  report_to_big_brother = global.report_to_big_brother = function(roomname, sender, ip, level, content, match) {
mercury233's avatar
mercury233 committed
3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684
    if (!settings.modules.big_brother.enabled) {
      return;
    }
    request.post({
      url: settings.modules.big_brother.post,
      form: {
        accesskey: settings.modules.big_brother.accesskey,
        roomname: roomname,
        sender: sender,
        ip: ip,
        level: level,
        content: content,
        match: match
      }
    }, function(error, response, body) {
      if (error) {
        log.warn('BIG BROTHER ERROR', error);
      } else {
        if (response.statusCode !== 200) {
          log.warn('BIG BROTHER FAIL', response.statusCode, roomname, body);
        }
      }
    });
  };

nanahira's avatar
nanahira committed
3685
  ygopro.ctos_follow('CHAT', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3686
    var cancel, ccolor, cip, cmd, cmsg, cname, color, cvalue, msg, name, oldmsg, ref2, room, struct, windbot;
3687 3688
    room = ROOM_all[client.rid];
    if (!room) {
mercury233's avatar
mercury233 committed
3689 3690
      return;
    }
mercury233's avatar
mercury233 committed
3691 3692
    msg = _.trim(info.msg);
    cancel = _.startsWith(msg, "/");
3693
    if (!(cancel || !(room.random_type || room.arena) || room.duel_stage === ygopro.constants.DUEL_STAGE.FINGER || room.duel_stage === ygopro.constants.DUEL_STAGE.FIRSTGO || room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING)) {
3694
      room.last_active_time = moment();
3695
    }
mercury233's avatar
mercury233 committed
3696 3697
    cmd = msg.split(' ');
    switch (cmd[0]) {
mercury233's avatar
mercury233 committed
3698 3699
      case '/投降':
      case '/surrender':
nanahira's avatar
nanahira committed
3700
        if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || room.hostinfo.mode === 2) {
mercury233's avatar
mercury233 committed
3701 3702
          return cancel;
        }
3703
        if (room.random_type && room.turn < 3) {
mercury233's avatar
mercury233 committed
3704 3705 3706 3707 3708 3709 3710 3711 3712 3713
          ygopro.stoc_send_chat(client, "${surrender_denied}", ygopro.constants.COLORS.BABYBLUE);
          return cancel;
        }
        if (client.surrend_confirm) {
          ygopro.ctos_send(client.server, 'SURRENDER');
        } else {
          ygopro.stoc_send_chat(client, "${surrender_confirm}", ygopro.constants.COLORS.BABYBLUE);
          client.surrend_confirm = true;
        }
        break;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3714
      case '/help':
mercury233's avatar
mercury233 committed
3715 3716
        ygopro.stoc_send_chat(client, "${chat_order_main}");
        ygopro.stoc_send_chat(client, "${chat_order_help}");
mercury233's avatar
mercury233 committed
3717
        if (!settings.modules.mycard.enabled) {
mercury233's avatar
mercury233 committed
3718
          ygopro.stoc_send_chat(client, "${chat_order_roomname}");
mercury233's avatar
merge  
mercury233 committed
3719
        }
mercury233's avatar
mercury233 committed
3720
        if (settings.modules.windbot.enabled) {
mercury233's avatar
mercury233 committed
3721
          ygopro.stoc_send_chat(client, "${chat_order_windbot}");
mercury233's avatar
mercury233 committed
3722
        }
mercury233's avatar
mercury233 committed
3723
        if (settings.modules.tips.enabled) {
mercury233's avatar
mercury233 committed
3724
          ygopro.stoc_send_chat(client, "${chat_order_tip}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3725
        }
nanahira's avatar
nanahira committed
3726 3727 3728 3729 3730 3731
        if (settings.modules.chat_color.enabled) {
          ygopro.stoc_send_chat(client, "${chat_order_chatcolor_1}");
        }
        if (settings.modules.chat_color.enabled) {
          ygopro.stoc_send_chat(client, "${chat_order_chatcolor_2}");
        }
mercury233's avatar
mercury233 committed
3732
        break;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3733
      case '/tip':
mercury233's avatar
mercury233 committed
3734
        if (settings.modules.tips.enabled) {
mercury233's avatar
test3  
mercury233 committed
3735
          ygopro.stoc_send_random_tip(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3736
        }
mercury233's avatar
mercury233 committed
3737
        break;
mercury233's avatar
mercury233 committed
3738
      case '/ai':
3739
        if (settings.modules.windbot.enabled && client.is_host && !settings.modules.challonge.enabled && !room.arena && room.random_type !== 'M') {
mercury233's avatar
mercury233 committed
3740
          if (name = cmd[1]) {
mercury233's avatar
mercury233 committed
3741
            windbot = _.sample(_.filter(windbots, function(w) {
mercury233's avatar
mercury233 committed
3742 3743 3744
              return w.name === name || w.deck === name;
            }));
            if (!windbot) {
mercury233's avatar
mercury233 committed
3745
              ygopro.stoc_send_chat(client, "${windbot_deck_not_found}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3746 3747 3748
              return;
            }
          } else {
mercury233's avatar
mercury233 committed
3749
            windbot = _.sample(windbots);
mercury233's avatar
mercury233 committed
3750
          }
mercury233's avatar
mercury233 committed
3751 3752 3753
          if (room.random_type) {
            ygopro.stoc_send_chat(client, "${windbot_disable_random_room} " + room.name, ygopro.constants.COLORS.BABYBLUE);
          }
mercury233's avatar
mercury233 committed
3754 3755 3756
          room.add_windbot(windbot);
        }
        break;
mercury233's avatar
mercury233 committed
3757
      case '/roomname':
3758
        if (room) {
mercury233's avatar
mercury233 committed
3759
          ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
3760
        }
nanahira's avatar
nanahira committed
3761 3762 3763
        break;
      case '/color':
        if (settings.modules.chat_color.enabled) {
nanahira's avatar
nanahira committed
3764
          cip = CLIENT_get_authorize_key(client);
nanahira's avatar
nanahira committed
3765 3766 3767
          if (cmsg = cmd[1]) {
            if (cmsg.toLowerCase() === "help") {
              ygopro.stoc_send_chat(client, "${show_color_list}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
3768 3769 3770
              ref2 = ygopro.constants.COLORS;
              for (cname in ref2) {
                cvalue = ref2[cname];
nanahira's avatar
nanahira committed
3771 3772 3773 3774 3775
                if (cvalue > 10) {
                  ygopro.stoc_send_chat(client, cname, cvalue);
                }
              }
            } else if (cmsg.toLowerCase() === "default") {
nanahira's avatar
fix  
nanahira committed
3776 3777
              chat_color.save_list[cip] = false;
              setting_save(chat_color);
nanahira's avatar
nanahira committed
3778 3779 3780
              ygopro.stoc_send_chat(client, "${set_chat_color_default}", ygopro.constants.COLORS.BABYBLUE);
            } else {
              ccolor = cmsg.toUpperCase();
nanahira's avatar
fix  
nanahira committed
3781 3782 3783
              if (ygopro.constants.COLORS[ccolor] && ygopro.constants.COLORS[ccolor] > 10 && ygopro.constants.COLORS[ccolor] < 20) {
                chat_color.save_list[cip] = ccolor;
                setting_save(chat_color);
nanahira's avatar
nanahira committed
3784 3785 3786 3787 3788 3789
                ygopro.stoc_send_chat(client, "${set_chat_color_part1}" + ccolor + "${set_chat_color_part2}", ygopro.constants.COLORS.BABYBLUE);
              } else {
                ygopro.stoc_send_chat(client, "${color_not_found_part1}" + ccolor + "${color_not_found_part2}", ygopro.constants.COLORS.RED);
              }
            }
          } else {
nanahira's avatar
fix  
nanahira committed
3790
            if (color = chat_color.save_list[cip]) {
nanahira's avatar
nanahira committed
3791 3792 3793 3794 3795 3796
              ygopro.stoc_send_chat(client, "${get_chat_color_part1}" + color + "${get_chat_color_part2}", ygopro.constants.COLORS.BABYBLUE);
            } else {
              ygopro.stoc_send_chat(client, "${get_chat_color_default}", ygopro.constants.COLORS.BABYBLUE);
            }
          }
        }
神楽坂玲奈's avatar
神楽坂玲奈 committed
3797
    }
mercury233's avatar
mercury233 committed
3798 3799 3800 3801 3802 3803 3804 3805
    if (msg.length > 100) {
      log.warn("SPAM WORD", client.name, client.ip, msg);
      if (client.abuse_count) {
        client.abuse_count = client.abuse_count + 2;
      }
      ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
      cancel = true;
    }
mercury233's avatar
mercury233 committed
3806
    if (!(room && (room.random_type || room.arena))) {
mercury233's avatar
mercury233 committed
3807 3808
      return cancel;
    }
nanahira's avatar
nanahira committed
3809
    if (client.abuse_count >= 5 || CLIENT_is_banned_by_mc(client)) {
mercury233's avatar
mercury233 committed
3810
      log.warn("BANNED CHAT", client.name, client.ip, msg);
nanahira's avatar
fix  
nanahira committed
3811
      ygopro.stoc_send_chat(client, "${banned_chat_tip}" + (client.ban_mc && client.ban_mc.message ? ": " + client.ban_mc.message : ""), ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3812 3813
      return true;
    }
mercury233's avatar
mercury233 committed
3814
    oldmsg = msg;
mercury233's avatar
mercury233 committed
3815
    if (_.any(badwords.level3, function(badword) {
mercury233's avatar
mercury233 committed
3816
      var regexp;
mercury233's avatar
fix  
mercury233 committed
3817
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
3818 3819
      return msg.match(regexp);
    }, msg)) {
mercury233's avatar
mercury233 committed
3820 3821
      log.warn("BAD WORD LEVEL 3", client.name, client.ip, oldmsg, RegExp.$1);
      report_to_big_brother(room.name, client.name, client.ip, 3, oldmsg, RegExp.$1);
mercury233's avatar
mercury233 committed
3822
      cancel = true;
mercury233's avatar
mercury233 committed
3823
      if (client.abuse_count > 0) {
mercury233's avatar
mercury233 committed
3824 3825 3826
        ygopro.stoc_send_chat(client, "${banned_duel_tip}", ygopro.constants.COLORS.RED);
        ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}");
        ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}", 3);
nanahira's avatar
nanahira committed
3827
        CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
3828
        CLIENT_kick(client);
mercury233's avatar
mercury233 committed
3829 3830 3831
        return true;
      } else {
        client.abuse_count = client.abuse_count + 4;
mercury233's avatar
mercury233 committed
3832
        ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3833
      }
nanahira's avatar
nanahira committed
3834
    } else if (client.rag && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
mercury233's avatar
mercury233 committed
3835 3836 3837 3838 3839 3840 3841 3842
      client.rag = false;
      cancel = true;
    } else if (_.any(settings.ban.spam_word, function(badword) {
      var regexp;
      regexp = new RegExp(badword, 'i');
      return msg.match(regexp);
    }, msg)) {
      client.abuse_count = client.abuse_count + 2;
mercury233's avatar
mercury233 committed
3843
      ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3844
      cancel = true;
mercury233's avatar
mercury233 committed
3845
    } else if (_.any(badwords.level2, function(badword) {
mercury233's avatar
mercury233 committed
3846
      var regexp;
mercury233's avatar
fix  
mercury233 committed
3847
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
3848 3849
      return msg.match(regexp);
    }, msg)) {
mercury233's avatar
mercury233 committed
3850 3851
      log.warn("BAD WORD LEVEL 2", client.name, client.ip, oldmsg, RegExp.$1);
      report_to_big_brother(room.name, client.name, client.ip, 2, oldmsg, RegExp.$1);
mercury233's avatar
mercury233 committed
3852
      client.abuse_count = client.abuse_count + 3;
mercury233's avatar
mercury233 committed
3853
      ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3854 3855
      cancel = true;
    } else {
mercury233's avatar
mercury233 committed
3856
      _.each(badwords.level1, function(badword) {
mercury233's avatar
mercury233 committed
3857
        var regexp;
mercury233's avatar
fix  
mercury233 committed
3858
        regexp = new RegExp(badword, "ig");
mercury233's avatar
mercury233 committed
3859 3860 3861
        msg = msg.replace(regexp, "**");
      }, msg);
      if (oldmsg !== msg) {
mercury233's avatar
mercury233 committed
3862 3863
        log.warn("BAD WORD LEVEL 1", client.name, client.ip, oldmsg, RegExp.$1);
        report_to_big_brother(room.name, client.name, client.ip, 1, oldmsg, RegExp.$1);
mercury233's avatar
mercury233 committed
3864
        client.abuse_count = client.abuse_count + 1;
mercury233's avatar
mercury233 committed
3865
        ygopro.stoc_send_chat(client, "${chat_warn_level1}");
mercury233's avatar
mercury233 committed
3866 3867 3868 3869
        struct = ygopro.structs["chat"];
        struct._setBuff(buffer);
        struct.set("msg", msg);
        buffer = struct.buffer;
mercury233's avatar
mercury233 committed
3870
      } else if (_.any(badwords.level0, function(badword) {
mercury233's avatar
mercury233 committed
3871 3872 3873 3874
        var regexp;
        regexp = new RegExp(badword, 'i');
        return msg.match(regexp);
      }, msg)) {
mercury233's avatar
mercury233 committed
3875 3876
        log.info("BAD WORD LEVEL 0", client.name, client.ip, oldmsg, RegExp.$1);
        report_to_big_brother(room.name, client.name, client.ip, 0, oldmsg, RegExp.$1);
mercury233's avatar
mercury233 committed
3877 3878
      }
    }
mercury233's avatar
mercury233 committed
3879 3880 3881
    if (client.abuse_count >= 2) {
      ROOM_unwelcome(room, client, "${random_ban_reason_abuse}");
    }
mercury233's avatar
mercury233 committed
3882
    if (client.abuse_count >= 5) {
mercury233's avatar
mercury233 committed
3883 3884
      ygopro.stoc_send_chat_to_room(room, client.name + " ${chat_banned}", ygopro.constants.COLORS.RED);
      ROOM_ban_player(client.name, client.ip, "${random_ban_reason_abuse}");
mercury233's avatar
mercury233 committed
3885
    }
3886
    return cancel;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3887 3888
  });

nanahira's avatar
nanahira committed
3889
  ygopro.ctos_follow('UPDATE_DECK', true, function(buffer, info, client, server, datas) {
3890
    var buff_main, buff_side, card, current_deck, deck, deck_array, deck_main, deck_side, deck_text, deckbuf, decks, found_deck, i, len2, len3, line, m, n, oppo_pos, room, struct, win_pos;
nanahira's avatar
nanahira committed
3891
    if (settings.modules.reconnect.enabled && client.pre_reconnecting) {
nanahira's avatar
nanahira committed
3892 3893 3894 3895
      if (!CLIENT_is_able_to_reconnect(client) && !CLIENT_is_able_to_kick_reconnect(client)) {
        ygopro.stoc_send_chat(client, "${reconnect_failed}", ygopro.constants.COLORS.RED);
        CLIENT_kick(client);
      } else if (CLIENT_is_able_to_reconnect(client, buffer)) {
nanahira's avatar
nanahira committed
3896
        CLIENT_reconnect(client);
nanahira's avatar
nanahira committed
3897 3898
      } else if (CLIENT_is_able_to_kick_reconnect(client, buffer)) {
        CLIENT_kick_reconnect(client, buffer);
nanahira's avatar
nanahira committed
3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910
      } else {
        ygopro.stoc_send_chat(client, "${deck_incorrect_reconnect}", ygopro.constants.COLORS.RED);
        ygopro.stoc_send(client, 'ERROR_MSG', {
          msg: 2,
          code: 0
        });
        ygopro.stoc_send(client, 'HS_PLAYER_CHANGE', {
          status: (client.pos << 4) | 0xa
        });
      }
      return true;
    }
mercury233's avatar
mercury233 committed
3911 3912 3913 3914
    room = ROOM_all[client.rid];
    if (!room) {
      return false;
    }
nanahira's avatar
nanahira committed
3915 3916 3917 3918
    if (info.mainc > 256 || info.sidec > 256) {
      CLIENT_kick(client);
      return true;
    }
mercury233's avatar
mercury233 committed
3919
    buff_main = (function() {
nanahira's avatar
nanahira committed
3920
      var m, ref2, results;
3921
      results = [];
nanahira's avatar
nanahira committed
3922
      for (i = m = 0, ref2 = info.mainc; 0 <= ref2 ? m < ref2 : m > ref2; i = 0 <= ref2 ? ++m : --m) {
3923
        results.push(info.deckbuf[i]);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3924
      }
3925
      return results;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3926
    })();
mercury233's avatar
mercury233 committed
3927
    buff_side = (function() {
nanahira's avatar
nanahira committed
3928
      var m, ref2, ref3, results;
3929
      results = [];
nanahira's avatar
nanahira committed
3930
      for (i = m = ref2 = info.mainc, ref3 = info.mainc + info.sidec; ref2 <= ref3 ? m < ref3 : m > ref3; i = ref2 <= ref3 ? ++m : --m) {
3931
        results.push(info.deckbuf[i]);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3932
      }
3933
      return results;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3934
    })();
mercury233's avatar
mercury233 committed
3935 3936
    client.main = buff_main;
    client.side = buff_side;
nanahira's avatar
nanahira committed
3937
    if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
3938 3939 3940 3941 3942 3943 3944
      client.selected_preduel = true;
      if (client.side_tcount) {
        clearInterval(client.side_interval);
        client.side_interval = null;
        client.side_tcount = null;
      }
    } else {
nanahira's avatar
fix  
nanahira committed
3945
      client.start_deckbuf = Buffer.from(buffer);
nanahira's avatar
nanahira committed
3946
    }
nanahira's avatar
nanahira committed
3947
    oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
nanahira's avatar
nanahira committed
3948
    if (settings.modules.http.quick_death_rule >= 2 && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.death && room.scores[room.dueling_players[0].name_vpass] !== room.scores[room.dueling_players[oppo_pos].name_vpass]) {
3949
      win_pos = room.scores[room.dueling_players[0].name_vpass] > room.scores[room.dueling_players[oppo_pos].name_vpass] ? 0 : oppo_pos;
nanahira's avatar
nanahira committed
3950
      room.finished_by_death = true;
nanahira's avatar
nanahira committed
3951
      ygopro.stoc_send_chat_to_room(room, "${death2_finish_part1}" + room.dueling_players[win_pos].name + "${death2_finish_part2}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
3952 3953 3954
      if (room.hostinfo.mode === 1) {
        CLIENT_send_replays(room.dueling_players[oppo_pos - win_pos], room);
      }
nanahira's avatar
nanahira committed
3955 3956 3957 3958
      ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos], 'DUEL_END');
      if (room.hostinfo.mode === 2) {
        ygopro.stoc_send(room.dueling_players[oppo_pos - win_pos + 1], 'DUEL_END');
      }
3959
      room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
3960
      CLIENT_kick(room.dueling_players[oppo_pos - win_pos]);
nanahira's avatar
nanahira committed
3961
      if (room.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
3962
        CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]);
nanahira's avatar
nanahira committed
3963
      }
nanahira's avatar
nanahira committed
3964 3965
      return true;
    }
3966
    if (room.random_type || room.arena) {
nanahira's avatar
nanahira committed
3967
      if (client.pos === 0) {
mercury233's avatar
mercury233 committed
3968 3969 3970
        room.waiting_for_player = room.waiting_for_player2;
      }
      room.last_active_time = moment();
nanahira's avatar
nanahira committed
3971
    } else if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.hostinfo.mode === 1 && settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.deck_check && fs.readdirSync(settings.modules.tournament_mode.deck_path).length) {
mercury233's avatar
mercury233 committed
3972 3973 3974 3975 3976 3977 3978 3979
      struct = ygopro.structs["deck"];
      struct._setBuff(buffer);
      struct.set("mainc", 1);
      struct.set("sidec", 1);
      struct.set("deckbuf", [4392470, 4392470]);
      buffer = struct.buffer;
      found_deck = false;
      decks = fs.readdirSync(settings.modules.tournament_mode.deck_path);
3980 3981
      for (m = 0, len2 = decks.length; m < len2; m++) {
        deck = decks[m];
Yuzurisa's avatar
Yuzurisa committed
3982
        if (deck_name_match(deck, client.name)) {
mercury233's avatar
fix  
mercury233 committed
3983 3984
          found_deck = deck;
        }
mercury233's avatar
mercury233 committed
3985 3986
      }
      if (found_deck) {
mercury233's avatar
mercury233 committed
3987
        deck_text = fs.readFileSync(settings.modules.tournament_mode.deck_path + found_deck, {
mercury233's avatar
mercury233 committed
3988 3989 3990 3991 3992 3993
          encoding: "ASCII"
        });
        deck_array = deck_text.split("\n");
        deck_main = [];
        deck_side = [];
        current_deck = deck_main;
3994 3995
        for (n = 0, len3 = deck_array.length; n < len3; n++) {
          line = deck_array[n];
mercury233's avatar
mercury233 committed
3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009
          if (line.indexOf("!side") >= 0) {
            current_deck = deck_side;
          }
          card = parseInt(line);
          if (!isNaN(card)) {
            current_deck.push(card);
          }
        }
        if (_.isEqual(buff_main, deck_main) && _.isEqual(buff_side, deck_side)) {
          deckbuf = deck_main.concat(deck_side);
          struct.set("mainc", deck_main.length);
          struct.set("sidec", deck_side.length);
          struct.set("deckbuf", deckbuf);
          buffer = struct.buffer;
mercury233's avatar
mercury233 committed
4010
          ygopro.stoc_send_chat(client, "${deck_correct_part1} " + found_deck + " ${deck_correct_part2}", ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
4011
        } else {
mercury233's avatar
mercury233 committed
4012
          ygopro.stoc_send_chat(client, "${deck_incorrect_part1} " + found_deck + " ${deck_incorrect_part2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4013 4014
        }
      } else {
mercury233's avatar
mercury233 committed
4015
        ygopro.stoc_send_chat(client, client.name + "${deck_not_found}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
4016
      }
mercury233's avatar
mercury233 committed
4017
    }
mercury233's avatar
mercury233 committed
4018
    return false;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4019 4020
  });

nanahira's avatar
nanahira committed
4021
  ygopro.ctos_follow('RESPONSE', false, function(buffer, info, client, server, datas) {
4022 4023
    var room;
    room = ROOM_all[client.rid];
4024
    if (!(room && (room.random_type || room.arena))) {
4025 4026
      return;
    }
4027
    room.last_active_time = moment();
4028 4029
  });

nanahira's avatar
nanahira committed
4030
  ygopro.stoc_follow('TIME_LIMIT', true, function(buffer, info, client, server, datas) {
4031
    var check, cur_players, room;
nanahira's avatar
nanahira committed
4032
    room = ROOM_all[client.rid];
nanahira's avatar
js  
nanahira committed
4033 4034 4035
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
4036 4037 4038 4039 4040 4041 4042
    if (settings.modules.reconnect.enabled) {
      if (client.closed) {
        ygopro.ctos_send(server, 'TIME_CONFIRM');
        return true;
      } else {
        client.time_confirm_required = true;
      }
nanahira's avatar
js  
nanahira committed
4043
    }
nanahira's avatar
nanahira committed
4044
    if (!(settings.modules.heartbeat_detection.enabled && room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING && !room.windbot)) {
nanahira's avatar
nanahira committed
4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075
      return;
    }
    check = false;
    if (room.hostinfo.mode !== 2) {
      check = (client.is_first && info.player === 0) || (!client.is_first && info.player === 1);
    } else {
      cur_players = [];
      switch (room.turn % 4) {
        case 1:
          cur_players[0] = 0;
          cur_players[1] = 3;
          break;
        case 2:
          cur_players[0] = 0;
          cur_players[1] = 2;
          break;
        case 3:
          cur_players[0] = 1;
          cur_players[1] = 2;
          break;
        case 0:
          cur_players[0] = 1;
          cur_players[1] = 3;
      }
      if (!room.dueling_players[0].is_first) {
        cur_players[0] = cur_players[0] + 2;
        cur_players[1] = cur_players[1] - 2;
      }
      check = client.pos === cur_players[info.player];
    }
    if (check) {
4076
      CLIENT_heartbeat_register(client, false);
nanahira's avatar
nanahira committed
4077
    }
nanahira's avatar
js  
nanahira committed
4078
    return false;
nanahira's avatar
nanahira committed
4079 4080
  });

nanahira's avatar
nanahira committed
4081
  ygopro.ctos_follow('TIME_CONFIRM', false, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4082 4083
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4084
    if (!room) {
nanahira's avatar
nanahira committed
4085 4086
      return;
    }
nanahira's avatar
nanahira committed
4087
    if (settings.modules.reconnect.enabled) {
4088 4089 4090 4091 4092 4093 4094 4095 4096
      if (client.waiting_for_last) {
        client.waiting_for_last = false;
        if (client.last_game_msg && client.last_game_msg_title !== 'WAITING') {
          if (client.last_hint_msg) {
            ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg);
          }
          ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg);
        }
      }
nanahira's avatar
nanahira committed
4097 4098
      client.time_confirm_required = false;
    }
4099 4100 4101 4102
    if (settings.modules.heartbeat_detection.enabled) {
      client.heartbeat_protected = false;
      client.heartbeat_responsed = true;
      CLIENT_heartbeat_unregister(client);
nanahira's avatar
typo  
nanahira committed
4103
    }
nanahira's avatar
nanahira committed
4104 4105
  });

nanahira's avatar
nanahira committed
4106
  ygopro.ctos_follow('HAND_RESULT', false, function(buffer, info, client, server, datas) {
4107 4108
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4109 4110 4111 4112 4113
    if (!room) {
      return;
    }
    client.selected_preduel = true;
    if (!(room.random_type || room.arena)) {
4114 4115
      return;
    }
nanahira's avatar
nanahira committed
4116
    if (client.pos === 0) {
4117
      room.waiting_for_player = room.waiting_for_player2;
4118
    }
mercury233's avatar
mercury233 committed
4119
    room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
4120 4121
  });

nanahira's avatar
nanahira committed
4122
  ygopro.ctos_follow('TP_RESULT', false, function(buffer, info, client, server, datas) {
4123 4124
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4125 4126 4127 4128 4129
    if (!room) {
      return;
    }
    client.selected_preduel = true;
    if (!(room.random_type || room.arena)) {
4130 4131
      return;
    }
4132
    room.last_active_time = moment();
4133 4134
  });

nanahira's avatar
nanahira committed
4135
  ygopro.stoc_follow('CHAT', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4136
    var len2, m, pid, player, ref2, room, tcolor, tplayer;
nanahira's avatar
nanahira committed
4137 4138
    room = ROOM_all[client.rid];
    pid = info.player;
nanahira's avatar
nanahira committed
4139
    if (!(room && pid < 4 && settings.modules.chat_color.enabled && (!settings.modules.hide_name || room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN))) {
nanahira's avatar
nanahira committed
4140 4141
      return;
    }
nanahira's avatar
nanahira committed
4142
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING && !room.dueling_players[0].is_first) {
nanahira's avatar
fix  
nanahira committed
4143
      if (room.hostinfo.mode === 2) {
nanahira's avatar
fix  
nanahira committed
4144 4145 4146 4147 4148 4149
        pid = {
          0: 2,
          1: 3,
          2: 0,
          3: 1
        }[pid];
nanahira's avatar
fix  
nanahira committed
4150 4151 4152 4153
      } else {
        pid = 1 - pid;
      }
    }
nanahira's avatar
nanahira committed
4154
    ref2 = room.players;
nanahira's avatar
nanahira committed
4155 4156
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
nanahira's avatar
nanahira committed
4157 4158 4159 4160 4161 4162 4163
      if (player && player.pos === pid) {
        tplayer = player;
      }
    }
    if (!tplayer) {
      return;
    }
nanahira's avatar
fi  
nanahira committed
4164
    tcolor = chat_color.save_list[CLIENT_get_authorize_key(tplayer)];
nanahira's avatar
nanahira committed
4165 4166 4167 4168 4169 4170 4171 4172 4173
    if (tcolor) {
      ygopro.stoc_send(client, 'CHAT', {
        player: ygopro.constants.COLORS[tcolor],
        msg: tplayer.name + ": " + info.msg
      });
      return true;
    }
  });

nanahira's avatar
nanahira committed
4174
  ygopro.stoc_follow('SELECT_HAND', false, function(buffer, info, client, server, datas) {
4175 4176
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4177 4178 4179 4180 4181
    if (!room) {
      return;
    }
    client.selected_preduel = false;
    if (client.pos === 0) {
nanahira's avatar
nanahira committed
4182
      room.duel_stage = ygopro.constants.DUEL_STAGE.FINGER;
nanahira's avatar
nanahira committed
4183 4184
    }
    if (!(room.random_type || room.arena)) {
4185 4186
      return;
    }
nanahira's avatar
nanahira committed
4187
    if (client.pos === 0) {
4188
      room.waiting_for_player = client;
4189
    } else {
4190
      room.waiting_for_player2 = client;
4191
    }
mercury233's avatar
mercury233 committed
4192
    room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
4193 4194
  });

nanahira's avatar
nanahira committed
4195
  ygopro.stoc_follow('SELECT_TP', false, function(buffer, info, client, server, datas) {
4196 4197
    var room;
    room = ROOM_all[client.rid];
4198
    if (!room) {
4199 4200
      return;
    }
nanahira's avatar
nanahira committed
4201
    client.selected_preduel = false;
nanahira's avatar
nanahira committed
4202
    room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO;
nanahira's avatar
nanahira committed
4203
    room.selecting_tp = client;
mercury233's avatar
fix  
mercury233 committed
4204
    if (room.random_type || room.arena) {
4205 4206 4207
      room.waiting_for_player = client;
      room.last_active_time = moment();
    }
4208 4209
  });

nanahira's avatar
nanahira committed
4210
  ygopro.stoc_follow('CHANGE_SIDE', false, function(buffer, info, client, server, datas) {
nanahira's avatar
js  
nanahira committed
4211
    var room, room_name, sinterval, temp_log;
4212
    room = ROOM_all[client.rid];
4213
    if (!room) {
mercury233's avatar
mercury233 committed
4214 4215
      return;
    }
nanahira's avatar
nanahira committed
4216 4217 4218
    if (client.pos === 0) {
      room.duel_stage = ygopro.constants.DUEL_STAGE.SIDING;
    }
nanahira's avatar
nanahira committed
4219
    client.selected_preduel = false;
nanahira's avatar
nanahira committed
4220 4221 4222 4223
    if (settings.modules.side_timeout) {
      client.side_tcount = settings.modules.side_timeout;
      ygopro.stoc_send_chat(client, "${side_timeout_part1}" + settings.modules.side_timeout + "${side_timeout_part2}", ygopro.constants.COLORS.BABYBLUE);
      sinterval = setInterval(function() {
nanahira's avatar
nanahira committed
4224
        if (!(room && client && client.side_tcount && room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING)) {
nanahira's avatar
nanahira committed
4225 4226 4227 4228
          clearInterval(sinterval);
          return;
        }
        if (client.side_tcount === 1) {
nanahira's avatar
fix  
nanahira committed
4229
          ygopro.stoc_send_chat_to_room(room, client.name + "${side_overtime_room}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4230
          ygopro.stoc_send_chat(client, "${side_overtime}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
4231
          CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
4232
          CLIENT_kick(client);
nanahira's avatar
nanahira committed
4233 4234 4235
          return clearInterval(sinterval);
        } else {
          client.side_tcount = client.side_tcount - 1;
nanahira's avatar
js  
nanahira committed
4236
          return ygopro.stoc_send_chat(client, "${side_remain_part1}" + client.side_tcount + "${side_remain_part2}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4237 4238 4239 4240
        }
      }, 60000);
      client.side_interval = sinterval;
    }
nanahira's avatar
js  
nanahira committed
4241
    if (settings.modules.challonge.enabled && settings.modules.challonge.post_score_midduel && room.hostinfo.mode !== 2 && client.pos === 0) {
nanahira's avatar
nanahira committed
4242
      temp_log = JSON.parse(JSON.stringify(room.get_challonge_score()));
nanahira's avatar
nanahira committed
4243
      delete temp_log.winnerId;
nanahira's avatar
js  
nanahira committed
4244
      room_name = room.name;
nanahira's avatar
nanahira committed
4245
      challonge.matches._update({
4246
        id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
4247 4248 4249 4250
        matchId: room.challonge_info.id,
        match: temp_log,
        callback: function(err, data) {
          if (err) {
nanahira's avatar
js  
nanahira committed
4251
            log.warn("Errored pushing scores to Challonge.", room_name, err);
nanahira's avatar
nanahira committed
4252 4253
          } else {
            refresh_challonge_cache();
nanahira's avatar
nanahira committed
4254 4255 4256 4257
          }
        }
      });
    }
4258
    if (room.random_type || room.arena) {
nanahira's avatar
nanahira committed
4259
      if (client.pos === 0) {
4260 4261 4262 4263 4264
        room.waiting_for_player = client;
      } else {
        room.waiting_for_player2 = client;
      }
      room.last_active_time = moment();
mercury233's avatar
mercury233 committed
4265 4266 4267
    }
  });

nanahira's avatar
nanahira committed
4268
  ygopro.stoc_follow('REPLAY', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4269
    var duellog, dueltime, i, len2, len3, m, n, player, ref2, ref3, replay_filename, room;
4270 4271
    room = ROOM_all[client.rid];
    if (!room) {
mercury233's avatar
fix  
mercury233 committed
4272
      return settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe && settings.modules.tournament_mode.block_replay_to_player || settings.modules.replay_delay;
4273
    }
mercury233's avatar
mercury233 committed
4274
    if (settings.modules.cloud_replay.enabled && room.random_type) {
mercury233's avatar
fix  
mercury233 committed
4275 4276
      Cloud_replay_ids.push(room.cloud_replay_id);
    }
nanahira's avatar
nanahira committed
4277
    if (!room.replays[room.duel_count - 1]) {
4278
      room.replays[room.duel_count - 1] = buffer;
nanahira's avatar
nanahira committed
4279
    }
mercury233's avatar
mercury233 committed
4280
    if (settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe) {
nanahira's avatar
nanahira committed
4281
      if (client.pos === 0) {
nanahira's avatar
nanahira committed
4282
        dueltime = moment().format('YYYY-MM-DD HH-mm-ss');
mercury233's avatar
mercury233 committed
4283
        replay_filename = dueltime;
nanahira's avatar
fix  
nanahira committed
4284
        if (room.hostinfo.mode !== 2) {
nanahira's avatar
nanahira committed
4285
          ref2 = room.dueling_players;
nanahira's avatar
nanahira committed
4286
          for (i = m = 0, len2 = ref2.length; m < len2; i = ++m) {
nanahira's avatar
nanahira committed
4287
            player = ref2[i];
nanahira's avatar
nanahira committed
4288 4289 4290
            replay_filename = replay_filename + (i > 0 ? " VS " : " ") + player.name;
          }
        } else {
nanahira's avatar
nanahira committed
4291
          ref3 = room.dueling_players;
nanahira's avatar
nanahira committed
4292
          for (i = n = 0, len3 = ref3.length; n < len3; i = ++n) {
nanahira's avatar
nanahira committed
4293
            player = ref3[i];
nanahira's avatar
nanahira committed
4294 4295
            replay_filename = replay_filename + (i > 0 ? (i === 2 ? " VS " : " & ") : " ") + player.name;
          }
mercury233's avatar
mercury233 committed
4296 4297
        }
        replay_filename = replay_filename.replace(/[\/\\\?\*]/g, '_') + ".yrp";
mercury233's avatar
mercury233 committed
4298
        duellog = {
mercury233's avatar
mercury233 committed
4299
          time: dueltime,
4300
          name: room.name + (settings.modules.tournament_mode.show_info ? " (Duel:" + room.duel_count + ")" : ""),
nanahira's avatar
nanahira committed
4301
          roomid: room.process_pid.toString(),
mercury233's avatar
mercury233 committed
4302
          cloud_replay_id: "R#" + room.cloud_replay_id,
mercury233's avatar
mercury233 committed
4303
          replay_filename: replay_filename,
nanahira's avatar
nanahira committed
4304
          roommode: room.hostinfo.mode,
mercury233's avatar
mercury233 committed
4305
          players: (function() {
nanahira's avatar
nanahira committed
4306
            var len4, o, ref4, results;
nanahira's avatar
nanahira committed
4307
            ref4 = room.dueling_players;
mercury233's avatar
mercury233 committed
4308
            results = [];
nanahira's avatar
nanahira committed
4309 4310
            for (o = 0, len4 = ref4.length; o < len4; o++) {
              player = ref4[o];
mercury233's avatar
mercury233 committed
4311
              results.push({
4312
                name: player.name + (settings.modules.tournament_mode.show_ip && !player.is_local ? " (IP: " + player.ip.slice(7) + ")" : "") + (settings.modules.tournament_mode.show_info && !(room.hostinfo.mode === 2 && player.pos % 2 > 0) ? " (Score:" + room.scores[player.name_vpass] + " LP:" + (player.lp != null ? player.lp : room.hostinfo.start_lp) + (room.hostinfo.mode !== 2 ? " Cards:" + (player.card_count != null ? player.card_count : room.hostinfo.start_hand) : "") + ")" : ""),
mercury233's avatar
mercury233 committed
4313 4314 4315 4316 4317 4318
                winner: player.pos === room.winner
              });
            }
            return results;
          })()
        };
mercury233's avatar
mercury233 committed
4319 4320
        duel_log.duel_log.unshift(duellog);
        setting_save(duel_log);
mercury233's avatar
mercury233 committed
4321 4322 4323 4324 4325
        fs.writeFile(settings.modules.tournament_mode.replay_path + replay_filename, buffer, function(err) {
          if (err) {
            return log.warn("SAVE REPLAY ERROR", replay_filename, err);
          }
        });
mercury233's avatar
mercury233 committed
4326
      }
mercury233's avatar
mercury233 committed
4327
      if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
4328
        ygopro.stoc_send_chat(client, "${cloud_replay_delay_part1}R#" + room.cloud_replay_id + "${cloud_replay_delay_part2}", ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
4329
      }
nanahira's avatar
nanahira committed
4330
      return settings.modules.tournament_mode.block_replay_to_player || settings.modules.replay_delay && room.hostinfo.mode === 1;
4331
    } else {
nanahira's avatar
nanahira committed
4332
      return settings.modules.replay_delay && room.hostinfo.mode === 1;
4333 4334 4335
    }
  });

mercury233's avatar
mercury233 committed
4336
  if (settings.modules.random_duel.enabled) {
mercury233's avatar
mercury233 committed
4337
    setInterval(function() {
nanahira's avatar
nanahira committed
4338 4339 4340
      var len2, m, room, time_passed;
      for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
        room = ROOM_all[m];
nanahira's avatar
js  
nanahira committed
4341
        if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.random_type && room.last_active_time && room.waiting_for_player && room.get_disconnected_count() === 0 && (!settings.modules.side_timeout || room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING))) {
mercury233's avatar
mercury233 committed
4342 4343 4344
          continue;
        }
        time_passed = Math.floor((moment() - room.last_active_time) / 1000);
4345
        if (time_passed >= settings.modules.random_duel.hang_timeout) {
mercury233's avatar
mercury233 committed
4346
          room.last_active_time = moment();
mercury233's avatar
mercury233 committed
4347
          ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}");
4348
          room.scores[room.waiting_for_player.name_vpass] = -9;
mercury233's avatar
mercury233 committed
4349
          ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
4350
          CLIENT_send_replays(room.waiting_for_player, room);
nanahira's avatar
js  
nanahira committed
4351
          CLIENT_kick(room.waiting_for_player);
4352
        } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
mercury233's avatar
mercury233 committed
4353
          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);
mercury233's avatar
mercury233 committed
4354
          ROOM_unwelcome(room, room.waiting_for_player, "${random_ban_reason_AFK}");
mercury233's avatar
mercury233 committed
4355
        }
4356
      }
mercury233's avatar
mercury233 committed
4357 4358 4359
    }, 1000);
  }

4360 4361
  if (settings.modules.mycard.enabled) {
    setInterval(function() {
nanahira's avatar
nanahira committed
4362
      var len2, len3, m, n, player, room, time_passed, waited_time;
nanahira's avatar
nanahira committed
4363 4364
      for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
        room = ROOM_all[m];
nanahira's avatar
js  
nanahira committed
4365
        if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.arena && room.last_active_time && room.waiting_for_player && room.get_disconnected_count() === 0 && (!settings.modules.side_timeout || room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING))) {
4366 4367 4368
          continue;
        }
        time_passed = Math.floor((moment() - room.last_active_time) / 1000);
4369
        if (time_passed >= settings.modules.random_duel.hang_timeout) {
4370 4371
          room.last_active_time = moment();
          ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
4372
          room.scores[room.waiting_for_player.name_vpass] = -9;
nanahira's avatar
nanahira committed
4373
          CLIENT_send_replays(room.waiting_for_player, room);
nanahira's avatar
js  
nanahira committed
4374
          CLIENT_kick(room.waiting_for_player);
4375
        } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
4376 4377 4378
          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);
        }
      }
4379 4380 4381
      if (settings.modules.arena_mode.punish_quit_before_match) {
        for (n = 0, len3 = ROOM_all.length; n < len3; n++) {
          room = ROOM_all[n];
nanahira's avatar
nanahira committed
4382
          if (!(room && room.arena && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.get_playing_player().length < 2)) {
4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393
            continue;
          }
          player = room.get_playing_player()[0];
          if (player && player.join_time && !player.arena_quit_free) {
            waited_time = moment() - player.join_time;
            if (waited_time >= 30000) {
              ygopro.stoc_send_chat(player, "${arena_wait_timeout}", ygopro.constants.COLORS.BABYBLUE);
              player.arena_quit_free = true;
            } else if (waited_time >= 5000 && waited_time < 6000) {
              ygopro.stoc_send_chat(player, "${arena_wait_hint}", ygopro.constants.COLORS.BABYBLUE);
            }
nanahira's avatar
nanahira committed
4394 4395 4396
          }
        }
      }
4397 4398 4399
    }, 1000);
  }

nanahira's avatar
nanahira committed
4400 4401 4402 4403 4404
  if (settings.modules.heartbeat_detection.enabled) {
    setInterval(function() {
      var len2, len3, m, n, player, ref2, room;
      for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
        room = ROOM_all[m];
nanahira's avatar
nanahira committed
4405
        if (room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && (room.hostinfo.time_limit === 0 || room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING) && !room.windbot) {
nanahira's avatar
fix  
nanahira committed
4406
          ref2 = room.get_playing_player();
nanahira's avatar
nanahira committed
4407 4408
          for (n = 0, len3 = ref2.length; n < len3; n++) {
            player = ref2[n];
nanahira's avatar
nanahira committed
4409
            if (player && (room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING || player.selected_preduel)) {
nanahira's avatar
nanahira committed
4410 4411 4412 4413 4414 4415 4416 4417
              CLIENT_heartbeat_register(player, true);
            }
          }
        }
      }
    }, settings.modules.heartbeat_detection.interval);
  }

nanahira's avatar
nanahira committed
4418 4419 4420 4421 4422 4423
  setInterval(function() {
    var current_time, len2, m, results, room;
    current_time = moment();
    results = [];
    for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
      room = ROOM_all[m];
nanahira's avatar
nanahira committed
4424
      if (!(room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && room.hostinfo.auto_death && !room.auto_death_triggered && current_time - moment(room.start_time) > 60000 * room.hostinfo.auto_death)) {
nanahira's avatar
nanahira committed
4425 4426 4427 4428 4429 4430 4431 4432
        continue;
      }
      room.auto_death_triggered = true;
      results.push(room.start_death());
    }
    return results;
  }, 1000);

nanahira's avatar
nanahira committed
4433 4434
  windbot_looplimit = 0;

nanahira's avatar
nanahira committed
4435
  windbot_process = global.windbot_process = null;
nanahira's avatar
nanahira committed
4436

nanahira's avatar
nanahira committed
4437
  spawn_windbot = global.spawn_windbot = function() {
nanahira's avatar
nanahira committed
4438
    var windbot_bin, windbot_parameters;
mercury233's avatar
mercury233 committed
4439 4440 4441 4442 4443 4444 4445 4446 4447 4448
    if (/^win/.test(process.platform)) {
      windbot_bin = 'WindBot.exe';
      windbot_parameters = [];
    } else {
      windbot_bin = 'mono';
      windbot_parameters = ['WindBot.exe'];
    }
    windbot_parameters.push('ServerMode=true');
    windbot_parameters.push('ServerPort=' + settings.modules.windbot.port);
    windbot_process = spawn(windbot_bin, windbot_parameters, {
mercury233's avatar
mercury233 committed
4449 4450 4451 4452
      cwd: 'windbot'
    });
    windbot_process.on('error', function(err) {
      log.warn('WindBot ERROR', err);
nanahira's avatar
nanahira committed
4453
      if (windbot_looplimit < 1000 && !rebooted) {
nanahira's avatar
nanahira committed
4454 4455 4456
        windbot_looplimit++;
        spawn_windbot();
      }
mercury233's avatar
mercury233 committed
4457 4458 4459
    });
    windbot_process.on('exit', function(code) {
      log.warn('WindBot EXIT', code);
nanahira's avatar
nanahira committed
4460
      if (windbot_looplimit < 1000 && !rebooted) {
nanahira's avatar
nanahira committed
4461 4462 4463
        windbot_looplimit++;
        spawn_windbot();
      }
mercury233's avatar
mercury233 committed
4464 4465 4466 4467 4468
    });
    windbot_process.stdout.setEncoding('utf8');
    windbot_process.stdout.on('data', function(data) {
      log.info('WindBot:', data);
    });
mercury233's avatar
fix  
mercury233 committed
4469
    windbot_process.stderr.setEncoding('utf8');
nanahira's avatar
nanahira committed
4470
    windbot_process.stderr.on('data', function(data) {
mercury233's avatar
mercury233 committed
4471 4472
      log.warn('WindBot Error:', data);
    });
nanahira's avatar
nanahira committed
4473 4474 4475 4476
  };

  if (settings.modules.windbot.enabled && settings.modules.windbot.spawn) {
    spawn_windbot();
mercury233's avatar
mercury233 committed
4477
  }
4478

nanahira's avatar
nanahira committed
4479 4480
  rebooted = false;

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4481
  if (settings.modules.http) {
mercury233's avatar
mercury233 committed
4482 4483 4484 4485 4486 4487
    addCallback = function(callback, text) {
      if (!callback) {
        return text;
      }
      return callback + "( " + text + " );";
    };
4488
    requestListener = function(request, response) {
nanahira's avatar
nanahira committed
4489
      var archive_args, archive_name, archive_process, check, death_room_found, duellog, error, filename, getpath, kick_room_found, len2, len3, len4, len5, len6, len7, m, n, o, p, parseQueryString, pass_validated, player, q, r, ref2, replay, room, roomsjson, u;
4490 4491 4492
      parseQueryString = true;
      u = url.parse(request.url, parseQueryString);
      if (u.pathname === '/api/getrooms') {
nanahira's avatar
fix  
nanahira committed
4493 4494
        pass_validated = auth.auth(u.query.username, u.query.pass, "get_rooms", "get_rooms");
        if (!settings.modules.http.public_roomlist && !pass_validated) {
4495
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4496
          response.end(addCallback(u.query.callback, '{"rooms":[{"roomid":"0","roomname":"密码错误","needpass":"true"}]}'));
4497 4498 4499 4500
        } else {
          response.writeHead(200);
          roomsjson = JSON.stringify({
            rooms: (function() {
nanahira's avatar
nanahira committed
4501
              var len2, m, results;
4502
              results = [];
nanahira's avatar
nanahira committed
4503 4504
              for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
                room = ROOM_all[m];
4505
                if (room && room.established) {
4506
                  results.push({
nanahira's avatar
nanahira committed
4507
                    roomid: room.process_pid.toString(),
4508
                    roomname: pass_validated ? room.name : room.name.split('$', 2)[0],
nanahira's avatar
fix  
nanahira committed
4509
                    roommode: room.hostinfo.mode,
4510
                    needpass: (room.name.indexOf('$') !== -1).toString(),
mercury233's avatar
mercury233 committed
4511
                    users: _.sortBy((function() {
nanahira's avatar
nanahira committed
4512
                      var len3, n, ref2, results1;
nanahira's avatar
nanahira committed
4513
                      ref2 = room.players;
4514
                      results1 = [];
nanahira's avatar
nanahira committed
4515 4516
                      for (n = 0, len3 = ref2.length; n < len3; n++) {
                        player = ref2[n];
4517 4518 4519
                        if (player.pos != null) {
                          results1.push({
                            id: (-1).toString(),
mercury233's avatar
mercury233 committed
4520 4521
                            name: player.name,
                            ip: settings.modules.http.show_ip && pass_validated && !player.is_local ? player.ip.slice(7) : null,
nanahira's avatar
nanahira committed
4522
                            status: settings.modules.http.show_info && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && player.pos !== 7 ? {
mercury233's avatar
mercury233 committed
4523 4524 4525 4526
                              score: room.scores[player.name_vpass],
                              lp: player.lp != null ? player.lp : room.hostinfo.start_lp,
                              cards: room.hostinfo.mode !== 2 ? (player.card_count != null ? player.card_count : room.hostinfo.start_hand) : null
                            } : null,
4527 4528 4529
                            pos: player.pos
                          });
                        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4530
                      }
4531
                      return results1;
mercury233's avatar
mercury233 committed
4532
                    })(), "pos"),
nanahira's avatar
nanahira committed
4533
                    istart: room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN ? (settings.modules.http.show_info ? "Duel:" + room.duel_count + " " + (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING ? "Siding" : "Turn:" + (room.turn != null ? room.turn : 0) + (room.death ? "/" + (room.death > 0 ? room.death - 1 : "Death") : "")) : 'start') : 'wait'
4534 4535
                  });
                }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4536
              }
4537 4538
              return results;
            })()
mercury233's avatar
mercury233 committed
4539 4540
          }, null, 2);
          response.end(addCallback(u.query.callback, roomsjson));
4541
        }
mercury233's avatar
mercury233 committed
4542
      } else if (u.pathname === '/api/duellog' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4543
        if (!auth.auth(u.query.username, u.query.pass, "duel_log", "duel_log")) {
mercury233's avatar
mercury233 committed
4544
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4545
          response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"));
mercury233's avatar
mercury233 committed
4546 4547 4548
          return;
        } else {
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4549
          duellog = JSON.stringify(duel_log.duel_log, null, 2);
mercury233's avatar
mercury233 committed
4550
          response.end(addCallback(u.query.callback, duellog));
mercury233's avatar
mercury233 committed
4551
        }
nanahira's avatar
nanahira committed
4552
      } else if (u.pathname === '/api/archive.zip' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4553
        if (!auth.auth(u.query.username, u.query.pass, "download_replay", "download_replay_archive")) {
nanahira's avatar
nanahira committed
4554 4555 4556 4557 4558
          response.writeHead(403);
          response.end("Invalid password.");
          return;
        } else {
          try {
nanahira's avatar
nanahira committed
4559
            archive_name = moment().format('YYYY-MM-DD HH-mm-ss') + ".zip";
nanahira's avatar
nanahira committed
4560
            archive_args = ["a", "-mx0", "-y", archive_name];
nanahira's avatar
fix  
nanahira committed
4561
            check = false;
nanahira's avatar
nanahira committed
4562
            ref2 = duel_log.duel_log;
nanahira's avatar
nanahira committed
4563 4564
            for (m = 0, len2 = ref2.length; m < len2; m++) {
              replay = ref2[m];
nanahira's avatar
fix  
nanahira committed
4565
              check = true;
nanahira's avatar
nanahira committed
4566 4567
              archive_args.push(replay.replay_filename);
            }
nanahira's avatar
fix  
nanahira committed
4568 4569 4570 4571 4572
            if (!check) {
              response.writeHead(403);
              response.end("Duel logs not found.");
              return;
            }
nanahira's avatar
nanahira committed
4573 4574 4575
            archive_process = spawn(settings.modules.tournament_mode.replay_archive_tool, archive_args, {
              cwd: settings.modules.tournament_mode.replay_path
            });
nanahira's avatar
js  
nanahira committed
4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597
            archive_process.on('error', (function(_this) {
              return function(err) {
                response.writeHead(403);
                response.end("Failed packing replays. " + err);
              };
            })(this));
            archive_process.on('exit', (function(_this) {
              return function(code) {
                return fs.readFile(settings.modules.tournament_mode.replay_path + archive_name, function(error, buffer) {
                  if (error) {
                    response.writeHead(403);
                    response.end("Failed sending replays. " + error);
                  } else {
                    response.writeHead(200, {
                      "Content-Type": "application/octet-stream",
                      "Content-Disposition": "attachment"
                    });
                    response.end(buffer);
                  }
                });
              };
            })(this));
nanahira's avatar
nanahira committed
4598
            archive_process.stdout.setEncoding('utf8');
nanahira's avatar
js  
nanahira committed
4599 4600 4601 4602 4603
            archive_process.stdout.on('data', (function(_this) {
              return function(data) {
                return log.info("archive process: " + data);
              };
            })(this));
nanahira's avatar
nanahira committed
4604
            archive_process.stderr.setEncoding('utf8');
nanahira's avatar
js  
nanahira committed
4605 4606 4607 4608 4609
            archive_process.stderr.on('data', (function(_this) {
              return function(data) {
                return log.warn("archive error: " + data);
              };
            })(this));
nanahira's avatar
nanahira committed
4610 4611 4612 4613 4614 4615
          } catch (error1) {
            error = error1;
            response.writeHead(403);
            response.end("Failed reading replays. " + error);
          }
        }
nanahira's avatar
nanahira committed
4616
      } else if (u.pathname === '/api/clearlog' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4617
        if (!auth.auth(u.query.username, u.query.pass, "clear_duel_log", "clear_duel_log")) {
nanahira's avatar
nanahira committed
4618 4619 4620 4621 4622
          response.writeHead(200);
          response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"));
          return;
        } else {
          response.writeHead(200);
4623 4624 4625 4626 4627 4628 4629
          if (settings.modules.tournament_mode.log_save_path) {
            fs.writeFile(settings.modules.tournament_mode.log_save_path + 'duel_log.' + moment().format('YYYY-MM-DD HH-mm-ss') + '.json', JSON.stringify(duel_log, null, 2), function(err) {
              if (err) {
                return log.warn('DUEL LOG SAVE ERROR', err);
              }
            });
          }
4630 4631
          duel_log.duel_log = [];
          setting_save(duel_log);
nanahira's avatar
nanahira committed
4632 4633
          response.end(addCallback(u.query.callback, "[{name:'Success'}]"));
        }
mercury233's avatar
mercury233 committed
4634
      } else if (_.startsWith(u.pathname, '/api/replay') && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4635
        if (!auth.auth(u.query.username, u.query.pass, "download_replay", "download_replay")) {
mercury233's avatar
mercury233 committed
4636 4637 4638 4639
          response.writeHead(403);
          response.end("密码错误");
          return;
        } else {
nanahira's avatar
nanahira committed
4640 4641 4642 4643 4644 4645 4646 4647 4648 4649
          getpath = null;
          filename = null;
          try {
            getpath = u.pathname.split("/");
            filename = path.basename(decodeURIComponent(getpath.pop()));
          } catch (error1) {
            response.writeHead(404);
            response.end("bad filename");
            return;
          }
mercury233's avatar
mercury233 committed
4650 4651 4652
          fs.readFile(settings.modules.tournament_mode.replay_path + filename, function(error, buffer) {
            if (error) {
              response.writeHead(404);
mercury233's avatar
fix  
mercury233 committed
4653
              response.end("未找到文件 " + filename);
mercury233's avatar
mercury233 committed
4654 4655 4656 4657 4658
            } else {
              response.writeHead(200, {
                "Content-Type": "application/octet-stream",
                "Content-Disposition": "attachment"
              });
mercury233's avatar
fix  
mercury233 committed
4659
              response.end(buffer);
mercury233's avatar
mercury233 committed
4660 4661 4662
            }
          });
        }
4663 4664
      } else if (u.pathname === '/api/message') {
        if (u.query.shout) {
nanahira's avatar
nanahira committed
4665 4666 4667 4668 4669
          if (!auth.auth(u.query.username, u.query.pass, "shout", "shout")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
4670 4671
          for (n = 0, len3 = ROOM_all.length; n < len3; n++) {
            room = ROOM_all[n];
4672 4673 4674
            if (room && room.established) {
              ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW);
            }
4675 4676
          }
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4677
          response.end(addCallback(u.query.callback, "['shout ok', '" + u.query.shout + "']"));
4678
        } else if (u.query.stop) {
nanahira's avatar
nanahira committed
4679 4680 4681 4682 4683
          if (!auth.auth(u.query.username, u.query.pass, "stop", "stop")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
4684 4685 4686
          if (u.query.stop === 'false') {
            u.query.stop = false;
          }
mercury233's avatar
mercury233 committed
4687
          setting_change(settings, 'modules:stop', u.query.stop);
4688
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4689
          response.end(addCallback(u.query.callback, "['stop ok', '" + u.query.stop + "']"));
4690
        } else if (u.query.welcome) {
nanahira's avatar
nanahira committed
4691 4692 4693 4694 4695
          if (!auth.auth(u.query.username, u.query.pass, "change_settings", "change_welcome")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
mercury233's avatar
mercury233 committed
4696
          setting_change(settings, 'modules:welcome', u.query.welcome);
mercury233's avatar
mercury233 committed
4697
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4698
          response.end(addCallback(u.query.callback, "['welcome ok', '" + u.query.welcome + "']"));
mercury233's avatar
mercury233 committed
4699
        } else if (u.query.getwelcome) {
nanahira's avatar
nanahira committed
4700 4701 4702 4703 4704
          if (!auth.auth(u.query.username, u.query.pass, "change_settings", "get_welcome")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
4705
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4706
          response.end(addCallback(u.query.callback, "['get ok', '" + settings.modules.welcome + "']"));
mercury233's avatar
mercury233 committed
4707
        } else if (u.query.loadtips) {
nanahira's avatar
nanahira committed
4708 4709 4710 4711 4712
          if (!auth.auth(u.query.username, u.query.pass, "change_settings", "change_tips")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
mercury233's avatar
mercury233 committed
4713 4714
          load_tips();
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4715
          response.end(addCallback(u.query.callback, "['loading tip', '" + settings.modules.tips.get + "']"));
mercury233's avatar
mercury233 committed
4716
        } else if (u.query.loaddialogues) {
nanahira's avatar
nanahira committed
4717 4718 4719 4720 4721
          if (!auth.auth(u.query.username, u.query.pass, "change_settings", "change_dialogues")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
mercury233's avatar
mercury233 committed
4722 4723
          load_dialogues();
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4724
          response.end(addCallback(u.query.callback, "['loading dialogues', '" + settings.modules.dialogues.get + "']"));
mercury233's avatar
mercury233 committed
4725
        } else if (u.query.ban) {
nanahira's avatar
nanahira committed
4726 4727 4728 4729 4730
          if (!auth.auth(u.query.username, u.query.pass, "ban_user", "ban_user")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
mercury233's avatar
mercury233 committed
4731
          ban_user(u.query.ban);
mercury233's avatar
mercury233 committed
4732
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4733
          response.end(addCallback(u.query.callback, "['ban ok', '" + u.query.ban + "']"));
nanahira's avatar
nanahira committed
4734
        } else if (u.query.kick) {
nanahira's avatar
nanahira committed
4735 4736 4737 4738 4739
          if (!auth.auth(u.query.username, u.query.pass, "kick_user", "kick_user")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
4740
          kick_room_found = false;
nanahira's avatar
nanahira committed
4741 4742
          for (o = 0, len4 = ROOM_all.length; o < len4; o++) {
            room = ROOM_all[o];
nanahira's avatar
nanahira committed
4743
            if (!(room && room.established && (u.query.kick === "all" || u.query.kick === room.process_pid.toString() || u.query.kick === room.name))) {
nanahira's avatar
nanahira committed
4744 4745 4746
              continue;
            }
            kick_room_found = true;
nanahira's avatar
nanahira committed
4747
            if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
4748 4749
              room.scores[room.dueling_players[0].name_vpass] = 0;
              room.scores[room.dueling_players[1].name_vpass] = 0;
nanahira's avatar
nanahira committed
4750
            }
nanahira's avatar
fix  
nanahira committed
4751
            room.kicked = true;
nanahira's avatar
js  
nanahira committed
4752
            room.send_replays();
nanahira's avatar
nanahira committed
4753 4754 4755 4756 4757 4758 4759 4760 4761 4762
            room.process.kill();
            room["delete"]();
          }
          response.writeHead(200);
          if (kick_room_found) {
            response.end(addCallback(u.query.callback, "['kick ok', '" + u.query.kick + "']"));
          } else {
            response.end(addCallback(u.query.callback, "['room not found', '" + u.query.kick + "']"));
          }
        } else if (u.query.death) {
nanahira's avatar
nanahira committed
4763 4764 4765 4766 4767
          if (!auth.auth(u.query.username, u.query.pass, "start_death", "start_death")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
4768 4769 4770
          death_room_found = false;
          for (p = 0, len5 = ROOM_all.length; p < len5; p++) {
            room = ROOM_all[p];
nanahira's avatar
nanahira committed
4771 4772 4773
            if (room && (u.query.death === "all" || u.query.death === room.process_pid.toString() || u.query.death === room.name)) {
              if (room.start_death()) {
                death_room_found = true;
nanahira's avatar
nanahira committed
4774
              }
nanahira's avatar
nanahira committed
4775 4776 4777 4778 4779 4780 4781 4782 4783
            }
          }
          response.writeHead(200);
          if (death_room_found) {
            response.end(addCallback(u.query.callback, "['death ok', '" + u.query.death + "']"));
          } else {
            response.end(addCallback(u.query.callback, "['room not found', '" + u.query.death + "']"));
          }
        } else if (u.query.deathcancel) {
nanahira's avatar
nanahira committed
4784 4785 4786 4787 4788
          if (!auth.auth(u.query.username, u.query.pass, "start_death", "cancel_death")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
nanahira's avatar
nanahira committed
4789
          death_room_found = false;
nanahira's avatar
nanahira committed
4790 4791
          for (q = 0, len6 = ROOM_all.length; q < len6; q++) {
            room = ROOM_all[q];
nanahira's avatar
nanahira committed
4792
            if (room && (u.query.deathcancel === "all" || u.query.deathcancel === room.process_pid.toString() || u.query.deathcancel === room.name)) {
nanahira's avatar
nanahira committed
4793 4794 4795
              if (room.cancel_death()) {
                death_room_found = true;
              }
nanahira's avatar
nanahira committed
4796 4797 4798 4799 4800 4801 4802 4803
            }
          }
          response.writeHead(200);
          if (death_room_found) {
            response.end(addCallback(u.query.callback, "['death cancel ok', '" + u.query.deathcancel + "']"));
          } else {
            response.end(addCallback(u.query.callback, "['room not found', '" + u.query.deathcancel + "']"));
          }
nanahira's avatar
nanahira committed
4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814
        } else if (u.query.reboot) {
          if (!auth.auth(u.query.username, u.query.pass, "stop", "reboot")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
          for (r = 0, len7 = ROOM_all.length; r < len7; r++) {
            room = ROOM_all[r];
            if (!(room)) {
              continue;
            }
nanahira's avatar
nanahira committed
4815
            if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830
              room.scores[room.dueling_players[0].name_vpass] = 0;
              room.scores[room.dueling_players[1].name_vpass] = 0;
            }
            room.kicked = true;
            room.send_replays();
            room.process.kill();
            room["delete"]();
          }
          rebooted = true;
          if (windbot_process) {
            windbot_process.kill();
          }
          response.writeHead(200);
          response.end(addCallback(u.query.callback, "['reboot ok', '" + u.query.reboot + "']"));
          throw "rebooted";
4831
        } else {
mercury233's avatar
mercury233 committed
4832
          response.writeHead(400);
4833
          response.end();
4834
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4835
      } else {
mercury233's avatar
mercury233 committed
4836
        response.writeHead(400);
mercury233's avatar
test3  
mercury233 committed
4837
        response.end();
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4838
      }
4839 4840
    };
    http_server = http.createServer(requestListener);
神楽坂玲奈's avatar
神楽坂玲奈 committed
4841
    http_server.listen(settings.modules.http.port);
mercury233's avatar
mercury233 committed
4842
    if (settings.modules.http.ssl.enabled) {
4843 4844 4845 4846 4847 4848
      https = require('https');
      options = {
        cert: fs.readFileSync(settings.modules.http.ssl.cert),
        key: fs.readFileSync(settings.modules.http.ssl.key)
      };
      https_server = https.createServer(options, requestListener);
nanahira's avatar
fix  
nanahira committed
4849 4850 4851
      if (settings.modules.http.websocket_roomlist && roomlist) {
        roomlist.init(https_server, ROOM_all);
      }
4852 4853
      https_server.listen(settings.modules.http.ssl.port);
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4854
  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
4855

nanahira's avatar
nanahira committed
4856 4857 4858 4859 4860 4861 4862 4863
  if (!fs.existsSync('./plugins')) {
    fs.mkdirSync('./plugins');
  }

  plugin_list = fs.readdirSync("./plugins");

  for (m = 0, len2 = plugin_list.length; m < len2; m++) {
    plugin_filename = plugin_list[m];
nanahira's avatar
nanahira committed
4864
    plugin_path = process.cwd() + "/plugins/" + plugin_filename;
nanahira's avatar
nanahira committed
4865
    require(plugin_path);
nanahira's avatar
nanahira committed
4866
    log.info("Plugin loaded:", plugin_filename);
nanahira's avatar
nanahira committed
4867 4868
  }

神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
4869
}).call(this);