838 lines
31 KiB
JavaScript
Executable File
838 lines
31 KiB
JavaScript
Executable File
DPTW = function(input){
|
||
|
||
const self = this,
|
||
default_settings = {
|
||
object_name : "dptw",
|
||
dptw_autostart : true,
|
||
settings_files : [
|
||
"/json/DPTW.settings.json",
|
||
"/json/DPTW.settings.secrets.json"
|
||
],
|
||
position : "body",
|
||
ajax_timeout : 2000,
|
||
dictionary_file : "/json/DPTW.dictionary.json",
|
||
class : "dptw"
|
||
},
|
||
sprites = {},
|
||
sounds = {},
|
||
images = {};
|
||
let started = false,
|
||
game_working = false,
|
||
game_thread = null,
|
||
difficulty, character_size, last_word_y, velocity, velocity_increment, current_velocity,
|
||
text_box, text_cache = "",
|
||
destruction_animations, destruction_size, destruction_sounds,
|
||
overwrite_sprites, overwrite_sounds,
|
||
scream_sounds, ok_sounds,
|
||
characters_sizer, reduce_life_value, increase_life_value, allow_alter_style, characters_color,
|
||
allow_reduce_score, character_ok_points, character_wrong_points, word_ok_points, word_wrong_points,
|
||
multiplier, allow_points_multiplier,
|
||
zeros_fill_score, allow_pause,
|
||
game_status = "loading",
|
||
font_family, main_background, secondary_background,
|
||
session_time_update, session_last_update = 0,
|
||
sessions_show_update_ok_message,
|
||
sessions_show_update_error_message,
|
||
word_number, word_proportional_timeout, last_word_time, word_enabled_random_timer,
|
||
allow_ignore_case,
|
||
multiplier_value;
|
||
|
||
this.sql_session_errors = [
|
||
"sql_exception",
|
||
"session_string_null",
|
||
"session_empty",
|
||
"session_bad_format",
|
||
"session_id_string_empty",
|
||
"session_id_string_bad",
|
||
"session_string_incompleted",
|
||
"session_null",
|
||
"session_not_id",
|
||
"session_not_exists",
|
||
"session_date_out",
|
||
"session_timeout",
|
||
null
|
||
];
|
||
|
||
let main_menu = self.main_menu;
|
||
|
||
let kanvas = self.kanvas;
|
||
let i18n = this.i18n;
|
||
let errors = this.errors;
|
||
let dictionary = this.dictionary;
|
||
let scores = this.scores;
|
||
|
||
const GAME = 2;
|
||
const MAIN_MENU = 5;
|
||
const FPS = 4;
|
||
const WORDS = 0;
|
||
const SHOTS = 1;
|
||
const DESTRUCTIONS = 2;
|
||
const LIFE = 6;
|
||
const PAUSE = 7;
|
||
const SCORE = this.SCORE = 8;
|
||
|
||
const construct = () => {
|
||
|
||
self.kanvas = kanvas = new Kanvas({
|
||
...default_settings,
|
||
...(typeof input != "object" ? {} : input),
|
||
autostart : false
|
||
});
|
||
|
||
kanvas.extends(self);
|
||
|
||
DPTW.I18N && (i18n = self.i18n = new DPTW.I18N(self, input));
|
||
DPTW.Errors && (errors = self.errors = new DPTW.Errors(self, input));
|
||
DPTW.Dictionary && (dictionary = self.dictionary = new DPTW.Dictionary(self, input));
|
||
DPTW.Scores && (scores = self.scores = new DPTW.Scores(self, input));
|
||
|
||
self.settings("dptw_autostart") && self.start();
|
||
|
||
};
|
||
|
||
this.start = callback => {
|
||
|
||
const end = status => typeof callback == "function" && callback(status);
|
||
|
||
if(started){
|
||
end(false);
|
||
return false;
|
||
};
|
||
started = true;
|
||
|
||
self.load_blocks(
|
||
self.set_array(self.settings("settings_files")),
|
||
json => self.settings_add(json, true),
|
||
() => {
|
||
|
||
difficulty = self.settings("difficulty");
|
||
velocity = self.settings("velocity");
|
||
velocity_increment = self.settings("velocity_increment");
|
||
destruction_size = self.settings("destruction_size");
|
||
overwrite_sprites = self.settings(["overwrite_sprites", "overwrite"]);
|
||
overwrite_sounds = self.settings(["overwrite_sounds", "overwrite"]);
|
||
characters_sizer = self.settings("characters_sizer");
|
||
reduce_life_value = self.settings("reduce_life_value");
|
||
increase_life_value = self.settings("increase_life_value");
|
||
allow_alter_style = self.settings("allow_alter_style");
|
||
characters_color = self.settings("characters_color");
|
||
word_proportional_timeout = self.settings("word_proportional_timeout");
|
||
word_enabled_random_timer = self.settings("word_enabled_random_timer");
|
||
allow_ignore_case = self.settings("allow_ignore_case");
|
||
|
||
allow_reduce_score = self.settings("allow_reduce_score");
|
||
character_ok_points = self.settings("character_ok_points");
|
||
word_ok_points = self.settings("word_wrong_points");
|
||
character_wrong_points = self.settings("character_wrong_points");
|
||
word_wrong_points = self.settings("word_wrong_points");
|
||
allow_points_multiplier = self.settings("allow_points_multiplier");
|
||
zeros_fill_score = self.settings("zeros_fill_score");
|
||
allow_pause = self.settings("allow_pause");
|
||
multiplier_value = self.settings("multiplier_value");
|
||
|
||
font_family = self.settings("font_family");
|
||
main_background = self.settings("main_background");
|
||
secondary_background = self.settings("secondary_background");
|
||
|
||
session_time_update = self.settings("session_time_update");
|
||
sessions_show_update_ok_message = dptw.settings("sessions_show_update_ok_message");
|
||
sessions_show_update_error_message = dptw.settings("sessions_show_update_error_message");
|
||
|
||
i18n.start(status => {
|
||
self.load_sprites(self.settings("sprites_files"), true, () => {
|
||
|
||
const destruction_animations_keys = self.settings("destruction_animations");
|
||
|
||
destruction_animations = [];
|
||
|
||
(
|
||
destruction_animations_keys instanceof Array ? destruction_animations_keys : typeof destruction_animations_keys == "string" ? [destruction_animations_keys] : []
|
||
).forEach(key => sprites[key] && destruction_animations.push({
|
||
sprite : sprites[key].path,
|
||
animation : sprites[key].animation,
|
||
frames_per_second : sprites[key].frames_per_second
|
||
}));
|
||
|
||
self.load_sounds(self.settings("sounds_files"), true, () => {
|
||
|
||
const sets = {
|
||
destruction_sounds : destruction_sounds = [],
|
||
scream_sounds : scream_sounds = [],
|
||
ok_sounds : ok_sounds = []
|
||
};
|
||
|
||
for(const key in sets){
|
||
|
||
const set = self.settings(key);
|
||
|
||
(set instanceof Array ? set : typeof set == "string" ? [set] : []).forEach(subkey => sounds[subkey] && sets[key].push({
|
||
sound : sounds[subkey].path,
|
||
fragments : sounds[subkey].fragments,
|
||
volume : sounds[subkey].volume || 1
|
||
}));
|
||
|
||
};
|
||
|
||
kanvas.start(status => {
|
||
dictionary.start(status => {
|
||
scores.start(status => {
|
||
|
||
builder();
|
||
game_thread = dptw.threads_add(game_thread_method);
|
||
|
||
end(status);
|
||
|
||
});
|
||
});
|
||
});
|
||
});
|
||
});
|
||
});
|
||
},
|
||
0
|
||
);
|
||
|
||
return true;
|
||
};
|
||
|
||
this.load_file = (url, callback) => {
|
||
|
||
let ended = false;
|
||
const ajax = new XMLHttpRequest(),
|
||
end = error_message => {
|
||
if(ended)
|
||
return;
|
||
ended = true;
|
||
callback(ajax.responseText, ajax.status, ajax.readyState, error_message == "OK", error_message);
|
||
},
|
||
date = Date.now(),
|
||
timeout = self.settings(["ajax_timeout", "timeout"]);
|
||
|
||
ajax.open("get", url, true);
|
||
ajax.timeout = timeout;
|
||
ajax.onreadystatechange = () => {
|
||
if(ended)
|
||
return;
|
||
if(ajax.readyState == 4)
|
||
end((ajax.status >= 200 && ajax.status < 300) || [301, 302, 304].includes(ajax.status) ? "OK" : "HTTP_ERROR");
|
||
else if(Date.now() - date > timeout)
|
||
end("FORCED_TIMEOUT");
|
||
};
|
||
ajax.send(null);
|
||
|
||
ajax.onerror = () => end("ERROR");
|
||
ajax.onabort = () => end("ABORTED");
|
||
ajax.ontimeout = () => end("TIMEOUT");
|
||
|
||
return ajax;
|
||
};
|
||
|
||
this.set_array = variable => (
|
||
variable instanceof Array ? variable :
|
||
["string", "object"].includes(typeof variable) ? [variable] :
|
||
[])
|
||
|
||
this.load_blocks = (inputs, fragment_callback, callback, i) => {
|
||
|
||
if(i == inputs.length){
|
||
typeof callback == "function" && callback();
|
||
return;
|
||
};
|
||
|
||
const end = () => self.load_blocks(inputs, fragment_callback, callback, i + 1);
|
||
|
||
if(inputs[i]){
|
||
if(inputs[i] instanceof Array)
|
||
self.load_blocks(inputs[i], fragment_callback, end, 0);
|
||
else if(typeof inputs[i] == "object"){
|
||
fragment_callback(inputs[i]);
|
||
end();
|
||
}else if(typeof inputs[i] == "string"){
|
||
|
||
let json;
|
||
|
||
try{
|
||
json = JSON.parse(inputs[i]);
|
||
}catch(exception){};
|
||
|
||
if(json)
|
||
self.load_blocks(self.set_array(json), fragment_callback, end, 0);
|
||
else
|
||
self.load_file(inputs[i], response => {
|
||
try{
|
||
json = JSON.parse(response);
|
||
}catch(exception){};
|
||
self.load_blocks(self.set_array(json), fragment_callback, end, 0);
|
||
});
|
||
}else
|
||
end();
|
||
}else
|
||
end();
|
||
|
||
};
|
||
|
||
this.load_sprites = (inputs, overwrite, callback) => this.load_blocks(inputs instanceof Array ? inputs : inputs ? [inputs] : [], json => {
|
||
typeof overwrite != "boolean" && (overflow = overwrite_sprites);
|
||
(json.sprites || []).forEach(sprite => {
|
||
if(
|
||
sprite &&
|
||
sprite.enabled &&
|
||
sprite.key
|
||
){
|
||
if(sprite.animation)
|
||
(overwrite || !sprites[sprite.key]) && (sprites[sprite.key] = sprite);
|
||
else
|
||
(overwrite || !images[sprite.key]) && (images[sprite.key] = sprite);
|
||
};
|
||
});
|
||
}, callback, 0);
|
||
|
||
this.load_sounds = (inputs, overwrite, callback) => this.load_blocks(inputs instanceof Array ? inputs : inputs ? [inputs] : [], json => {
|
||
typeof overwrite != "boolean" && (overflow = overwrite_sounds);
|
||
(json.sounds || []).forEach(sound => (
|
||
sound &&
|
||
sound.enabled &&
|
||
sound.key &&
|
||
(overwrite || !sounds[sound.key]) &&
|
||
(sounds[sound.key] = sound)
|
||
));
|
||
}, callback, 0);
|
||
|
||
const create_button = (key, x, y, width, height) => ({
|
||
type : "rectangle",
|
||
x : x,
|
||
y : y,
|
||
width : width || 16,
|
||
height : height || 3,
|
||
background : "rgba(255, 255, 255, .3)",
|
||
on_click : "{object_name}.go_to_" + key,
|
||
childs : [{
|
||
type : "text",
|
||
x : 8,
|
||
y : .5,
|
||
align : "center",
|
||
baseline : "top",
|
||
text : i18n.get(key),
|
||
background : "#FFF",
|
||
size : 2,
|
||
border_width : .05,
|
||
border_color : "#000",
|
||
style : "bold",
|
||
family : font_family,
|
||
shadows : [
|
||
[0, 0, .125, "#000"],
|
||
[0, 0, .25, "#000"],
|
||
[0, 0, .5, "#000"],
|
||
[0, 0, 1, "#000"]
|
||
]
|
||
}]
|
||
});
|
||
|
||
const show_menu = this.show_menu = () => {
|
||
|
||
const half = kanvas.cells / 2,
|
||
menu = {type : "block", x : -half, y : -half, childs : [
|
||
{type : "rectangle", x : 0, y : 0, width : kanvas.cells, height : kanvas.cells, background : "#000", alpha : .7},
|
||
{type : "block", x : half - 8, y : half - 9.5, childs : [{
|
||
type : "text",
|
||
x : 8,
|
||
y : -5,
|
||
align : "center",
|
||
baseline : "top",
|
||
text : i18n.get("test_mode"),
|
||
background : "#FFF",
|
||
size : 4,
|
||
border_width : .05,
|
||
border_color : "#000",
|
||
style : "bold",
|
||
family : font_family,
|
||
shadows : [
|
||
[0, 0, .25, "#000"]
|
||
]
|
||
}]}
|
||
]};
|
||
|
||
game_status = "main_menu";
|
||
|
||
["start", "settings", "scores", "manual", "credits"].forEach((key, i) => menu.childs[1].childs.push(create_button(key, 0, (i * 4) + .5)));
|
||
|
||
kanvas.map[MAIN_MENU] = menu;
|
||
|
||
};
|
||
|
||
const hide_menu = () => kanvas.map[MAIN_MENU] = null;
|
||
|
||
const builder = () => {
|
||
|
||
const half = kanvas.cells / 2,
|
||
margin = kanvas.cells / 8,
|
||
padding = half + margin,
|
||
full_padding = padding * 2,
|
||
margined = half - margin;
|
||
|
||
game_status = "building";
|
||
|
||
errors.build_toast();
|
||
|
||
kanvas.map.push(
|
||
{type : "rectangle", x : -kanvas.cells_x, y : -kanvas.cells_y, width : kanvas.cells_x * 2, height : kanvas.cells_y * 2, background : "#000", childs : images[secondary_background] ? [
|
||
{type : "image", x : 0, y : 0, width : kanvas.cells_x * 2, height : kanvas.cells_y * 2, url : images[secondary_background].path},
|
||
{type : "rectangle", x : 0, y : 0, width : kanvas.cells_x, height : kanvas.cells_y, background : "#000", alpha : .85}
|
||
] : []},
|
||
{type : "cache", name : "main_background_back", x : -padding, y : -padding, width : full_padding, height : full_padding, childs : [
|
||
images[main_background] ? {type : "image", x : -half, y : -half, width : kanvas.cells, height : kanvas.cells, url : images[main_background].path} : null,
|
||
{type : "rectangle", x : -half, y : -half, width : kanvas.cells, height : kanvas.cells, background : "#246", alpha : .5}
|
||
]},
|
||
null,
|
||
{type : "cache", name : "main_background_fore", x : -half, y : -half, width : kanvas.cells, height : kanvas.cells, childs : [
|
||
{type : "rectangle", x : -half, y : -half, width : kanvas.cells, height : margin, background : [0, -half, 0, -margined, [
|
||
[0, "#000"],
|
||
[1, "rgba(0, 0, 0, 0)"]
|
||
]]},
|
||
{type : "rectangle", x : -half, y : -half, width : margin, height : kanvas.cells, background : [-half, 0, -margined, 0, [
|
||
[0, "#000"],
|
||
[1, "rgba(0, 0, 0, 0)"]
|
||
]]},
|
||
{type : "rectangle", x : -half, y : margined, width : kanvas.cells, height : margin, background : [0, half, 0, margined, [
|
||
[0, "#000"],
|
||
[1, "rgba(0, 0, 0, 0)"]
|
||
]]},
|
||
{type : "rectangle", x : margined, y : -half, width : margin, height : kanvas.cells, background : [half, 0, margined, 0, [
|
||
[0, "#000"],
|
||
[1, "rgba(0, 0, 0, 0)"]
|
||
]]},
|
||
{type : "rectangle", x : -half, y : -half, width : kanvas.cells, height : kanvas.cells, border_color : "#147", border_width : .4, shadow : [
|
||
[0, 0, .5, "#28F"]
|
||
]}
|
||
]},
|
||
{type : "text", x : kanvas.cells_x, y : -kanvas.cells_y, align : "right", baseline : "top", text : "0.00", background : "#FFF"},
|
||
null,
|
||
{type : "rectangle", x : -half + 1, y : -half + 1, width : kanvas.cells - 2, height : 1, alpha : .3, border_color : "#000", border_width : .1, background : "#F00", shadow : [
|
||
[0, 0, .1, "#FFF"]
|
||
], childs : [
|
||
{type : "rectangle", x : .1, y : .1, width : kanvas.cells - 2.2, full : kanvas.cells - 2.2, height : .8, background : "#0F0"}
|
||
]},
|
||
null,
|
||
{type : "text", x : kanvas.cells_x, y : kanvas.cells_y, baseline : "bottom", align : "right", text : zeros_fill_score, style : "bold", background : "#FFF", size : 2},
|
||
null
|
||
);
|
||
|
||
show_menu();
|
||
|
||
kanvas.on_screen_change.add(() => {
|
||
with(kanvas.map[0]){
|
||
x = -kanvas.cells_x;
|
||
y = -kanvas.cells_y;
|
||
};
|
||
[kanvas.map[0], kanvas.map[0].childs[0], kanvas.map[0].childs[1]].forEach(level => {
|
||
if(level){
|
||
level.width = kanvas.cells_x * 2;
|
||
level.height = kanvas.cells_y * 2;
|
||
};
|
||
});
|
||
with(kanvas.map[FPS]){
|
||
x = kanvas.cells_x - 1;
|
||
y = -kanvas.cells_y + .3;
|
||
};
|
||
with(kanvas.map[SCORE]){
|
||
x = kanvas.cells_x;
|
||
y = kanvas.cells_y;
|
||
};
|
||
});
|
||
|
||
kanvas.threads_add(() => {
|
||
kanvas.map[FPS].text = kanvas.get_real_fps().toFixed(2);
|
||
});
|
||
|
||
text_box = kanvas.item_self.appendChild(document.createElement("textarea"));
|
||
|
||
["up", "down"].forEach(action => text_box.addEventListener("key" + action, check_characters));
|
||
kanvas.item_self.querySelector(".kanvas-ui").addEventListener("click", set_focus);
|
||
|
||
};
|
||
|
||
this.go_to_start = (item, event) => {
|
||
|
||
hide_menu();
|
||
start_game();
|
||
|
||
};
|
||
|
||
this.go_to_settings = (item, event) => console.log(["settings", item, event]);
|
||
|
||
this.go_to_scores = (item, event) => {
|
||
|
||
kanvas.map[MAIN_MENU] = null;
|
||
scores.build();
|
||
|
||
};
|
||
|
||
this.go_to_manual = (item, event) => window.open("/doc", "_blank");
|
||
|
||
this.go_to_credits = (item, event) => console.log(["credits", item, event]);
|
||
|
||
const start_game = () => {
|
||
|
||
self.map[GAME] = {type : "block", x : -kanvas.cells / 2, y : -kanvas.cells / 2, childs : [
|
||
{type : "block", x : 0, y : 0, childs : []},
|
||
{type : "block", x : 0, y : 0, childs : []},
|
||
{type : "block", x : 0, y : 0, childs : []}
|
||
]};
|
||
|
||
character_size = kanvas.cells / dictionary.maximum_characters,
|
||
last_word_y = kanvas.cells;
|
||
current_velocity = 0 + velocity;
|
||
text_cache = "";
|
||
text_box.value = "";
|
||
self.map[LIFE].childs[0].width = self.map[LIFE].childs[0].full;
|
||
self.map[GAME].childs[WORDS].childs = [];
|
||
kanvas.map[SCORE].text = zeros_fill_score;
|
||
multiplier = 1;
|
||
word_number = 0;
|
||
last_word_time = 0;
|
||
|
||
game_status = "running";
|
||
game_working = true;
|
||
|
||
};
|
||
|
||
const reduce_life = () => {
|
||
if((self.map[LIFE].childs[0].width -= reduce_life_value * difficulty) < 0){
|
||
self.map[LIFE].childs[0].width = 0;
|
||
end_game();
|
||
};
|
||
};
|
||
|
||
const increase_life = () => (
|
||
(self.map[LIFE].childs[0].width += increase_life_value * (1 - difficulty)) > self.map[LIFE].childs[0].full &&
|
||
(self.map[LIFE].childs[0].width = self.map[LIFE].childs[0].full
|
||
));
|
||
|
||
const set_score = points => {
|
||
if(allow_reduce_score || points > 0){
|
||
|
||
const new_points = Number(kanvas.map[SCORE].text) + points;
|
||
|
||
kanvas.map[SCORE].text = (zeros_fill_score + (new_points < 0 ? 0 : new_points)).slice(-zeros_fill_score.length);
|
||
|
||
};
|
||
};
|
||
|
||
const game_thread_method = () => {
|
||
|
||
const date = Date.now();
|
||
|
||
if(date - session_last_update > session_time_update){
|
||
session_last_update = date;
|
||
self.load_file("/api/sessions/update", response => {
|
||
console.log(response);
|
||
|
||
response = JSON.parse(response);
|
||
session_last_update = Date.now();
|
||
|
||
errors.validate(
|
||
response.content.error,
|
||
[].concat(self.sql_session_errors),
|
||
{},
|
||
sessions_show_update_error_message && "session_update_error",
|
||
sessions_show_update_ok_message && "session_update_ok"
|
||
);
|
||
|
||
});
|
||
};
|
||
|
||
if(!game_working)
|
||
return;
|
||
|
||
const real_velocity = (current_velocity += (kanvas.delta_time * velocity_increment * difficulty));
|
||
|
||
if(
|
||
!word_number ||
|
||
(
|
||
word_enabled_random_timer &&
|
||
last_word_y >= character_size && Math.random() * (1 / kanvas.get_real_fps()) < difficulty / 10000
|
||
) ||
|
||
(
|
||
word_proportional_timeout &&
|
||
date - last_word_time > word_proportional_timeout * (1 - (real_velocity / kanvas.cells))
|
||
)
|
||
){
|
||
|
||
let i = 0;
|
||
const l = self.map[GAME].childs[WORDS].childs.length,
|
||
word = dictionary.get_random_word();
|
||
|
||
last_word_y = 0;
|
||
word_number ++;
|
||
last_word_time = date;
|
||
|
||
for(; i < l; i ++)
|
||
if(!self.map[GAME].childs[WORDS].childs[i])
|
||
break;
|
||
|
||
const x = Math.random() * (dictionary.maximum_characters - word.length + 1) >> 0,
|
||
characters = [],
|
||
half = character_size / 2;
|
||
|
||
word.split("").forEach((character, j) => characters.push({
|
||
type : "text",
|
||
x : (character_size * j) + half,
|
||
y : half,
|
||
align : "center",
|
||
baseline : "middle",
|
||
text : character,
|
||
size : character_size * (allow_alter_style ? (1 - characters_sizer) + (Math.random() * characters_sizer) : 1),
|
||
style : allow_alter_style ? Math.random() > .5 ? "bold" : null : "bold",
|
||
background : characters_color || "rgb(" + [0, 0, 0].map(_ => Math.random() * 256 >> 0).join(",") + ")",
|
||
shadow : [
|
||
[0, 0, .5, "#FFF"],
|
||
[0, 0, .35, "#FFF"],
|
||
[0, 0, .2, "#000"]
|
||
]
|
||
}));
|
||
|
||
self.map[GAME].childs[WORDS].childs[i] = {type : "block", x : character_size * x, y : 0, alpha : 0, childs : characters};
|
||
|
||
};
|
||
|
||
last_word_y += real_velocity;
|
||
|
||
self.map[GAME].childs[WORDS].childs.forEach((word, j) => {
|
||
if(word){
|
||
if(word.y > kanvas.cells - character_size){
|
||
word.childs.forEach(character => {
|
||
if(!character)
|
||
return;
|
||
set_destruction(word.x + character.x, word.y);
|
||
play_audios_from(scream_sounds);characters_color
|
||
reduce_life();
|
||
set_score(character_wrong_points);
|
||
});
|
||
self.map[GAME].childs[WORDS].childs[j] = null;
|
||
set_score(word_wrong_points);
|
||
multiplier = 1;
|
||
}else{
|
||
word.alpha != 1 && (word.alpha += real_velocity / 5) > 1 && (word.alpha = 1);
|
||
word.y += real_velocity;
|
||
};
|
||
};
|
||
});
|
||
|
||
};
|
||
|
||
const set_focus = event => text_box.focus();
|
||
|
||
this.go_to_resume = () => self.end_pause();
|
||
|
||
this.go_to_left_match = () => {
|
||
|
||
self.end_pause();
|
||
end_game();
|
||
|
||
};
|
||
|
||
this.start_pause = () => {
|
||
|
||
if(allow_pause && game_status == "running"){
|
||
|
||
const half = kanvas.cells / 2;
|
||
|
||
game_status = "stopped";
|
||
game_working = false;
|
||
|
||
kanvas.map[PAUSE] = {type : "block", x : -half, y : -half, childs : [
|
||
{type : "rectangle", x : 0, y : 0, width : kanvas.cells, height : kanvas.cells, background : "#000", alpha : .7},
|
||
{type : "text", x : half, y : half - 10, baseline : "middle", align : "center", text : i18n.get("paused"), size : 4, style : "bold", shadow : [
|
||
[0, 0, .35, "#BBB"]
|
||
]},
|
||
create_button("resume", half - 8, half - 3),
|
||
create_button("left_match", half - 8, half + 1)
|
||
]}
|
||
|
||
return true;
|
||
};
|
||
|
||
return false;
|
||
};
|
||
|
||
this.end_pause = () => {
|
||
|
||
if(game_status == "stopped"){
|
||
|
||
game_status = "running";
|
||
game_working = true;
|
||
|
||
kanvas.map[PAUSE] = null;
|
||
|
||
return true;
|
||
};
|
||
|
||
return false;
|
||
};
|
||
|
||
const check_characters = event => {
|
||
|
||
if(event.type == "keyup")
|
||
switch(event.keyCode){
|
||
case 27:
|
||
self.start_pause() || self.end_pause();
|
||
default:
|
||
break;
|
||
};
|
||
|
||
if(text_box.value == text_cache)
|
||
return;
|
||
|
||
const last_changed = text_cache.length == text_box.value.length,
|
||
characters = text_box.value.substr(text_cache.length - (last_changed ? 1 : 0)).split("");
|
||
|
||
text_cache = text_box.value;
|
||
|
||
if(game_status != "running")
|
||
return;
|
||
|
||
characters.forEach(own_character => {
|
||
allow_ignore_case && (own_character = own_character.toLowerCase());
|
||
if(!self.map[GAME].childs[WORDS].childs.some((word, i) => {
|
||
|
||
const ok = word && word.childs.some((character, j) => {
|
||
|
||
const ok = character && (allow_ignore_case ? character.text.toLowerCase() : character.text) == own_character;
|
||
|
||
if(ok){
|
||
with(self.map[GAME].childs[WORDS].childs[i].childs[j])
|
||
set_destruction(
|
||
self.map[GAME].childs[WORDS].childs[i].x + x,
|
||
self.map[GAME].childs[WORDS].childs[i].y + y
|
||
);
|
||
self.map[GAME].childs[WORDS].childs[i].childs[j] = null;
|
||
set_score(character_ok_points * (allow_points_multiplier ? multiplier : 1));
|
||
multiplier += multiplier_value;
|
||
};
|
||
|
||
return ok;
|
||
});
|
||
|
||
if(ok && self.map[GAME].childs[WORDS].childs[i].childs.every(character => !character)){
|
||
self.map[GAME].childs[WORDS].childs[i] = null;
|
||
play_audios_from(ok_sounds);
|
||
increase_life();
|
||
set_score(word_ok_points);
|
||
};
|
||
|
||
return ok;
|
||
})){
|
||
if(!['`', '´', '^',, '¨'].includes(own_character)){
|
||
play_audios_from(scream_sounds);
|
||
reduce_life();
|
||
set_score(character_wrong_points);
|
||
multiplier = 1;
|
||
};
|
||
};
|
||
});
|
||
|
||
};
|
||
|
||
const play_audios_from_uri = (uri_data, volume, from, to) => {
|
||
|
||
const audio = new Audio(uri_data);
|
||
|
||
audio.load();
|
||
audio.currentTime = from;
|
||
audio.volume = volume;
|
||
audio.play();
|
||
setTimeout(() => audio.pause(), (to ? to - from : audio.duration) * 1000);
|
||
|
||
};
|
||
|
||
const play_audios_from = set => {
|
||
|
||
const sound = set.length ? set[Math.random() * set.length >> 0] : null,
|
||
[from, to] = sound.fragments ? sound.fragments[Math.random() * sound.fragments.length >> 0] : [0, 0];
|
||
|
||
if(!sound)
|
||
return;
|
||
|
||
if(sound.uri_data){
|
||
play_audios_from_uri(sound.uri_data, sound.volume, from, to);
|
||
return;
|
||
}else if(sound.loading)
|
||
return;
|
||
|
||
const ajax = new XMLHttpRequest();
|
||
|
||
sound.loading = true;
|
||
|
||
ajax.open("get", sound.sound, true);
|
||
ajax.responseType = "blob";
|
||
ajax.onload = () => {
|
||
if(ajax.readyState == 4){
|
||
ajax.loading = false;
|
||
ajax.status == 200 && play_audios_from_uri(sound.uri_data = URL.createObjectURL(ajax.response), sound.volume, from, to);
|
||
};
|
||
};
|
||
ajax.send(null);
|
||
|
||
};
|
||
|
||
const set_destruction = (x, y) => {
|
||
|
||
const i = Math.random() * destruction_animations.length >> 0,
|
||
m = self.map[GAME].childs[DESTRUCTIONS].childs.length,
|
||
half = (character_size / 2) - (destruction_size / 2);
|
||
let thread,
|
||
j = 0,
|
||
k = 0;
|
||
|
||
for(; j < m; j ++)
|
||
if(!self.map[GAME].childs[DESTRUCTIONS].childs[j])
|
||
break;
|
||
|
||
self.map[GAME].childs[DESTRUCTIONS].childs[j] = {
|
||
type : "image",
|
||
x : x + half,
|
||
y : y + half,
|
||
width : destruction_size,
|
||
height : destruction_size,
|
||
cut_x : destruction_animations[i].animation[0][0],
|
||
cut_y : destruction_animations[i].animation[0][1],
|
||
cut_width : destruction_animations[i].animation[0][2],
|
||
cut_height : destruction_animations[i].animation[0][3],
|
||
url : destruction_animations[i].sprite
|
||
};
|
||
|
||
play_audios_from(destruction_sounds);
|
||
|
||
thread = kanvas.threads_add(() => {
|
||
if(k < destruction_animations[i].animation.length){
|
||
|
||
const _k = k >> 0;
|
||
|
||
with(self.map[GAME].childs[DESTRUCTIONS].childs[j]){
|
||
cut_x = destruction_animations[i].animation[_k][0];
|
||
cut_y = destruction_animations[i].animation[_k][1];
|
||
cut_width = destruction_animations[i].animation[_k][2];
|
||
cut_height = destruction_animations[i].animation[_k][3];
|
||
};
|
||
k += destruction_animations[i].frames_per_second / kanvas.get_real_fps();
|
||
|
||
}else{
|
||
kanvas.threads_remove(thread);
|
||
self.map[GAME].childs[DESTRUCTIONS].childs[j] = null;
|
||
};
|
||
});
|
||
|
||
};
|
||
|
||
const end_game = () => {
|
||
|
||
game_status = "ended";
|
||
|
||
game_working = false;
|
||
scores.build_add();
|
||
|
||
};
|
||
|
||
construct();
|
||
|
||
}; |