tetris-fumen
Version:
Fumen parser for tetris
259 lines (258 loc) • 9.23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.decode = exports.extract = exports.Page = void 0;
var inner_field_1 = require("./inner_field");
var buffer_1 = require("./buffer");
var defines_1 = require("./defines");
var action_1 = require("./action");
var comments_1 = require("./comments");
var quiz_1 = require("./quiz");
var field_1 = require("./field");
var Page = /** @class */ (function () {
function Page(index, field, operation, comment, flags, refs) {
this.index = index;
this.operation = operation;
this.comment = comment;
this.flags = flags;
this.refs = refs;
this._field = field.copy();
}
Object.defineProperty(Page.prototype, "field", {
get: function () {
return new field_1.Field(this._field.copy());
},
set: function (field) {
this._field = (0, inner_field_1.createInnerField)(field);
},
enumerable: false,
configurable: true
});
Page.prototype.mino = function () {
return field_1.Mino.from(this.operation);
};
return Page;
}());
exports.Page = Page;
var FieldConstants = {
GarbageLine: 1,
Width: 10,
};
function extract(str) {
var format = function (version, data) {
var trim = data.trim().replace(/[?\s]+/g, '');
return { version: version, data: trim };
};
var data = str;
// url parameters
var paramIndex = data.indexOf('&');
if (0 <= paramIndex) {
data = data.substring(0, paramIndex);
}
// v115@~
{
var match = str.match(/[vmd]115@/);
if (match !== undefined && match !== null && match.index !== undefined) {
var sub = data.substr(match.index + 5);
return format('115', sub);
}
}
// v110@~
{
var match = str.match(/[vmd]110@/);
if (match !== undefined && match !== null && match.index !== undefined) {
var sub = data.substr(match.index + 5);
return format('110', sub);
}
}
throw new Error('Unsupported fumen version');
}
exports.extract = extract;
function decode(fumen) {
var _a = extract(fumen), version = _a.version, data = _a.data;
switch (version) {
case '115':
return innerDecode(data, 23);
case '110':
return innerDecode(data, 21);
}
throw new Error('Unsupported fumen version');
}
exports.decode = decode;
function innerDecode(data, fieldTop) {
var fieldMaxHeight = fieldTop + FieldConstants.GarbageLine;
var numFieldBlocks = fieldMaxHeight * FieldConstants.Width;
var buffer = new buffer_1.Buffer(data);
var updateField = function (prev) {
var result = {
changed: true,
field: prev,
};
var index = 0;
while (index < numFieldBlocks) {
var diffBlock = buffer.poll(2);
var diff = Math.floor(diffBlock / numFieldBlocks);
var numOfBlocks = diffBlock % numFieldBlocks;
if (diff === 8 && numOfBlocks === numFieldBlocks - 1) {
result.changed = false;
}
for (var block = 0; block < numOfBlocks + 1; block += 1) {
var x = index % FieldConstants.Width;
var y = fieldTop - Math.floor(index / FieldConstants.Width) - 1;
result.field.addNumber(x, y, diff - 8);
index += 1;
}
}
return result;
};
var pageIndex = 0;
var prevField = (0, inner_field_1.createNewInnerField)();
var store = {
repeatCount: -1,
refIndex: {
comment: 0,
field: 0,
},
quiz: undefined,
lastCommentText: '',
};
var pages = [];
var actionDecoder = (0, action_1.createActionDecoder)(FieldConstants.Width, fieldTop, FieldConstants.GarbageLine);
var commentDecoder = (0, comments_1.createCommentParser)();
while (!buffer.isEmpty()) {
// Parse field
var currentFieldObj = void 0;
if (0 < store.repeatCount) {
currentFieldObj = {
field: prevField,
changed: false,
};
store.repeatCount -= 1;
}
else {
currentFieldObj = updateField(prevField.copy());
if (!currentFieldObj.changed) {
store.repeatCount = buffer.poll(1);
}
}
// Parse action
var actionValue = buffer.poll(3);
var action = actionDecoder.decode(actionValue);
// Parse comment
var comment = void 0;
if (action.comment) {
// コメントに更新があるとき
var commentValues = [];
var commentLength = buffer.poll(2);
for (var commentCounter = 0; commentCounter < Math.floor((commentLength + 3) / 4); commentCounter += 1) {
var commentValue = buffer.poll(5);
commentValues.push(commentValue);
}
var flatten = '';
for (var _i = 0, commentValues_1 = commentValues; _i < commentValues_1.length; _i++) {
var value = commentValues_1[_i];
flatten += commentDecoder.decode(value);
}
var commentText = unescape(flatten.slice(0, commentLength));
store.lastCommentText = commentText;
comment = { text: commentText };
store.refIndex.comment = pageIndex;
var text = comment.text;
if (quiz_1.Quiz.isQuizComment(text)) {
try {
store.quiz = new quiz_1.Quiz(text);
}
catch (e) {
store.quiz = undefined;
}
}
else {
store.quiz = undefined;
}
}
else if (pageIndex === 0) {
// コメントに更新がないが、先頭のページのとき
comment = { text: '' };
}
else {
// コメントに更新がないとき
comment = {
text: store.quiz !== undefined ? store.quiz.format().toString() : undefined,
ref: store.refIndex.comment,
};
}
// Quiz用の操作を取得し、次ページ開始時点のQuizに1手進める
var quiz = false;
if (store.quiz !== undefined) {
quiz = true;
if (store.quiz.canOperate() && action.lock) {
if ((0, defines_1.isMinoPiece)(action.piece.type)) {
try {
var nextQuiz = store.quiz.nextIfEnd();
var operation = nextQuiz.getOperation(action.piece.type);
store.quiz = nextQuiz.operate(operation);
}
catch (e) {
// console.error(e.message);
// Not operate
store.quiz = store.quiz.format();
}
}
else {
store.quiz = store.quiz.format();
}
}
}
// データ処理用に加工する
var currentPiece = void 0;
if (action.piece.type !== defines_1.Piece.Empty) {
currentPiece = action.piece;
}
// pageの作成
var field = void 0;
if (currentFieldObj.changed || pageIndex === 0) {
// フィールドに変化があったとき
// フィールドに変化がなかったが、先頭のページだったとき
field = {};
store.refIndex.field = pageIndex;
}
else {
// フィールドに変化がないとき
field = { ref: store.refIndex.field };
}
pages.push(new Page(pageIndex, currentFieldObj.field, currentPiece !== undefined ? field_1.Mino.from({
type: (0, defines_1.parsePieceName)(currentPiece.type),
rotation: (0, defines_1.parseRotationName)(currentPiece.rotation),
x: currentPiece.x,
y: currentPiece.y,
}) : undefined, comment.text !== undefined ? comment.text : store.lastCommentText, {
quiz: quiz,
lock: action.lock,
mirror: action.mirror,
colorize: action.colorize,
rise: action.rise,
}, {
field: field.ref,
comment: comment.ref,
}));
// callback(
// currentFieldObj.field.copy()
// , currentPiece
// , store.quiz !== undefined ? store.quiz.format().toString() : store.lastCommentText,
// );
pageIndex += 1;
if (action.lock) {
if ((0, defines_1.isMinoPiece)(action.piece.type)) {
currentFieldObj.field.fill(action.piece);
}
currentFieldObj.field.clearLine();
if (action.rise) {
currentFieldObj.field.riseGarbage();
}
if (action.mirror) {
currentFieldObj.field.mirror();
}
}
prevField = currentFieldObj.field;
}
return pages;
}