ygopro-server.js 182 KB
Newer Older
mercury233's avatar
mercury233 committed
1
// Generated by CoffeeScript 1.12.7
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2
(function() {
nanahira's avatar
nanahira 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_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, 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;

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

神楽坂玲奈'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');

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

41 42
  moment = require('moment');

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 = ["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 {
mercury233's avatar
mercury233 committed
249
    tips = loadJSON('./config/tips.json');
mercury233's avatar
mercury233 committed
250 251 252 253 254 255
  } catch (error1) {
    tips = default_data.tips;
    setting_save(tips);
  }

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

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

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

nanahira's avatar
nanahira committed
276
  try {
mercury233's avatar
mercury233 committed
277
    chat_color = loadJSON('./config/chat_color.json');
nanahira's avatar
nanahira committed
278 279 280 281 282
  } catch (error1) {
    chat_color = default_data.chat_color;
    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 = 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) {
mercury233's avatar
mercury233 committed
337
    windbots = loadJSON(settings.modules.windbot.botlist).windbots;
nanahira's avatar
nanahira committed
338 339 340 341 342 343 344 345 346
    real_windbot_server_ip = settings.modules.windbot.server_ip;
    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) {
          return real_windbot_server_ip = addr;
        }
      });
    }
mercury233's avatar
mercury233 committed
347 348
  }

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

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;
mercury233's avatar
mercury233 committed
367
    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;
    }
410
    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 = 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));
mercury233's avatar
fix  
mercury233 committed
506
      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
  ROOM_validate = global.ROOM_validate = function(name) {
mercury233's avatar
mercury233 committed
803 804 805 806 807 808 809 810 811
    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;
812 813 814
      if (!room) {
        return false;
      }
mercury233's avatar
mercury233 committed
815 816 817 818 819 820 821
      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
822
  ROOM_unwelcome = global.ROOM_unwelcome = function(room, bad_player, reason) {
nanahira's avatar
nanahira committed
823
    var len2, m, player, ref2;
mercury233's avatar
mercury233 committed
824 825 826
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
827
    ref2 = room.players;
nanahira's avatar
nanahira committed
828 829
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
mercury233's avatar
mercury233 committed
830 831 832 833 834 835 836 837 838
      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
839
  CLIENT_kick = global.CLIENT_kick = function(client) {
nanahira's avatar
nanahira committed
840 841 842
    if (!client) {
      return false;
    }
nanahira's avatar
nanahira committed
843
    client.system_kicked = true;
nanahira's avatar
typo  
nanahira committed
844
    if (settings.modules.reconnect.enabled && client.closed) {
nanahira's avatar
fix  
nanahira committed
845 846 847
      if (client.server && !client.had_new_reconnection) {
        client.server.destroy();
      }
nanahira's avatar
nanahira committed
848 849 850
    } else {
      client.destroy();
    }
nanahira's avatar
nanahira committed
851
    return true;
nanahira's avatar
nanahira committed
852 853
  };

nanahira's avatar
nanahira committed
854
  release_disconnect = global.release_disconnect = function(dinfo, reconnected) {
nanahira's avatar
nanahira committed
855 856 857 858 859 860 861 862 863
    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
864
  CLIENT_get_authorize_key = global.CLIENT_get_authorize_key = function(client) {
nanahira's avatar
js  
nanahira committed
865
    if (!settings.modules.mycard.enabled && client.vpass) {
866
      return client.name_vpass;
nanahira's avatar
js  
nanahira committed
867 868
    } 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
869
    } else {
870
      return client.ip + ":" + client.name;
nanahira's avatar
nanahira committed
871 872 873
    }
  };

nanahira's avatar
nanahira committed
874
  CLIENT_reconnect_unregister = global.CLIENT_reconnect_unregister = function(client, reconnected, exact) {
nanahira's avatar
nanahira committed
875 876 877 878
    if (!settings.modules.reconnect.enabled) {
      return false;
    }
    if (disconnect_list[CLIENT_get_authorize_key(client)]) {
nanahira's avatar
nanahira committed
879 880 881
      if (exact && disconnect_list[CLIENT_get_authorize_key(client)].old_client !== client) {
        return false;
      }
nanahira's avatar
nanahira committed
882 883 884 885 886 887 888
      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
889
  CLIENT_reconnect_register = global.CLIENT_reconnect_register = function(client, room_id, error) {
nanahira's avatar
nanahira committed
890
    var dinfo, room, tmot;
nanahira's avatar
nanahira committed
891
    room = ROOM_all[room_id];
nanahira's avatar
nanahira committed
892 893 894
    if (client.had_new_reconnection) {
      return false;
    }
nanahira's avatar
nanahira committed
895
    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
896 897 898
      return false;
    }
    dinfo = {
nanahira's avatar
nanahira committed
899
      room_id: room_id,
nanahira's avatar
nanahira committed
900 901 902 903 904 905 906 907 908 909
      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
910
    ygopro.stoc_send_chat_to_room(room, (client.name + " ${disconnect_from_game}") + (error ? ": " + error : ''));
nanahira's avatar
nanahira committed
911 912 913 914
    if (client.time_confirm_required) {
      client.time_confirm_required = false;
      ygopro.ctos_send(client.server, 'TIME_CONFIRM');
    }
nanahira's avatar
nanahira committed
915
    if (settings.modules.reconnect.auto_surrender_after_disconnect && room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) {
916 917
      ygopro.ctos_send(client.server, 'SURRENDER');
    }
nanahira's avatar
nanahira committed
918 919 920
    return true;
  };

nanahira's avatar
nanahira committed
921
  CLIENT_import_data = global.CLIENT_import_data = function(client, old_client, room) {
nanahira's avatar
nanahira committed
922
    var index, key, len2, len3, m, n, player, ref2;
nanahira's avatar
nanahira committed
923 924 925 926 927 928 929 930 931
    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
932
    if (room.waiting_for_player === old_client) {
nanahira's avatar
nanahira committed
933 934
      room.waiting_for_player = client;
    }
nanahira's avatar
nanahira committed
935
    if (room.waiting_for_player2 === old_client) {
nanahira's avatar
nanahira committed
936 937
      room.waiting_for_player2 = client;
    }
nanahira's avatar
nanahira committed
938
    if (room.selecting_tp === old_client) {
nanahira's avatar
nanahira committed
939 940
      room.selecting_tp = client;
    }
nanahira's avatar
nanahira committed
941 942 943 944
    for (n = 0, len3 = import_datas.length; n < len3; n++) {
      key = import_datas[n];
      client[key] = old_client[key];
    }
nanahira's avatar
nanahira committed
945 946 947
    old_client.had_new_reconnection = true;
  };

nanahira's avatar
nanahira committed
948
  SERVER_clear_disconnect = global.SERVER_clear_disconnect = function(server) {
nanahira's avatar
nanahira committed
949 950
    var k, v;
    if (!settings.modules.reconnect.enabled) {
nanahira's avatar
nanahira committed
951
      return false;
nanahira's avatar
nanahira committed
952 953 954 955 956 957
    }
    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
958
        return true;
nanahira's avatar
nanahira committed
959 960
      }
    }
nanahira's avatar
nanahira committed
961 962 963
    return false;
  };

nanahira's avatar
nanahira committed
964
  ROOM_clear_disconnect = global.ROOM_clear_disconnect = function(room_id) {
nanahira's avatar
nanahira committed
965 966 967 968 969 970 971 972 973 974 975 976 977
    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
978 979
  };

nanahira's avatar
nanahira committed
980
  CLIENT_is_player = global.CLIENT_is_player = function(client, room) {
nanahira's avatar
nanahira committed
981 982 983 984 985 986 987 988 989 990
    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
991
    return is_player && client.pos <= 3;
nanahira's avatar
nanahira committed
992 993
  };

nanahira's avatar
nanahira committed
994
  CLIENT_is_able_to_reconnect = global.CLIENT_is_able_to_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
995
    var disconnect_info, room;
nanahira's avatar
nanahira committed
996 997 998 999 1000 1001 1002 1003 1004 1005
    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
1006 1007 1008 1009 1010
    room = ROOM_all[disconnect_info.room_id];
    if (!room) {
      CLIENT_reconnect_unregister(client);
      return false;
    }
nanahira's avatar
nanahira committed
1011 1012 1013 1014 1015 1016
    if (deckbuf && !_.isEqual(deckbuf, disconnect_info.deckbuf)) {
      return false;
    }
    return true;
  };

nanahira's avatar
nanahira committed
1017
  CLIENT_get_kick_reconnect_target = global.CLIENT_get_kick_reconnect_target = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1018 1019 1020
    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
1021
      if (room && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && !room.windbot) {
nanahira's avatar
nanahira committed
1022 1023 1024
        ref2 = room.get_playing_player();
        for (n = 0, len3 = ref2.length; n < len3; n++) {
          player = ref2[n];
1025
          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
1026 1027 1028 1029 1030 1031 1032 1033
            return player;
          }
        }
      }
    }
    return null;
  };

nanahira's avatar
nanahira committed
1034
  CLIENT_is_able_to_kick_reconnect = global.CLIENT_is_able_to_kick_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1035 1036 1037 1038 1039 1040
    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
1041 1042 1043
    return true;
  };

nanahira's avatar
nanahira committed
1044
  CLIENT_send_pre_reconnect_info = global.CLIENT_send_pre_reconnect_info = function(client, room, old_client) {
nanahira's avatar
nanahira committed
1045
    var len2, m, player, ref2, req_pos;
nanahira's avatar
nanahira committed
1046
    ygopro.stoc_send_chat(client, "${pre_reconnecting_to_room}", ygopro.constants.COLORS.BABYBLUE);
1047
    ygopro.stoc_send(client, 'JOIN_GAME', room.join_game_buffer);
nanahira's avatar
nanahira committed
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
    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
1058
      ygopro.stoc_send(client, 'HS_PLAYER_ENTER', {
nanahira's avatar
nanahira committed
1059 1060
        name: player.name,
        pos: player.pos
nanahira's avatar
nanahira committed
1061
      });
nanahira's avatar
nanahira committed
1062 1063 1064
    }
  };

nanahira's avatar
nanahira committed
1065
  CLIENT_send_reconnect_info = global.CLIENT_send_reconnect_info = function(client, server, room) {
nanahira's avatar
nanahira committed
1066 1067
    client.reconnecting = true;
    ygopro.stoc_send_chat(client, "${reconnecting_to_room}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
    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
1093 1094 1095
    }
  };

nanahira's avatar
nanahira committed
1096
  CLIENT_pre_reconnect = global.CLIENT_pre_reconnect = function(client) {
nanahira's avatar
nanahira committed
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
    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
1110 1111 1112
    }
  };

nanahira's avatar
nanahira committed
1113
  CLIENT_reconnect = global.CLIENT_reconnect = function(client) {
nanahira's avatar
nanahira committed
1114
    var current_old_server, dinfo, room;
nanahira's avatar
nanahira committed
1115 1116 1117 1118 1119 1120 1121
    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
1122
    room = ROOM_all[dinfo.room_id];
nanahira's avatar
nanahira committed
1123 1124 1125 1126 1127 1128 1129 1130 1131
    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
1132 1133 1134
    if (room.random_type || room.arena) {
      room.last_active_time = moment();
    }
nanahira's avatar
nanahira committed
1135 1136
    CLIENT_import_data(client, dinfo.old_client, room);
    CLIENT_send_reconnect_info(client, client.server, room);
nanahira's avatar
js  
nanahira committed
1137
    ygopro.stoc_send_chat_to_room(room, client.name + " ${reconnect_to_game}");
nanahira's avatar
nanahira committed
1138 1139 1140
    CLIENT_reconnect_unregister(client, true);
  };

nanahira's avatar
nanahira committed
1141
  CLIENT_kick_reconnect = global.CLIENT_kick_reconnect = function(client, deckbuf) {
nanahira's avatar
nanahira committed
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
    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
1172 1173 1174 1175
  if (settings.modules.reconnect.enabled) {
    disconnect_list = {};
  }

nanahira's avatar
nanahira committed
1176
  CLIENT_heartbeat_unregister = global.CLIENT_heartbeat_unregister = function(client) {
nanahira's avatar
nanahira committed
1177 1178 1179 1180 1181 1182 1183 1184
    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
1185
  CLIENT_heartbeat_register = global.CLIENT_heartbeat_register = function(client, send) {
1186
    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
1187 1188 1189 1190 1191 1192 1193 1194
      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
1195 1196 1197 1198 1199
        player: 0,
        left_time: 0
      });
      ygopro.stoc_send(client, "TIME_LIMIT", {
        player: 1,
nanahira's avatar
nanahira committed
1200 1201 1202 1203 1204 1205 1206 1207
        left_time: 0
      });
    }
    client.heartbeat_timeout = setTimeout(function() {
      CLIENT_heartbeat_unregister(client);
      if (!(client.closed || client.heartbeat_responsed)) {
        client.destroy();
      }
1208
    }, settings.modules.heartbeat_detection.wait_time);
nanahira's avatar
nanahira committed
1209 1210 1211
    return true;
  };

nanahira's avatar
nanahira committed
1212
  CLIENT_is_banned_by_mc = global.CLIENT_is_banned_by_mc = function(client) {
nanahira's avatar
nanahira committed
1213 1214 1215
    return client.ban_mc && client.ban_mc.banned && moment().isBefore(client.ban_mc.until);
  };

nanahira's avatar
nanahira committed
1216
  CLIENT_send_replays = global.CLIENT_send_replays = function(client, room) {
nanahira's avatar
nanahira committed
1217
    var buffer, i, len2, m, ref2;
nanahira's avatar
nanahira committed
1218
    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
1219 1220
      return false;
    }
nanahira's avatar
nanahira committed
1221
    client.replays_sent = true;
nanahira's avatar
nanahira committed
1222 1223 1224 1225 1226
    i = 0;
    ref2 = room.replays;
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      buffer = ref2[m];
      ++i;
nanahira's avatar
fix  
nanahira committed
1227 1228 1229 1230
      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
1231 1232 1233 1234
    }
    return true;
  };

nanahira's avatar
nanahira committed
1235
  SOCKET_flush_data = global.SOCKET_flush_data = function(sk, datas) {
1236
    var buffer, len2, m;
nanahira's avatar
js  
nanahira committed
1237 1238 1239
    if (!sk || sk.closed) {
      return false;
    }
1240 1241 1242 1243 1244
    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
1245
    return true;
1246 1247
  };

mercury233's avatar
mercury233 committed
1248 1249
  Room = (function() {
    function Room(name, hostinfo) {
1250
      var death_time, draw_count, duel_rule, lflist, param, rule, start_hand, start_lp, time_limit;
mercury233's avatar
mercury233 committed
1251 1252 1253 1254 1255 1256 1257 1258
      this.hostinfo = hostinfo;
      this.name = name;
      this.players = [];
      this.player_datas = [];
      this.status = 'starting';
      this.established = false;
      this.watcher_buffers = [];
      this.recorder_buffers = [];
1259
      this.cloud_replay_id = Math.floor(Math.random() * 100000000);
mercury233's avatar
mercury233 committed
1260 1261 1262
      this.watchers = [];
      this.random_type = '';
      this.welcome = '';
mercury233's avatar
mercury233 committed
1263
      this.scores = {};
nanahira's avatar
nanahira committed
1264
      this.decks = {};
1265
      this.duel_count = 0;
nanahira's avatar
nanahira committed
1266
      this.death = 0;
nanahira's avatar
nanahira committed
1267
      this.turn = 0;
nanahira's avatar
nanahira committed
1268
      this.duel_stage = ygopro.constants.DUEL_STAGE.BEGIN;
nanahira's avatar
nanahira committed
1269
      this.replays = [];
mercury233's avatar
mercury233 committed
1270
      ROOM_all.push(this);
mercury233's avatar
fix  
mercury233 committed
1271
      this.hostinfo || (this.hostinfo = JSON.parse(JSON.stringify(settings.hostinfo)));
nanahira's avatar
nanahira committed
1272
      delete this.hostinfo.comment;
mercury233's avatar
mercury233 committed
1273
      if (lflists.length) {
1274
        if (this.hostinfo.rule === 1 && this.hostinfo.lflist === 0) {
mercury233's avatar
mercury233 committed
1275
          this.hostinfo.lflist = _.findIndex(lflists, function(list) {
1276 1277 1278 1279 1280 1281
            return list.tcg;
          });
        }
      } else {
        this.hostinfo.lflist = -1;
      }
mercury233's avatar
mercury233 committed
1282 1283 1284 1285 1286
      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
1287 1288 1289
      } else if (name.slice(0, 3) === 'AI#') {
        this.hostinfo.rule = 2;
        this.hostinfo.lflist = -1;
mercury233's avatar
mercury233 committed
1290
        this.hostinfo.time_limit = 999;
mercury233's avatar
mercury233 committed
1291 1292 1293
      } 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]);
1294
        this.hostinfo.duel_rule = (param[3] === 'T' ? 3 : 4);
mercury233's avatar
mercury233 committed
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
        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
1311
          this.hostinfo.lflist = _.findIndex(lflists, function(list) {
mercury233's avatar
mercury233 committed
1312
            return list.tcg;
mercury233's avatar
mercury233 committed
1313 1314 1315 1316
          });
        }
        if (rule.match(/(^|,|,)(OCGONLY|OO)(,|,|$)/)) {
          this.hostinfo.rule = 0;
1317
          this.hostinfo.lflist = 0;
mercury233's avatar
mercury233 committed
1318 1319 1320 1321 1322 1323 1324 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
        }
        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)(,|,|$)/)) {
1379 1380 1381 1382 1383 1384 1385
          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
1386
        }
nanahira's avatar
nanahira committed
1387
        if (rule.match(/(^|,|,)(NOWATCH|NW)(,|,|$)/)) {
nanahira's avatar
nanahira committed
1388
          this.hostinfo.no_watch = true;
nanahira's avatar
nanahira committed
1389
        }
nanahira's avatar
nanahira committed
1390 1391 1392 1393 1394 1395 1396 1397
        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
1398
      }
1399 1400 1401 1402 1403 1404 1405
      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;
      }
1406
      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
1407 1408
      try {
        this.process = spawn('./ygopro', param, {
mercury233's avatar
mercury233 committed
1409
          cwd: 'ygopro'
mercury233's avatar
mercury233 committed
1410
        });
nanahira's avatar
nanahira committed
1411
        this.process_pid = this.process.pid;
mercury233's avatar
fix  
mercury233 committed
1412 1413 1414
        this.process.on('error', (function(_this) {
          return function(err) {
            _.each(_this.players, function(player) {
mercury233's avatar
mercury233 committed
1415
              return ygopro.stoc_die(player, "${create_room_failed}");
mercury233's avatar
fix  
mercury233 committed
1416 1417 1418 1419
            });
            _this["delete"]();
          };
        })(this));
mercury233's avatar
mercury233 committed
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
        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
1432
            if (!_this.windbot && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1433 1434 1435 1436 1437
              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
1438
                var buffer, len2, m, ref2;
nanahira's avatar
nanahira committed
1439
                ref2 = player.pre_establish_buffers;
nanahira's avatar
nanahira committed
1440 1441
                for (m = 0, len2 = ref2.length; m < len2; m++) {
                  buffer = ref2[m];
mercury233's avatar
mercury233 committed
1442 1443 1444 1445 1446 1447 1448
                  player.server.write(buffer);
                }
                player.established = true;
                player.pre_establish_buffers = [];
              });
            });
            if (_this.windbot) {
mercury233's avatar
mercury233 committed
1449 1450 1451
              setTimeout(function() {
                return _this.add_windbot(_this.windbot);
              }, 200);
mercury233's avatar
mercury233 committed
1452 1453 1454
            }
          };
        })(this));
mercury233's avatar
mercury233 committed
1455 1456
        this.process.stderr.on('data', (function(_this) {
          return function(data) {
mercury233's avatar
mercury233 committed
1457 1458 1459 1460
            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
1461
            _this.has_ygopro_error = true;
1462 1463
            _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
1464
              _this.send_replays();
1465 1466
              _this.process.kill();
            }
mercury233's avatar
mercury233 committed
1467 1468
          };
        })(this));
mercury233's avatar
mercury233 committed
1469
      } catch (error1) {
mercury233's avatar
mercury233 committed
1470
        this.error = "${create_room_failed}";
mercury233's avatar
mercury233 committed
1471 1472 1473 1474
      }
    }

    Room.prototype["delete"] = function() {
nanahira's avatar
fix  
nanahira committed
1475
      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
1476 1477 1478
      if (this.deleted) {
        return;
      }
1479
      score_array = [];
nanahira's avatar
nanahira committed
1480 1481 1482
      ref2 = this.scores;
      for (name in ref2) {
        score = ref2[name];
nanahira's avatar
nanahira committed
1483
        score_form = {
1484
          name: name.split('$')[0],
nanahira's avatar
nanahira committed
1485
          score: score,
1486 1487
          deck: null,
          name_vpass: name
nanahira's avatar
nanahira committed
1488 1489 1490 1491 1492
        };
        if (this.decks[name]) {
          score_form.deck = this.decks[name];
        }
        score_array.push(score_form);
1493
      }
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
      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
1511 1512 1513 1514 1515 1516 1517 1518
      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
1519
              name: null,
nanahira's avatar
nanahira committed
1520 1521
              score: -5,
              deck: null
nanahira's avatar
-5  
nanahira committed
1522
            };
1523
          }
nanahira's avatar
-5  
nanahira committed
1524 1525
          if (!score_array[1]) {
            score_array[1] = {
nanahira's avatar
nanahira committed
1526
              name: null,
nanahira's avatar
nanahira committed
1527 1528
              score: -5,
              deck: null
mercury233's avatar
merge  
mercury233 committed
1529
            };
nanahira's avatar
-5  
nanahira committed
1530 1531 1532
          }
          score_array[0].score = -5;
          score_array[1].score = -5;
mercury233's avatar
merge  
mercury233 committed
1533
        }
nanahira's avatar
fix  
nanahira committed
1534 1535 1536 1537 1538 1539 1540 1541
        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
1542 1543 1544 1545 1546 1547 1548 1549
        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
1550 1551
            userdeckA: score_array[0].deck,
            userdeckB: score_array[1].deck,
nanahira's avatar
fix  
nanahira committed
1552
            replays: formatted_replays,
nanahira's avatar
-5  
nanahira committed
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
            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
1568
      }
nanahira's avatar
nanahira committed
1569
      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
1570
        room_name = this.name;
nanahira's avatar
nanahira committed
1571
        challonge.matches._update({
1572
          id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
1573
          matchId: this.challonge_info.id,
nanahira's avatar
nanahira committed
1574
          match: this.get_challonge_score(),
nanahira's avatar
nanahira committed
1575 1576
          callback: function(err, data) {
            if (err) {
nanahira's avatar
js  
nanahira committed
1577
              log.warn("Errored pushing scores to Challonge.", room_name, err);
nanahira's avatar
nanahira committed
1578 1579
            } else {
              refresh_challonge_cache();
nanahira's avatar
nanahira committed
1580 1581 1582 1583
            }
          }
        });
      }
mercury233's avatar
mercury233 committed
1584
      if (this.player_datas.length && settings.modules.cloud_replay.enabled) {
1585
        replay_id = this.cloud_replay_id;
mercury233's avatar
mercury233 committed
1586 1587 1588
        if (this.has_ygopro_error) {
          log_rep_id = true;
        }
mercury233's avatar
mercury233 committed
1589 1590 1591
        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) {
1592
          player_ips.push(player.key);
mercury233's avatar
mercury233 committed
1593 1594 1595
        });
        recorder_buffer = Buffer.concat(this.recorder_buffers);
        zlib.deflate(recorder_buffer, function(err, replay_buffer) {
1596
          var date_time, recorded_ip;
mercury233's avatar
mercury233 committed
1597 1598 1599
          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
1600
          if (!log_rep_id && !settings.modules.cloud_replay.never_expire) {
mercury233's avatar
mercury233 committed
1601 1602
            redisdb.expire("replay:" + replay_id, 60 * 60 * 24);
          }
mercury233's avatar
mercury233 committed
1603 1604 1605 1606 1607 1608 1609 1610
          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
1611
          if (log_rep_id) {
mercury233's avatar
mercury233 committed
1612 1613
            log.info("error replay: R#" + replay_id);
          }
mercury233's avatar
mercury233 committed
1614 1615 1616 1617 1618 1619
        });
      }
      this.watcher_buffers = [];
      this.recorder_buffers = [];
      this.players = [];
      if (this.watcher) {
mercury233's avatar
mercury233 committed
1620
        this.watcher.destroy();
mercury233's avatar
mercury233 committed
1621
      }
mercury233's avatar
fix  
mercury233 committed
1622 1623 1624
      if (this.recorder) {
        this.recorder.destroy();
      }
mercury233's avatar
mercury233 committed
1625 1626
      this.deleted = true;
      index = _.indexOf(ROOM_all, this);
nanahira's avatar
nanahira committed
1627
      if (settings.modules.reconnect.enabled) {
nanahira's avatar
nanahira committed
1628
        ROOM_clear_disconnect(index);
nanahira's avatar
nanahira committed
1629
      }
mercury233's avatar
mercury233 committed
1630
      if (index !== -1) {
1631
        ROOM_all[index] = null;
mercury233's avatar
mercury233 committed
1632
      }
mercury233's avatar
mercury233 committed
1633
      if (!this.windbot && this.established && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1634
        roomlist["delete"](this);
mercury233's avatar
mercury233 committed
1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
      }
    };

    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;
    };

1660
    Room.prototype.get_disconnected_count = function() {
1661 1662
      var found, len2, m, player, ref2;
      if (!settings.modules.reconnect.enabled) {
1663
        return 0;
1664
      }
1665
      found = 0;
1666 1667 1668
      ref2 = this.get_playing_player();
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        player = ref2[m];
1669 1670
        if (player.closed) {
          found++;
1671 1672 1673 1674 1675
        }
      }
      return found;
    };

nanahira's avatar
nanahira committed
1676 1677
    Room.prototype.get_challonge_score = function() {
      var challonge_duel_log;
nanahira's avatar
nanahira committed
1678
      if (!settings.modules.challonge.enabled || this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || this.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
1679 1680 1681
        return null;
      }
      challonge_duel_log = {};
1682
      if (this.scores[this.dueling_players[0].name_vpass] > this.scores[this.dueling_players[1].name_vpass]) {
nanahira's avatar
nanahira committed
1683
        challonge_duel_log.winnerId = this.dueling_players[0].challonge_info.id;
1684
      } else if (this.scores[this.dueling_players[0].name_vpass] < this.scores[this.dueling_players[1].name_vpass]) {
nanahira's avatar
nanahira committed
1685 1686 1687 1688 1689 1690
        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) {
1691
          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
1692
        } else if (this.dueling_players[1].challonge_info.id === this.challonge_info.player1Id && this.dueling_players[0].challonge_info.id === this.challonge_info.player2Id) {
1693
          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
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709
        } 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
1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
    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
1728 1729 1730
    Room.prototype.add_windbot = function(botdata) {
      this.windbot = botdata;
      request({
1731
        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
1732 1733 1734
      }, (function(_this) {
        return function(error, response, body) {
          if (error) {
mercury233's avatar
merge  
mercury233 committed
1735
            log.warn('windbot add error', error, _this.name);
mercury233's avatar
mercury233 committed
1736
            ygopro.stoc_send_chat_to_room(_this, "${add_windbot_failed}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
1737 1738 1739 1740 1741
          }
        };
      })(this));
    };

mercury233's avatar
mercury233 committed
1742
    Room.prototype.connect = function(client) {
mercury233's avatar
mercury233 committed
1743
      var host_player;
mercury233's avatar
mercury233 committed
1744
      this.players.push(client);
nanahira's avatar
nanahira committed
1745
      client.join_time = moment();
mercury233's avatar
mercury233 committed
1746
      if (this.random_type) {
mercury233's avatar
mercury233 committed
1747
        client.abuse_count = 0;
mercury233's avatar
mercury233 committed
1748 1749
        host_player = this.get_host();
        if (host_player && (host_player !== client)) {
mercury233's avatar
mercury233 committed
1750 1751
          ROOM_players_oppentlist[host_player.ip] = client.ip;
          ROOM_players_oppentlist[client.ip] = host_player.ip;
mercury233's avatar
mercury233 committed
1752
        } else {
mercury233's avatar
mercury233 committed
1753
          ROOM_players_oppentlist[client.ip] = null;
mercury233's avatar
mercury233 committed
1754 1755 1756
        }
      }
      if (this.established) {
nanahira's avatar
nanahira committed
1757
        if (!this.windbot && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1758 1759 1760
          roomlist.update(this);
        }
        client.server.connect(this.port, '127.0.0.1', function() {
nanahira's avatar
nanahira committed
1761
          var buffer, len2, m, ref2;
nanahira's avatar
nanahira committed
1762
          ref2 = client.pre_establish_buffers;
nanahira's avatar
nanahira committed
1763 1764
          for (m = 0, len2 = ref2.length; m < len2; m++) {
            buffer = ref2[m];
mercury233's avatar
mercury233 committed
1765 1766 1767 1768 1769 1770 1771 1772 1773
            client.server.write(buffer);
          }
          client.established = true;
          client.pre_establish_buffers = [];
        });
      }
    };

    Room.prototype.disconnect = function(client, error) {
1774
      var index, left_name, len2, len3, m, n, player, ref2, ref3;
nanahira's avatar
nanahira committed
1775 1776 1777
      if (client.had_new_reconnection) {
        return;
      }
mercury233's avatar
mercury233 committed
1778
      if (client.is_post_watcher) {
mercury233's avatar
mercury233 committed
1779
        ygopro.stoc_send_chat_to_room(this, (client.name + " ${quit_watch}") + (error ? ": " + error : ''));
mercury233's avatar
mercury233 committed
1780 1781 1782 1783
        index = _.indexOf(this.watchers, client);
        if (index !== -1) {
          this.watchers.splice(index, 1);
        }
nanahira's avatar
nanahira committed
1784
        client.server.destroy();
mercury233's avatar
mercury233 committed
1785
      } else {
nanahira's avatar
nanahira committed
1786
        if (this.arena && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && this.disconnector !== 'server' && !this.arena_score_handled) {
1787 1788 1789 1790 1791 1792 1793
          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;
              }
1794
            }
1795
            this.scores[client.name_vpass] = -9;
1796 1797 1798 1799 1800 1801 1802 1803
          } 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
-5  
nanahira committed
1804
          }
nanahira's avatar
nanahira committed
1805
          this.arena_score_handled = true;
1806
        }
mercury233's avatar
mercury233 committed
1807 1808 1809 1810
        index = _.indexOf(this.players, client);
        if (index !== -1) {
          this.players.splice(index, 1);
        }
nanahira's avatar
nanahira committed
1811
        if (this.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && this.disconnector !== 'server' && client.pos < 4) {
1812
          this.finished = true;
nanahira's avatar
nanahira committed
1813
          if (!this.finished_by_death) {
1814
            this.scores[client.name_vpass] = -9;
nanahira's avatar
fix  
nanahira committed
1815
            if (this.random_type && !client.flee_free && (!settings.modules.reconnect.enabled || this.get_disconnected_count() === 0)) {
nanahira's avatar
nanahira committed
1816
              ROOM_ban_player(client.name, client.ip, "${random_ban_reason_flee}");
mercury233's avatar
mercury233 committed
1817 1818 1819
              if (settings.modules.random_duel.record_match_scores && this.random_type === 'M') {
                ROOM_player_flee(client.name_vpass);
              }
nanahira's avatar
nanahira committed
1820
            }
mercury233's avatar
mercury233 committed
1821
          }
mercury233's avatar
mercury233 committed
1822
        }
nanahira's avatar
nanahira committed
1823 1824
        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
1825
          ygopro.stoc_send_chat_to_room(this, (left_name + " ${left_game}") + (error ? ": " + error : ''));
nanahira's avatar
nanahira committed
1826
          if (!this.windbot && this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
1827 1828 1829
            roomlist.update(this);
          }
        } else {
nanahira's avatar
nanahira committed
1830
          this.send_replays();
mercury233's avatar
mercury233 committed
1831 1832 1833
          this.process.kill();
          this["delete"]();
        }
nanahira's avatar
nanahira committed
1834
        if (!CLIENT_reconnect_unregister(client, false, true)) {
nanahira's avatar
nanahira committed
1835 1836
          client.server.destroy();
        }
mercury233's avatar
mercury233 committed
1837 1838 1839
      }
    };

nanahira's avatar
nanahira committed
1840 1841
    Room.prototype.start_death = function() {
      var oppo_pos, win_pos;
nanahira's avatar
nanahira committed
1842
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || this.death) {
nanahira's avatar
nanahira committed
1843 1844 1845
        return false;
      }
      oppo_pos = this.hostinfo.mode === 2 ? 2 : 1;
nanahira's avatar
nanahira committed
1846
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.DUELING) {
nanahira's avatar
nanahira committed
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 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
        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
1899
      if (this.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || !this.death) {
nanahira's avatar
nanahira committed
1900 1901 1902 1903 1904 1905 1906
        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
1907 1908 1909 1910
    return Room;

  })();

神楽坂玲奈's avatar
神楽坂玲奈 committed
1911
  net.createServer(function(client) {
mercury233's avatar
mercury233 committed
1912 1913
    var connect_count, server;
    client.ip = client.remoteAddress;
nanahira's avatar
nanahira committed
1914
    client.is_local = client.ip && (client.ip.includes('127.0.0.1') || client.ip.includes(real_windbot_server_ip));
mercury233's avatar
mercury233 committed
1915
    connect_count = ROOM_connected_ip[client.ip] || 0;
1916
    if (!settings.modules.test_mode.no_connect_count_limit && !client.is_local) {
mercury233's avatar
mercury233 committed
1917 1918 1919
      connect_count++;
    }
    ROOM_connected_ip[client.ip] = connect_count;
神楽坂玲奈's avatar
神楽坂玲奈 committed
1920 1921
    server = new net.Socket();
    client.server = server;
nanahira's avatar
nanahira committed
1922
    server.client = client;
mercury233's avatar
mercury233 committed
1923
    client.setTimeout(2000);
1924
    client.on('close', function(had_error) {
mercury233's avatar
mercury233 committed
1925
      var room;
1926
      room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
1927 1928 1929 1930 1931
      connect_count = ROOM_connected_ip[client.ip];
      if (connect_count > 0) {
        connect_count--;
      }
      ROOM_connected_ip[client.ip] = connect_count;
1932
      if (!client.closed) {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
1933
        client.closed = true;
nanahira's avatar
nanahira committed
1934 1935 1936
        if (settings.modules.heartbeat_detection.enabled) {
          CLIENT_heartbeat_unregister(client);
        }
1937
        if (room) {
nanahira's avatar
nanahira committed
1938
          if (!CLIENT_reconnect_register(client, client.rid)) {
nanahira's avatar
nanahira committed
1939 1940 1941 1942
            room.disconnect(client);
          }
        } else if (!client.had_new_reconnection) {
          client.server.destroy();
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1943
        }
mercury233's avatar
mercury233 committed
1944 1945
      }
    });
1946
    client.on('error', function(error) {
mercury233's avatar
mercury233 committed
1947
      var room;
1948
      room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
1949 1950 1951 1952 1953
      connect_count = ROOM_connected_ip[client.ip];
      if (connect_count > 0) {
        connect_count--;
      }
      ROOM_connected_ip[client.ip] = connect_count;
1954
      if (!client.closed) {
nanahira's avatar
nanahira committed
1955
        client.closed = true;
1956
        if (room) {
nanahira's avatar
nanahira committed
1957
          if (!CLIENT_reconnect_register(client, client.rid, error)) {
nanahira's avatar
nanahira committed
1958 1959 1960 1961
            room.disconnect(client, error);
          }
        } else if (!client.had_new_reconnection) {
          client.server.destroy();
1962
        }
神楽坂玲奈's avatar
神楽坂玲奈 committed
1963
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
1964
    });
1965
    client.on('timeout', function() {
nanahira's avatar
nanahira committed
1966
      if (!(settings.modules.reconnect.enabled && (disconnect_list[CLIENT_get_authorize_key(client)] || client.had_new_reconnection))) {
nanahira's avatar
nanahira committed
1967
        client.destroy();
nanahira's avatar
nanahira committed
1968
      }
1969
    });
1970
    server.on('close', function(had_error) {
1971
      var room;
nanahira's avatar
nanahira committed
1972
      room = ROOM_all[server.client.rid];
1973 1974 1975
      if (room) {
        room.disconnector = 'server';
      }
1976 1977
      if (!server.closed) {
        server.closed = true;
mercury233's avatar
mercury233 committed
1978
      }
nanahira's avatar
nanahira committed
1979 1980 1981 1982 1983 1984 1985
      if (!server.client) {
        return;
      }
      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
1986 1987
      }
    });
1988
    server.on('error', function(error) {
1989
      var room;
nanahira's avatar
nanahira committed
1990
      room = ROOM_all[server.client.rid];
1991 1992 1993
      if (room) {
        room.disconnector = 'server';
      }
1994
      server.closed = error;
nanahira's avatar
nanahira committed
1995 1996 1997 1998 1999 2000 2001
      if (!server.client) {
        return;
      }
      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
2002 2003
      }
    });
mercury233's avatar
mercury233 committed
2004
    if (ROOM_bad_ip[client.ip] > 5 || ROOM_connected_ip[client.ip] > 10) {
mercury233's avatar
mercury233 committed
2005
      log.info('BAD IP', client.ip);
nanahira's avatar
nanahira committed
2006
      CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2007 2008
      return;
    }
mercury233's avatar
mercury233 committed
2009
    if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2010 2011 2012
      client.open_cloud_replay = function(err, replay) {
        var buffer;
        if (err || !replay) {
mercury233's avatar
mercury233 committed
2013
          ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2014
          return;
mercury233's avatar
mercury233 committed
2015
        }
mercury233's avatar
mercury233 committed
2016
        redisdb.expire("replay:" + replay.replay_id, 60 * 60 * 48);
nanahira's avatar
nanahira committed
2017
        buffer = Buffer.from(replay.replay_buffer, 'binary');
mercury233's avatar
mercury233 committed
2018 2019
        zlib.unzip(buffer, function(err, replay_buffer) {
          if (err) {
mercury233's avatar
mercury233 committed
2020
            log.info("cloud replay unzip error: " + err);
mercury233's avatar
mercury233 committed
2021
            ygopro.stoc_send_chat(client, "${cloud_replay_error}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
2022
            CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2023 2024
            return;
          }
mercury233's avatar
mercury233 committed
2025
          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
2026
          client.write(replay_buffer, function() {
nanahira's avatar
nanahira committed
2027
            CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2028
          });
mercury233's avatar
mercury233 committed
2029
        });
mercury233's avatar
mercury233 committed
2030 2031
      };
    }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2032
    client.pre_establish_buffers = new Array();
mercury233's avatar
mercury233 committed
2033
    client.on('data', function(ctos_buffer) {
nanahira's avatar
nanahira committed
2034
      var b, bad_ip_count, buffer, cancel, ctos_message_length, ctos_proto, datas, info, len2, len3, looplimit, m, n, room, struct;
2035
      if (client.is_post_watcher) {
2036
        room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
2037
        if (room && !CLIENT_is_banned_by_mc(client)) {
mercury233's avatar
mercury233 committed
2038
          room.watcher.write(ctos_buffer);
2039
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2040
      } else {
mercury233's avatar
mercury233 committed
2041 2042
        ctos_message_length = 0;
        ctos_proto = 0;
2043
        datas = [];
mercury233's avatar
mercury233 committed
2044
        looplimit = 0;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2045
        while (true) {
2046 2047
          if (ctos_message_length === 0) {
            if (ctos_buffer.length >= 2) {
mercury233's avatar
test3  
mercury233 committed
2048
              ctos_message_length = ctos_buffer.readUInt16LE(0);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2049
            } else {
mercury233's avatar
mercury233 committed
2050 2051 2052
              if (ctos_buffer.length !== 0) {
                log.warn("bad ctos_buffer length", client.ip);
              }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2053 2054
              break;
            }
2055 2056
          } else if (ctos_proto === 0) {
            if (ctos_buffer.length >= 3) {
mercury233's avatar
test3  
mercury233 committed
2057
              ctos_proto = ctos_buffer.readUInt8(2);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2058
            } else {
mercury233's avatar
mercury233 committed
2059
              log.warn("bad ctos_proto length", client.ip);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2060
              break;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2061 2062
            }
          } else {
2063
            if (ctos_buffer.length >= 2 + ctos_message_length) {
2064
              cancel = false;
nanahira's avatar
nanahira committed
2065 2066 2067 2068
              if (settings.modules.reconnect.enabled && client.pre_reconnecting && ygopro.constants.CTOS[ctos_proto] !== 'UPDATE_DECK') {
                cancel = true;
              }
              if (ygopro.ctos_follows[ctos_proto] && !cancel) {
2069
                b = ctos_buffer.slice(3, ctos_message_length - 1 + 3);
2070
                info = null;
2071
                if (struct = ygopro.structs[ygopro.proto_structs.CTOS[ygopro.constants.CTOS[ctos_proto]]]) {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2072
                  struct._setBuff(b);
2073 2074 2075
                  info = _.clone(struct.fields);
                }
                if (ygopro.ctos_follows[ctos_proto].synchronous) {
2076
                  cancel = ygopro.ctos_follows[ctos_proto].callback(b, info, client, client.server, datas);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2077
                } else {
2078
                  ygopro.ctos_follows[ctos_proto].callback(b, info, client, client.server, datas);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2079 2080
                }
              }
2081 2082 2083
              if (!cancel) {
                datas.push(ctos_buffer.slice(0, 2 + ctos_message_length));
              }
2084 2085
              ctos_buffer = ctos_buffer.slice(2 + ctos_message_length);
              ctos_message_length = 0;
mercury233's avatar
test3  
mercury233 committed
2086
              ctos_proto = 0;
mercury233's avatar
fix  
mercury233 committed
2087 2088 2089 2090
            } 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
2091 2092
              break;
            }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2093
          }
mercury233's avatar
mercury233 committed
2094
          looplimit++;
mercury233's avatar
mercury233 committed
2095 2096 2097
          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
2098
            if (bad_ip_count) {
mercury233's avatar
mercury233 committed
2099
              ROOM_bad_ip[client.ip] = bad_ip_count + 1;
mercury233's avatar
mercury233 committed
2100
            } else {
mercury233's avatar
mercury233 committed
2101
              ROOM_bad_ip[client.ip] = 1;
mercury233's avatar
mercury233 committed
2102
            }
nanahira's avatar
nanahira committed
2103
            CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2104 2105
            break;
          }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2106
        }
nanahira's avatar
nanahira committed
2107 2108 2109
        if (!client.server) {
          return;
        }
2110
        if (client.established) {
nanahira's avatar
nanahira committed
2111 2112 2113
          for (m = 0, len2 = datas.length; m < len2; m++) {
            buffer = datas[m];
            client.server.write(buffer);
2114 2115
          }
        } else {
nanahira's avatar
nanahira committed
2116 2117
          for (n = 0, len3 = datas.length; n < len3; n++) {
            buffer = datas[n];
2118 2119 2120
            client.pre_establish_buffers.push(buffer);
          }
        }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2121 2122
      }
    });
mercury233's avatar
mercury233 committed
2123
    server.on('data', function(stoc_buffer) {
nanahira's avatar
nanahira committed
2124
      var b, buffer, cancel, datas, info, len2, looplimit, m, stanzas, stoc_message_length, stoc_proto, struct;
mercury233's avatar
mercury233 committed
2125 2126
      stoc_message_length = 0;
      stoc_proto = 0;
2127
      datas = [];
mercury233's avatar
mercury233 committed
2128
      looplimit = 0;
神楽坂玲奈's avatar
神楽坂玲奈 committed
2129
      while (true) {
2130 2131
        if (stoc_message_length === 0) {
          if (stoc_buffer.length >= 2) {
mercury233's avatar
test3  
mercury233 committed
2132
            stoc_message_length = stoc_buffer.readUInt16LE(0);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2133
          } else {
mercury233's avatar
mercury233 committed
2134
            if (stoc_buffer.length !== 0) {
nanahira's avatar
nanahira committed
2135
              log.warn("bad stoc_buffer length", server.client.ip);
mercury233's avatar
mercury233 committed
2136
            }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2137 2138
            break;
          }
2139 2140
        } else if (stoc_proto === 0) {
          if (stoc_buffer.length >= 3) {
mercury233's avatar
test3  
mercury233 committed
2141
            stoc_proto = stoc_buffer.readUInt8(2);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2142
          } else {
nanahira's avatar
nanahira committed
2143
            log.warn("bad stoc_proto length", server.client.ip);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2144 2145 2146
            break;
          }
        } else {
2147
          if (stoc_buffer.length >= 2 + stoc_message_length) {
2148
            cancel = false;
2149 2150 2151
            stanzas = stoc_proto;
            if (ygopro.stoc_follows[stoc_proto]) {
              b = stoc_buffer.slice(3, stoc_message_length - 1 + 3);
2152
              info = null;
2153
              if (struct = ygopro.structs[ygopro.proto_structs.STOC[ygopro.constants.STOC[stoc_proto]]]) {
神楽坂玲奈's avatar
神楽坂玲奈 committed
2154
                struct._setBuff(b);
2155 2156 2157
                info = _.clone(struct.fields);
              }
              if (ygopro.stoc_follows[stoc_proto].synchronous) {
2158
                cancel = ygopro.stoc_follows[stoc_proto].callback(b, info, server.client, server, datas);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2159
              } else {
2160
                ygopro.stoc_follows[stoc_proto].callback(b, info, server.client, server, datas);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2161 2162
              }
            }
2163 2164 2165
            if (!cancel) {
              datas.push(stoc_buffer.slice(0, 2 + stoc_message_length));
            }
2166 2167
            stoc_buffer = stoc_buffer.slice(2 + stoc_message_length);
            stoc_message_length = 0;
mercury233's avatar
test3  
mercury233 committed
2168
            stoc_proto = 0;
神楽坂玲奈's avatar
神楽坂玲奈 committed
2169
          } else {
nanahira's avatar
nanahira committed
2170
            log.warn("bad stoc_message length", server.client.ip);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2171 2172 2173
            break;
          }
        }
mercury233's avatar
mercury233 committed
2174 2175
        looplimit++;
        if (looplimit > 800) {
nanahira's avatar
nanahira committed
2176
          log.info("error stoc", server.client.name);
mercury233's avatar
mercury233 committed
2177
          server.destroy();
mercury233's avatar
mercury233 committed
2178 2179
          break;
        }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
2180
      }
nanahira's avatar
nanahira committed
2181 2182 2183 2184 2185
      if (server.client && !server.client.closed) {
        for (m = 0, len2 = datas.length; m < len2; m++) {
          buffer = datas[m];
          server.client.write(buffer);
        }
2186
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2187
    });
神楽坂玲奈's avatar
神楽坂玲奈 committed
2188
  }).listen(settings.port, function() {
mercury233's avatar
mercury233 committed
2189
    log.info("server started", settings.port);
神楽坂玲奈's avatar
神楽坂玲奈 committed
2190
  });
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2191

mercury233's avatar
mercury233 committed
2192 2193 2194 2195
  if (settings.modules.stop) {
    log.info("NOTE: server not open due to config, ", settings.modules.stop);
  }

nanahira's avatar
nanahira committed
2196
  ygopro.ctos_follow('PLAYER_INFO', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
2197 2198 2199 2200 2201 2202 2203
    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
2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
    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
2216
    if (settings.modules.mycard.enabled) {
nanahira's avatar
nanahira committed
2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
      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;
        }
      });
    }
2233 2234 2235 2236 2237
    struct = ygopro.structs["CTOS_PlayerInfo"];
    struct._setBuff(buffer);
    struct.set("name", name);
    buffer = struct.buffer;
    client.name = name;
nanahira's avatar
nanahira committed
2238
    client.vpass = vpass;
2239
    client.name_vpass = vpass ? name + "$" + vpass : name;
2240
    if (!settings.modules.i18n.auto_pick || client.is_local) {
mercury233's avatar
mercury233 committed
2241 2242 2243 2244
      client.lang = settings.modules.i18n["default"];
    } else {
      geo = geoip.lookup(client.ip);
      if (!geo) {
mercury233's avatar
mercury233 committed
2245
        log.warn("fail to locate ip", client.name, client.ip);
mercury233's avatar
mercury233 committed
2246 2247 2248 2249 2250 2251 2252 2253
        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
2254
    }
2255
    return false;
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2256 2257
  });

nanahira's avatar
nanahira committed
2258
  ygopro.ctos_follow('JOIN_GAME', false, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
2259
    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
2260
    info.pass = info.pass.trim();
nanahira's avatar
nanahira committed
2261 2262
    client.pass = info.pass;
    if (CLIENT_is_able_to_reconnect(client) || CLIENT_is_able_to_kick_reconnect(client)) {
nanahira's avatar
nanahira committed
2263 2264 2265
      CLIENT_pre_reconnect(client);
      return;
    } else if (settings.modules.stop) {
mercury233's avatar
mercury233 committed
2266
      ygopro.stoc_die(client, settings.modules.stop);
nanahira's avatar
nanahira committed
2267 2268
    } else if (info.pass === "Marshtomp" || info.pass === "the Big Brother") {
      ygopro.stoc_die(client, "${bad_user_name}");
mercury233's avatar
mercury233 committed
2269
    } else if (info.pass.toUpperCase() === "R" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2270
      ygopro.stoc_send_chat(client, "${cloud_replay_hint}", ygopro.constants.COLORS.BABYBLUE);
2271
      redisdb.lrange(CLIENT_get_authorize_key(client) + ":replays", 0, 2, function(err, result) {
mercury233's avatar
mercury233 committed
2272 2273 2274
        _.each(result, function(replay_id, id) {
          redisdb.hgetall("replay:" + replay_id, function(err, replay) {
            if (err || !replay) {
mercury233's avatar
mercury233 committed
2275 2276 2277
              if (err) {
                log.info("cloud replay getall error: " + err);
              }
mercury233's avatar
mercury233 committed
2278 2279 2280
              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
2281
          });
mercury233's avatar
mercury233 committed
2282 2283 2284 2285 2286
        });
      });
      setTimeout((function() {
        ygopro.stoc_send(client, 'ERROR_MSG', {
          msg: 1,
mercury233's avatar
mercury233 committed
2287
          code: 9
mercury233's avatar
mercury233 committed
2288
        });
nanahira's avatar
nanahira committed
2289
        CLIENT_kick(client);
mercury233's avatar
mercury233 committed
2290
      }), 500);
mercury233's avatar
mercury233 committed
2291
    } else if (info.pass.slice(0, 2).toUpperCase() === "R#" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2292
      replay_id = info.pass.split("#")[1];
mercury233's avatar
fix  
mercury233 committed
2293
      if (replay_id > 0 && replay_id <= 9) {
mercury233's avatar
mercury233 committed
2294
        redisdb.lindex(client.ip + ":replays", replay_id - 1, function(err, replay_id) {
mercury233's avatar
mercury233 committed
2295
          if (err || !replay_id) {
mercury233's avatar
mercury233 committed
2296 2297 2298
            if (err) {
              log.info("cloud replay replayid error: " + err);
            }
mercury233's avatar
mercury233 committed
2299
            ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2300 2301 2302 2303
            return;
          }
          redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
        });
mercury233's avatar
mercury233 committed
2304 2305 2306
      } else if (replay_id) {
        redisdb.hgetall("replay:" + replay_id, client.open_cloud_replay);
      } else {
mercury233's avatar
mercury233 committed
2307
        ygopro.stoc_die(client, "${cloud_replay_no}");
mercury233's avatar
mercury233 committed
2308
      }
mercury233's avatar
mercury233 committed
2309
    } else if (info.pass.toUpperCase() === "W" && settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
2310 2311
      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
2312
    } else if (info.version !== settings.version) {
mercury233's avatar
mercury233 committed
2313
      ygopro.stoc_send_chat(client, settings.modules.update, ygopro.constants.COLORS.RED);
mercury233's avatar
fix  
mercury233 committed
2314 2315 2316 2317
      ygopro.stoc_send(client, 'ERROR_MSG', {
        msg: 4,
        code: settings.version
      });
nanahira's avatar
nanahira committed
2318
      CLIENT_kick(client);
nanahira's avatar
nanahira committed
2319
    } else if (!info.pass.length && !settings.modules.random_duel.enabled && !settings.modules.windbot.enabled && !settings.modules.challonge.enabled) {
mercury233's avatar
mercury233 committed
2320
      ygopro.stoc_die(client, "${blank_room_name}");
mercury233's avatar
fix  
mercury233 committed
2321
    } else if (info.pass.length && settings.modules.mycard.enabled && info.pass.slice(0, 3) !== 'AI#') {
mercury233's avatar
mercury233 committed
2322
      ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2323
      if (info.pass.length <= 8) {
mercury233's avatar
mercury233 committed
2324
        ygopro.stoc_die(client, '${invalid_password_length}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2325 2326
        return;
      }
nanahira's avatar
nanahira committed
2327
      buffer = Buffer.from(info.pass.slice(0, 8), 'base64');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2328
      if (buffer.length !== 6) {
mercury233's avatar
mercury233 committed
2329
        ygopro.stoc_die(client, '${invalid_password_payload}');
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2330 2331
        return;
      }
nanahira's avatar
nanahira committed
2332
      check_buffer_indentity = function(buf) {
nanahira's avatar
nanahira committed
2333
        var checksum, i, m, ref2;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2334
        checksum = 0;
nanahira's avatar
nanahira committed
2335
        for (i = m = 0, ref2 = buf.length; 0 <= ref2 ? m < ref2 : m > ref2; i = 0 <= ref2 ? ++m : --m) {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2336
          checksum += buf.readUInt8(i);
2337
        }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2338 2339
        return (checksum & 0xFF) === 0;
      };
nanahira's avatar
fix  
nanahira committed
2340
      buffer_handle_callback = function(buffer, decrypted_buffer, match_permit) {
nanahira's avatar
nanahira committed
2341
        var action, len2, len3, m, n, name, opt1, opt2, opt3, options, player, ref2, ref3, room, title;
nanahira's avatar
nanahira committed
2342 2343 2344
        if (client.closed) {
          return;
        }
2345 2346
        action = buffer.readUInt8(1) >> 4;
        if (buffer !== decrypted_buffer && (action === 1 || action === 2 || action === 4)) {
mercury233's avatar
mercury233 committed
2347
          ygopro.stoc_die(client, '${invalid_password_unauthorized}');
2348 2349 2350 2351 2352 2353
          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
2354
            if (ROOM_find_by_name(name)) {
mercury233's avatar
mercury233 committed
2355
              ygopro.stoc_die(client, '${invalid_password_existed}');
2356 2357 2358
              return;
            }
            opt1 = buffer.readUInt8(2);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2359
            opt2 = buffer.readUInt16LE(3);
2360 2361 2362 2363 2364 2365
            opt3 = buffer.readUInt8(5);
            options = {
              lflist: 0,
              time_limit: 180,
              rule: (opt1 >> 5) & 3,
              mode: (opt1 >> 3) & 3,
nanahira's avatar
fix  
nanahira committed
2366
              duel_rule: (!!((opt1 >> 2) & 1) ? 3 : 4),
2367 2368 2369 2370
              no_check_deck: !!((opt1 >> 1) & 1),
              no_shuffle_deck: !!(opt1 & 1),
              start_lp: opt2,
              start_hand: opt3 >> 4,
nanahira's avatar
nanahira committed
2371 2372 2373
              draw_count: opt3 & 0xF,
              no_watch: false,
              auto_death: false
2374
            };
mercury233's avatar
mercury233 committed
2375
            options.lflist = _.findIndex(lflists, function(list) {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2376
              return ((options.rule === 1) === list.tcg) && list.date.isBefore();
神楽坂玲奈's avatar
神楽坂玲奈 committed
2377
            });
2378
            room = new Room(name, options);
nanahira's avatar
nanahira committed
2379 2380 2381 2382
            if (room) {
              room.title = info.pass.slice(8).replace(String.fromCharCode(0xFEFF), ' ');
              room["private"] = action === 2;
            }
2383 2384 2385
            break;
          case 3:
            name = info.pass.slice(8);
mercury233's avatar
mercury233 committed
2386
            room = ROOM_find_by_name(name);
2387
            if (!room) {
mercury233's avatar
mercury233 committed
2388
              ygopro.stoc_die(client, '${invalid_password_not_found}');
2389 2390 2391 2392
              return;
            }
            break;
          case 4:
nanahira's avatar
move  
nanahira committed
2393 2394 2395 2396
            if (match_permit && !match_permit.permit) {
              ygopro.stoc_die(client, '${invalid_password_unauthorized}');
              return;
            }
mercury233's avatar
mercury233 committed
2397
            room = ROOM_find_or_create_by_name('M#' + info.pass.slice(8));
nanahira's avatar
nanahira committed
2398
            if (room) {
nanahira's avatar
nanahira committed
2399 2400 2401 2402 2403 2404 2405 2406 2407
              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
2408 2409 2410 2411 2412 2413
              room["private"] = true;
              room.arena = settings.modules.arena_mode.mode;
              if (room.arena === "athletic") {
                room.max_player = 2;
                room.welcome = "${athletic_arena_tip}";
              }
2414
            }
2415
            break;
mercury233's avatar
mercury233 committed
2416 2417 2418 2419 2420 2421 2422 2423
          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;
2424
          default:
mercury233's avatar
mercury233 committed
2425
            ygopro.stoc_die(client, '${invalid_password_action}');
2426 2427
            return;
        }
mercury233's avatar
mercury233 committed
2428
        if (!room) {
mercury233's avatar
mercury233 committed
2429
          ygopro.stoc_die(client, "${server_full}");
mercury233's avatar
mercury233 committed
2430
        } else if (room.error) {
mercury233's avatar
mercury233 committed
2431
          ygopro.stoc_die(client, room.error);
nanahira's avatar
nanahira committed
2432
        } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
2433
          if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
mercury233's avatar
mercury233 committed
2434 2435 2436 2437 2438 2439
            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
2440 2441 2442
            ref3 = room.watcher_buffers;
            for (n = 0, len3 = ref3.length; n < len3; n++) {
              buffer = ref3[n];
mercury233's avatar
mercury233 committed
2443 2444 2445 2446 2447
              client.write(buffer);
            }
          } else {
            ygopro.stoc_die(client, "${watch_denied}");
          }
nanahira's avatar
nanahira committed
2448
        } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
nanahira's avatar
fix  
nanahira committed
2449
          ygopro.stoc_die(client, "${watch_denied_room}");
mercury233's avatar
mercury233 committed
2450
        } else {
mercury233's avatar
mercury233 committed
2451
          client.setTimeout(300000);
2452 2453
          client.rid = _.indexOf(ROOM_all, room);
          room.connect(client);
mercury233's avatar
mercury233 committed
2454
        }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2455
      };
nanahira's avatar
nanahira committed
2456 2457 2458 2459
      match_permit_callback = function(buffer, match_permit) {
        var decrypted_buffer, i, id, len2, m, ref2, secret;
        if (client.closed) {
          return;
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2460
        }
nanahira's avatar
nanahira committed
2461 2462
        if (id = users_cache[client.name]) {
          secret = id % 65535 + 1;
nanahira's avatar
nanahira committed
2463
          decrypted_buffer = Buffer.allocUnsafe(6);
nanahira's avatar
nanahira committed
2464 2465 2466
          ref2 = [0, 2, 4];
          for (m = 0, len2 = ref2.length; m < len2; m++) {
            i = ref2[m];
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2467 2468
            decrypted_buffer.writeUInt16LE(buffer.readUInt16LE(i) ^ secret, i);
          }
nanahira's avatar
nanahira committed
2469
          if (check_buffer_indentity(decrypted_buffer)) {
nanahira's avatar
fix  
nanahira committed
2470
            return buffer_handle_callback(decrypted_buffer, decrypted_buffer, match_permit);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
2471 2472
          }
        }
nanahira's avatar
nanahira committed
2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500
        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;
          if (body && body.user) {
            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;
            }
          }
          if (!check_buffer_indentity(buffer)) {
            ygopro.stoc_die(client, '${invalid_password_checksum}');
            return;
          }
nanahira's avatar
fix  
nanahira committed
2501
          return buffer_handle_callback(buffer, decrypted_buffer, match_permit);
nanahira's avatar
nanahira committed
2502 2503 2504 2505 2506 2507 2508 2509
        });
      };
      if (settings.modules.arena_mode.check_permit) {
        request({
          url: settings.modules.arena_mode.check_permit,
          json: true,
          qs: {
            username: client.name,
2510 2511
            password: info.pass,
            arena: settings.modules.arena_mode.mode
nanahira's avatar
nanahira committed
2512 2513 2514 2515 2516 2517 2518 2519
          }
        }, function(error, response, body) {
          if (client.closed) {
            return;
          }
          if (!error && body) {
            match_permit_callback(buffer, body);
          } else {
nanahira's avatar
log  
nanahira committed
2520
            log.warn("Match permit request error", error);
nanahira's avatar
nanahira committed
2521 2522 2523 2524 2525 2526
            match_permit_callback(buffer, null);
          }
        });
      } else {
        match_permit_callback(buffer, null);
      }
nanahira's avatar
nanahira committed
2527 2528
    } else if (settings.modules.challonge.enabled) {
      pre_room = ROOM_find_by_name(info.pass);
nanahira's avatar
nanahira committed
2529
      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
2530 2531 2532 2533 2534 2535 2536
        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
2537 2538 2539
        ref2 = room.watcher_buffers;
        for (m = 0, len2 = ref2.length; m < len2; m++) {
          buffer = ref2[m];
nanahira's avatar
nanahira committed
2540 2541 2542 2543
          client.write(buffer);
        }
      } else {
        ygopro.stoc_send_chat(client, '${loading_user_info}', ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
fix  
nanahira committed
2544
        client.setTimeout(300000);
nanahira's avatar
nanahira committed
2545
        challonge.participants._index({
2546
          id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
2547 2548
          callback: function(err, data) {
            var found, k, user;
nanahira's avatar
nanahira committed
2549 2550 2551
            if (client.closed) {
              return;
            }
nanahira's avatar
nanahira committed
2552 2553 2554 2555 2556 2557 2558 2559 2560 2561
            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];
nanahira's avatar
nanahira committed
2562
              if (user.participant && user.participant.name && _.endsWith(user.participant.name, client.name)) {
nanahira's avatar
nanahira committed
2563 2564 2565 2566 2567 2568 2569 2570 2571
                found = user.participant;
                break;
              }
            }
            if (!found) {
              ygopro.stoc_die(client, '${challonge_user_not_found}');
              return;
            }
            client.challonge_info = found;
nanahira's avatar
nanahira committed
2572
            challonge.matches._index({
2573
              id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
2574
              callback: function(err, data) {
nanahira's avatar
nanahira committed
2575
                var len3, len4, match, n, o, player, ref3, ref4;
nanahira's avatar
nanahira committed
2576 2577 2578
                if (client.closed) {
                  return;
                }
nanahira's avatar
nanahira committed
2579 2580 2581 2582 2583 2584 2585 2586 2587 2588
                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
2589
                  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
2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606
                    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
2607
                } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
2608
                  if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
2609 2610 2611 2612 2613
                    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
2614 2615 2616
                    ref3 = room.watcher_buffers;
                    for (n = 0, len3 = ref3.length; n < len3; n++) {
                      buffer = ref3[n];
nanahira's avatar
nanahira committed
2617 2618 2619 2620 2621
                      client.write(buffer);
                    }
                  } else {
                    ygopro.stoc_die(client, "${watch_denied}");
                  }
nanahira's avatar
nanahira committed
2622
                } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
nanahira's avatar
fix  
nanahira committed
2623
                  ygopro.stoc_die(client, "${watch_denied_room}");
nanahira's avatar
nanahira committed
2624
                } else {
nanahira's avatar
nanahira committed
2625 2626 2627
                  ref4 = room.get_playing_player();
                  for (o = 0, len4 = ref4.length; o < len4; o++) {
                    player = ref4[o];
nanahira's avatar
nanahira committed
2628
                    if (!(player && player !== client && player.challonge_info.id === client.challonge_info.id)) {
nanahira's avatar
nanahira committed
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641
                      continue;
                    }
                    ygopro.stoc_die(client, "${challonge_player_already_in}");
                    return;
                  }
                  client.rid = _.indexOf(ROOM_all, room);
                  room.connect(client);
                }
              }
            });
          }
        });
      }
mercury233's avatar
mercury233 committed
2642
    } else if (!client.name || client.name === "") {
mercury233's avatar
mercury233 committed
2643
      ygopro.stoc_die(client, "${bad_user_name}");
mercury233's avatar
mercury233 committed
2644 2645
    } else if (ROOM_connected_ip[client.ip] > 5) {
      log.warn("MULTI LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2646
      ygopro.stoc_die(client, "${too_much_connection}" + client.ip);
mercury233's avatar
mercury233 committed
2647
    } else if (_.indexOf(settings.ban.banned_user, client.name) > -1) {
mercury233's avatar
mercury233 committed
2648
      settings.ban.banned_ip.push(client.ip);
mercury233's avatar
mercury233 committed
2649
      setting_save(settings);
mercury233's avatar
mercury233 committed
2650
      log.warn("BANNED USER LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2651
      ygopro.stoc_die(client, "${banned_user_login}");
mercury233's avatar
mercury233 committed
2652 2653
    } else if (_.indexOf(settings.ban.banned_ip, client.ip) > -1) {
      log.warn("BANNED IP LOGIN", client.name, client.ip);
mercury233's avatar
mercury233 committed
2654
      ygopro.stoc_die(client, "${banned_ip_login}");
mercury233's avatar
mercury233 committed
2655
    } else if (_.any(badwords.level3, function(badword) {
mercury233's avatar
mercury233 committed
2656
      var regexp;
mercury233's avatar
fix  
mercury233 committed
2657
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
2658 2659
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
2660
      log.warn("BAD NAME LEVEL 3", client.name, client.ip);
mercury233's avatar
mercury233 committed
2661
      ygopro.stoc_die(client, "${bad_name_level3}");
mercury233's avatar
mercury233 committed
2662
    } else if (_.any(badwords.level2, function(badword) {
mercury233's avatar
mercury233 committed
2663
      var regexp;
mercury233's avatar
fix  
mercury233 committed
2664
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
2665 2666
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
2667
      log.warn("BAD NAME LEVEL 2", client.name, client.ip);
mercury233's avatar
mercury233 committed
2668
      ygopro.stoc_die(client, "${bad_name_level2}");
mercury233's avatar
mercury233 committed
2669
    } else if (_.any(badwords.level1, function(badword) {
mercury233's avatar
mercury233 committed
2670
      var regexp;
mercury233's avatar
fix  
mercury233 committed
2671
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
2672 2673
      return name.match(regexp);
    }, name = client.name)) {
mercury233's avatar
mercury233 committed
2674
      log.warn("BAD NAME LEVEL 1", client.name, client.ip);
mercury233's avatar
mercury233 committed
2675
      ygopro.stoc_die(client, "${bad_name_level1}");
mercury233's avatar
mercury233 committed
2676
    } else if (info.pass.length && !ROOM_validate(info.pass)) {
mercury233's avatar
mercury233 committed
2677
      ygopro.stoc_die(client, "${invalid_password_room}");
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2678
    } else {
mercury233's avatar
mercury233 committed
2679
      room = ROOM_find_or_create_by_name(info.pass, client.ip);
mercury233's avatar
mercury233 committed
2680
      if (!room) {
mercury233's avatar
mercury233 committed
2681
        ygopro.stoc_die(client, "${server_full}");
mercury233's avatar
mercury233 committed
2682
      } else if (room.error) {
mercury233's avatar
mercury233 committed
2683
        ygopro.stoc_die(client, room.error);
nanahira's avatar
nanahira committed
2684
      } else if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
2685
        if (settings.modules.cloud_replay.enable_halfway_watch && !room.hostinfo.no_watch) {
mercury233's avatar
mercury233 committed
2686
          client.setTimeout(300000);
2687
          client.rid = _.indexOf(ROOM_all, room);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2688
          client.is_post_watcher = true;
mercury233's avatar
mercury233 committed
2689
          ygopro.stoc_send_chat_to_room(room, client.name + " ${watch_join}");
2690
          room.watchers.push(client);
mercury233's avatar
mercury233 committed
2691
          ygopro.stoc_send_chat(client, "${watch_watching}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2692 2693 2694
          ref3 = room.watcher_buffers;
          for (n = 0, len3 = ref3.length; n < len3; n++) {
            buffer = ref3[n];
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2695 2696 2697
            client.write(buffer);
          }
        } else {
mercury233's avatar
mercury233 committed
2698
          ygopro.stoc_die(client, "${watch_denied}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2699
        }
nanahira's avatar
nanahira committed
2700
      } else if (room.hostinfo.no_watch && room.players.length >= (room.hostinfo.mode === 2 ? 4 : 2)) {
nanahira's avatar
nanahira committed
2701
        ygopro.stoc_die(client, "${watch_denied_room}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2702
      } else {
mercury233's avatar
mercury233 committed
2703
        client.setTimeout(300000);
2704 2705
        client.rid = _.indexOf(ROOM_all, room);
        room.connect(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2706
      }
神楽坂玲奈's avatar
init  
神楽坂玲奈 committed
2707 2708 2709
    }
  });

nanahira's avatar
nanahira committed
2710
  ygopro.stoc_follow('JOIN_GAME', false, function(buffer, info, client, server, datas) {
2711
    var len2, m, player, recorder, ref2, room, watcher;
2712
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
2713
    if (!(room && !client.reconnecting)) {
2714 2715
      return;
    }
2716 2717 2718
    if (!room.join_game_buffer) {
      room.join_game_buffer = buffer;
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2719
    if (settings.modules.welcome) {
mercury233's avatar
mercury233 committed
2720
      ygopro.stoc_send_chat(client, settings.modules.welcome, ygopro.constants.COLORS.GREEN);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2721
    }
2722 2723
    if (room.welcome) {
      ygopro.stoc_send_chat(client, room.welcome, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
add  
mercury233 committed
2724
    }
2725
    if (settings.modules.arena_mode.enabled && !client.is_local) {
mercury233's avatar
mercury233 committed
2726 2727 2728 2729
      request({
        url: settings.modules.arena_mode.get_score + encodeURIComponent(client.name),
        json: true
      }, function(error, response, body) {
mercury233's avatar
merge  
mercury233 committed
2730
        var rank_txt;
mercury233's avatar
merge  
mercury233 committed
2731 2732 2733 2734
        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
2735
        } else {
mercury233's avatar
mercury233 committed
2736 2737
          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
2738 2739 2740
        }
      });
    }
2741 2742 2743 2744 2745 2746 2747 2748 2749 2750
    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);
        }
      }
    }
2751 2752
    if (!room.recorder) {
      room.recorder = recorder = net.connect(room.port, function() {
mercury233's avatar
mercury233 committed
2753 2754 2755 2756 2757
        ygopro.ctos_send(recorder, 'PLAYER_INFO', {
          name: "Marshtomp"
        });
        ygopro.ctos_send(recorder, 'JOIN_GAME', {
          version: settings.version,
mercury233's avatar
mercury233 committed
2758
          pass: "Marshtomp"
mercury233's avatar
mercury233 committed
2759
        });
mercury233's avatar
mercury233 committed
2760
        ygopro.ctos_send(recorder, 'HS_TOOBSERVER');
mercury233's avatar
mercury233 committed
2761 2762
      });
      recorder.on('data', function(data) {
2763
        room = ROOM_all[client.rid];
mercury233's avatar
mercury233 committed
2764
        if (!(room && settings.modules.cloud_replay.enabled)) {
mercury233's avatar
mercury233 committed
2765 2766
          return;
        }
mercury233's avatar
mercury233 committed
2767
        room.recorder_buffers.push(data);
mercury233's avatar
mercury233 committed
2768 2769 2770
      });
      recorder.on('error', function(error) {});
    }
nanahira's avatar
nanahira committed
2771
    if (settings.modules.cloud_replay.enable_halfway_watch && !room.watcher && !room.hostinfo.no_watch) {
2772
      room.watcher = watcher = settings.modules.test_mode.watch_public_hand ? room.recorder : net.connect(room.port, function() {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2773 2774 2775 2776 2777
        ygopro.ctos_send(watcher, 'PLAYER_INFO', {
          name: "the Big Brother"
        });
        ygopro.ctos_send(watcher, 'JOIN_GAME', {
          version: settings.version,
mercury233's avatar
mercury233 committed
2778
          pass: "the Big Brother"
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2779
        });
mercury233's avatar
mercury233 committed
2780
        ygopro.ctos_send(watcher, 'HS_TOOBSERVER');
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2781
      });
mercury233's avatar
fix  
mercury233 committed
2782
      watcher.on('data', function(data) {
2783
        var len3, n, ref3, w;
2784 2785
        room = ROOM_all[client.rid];
        if (!room) {
2786 2787
          return;
        }
2788
        room.watcher_buffers.push(data);
2789 2790 2791
        ref3 = room.watchers;
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          w = ref3[n];
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
2792
          if (w) {
mercury233's avatar
test3  
mercury233 committed
2793
            w.write(data);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
2794
          }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2795 2796
        }
      });
mercury233's avatar
test3  
mercury233 committed
2797
      watcher.on('error', function(error) {});
神楽坂玲奈's avatar
神楽坂玲奈 committed
2798
    }
神楽坂玲奈's avatar
tip  
神楽坂玲奈 committed
2799
  });
神楽坂玲奈's avatar
神楽坂玲奈 committed
2800

nanahira's avatar
nanahira committed
2801
  load_dialogues = global.load_dialogues = function() {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2802
    request({
mercury233's avatar
mercury233 committed
2803
      url: settings.modules.dialogues.get,
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2804 2805 2806
      json: true
    }, function(error, response, body) {
      if (_.isString(body)) {
mercury233's avatar
test3  
mercury233 committed
2807
        log.warn("dialogues bad json", body);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
2808
      } else if (error || !body) {
mercury233's avatar
test3  
mercury233 committed
2809
        log.warn('dialogues error', error, response);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2810
      } else {
mercury233's avatar
mercury233 committed
2811 2812
        setting_change(dialogues, "dialogues", body);
        log.info("dialogues loaded", _.size(dialogues.dialogues));
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2813 2814
      }
    });
mercury233's avatar
mercury233 committed
2815 2816
  };

mercury233's avatar
mercury233 committed
2817
  if (settings.modules.dialogues.get) {
mercury233's avatar
mercury233 committed
2818
    load_dialogues();
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2819 2820
  }

nanahira's avatar
nanahira committed
2821
  ygopro.stoc_follow('GAME_MSG', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
2822
    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;
2823
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
2824
    if (!(room && !client.reconnecting)) {
2825 2826
      return;
    }
神楽坂玲奈's avatar
神楽坂玲奈 committed
2827
    msg = buffer.readInt8(0);
nanahira's avatar
nanahira committed
2828 2829 2830 2831 2832 2833 2834 2835 2836 2837
    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
2838
          CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
2839
          CLIENT_kick(client);
nanahira's avatar
nanahira committed
2840 2841 2842 2843 2844 2845 2846 2847
          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
2848 2849 2850
          if (client.last_hint_msg) {
            ygopro.stoc_send(client, 'GAME_MSG', client.last_hint_msg);
          }
nanahira's avatar
nanahira committed
2851 2852 2853 2854 2855
          ygopro.stoc_send(client, 'GAME_MSG', client.last_game_msg);
          return true;
        }
      } else {
        client.last_game_msg = buffer;
nanahira's avatar
nanahira committed
2856
        client.last_game_msg_title = ygopro.constants.MSG[msg];
nanahira's avatar
nanahira committed
2857
      }
nanahira's avatar
nanahira committed
2858 2859 2860
    } 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
2861
    }
nanahira's avatar
fix  
nanahira committed
2862
    if ((msg >= 10 && msg < 30) || msg === 132 || (msg >= 140 && msg <= 144)) {
2863 2864
      room.waiting_for_player = client;
      room.last_active_time = moment();
2865
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2866 2867 2868
    if (ygopro.constants.MSG[msg] === 'START') {
      playertype = buffer.readUInt8(1);
      client.is_first = !(playertype & 0xf);
2869
      client.lp = room.hostinfo.start_lp;
nanahira's avatar
nanahira committed
2870 2871 2872
      if (room.hostinfo.mode !== 2) {
        client.card_count = 0;
      }
nanahira's avatar
nanahira committed
2873
      room.duel_stage = ygopro.constants.DUEL_STAGE.DUELING;
nanahira's avatar
nanahira committed
2874
      if (client.pos === 0) {
2875
        room.turn = 0;
nanahira's avatar
nanahira committed
2876
        room.duel_count++;
nanahira's avatar
nanahira committed
2877 2878 2879 2880 2881 2882 2883
        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
2884
      }
nanahira's avatar
nanahira committed
2885 2886 2887 2888
      if (settings.modules.retry_handle.enabled) {
        client.retry_count = 0;
        client.last_game_msg = null;
      }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
2889
    }
nanahira's avatar
nanahira committed
2890 2891
    if (ygopro.constants.MSG[msg] === 'HINT') {
      hint_type = buffer.readUInt8(1);
nanahira's avatar
typo  
nanahira committed
2892
      if (hint_type === 3) {
nanahira's avatar
nanahira committed
2893 2894 2895
        client.last_hint_msg = buffer;
      }
    }
2896
    if (ygopro.constants.MSG[msg] === 'NEW_TURN') {
nanahira's avatar
nanahira committed
2897
      if (client.pos === 0) {
nanahira's avatar
nanahira committed
2898
        room.turn++;
nanahira's avatar
nanahira committed
2899
        if (room.death && room.death !== -2) {
nanahira's avatar
nanahira committed
2900
          if (room.turn >= room.death) {
nanahira's avatar
nanahira committed
2901 2902 2903
            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
2904
              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
2905
              if (room.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
2906
                room.finished_by_death = true;
nanahira's avatar
nanahira committed
2907 2908
                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');
2909
                room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
2910 2911
                CLIENT_kick(room.dueling_players[oppo_pos - win_pos]);
                CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]);
nanahira's avatar
nanahira committed
2912 2913 2914
              } else {
                ygopro.ctos_send(room.dueling_players[oppo_pos - win_pos].server, 'SURRENDER');
              }
nanahira's avatar
nanahira committed
2915
            } else {
nanahira's avatar
nanahira committed
2916
              room.death = -1;
nanahira's avatar
nanahira committed
2917 2918 2919 2920 2921 2922
              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);
          }
        }
2923 2924 2925 2926 2927
      }
      if (client.surrend_confirm) {
        client.surrend_confirm = false;
        ygopro.stoc_send_chat(client, "${surrender_canceled}", ygopro.constants.COLORS.BABYBLUE);
      }
mercury233's avatar
mercury233 committed
2928
    }
nanahira's avatar
nanahira committed
2929 2930 2931
    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
2932 2933 2934 2935 2936
      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
2937
            room.finished_by_death = true;
nanahira's avatar
fix  
nanahira committed
2938 2939
            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');
2940
            room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
2941 2942
            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
2943 2944 2945
          } else {
            ygopro.ctos_send(room.dueling_players[oppo_pos - win_pos].server, 'SURRENDER');
          }
nanahira's avatar
nanahira committed
2946
        } else {
nanahira's avatar
fix  
nanahira committed
2947 2948
          room.death = -1;
          ygopro.stoc_send_chat_to_room(room, "${death_remain_final}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
2949 2950 2951
        }
      }
    }
nanahira's avatar
nanahira committed
2952
    if (ygopro.constants.MSG[msg] === 'WIN' && client.pos === 0) {
mercury233's avatar
mercury233 committed
2953
      pos = buffer.readUInt8(1);
nanahira's avatar
nanahira committed
2954
      if (!(client.is_first || pos === 2 || room.duel_stage !== ygopro.constants.DUEL_STAGE.DUELING)) {
mercury233's avatar
mercury233 committed
2955 2956
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
2957 2958 2959
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
mercury233's avatar
mercury233 committed
2960 2961
      reason = buffer.readUInt8(2);
      room.winner = pos;
nanahira's avatar
nanahira committed
2962
      room.turn = 0;
nanahira's avatar
nanahira committed
2963
      room.duel_stage = ygopro.constants.DUEL_STAGE.END;
nanahira's avatar
nanahira committed
2964 2965 2966 2967
      if (settings.modules.heartbeat_detection.enabled) {
        ref2 = room.players;
        for (m = 0, len2 = ref2.length; m < len2; m++) {
          player = ref2[m];
2968
          player.heartbeat_protected = false;
nanahira's avatar
nanahira committed
2969
        }
nanahira's avatar
nanahira committed
2970 2971
        delete room.long_resolve_card;
        delete room.long_resolve_chain;
nanahira's avatar
nanahira committed
2972
      }
mercury233's avatar
fix  
mercury233 committed
2973
      if (room && !room.finished && room.dueling_players[pos]) {
2974
        room.winner_name = room.dueling_players[pos].name_vpass;
mercury233's avatar
mercury233 committed
2975
        room.scores[room.winner_name] = room.scores[room.winner_name] + 1;
nanahira's avatar
nanahira committed
2976 2977 2978 2979
        if (room.match_kill) {
          room.match_kill = false;
          room.scores[room.winner_name] = 99;
        }
mercury233's avatar
mercury233 committed
2980
      }
nanahira's avatar
fix  
nanahira committed
2981
      if (room.death) {
nanahira's avatar
nanahira committed
2982
        if (settings.modules.http.quick_death_rule === 1 || settings.modules.http.quick_death_rule === 3) {
nanahira's avatar
fix  
nanahira committed
2983 2984 2985 2986 2987
          room.death = -1;
        } else {
          room.death = 5;
        }
      }
mercury233's avatar
mercury233 committed
2988
    }
nanahira's avatar
nanahira committed
2989 2990 2991
    if (ygopro.constants.MSG[msg] === 'MATCH_KILL' && client.pos === 0) {
      room.match_kill = true;
    }
nanahira's avatar
nanahira committed
2992
    if (ygopro.constants.MSG[msg] === 'DAMAGE' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
2993 2994 2995 2996
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
2997 2998 2999
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3000
      val = buffer.readInt32LE(2);
3001
      room.dueling_players[pos].lp -= val;
nanahira's avatar
fix  
nanahira committed
3002 3003 3004
      if (room.dueling_players[pos].lp < 0) {
        room.dueling_players[pos].lp = 0;
      }
nanahira's avatar
nanahira committed
3005
      if ((0 < (ref3 = room.dueling_players[pos].lp) && ref3 <= 100)) {
mercury233's avatar
mercury233 committed
3006
        ygopro.stoc_send_chat_to_room(room, "${lp_low_opponent}", ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3007 3008
      }
    }
nanahira's avatar
nanahira committed
3009
    if (ygopro.constants.MSG[msg] === 'RECOVER' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3010 3011 3012 3013
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3014 3015 3016
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3017
      val = buffer.readInt32LE(2);
3018
      room.dueling_players[pos].lp += val;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3019
    }
nanahira's avatar
nanahira committed
3020
    if (ygopro.constants.MSG[msg] === 'LPUPDATE' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3021 3022 3023 3024
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3025 3026 3027
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3028
      val = buffer.readInt32LE(2);
3029
      room.dueling_players[pos].lp = val;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3030
    }
nanahira's avatar
nanahira committed
3031
    if (ygopro.constants.MSG[msg] === 'PAY_LPCOST' && client.pos === 0) {
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3032 3033 3034 3035
      pos = buffer.readUInt8(1);
      if (!client.is_first) {
        pos = 1 - pos;
      }
nanahira's avatar
nanahira committed
3036 3037 3038
      if (pos >= 0 && room.hostinfo.mode === 2) {
        pos = pos * 2;
      }
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3039
      val = buffer.readInt32LE(2);
3040
      room.dueling_players[pos].lp -= val;
nanahira's avatar
fix  
nanahira committed
3041 3042 3043
      if (room.dueling_players[pos].lp < 0) {
        room.dueling_players[pos].lp = 0;
      }
nanahira's avatar
nanahira committed
3044
      if ((0 < (ref4 = room.dueling_players[pos].lp) && ref4 <= 100)) {
mercury233's avatar
mercury233 committed
3045
        ygopro.stoc_send_chat_to_room(room, "${lp_low_self}", ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3046 3047
      }
    }
nanahira's avatar
nanahira committed
3048
    if (ygopro.constants.MSG[msg] === 'MOVE' && room.hostinfo.mode !== 2) {
nanahira's avatar
nanahira committed
3049 3050 3051 3052 3053
      pos = buffer.readUInt8(5);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      loc = buffer.readUInt8(6);
nanahira's avatar
nanahira committed
3054 3055
      if ((loc & 0xe) && pos === 0) {
        client.card_count--;
nanahira's avatar
nanahira committed
3056 3057 3058 3059 3060 3061
      }
      pos = buffer.readUInt8(9);
      if (!client.is_first) {
        pos = 1 - pos;
      }
      loc = buffer.readUInt8(10);
nanahira's avatar
nanahira committed
3062 3063
      if ((loc & 0xe) && pos === 0) {
        client.card_count++;
nanahira's avatar
nanahira committed
3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075
      }
    }
    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
3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094
    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) {
3095
        client.heartbeat_protected = true;
nanahira's avatar
nanahira committed
3096 3097
      }
    }
nanahira's avatar
nanahira committed
3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138
    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
3139
    if (settings.modules.dialogues.enabled) {
nanahira's avatar
nanahira committed
3140
      if (ygopro.constants.MSG[msg] === 'SUMMONING' || ygopro.constants.MSG[msg] === 'SPSUMMONING' || ygopro.constants.MSG[msg] === 'CHAINING') {
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3141
        card = buffer.readUInt32LE(1);
nanahira's avatar
fix  
nanahira committed
3142
        trigger_location = buffer.readUInt8(6);
nanahira's avatar
nanahira committed
3143
        if (dialogues.dialogues[card] && (ygopro.constants.MSG[msg] !== 'CHAINING' || (trigger_location & 0x8) && client.ready_trap)) {
nanahira's avatar
nanahira committed
3144 3145 3146
          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
3147
            ygopro.stoc_send_chat(client, line, ygopro.constants.COLORS.PINK);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3148
          }
神楽坂玲奈's avatar
神楽坂玲奈 committed
3149
        }
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
3150
      }
nanahira's avatar
nanahira committed
3151 3152 3153 3154 3155 3156 3157 3158
      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
3159
    }
nanahira's avatar
nanahira committed
3160
    return false;
神楽坂玲奈's avatar
 
神楽坂玲奈 committed
3161 3162
  });

nanahira's avatar
nanahira committed
3163
  ygopro.ctos_follow('HS_TOOBSERVER', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3164
    var len2, m, player, ref2, room;
3165 3166 3167 3168
    room = ROOM_all[client.rid];
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
3169
    if (room.hostinfo.no_watch) {
nanahira's avatar
nanahira committed
3170 3171 3172
      ygopro.stoc_send_chat(client, "${watch_denied_room}", ygopro.constants.COLORS.RED);
      return true;
    }
nanahira's avatar
nanahira committed
3173
    if ((!room.arena && !settings.modules.challonge.enabled) || client.is_local) {
3174 3175
      return false;
    }
nanahira's avatar
nanahira committed
3176
    ref2 = room.players;
nanahira's avatar
nanahira committed
3177 3178
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
3179 3180 3181 3182 3183 3184 3185
      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
3186

nanahira's avatar
nanahira committed
3187
  ygopro.ctos_follow('HS_KICK', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3188
    var len2, m, player, ref2, room;
3189 3190
    room = ROOM_all[client.rid];
    if (!room) {
3191 3192
      return;
    }
nanahira's avatar
nanahira committed
3193
    ref2 = room.players;
nanahira's avatar
nanahira committed
3194 3195
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
mercury233's avatar
mercury233 committed
3196
      if (player && player.pos === info.pos && player !== client) {
nanahira's avatar
nanahira committed
3197
        if (room.arena === "athletic" || settings.modules.challonge.enabled) {
3198
          ygopro.stoc_send_chat_to_room(room, client.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3199
          CLIENT_kick(client);
3200 3201
          return true;
        }
mercury233's avatar
mercury233 committed
3202
        client.kick_count = client.kick_count ? client.kick_count + 1 : 1;
mercury233's avatar
fix  
mercury233 committed
3203
        if (client.kick_count >= 5 && room.random_type) {
mercury233's avatar
mercury233 committed
3204
          ygopro.stoc_send_chat_to_room(room, client.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3205
          ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
nanahira's avatar
nanahira committed
3206
          CLIENT_kick(client);
mercury233's avatar
mercury233 committed
3207 3208
          return true;
        }
mercury233's avatar
mercury233 committed
3209
        ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_player}", ygopro.constants.COLORS.RED);
3210 3211 3212 3213 3214
      }
    }
    return false;
  });

nanahira's avatar
nanahira committed
3215
  ygopro.stoc_follow('TYPE_CHANGE', true, function(buffer, info, client, server, datas) {
神楽坂玲奈's avatar
神楽坂玲奈 committed
3216 3217 3218 3219
    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
3220
    client.pos = selftype;
nanahira's avatar
nanahira committed
3221
    return false;
神楽坂玲奈's avatar
神楽坂玲奈 committed
3222 3223
  });

3224 3225 3226
  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
3227
    if (!(room && settings.modules.hide_name && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN)) {
3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239
      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
3240
  ygopro.stoc_follow('HS_PLAYER_CHANGE', false, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3241
    var is_ready, len2, len3, m, n, p1, p2, player, pos, ref2, ref3, room;
3242 3243
    room = ROOM_all[client.rid];
    if (!(room && room.max_player && client.is_host)) {
3244 3245 3246 3247
      return;
    }
    pos = info.status >> 4;
    is_ready = (info.status & 0xf) === 9;
3248
    if (pos < room.max_player) {
3249 3250
      if (room.arena) {
        room.ready_player_count = 0;
nanahira's avatar
nanahira committed
3251
        ref2 = room.players;
nanahira's avatar
nanahira committed
3252 3253
        for (m = 0, len2 = ref2.length; m < len2; m++) {
          player = ref2[m];
3254 3255 3256
          if (player.pos === pos) {
            player.is_ready = is_ready;
          }
3257
        }
3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279
        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
3280
          room.waiting_for_player_time = settings.modules.arena_mode.ready_time;
3281 3282 3283 3284 3285 3286
          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
3287
          room.waiting_for_player_time = settings.modules.arena_mode.ready_time;
3288 3289 3290
        }
      } else {
        room.ready_player_count_without_host = 0;
nanahira's avatar
nanahira committed
3291
        ref3 = room.players;
nanahira's avatar
nanahira committed
3292 3293
        for (n = 0, len3 = ref3.length; n < len3; n++) {
          player = ref3[n];
3294 3295 3296 3297 3298 3299 3300 3301 3302
          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
3303
            wait_room_start(ROOM_all[client.rid], settings.modules.random_duel.ready_time);
3304
          }), 1000);
3305 3306 3307 3308 3309
        }
      }
    }
  });

nanahira's avatar
nanahira committed
3310
  ygopro.ctos_follow('REQUEST_FIELD', true, function(buffer, info, client, server, datas) {
3311 3312 3313
    return true;
  });

nanahira's avatar
nanahira committed
3314
  ygopro.stoc_follow('FIELD_FINISH', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3315 3316
    var room;
    room = ROOM_all[client.rid];
3317
    if (!(room && settings.modules.reconnect.enabled)) {
nanahira's avatar
nanahira committed
3318 3319
      return true;
    }
3320
    client.reconnecting = false;
3321 3322 3323
    if (client.time_confirm_required) {
      client.waiting_for_last = true;
    } else if (client.last_game_msg && client.last_game_msg_title !== 'WAITING') {
3324 3325 3326 3327
      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
3328 3329 3330 3331
    }
    return true;
  });

3332
  ygopro.stoc_follow('DUEL_END', false, function(buffer, info, client, server, datas) {
nanahira's avatar
js  
nanahira committed
3333
    var len2, len3, m, n, player, ref2, ref3, results, room;
nanahira's avatar
move  
nanahira committed
3334 3335 3336 3337
    room = ROOM_all[client.rid];
    if (!(room && settings.modules.replay_delay && room.hostinfo.mode === 1)) {
      return;
    }
3338
    SOCKET_flush_data(client, datas);
nanahira's avatar
move  
nanahira committed
3339
    CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
3340
    if (!room.replays_sent_to_watchers) {
nanahira's avatar
move  
nanahira committed
3341
      room.replays_sent_to_watchers = true;
nanahira's avatar
js  
nanahira committed
3342
      ref2 = room.players;
nanahira's avatar
move  
nanahira committed
3343 3344
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        player = ref2[m];
nanahira's avatar
js  
nanahira committed
3345 3346 3347 3348 3349 3350 3351 3352
        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
3353 3354 3355 3356 3357 3358 3359 3360
        if (player) {
          results.push(CLIENT_send_replays(player, room));
        }
      }
      return results;
    }
  });

3361
  wait_room_start = function(room, time) {
nanahira's avatar
nanahira committed
3362
    var len2, m, player, ref2;
nanahira's avatar
nanahira committed
3363
    if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.ready_player_count_without_host >= room.max_player - 1) {
3364 3365 3366
      time -= 1;
      if (time) {
        if (!(time % 5)) {
mercury233's avatar
mercury233 committed
3367
          ygopro.stoc_send_chat_to_room(room, "" + (time <= 9 ? ' ' : '') + time + "${kick_count_down}", time <= 9 ? ygopro.constants.COLORS.RED : ygopro.constants.COLORS.LIGHTBLUE);
3368 3369 3370 3371 3372
        }
        setTimeout((function() {
          wait_room_start(room, time);
        }), 1000);
      } else {
nanahira's avatar
nanahira committed
3373
        ref2 = room.players;
nanahira's avatar
nanahira committed
3374 3375
        for (m = 0, len2 = ref2.length; m < len2; m++) {
          player = ref2[m];
mercury233's avatar
fix  
mercury233 committed
3376
          if (player && player.is_host) {
mercury233's avatar
mercury233 committed
3377
            ROOM_ban_player(player.name, player.ip, "${random_ban_reason_zombie}");
mercury233's avatar
mercury233 committed
3378
            ygopro.stoc_send_chat_to_room(room, player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
3379
            CLIENT_kick(player);
3380 3381 3382 3383 3384 3385
          }
        }
      }
    }
  };

3386
  wait_room_start_arena = function(room) {
nanahira's avatar
fix  
nanahira committed
3387
    var display_name, len2, m, player, ref2;
nanahira's avatar
nanahira committed
3388
    if (room && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.waiting_for_player) {
3389 3390 3391
      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
3392 3393 3394 3395 3396 3397 3398 3399 3400
          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);
          }
3401 3402 3403
        }
      } 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
3404
        CLIENT_kick(room.waiting_for_player);
3405 3406 3407 3408 3409 3410 3411 3412
        if (room.waiting_for_player_interval) {
          clearInterval(room.waiting_for_player_interval);
          room.waiting_for_player_interval = null;
        }
      }
    }
  };

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3413
  ygopro.stoc_send_random_tip = function(client) {
mercury233's avatar
mercury233 committed
3414 3415
    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
3416
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3417 3418
  };

3419
  ygopro.stoc_send_random_tip_to_room = function(room) {
mercury233's avatar
mercury233 committed
3420 3421
    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)]);
3422 3423 3424
    }
  };

nanahira's avatar
nanahira committed
3425
  load_tips = global.load_tips = function() {
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3426
    request({
mercury233's avatar
mercury233 committed
3427
      url: settings.modules.tips.get,
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3428 3429
      json: true
    }, function(error, response, body) {
mercury233's avatar
mercury233 committed
3430 3431 3432 3433 3434
      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
3435 3436
        setting_change(tips, "tips", body);
        log.info("tips loaded", tips.tips.length);
mercury233's avatar
mercury233 committed
3437
      }
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3438
    });
mercury233's avatar
mercury233 committed
3439 3440
  };

mercury233's avatar
mercury233 committed
3441
  if (settings.modules.tips.get) {
mercury233's avatar
mercury233 committed
3442 3443
    load_tips();
    setInterval(function() {
nanahira's avatar
nanahira committed
3444 3445 3446
      var len2, m, room;
      for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
        room = ROOM_all[m];
3447
        if (room && room.established) {
nanahira's avatar
nanahira committed
3448
          if (room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING || room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) {
3449 3450
            ygopro.stoc_send_random_tip_to_room(room);
          }
mercury233's avatar
mercury233 committed
3451 3452 3453
        }
      }
    }, 30000);
神楽坂玲奈's avatar
fix  
神楽坂玲奈 committed
3454
  }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3455

nanahira's avatar
nanahira committed
3456
  ygopro.stoc_follow('DUEL_START', false, function(buffer, info, client, server, datas) {
3457
    var deck_arena, deck_name, deck_text, len2, len3, m, n, player, ref2, ref3, room;
3458
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
3459
    if (!(room && !client.reconnecting)) {
3460 3461
      return;
    }
nanahira's avatar
nanahira committed
3462 3463
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) {
      room.duel_stage = ygopro.constants.DUEL_STAGE.FINGER;
mercury233's avatar
mercury233 committed
3464
      room.start_time = moment().format();
nanahira's avatar
nanahira committed
3465
      room.turn = 0;
mercury233's avatar
mercury233 committed
3466
      if (!room.windbot && settings.modules.http.websocket_roomlist) {
mercury233's avatar
mercury233 committed
3467
        roomlist.start(room);
神楽坂玲奈's avatar
神楽坂玲奈 committed
3468
      }
3469
      room.dueling_players = [];
nanahira's avatar
nanahira committed
3470
      ref2 = room.players;
nanahira's avatar
nanahira committed
3471 3472
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        player = ref2[m];
mercury233's avatar
mercury233 committed
3473 3474
        if (!(player.pos !== 7)) {
          continue;
神楽坂玲奈's avatar
12.2  
神楽坂玲奈 committed
3475
        }
3476
        room.dueling_players[player.pos] = player;
3477
        room.scores[player.name_vpass] = 0;
3478
        room.player_datas.push({
3479
          key: CLIENT_get_authorize_key(player),
mercury233's avatar
mercury233 committed
3480 3481
          name: player.name
        });
mercury233's avatar
mercury233 committed
3482 3483 3484
        if (room.random_type === 'T') {
          ROOM_players_oppentlist[player.ip] = null;
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3485
      }
3486 3487 3488
      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
3489
    }
3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501
    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
3502
    if (settings.modules.tips.enabled) {
mercury233's avatar
test3  
mercury233 committed
3503
      ygopro.stoc_send_random_tip(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3504
    }
nanahira's avatar
nanahira committed
3505 3506
    deck_text = null;
    if (client.main && client.main.length) {
mercury233's avatar
mercury233 committed
3507
      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
3508 3509 3510
      room.decks[client.name] = deck_text;
    }
    if (settings.modules.deck_log.enabled && deck_text && !client.deck_saved && !room.windbot) {
mercury233's avatar
mercury233 committed
3511 3512 3513 3514 3515 3516 3517 3518
      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
3519
        deck_arena = deck_arena + 'athletic';
mercury233's avatar
mercury233 committed
3520 3521 3522
      } else {
        deck_arena = deck_arena + 'custom';
      }
mercury233's avatar
mercury233 committed
3523
      if (settings.modules.deck_log.local) {
nanahira's avatar
nanahira committed
3524
        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
3525
        fs.writeFile(settings.modules.deck_log.local + deck_name + '.ydk', deck_text, 'utf-8', function(err) {
mercury233's avatar
mercury233 committed
3526 3527 3528 3529 3530
          if (err) {
            return log.warn('DECK SAVE ERROR', err);
          }
        });
      }
mercury233's avatar
mercury233 committed
3531
      if (settings.modules.deck_log.post) {
mercury233's avatar
mercury233 committed
3532
        request.post({
mercury233's avatar
mercury233 committed
3533
          url: settings.modules.deck_log.post,
mercury233's avatar
mercury233 committed
3534
          form: {
mercury233's avatar
mercury233 committed
3535
            accesskey: settings.modules.deck_log.accesskey,
mercury233's avatar
mercury233 committed
3536 3537
            deck: deck_text,
            playername: client.name,
mercury233's avatar
mercury233 committed
3538
            arena: deck_arena
mercury233's avatar
mercury233 committed
3539 3540 3541
          }
        }, function(error, response, body) {
          if (error) {
mercury233's avatar
merge  
mercury233 committed
3542
            log.warn('DECK POST ERROR', error);
mercury233's avatar
mercury233 committed
3543 3544
          } else {
            if (response.statusCode !== 200) {
mercury233's avatar
merge  
mercury233 committed
3545
              log.warn('DECK POST FAIL', response.statusCode, client.name, body);
mercury233's avatar
mercury233 committed
3546 3547 3548 3549
            }
          }
        });
      }
mercury233's avatar
mercury233 committed
3550 3551
      client.deck_saved = true;
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3552 3553
  });

nanahira's avatar
nanahira committed
3554
  ygopro.ctos_follow('SURRENDER', true, function(buffer, info, client, server, datas) {
3555 3556 3557 3558 3559
    var room;
    room = ROOM_all[client.rid];
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
3560
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || room.hostinfo.mode === 2) {
3561 3562
      return true;
    }
3563
    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)) {
3564 3565 3566 3567 3568 3569
      ygopro.stoc_send_chat(client, "${surrender_denied}", ygopro.constants.COLORS.BABYBLUE);
      return true;
    }
    return false;
  });

nanahira's avatar
nanahira committed
3570
  report_to_big_brother = global.report_to_big_brother = function(roomname, sender, ip, level, content, match) {
mercury233's avatar
mercury233 committed
3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595
    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
3596
  ygopro.ctos_follow('CHAT', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
3597
    var cancel, ccolor, cip, cmd, cmsg, cname, color, cvalue, msg, name, oldmsg, ref2, room, struct, windbot;
3598 3599
    room = ROOM_all[client.rid];
    if (!room) {
mercury233's avatar
mercury233 committed
3600 3601
      return;
    }
mercury233's avatar
mercury233 committed
3602 3603
    msg = _.trim(info.msg);
    cancel = _.startsWith(msg, "/");
mercury233's avatar
fix  
mercury233 committed
3604
    if (!(cancel || !(room.random_type || room.arena))) {
3605
      room.last_active_time = moment();
3606
    }
mercury233's avatar
mercury233 committed
3607 3608
    cmd = msg.split(' ');
    switch (cmd[0]) {
mercury233's avatar
mercury233 committed
3609 3610
      case '/投降':
      case '/surrender':
nanahira's avatar
nanahira committed
3611
        if (room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN || room.hostinfo.mode === 2) {
mercury233's avatar
mercury233 committed
3612 3613
          return cancel;
        }
3614
        if (room.random_type && room.turn < 3) {
mercury233's avatar
mercury233 committed
3615 3616 3617 3618 3619 3620 3621 3622 3623 3624
          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
3625
      case '/help':
mercury233's avatar
mercury233 committed
3626 3627
        ygopro.stoc_send_chat(client, "${chat_order_main}");
        ygopro.stoc_send_chat(client, "${chat_order_help}");
mercury233's avatar
mercury233 committed
3628
        if (!settings.modules.mycard.enabled) {
mercury233's avatar
mercury233 committed
3629
          ygopro.stoc_send_chat(client, "${chat_order_roomname}");
mercury233's avatar
merge  
mercury233 committed
3630
        }
mercury233's avatar
mercury233 committed
3631
        if (settings.modules.windbot.enabled) {
mercury233's avatar
mercury233 committed
3632
          ygopro.stoc_send_chat(client, "${chat_order_windbot}");
mercury233's avatar
mercury233 committed
3633
        }
mercury233's avatar
mercury233 committed
3634
        if (settings.modules.tips.enabled) {
mercury233's avatar
mercury233 committed
3635
          ygopro.stoc_send_chat(client, "${chat_order_tip}");
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3636
        }
nanahira's avatar
nanahira committed
3637 3638 3639 3640 3641 3642
        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
3643
        break;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3644
      case '/tip':
mercury233's avatar
mercury233 committed
3645
        if (settings.modules.tips.enabled) {
mercury233's avatar
test3  
mercury233 committed
3646
          ygopro.stoc_send_random_tip(client);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3647
        }
mercury233's avatar
mercury233 committed
3648
        break;
mercury233's avatar
mercury233 committed
3649
      case '/ai':
3650
        if (settings.modules.windbot.enabled && client.is_host && !settings.modules.challonge.enabled && !room.arena && room.random_type !== 'M') {
mercury233's avatar
mercury233 committed
3651
          if (name = cmd[1]) {
mercury233's avatar
mercury233 committed
3652
            windbot = _.sample(_.filter(windbots, function(w) {
mercury233's avatar
mercury233 committed
3653 3654 3655
              return w.name === name || w.deck === name;
            }));
            if (!windbot) {
mercury233's avatar
mercury233 committed
3656
              ygopro.stoc_send_chat(client, "${windbot_deck_not_found}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3657 3658 3659
              return;
            }
          } else {
mercury233's avatar
mercury233 committed
3660
            windbot = _.sample(windbots);
mercury233's avatar
mercury233 committed
3661
          }
mercury233's avatar
mercury233 committed
3662 3663 3664
          if (room.random_type) {
            ygopro.stoc_send_chat(client, "${windbot_disable_random_room} " + room.name, ygopro.constants.COLORS.BABYBLUE);
          }
mercury233's avatar
mercury233 committed
3665 3666 3667
          room.add_windbot(windbot);
        }
        break;
mercury233's avatar
mercury233 committed
3668
      case '/roomname':
3669
        if (room) {
mercury233's avatar
mercury233 committed
3670
          ygopro.stoc_send_chat(client, "${room_name} " + room.name, ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
3671
        }
nanahira's avatar
nanahira committed
3672 3673 3674
        break;
      case '/color':
        if (settings.modules.chat_color.enabled) {
nanahira's avatar
nanahira committed
3675
          cip = CLIENT_get_authorize_key(client);
nanahira's avatar
nanahira committed
3676 3677 3678
          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
3679 3680 3681
              ref2 = ygopro.constants.COLORS;
              for (cname in ref2) {
                cvalue = ref2[cname];
nanahira's avatar
nanahira committed
3682 3683 3684 3685 3686
                if (cvalue > 10) {
                  ygopro.stoc_send_chat(client, cname, cvalue);
                }
              }
            } else if (cmsg.toLowerCase() === "default") {
nanahira's avatar
fix  
nanahira committed
3687 3688
              chat_color.save_list[cip] = false;
              setting_save(chat_color);
nanahira's avatar
nanahira committed
3689 3690 3691
              ygopro.stoc_send_chat(client, "${set_chat_color_default}", ygopro.constants.COLORS.BABYBLUE);
            } else {
              ccolor = cmsg.toUpperCase();
nanahira's avatar
fix  
nanahira committed
3692 3693 3694
              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
3695 3696 3697 3698 3699 3700
                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
3701
            if (color = chat_color.save_list[cip]) {
nanahira's avatar
nanahira committed
3702 3703 3704 3705 3706 3707
              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
3708
    }
mercury233's avatar
mercury233 committed
3709 3710 3711 3712 3713 3714 3715 3716
    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
3717
    if (!(room && (room.random_type || room.arena))) {
mercury233's avatar
mercury233 committed
3718 3719
      return cancel;
    }
nanahira's avatar
nanahira committed
3720
    if (client.abuse_count >= 5 || CLIENT_is_banned_by_mc(client)) {
mercury233's avatar
mercury233 committed
3721
      log.warn("BANNED CHAT", client.name, client.ip, msg);
nanahira's avatar
fix  
nanahira committed
3722
      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
3723 3724
      return true;
    }
mercury233's avatar
mercury233 committed
3725
    oldmsg = msg;
mercury233's avatar
mercury233 committed
3726
    if (_.any(badwords.level3, function(badword) {
mercury233's avatar
mercury233 committed
3727
      var regexp;
mercury233's avatar
fix  
mercury233 committed
3728
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
3729 3730
      return msg.match(regexp);
    }, msg)) {
mercury233's avatar
mercury233 committed
3731 3732
      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
3733
      cancel = true;
mercury233's avatar
mercury233 committed
3734
      if (client.abuse_count > 0) {
mercury233's avatar
mercury233 committed
3735 3736 3737
        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
3738
        CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
3739
        CLIENT_kick(client);
mercury233's avatar
mercury233 committed
3740 3741 3742
        return true;
      } else {
        client.abuse_count = client.abuse_count + 4;
mercury233's avatar
mercury233 committed
3743
        ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3744
      }
nanahira's avatar
nanahira committed
3745
    } else if (client.rag && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
mercury233's avatar
mercury233 committed
3746 3747 3748 3749 3750 3751 3752 3753
      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
3754
      ygopro.stoc_send_chat(client, "${chat_warn_level0}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3755
      cancel = true;
mercury233's avatar
mercury233 committed
3756
    } else if (_.any(badwords.level2, function(badword) {
mercury233's avatar
mercury233 committed
3757
      var regexp;
mercury233's avatar
fix  
mercury233 committed
3758
      regexp = new RegExp(badword, 'i');
mercury233's avatar
mercury233 committed
3759 3760
      return msg.match(regexp);
    }, msg)) {
mercury233's avatar
mercury233 committed
3761 3762
      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
3763
      client.abuse_count = client.abuse_count + 3;
mercury233's avatar
mercury233 committed
3764
      ygopro.stoc_send_chat(client, "${chat_warn_level2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3765 3766
      cancel = true;
    } else {
mercury233's avatar
mercury233 committed
3767
      _.each(badwords.level1, function(badword) {
mercury233's avatar
mercury233 committed
3768
        var regexp;
mercury233's avatar
fix  
mercury233 committed
3769
        regexp = new RegExp(badword, "ig");
mercury233's avatar
mercury233 committed
3770 3771 3772
        msg = msg.replace(regexp, "**");
      }, msg);
      if (oldmsg !== msg) {
mercury233's avatar
mercury233 committed
3773 3774
        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
3775
        client.abuse_count = client.abuse_count + 1;
mercury233's avatar
mercury233 committed
3776
        ygopro.stoc_send_chat(client, "${chat_warn_level1}");
mercury233's avatar
mercury233 committed
3777 3778 3779 3780
        struct = ygopro.structs["chat"];
        struct._setBuff(buffer);
        struct.set("msg", msg);
        buffer = struct.buffer;
mercury233's avatar
mercury233 committed
3781
      } else if (_.any(badwords.level0, function(badword) {
mercury233's avatar
mercury233 committed
3782 3783 3784 3785
        var regexp;
        regexp = new RegExp(badword, 'i');
        return msg.match(regexp);
      }, msg)) {
mercury233's avatar
mercury233 committed
3786 3787
        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
3788 3789
      }
    }
mercury233's avatar
mercury233 committed
3790 3791 3792
    if (client.abuse_count >= 2) {
      ROOM_unwelcome(room, client, "${random_ban_reason_abuse}");
    }
mercury233's avatar
mercury233 committed
3793
    if (client.abuse_count >= 5) {
mercury233's avatar
mercury233 committed
3794 3795
      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
3796
    }
3797
    return cancel;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3798 3799
  });

nanahira's avatar
nanahira committed
3800
  ygopro.ctos_follow('UPDATE_DECK', true, function(buffer, info, client, server, datas) {
3801
    var buff_main, buff_side, card, code, current_deck, deck, deck_array, deck_main, deck_side, deck_text, deckbuf, decks, found_deck, i, len2, len3, len4, line, m, n, o, oppo_pos, ref2, room, struct, win_pos;
nanahira's avatar
nanahira committed
3802
    if (settings.modules.reconnect.enabled && client.pre_reconnecting) {
nanahira's avatar
nanahira committed
3803 3804 3805 3806
      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
3807
        CLIENT_reconnect(client);
nanahira's avatar
nanahira committed
3808 3809
      } else if (CLIENT_is_able_to_kick_reconnect(client, buffer)) {
        CLIENT_kick_reconnect(client, buffer);
nanahira's avatar
nanahira committed
3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821
      } 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
3822 3823 3824 3825
    room = ROOM_all[client.rid];
    if (!room) {
      return false;
    }
nanahira's avatar
nanahira committed
3826 3827 3828 3829
    if (info.mainc > 256 || info.sidec > 256) {
      CLIENT_kick(client);
      return true;
    }
mercury233's avatar
mercury233 committed
3830
    buff_main = (function() {
nanahira's avatar
nanahira committed
3831
      var m, ref2, results;
3832
      results = [];
nanahira's avatar
nanahira committed
3833
      for (i = m = 0, ref2 = info.mainc; 0 <= ref2 ? m < ref2 : m > ref2; i = 0 <= ref2 ? ++m : --m) {
3834
        results.push(info.deckbuf[i]);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3835
      }
3836
      return results;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3837
    })();
mercury233's avatar
mercury233 committed
3838
    buff_side = (function() {
nanahira's avatar
nanahira committed
3839
      var m, ref2, ref3, results;
3840
      results = [];
nanahira's avatar
nanahira committed
3841
      for (i = m = ref2 = info.mainc, ref3 = info.mainc + info.sidec; ref2 <= ref3 ? m < ref3 : m > ref3; i = ref2 <= ref3 ? ++m : --m) {
3842
        results.push(info.deckbuf[i]);
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3843
      }
3844
      return results;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3845
    })();
mercury233's avatar
mercury233 committed
3846 3847
    client.main = buff_main;
    client.side = buff_side;
nanahira's avatar
nanahira committed
3848
    if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
3849 3850 3851 3852 3853 3854 3855
      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
3856
      client.start_deckbuf = Buffer.from(buffer);
nanahira's avatar
nanahira committed
3857
    }
nanahira's avatar
nanahira committed
3858
    oppo_pos = room.hostinfo.mode === 2 ? 2 : 1;
nanahira's avatar
nanahira committed
3859
    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]) {
3860
      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
3861
      room.finished_by_death = true;
nanahira's avatar
nanahira committed
3862
      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
3863 3864 3865
      if (room.hostinfo.mode === 1) {
        CLIENT_send_replays(room.dueling_players[oppo_pos - win_pos], room);
      }
nanahira's avatar
nanahira committed
3866 3867 3868 3869
      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');
      }
3870
      room.scores[room.dueling_players[oppo_pos - win_pos].name_vpass] = -1;
nanahira's avatar
nanahira committed
3871
      CLIENT_kick(room.dueling_players[oppo_pos - win_pos]);
nanahira's avatar
nanahira committed
3872
      if (room.hostinfo.mode === 2) {
nanahira's avatar
nanahira committed
3873
        CLIENT_kick(room.dueling_players[oppo_pos - win_pos + 1]);
nanahira's avatar
nanahira committed
3874
      }
nanahira's avatar
nanahira committed
3875 3876
      return true;
    }
nanahira's avatar
nanahira committed
3877
    if (settings.modules.side_restrict.enabled && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890
      ref2 = settings.modules.side_restrict.restrict_cards;
      for (m = 0, len2 = ref2.length; m < len2; m++) {
        code = ref2[m];
        if (_.indexOf(buff_side, code) > -1) {
          ygopro.stoc_send_chat_to_room(room, "${invalid_side_rule}", ygopro.constants.COLORS.RED);
          ygopro.stoc_send(client, 'ERROR_MSG', {
            msg: 3,
            code: 0
          });
          return true;
        }
      }
    }
3891
    if (room.random_type || room.arena) {
nanahira's avatar
nanahira committed
3892
      if (client.pos === 0) {
mercury233's avatar
mercury233 committed
3893 3894 3895
        room.waiting_for_player = room.waiting_for_player2;
      }
      room.last_active_time = moment();
nanahira's avatar
nanahira committed
3896
    } 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
3897 3898 3899 3900 3901 3902 3903 3904
      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);
3905 3906
      for (n = 0, len3 = decks.length; n < len3; n++) {
        deck = decks[n];
mercury233's avatar
mercury233 committed
3907 3908 3909
        if (_.endsWith(deck, client.name + ".ydk")) {
          found_deck = deck;
        }
mercury233's avatar
fix  
mercury233 committed
3910 3911 3912
        if (_.endsWith(deck, client.name + ".ydk.ydk")) {
          found_deck = deck;
        }
mercury233's avatar
mercury233 committed
3913 3914
      }
      if (found_deck) {
mercury233's avatar
mercury233 committed
3915
        deck_text = fs.readFileSync(settings.modules.tournament_mode.deck_path + found_deck, {
mercury233's avatar
mercury233 committed
3916 3917 3918 3919 3920 3921
          encoding: "ASCII"
        });
        deck_array = deck_text.split("\n");
        deck_main = [];
        deck_side = [];
        current_deck = deck_main;
3922 3923
        for (o = 0, len4 = deck_array.length; o < len4; o++) {
          line = deck_array[o];
mercury233's avatar
mercury233 committed
3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937
          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
3938
          ygopro.stoc_send_chat(client, "${deck_correct_part1} " + found_deck + " ${deck_correct_part2}", ygopro.constants.COLORS.BABYBLUE);
mercury233's avatar
mercury233 committed
3939
        } else {
mercury233's avatar
mercury233 committed
3940
          ygopro.stoc_send_chat(client, "${deck_incorrect_part1} " + found_deck + " ${deck_incorrect_part2}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3941 3942
        }
      } else {
mercury233's avatar
mercury233 committed
3943
        ygopro.stoc_send_chat(client, client.name + "${deck_not_found}", ygopro.constants.COLORS.RED);
mercury233's avatar
mercury233 committed
3944
      }
mercury233's avatar
mercury233 committed
3945
    }
mercury233's avatar
mercury233 committed
3946
    return false;
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
3947 3948
  });

nanahira's avatar
nanahira committed
3949
  ygopro.ctos_follow('RESPONSE', false, function(buffer, info, client, server, datas) {
3950 3951
    var room;
    room = ROOM_all[client.rid];
3952
    if (!(room && (room.random_type || room.arena))) {
3953 3954
      return;
    }
3955
    room.last_active_time = moment();
3956 3957
  });

nanahira's avatar
nanahira committed
3958
  ygopro.stoc_follow('TIME_LIMIT', true, function(buffer, info, client, server, datas) {
3959
    var check, cur_players, room;
nanahira's avatar
nanahira committed
3960
    room = ROOM_all[client.rid];
nanahira's avatar
js  
nanahira committed
3961 3962 3963
    if (!room) {
      return;
    }
nanahira's avatar
nanahira committed
3964 3965 3966 3967 3968 3969 3970
    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
3971
    }
nanahira's avatar
nanahira committed
3972
    if (!(settings.modules.heartbeat_detection.enabled && room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING && !room.windbot)) {
nanahira's avatar
nanahira committed
3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003
      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) {
4004
      CLIENT_heartbeat_register(client, false);
nanahira's avatar
nanahira committed
4005
    }
nanahira's avatar
js  
nanahira committed
4006
    return false;
nanahira's avatar
nanahira committed
4007 4008
  });

nanahira's avatar
nanahira committed
4009
  ygopro.ctos_follow('TIME_CONFIRM', false, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4010 4011
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4012
    if (!room) {
nanahira's avatar
nanahira committed
4013 4014
      return;
    }
nanahira's avatar
nanahira committed
4015
    if (settings.modules.reconnect.enabled) {
4016 4017 4018 4019 4020 4021 4022 4023 4024
      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
4025 4026
      client.time_confirm_required = false;
    }
4027 4028 4029 4030
    if (settings.modules.heartbeat_detection.enabled) {
      client.heartbeat_protected = false;
      client.heartbeat_responsed = true;
      CLIENT_heartbeat_unregister(client);
nanahira's avatar
typo  
nanahira committed
4031
    }
nanahira's avatar
nanahira committed
4032 4033
  });

nanahira's avatar
nanahira committed
4034
  ygopro.ctos_follow('HAND_RESULT', false, function(buffer, info, client, server, datas) {
4035 4036
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4037 4038 4039 4040 4041
    if (!room) {
      return;
    }
    client.selected_preduel = true;
    if (!(room.random_type || room.arena)) {
4042 4043
      return;
    }
nanahira's avatar
nanahira committed
4044
    if (client.pos === 0) {
4045
      room.waiting_for_player = room.waiting_for_player2;
4046
    }
mercury233's avatar
mercury233 committed
4047
    room.last_active_time = moment().subtract(settings.modules.random_duel.hang_timeout - 19, 's');
4048 4049
  });

nanahira's avatar
nanahira committed
4050
  ygopro.ctos_follow('TP_RESULT', false, function(buffer, info, client, server, datas) {
4051 4052
    var room;
    room = ROOM_all[client.rid];
nanahira's avatar
nanahira committed
4053 4054 4055 4056 4057
    if (!room) {
      return;
    }
    client.selected_preduel = true;
    if (!(room.random_type || room.arena)) {
4058 4059
      return;
    }
4060
    room.last_active_time = moment();
4061 4062
  });

nanahira's avatar
nanahira committed
4063
  ygopro.stoc_follow('CHAT', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4064
    var len2, m, pid, player, ref2, room, tcolor, tplayer;
nanahira's avatar
nanahira committed
4065 4066
    room = ROOM_all[client.rid];
    pid = info.player;
nanahira's avatar
nanahira committed
4067
    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
4068 4069
      return;
    }
nanahira's avatar
nanahira committed
4070
    if (room.duel_stage === ygopro.constants.DUEL_STAGE.DUELING && !room.dueling_players[0].is_first) {
nanahira's avatar
fix  
nanahira committed
4071
      if (room.hostinfo.mode === 2) {
nanahira's avatar
fix  
nanahira committed
4072 4073 4074 4075 4076 4077
        pid = {
          0: 2,
          1: 3,
          2: 0,
          3: 1
        }[pid];
nanahira's avatar
fix  
nanahira committed
4078 4079 4080 4081
      } else {
        pid = 1 - pid;
      }
    }
nanahira's avatar
nanahira committed
4082
    ref2 = room.players;
nanahira's avatar
nanahira committed
4083 4084
    for (m = 0, len2 = ref2.length; m < len2; m++) {
      player = ref2[m];
nanahira's avatar
nanahira committed
4085 4086 4087 4088 4089 4090 4091
      if (player && player.pos === pid) {
        tplayer = player;
      }
    }
    if (!tplayer) {
      return;
    }
nanahira's avatar
fi  
nanahira committed
4092
    tcolor = chat_color.save_list[CLIENT_get_authorize_key(tplayer)];
nanahira's avatar
nanahira committed
4093 4094 4095 4096 4097 4098 4099 4100 4101
    if (tcolor) {
      ygopro.stoc_send(client, 'CHAT', {
        player: ygopro.constants.COLORS[tcolor],
        msg: tplayer.name + ": " + info.msg
      });
      return true;
    }
  });

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

nanahira's avatar
nanahira committed
4123
  ygopro.stoc_follow('SELECT_TP', false, function(buffer, info, client, server, datas) {
4124 4125
    var room;
    room = ROOM_all[client.rid];
4126
    if (!room) {
4127 4128
      return;
    }
nanahira's avatar
nanahira committed
4129
    client.selected_preduel = false;
nanahira's avatar
nanahira committed
4130
    room.duel_stage = ygopro.constants.DUEL_STAGE.FIRSTGO;
nanahira's avatar
nanahira committed
4131
    room.selecting_tp = client;
mercury233's avatar
fix  
mercury233 committed
4132
    if (room.random_type || room.arena) {
4133 4134 4135
      room.waiting_for_player = client;
      room.last_active_time = moment();
    }
4136 4137
  });

nanahira's avatar
nanahira committed
4138
  ygopro.stoc_follow('CHANGE_SIDE', false, function(buffer, info, client, server, datas) {
nanahira's avatar
js  
nanahira committed
4139
    var room, room_name, sinterval, temp_log;
4140
    room = ROOM_all[client.rid];
4141
    if (!room) {
mercury233's avatar
mercury233 committed
4142 4143
      return;
    }
nanahira's avatar
nanahira committed
4144 4145 4146
    if (client.pos === 0) {
      room.duel_stage = ygopro.constants.DUEL_STAGE.SIDING;
    }
nanahira's avatar
nanahira committed
4147
    client.selected_preduel = false;
nanahira's avatar
nanahira committed
4148 4149 4150 4151
    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
4152
        if (!(room && client && client.side_tcount && room.duel_stage === ygopro.constants.DUEL_STAGE.SIDING)) {
nanahira's avatar
nanahira committed
4153 4154 4155 4156
          clearInterval(sinterval);
          return;
        }
        if (client.side_tcount === 1) {
nanahira's avatar
fix  
nanahira committed
4157
          ygopro.stoc_send_chat_to_room(room, client.name + "${side_overtime_room}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4158
          ygopro.stoc_send_chat(client, "${side_overtime}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
4159
          CLIENT_send_replays(client, room);
nanahira's avatar
nanahira committed
4160
          CLIENT_kick(client);
nanahira's avatar
nanahira committed
4161 4162 4163
          return clearInterval(sinterval);
        } else {
          client.side_tcount = client.side_tcount - 1;
nanahira's avatar
js  
nanahira committed
4164
          return ygopro.stoc_send_chat(client, "${side_remain_part1}" + client.side_tcount + "${side_remain_part2}", ygopro.constants.COLORS.BABYBLUE);
nanahira's avatar
nanahira committed
4165 4166 4167 4168
        }
      }, 60000);
      client.side_interval = sinterval;
    }
nanahira's avatar
js  
nanahira committed
4169
    if (settings.modules.challonge.enabled && settings.modules.challonge.post_score_midduel && room.hostinfo.mode !== 2 && client.pos === 0) {
nanahira's avatar
nanahira committed
4170
      temp_log = JSON.parse(JSON.stringify(room.get_challonge_score()));
nanahira's avatar
nanahira committed
4171
      delete temp_log.winnerId;
nanahira's avatar
js  
nanahira committed
4172
      room_name = room.name;
nanahira's avatar
nanahira committed
4173
      challonge.matches._update({
4174
        id: settings.modules.challonge.tournament_id,
nanahira's avatar
nanahira committed
4175 4176 4177 4178
        matchId: room.challonge_info.id,
        match: temp_log,
        callback: function(err, data) {
          if (err) {
nanahira's avatar
js  
nanahira committed
4179
            log.warn("Errored pushing scores to Challonge.", room_name, err);
nanahira's avatar
nanahira committed
4180 4181
          } else {
            refresh_challonge_cache();
nanahira's avatar
nanahira committed
4182 4183 4184 4185
          }
        }
      });
    }
4186
    if (room.random_type || room.arena) {
nanahira's avatar
nanahira committed
4187
      if (client.pos === 0) {
4188 4189 4190 4191 4192
        room.waiting_for_player = client;
      } else {
        room.waiting_for_player2 = client;
      }
      room.last_active_time = moment();
mercury233's avatar
mercury233 committed
4193 4194 4195
    }
  });

nanahira's avatar
nanahira committed
4196
  ygopro.stoc_follow('REPLAY', true, function(buffer, info, client, server, datas) {
nanahira's avatar
nanahira committed
4197
    var duellog, dueltime, i, len2, len3, m, n, player, ref2, ref3, replay_filename, room;
4198 4199
    room = ROOM_all[client.rid];
    if (!room) {
mercury233's avatar
fix  
mercury233 committed
4200
      return settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe && settings.modules.tournament_mode.block_replay_to_player || settings.modules.replay_delay;
4201
    }
mercury233's avatar
mercury233 committed
4202
    if (settings.modules.cloud_replay.enabled && room.random_type) {
mercury233's avatar
fix  
mercury233 committed
4203 4204
      Cloud_replay_ids.push(room.cloud_replay_id);
    }
nanahira's avatar
nanahira committed
4205
    if (!room.replays[room.duel_count - 1]) {
4206
      room.replays[room.duel_count - 1] = buffer;
nanahira's avatar
nanahira committed
4207
    }
mercury233's avatar
mercury233 committed
4208
    if (settings.modules.tournament_mode.enabled && settings.modules.tournament_mode.replay_safe) {
nanahira's avatar
nanahira committed
4209
      if (client.pos === 0) {
nanahira's avatar
nanahira committed
4210
        dueltime = moment().format('YYYY-MM-DD HH-mm-ss');
mercury233's avatar
mercury233 committed
4211
        replay_filename = dueltime;
nanahira's avatar
fix  
nanahira committed
4212
        if (room.hostinfo.mode !== 2) {
nanahira's avatar
nanahira committed
4213
          ref2 = room.dueling_players;
nanahira's avatar
nanahira committed
4214
          for (i = m = 0, len2 = ref2.length; m < len2; i = ++m) {
nanahira's avatar
nanahira committed
4215
            player = ref2[i];
nanahira's avatar
nanahira committed
4216 4217 4218
            replay_filename = replay_filename + (i > 0 ? " VS " : " ") + player.name;
          }
        } else {
nanahira's avatar
nanahira committed
4219
          ref3 = room.dueling_players;
nanahira's avatar
nanahira committed
4220
          for (i = n = 0, len3 = ref3.length; n < len3; i = ++n) {
nanahira's avatar
nanahira committed
4221
            player = ref3[i];
nanahira's avatar
nanahira committed
4222 4223
            replay_filename = replay_filename + (i > 0 ? (i === 2 ? " VS " : " & ") : " ") + player.name;
          }
mercury233's avatar
mercury233 committed
4224 4225
        }
        replay_filename = replay_filename.replace(/[\/\\\?\*]/g, '_') + ".yrp";
mercury233's avatar
mercury233 committed
4226
        duellog = {
mercury233's avatar
mercury233 committed
4227
          time: dueltime,
4228
          name: room.name + (settings.modules.tournament_mode.show_info ? " (Duel:" + room.duel_count + ")" : ""),
nanahira's avatar
nanahira committed
4229
          roomid: room.process_pid.toString(),
mercury233's avatar
mercury233 committed
4230
          cloud_replay_id: "R#" + room.cloud_replay_id,
mercury233's avatar
mercury233 committed
4231
          replay_filename: replay_filename,
nanahira's avatar
nanahira committed
4232
          roommode: room.hostinfo.mode,
mercury233's avatar
mercury233 committed
4233
          players: (function() {
nanahira's avatar
nanahira committed
4234
            var len4, o, ref4, results;
nanahira's avatar
nanahira committed
4235
            ref4 = room.dueling_players;
mercury233's avatar
mercury233 committed
4236
            results = [];
nanahira's avatar
nanahira committed
4237 4238
            for (o = 0, len4 = ref4.length; o < len4; o++) {
              player = ref4[o];
mercury233's avatar
mercury233 committed
4239
              results.push({
4240
                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
4241 4242 4243 4244 4245 4246
                winner: player.pos === room.winner
              });
            }
            return results;
          })()
        };
mercury233's avatar
mercury233 committed
4247 4248
        duel_log.duel_log.unshift(duellog);
        setting_save(duel_log);
mercury233's avatar
mercury233 committed
4249 4250 4251 4252 4253
        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
4254
      }
mercury233's avatar
mercury233 committed
4255
      if (settings.modules.cloud_replay.enabled) {
mercury233's avatar
mercury233 committed
4256
        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
4257
      }
nanahira's avatar
nanahira committed
4258
      return settings.modules.tournament_mode.block_replay_to_player || settings.modules.replay_delay && room.hostinfo.mode === 1;
4259
    } else {
nanahira's avatar
nanahira committed
4260
      return settings.modules.replay_delay && room.hostinfo.mode === 1;
4261 4262 4263
    }
  });

mercury233's avatar
mercury233 committed
4264
  if (settings.modules.random_duel.enabled) {
mercury233's avatar
mercury233 committed
4265
    setInterval(function() {
nanahira's avatar
nanahira committed
4266 4267 4268
      var len2, m, room, time_passed;
      for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
        room = ROOM_all[m];
nanahira's avatar
nanahira committed
4269
        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)) {
mercury233's avatar
mercury233 committed
4270 4271 4272
          continue;
        }
        time_passed = Math.floor((moment() - room.last_active_time) / 1000);
4273
        if (time_passed >= settings.modules.random_duel.hang_timeout) {
mercury233's avatar
mercury233 committed
4274
          room.last_active_time = moment();
mercury233's avatar
mercury233 committed
4275
          ROOM_ban_player(room.waiting_for_player.name, room.waiting_for_player.ip, "${random_ban_reason_AFK}");
4276
          room.scores[room.waiting_for_player.name_vpass] = -9;
mercury233's avatar
mercury233 committed
4277
          ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
nanahira's avatar
nanahira committed
4278
          CLIENT_send_replays(room.waiting_for_player, room);
nanahira's avatar
js  
nanahira committed
4279
          CLIENT_kick(room.waiting_for_player);
4280
        } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
mercury233's avatar
mercury233 committed
4281
          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
4282
          ROOM_unwelcome(room, room.waiting_for_player, "${random_ban_reason_AFK}");
mercury233's avatar
mercury233 committed
4283
        }
4284
      }
mercury233's avatar
mercury233 committed
4285 4286 4287
    }, 1000);
  }

4288 4289
  if (settings.modules.mycard.enabled) {
    setInterval(function() {
nanahira's avatar
nanahira committed
4290
      var len2, len3, m, n, player, room, time_passed, waited_time;
nanahira's avatar
nanahira committed
4291 4292
      for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
        room = ROOM_all[m];
nanahira's avatar
nanahira committed
4293
        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)) {
4294 4295 4296
          continue;
        }
        time_passed = Math.floor((moment() - room.last_active_time) / 1000);
4297
        if (time_passed >= settings.modules.random_duel.hang_timeout) {
4298 4299
          room.last_active_time = moment();
          ygopro.stoc_send_chat_to_room(room, room.waiting_for_player.name + " ${kicked_by_system}", ygopro.constants.COLORS.RED);
4300
          room.scores[room.waiting_for_player.name_vpass] = -9;
nanahira's avatar
nanahira committed
4301
          CLIENT_send_replays(room.waiting_for_player, room);
nanahira's avatar
js  
nanahira committed
4302
          CLIENT_kick(room.waiting_for_player);
4303
        } else if (time_passed >= (settings.modules.random_duel.hang_timeout - 20) && !(time_passed % 10)) {
4304 4305 4306
          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);
        }
      }
4307 4308 4309
      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
4310
          if (!(room && room.arena && room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN && room.get_playing_player().length < 2)) {
4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321
            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
4322 4323 4324
          }
        }
      }
4325 4326 4327
    }, 1000);
  }

nanahira's avatar
nanahira committed
4328 4329 4330 4331 4332
  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
4333
        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
4334
          ref2 = room.get_playing_player();
nanahira's avatar
nanahira committed
4335 4336
          for (n = 0, len3 = ref2.length; n < len3; n++) {
            player = ref2[n];
nanahira's avatar
nanahira committed
4337
            if (player && (room.duel_stage !== ygopro.constants.DUEL_STAGE.SIDING || player.selected_preduel)) {
nanahira's avatar
nanahira committed
4338 4339 4340 4341 4342 4343 4344 4345
              CLIENT_heartbeat_register(player, true);
            }
          }
        }
      }
    }, settings.modules.heartbeat_detection.interval);
  }

nanahira's avatar
nanahira committed
4346 4347 4348 4349 4350 4351
  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
4352
      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
4353 4354 4355 4356 4357 4358 4359 4360
        continue;
      }
      room.auto_death_triggered = true;
      results.push(room.start_death());
    }
    return results;
  }, 1000);

nanahira's avatar
nanahira committed
4361 4362
  windbot_looplimit = 0;

nanahira's avatar
nanahira committed
4363
  windbot_process = global.windbot_process = null;
nanahira's avatar
nanahira committed
4364

nanahira's avatar
nanahira committed
4365
  spawn_windbot = global.spawn_windbot = function() {
nanahira's avatar
nanahira committed
4366
    var windbot_bin, windbot_parameters;
mercury233's avatar
mercury233 committed
4367 4368 4369 4370 4371 4372 4373 4374 4375 4376
    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
4377 4378 4379 4380
      cwd: 'windbot'
    });
    windbot_process.on('error', function(err) {
      log.warn('WindBot ERROR', err);
nanahira's avatar
nanahira committed
4381
      if (windbot_looplimit < 1000 && !rebooted) {
nanahira's avatar
nanahira committed
4382 4383 4384
        windbot_looplimit++;
        spawn_windbot();
      }
mercury233's avatar
mercury233 committed
4385 4386 4387
    });
    windbot_process.on('exit', function(code) {
      log.warn('WindBot EXIT', code);
nanahira's avatar
nanahira committed
4388
      if (windbot_looplimit < 1000 && !rebooted) {
nanahira's avatar
nanahira committed
4389 4390 4391
        windbot_looplimit++;
        spawn_windbot();
      }
mercury233's avatar
mercury233 committed
4392 4393 4394 4395 4396
    });
    windbot_process.stdout.setEncoding('utf8');
    windbot_process.stdout.on('data', function(data) {
      log.info('WindBot:', data);
    });
mercury233's avatar
fix  
mercury233 committed
4397
    windbot_process.stderr.setEncoding('utf8');
nanahira's avatar
nanahira committed
4398
    windbot_process.stderr.on('data', function(data) {
mercury233's avatar
mercury233 committed
4399 4400
      log.warn('WindBot Error:', data);
    });
nanahira's avatar
nanahira committed
4401 4402 4403 4404
  };

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

nanahira's avatar
nanahira committed
4407 4408
  rebooted = false;

神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4409
  if (settings.modules.http) {
mercury233's avatar
mercury233 committed
4410 4411 4412 4413 4414 4415
    addCallback = function(callback, text) {
      if (!callback) {
        return text;
      }
      return callback + "( " + text + " );";
    };
4416
    requestListener = function(request, response) {
nanahira's avatar
nanahira committed
4417
      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;
4418 4419 4420
      parseQueryString = true;
      u = url.parse(request.url, parseQueryString);
      if (u.pathname === '/api/getrooms') {
nanahira's avatar
fix  
nanahira committed
4421 4422
        pass_validated = auth.auth(u.query.username, u.query.pass, "get_rooms", "get_rooms");
        if (!settings.modules.http.public_roomlist && !pass_validated) {
4423
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4424
          response.end(addCallback(u.query.callback, '{"rooms":[{"roomid":"0","roomname":"密码错误","needpass":"true"}]}'));
4425 4426 4427 4428
        } else {
          response.writeHead(200);
          roomsjson = JSON.stringify({
            rooms: (function() {
nanahira's avatar
nanahira committed
4429
              var len2, m, results;
4430
              results = [];
nanahira's avatar
nanahira committed
4431 4432
              for (m = 0, len2 = ROOM_all.length; m < len2; m++) {
                room = ROOM_all[m];
4433
                if (room && room.established) {
4434
                  results.push({
nanahira's avatar
nanahira committed
4435
                    roomid: room.process_pid.toString(),
4436
                    roomname: pass_validated ? room.name : room.name.split('$', 2)[0],
nanahira's avatar
fix  
nanahira committed
4437
                    roommode: room.hostinfo.mode,
4438
                    needpass: (room.name.indexOf('$') !== -1).toString(),
mercury233's avatar
mercury233 committed
4439
                    users: _.sortBy((function() {
nanahira's avatar
nanahira committed
4440
                      var len3, n, ref2, results1;
nanahira's avatar
nanahira committed
4441
                      ref2 = room.players;
4442
                      results1 = [];
nanahira's avatar
nanahira committed
4443 4444
                      for (n = 0, len3 = ref2.length; n < len3; n++) {
                        player = ref2[n];
4445 4446 4447
                        if (player.pos != null) {
                          results1.push({
                            id: (-1).toString(),
mercury233's avatar
mercury233 committed
4448 4449
                            name: player.name,
                            ip: settings.modules.http.show_ip && pass_validated && !player.is_local ? player.ip.slice(7) : null,
nanahira's avatar
nanahira committed
4450
                            status: settings.modules.http.show_info && room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN && player.pos !== 7 ? {
mercury233's avatar
mercury233 committed
4451 4452 4453 4454
                              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,
4455 4456 4457
                            pos: player.pos
                          });
                        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4458
                      }
4459
                      return results1;
mercury233's avatar
mercury233 committed
4460
                    })(), "pos"),
nanahira's avatar
nanahira committed
4461
                    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'
4462 4463
                  });
                }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4464
              }
4465 4466
              return results;
            })()
mercury233's avatar
mercury233 committed
4467 4468
          }, null, 2);
          response.end(addCallback(u.query.callback, roomsjson));
4469
        }
mercury233's avatar
mercury233 committed
4470
      } else if (u.pathname === '/api/duellog' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4471
        if (!auth.auth(u.query.username, u.query.pass, "duel_log", "duel_log")) {
mercury233's avatar
mercury233 committed
4472
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4473
          response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"));
mercury233's avatar
mercury233 committed
4474 4475 4476
          return;
        } else {
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4477
          duellog = JSON.stringify(duel_log.duel_log, null, 2);
mercury233's avatar
mercury233 committed
4478
          response.end(addCallback(u.query.callback, duellog));
mercury233's avatar
mercury233 committed
4479
        }
nanahira's avatar
nanahira committed
4480
      } else if (u.pathname === '/api/archive.zip' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4481
        if (!auth.auth(u.query.username, u.query.pass, "download_replay", "download_replay_archive")) {
nanahira's avatar
nanahira committed
4482 4483 4484 4485 4486
          response.writeHead(403);
          response.end("Invalid password.");
          return;
        } else {
          try {
nanahira's avatar
nanahira committed
4487
            archive_name = moment().format('YYYY-MM-DD HH-mm-ss') + ".zip";
nanahira's avatar
nanahira committed
4488
            archive_args = ["a", "-mx0", "-y", archive_name];
nanahira's avatar
fix  
nanahira committed
4489
            check = false;
nanahira's avatar
nanahira committed
4490
            ref2 = duel_log.duel_log;
nanahira's avatar
nanahira committed
4491 4492
            for (m = 0, len2 = ref2.length; m < len2; m++) {
              replay = ref2[m];
nanahira's avatar
fix  
nanahira committed
4493
              check = true;
nanahira's avatar
nanahira committed
4494 4495
              archive_args.push(replay.replay_filename);
            }
nanahira's avatar
fix  
nanahira committed
4496 4497 4498 4499 4500
            if (!check) {
              response.writeHead(403);
              response.end("Duel logs not found.");
              return;
            }
nanahira's avatar
nanahira committed
4501 4502 4503
            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
4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525
            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
4526
            archive_process.stdout.setEncoding('utf8');
nanahira's avatar
js  
nanahira committed
4527 4528 4529 4530 4531
            archive_process.stdout.on('data', (function(_this) {
              return function(data) {
                return log.info("archive process: " + data);
              };
            })(this));
nanahira's avatar
nanahira committed
4532
            archive_process.stderr.setEncoding('utf8');
nanahira's avatar
js  
nanahira committed
4533 4534 4535 4536 4537
            archive_process.stderr.on('data', (function(_this) {
              return function(data) {
                return log.warn("archive error: " + data);
              };
            })(this));
nanahira's avatar
nanahira committed
4538 4539 4540 4541 4542 4543
          } catch (error1) {
            error = error1;
            response.writeHead(403);
            response.end("Failed reading replays. " + error);
          }
        }
nanahira's avatar
nanahira committed
4544
      } else if (u.pathname === '/api/clearlog' && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4545
        if (!auth.auth(u.query.username, u.query.pass, "clear_duel_log", "clear_duel_log")) {
nanahira's avatar
nanahira committed
4546 4547 4548 4549 4550
          response.writeHead(200);
          response.end(addCallback(u.query.callback, "[{name:'密码错误'}]"));
          return;
        } else {
          response.writeHead(200);
4551 4552 4553 4554 4555 4556 4557
          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);
              }
            });
          }
4558 4559
          duel_log.duel_log = [];
          setting_save(duel_log);
nanahira's avatar
nanahira committed
4560 4561
          response.end(addCallback(u.query.callback, "[{name:'Success'}]"));
        }
mercury233's avatar
mercury233 committed
4562
      } else if (_.startsWith(u.pathname, '/api/replay') && settings.modules.tournament_mode.enabled) {
nanahira's avatar
nanahira committed
4563
        if (!auth.auth(u.query.username, u.query.pass, "download_replay", "download_replay")) {
mercury233's avatar
mercury233 committed
4564 4565 4566 4567 4568
          response.writeHead(403);
          response.end("密码错误");
          return;
        } else {
          getpath = u.pathname.split("/");
4569
          filename = path.basename(decodeURIComponent(getpath.pop()));
mercury233's avatar
mercury233 committed
4570 4571 4572
          fs.readFile(settings.modules.tournament_mode.replay_path + filename, function(error, buffer) {
            if (error) {
              response.writeHead(404);
mercury233's avatar
fix  
mercury233 committed
4573
              response.end("未找到文件 " + filename);
mercury233's avatar
mercury233 committed
4574 4575 4576 4577 4578
            } else {
              response.writeHead(200, {
                "Content-Type": "application/octet-stream",
                "Content-Disposition": "attachment"
              });
mercury233's avatar
fix  
mercury233 committed
4579
              response.end(buffer);
mercury233's avatar
mercury233 committed
4580 4581 4582
            }
          });
        }
4583 4584
      } else if (u.pathname === '/api/message') {
        if (u.query.shout) {
nanahira's avatar
nanahira committed
4585 4586 4587 4588 4589
          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
4590 4591
          for (n = 0, len3 = ROOM_all.length; n < len3; n++) {
            room = ROOM_all[n];
4592 4593 4594
            if (room && room.established) {
              ygopro.stoc_send_chat_to_room(room, u.query.shout, ygopro.constants.COLORS.YELLOW);
            }
4595 4596
          }
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4597
          response.end(addCallback(u.query.callback, "['shout ok', '" + u.query.shout + "']"));
4598
        } else if (u.query.stop) {
nanahira's avatar
nanahira committed
4599 4600 4601 4602 4603
          if (!auth.auth(u.query.username, u.query.pass, "stop", "stop")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
4604 4605 4606
          if (u.query.stop === 'false') {
            u.query.stop = false;
          }
mercury233's avatar
mercury233 committed
4607
          setting_change(settings, 'modules:stop', u.query.stop);
4608
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4609
          response.end(addCallback(u.query.callback, "['stop ok', '" + u.query.stop + "']"));
4610
        } else if (u.query.welcome) {
nanahira's avatar
nanahira committed
4611 4612 4613 4614 4615
          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
4616
          setting_change(settings, 'modules:welcome', u.query.welcome);
mercury233's avatar
mercury233 committed
4617
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4618
          response.end(addCallback(u.query.callback, "['welcome ok', '" + u.query.welcome + "']"));
mercury233's avatar
mercury233 committed
4619
        } else if (u.query.getwelcome) {
nanahira's avatar
nanahira committed
4620 4621 4622 4623 4624
          if (!auth.auth(u.query.username, u.query.pass, "change_settings", "get_welcome")) {
            response.writeHead(200);
            response.end(addCallback(u.query.callback, "['密码错误', 0]"));
            return;
          }
4625
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4626
          response.end(addCallback(u.query.callback, "['get ok', '" + settings.modules.welcome + "']"));
mercury233's avatar
mercury233 committed
4627
        } else if (u.query.loadtips) {
nanahira's avatar
nanahira committed
4628 4629 4630 4631 4632
          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
4633 4634
          load_tips();
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4635
          response.end(addCallback(u.query.callback, "['loading tip', '" + settings.modules.tips.get + "']"));
mercury233's avatar
mercury233 committed
4636
        } else if (u.query.loaddialogues) {
nanahira's avatar
nanahira committed
4637 4638 4639 4640 4641
          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
4642 4643
          load_dialogues();
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4644
          response.end(addCallback(u.query.callback, "['loading dialogues', '" + settings.modules.dialogues.get + "']"));
mercury233's avatar
mercury233 committed
4645
        } else if (u.query.ban) {
nanahira's avatar
nanahira committed
4646 4647 4648 4649 4650
          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
4651
          ban_user(u.query.ban);
mercury233's avatar
mercury233 committed
4652
          response.writeHead(200);
mercury233's avatar
mercury233 committed
4653
          response.end(addCallback(u.query.callback, "['ban ok', '" + u.query.ban + "']"));
nanahira's avatar
nanahira committed
4654
        } else if (u.query.kick) {
nanahira's avatar
nanahira committed
4655 4656 4657 4658 4659
          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
4660
          kick_room_found = false;
nanahira's avatar
nanahira committed
4661 4662
          for (o = 0, len4 = ROOM_all.length; o < len4; o++) {
            room = ROOM_all[o];
nanahira's avatar
nanahira committed
4663
            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
4664 4665 4666
              continue;
            }
            kick_room_found = true;
nanahira's avatar
nanahira committed
4667
            if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
4668 4669
              room.scores[room.dueling_players[0].name_vpass] = 0;
              room.scores[room.dueling_players[1].name_vpass] = 0;
nanahira's avatar
nanahira committed
4670
            }
nanahira's avatar
fix  
nanahira committed
4671
            room.kicked = true;
nanahira's avatar
js  
nanahira committed
4672
            room.send_replays();
nanahira's avatar
nanahira committed
4673 4674 4675 4676 4677 4678 4679 4680 4681 4682
            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
4683 4684 4685 4686 4687
          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
4688 4689 4690
          death_room_found = false;
          for (p = 0, len5 = ROOM_all.length; p < len5; p++) {
            room = ROOM_all[p];
nanahira's avatar
nanahira committed
4691 4692 4693
            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
4694
              }
nanahira's avatar
nanahira committed
4695 4696 4697 4698 4699 4700 4701 4702 4703
            }
          }
          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
4704 4705 4706 4707 4708
          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
4709
          death_room_found = false;
nanahira's avatar
nanahira committed
4710 4711
          for (q = 0, len6 = ROOM_all.length; q < len6; q++) {
            room = ROOM_all[q];
nanahira's avatar
nanahira committed
4712
            if (room && (u.query.deathcancel === "all" || u.query.deathcancel === room.process_pid.toString() || u.query.deathcancel === room.name)) {
nanahira's avatar
nanahira committed
4713 4714 4715
              if (room.cancel_death()) {
                death_room_found = true;
              }
nanahira's avatar
nanahira committed
4716 4717 4718 4719 4720 4721 4722 4723
            }
          }
          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
4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734
        } 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
4735
            if (room.duel_stage !== ygopro.constants.DUEL_STAGE.BEGIN) {
nanahira's avatar
nanahira committed
4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750
              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";
4751
        } else {
mercury233's avatar
mercury233 committed
4752
          response.writeHead(400);
4753
          response.end();
4754
        }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4755
      } else {
mercury233's avatar
mercury233 committed
4756
        response.writeHead(400);
mercury233's avatar
test3  
mercury233 committed
4757
        response.end();
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4758
      }
4759 4760
    };
    http_server = http.createServer(requestListener);
神楽坂玲奈's avatar
神楽坂玲奈 committed
4761
    http_server.listen(settings.modules.http.port);
mercury233's avatar
mercury233 committed
4762
    if (settings.modules.http.ssl.enabled) {
4763 4764 4765 4766 4767 4768
      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
4769 4770 4771
      if (settings.modules.http.websocket_roomlist && roomlist) {
        roomlist.init(https_server, ROOM_all);
      }
4772 4773
      https_server.listen(settings.modules.http.ssl.port);
    }
神楽坂玲奈's avatar
11.7  
神楽坂玲奈 committed
4774
  }
神楽坂玲奈's avatar
神楽坂玲奈 committed
4775

nanahira's avatar
nanahira committed
4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787
  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];
    plugin_path = "./plugins/" + plugin_filename;
    require(plugin_path);
  }

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