Add routes
This commit is contained in:
parent
3c936c75a6
commit
f4b3c0a333
521
routes/mj.js
Normal file
521
routes/mj.js
Normal file
@ -0,0 +1,521 @@
|
||||
let dict = require('./translate');
|
||||
|
||||
function Tile(t) {
|
||||
let m = Math.floor(t / 36),
|
||||
d = t % 36,
|
||||
n = Math.floor(d / 4) + 1,
|
||||
res;
|
||||
switch (m) {
|
||||
case 0:
|
||||
res = 'm' + (d == 16 ? 'a' : n);
|
||||
break;
|
||||
case 1:
|
||||
res = 'p' + (d == 16 ? 'a' : n);
|
||||
break;
|
||||
case 2:
|
||||
res = 's' + (d == 16 ? 'a' : n);
|
||||
break;
|
||||
case 3:
|
||||
let s = Math.floor(d / 4);
|
||||
switch (s) {
|
||||
case 0:
|
||||
res = 'tan';
|
||||
break;
|
||||
case 1:
|
||||
res = 'nan';
|
||||
break;
|
||||
case 2:
|
||||
res = 'xia';
|
||||
break;
|
||||
case 3:
|
||||
res = 'pei';
|
||||
break;
|
||||
case 4:
|
||||
res = 'haku';
|
||||
break;
|
||||
case 5:
|
||||
res = 'hatsu';
|
||||
break;
|
||||
case 6:
|
||||
res = 'chun';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function Hand(h) {
|
||||
return h.map(function(t) {
|
||||
return Tile(t);
|
||||
});
|
||||
}
|
||||
|
||||
function replaceTiles(trg) {
|
||||
let res = trg;
|
||||
for (var r = 0; r < res.rounds.length; r++) {
|
||||
// обработка конечных рук
|
||||
for (var f = 0; f < res.rounds[r].finish.length; f++) {
|
||||
let finish = res.rounds[r].finish[f].sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
res.rounds[r].finish[f] = Hand(res.rounds[r].finish[f]).slice();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function decodeList(list, to_int, sort) {
|
||||
if (typeof sort === 'undefined') sort = false;
|
||||
let res = list.split(',');
|
||||
res = (to_int ? res.map(function(a) {
|
||||
return parseInt(a);
|
||||
}) : res);
|
||||
return (sort ? res.sort(function(a, b) {
|
||||
return a - b;
|
||||
}) : res);
|
||||
}
|
||||
|
||||
function parseScore(data, mult) {
|
||||
let res = [];
|
||||
for (var i = 0; i < data.length / 2; i++) {
|
||||
res.push({
|
||||
begin: data[2 * i] * mult,
|
||||
diff: data[2 * i + 1] * mult,
|
||||
end: (data[2 * i] + data[2 * i + 1]) * mult
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function parseMeld(data) {
|
||||
if (data & 0x4) {
|
||||
return parse_chi(data);
|
||||
} else if (data & 0x18) {
|
||||
return parse_pon(data);
|
||||
} else if (data & 0x20) {
|
||||
return parse_nuki(data);
|
||||
} else {
|
||||
return parse_kan(data);
|
||||
}
|
||||
}
|
||||
|
||||
function parse_chi(data) {
|
||||
let t0 = (data >> 3) & 0x3,
|
||||
t1 = (data >> 5) & 0x3,
|
||||
t2 = (data >> 7) & 0x3,
|
||||
base_and_called = data >> 10,
|
||||
base = Math.floor(base_and_called / 3),
|
||||
called = base_and_called - 3 * base;
|
||||
base = Math.floor(base / 7) * 9 + base % 7;
|
||||
return {
|
||||
type: 'chi',
|
||||
fromPlayer: (data & 0x3),
|
||||
called: called,
|
||||
tiles: [t0 + 4 * (base + 0), t1 + 4 * (base + 1), t2 + 4 * (base + 2)]
|
||||
};
|
||||
}
|
||||
|
||||
function parse_pon(data) {
|
||||
let t4 = (data >> 5) & 0x3,
|
||||
arr = [
|
||||
[1, 2, 3],
|
||||
[0, 2, 3],
|
||||
[0, 1, 3],
|
||||
[0, 1, 2]
|
||||
],
|
||||
t0 = arr[t4][0],
|
||||
t1 = arr[t4][1],
|
||||
t2 = arr[t4][2],
|
||||
base_and_called = data >> 9,
|
||||
base = Math.floor(base_and_called / 3),
|
||||
called = base_and_called - 3 * base;
|
||||
if (data & 0x8) {
|
||||
return {
|
||||
type: 'pon',
|
||||
fromPlayer: (data & 0x3),
|
||||
called: called,
|
||||
tiles: [t0 + 4 * base, t1 + 4 * base, t2 + 4 * base]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: 'chakan',
|
||||
fromPlayer: (data & 0x3),
|
||||
called: called,
|
||||
tiles: [t0 + 4 * base, t1 + 4 * base, t2 + 4 * base, t4 + 4 * base]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function parse_kan(data) {
|
||||
let base_and_called = data >> 8,
|
||||
base = Math.floor(base_and_called / 4),
|
||||
called = base_and_called - 4 * base;
|
||||
return {
|
||||
type: 'kan',
|
||||
fromPlayer: (data & 0x3),
|
||||
called: called,
|
||||
tiles: [4 * base, 1 + 4 * base, 2 + 4 * base, 3 + 4 * base]
|
||||
};
|
||||
}
|
||||
|
||||
function parse_nuki(data) {
|
||||
return {
|
||||
type: 'nuki',
|
||||
tiles: [data >> 8]
|
||||
};
|
||||
}
|
||||
|
||||
function parseLog(namelog, file, lang) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var fs = require('fs'),
|
||||
xmlparser = require('htmlparser2');
|
||||
var parser = new xmlparser.Parser({
|
||||
onopentag: function(name, attribs) {
|
||||
switch (true) {
|
||||
case /mjloggm/.test(name):
|
||||
res = {
|
||||
log: namelog,
|
||||
players: [],
|
||||
rounds: []
|
||||
};
|
||||
break;
|
||||
case /un/.test(name) && (typeof attribs.sx !== 'undefined'):
|
||||
var sex = decodeList(attribs.sx),
|
||||
dan = decodeList(attribs.dan),
|
||||
rate = decodeList(attribs.rate);
|
||||
[0, 1, 2, 3].forEach(function(p) {
|
||||
res.players[p] = {
|
||||
name: decodeURIComponent(attribs['n' + p]),
|
||||
sex: sex[p],
|
||||
dan: parseInt(dan[p]),
|
||||
rate: parseFloat(rate[p]),
|
||||
connected: true
|
||||
};
|
||||
});
|
||||
break;
|
||||
case /bye/.test(name) && (typeof attribs.who !== 'undefined'):
|
||||
res.players[parseInt(attribs.who)].connected = false;
|
||||
break;
|
||||
case /taikyoku/.test(name) && (typeof attribs.oya !== 'undefined'):
|
||||
res.diler = parseInt(attribs.oya);
|
||||
break;
|
||||
case /init/.test(name) && (typeof attribs.oya !== 'undefined'):
|
||||
let seed = decodeList(attribs.seed);
|
||||
res.rounds.push({
|
||||
name: parseInt(seed[0]),
|
||||
honba: parseInt(seed[1]),
|
||||
riichi: {
|
||||
count: parseInt(seed[2]),
|
||||
player: []
|
||||
},
|
||||
d0: parseInt(seed[3]),
|
||||
d1: parseInt(seed[4]),
|
||||
dora: Hand([parseInt(seed[5])]),
|
||||
uradora: [],
|
||||
diler: parseInt(attribs.oya),
|
||||
hands: [],
|
||||
finish: [],
|
||||
meld: [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
events: [
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
]
|
||||
});
|
||||
cur_game = res.rounds.length - 1;
|
||||
cur_player = res.rounds[cur_game].diler;
|
||||
cur_event = -1;
|
||||
[0, 1, 2, 3].forEach(function(p) {
|
||||
res.rounds[cur_game].finish[p] = decodeList(attribs['hai' + p], true, true);
|
||||
res.rounds[cur_game].hands[p] = Hand(decodeList(attribs['hai' + p], true, true));
|
||||
});
|
||||
break;
|
||||
case /agari/.test(name) && (typeof attribs.ba !== 'undefined'):
|
||||
if (!res.rounds[cur_game].win) res.rounds[cur_game].win = [];
|
||||
let ten = decodeList(attribs.ten),
|
||||
hand = decodeList(attribs.hai, true, true),
|
||||
machi = decodeList(attribs.machi, true, false),
|
||||
wintile = hand.indexOf(machi[0]),
|
||||
agari = {
|
||||
type: (attribs.fromwho != attribs.who ? 'ron' : 'tsumo'),
|
||||
player: parseInt(attribs.who),
|
||||
hand: Hand(hand),
|
||||
points: parseInt(ten[1]),
|
||||
fu: parseInt(ten[0]),
|
||||
dora: Hand(decodeList(attribs.dorahai, true, false)),
|
||||
machi: wintile
|
||||
};
|
||||
if (attribs.m) {
|
||||
agari.melds = [];
|
||||
decodeList(attribs.m, true, false).forEach(function(m) {
|
||||
agari.melds.push(parseMeld(m));
|
||||
});
|
||||
agari.closed = [];
|
||||
agari.melds.forEach(function(m) {
|
||||
m.tiles = Hand(m.tiles);
|
||||
if (!m.fromPlayer) {
|
||||
agari.closed.push(m);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
agari.closed = true;
|
||||
}
|
||||
if (parseInt(ten[2]) > 0) {
|
||||
agari.limit = parseInt(ten[2]);
|
||||
}
|
||||
if (attribs.dorahaiura) {
|
||||
agari.uradora = Hand(decodeList(attribs.dorahaiura, true, false));
|
||||
res.rounds[cur_game].uradora = agari.uradora;
|
||||
}
|
||||
if (agari.type == 'ron') {
|
||||
agari.fromPlayer = parseInt(attribs.fromwho);
|
||||
res.rounds[cur_game].events[agari.fromPlayer][res.rounds[cur_game].events[agari.fromPlayer].length - 1].furikomi = 1;
|
||||
}
|
||||
if (attribs.yaku) {
|
||||
let yakus = decodeList(attribs.yaku);
|
||||
agari.yakulist = [];
|
||||
for (var y = 0; y < yakus.length / 2; y++) {
|
||||
agari.yakulist.push({
|
||||
yaku: parseInt(yakus[2 * y]),
|
||||
han: parseInt(yakus[2 * y + 1])
|
||||
});
|
||||
}
|
||||
} else if (attribs.yakuman) {
|
||||
agari.yakuman = decodeList(attribs.yakuman, true, true);
|
||||
}
|
||||
if (attribs.sc) {
|
||||
res.rounds[cur_game].score = parseScore(decodeList(attribs.sc, true, false), 100);
|
||||
}
|
||||
res.rounds[cur_game].win.push(agari);
|
||||
res.rounds[cur_game].finish[parseInt(attribs.who)] = [];
|
||||
break;
|
||||
case /ryuukyoku/.test(name) && (typeof attribs.ba !== 'undefined'):
|
||||
res.rounds[cur_game].draw = {};
|
||||
if (attribs.type) {
|
||||
res.rounds[cur_game].draw.type = attribs.type;
|
||||
}
|
||||
if (attribs.sc) {
|
||||
res.rounds[cur_game].score = parseScore(decodeList(attribs.sc, true, false), 100);
|
||||
}
|
||||
if (attribs.ba) {
|
||||
let ba = decodeList(attribs.ba, true, false);
|
||||
res.rounds[cur_game].draw.honba = ba[0];
|
||||
res.rounds[cur_game].draw.riichi = ba[1];
|
||||
}
|
||||
if (res.rounds[cur_game].draw || res.rounds[cur_game].draw.type === 'nm') {
|
||||
res.rounds[cur_game].draw.tenpai = [];
|
||||
[0, 1, 2, 3].forEach(function(p) {
|
||||
let hand = [];
|
||||
if (attribs['hai' + p]) {
|
||||
hand = Hand(decodeList(attribs['hai' + p], true, true));
|
||||
res.rounds[cur_game].finish[p] = [];
|
||||
}
|
||||
res.rounds[cur_game].draw.tenpai.push(hand);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case /^[t-w]\d+/.test(name):
|
||||
let draw = /^([t-w])(\d+)$/.exec(name);
|
||||
cur_player = ['t', 'u', 'v', 'w'].indexOf(draw[1]);
|
||||
// Проверим тайл замены при кане
|
||||
if (res.rounds[cur_game].events[cur_player][cur_event] &&
|
||||
res.rounds[cur_game].events[cur_player][cur_event].call &&
|
||||
(res.rounds[cur_game].events[cur_player][cur_event].call.type === 'kan' ||
|
||||
res.rounds[cur_game].events[cur_player][cur_event].call.type === 'chakan')
|
||||
) {
|
||||
res.rounds[cur_game].events[cur_player][cur_event].draw = Tile(parseInt(draw[2]));
|
||||
} else {
|
||||
// начало ходов начинаем с дилера
|
||||
if (cur_player === res.rounds[cur_game].diler) cur_event++;
|
||||
res.rounds[cur_game].events[cur_player][cur_event] = {
|
||||
draw: Tile(parseInt(draw[2]))
|
||||
};
|
||||
}
|
||||
res.rounds[cur_game].finish[cur_player].push(parseInt(draw[2]));
|
||||
break;
|
||||
case /^[d-g]\d+/.test(name):
|
||||
let discard = /^([d-g])(\d+)$/.exec(name);
|
||||
cur_player = ['d', 'e', 'f', 'g'].indexOf(discard[1]);
|
||||
// Обработка цумогири
|
||||
if (!res.rounds[cur_game].events[cur_player][cur_event].call &&
|
||||
!res.rounds[cur_game].events[cur_player][cur_event].reach &&
|
||||
res.rounds[cur_game].events[cur_player][cur_event].draw == Tile(parseInt(discard[2]))) {
|
||||
delete res.rounds[cur_game].events[cur_player][cur_event].draw;
|
||||
res.rounds[cur_game].events[cur_player][cur_event].tsumogiri = Tile(parseInt(discard[2]));
|
||||
} else {
|
||||
res.rounds[cur_game].events[cur_player][cur_event].discard = Tile(parseInt(discard[2]));
|
||||
}
|
||||
// Уберем из финальной руки выкинутый тайл
|
||||
if (res.rounds[cur_game].finish[cur_player].indexOf(parseInt(discard[2])) >= 0) {
|
||||
res.rounds[cur_game].finish[cur_player].splice(
|
||||
res.rounds[cur_game].finish[cur_player].indexOf(parseInt(discard[2])), 1);
|
||||
}
|
||||
break;
|
||||
case /dora/.test(name) && (typeof attribs.hai !== 'undefined'):
|
||||
res.rounds[cur_game].events[cur_player][cur_event].dora = Tile(parseInt(attribs.hai));
|
||||
res.rounds[cur_game].dora.push(Tile(parseInt(attribs.hai)));
|
||||
break;
|
||||
case /n/.test(name) && (typeof attribs.m !== 'undefined'):
|
||||
let meld = parseMeld(attribs.m);
|
||||
meld.player = parseInt(attribs.who);
|
||||
// уберем из финальной руки сет
|
||||
for (var i = 0; i < meld.tiles.length; i++) {
|
||||
if (res.rounds[cur_game].finish[meld.player].indexOf(parseInt(meld.tiles[i])) >= 0) {
|
||||
res.rounds[cur_game].finish[meld.player].splice(
|
||||
res.rounds[cur_game].finish[meld.player].indexOf(parseInt(meld.tiles[i])), 1);
|
||||
}
|
||||
}
|
||||
meld.tiles = Hand(meld.tiles);
|
||||
if (meld.type != 'chakan') {
|
||||
// проверим нужно ли увеличить счетчик хода
|
||||
let tmp_meld = meld.player - res.rounds[cur_game].diler,
|
||||
tmp_player = cur_player - res.rounds[cur_game].diler;
|
||||
tmp_meld = (tmp_meld < 0 ? tmp_meld + 4 : tmp_meld);
|
||||
tmp_player = (tmp_player < 0 ? tmp_player + 4 : tmp_player);
|
||||
if (tmp_meld < tmp_player) {
|
||||
cur_event++;
|
||||
}
|
||||
meld.rotate = (meld.player - cur_player + 4) % 4;
|
||||
if (meld.type === 'pon') {
|
||||
meld.rotate--;
|
||||
} else if (meld.type === 'kan') {
|
||||
meld.rotate = [4, 0, 1, 3][meld.rotate];
|
||||
}
|
||||
res.rounds[cur_game].events[meld.player][cur_event] = {
|
||||
call: meld
|
||||
};
|
||||
} else {
|
||||
res.rounds[cur_game].meld[meld.player].forEach(function(item, i) {
|
||||
if (item.type === 'pon' && item.tiles[0] === meld.tiles[0]) {
|
||||
res.rounds[cur_game].meld[meld.player].splice(i, 1);
|
||||
meld.rotate = item.rotate;
|
||||
}
|
||||
});
|
||||
res.rounds[cur_game].events[meld.player][cur_event].call = meld;
|
||||
}
|
||||
res.rounds[cur_game].meld[meld.player].push(meld);
|
||||
cur_player = meld.player;
|
||||
break;
|
||||
case /reach/.test(name) && (typeof attribs.step !== 'undefined'):
|
||||
if (attribs.ten && attribs.step == 2) {
|
||||
res.rounds[cur_game].events[attribs.who][cur_event].reach = decodeList(attribs.ten, true, false);
|
||||
res.rounds[cur_game].riichi.player.push(parseInt(attribs.who));
|
||||
} else if (attribs.step == 1) {
|
||||
res.rounds[cur_game].events[attribs.who][cur_event].reach = [];
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
onclosetag: function(tagname) {
|
||||
if (tagname === 'mjloggm') {
|
||||
res = replaceTiles(res);
|
||||
resolve(res);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
xmlMode: true,
|
||||
lowerCaseTags: true,
|
||||
lowerCaseAttributeNames: true
|
||||
});
|
||||
|
||||
fs.readFile(file, function(err, data) {
|
||||
if (err) reject(err);
|
||||
parser.write(data);
|
||||
});
|
||||
parser.end();
|
||||
});
|
||||
}
|
||||
|
||||
function workLog(req, res) {
|
||||
var url = require('url'),
|
||||
qs = require('querystring'),
|
||||
http = require('http'),
|
||||
fs = require('fs'),
|
||||
log, lang, json;
|
||||
if (req.method === 'POST') {
|
||||
var urlobj = url.parse(req.body.url),
|
||||
query = qs.parse(urlobj.query);
|
||||
log = query.log;
|
||||
lang = req.body.lang;
|
||||
json = req.body.json;
|
||||
} else if (req.method === 'GET') {
|
||||
log = req.query.log;
|
||||
lang = req.query.lang;
|
||||
json = req.query.json;
|
||||
}
|
||||
lang = (Object.keys(dict).indexOf(lang) >= 0 ? lang : 'en');
|
||||
if (!log) {
|
||||
res.status(200).send('Нужно передать URL на лог игры!!!');
|
||||
} else {
|
||||
var options = {
|
||||
host: 'e.mjv.jp',
|
||||
//host: 'e0.mjv.jp',
|
||||
port: 80,
|
||||
//followAllRedirects: true,
|
||||
path: '/0/log/plainfiles.cgi?' + log
|
||||
//path: '/0/log/?' + log
|
||||
},
|
||||
logfile = __dirname + '/tenhou/' + log + '.xml';
|
||||
if (!fs.existsSync(logfile)) {
|
||||
http.get(options, function(responce) {
|
||||
var body = '';
|
||||
responce.on('data', function(chunk) {
|
||||
body += chunk;
|
||||
});
|
||||
responce.on('end', function() {
|
||||
let fl = fs.openSync(logfile, 'wx');
|
||||
if (fl) {
|
||||
fs.writeSync(fl, body);
|
||||
fs.closeSync(fl);
|
||||
}
|
||||
if (fs.existsSync(logfile)) {
|
||||
parseLog(log, logfile, lang)
|
||||
.then(
|
||||
result =>
|
||||
(json === 1 ?
|
||||
res.status(200).json(result) : res.render('paifu', {
|
||||
data: result,
|
||||
str: dict[lang],
|
||||
lang: lang
|
||||
})),
|
||||
error => res.status(200).send('Error: ' + error)
|
||||
);
|
||||
}
|
||||
}).on('error', function(e) {
|
||||
log.error("Got error: " + e.message);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
parseLog(log, logfile, lang)
|
||||
.then(
|
||||
result => (json == 1 ?
|
||||
res.status(200).json(result) : res.render('paifu', {
|
||||
data: result,
|
||||
str: dict[lang],
|
||||
lang: lang
|
||||
})),
|
||||
//res.status(200).json(result),
|
||||
error => res.status(200).send('Error: ' + error)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.index = function(req, res) {
|
||||
if (!req.query.log) {
|
||||
res.render('index', {
|
||||
error: req.flash('error')
|
||||
});
|
||||
} else {
|
||||
workLog(req, res);
|
||||
}
|
||||
};
|
||||
|
||||
exports.parse = workLog;
|
341
routes/translate.js
Normal file
341
routes/translate.js
Normal file
@ -0,0 +1,341 @@
|
||||
module.exports = {
|
||||
ru: {
|
||||
title: 'Пайфу',
|
||||
link: 'Прямая ссылка на пайфу',
|
||||
player_info: 'Информация об игроках',
|
||||
name: 'Имя',
|
||||
sex: 'Пол',
|
||||
rate: 'Рейтинг',
|
||||
dan: 'Дан',
|
||||
sexF: 'жен.',
|
||||
sexM: 'муж.',
|
||||
sexC: 'комп',
|
||||
sex_: 'неизв.',
|
||||
log: 'Лог',
|
||||
dans: ['10 кю', '9 кю', '8 кю', '7 кю', '6 кю', '5 кю', '4 кю', '3 кю', '2 кю', '1 кю',
|
||||
'1 дан', '2 дан', '3 дан', '4 дан', '5 дан', '6 дан', '7 дан', '8 дан', '9 дан', '10 дан'
|
||||
],
|
||||
rounds: ['東1', '東2', '東3', '東4', '南1', '南2', '南3', '南4',
|
||||
'西1', '西2', '西3', '西4', '北1', '北2', '北3', '北4'
|
||||
],
|
||||
seat: ['東', '南', '西', '北'],
|
||||
round: 'Раунд',
|
||||
honba: 'Хонба',
|
||||
reach: 'Риичи',
|
||||
dora: 'Дора',
|
||||
urador: 'Урадора',
|
||||
start: 'Старт',
|
||||
draw: 'Взято',
|
||||
discard: 'Сброс',
|
||||
final: 'Финал',
|
||||
pon: 'Пон',
|
||||
chi: 'Чи',
|
||||
kan: 'Кан',
|
||||
chakan: 'Кан',
|
||||
nuki: 'Наки',
|
||||
ron: 'Рон',
|
||||
furikomi: 'Оплата',
|
||||
tsumo: 'Цумо',
|
||||
from: {
|
||||
M: 'выиграл с',
|
||||
F: 'выиграла с',
|
||||
C: 'выиграл с'
|
||||
},
|
||||
han: 'хан',
|
||||
fu: 'фу',
|
||||
score: 'Очков',
|
||||
yakulist: 'Список яку',
|
||||
ryuukyoku: {
|
||||
title: "Ничья",
|
||||
tenpai: "Темпай",
|
||||
noten: "Нотен",
|
||||
yao9: "9 терминалов и благородных",
|
||||
reach4: "Четыре риичи",
|
||||
ron3: "Тройной рон",
|
||||
kan4: "Четыре кана",
|
||||
kaze4: "Четыре ветра в сносе",
|
||||
nm: "Нагаши манган"
|
||||
},
|
||||
limits: ['', 'Манган', 'Ханеман', 'Байман', 'Санбайман', 'Якуман'],
|
||||
yaku: ['Мензенцумо',
|
||||
'Риичи',
|
||||
'Иппацу',
|
||||
'Чанкан',
|
||||
'Риншан кайхо',
|
||||
'Хайтей',
|
||||
'Хотей',
|
||||
'Пинфу',
|
||||
'Тан-яо',
|
||||
'Иипейко',
|
||||
'Свой восток',
|
||||
'Свой юг',
|
||||
'Свой запад',
|
||||
'Свой север',
|
||||
'Восток раунда',
|
||||
'Юг раунда',
|
||||
'Запад раунда',
|
||||
'Север раунда',
|
||||
'Белый дракон',
|
||||
'Зеленый дракон',
|
||||
'Красный дракон',
|
||||
'Дабл-риичи',
|
||||
'Чиитойцу',
|
||||
'Чанта',
|
||||
'Иццу',
|
||||
'Саншоку',
|
||||
'Саншоку доко',
|
||||
'Сууканцу',
|
||||
'Тойтой',
|
||||
'Сананко',
|
||||
'Шосанген',
|
||||
'Хонрото',
|
||||
'Рянпейко',
|
||||
'Джунчан',
|
||||
'Хоницу',
|
||||
'Чиницу',
|
||||
'Ренхо',
|
||||
'Тенхо',
|
||||
'Чихо',
|
||||
'Дайсанген',
|
||||
'Сууанко',
|
||||
'Сууанко танки',
|
||||
'Цууисо',
|
||||
'Рюисо',
|
||||
'Чинрото',
|
||||
'Чууренпото',
|
||||
'Чууренпото 9-стор',
|
||||
'Кокушимусо',
|
||||
'Кокушимусо 13-стор',
|
||||
'Дайсууши',
|
||||
'Шосууши',
|
||||
'Санканцу',
|
||||
'Дора',
|
||||
'Урадора',
|
||||
'Акадора'
|
||||
]
|
||||
},
|
||||
en: {
|
||||
title: 'Paifu',
|
||||
link: 'Direct paifu link',
|
||||
player_info: 'Player information',
|
||||
name: 'Name',
|
||||
sex: 'Sex',
|
||||
rate: 'Rating',
|
||||
dan: 'Dan',
|
||||
sexF: 'female',
|
||||
sexM: 'male',
|
||||
sexC: 'comp',
|
||||
sex_: 'NA',
|
||||
log: 'Log',
|
||||
dans: ['10 kyuu', '9 kyuu', '8 kyuu', '7 kyuu', '6 kyuu', '5 kyuu', '4 kyuu', '3 kyuu', '2 kyuu', '1 kyuu',
|
||||
'1 dan', '2 dan', '3 dan', '4 dan', '5 dan', '6 dan', '7 dan', '8 dan', '9 dan', '10 dan'
|
||||
],
|
||||
rounds: ['東1', '東2', '東3', '東4', '南1', '南2', '南3', '南4',
|
||||
'西1', '西2', '西3', '西4', '北1', '北2', '北3', '北4'
|
||||
],
|
||||
seat: ['東', '南', '西', '北'],
|
||||
round: 'Round',
|
||||
honba: 'Combo',
|
||||
reach: 'Reach',
|
||||
dora: 'Dora',
|
||||
urador: 'Uradora',
|
||||
start: 'Start',
|
||||
draw: 'Draw',
|
||||
discard: 'Drop',
|
||||
final: 'Final',
|
||||
pon: 'Pon',
|
||||
chi: 'Chii',
|
||||
kan: 'Kan',
|
||||
chakan: 'Kan',
|
||||
nuki: 'Nuki',
|
||||
ron: 'Ron',
|
||||
furikomi: 'Furikomi',
|
||||
tsumo: 'Tsumo',
|
||||
from: {
|
||||
M: 'win from',
|
||||
F: 'win from',
|
||||
C: 'win from'
|
||||
},
|
||||
han: 'han',
|
||||
fu: 'fu',
|
||||
score: 'Score',
|
||||
yakulist: 'Yaku list',
|
||||
ryuukyoku: {
|
||||
yao9: "9 ends",
|
||||
reach4: "Four riichi",
|
||||
ron3: "Triple ron",
|
||||
kan4: "Four kans",
|
||||
kaze4: "Wind discard",
|
||||
nm: "Nagashi mangan"
|
||||
},
|
||||
limits: ['', 'Mangan', 'haneman', 'baiman', 'sanbaiman', 'yakuman'],
|
||||
yaku: ['Mentsumo',
|
||||
'Riichi',
|
||||
'Ippatsu',
|
||||
'Chankan',
|
||||
'Rinshan kaihou',
|
||||
'Haitei raoyue',
|
||||
'Houtei raoyui',
|
||||
'Pinfu',
|
||||
'Tanyao',
|
||||
'Iipeiko',
|
||||
'Own east',
|
||||
'Own south',
|
||||
'Own west',
|
||||
'Own north',
|
||||
'Round east',
|
||||
'Round south',
|
||||
'Round west',
|
||||
'Round north',
|
||||
'White dragon',
|
||||
'Green dragon',
|
||||
'Red dragon',
|
||||
'Daburu riichi',
|
||||
'Chiitoitsu',
|
||||
'Chanta',
|
||||
'Ittsu',
|
||||
'Sanshoku doujun',
|
||||
'Sanshoku doukou',
|
||||
'Sankantsu',
|
||||
'Toitoi',
|
||||
'Sanankou',
|
||||
'Shousangen',
|
||||
'Honroutou',
|
||||
'Ryanpeikou',
|
||||
'Junchan',
|
||||
'Honitsu',
|
||||
'Chinitsu',
|
||||
'Renhou',
|
||||
'Tenhou',
|
||||
'Chihou',
|
||||
'Daisangen',
|
||||
'Suuankou',
|
||||
'Suuankou tanki',
|
||||
'Tsuuiisou',
|
||||
'Ryuuiisou',
|
||||
'Chinroutou',
|
||||
'Chuuren pouto',
|
||||
'Chuuren pouto 9-wait',
|
||||
'Kokushi musou',
|
||||
'Kokushi musou 13-wait',
|
||||
'Daisuushi',
|
||||
'Shousuushi',
|
||||
'Suukantsu',
|
||||
'Dora',
|
||||
'Uradora',
|
||||
'Akadora'
|
||||
]
|
||||
},
|
||||
jp: {
|
||||
title: 'Paifu',
|
||||
link: 'Direct paifu link',
|
||||
player_info: 'Player information',
|
||||
name: 'Name',
|
||||
sex: 'Sex',
|
||||
rate: 'Rating',
|
||||
dan: 'Dan',
|
||||
sexF: 'famale',
|
||||
sexM: 'male',
|
||||
sexC: 'comp',
|
||||
sex_: 'NA',
|
||||
log: 'Log',
|
||||
dans: ['新人', '9級', '8級', '7級', '6級', '5級', '4級', '3級', '2級', '1級',
|
||||
'初段', '二段', '三段', '四段', '五段', '六段', '七段', '八段', '九段', '十段', '天鳳位'
|
||||
],
|
||||
rounds: ['東1', '東2', '東3', '東4', '南1', '南2', '南3', '南4',
|
||||
'西1', '西2', '西3', '西4', '北1', '北2', '北3', '北4'
|
||||
],
|
||||
seat: ['東', '南', '西', '北'],
|
||||
round: 'Round',
|
||||
honba: 'Combo',
|
||||
reach: 'Reach',
|
||||
dora: 'Dora',
|
||||
urador: 'Uradora',
|
||||
start: 'Start',
|
||||
draw: 'Draw',
|
||||
discard: 'Drop',
|
||||
final: 'Final',
|
||||
pon: 'Pon',
|
||||
chi: 'Chii',
|
||||
kan: 'Kan',
|
||||
chakan: 'Kan',
|
||||
nuki: 'Nuki',
|
||||
ron: 'Ron',
|
||||
furikomi: 'フリコミ',
|
||||
tsumo: 'ツモ',
|
||||
from: {
|
||||
M: 'win from',
|
||||
F: 'win from',
|
||||
C: 'win from'
|
||||
},
|
||||
han: 'han',
|
||||
fu: 'fu',
|
||||
score: 'Score',
|
||||
yakulist: 'Yaku list',
|
||||
ryuukyoku: {
|
||||
yao9: "9 ends",
|
||||
reach4: "Four riichi",
|
||||
ron3: "Triple ron",
|
||||
kan4: "Four kans",
|
||||
kaze4: "Wind discard",
|
||||
nm: "Nagashi mangan"
|
||||
},
|
||||
limits: ['', 'Mangan', 'haneman', 'baiman', 'sanbaiman', 'yakuman'],
|
||||
yaku: ['門前清自摸和',
|
||||
'立直',
|
||||
'一発',
|
||||
'槍槓',
|
||||
'嶺上開花',
|
||||
'海底摸月',
|
||||
'河底撈魚',
|
||||
'平和',
|
||||
'断幺九',
|
||||
'一盃口',
|
||||
'自風 東',
|
||||
'自風 南',
|
||||
'自風 西',
|
||||
'自風 北',
|
||||
'場風 東',
|
||||
'場風 南',
|
||||
'場風 西',
|
||||
'場風 北',
|
||||
'役牌 白',
|
||||
'役牌 發',
|
||||
'役牌 中',
|
||||
'両立直',
|
||||
'七対子',
|
||||
'混全帯幺九',
|
||||
'一気通貫',
|
||||
'三色同順',
|
||||
'三色同刻',
|
||||
'三槓子',
|
||||
'対々和',
|
||||
'三暗刻',
|
||||
'小三元',
|
||||
'混老頭',
|
||||
'二盃口',
|
||||
'純全帯幺九',
|
||||
'混一色',
|
||||
'清一色',
|
||||
'人和',
|
||||
'天和',
|
||||
'地和',
|
||||
'大三元',
|
||||
'四暗刻',
|
||||
'四暗刻単騎',
|
||||
'字一色',
|
||||
'緑一色',
|
||||
'清老頭',
|
||||
'九蓮宝燈',
|
||||
'純正九蓮宝燈',
|
||||
'国士無双',
|
||||
'国士無双13面',
|
||||
'大四喜',
|
||||
'小四喜',
|
||||
'四槓子',
|
||||
'ドラ',
|
||||
'裏ドラ',
|
||||
'赤ドラ]'
|
||||
]
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user