First demo

This commit is contained in:
Victor 2015-12-06 13:49:35 +02:00
commit c7539bc0d5
14 changed files with 1338 additions and 0 deletions

View File

@ -0,0 +1,5 @@
file.reference.RpyPlayer-public_html=public_html
file.reference.RpyPlayer-test=test
files.encoding=UTF-8
site.root.folder=${file.reference.RpyPlayer-public_html}
test.folder=${file.reference.RpyPlayer-test}

9
nbproject/project.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.web.clientproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/clientside-project/1">
<name>RpyPlayer</name>
</data>
</configuration>
</project>

32
public_html/index.html Normal file
View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>Everlasting Summer</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="resources/js/jquery-1.11.3.min.js"></script>
<script src="resources/js/Utils.js"></script>
<script src="resources/js/Transitions.js"></script>
<script src="resources/js/Characters.js"></script>
<script src="resources/js/TokenType.js"></script>
<script src="resources/js/Token.js"></script>
<script src="resources/js/Lexer.js"></script>
<script src="resources/js/Parser.js"></script>
<script src="resources/js/Views.js"></script>
<script src="resources/js/Main.js"></script>
<link rel="stylesheet" href="resources/css/style.css">
</head>
<body>
<!-- <div>Everlasting Summer</div>-->
<!--<div id="backgroundBottom">-->
<div id="background">
<div id="container"></div>
<div id="window">
<div id="textAuthor"></div>
<div id="textContent"></div>
</div>
<p id="result"></p>
</div>
<!--</div>-->
</body>
</html>

View File

@ -0,0 +1,54 @@
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
html, body, div, span, p {
margin: 0;
padding: 0;
}
body {
font-family: "Open Sans", sans-serif;
font-size: 18px;
line-height: 1.5;
}
#background {
width: 100%;
height: 100%;
background: black;
overflow: hidden;
position: relative;
background-attachment: fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
#window {
position: absolute;
bottom: 0px;
width: 100%;
min-height: 20%;
background-color: rgba(0, 0, 0, 0.5);
}
#textAuthor {
margin: 5px 0 10px 20px;
color: white;
}
#textContent {
color: #DEC88C;
margin: 0 10px;
}
.sprite {
position: absolute;
bottom: 0px;
}

View File

@ -0,0 +1,101 @@
function NameInfo(name, color) {
this.name = name;
this.color = color;
}
function Characters() {
this.names = {};
}
Characters.prototype.DEFAULT_COLOR = 0xFFC0C0C0;
Characters.prototype.contains = function (shortName) {
return shortName in this.names;
};
Characters.prototype.get = function (shortName) {
return this.names[shortName];
};
Characters.prototype.setName_2 = function (shortName, fullName) {
if (shortName in this.names) {
var info = this.names[shortName];
info.name = fullName;
} else {
this.names[shortName] = new NameInfo(fullName, this.DEFAULT_COLOR);
}
return shortName in this.names;
};
Characters.prototype.setName_3 = function (shortName, fullName, color) {
if (shortName in this.names) {
var info = this.names[shortName];
info.name = fullName;
info.color = color;
} else {
this.names[shortName] = new NameInfo(fullName, color);
}
return shortName in this.names;
};
Characters.prototype.setName = function (arg1, arg2, arg3) {
if (arguments.length === 2) return this.setName_2(arg1, arg2);
else return this.setName_2(arg1, arg2, arg3);
};
Characters.prototype.makeNamesUnknown = function () {
// https://github.com/yakui-lover/eroge-dopil/blob/master/media.rpy#L365
this.names["me"] = new NameInfo("Семён", 0xFFE1DD7D);
this.names["un"] = new NameInfo("Пионерка", 0xFFB956FF);
this.names["dv"] = new NameInfo("Пионерка", 0xFFFFAA00);
this.names["sl"] = new NameInfo("Пионерка", 0xFFFFD200);
this.names["us"] = new NameInfo("Пионерка", 0xFFFF3200);
this.names["mt"] = new NameInfo("Вожатая", 0xFF00EA32);
this.names["cs"] = new NameInfo("Медсестра", 0xFFA5A5FF);
this.names["mz"] = new NameInfo("Пионерка", 0xFF4A86FF);
this.names["mi"] = new NameInfo("Пионерка", 0xFF00DEFF);
this.names["uv"] = new NameInfo("Странная девочка", 0xFF4EFF00);
this.names["lk"] = new NameInfo("Луркмор-кун", 0xFFFF8080);
this.names["sh"] = new NameInfo("Пионер", 0xFFFFF226);
this.names["el"] = new NameInfo("Пионер", 0xFFFFFF00);
this.names["pi"] = new NameInfo("Пионер", 0xFFE60101);
this.names["dy"] = new NameInfo("Голос из динамика", 0xFFC0C0C0);
this.names["voice"] = new NameInfo("Голос", 0xFFE1DD7D);
this.names["voices"] = new NameInfo("Голоса", 0xFFC0C0C0);
this.names["message"] = new NameInfo("Сообщение", 0xFFC0C0C0);
this.names["all"] = new NameInfo("Пионеры", 0xFFED4444);
this.names["kids"] = new NameInfo("Малышня", 0xFFEB7883);
this.names["dreamgirl"] = new NameInfo("...", 0xFFC0C0C0);
this.names["bush"] = new NameInfo("Голос", 0xFFC0C0C0);
this.names["FIXME_voice"] = new NameInfo("Голос", 0xFFC0C0C0);
this.names["odn"] = new NameInfo("Одногруппник", 0xFFC0C0C0);
this.names["mt_voice"] = new NameInfo("Голос", 0xFF00EA32);
};
Characters.prototype.makeNamesKnown = function () {
this.setName("me", "Семён");
this.setName("un", "Лена");
this.setName("dv", "Алиса");
this.setName("sl", "Славя");
this.setName("us", "Ульяна");
this.setName("mt", "Ольга Дмитриевна");
this.setName("cs", "Виола");
this.setName("mz", "Женя");
this.setName("mi", "Мику");
this.setName("uv", "Юля");
this.setName("lk", "Луркмор-кун");
this.setName("sh", "Шурик");
this.setName("el", "Электроник");
this.setName("pi", "Пионер");
this.setName("dy", "Голос из динамика");
this.setName("voice", "Голос");
this.setName("voices", "Голоса");
this.setName("message", "Сообщение");
this.setName("all", "Пионеры");
this.setName("kids", "Малышня");
this.setName("dreamgirl", "...");
this.setName("bush", "Голос");
this.setName("FIXME_voice", "Голос");
this.setName("odn", "Одногруппник");
this.setName("mt_voice", "Голос");
};

View File

@ -0,0 +1,228 @@
/* global TokenType */
function Lexer(input) {
this.input = input;
this.tokens = [];
this.length = input.length;
this.pos = 0;
this.buffer = "";
}
Lexer.prototype.OPERATOR_CHARS = "=+-<>()[]!$:";
Lexer.prototype.OPERATOR_TYPES = [
TokenType.EQ,
TokenType.PLUS, TokenType.MINUS,
TokenType.LT, TokenType.GT,
TokenType.LPAREN, TokenType.RPAREN, TokenType.LBRACKET, TokenType.RBRACKET,
TokenType.EXCL, TokenType.COMMAND, TokenType.COLON
];
Lexer.prototype.KEYWORDS = {
"play" : TokenType.PLAY,
"queue" : TokenType.QUEUE,
"stop" : TokenType.STOP,
"music" : TokenType.MUSIC,
"ambience" : TokenType.AMBIENCE,
"sound" : TokenType.SOUND,
"sound_loop" : TokenType.SOUNDLOOP,
"fadein" : TokenType.FADEIN,
"fadeout" : TokenType.FADEOUT,
"scene" : TokenType.SCENE,
"anim" : TokenType.ANIM,
"bg" : TokenType.BG,
"cg" : TokenType.CG,
"at" : TokenType.AT,
"as" : TokenType.AS,
"define" : TokenType.DEFINE,
"window" : TokenType.WINDOW,
"hide" : TokenType.HIDE,
"show" : TokenType.SHOW,
"with" : TokenType.WITH,
"return" : TokenType.RETURN,
"menu" : TokenType.MENU,
"endmenu" : TokenType.ENDMENU,
"jump" : TokenType.JUMP,
"label" : TokenType.LABEL,
"if" : TokenType.IF,
"else" : TokenType.ELSE,
"endif" : TokenType.ENDIF,
"or" : TokenType.OR,
"and" : TokenType.AND,
"not" : TokenType.NOT,
"renpy.pause" : TokenType.RENPY_PAUSE,
"renpy.say" : TokenType.RENPY_SAY,
"persistent.sprite_time" : TokenType.PERSISTENT_SPRITE_TIME,
"prolog_time" : TokenType.PROLOG_TIME,
"day_time" : TokenType.DAY_TIME,
"sunset_time" : TokenType.SUNSET_TIME,
"night_time" : TokenType.NIGHT_TIME,
"make_names_known" : TokenType.MAKE_NAMES_KNOWN,
"make_names_unknown" : TokenType.MAKE_NAMES_UNKNOWN,
"set_name" : TokenType.SET_NAME,
"meet" : TokenType.SET_NAME,
"disable_all_zones" : TokenType.DISABLE_ALL_ZONES,
"disable_current_zone" : TokenType.DISABLE_CURRENT_ZONE,
"reset_zone" : TokenType.RESET_ZONE,
"set_zone" : TokenType.SET_ZONE,
"show_map" : TokenType.SHOW_MAP
};
Lexer.prototype.getTokens = function () { return this.tokens; };
Lexer.prototype.process = function () {
this.pos = 0;
while (this.pos < this.length) {
this.tokenize();
}
return this;
};
Lexer.prototype.tokenize = function () {
this.skipWhitespaces();
var ch = this.peek(0);
if (ch.match(/[a-z]/i)) {
// Слово (ключевое слово или команда)
this.tokenizeWord();
} else if (ch.match(/[0-9]/i)) {
// Число
this.tokenizeNumber();
} else if (ch === '"' || ch === '\'') {
// Текст в "кавычках" или 'одинарных'
this.tokenizeText(ch);
} else if (ch === '#') {
this.tokenizeComment();
} else {
// Операторы и спецсимволы
this.tokenizeOperator();
}
};
Lexer.prototype.tokenizeWord = function () {
var ch = this.peek(0);
// Строка в юникоде u"текст" или u'текст'
if (ch === 'u') {
var textStartChar = this.peek(1);
if (textStartChar === '"' || textStartChar === '\'') {
this.next(); // u
this.tokenizeText(textStartChar);
return;
}
}
this.clearBuffer();
while (ch.match(/[a-z0-9_\.]/i)) {
this.buffer += (ch);
ch = this.next();
}
var word = this.buffer;
var key = word.toLowerCase();
if (key in this.KEYWORDS) {
this.addToken(this.KEYWORDS[key]);
} else {
this.addToken(TokenType.WORD, word);
}
};
Lexer.prototype.tokenizeNumber = function () {
var ch = this.peek(0);
this.clearBuffer();
var decimal = false;
while (true) {
// Целое или вещественное число.
if (ch === '.') {
// Пропускаем десятичные точки, если они уже были в числе.
if (!decimal) this.buffer += (ch);
decimal = true;
ch = this.next();
continue;
} else if (!ch.match(/[0-9]/i)) {
break;
}
this.buffer += (ch);
ch = this.next();
}
this.addToken(TokenType.NUMBER, this.buffer);
};
Lexer.prototype.tokenizeOperator = function () {
var ch = this.peek(0);
var index = this.OPERATOR_CHARS.indexOf(ch);
if (index !== -1) {
this.addToken(this.OPERATOR_TYPES[index]);
}
this.next();
};
Lexer.prototype.tokenizeText = function (textStartChar) {
this.clearBuffer();
var ch = this.next(); // пропускаем открывающую кавычку
while (true) {
if (ch === textStartChar) break;
if (ch === '\0') break; // не закрыта кавычка, но мы добавим то, что есть
if (ch === '\\') {
ch = this.next();
switch (ch) {
case 'n': ch = next(); this.buffer += ('\n'); continue;
case 't': ch = next(); this.buffer += ('\t'); continue;
default:
if (ch === textStartChar) {
ch = this.next();
this.buffer += ('"');
continue;
}
}
this.buffer += ('\\');
continue;
}
this.buffer += (ch);
ch = this.next();
}
this.next(); // пропускаем закрывающую кавычку
this.addToken(TokenType.TEXT, this.buffer);
};
Lexer.prototype.tokenizeComment = function () {
var ch = this.peek(0);
while ("\n\r\0".indexOf(ch) === -1) {
ch = this.next();
}
};
Lexer.prototype.skipWhitespaces = function () {
var ch = this.peek(0);
while (ch !== '\0' && ch.match(/\s/)) {
ch = this.next();
}
};
Lexer.prototype.addToken_1 = function (type) {
this.addToken_2(type, "");
};
Lexer.prototype.addToken_2 = function (type, text) {
this.tokens.push(new Token(text, type));
};
Lexer.prototype.addToken = function (arg1, arg2) {
if (arguments.length === 1) this.addToken_1(arg1);
else this.addToken_2(arg1, arg2);
};
Lexer.prototype.clearBuffer = function () {
this.buffer = "";
};
Lexer.prototype.next = function () {
this.pos++;
if (this.pos >= this.length) return '\0';
return this.input.charAt(this.pos);
};
Lexer.prototype.peek = function (relativePosition) {
var tempPos = this.pos + relativePosition;
if (tempPos >= this.length) return '\0';
return this.input.charAt(tempPos);
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,397 @@
/* global TokenType, ViewActivity, TextUtils */
function Parser(tokens) {
this.tokens = tokens;
this.tokensCount = tokens.length;
this.position = 0;
this.lastPosition = 0;
this.labels = {};
}
Parser.prototype.EOF = new Token("", TokenType.EOF);
Parser.prototype.getInstance = function () {
return this;
};
Parser.prototype.next = function () {
this.lastPosition = this.position;
var terminal = false;
var counter = 0;
do {
try {
terminal = this.statement();
} catch (re) {
console.log("Parser.next() " + re);
if (this.tokens.length === 0) return;
}
// антизацикливание
counter++;
if (counter >= 1000) {
this.position++;
counter = 0;
}
} while (!terminal);
};
Parser.prototype.findFrom = function(from, which, step) {
var pos = from;
while (true) {
pos += step;
if (pos < 0 || pos >= this.tokensCount) break;
var token = this.tokens[pos];
if (which === token.getType()) return pos;
}
// Возвращаем текущее значение во избежание лишних проверок.
return from;
};
Parser.prototype.statement = function() {
var token = this.get(0);
if (this.match(token, TokenType.COMMAND)) return this.command();
if (this.match(token, TokenType.SCENE)) return this.scene();
if (this.match(token, TokenType.PLAY)) return this.play();
// if (this.match(token, TokenType.QUEUE)) return this.queue();
// if (this.match(token, TokenType.STOP)) return this.stop();
if (this.match(token, TokenType.SHOW)) return this.show();
if (this.match(token, TokenType.HIDE)) return this.hide();
// if (this.match(token, TokenType.JUMP)) return this.jump();
// if (this.match(token, TokenType.IF)) return this.ifStatement();
/*if (this.lookMatch(1, TokenType.COLON)) {
// menu:
if (this.match(token, TokenType.MENU)) return this.menu();
// Остаток от меню выбора. Пропускаем до появления ENDMENU.
if (this.match(token, TokenType.TEXT)) {
if (this.hasEndMenu) this.position += this.skipMenu();
return false;
}
// Остаток от условного выражения. Пропускаем до появления ENDIF.
if (this.match(token, TokenType.ELSE)) {
if (this.hasEndIf) this.position += this.skipIf();
return false;
}
}*/
// Текст с именем автора реплики.
if (this.lookMatch(1, TokenType.TEXT) && this.match(token, TokenType.WORD)) {
var whoid = token.getText();
ViewActivity.getInstance().text(whoid, this.consume(TokenType.TEXT).getText());
return true;
}
// Обычный текст.
if (this.match(token, TokenType.TEXT)) {
ViewActivity.getInstance().text(token.getText());
return true;
}
if (this.match(token, TokenType.EOF)) {
//ViewActivity.getInstance().finish();
return true;
}
if (this.match(token, TokenType.WINDOW)) {
if (this.match(TokenType.SHOW))
return ViewActivity.getInstance().windowShow(this.matchWithEffect());
else if (this.match(TokenType.HIDE))
return ViewActivity.getInstance().windowHide(this.matchWithEffect());
return false;
}
if (!TextUtils.isEmpty(this.matchWithEffect())) return false;
this.position++;
return false;
};
Parser.prototype.command = function() {
var token = this.get(0);
if (this.match(token, TokenType.RENPY_PAUSE)) {
this.consume(TokenType.LPAREN);
var pause = this.consumeDouble();
var hard = false;
if (!this.lookMatch(0, TokenType.RPAREN)) {
this.consume(TokenType.WORD); // hard
this.consume(TokenType.EQ);
hard = this.consumeBoolean();
}
this.consume(TokenType.RPAREN);
ViewActivity.getInstance().pause(Math.floor(1000 * pause), hard);
return true;
}
if (this.match(token, TokenType.RENPY_SAY)) {
this.consume(TokenType.LPAREN);
var whoid = this.consume(TokenType.WORD).getText();
// TODO: this.consume(TokenType.COMMA)
var text = this.consume(TokenType.TEXT).getText();
// TODO: this.consume(TokenType.COMMA)
this.consume(TokenType.WORD); // interact
this.consume(TokenType.EQ);
var interact = this.consumeBoolean();
this.consume(TokenType.RPAREN);
ViewActivity.getInstance().text(whoid, text);
return interact;
}
if (this.match(token, TokenType.PERSISTENT_SPRITE_TIME)) {
this.consume(TokenType.EQ);
this.consume(TokenType.TEXT);
return false;
}
if (this.match(token, TokenType.PROLOG_TIME) ||
this.match(token, TokenType.DAY_TIME) ||
this.match(token, TokenType.SUNSET_TIME) ||
this.match(token, TokenType.NIGHT_TIME)) {
this.consume(TokenType.LPAREN);
this.consume(TokenType.RPAREN);
return false;
}
if (this.match(token, TokenType.MAKE_NAMES_KNOWN) ||
this.match(token, TokenType.MAKE_NAMES_UNKNOWN)) {
this.consume(TokenType.LPAREN);
this.consume(TokenType.RPAREN);
if (token.getType() === TokenType.MAKE_NAMES_KNOWN) {
ViewActivity.getInstance().makeNamesKnown();
} else ViewActivity.getInstance().makeNamesUnknown();
return false;
}
if (this.match(token, TokenType.SET_NAME)) {
this.consume(TokenType.LPAREN);
var whoid = this.consume(TokenType.TEXT).getText();
// TODO: this.consume(TokenType.COMMA)
var name = this.consume(TokenType.TEXT).getText();
this.consume(TokenType.RPAREN);
ViewActivity.getInstance().meet(whoid, name);
return false;
}
// Карта
if (this.match(token, TokenType.DISABLE_ALL_ZONES)) {
this.consume(TokenType.LPAREN);
this.consume(TokenType.RPAREN);
ViewActivity.getInstance().disableAllZones();
return false;
}
if (this.match(token, TokenType.DISABLE_CURRENT_ZONE)) {
this.consume(TokenType.LPAREN);
this.consume(TokenType.RPAREN);
ViewActivity.getInstance().disableCurrentZone();
return false;
}
if (this.match(token, TokenType.RESET_ZONE)) {
this.consume(TokenType.LPAREN);
var zone = this.consume(TokenType.TEXT).getText();
this.consume(TokenType.RPAREN);
ViewActivity.getInstance().resetZone(zone);
return false;
}
if (this.match(token, TokenType.SET_ZONE)) {
this.consume(TokenType.LPAREN);
var zone = this.consume(TokenType.TEXT).getText();
// TODO: this.consume(TokenType.COMMA)
var label = this.consume(TokenType.TEXT).getText();
this.consume(TokenType.RPAREN);
ViewActivity.getInstance().setZone(zone, label);
return false;
}
if (this.match(token, TokenType.SHOW_MAP)) {
this.consume(TokenType.LPAREN);
this.consume(TokenType.RPAREN);
ViewActivity.getInstance().showMap();
return true;
}
/*if (this.match(token, TokenType.WORD)) {
if (this.match(TokenType.EQ)) {
// variable = expression
Variables.setVariable(token.getText(), expression().eval());
return false;
}
if (this.lookMatch(1, TokenType.EQ) && this.match(TokenType.PLUS)) {
// variable += expression
this.consume(TokenType.EQ);
var varValue = Variables.getVariable(token.getText());
Variables.setVariable(token.getText(), varValue + expression().eval());
return false;
}
if (this.lookMatch(1, TokenType.EQ) && this.match(TokenType.MINUS)) {
// variable -= expression
this.consume(TokenType.EQ);
var varValue = Variables.getVariable(token.getText());
Variables.setVariable(token.getText(), varValue - expression().eval());
return false;
}
}*/
return false;
};
Parser.prototype.scene = function() {
var type = "";
if (this.match(TokenType.BG)) type = "bg";
else if (this.match(TokenType.CG)) type = "cg";
else if (this.match(TokenType.ANIM)) type = "anim";
var name = this.consume(TokenType.WORD).getText();
var effect = this.matchWithEffect();
ViewActivity.getInstance().background(type, name, effect);
return true;
};
Parser.prototype.show = function() {
var whoid = this.consume(TokenType.WORD).getText();
var params = ""; // emotion? cloth? distance?
while (this.lookMatch(0, TokenType.WORD)) {
var text = this.consume(TokenType.WORD).getText();
params += text;
if (text.equals("close") || text.equals("far")) break;
}
// Положение (left, cleft, ...)
var position = "";
if (this.match(TokenType.AT)) {
position = this.consume(TokenType.WORD).getText();
}
// Псевдоним (для показа одно и того же спрайта в разных местах)
var alias = "";
if (this.match(TokenType.AS)) {
alias = this.consume(TokenType.WORD).getText();
}
var effect = this.matchWithEffect();
ViewActivity.getInstance().sprite(whoid, params, position, alias, effect);
return false;
};
Parser.prototype.hide = function() {
var whoid = this.consume(TokenType.WORD).getText();
var effect = this.matchWithEffect();
ViewActivity.getInstance().hideSprite(whoid, effect);
return false;
};
Parser.prototype.play = function() {
if (this.match(TokenType.MUSIC)) return this.playMusic();
if (this.match(TokenType.AMBIENCE)) return this.playAmbience();
if (this.lookMatch(0, TokenType.SOUND) || this.lookMatch(0, TokenType.SOUNDLOOP)) {
return this.playSound();
}
return false;
};
Parser.prototype.playMusic = function() {
var name = this.consumeMusicName();
var fade = this.matchFade();
ViewActivity.getInstance().music(name, fade);
return false;
};
Parser.prototype.playSound = function() {
var loop = false;
if (this.match(TokenType.SOUND)) loop = false;
else if (this.match(TokenType.SOUNDLOOP)) loop = true;
var name = this.consumeMusicName();
var fade = this.matchFade();
ViewActivity.getInstance().sound(name, loop, fade);
return false;
};
Parser.prototype.playAmbience = function() {
var name = this.consumeMusicName();
var fade = this.matchFade();
return false;
};
Parser.prototype.consumeMusicName = function() {
var name = "";
if (this.lookMatch(1, TokenType.LBRACKET)) {
// music_list["music"]
this.consume(TokenType.WORD);
this.consume(TokenType.LBRACKET);
name = this.consume(TokenType.TEXT).getText();
this.consume(TokenType.RBRACKET);
} else if (this.lookMatch(0, TokenType.TEXT)) {
name = this.consume(TokenType.TEXT).getText();
} else {
name = this.consume(TokenType.WORD).getText();
}
return name;
};
Parser.prototype.matchFade = function() {
var result = new FadeInfo();
if (this.match(TokenType.FADEIN)) {
result.fadeIn = true;
result.duration = this.consumeDouble();
} else if (this.match(TokenType.FADEOUT)) {
result.fadeOut = true;
result.duration = this.consumeDouble();
}
return result;
};
Parser.prototype.matchWithEffect = function() {
if (this.match(TokenType.WITH)) {
return this.consume(TokenType.WORD).getText();
}
return "";
};
Parser.prototype.consumeDouble = function() {
return parseFloat(this.consume(TokenType.NUMBER).getText());
};
Parser.prototype.consumeBoolean = function() {
return "true" === (this.consume(TokenType.NUMBER).getText().toLowerCase());
};
Parser.prototype.matchWithEffect = function() {
if (this.match(TokenType.WITH)) {
return this.consume(TokenType.WORD).getText();
}
return "";
};
Parser.prototype.match_1 = function(type) {
if (this.get(0).getType() !== type) return false;
this.position++;
return true;
};
Parser.prototype.match_2 = function(token, type) {
if (type !== token.getType()) return false;
this.position++;
return true;
};
Parser.prototype.match = function(arg1, arg2) {
if (arguments.length === 1) return this.match_1(arg1);
else return this.match_2(arg1, arg2);
};
Parser.prototype.consume = function(type) {
if (this.get(0).getType() !== type) throw "Ожидался токен " + type + ".";
return this.tokens[this.position++];
};
Parser.prototype.lookMatch = function(pos, type) {
return (type === this.get(pos).getType());
};
Parser.prototype.get = function(offset) {
if (this.position + offset >= this.tokensCount) return this.EOF;
return this.tokens[this.position + offset];
};

View File

@ -0,0 +1,12 @@
function Token(text, type) {
this.text = text;
this.type = type;
}
Token.prototype.getText = function () { return this.text; };
Token.prototype.getType = function () { return this.type; };
Token.prototype.toString = function () {
return this.type + " " + this.text;
};

View File

@ -0,0 +1,76 @@
TokenType = {
COMMAND : 1, // начинается с $
WORD : 2,
TEXT : 3,
NUMBER : 4,
// операторы и спецсимволы
EQ : 5,
PLUS : 6,
MINUS : 7,
LT : 8,
GT : 9,
LPAREN : 10,
RPAREN : 11,
LBRACKET : 12,
RBRACKET : 13,
EXCL : 14,
COLON : 15,
// ключевые слова
PLAY : 16,
QUEUE : 17,
STOP : 18,
MUSIC : 19,
AMBIENCE : 20,
SOUND : 21,
SOUNDLOOP : 22,
FADEIN : 23,
FADEOUT : 24,
SCENE : 25,
ANIM : 26,
BG : 27,
CG : 28,
WINDOW : 29,
HIDE : 30,
SHOW : 31,
AT : 32,
AS : 33,
WITH : 34,
DEFINE : 35,
MENU : 36,
ENDMENU : 37,
JUMP : 38,
LABEL : 39,
RETURN : 40,
IF : 41,
ELSE : 42,
ENDIF : 43,
OR : 44,
AND : 45,
NOT : 46,
// команды
RENPY_PAUSE : 47,
RENPY_SAY : 48,
PERSISTENT_SPRITE_TIME : 49,
PROLOG_TIME : 50,
DAY_TIME : 51,
SUNSET_TIME : 52,
NIGHT_TIME : 53,
MAKE_NAMES_KNOWN : 54,
MAKE_NAMES_UNKNOWN : 55,
SET_NAME : 56,
DISABLE_ALL_ZONES : 57,
DISABLE_CURRENT_ZONE : 58,
RESET_ZONE : 59,
SET_ZONE : 60,
SHOW_MAP : 61,
EOF : 63
};

View File

@ -0,0 +1,46 @@
function Transition(type) {
this.type = type;
};
Transition.prototype.TYPE_FADE = 0;
Transition.prototype.TYPE_DISSOLVE = 1;
var transitions = {
"fade": {
"type": Transition.TYPE_FADE,
"outTime": 500,
"holdTime": 0,
"inTime": 500
},
"fade2": {
"type": Transition.TYPE_FADE,
"outTime": 1000,
"holdTime": 0,
"inTime": 1000
},
"fade3": {
"type": Transition.TYPE_FADE,
"outTime": 1500,
"holdTime": 0,
"inTime": 1500
},
"dspr": {
"type": Transition.TYPE_FADE,
"outTime": 200,
"holdTime": 0,
"inTime": 200
},
"dissolve": {
"type": Transition.TYPE_FADE,
"outTime": 1000,
"holdTime": 0,
"inTime": 1000
},
"dissolve2": {
"type": Transition.TYPE_FADE,
"outTime": 2000,
"holdTime": 0,
"inTime": 2000
}
};

View File

@ -0,0 +1,73 @@
function FadeInfo() {
this.fadeIn = false;
this.fadeOut = false;
this.duration = 0;
}
function TextUtilsImpl() { }
TextUtilsImpl.prototype.isEmpty = function (text) {
if (text === undefined) return true;
return text.length === 0;
};
var TextUtils = new TextUtilsImpl();
String.prototype.equalsIgnoreCase = function(text) {
return this.toLowerCase() == text.toLowerCase();
};
String.prototype.equals = function(text) {
return this == text;
};
String.prototype.contains = function(text) {
return this.indexOf(text) >= 0;
};
/*String.prototype.startsWith = function(text) {
return this.indexOf(text) == 0;
};*/
String.prototype.replaceAll = function (find, replace) {
var str = this;
return str.replace(new RegExp(find, 'g'), replace);
};
function toColor(num) {
num >>>= 0;
var b = num & 0xFF,
g = (num & 0xFF00) >>> 8,
r = (num & 0xFF0000) >>> 16,
a = ( (num & 0xFF000000) >>> 24 ) / 255 ;
return "rgba(" + [r, g, b, a].join(",") + ")";
}
var PathResolver = new function () {
this.background = function (type, name) {
return "resources/images/" + type.toLowerCase() + "/" + name + ".jpg";
};
this.sprite = function (whoid, params) {
var path = "file:///E:/everlastingsummer/sprites/";
path += whoid.toLowerCase() + "/";
path += (TextUtils.isEmpty(params) ? "normal" : params);
path += ".png";
return path;
};
this.music = function (name) {
// return "resources/music/" + name + ".ogg";
return "file:///E:/everlastingsummer/music/" + name + ".ogg";
};
this.sound = function (name) {
var path = "file:///E:/everlastingsummer/sfx/";
if (path.startsWith("sfx_")) path += name.substring(4);
else path += name;
path += ".ogg";
return path;
// return "resources/music/" + name + ".ogg";
};
};

View File

@ -0,0 +1,272 @@
/* global TextUtils, PathResolver, ViewActivity, transitions, Transition */
function Views(parser) {
this.parser = parser;
this.screenWidth = window.innerWidth;
this.screenHeight = window.innerHeight;
this.backgroundTag = document.getElementById("background");
this.windowTag = document.getElementById("window");
this.textAuthorTag = document.getElementById("textAuthor");
this.textContentTag = document.getElementById("textContent");
this.musicPlayerAudio = new Audio();
this.soundPlayerAudio = new Audio();
this.backgroundName = "";
this.backgroundType = "";
this.characters = new Characters();
this.characters.makeNamesKnown();
this.useSpriteTransitions = true;
this.spriteInContainer = {};
this.blockTap = false;
this.cancelNextStep = false;
this.nextCommandRunnable = function () {
Views.blockTap = false;
if (!Views.cancelNextStep) parser.next();
};
}
Views.prototype.getInstance = function () {
return this;
};
Views.prototype.onTouch = function (e) {
if (this.blockTap) return;
this.cancelNextStep = true;
this.parser.next();
};
Views.prototype.windowShow = function (effect) {
if (this.windowTag.style.visibility !== "visible") {
this.windowTag.style.visibility = "visible";
}
if (!TextUtils.isEmpty(effect)) {
this.background(this.backgroundType, this.backgroundName, effect);
return true;
}
return false;
};
Views.prototype.windowHide = function (effect) {
if (this.windowTag.style.visibility !== "hidden") {
this.windowTag.style.visibility = "hidden";
}
if (!TextUtils.isEmpty(effect)) {
this.background(this.backgroundType, this.backgroundName, effect);
return true;
}
return false;
};
Views.prototype.windowSwitchVisibility = function () {
if (this.windowTag.style.visibility === "hidden") {
this.windowTag.style.visibility = "visible";
} else {
this.windowTag.style.visibility = "hidden";
}
};
Views.prototype.background = function (type, name, effect) {
if (TextUtils.isEmpty(name)) return;
this.backgroundType = type;
this.backgroundName = name;
this.text("");
var animationTime = 0;
if (name.equalsIgnoreCase("black")) {
this.backgroundTag.style.background = "black";
} else if (name.equalsIgnoreCase("white")) {
this.backgroundTag.style.background = "white";
} else {
this.backgroundTag.style.background = 'url("' + PathResolver.background(type, name) + '") no-repeat center center fixed';
this.backgroundTag.style.backgroundSize = 'cover';
}
this.pause(animationTime, false);
};
Views.prototype.spritesClear = function () {
$('#container').empty();
this.spriteInContainer = {};
};
Views.prototype.sprite = function (whoid, params, position, alias, effect) {
var img = undefined;
var key = TextUtils.isEmpty(alias) ? whoid : alias;
if (key in this.spriteInContainer) {
img = this.spriteInContainer[key];
} else {
//if (this.useSpriteTransitions) img = new AnimatableImageView(this);
//else img = new ImageView(this);
img = $('<img>', {class: "sprite", style: "height: " + this.screenHeight + "px;" });
this.spriteInContainer[key] = img;
}
var path = PathResolver.sprite(whoid, params);
try {
//if (useSpriteTransitions) ((AnimatableImageView)img).setImageBitmap(bitmap, effect);
//else img.setImageBitmap(bitmap);
img.one("load", function() {
ViewActivity.getInstance().setSpritePosition($(this), position);
});
img.attr('src', path);
if (!$.contains($('#container'), img))
$('#container').append(img);
if (effect in transitions) {
var transition = transitions[effect];
if (transition["type"] === Transition.TYPE_FADE) {
img.hide().fadeIn(transition["inTime"]);
}
}
} catch (ioe) {
console.log("sprite: " + path, ioe);
//if (Logger.DEBUG) Logger.log("sprite: " + path, ioe);
}
};
Views.prototype.hideSprite = function (whoid, effect) {
if (!(whoid in this.spriteInContainer)) return;
this.hide(whoid, effect);
};
Views.prototype.hide = function (whoid, effect) {
var img = this.spriteInContainer[whoid];
if (img == null) return;
if (effect in transitions) {
var transition = transitions[effect];
if (transition["type"] === Transition.TYPE_FADE) {
img.fadeOut(transition["outTime"], function() {
$(this).remove();
});
}
} else {
img.remove();
}
delete this.spriteInContainer[whoid];
};
Views.prototype.setSpritePosition = function (img, position) {
var width = this.screenWidth;
var imgWidth = img.width();
if (TextUtils.isEmpty(position) || position.equals("center")) {
img.css("left", Math.floor(width / 2 - imgWidth / 2) + "px");
} else if (position.equals("left")) {
img.css("left", Math.floor(imgWidth / 6) + "px");
} else if (position.equals("cleft")) {
img.css("left", Math.floor(width / 2 - imgWidth + imgWidth / 8) + "px");
} else if (position.equals("right")) {
img.css("right", Math.floor(imgWidth / 6) + "px");
} else if (position.equals("cright")) {
img.css("right", Math.floor(width / 2 - imgWidth + imgWidth / 8) + "px");
} else if (position.equals("fleft")) {
img.css("left", Math.floor(-imgWidth / 4) + "px");
} else if (position.equals("fright")) {
img.css("right", Math.floor(-imgWidth / 4) + "px");
}
};
Views.prototype.pause = function (duration, hard) {
this.blockTap = hard;
this.cancelNextStep = false;
/* var now = new Date().getTime();
while(new Date().getTime() < now + sleepDuration){ ; } */
setTimeout(this.nextCommandRunnable, duration);
};
Views.prototype.text_1 = function (text) {
this.textAuthorTag.innerText = "";
if (TextUtils.isEmpty(text)) this.windowHide("");
else {
this.windowShow("");
this.formatString(this.textContentTag, text);
}
};
Views.prototype.text_2 = function (whoid, text) {
if (whoid.equalsIgnoreCase("th")) this.text("~ " + text + " ~");
else if (!this.characters.contains(whoid)) this.text(text);
else {
this.windowShow("");
var person = this.characters.get(whoid);
this.textAuthorTag.innerText = person.name;
this.textAuthorTag.style.color = toColor(person.color);
this.formatString(this.textContentTag, text);
}
};
Views.prototype.text = function (arg1, arg2) {
if (arguments.length === 1) this.text_1(arg1);
else this.text_2(arg1, arg2);
};
Views.prototype.formatString = function (tag, text) {
var edited = text.replaceAll("\\{w.*?\\}", "");
if (edited.contains("{center}")) {
edited = text.replaceAll("\\{center\\}", "");
this.textContentTag.style.textAlign = "center";
} else {
this.textContentTag.style.textAlign = "left";
}
if (edited.contains("{html}")) {
edited = edited.replaceAll("\\{html\\}", "");
return edited;
}
var codes = ["b","i","s","u","big","small"];
var html = false;
for (var i = 0; i < codes.length; i++) {
var ch = codes[i];
if (edited.contains("{"+ch+"}")) {
edited = edited.replace("{"+ch+"}", "<"+ch+">");
edited = edited.replace("{/"+ch+"}", "</"+ch+">");
html = true;
}
}
if (html) {
edited = edited.replace("\n", "<br/>");
tag.innerHtml = edited;
} else {
tag.innerText = edited;
}
};
Views.prototype.makeNamesKnown = function () {
this.characters.makeNamesKnown();
};
Views.prototype.makeNamesUnknown = function () {
this.characters.makeNamesUnknown();
};
Views.prototype.meet = function (whoid, name) {
this.characters.setName(whoid, name);
};
Views.prototype.disableAllZones = function () {
};
Views.prototype.disableCurrentZone = function () {
};
Views.prototype.resetZone = function (zone) {
};
Views.prototype.setZone = function (name, label) {
};
Views.prototype.showMap = function () {
};
Views.prototype.menu = function (menu) {
};
Views.prototype.music = function (name, fade) {
// !musicPlayerAudio.paused;
this.musicPlayerAudio.src = PathResolver.music(name);
this.musicPlayerAudio.play();
if (fade.fadeIn || fade.fadeOut) {
var startVolume = fade.fadeIn ? 0.0 : 1.0;
$(this.musicPlayerAudio).prop("volume", startVolume);
var targetVolume = fade.fadeIn ? 1.0 : 0.0;
$(this.musicPlayerAudio).animate({volume: targetVolume}, fade.duration * 1000);
}
};

File diff suppressed because one or more lines are too long