"Canasta Opening" - карточная игра на Point JS
Участников: 5
Страница 3 из 6
Страница 3 из 6 • 1, 2, 3, 4, 5, 6
Re: "Canasta Opening" - карточная игра на Point JS
Вообще начнем с того, какие есть объекты с общим поведением. Например, есть "рука"? Это массив карт у каждого игрока. Все карты в "руке" обладают одинаковым набором состояний.
Есть общая колода на столе? Типа куда сбрасывают карты как в дураке или козле?
Есть колода для сброса? Это карты, которые уже свое отыграли и больше никак в игре не участвуют?
Есть общая колода, из которой берут карты?
Какие еще объекты с уникальными состояниями (характеристиками)? Где и как они располагаются? Когда появляются и когда исчезают. Нарисуй схематичный рисунок, где что находится. Это поможет визуальному пониманию механики игры.
Есть общая колода на столе? Типа куда сбрасывают карты как в дураке или козле?
Есть колода для сброса? Это карты, которые уже свое отыграли и больше никак в игре не участвуют?
Есть общая колода, из которой берут карты?
Какие еще объекты с уникальными состояниями (характеристиками)? Где и как они располагаются? Когда появляются и когда исчезают. Нарисуй схематичный рисунок, где что находится. Это поможет визуальному пониманию механики игры.
raingo- Отдел прокрастинации
- Сообщения : 756
Дата регистрации : 2017-12-25
Re: "Canasta Opening" - карточная игра на Point JS
http://www.gamedev.ru/code/articles/finite_state_machine - вот годная статья
raingo- Отдел прокрастинации
- Сообщения : 756
Дата регистрации : 2017-12-25
Re: "Canasta Opening" - карточная игра на Point JS
Raingo, привет. Вот всё разбил на зоны.
Zona A, Zona B - карты игроков (A - компьютер, B - игрок)
Zona C, там где "0" - это "колода для сноса карт",
Zona D - "закрытая колода" - колода из которой карты берут игроки по очереди и из которой в начале каждой партии раздаётся в открытую по 9 карт каждому игроку.
Zona E - зона для выкладки комбинаций из карт компьютера,
Zona F - зона для выкладки комбинаций из карт игрока.
В зонах E и F - комбинации выкладываются в вертикальном порядке
В этой игре участвуют все карты. Ещё дополнение - у игрока, когда он берёт карту из "закрытой колоды" = 10 карт, так же в 1 ходе и у компьютера. Когда игрок "заваливает" "колоду для сноса" - у него может быть иногда больше 20-ти карт в руке.
Zona A, Zona B - карты игроков (A - компьютер, B - игрок)
Zona C, там где "0" - это "колода для сноса карт",
Zona D - "закрытая колода" - колода из которой карты берут игроки по очереди и из которой в начале каждой партии раздаётся в открытую по 9 карт каждому игроку.
Zona E - зона для выкладки комбинаций из карт компьютера,
Zona F - зона для выкладки комбинаций из карт игрока.
В зонах E и F - комбинации выкладываются в вертикальном порядке
В этой игре участвуют все карты. Ещё дополнение - у игрока, когда он берёт карту из "закрытой колоды" = 10 карт, так же в 1 ходе и у компьютера. Когда игрок "заваливает" "колоду для сноса" - у него может быть иногда больше 20-ти карт в руке.
AlexeyOK- Сообщения : 50
Дата регистрации : 2018-01-08
Re: "Canasta Opening" - карточная игра на Point JS
вот это я вообще не пойму. это типа "отбой" или что? это типа после выкладки комбинаций туда убираются выложенные карты и больше не используются? или как?колода для сноса карт
одновременно можно выкладывать по нескольку комбинаций?В зонах E и F - комбинации выкладываются в вертикальном порядке
что это значит?Когда игрок "заваливает" "колоду для сноса" -
тебе бы стоило подумать о кнопках интерфейса: "завершить ход" там например или какие там кнопки еще должны быть
Re: "Canasta Opening" - карточная игра на Point JS
так ну вроде почитал первый твой пост - слегка понял, что к чему, но не совсем.
1) в "колоду для сноса" карты кладутся лицом вверх или рубашкой?
2) после завершения хода, выложенные комбинации убираются и эти карты больше не участвуют в игре?
1) в "колоду для сноса" карты кладутся лицом вверх или рубашкой?
2) после завершения хода, выложенные комбинации убираются и эти карты больше не участвуют в игре?
Re: "Canasta Opening" - карточная игра на Point JS
ну вобщем вот. https://pyro338.ru/CanastaPJS/
- Код:
<script type="text/javascript">
var pjs = new PointJS(1280, 1024, {backgroundColor: "GREEN"})
var game = pjs.game;
var system = pjs.system;
var mouse = pjs.mouseControl.initMouseControl();
var brush = pjs.brush;
var width = pjs.game.getWH().w; //получаем ширину игровой области
var height = pjs.game.getWH().h; //получаем высоту игровой области
system.initFullScale();
//переменные для самой игры
var PlayerOpenCards = []; //массив со строками номиналов карт у игрока
var CompOpenCards = []; //массив со строками номиналов карт у компьютера
var PlayerOpenCards_objects = []; //массив с объектами карт у игрока
var CompOpenCards_objects = []; //массив с объектами карт у компьютера
var card_height = 107 * 1.5; //высота карты
var card_width = 74 * 1.5; //ширина карты
var left_offset = 20; //отступ слева для "рук"
var player_top_offset = height - 20 - card_height; //отступ сверху для "руки" игрока
var comp_top_offset = 20; //отступ сверху для "руки" компьютера
var deck = ['c2c', 'c3c', 'c4c', 'c5c', 'c6c', 'c7c', 'c8c', 'c9c', 'c10c', 'cjc', 'cqc', 'ckc', 'cac', 'c2h', 'c3h', 'c4h', 'c5h', 'c6h', 'c7h', 'c8h', 'c9h', 'c10h', 'cjh', 'cqh', 'ckh', 'cah', 'c2s', 'c3s', 'c4s', 'c5s', 'c6s', 'c7s', 'c8s', 'c9s', 'c10s', 'cjs', 'cqs', 'cks', 'cas', 'c2d', 'c3d', 'c4d', 'c5d', 'c6d', 'c7d', 'c8d', 'c9d', 'c10d', 'cjd', 'cqd', 'ckd', 'cad', 'cjkb', 'cjkk'];
let pull_deck = []; //колода для сноса
let game_step = 1; //переменная показывает на каком этапе игры мы находимся: 1 - игрок берет карту, 2 - игрок ходит, 3 - компьютер берет карту, 4 - компьютер ходит
let green_button_sprite = pjs.tiles.newImage('green-button.png'); //кнопочки
let red_button_sprite = pjs.tiles.newImage('red-button.png');
let is_pulled = false; //снесена ли карта
let push_combination_button = game.newImageObject({ //кнопочки
file: green_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 + card_height / 2 + 20
});
let push_combination_text = game.newTextObject({
text : 'Выложить комбинацию',
size : 20,
color : '#fff',
x : width - card_width * 2 - 10,
y : height / 2 + card_height / 2 + 50
});
let pull_card_button = game.newImageObject({
file: red_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 + card_height / 2 + 120
});
let pull_card_text = game.newTextObject({
text : 'Снести карту',
size : 20,
color : '#fff',
x : width - card_width * 2 + 40,
y : height / 2 + card_height / 2 + 150
});
let finish_round_button = game.newImageObject({
file: red_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 - card_height / 2 - 100
});
let finish_round_text = game.newTextObject({
text : 'Завершить ход',
size : 20,
color : '#fff',
x : width - card_width * 2 + 30,
y : height / 2 - card_height / 2 - 70
});
function parseCardValue(card) { //функция вычисления масти и достоинства карты
var card_properties = {};
if (card == 'cjkb' || card == 'cjkk') { //если джокер, даем ему максимальную масть и достоинство
card_properties.suite = 5;
card_properties.score = 15;
return card_properties;
}
if (card.length == 3) {
card_properties.suite = card.charAt(2);
card_properties.score = card.charAt(1);
} else {
card_properties.suite = card.charAt(3);
card_properties.score = card.charAt(1) + card.charAt(2);
}
switch (card_properties.suite) { //парсим масти
case 's':
card_properties.suite = 1;
break;
case 'c':
card_properties.suite = 2;
break;
case 'd':
card_properties.suite = 3;
break;
case 'h':
card_properties.suite = 4;
break;
}
switch (card_properties.score) { //парсим картинки
case 'j':
card_properties.score = 11;
break;
case 'q':
card_properties.score = 12;
break;
case 'k':
card_properties.score = 13;
break;
case 'a':
card_properties.score = 14;
break;
}
return card_properties;
}
function fieldSorter(fields) {//функция сортировки
return function (a, b) {
return fields
.map(function (o) {
var dir = 1;
if (o[0] === '-') {
dir = -1;
o = o.substring(1);
}
if (a[o] > b[o]) return dir;
if (a[o] < b[o]) return -(dir);
return 0;
})
.reduce(function firstNonZeroValue(p, n) {
return p ? p : n;
}, 0);
};
}
function addCardToPlayer(player_cards_array){ //функция взятия карты из колоды. параметром принимает массив карт игрока/компа
let last_item = deck[deck.length - 1];
player_cards_array.push(last_item);
deck.splice(deck.length - 1, 1);
BasecolClose.cards_count--;
}
function sortCards(player_cards_array, player_cards_objects_array, offset){ //функция сортировки руки
player_cards_objects_array.length = 0;
player_cards_array.forEach(function (item) { //для всех номиналов карт у игрока
var card_object = game.newImageObject({ //создаем объект
file : item + '.bmp', //картинка
y : offset, //отступ сверху
h : card_height, //высота карты
w : card_width, //ширина карты
userData: {
card_value : item, //номинал карты
card_suite : parseCardValue(item).suite, //масть карты
card_score : parseInt(parseCardValue(item).score), //достоинство карты
card_active: false
}
});
player_cards_objects_array.push(card_object); //добавляем объект карты в массив
});
player_cards_objects_array.sort(fieldSorter(['card_suite', 'card_score'])); //сортируем карты по масти и по достоинству
for (var index = 0; index < PlayerOpenCards_objects.length; index++) {
player_cards_objects_array[index].x = left_offset + card_width * index; //в соответствии с сортировкой, указываем позицию по иксу
}
}
var TasCards = function () {//функция тасования кард
pjs.math.randomFY(deck);
for (var i = 0; i < 9; i++) {
addCardToPlayer(PlayerOpenCards); //даем карту игроку
addCardToPlayer(CompOpenCards); //даем карту компу
}
sortCards(PlayerOpenCards, PlayerOpenCards_objects, player_top_offset); //сортируем руку игрока
sortCards(CompOpenCards, CompOpenCards_objects, comp_top_offset); //сортируем руку компа
}
var BasecolClose = game.newImageObject({
file : 'card_mask.bmp',
x : width - 20 - card_width,
y : height / 2 - card_height / 2,
h : card_height,
w : card_width,
userData: {
cards_count: 54
}
});
var DeckP = game.newImageObject({
file: 'deck_pool.bmp',
x : width - 20 - card_width * 2,
y : height / 2 - card_height / 2,
h : card_height,
w : card_width,
});
game.newLoopFromConstructor("my game", function () { //создаем игровой цикл
this.entry = function () { //при входе в игровой цикл
TasCards(); //тасуем карты и раздаем их
game_step = 1; //начинаем с хода игрока
}
this.update = function () { //в игровом цикле
game.clear(); //очищаем экран
switch (game_step){
case 1:
addCardToPlayer(PlayerOpenCards); //даем игроку карту
sortCards(PlayerOpenCards, PlayerOpenCards_objects, player_top_offset); //сортируем руку
is_pulled = false; //карта пока не снесена
game_step = 2; //переходим к следующему этапу
break;
case 2:
push_combination_button.draw(); //рисуем кнопку выкладывания комбинаций
push_combination_text.draw();
if(is_pulled == false){ //если карта не снесена
pull_card_button.draw(); //рисуем кнопку сноса
pull_card_text.draw();
}else{ //иначе
finish_round_button.draw(); //рисуем кнопку завершения хода
finish_round_text.draw();
}
PlayerOpenCards_objects.forEach(function (item, index) { //для всех карт игрока
if (mouse.isPeekObject('LEFT', PlayerOpenCards_objects[index])) { //если тыкнуть мышкой в карту
if (PlayerOpenCards_objects[index].card_active == false) { //если карта неактивна
PlayerOpenCards_objects[index].y -= 50; //выдвигаем ее вверх
PlayerOpenCards_objects[index].card_active = true; //и делаем активной
} else { //иначе
PlayerOpenCards_objects[index].y += 50; //задвигаем назад
PlayerOpenCards_objects[index].card_active = false; //и делаем неактивной
}
}
});
if(mouse.isPeekObject('LEFT', pull_card_button) || mouse.isPeekObject('LEFT', pull_card_text)){ //если тыкнуть в кнопку сноса
let selected_cards = 0; //количество выбранных карт 0
let selected_card_index = ''; //номер выбранной карты
PlayerOpenCards_objects.forEach(function(item, index){ //для всех карт
if(PlayerOpenCards_objects[index].card_active == true){ //если карта активна
selected_cards ++; //увеличиваем счетчик активных карт
selected_card_index = index; //запоминаем номер выбранной карты
}
});
if(selected_cards == 1){ //если выбрана одна карта
pull_deck.push(PlayerOpenCards_objects[selected_card_index].card_value); //пушим ее в колоду для сноса
DeckP.file = pull_deck[pull_deck.length - 1] + '.bmp'; //назначаем колоде для сноса ее картинку
PlayerOpenCards.forEach(function(item, index){ //ищем в картах игрока карту которую нужно убрать
if(PlayerOpenCards[index] == PlayerOpenCards_objects[selected_card_index].card_value){ //находим
PlayerOpenCards.splice(index, 1); //убираем
}
});
sortCards(PlayerOpenCards, PlayerOpenCards_objects, player_top_offset); //сортируем руку
is_pulled = true; //карта снесена
}else{
alert('Для сноса должна быть выбрана одна карта'); //если не выбрана ни одна карта или больше одной, матюкаемся
}
}
if(mouse.isPeekObject('LEFT', finish_round_button) || mouse.isPeekObject('LEFT', finish_round_text)){ //если тыкаем "завершить ход"
game_step = 3;//переходим к следующему шагу
}
break;
}
if (BasecolClose.cards_count > 0) {
BasecolClose.draw(); //рисуем закрытую колоду
}
DeckP.draw(); //рисуем колоду для сноса
pjs.OOP.drawArr(CompOpenCards_objects); //рисуем массив объектов карт комьютера
pjs.OOP.drawArr(PlayerOpenCards_objects); //рисуем массив объектов карт игрока
}
});
game.setLoop("my game");
game.start();
</script>
Re: "Canasta Opening" - карточная игра на Point JS
Офигенно) Алексей либо обрадуется, либо наоборот разозлиться, что все делают за него=)
Ну да, кстати, чо парится и всякие стейт машины выдумывать, если можно сделать все на switch-case=)) Если что-то большее не планируется, то и можно обойтись и этой конструкцией.
Красава!
P.S. Вопрос Алексею, насколько тебе понятно то, что написано в коде у пиро?
Ну да, кстати, чо парится и всякие стейт машины выдумывать, если можно сделать все на switch-case=)) Если что-то большее не планируется, то и можно обойтись и этой конструкцией.
Красава!
P.S. Вопрос Алексею, насколько тебе понятно то, что написано в коде у пиро?
raingo- Отдел прокрастинации
- Сообщения : 756
Дата регистрации : 2017-12-25
Re: "Canasta Opening" - карточная игра на Point JS
да я чот ворвался). пока мысль прёт - лучше ее не останавливать))
да фиг знает. это пока у меня так - поток сознания. потом можно переделать если чочо парится и всякие стейт машины выдумывать, если можно сделать все на switch-case
Re: "Canasta Opening" - карточная игра на Point JS
комбинации карт "по значению"
- Код:
var pjs = new PointJS(1280, 1024, {backgroundColor: "GREEN"})
var game = pjs.game;
var system = pjs.system;
var mouse = pjs.mouseControl.initMouseControl();
var brush = pjs.brush;
var width = pjs.game.getWH().w; //получаем ширину игровой области
var height = pjs.game.getWH().h; //получаем высоту игровой области
system.initFullScale();
//переменные для самой игры
var PlayerOpenCards = []; //массив со строками номиналов карт у игрока
var CompOpenCards = []; //массив со строками номиналов карт у компьютера
var PlayerOpenCards_objects = []; //массив с объектами карт у игрока
var CompOpenCards_objects = []; //массив с объектами карт у компьютера
var card_height = 107 * 1.5; //высота карты
var card_width = 74 * 1.5; //ширина карты
var left_offset = 20; //отступ слева для "рук"
var player_top_offset = height - 20 - card_height; //отступ сверху для "руки" игрока
var comp_top_offset = 20; //отступ сверху для "руки" компьютера
var deck = ['c2c', 'c3c', 'c4c', 'c5c', 'c6c', 'c7c', 'c8c', 'c9c', 'c10c', 'cjc', 'cqc', 'ckc', 'cac', 'c2h', 'c3h', 'c4h', 'c5h', 'c6h', 'c7h', 'c8h', 'c9h', 'c10h', 'cjh', 'cqh', 'ckh', 'cah', 'c2s', 'c3s', 'c4s', 'c5s', 'c6s', 'c7s', 'c8s', 'c9s', 'c10s', 'cjs', 'cqs', 'cks', 'cas', 'c2d', 'c3d', 'c4d', 'c5d', 'c6d', 'c7d', 'c8d', 'c9d', 'c10d', 'cjd', 'cqd', 'ckd', 'cad', 'cjkb', 'cjkk'];
let pull_deck = []; //колода для сноса
let game_step = 1; //переменная показывает на каком этапе игры мы находимся: 1 - игрок берет карту, 2 - игрок ходит, 3 - компьютер берет карту, 4 - компьютер ходит
let green_button_sprite = pjs.tiles.newImage('green-button.png'); //кнопочки
let red_button_sprite = pjs.tiles.newImage('red-button.png');
let is_pulled = false; //снесена ли карта
let player_combinations = []; //комбинации игрока
let push_combination_button = game.newImageObject({ //кнопочки
file: green_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 + card_height / 2 + 20
});
let push_combination_text = game.newTextObject({
text : 'Выложить комбинацию',
size : 20,
color: '#fff',
x : width - card_width * 2 - 10,
y : height / 2 + card_height / 2 + 50
});
let pull_card_button = game.newImageObject({
file: red_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 + card_height / 2 + 120
});
let pull_card_text = game.newTextObject({
text : 'Снести карту',
size : 20,
color: '#fff',
x : width - card_width * 2 + 40,
y : height / 2 + card_height / 2 + 150
});
let finish_round_button = game.newImageObject({
file: red_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 - card_height / 2 - 100
});
let finish_round_text = game.newTextObject({
text : 'Завершить ход',
size : 20,
color: '#fff',
x : width - card_width * 2 + 30,
y : height / 2 - card_height / 2 - 70
});
function parseCardValue(card) { //функция вычисления масти и достоинства карты
var card_properties = {};
if (card == 'cjkb' || card == 'cjkk') { //если джокер, даем ему максимальную масть и достоинство
card_properties.suite = 5;
card_properties.score = 15;
return card_properties;
}
if (card.length == 3) {
card_properties.suite = card.charAt(2);
card_properties.score = card.charAt(1);
} else {
card_properties.suite = card.charAt(3);
card_properties.score = card.charAt(1) + card.charAt(2);
}
switch (card_properties.suite) { //парсим масти
case 's':
card_properties.suite = 1;
break;
case 'c':
card_properties.suite = 2;
break;
case 'd':
card_properties.suite = 3;
break;
case 'h':
card_properties.suite = 4;
break;
}
switch (card_properties.score) { //парсим картинки
case 'j':
card_properties.score = 11;
break;
case 'q':
card_properties.score = 12;
break;
case 'k':
card_properties.score = 13;
break;
case 'a':
card_properties.score = 14;
break;
}
return card_properties;
}
function fieldSorter(fields) {//функция сортировки
return function (a, b) {
return fields
.map(function (o) {
var dir = 1;
if (o[0] === '-') {
dir = -1;
o = o.substring(1);
}
if (a[o] > b[o]) return dir;
if (a[o] < b[o]) return -(dir);
return 0;
})
.reduce(function firstNonZeroValue(p, n) {
return p ? p : n;
}, 0);
};
}
function addCardToPlayer(player_cards_array) { //функция взятия карты из колоды. параметром принимает массив карт игрока/компа
let last_item = deck[deck.length - 1];
player_cards_array.push(last_item);
deck.splice(deck.length - 1, 1);
BasecolClose.cards_count--;
}
function sortCards(player_cards_array, player_cards_objects_array, offset) { //функция сортировки руки
player_cards_objects_array.length = 0;
player_cards_array.forEach(function (item) { //для всех номиналов карт у игрока
var card_object = game.newImageObject({ //создаем объект
file : item + '.bmp', //картинка
y : offset, //отступ сверху
h : card_height, //высота карты
w : card_width, //ширина карты
userData: {
card_value : item, //номинал карты
card_suite : parseCardValue(item).suite, //масть карты
card_score : parseInt(parseCardValue(item).score), //достоинство карты
card_active: false
}
});
player_cards_objects_array.push(card_object); //добавляем объект карты в массив
});
player_cards_objects_array.sort(fieldSorter(['card_suite', 'card_score'])); //сортируем карты по масти и по достоинству
for (var index = 0; index < PlayerOpenCards_objects.length; index++) {
player_cards_objects_array[index].x = left_offset + card_width * index; //в соответствии с сортировкой, указываем позицию по иксу
}
}
var TasCards = function () {//функция тасования кард
pjs.math.randomFY(deck);
for (var i = 0; i < 9; i++) {
addCardToPlayer(PlayerOpenCards); //даем карту игроку
addCardToPlayer(CompOpenCards); //даем карту компу
}
sortCards(PlayerOpenCards, PlayerOpenCards_objects, player_top_offset); //сортируем руку игрока
sortCards(CompOpenCards, CompOpenCards_objects, comp_top_offset); //сортируем руку компа
}
var BasecolClose = game.newImageObject({
file : 'card_mask.bmp',
x : width - 20 - card_width,
y : height / 2 - card_height / 2,
h : card_height,
w : card_width,
userData: {
cards_count: 54
}
});
var DeckP = game.newImageObject({
file: 'deck_pool.bmp',
x : width - 20 - card_width * 2,
y : height / 2 - card_height / 2,
h : card_height,
w : card_width,
});
function checkValueCombination(active_cards){ //проверка комбинаций "по значению"
let combination_checked = true; //установим флаг, что проверка пройдена
let previousCard = active_cards[0].card_score; //предведущая карта = первая карта
if(active_cards.length < 3){ //если выбрано меньше трех карт
return false; //проверка не пройдена
}
active_cards.forEach(function(item, index){ //для всех выбранных карт
if(active_cards[index].card_score != 15){ //если не джокер
if(active_cards[index].card_score != previousCard){ //если значение текущей карты не равно значению предведущей
combination_checked = false; //проверка провалена
}
previousCard = active_cards[index].card_score; //предведущая карта = текущая карта
}
});
return(combination_checked); //возвращаем результат проверки
}
function checkSuitCombination(active_cards){ //проверка комбинаций "по масти"
return false; //ну тут пока хз
}
function drawPlayerCombinations(){ //отрисовка комбинаций карт
player_combinations.forEach(function(item, index){
player_combinations[index].forEach(function(item2, index2){
player_combinations[index][index2].x = left_offset + card_width * index + 20; //сложем в стопочку
player_combinations[index][index2].y = height / 2 + 20 + 20 * index2;
});
});
}
game.newLoopFromConstructor("my game", function () { //создаем игровой цикл
this.entry = function () { //при входе в игровой цикл
TasCards(); //тасуем карты и раздаем их
game_step = 1; //начинаем с хода игрока
}
this.update = function () { //в игровом цикле
game.clear(); //очищаем экран
switch (game_step) {
case 1:
addCardToPlayer(PlayerOpenCards); //даем игроку карту
sortCards(PlayerOpenCards, PlayerOpenCards_objects, player_top_offset); //сортируем руку
is_pulled = false; //карта пока не снесена
game_step = 2; //переходим к следующему этапу
break;
case 2:
push_combination_button.draw(); //рисуем кнопку выкладывания комбинаций
push_combination_text.draw();
if (is_pulled == false) { //если карта не снесена
pull_card_button.draw(); //рисуем кнопку сноса
pull_card_text.draw();
} else { //иначе
finish_round_button.draw(); //рисуем кнопку завершения хода
finish_round_text.draw();
}
PlayerOpenCards_objects.forEach(function (item, index) { //для всех карт игрока
if (mouse.isPeekObject('LEFT', PlayerOpenCards_objects[index])) { //если тыкнуть мышкой в карту
if (PlayerOpenCards_objects[index].card_active == false) { //если карта неактивна
PlayerOpenCards_objects[index].y -= 50; //выдвигаем ее вверх
PlayerOpenCards_objects[index].card_active = true; //и делаем активной
} else { //иначе
PlayerOpenCards_objects[index].y += 50; //задвигаем назад
PlayerOpenCards_objects[index].card_active = false; //и делаем неактивной
}
}
});
if (mouse.isPeekObject('LEFT', push_combination_button) || mouse.isPeekObject('LEFT', push_combination_text)) {
let active_cards = []; //массив активных карт
active_cards.length = 0;
PlayerOpenCards_objects.forEach(function (item, index) { //для всех карт игрока
if (PlayerOpenCards_objects[index].card_active == true) { //если карта активна
let card = PlayerOpenCards_objects[index];
active_cards.push(card); //пихаем ее в массив
}
});
if(checkValueCombination(active_cards)){ //если проверка на комбинацию пройдена
player_combinations.push(active_cards); //пушим активные карты в массив с комбинациями
drawPlayerCombinations(); //складываем в стопочки
PlayerOpenCards.forEach(function(item, index){ //убираем ненужные карты из "руки"
active_cards.forEach(function(item2, index2){
if(PlayerOpenCards[index] == active_cards[index2].card_value){
PlayerOpenCards.splice(index, 1);
}
})
});
sortCards(PlayerOpenCards, PlayerOpenCards_objects, player_top_offset); //сортируем "руку"
}
}
if (mouse.isPeekObject('LEFT', pull_card_button) || mouse.isPeekObject('LEFT', pull_card_text)) { //если тыкнуть в кнопку сноса
let selected_cards = 0; //количество выбранных карт 0
let selected_card_index = ''; //номер выбранной карты
PlayerOpenCards_objects.forEach(function (item, index) { //для всех карт
if (PlayerOpenCards_objects[index].card_active == true) { //если карта активна
selected_cards++; //увеличиваем счетчик активных карт
selected_card_index = index; //запоминаем номер выбранной карты
}
});
if (selected_cards == 1) { //если выбрана одна карта
pull_deck.push(PlayerOpenCards_objects[selected_card_index].card_value); //пушим ее в колоду для сноса
DeckP.file = pull_deck[pull_deck.length - 1] + '.bmp'; //назначаем колоде для сноса ее картинку
PlayerOpenCards.forEach(function (item, index) { //ищем в картах игрока карту которую нужно убрать
if (PlayerOpenCards[index] == PlayerOpenCards_objects[selected_card_index].card_value) { //находим
PlayerOpenCards.splice(index, 1); //убираем
}
});
sortCards(PlayerOpenCards, PlayerOpenCards_objects, player_top_offset); //сортируем руку
is_pulled = true; //карта снесена
} else {
alert('Для сноса должна быть выбрана одна карта'); //если не выбрана ни одна карта или больше одной, матюкаемся
}
}
if (mouse.isPeekObject('LEFT', finish_round_button) || mouse.isPeekObject('LEFT', finish_round_text)) { //если тыкаем "завершить ход"
game_step = 3;//переходим к следующему шагу
}
break;
}
if (BasecolClose.cards_count > 0) {
BasecolClose.draw(); //рисуем закрытую колоду
}
DeckP.draw(); //рисуем колоду для сноса
pjs.OOP.drawArr(CompOpenCards_objects); //рисуем массив объектов карт комьютера
pjs.OOP.drawArr(PlayerOpenCards_objects); //рисуем массив объектов карт игрока
player_combinations.forEach(function(item){
pjs.OOP.drawArr(item); //рисуем стопочки с комбинациями
})
}
});
game.setLoop("my game");
game.start();
Re: "Canasta Opening" - карточная игра на Point JS
Кстати, вот эта сортировка называется сортировка через компаратор? Недавно узнал. Или это и есть пузырьком?
Комбинации "по масти" для AI можно делать через графы. Для игрока - это просто проверка на последовательность карт, что не очень сложно. Если без сложных математических формул алгоритм получается такой:
Кстати, получились не графы. Но и фиг с ними, код с тру-графами со всякими степенями будет ненамного чище. Вроде должно работать, навскидку написал. Сразу видно, что можно улучшить. Но тут главное функционал. В цикл можно добавить всякие операции для подсчета сложных комбинаций, типа джокера и т.д. Я не понял, что там с джокером.
И еще, король-туз-2-3 - это тоже комба? Т.е. карты вычисляются по кругу?
- Код:
function fieldSorter(fields) {//функция сортировки
return function (a, b) {
return fields
.map(function (o) {
var dir = 1;
if (o[0] === '-') {
dir = -1;
o = o.substring(1);
}
if (a[o] > b[o]) return dir;
if (a[o] < b[o]) return -(dir);
return 0;
})
.reduce(function firstNonZeroValue(p, n) {
return p ? p : n;
}, 0);
};
}
Комбинации "по масти" для AI можно делать через графы. Для игрока - это просто проверка на последовательность карт, что не очень сложно. Если без сложных математических формул алгоритм получается такой:
- разделяем все карты AI на четыре массива. Один массив - одна масть. Сортируем массивы по весу карт (от 2 до короля).
- вместо туза можно сделать две фиктивные карты - единичка и 13 (король - 12 баллов).
- var v = 0;//Создаем переменную для сравнения веса карт.
- var r[]; //массив для хранения всех результатов
- var index = 0; //индикатор массива, чтобы сохранять результаты в разные ячейки
- for (i=0; i < массивКарт.lenght(); i++){ //в цикле проходим по каждому массиву масти рук
if (массивКарт[i].весКарты == (v+1)) { v++; r[index]++; } //если карты идут подряд, увеличиваем подручные переменные
else {v=массивКарт[i].весКарты; index++;} //если карты идут не подряд, пишем результат в следующую ячейку
} - в итоге у нас есть массив r[] со всеми длинами последовательных карт. Мы сортируем его, получаем самую длинную последовательность, а потом тупо из этой последовательности вычисляем реузльтат.
Кстати, получились не графы. Но и фиг с ними, код с тру-графами со всякими степенями будет ненамного чище. Вроде должно работать, навскидку написал. Сразу видно, что можно улучшить. Но тут главное функционал. В цикл можно добавить всякие операции для подсчета сложных комбинаций, типа джокера и т.д. Я не понял, что там с джокером.
И еще, король-туз-2-3 - это тоже комба? Т.е. карты вычисляются по кругу?
raingo- Отдел прокрастинации
- Сообщения : 756
Дата регистрации : 2017-12-25
Re: "Canasta Opening" - карточная игра на Point JS
насколько я понял, джокер используется вместо любой картыЯ не понял, что там с джокером
вроде даТ.е. есть карты вычисляются по кругу
*нецензурная брань* знает. я с графами уже вообще не помню как и чо с института. в повседневной работе они мне так-то и не нужны
Re: "Canasta Opening" - карточная игра на Point JS
Графы хyяфы. И так норм.
Не очень интересно конеш, когда автор в замедленном темпе. Эту игру за два дня можно сделать. Если правила понять=) А за три дня еще написать мультиплеер и серверную часть, залить на гитхаб, залить вк и в одноклассники. Перенести на мобилки в гугл плей и апп стор, податься в стим и другие маркеты и площадки для веб-игр.
Не очень интересно конеш, когда автор в замедленном темпе. Эту игру за два дня можно сделать. Если правила понять=) А за три дня еще написать мультиплеер и серверную часть, залить на гитхаб, залить вк и в одноклассники. Перенести на мобилки в гугл плей и апп стор, податься в стим и другие маркеты и площадки для веб-игр.
raingo- Отдел прокрастинации
- Сообщения : 756
Дата регистрации : 2017-12-25
Re: "Canasta Opening" - карточная игра на Point JS
Не, только сегодня с дессаном обсуждали мою несосредоточенность. Надо своим проектом заняться.
Я так понял, Алексей совсем недавно был совсем нулем в кодинге. Да и работает гуманитарием. Так что можно войти в положение, принять его медленный темп. Сделаем все за него, не познает вкус геймдева. Или со следующей игрой будет думать, что все так просто.
Я так понял, Алексей совсем недавно был совсем нулем в кодинге. Да и работает гуманитарием. Так что можно войти в положение, принять его медленный темп. Сделаем все за него, не познает вкус геймдева. Или со следующей игрой будет думать, что все так просто.
raingo- Отдел прокрастинации
- Сообщения : 756
Дата регистрации : 2017-12-25
Re: "Canasta Opening" - карточная игра на Point JS
ну я так-то старался считай каждую строчку комментировать. что там может быть непонятно - я хз. хотя наверное в некоторых местах можно было и проще сделать
Re: "Canasta Opening" - карточная игра на Point JS
вот в божеский вид привел - убрал лишние строчки там и вот это вот все
Пыщь Архив с картинками, если нужно. хотя тоже говно - слишком мелкие - не разглядишь. хз.
- Код:
let pjs = new PointJS(1280, 1024, {
backgroundImage: "url(sukno.jpg)",
backgroundSize: "cover",
});
let game = pjs.game;
let system = pjs.system;
let mouse = pjs.mouseControl.initMouseControl();
let brush = pjs.brush;
let width = pjs.game.getWH().w; //получаем ширину игровой области
let height = pjs.game.getWH().h; //получаем высоту игровой области
let point = pjs.vector.point;
system.initFullScale();
//переменные для самой игры
let cards_array = ['c2c', 'c3c', 'c4c', 'c5c', 'c6c', 'c7c', 'c8c', 'c9c', 'c10c', 'cjc', 'cqc', 'ckc', 'cac', 'c2h', 'c3h', 'c4h', 'c5h', 'c6h', 'c7h', 'c8h', 'c9h', 'c10h', 'cjh', 'cqh', 'ckh', 'cah', 'c2s', 'c3s', 'c4s', 'c5s', 'c6s', 'c7s', 'c8s', 'c9s', 'c10s', 'cjs', 'cqs', 'cks', 'cas', 'c2d', 'c3d', 'c4d', 'c5d', 'c6d', 'c7d', 'c8d', 'c9d', 'c10d', 'cjd', 'cqd', 'ckd', 'cad', 'cjkb', 'cjkk'];
let player_cards = []; //массив карт игрока
let comp_cards = []; //массив карт компа
let card_height = 172; //высота карты
let card_width = 115; //ширина карты
let left_offset = 20; //отступ слева для "рук"
let player_top_offset = height - 20 - card_height; //отступ сверху для "руки" игрока
let comp_top_offset = 20; //отступ сверху для "руки" компьютера
let deck = []; //колода
let pull_deck = []; //колода для сноса
let game_step = 0; //переменная показывает на каком этапе игры мы находимся: 1 - игрок берет карту, 2 - игрок ходит, 3 - компьютер берет карту, 4 - компьютер ходит
let pull_button_sprite = pjs.tiles.newImage('pull-button.png'); //кнопочки
let round_button_sprite = pjs.tiles.newImage('round-button.png');
let combination_button_sprite = pjs.tiles.newImage('combination-button.png');
let is_pulled = false; //снесена ли карта
let player_combinations = []; //комбинации игрока
let deck_close = game.newImageObject({
file : 'card_mask.png',
x : width - 20 - card_width,
y : height / 2 - card_height / 2,
h : card_height,
w : card_width,
userData: {
cards_count: 54
}
});
let deck_pull = game.newImageObject({
file: 'deck_pool.png',
x : width - 20 - card_width * 2,
y : height / 2 - card_height / 2,
h : card_height,
w : card_width,
userData: {
cards_count: 0
}
});
let push_combination_button = game.newImageObject({ //кнопочки
file: combination_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 + card_height / 2 + 20
});
let pull_card_button = game.newImageObject({
file: pull_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 + card_height / 2 + 120
});
let finish_round_button = game.newImageObject({
file: round_button_sprite.file,
w : card_width * 2,
h : 80,
x : width - card_width * 2 - 20,
y : height / 2 - card_height / 2 - 100
});
function parseCardValue(card) { //функция вычисления масти и достоинства карты
let card_properties = {};
if (card == 'cjkb' || card == 'cjkk') { //если джокер, даем ему максимальную масть и достоинство
card_properties.suite = 5;
card_properties.score = 15;
return card_properties;
}
if (card.length == 3) {
card_properties.suite = card.charAt(2);
card_properties.score = card.charAt(1);
} else {
card_properties.suite = card.charAt(3);
card_properties.score = card.charAt(1) + card.charAt(2);
}
switch (card_properties.suite) { //парсим масти
case 's':
card_properties.suite = 1;
break;
case 'c':
card_properties.suite = 2;
break;
case 'd':
card_properties.suite = 3;
break;
case 'h':
card_properties.suite = 4;
break;
}
switch (card_properties.score) { //парсим картинки
case 'j':
card_properties.score = 11;
break;
case 'q':
card_properties.score = 12;
break;
case 'k':
card_properties.score = 13;
break;
case 'a':
card_properties.score = 14;
break;
}
return card_properties;
}
function fieldSorter(fields) {//функция сортировки
return function (a, b) {
return fields
.map(function (o) {
var dir = 1;
if (o[0] === '-') {
dir = -1;
o = o.substring(1);
}
if (a[o] > b[o]) return dir;
if (a[o] < b[o]) return -(dir);
return 0;
})
.reduce(function firstNonZeroValue(p, n) {
return p ? p : n;
}, 0);
};
}
function addCardToPlayer(player_cards_array) { //функция взятия карты из колоды. параметром принимает массив карт игрока/компа
let last_item = deck[deck.length - 1];
player_cards_array.push(last_item);
deck.splice(deck.length - 1, 1);
deck_close.cards_count--;
}
function sortCards(player_cards_array, offset) { //функция сортировки руки
player_cards_array.sort(fieldSorter(['card_suite', 'card_score'])); //сортируем карты по масти и по достоинству
player_cards_array.forEach(function(item, index){
item.y = offset; //ставим карту в нужную позицию
item.x = left_offset + card_width * index;
});
}
function TasCards() {//функция тасования кард
cards_array.forEach(function(item){
let card = game.newImageObject({ //создаем объект
file : item + '.png', //картинка
h : card_height, //высота карты
w : card_width, //ширина карты
userData: {
card_value : item, //номинал карты
card_suite : parseCardValue(item).suite, //масть карты
card_score : parseInt(parseCardValue(item).score), //достоинство карты
card_active: false
}
});
deck.push(card);
});
pjs.math.randomFY(deck);
for (var i = 0; i < 9; i++) {
addCardToPlayer(player_cards); //даем карту игроку
addCardToPlayer(comp_cards); //даем карту компу
}
sortCards(player_cards, player_top_offset); //сортируем руку игрока
sortCards(comp_cards, comp_top_offset); //сортируем руку компа
}
function checkValueCombination(active_cards){ //проверка комбинаций "по значению"
let combination_checked = true; //установим флаг, что проверка пройдена
let previousCard = active_cards[0].card_score; //предведущая карта = первая карта
if(active_cards.length < 3){ //если выбрано меньше трех карт
return false; //проверка не пройдена
}
active_cards.forEach(function(item){ //для всех выбранных карт
if(item.card_score != 15){ //если не джокер
if(item.card_score != previousCard){ //если значение текущей карты не равно значению предведущей
combination_checked = false; //проверка провалена
}
previousCard = item.card_score; //предведущая карта = текущая карта
}
});
return(combination_checked); //возвращаем результат проверки
}
function checkSuitCombination(active_cards){ //проверка комбинаций "по масти"
return false; //ну тут пока хз
}
function drawPlayerCombinations(){ //отрисовка комбинаций карт
player_combinations.forEach(function(item, index){
player_combinations[index].forEach(function(item2, index2){
player_combinations[index][index2].x = left_offset + card_width * index + 20; //сложем в стопочку
player_combinations[index][index2].y = height / 2 + 20 + 20 * index2;
});
});
}
game.newLoopFromConstructor("my game", function () { //создаем игровой цикл
this.entry = function () { //при входе в игровой цикл
game_step = 0;
}
this.update = function () { //в игровом цикле
game.clear(); //очищаем экран
switch (game_step) {
case 0:
TasCards(); //тасуем карты и раздаем их
game_step = 1;
break;
case 1:
addCardToPlayer(player_cards); //даем игроку карту
sortCards(player_cards, player_top_offset); //сортируем руку
is_pulled = false; //карта пока не снесена
game_step = 2; //переходим к следующему этапу
break;
case 2:
push_combination_button.draw(); //рисуем кнопку выкладывания комбинаций
if (is_pulled == false) { //если карта не снесена
pull_card_button.draw(); //рисуем кнопку сноса
} else { //иначе
finish_round_button.draw(); //рисуем кнопку завершения хода
}
player_cards.forEach(function (item) { //для всех карт игрока
if (mouse.isPeekObject('LEFT', item)) { //если тыкнуть мышкой в карту
if (item.card_active == false) { //если карта неактивна
item.y -= 50; //выдвигаем ее вверх
item.card_active = true; //и делаем активной
} else { //иначе
item.y += 50; //задвигаем назад
item.card_active = false; //и делаем неактивной
}
}
});
if (mouse.isPeekObject('LEFT', push_combination_button)) {
let active_cards = []; //массив активных карт
player_cards.forEach(function (item) { //для всех карт игрока
if (item.card_active == true) { //если карта активна
active_cards.push(item); //пихаем ее в массив
}
});
if(checkValueCombination(active_cards)){ //если проверка на комбинацию пройдена
player_combinations.push(active_cards); //пушим активные карты в массив с комбинациями
drawPlayerCombinations(); //складываем в стопочки
player_cards.forEach(function(item, index){ //убираем ненужные карты из "руки"
active_cards.forEach(function(item2){
if(item.card_value == item2.card_value){
player_cards.splice(index, 1);
}
})
});
sortCards(player_cards, player_top_offset); //сортируем "руку"
}
}
if (mouse.isPeekObject('LEFT', pull_card_button)) { //если тыкнуть в кнопку сноса
let selected_cards = 0; //количество выбранных карт 0
let selected_card_index = ''; //номер выбранной карты
player_cards.forEach(function (item, index) { //для всех карт
if (item.card_active == true) { //если карта активна
selected_cards++; //увеличиваем счетчик активных карт
selected_card_index = index; //запоминаем номер выбранной карты
}
});
if (selected_cards == 1) { //если выбрана одна карта
pull_deck.push(player_cards[selected_card_index].card_value); //пушим ее в колоду для сноса
deck_pull.file = pull_deck[pull_deck.length - 1] + '.png'; //назначаем колоде для сноса ее картинку
deck_pull.cards_count ++;
player_cards.splice(selected_card_index, 1); //убираем
sortCards(player_cards, player_top_offset); //сортируем руку
is_pulled = true; //карта снесена
} else {
alert('Для сноса должна быть выбрана одна карта'); //если не выбрана ни одна карта или больше одной, матюкаемся
}
}
if (mouse.isPeekObject('LEFT', finish_round_button)) { //если тыкаем "завершить ход"
game_step = 3;//переходим к следующему шагу
}
break;
}
if (deck_close.cards_count == 0) {
deck_close.file = 'deck_pool.png';
}
deck_close.draw();
deck_pull.draw(); //рисуем колоду для сноса
pjs.OOP.drawArr(player_cards); //рисуем массив объектов карт комьютера
pjs.OOP.drawArr(comp_cards); //рисуем массив объектов карт игрока
player_combinations.forEach(function(item){
pjs.OOP.drawArr(item); //рисуем стопочки с комбинациями
})
}
});
game.setLoop("my game");
game.start();
Пыщь Архив с картинками, если нужно. хотя тоже говно - слишком мелкие - не разглядишь. хз.
Последний раз редактировалось: Pyro338 (Чт Фев 08, 2018 9:50 pm), всего редактировалось 1 раз(а)
Re: "Canasta Opening" - карточная игра на Point JS
Ну вот - поток сознания - это вещь очень хорошая.) Для тех, кто не слишком понял: колода для сноса карт - это то место, куда игроки по очереди своего хода сбрасывают любую ненужную карту после объявления или не объявления комбинации. Карты скидываются лицом вверх.
2. Комбинации можно в будущем дополнять приходящими картами из "закрытой колоды" или из "колоды для сноса".
2. Комбинации можно в будущем дополнять приходящими картами из "закрытой колоды" или из "колоды для сноса".
AlexeyOK- Сообщения : 50
Дата регистрации : 2018-01-08
Re: "Canasta Opening" - карточная игра на Point JS
Кнопки интерфейса, такие как "завершить ход", "объявить комбинации" ребят, я реально что-то не продумал.(
AlexeyOK- Сообщения : 50
Дата регистрации : 2018-01-08
Re: "Canasta Opening" - карточная игра на Point JS
Для тех, кто не слишком понял: колода для сноса карт - это то место, куда игроки по очереди своего хода сбрасывают любую ненужную карту после объявления или не объявления комбинации. Карты скидываются лицом вверх.
ну я сначала нихрена не понял, а потом вроде понял и сделал как надо))
по этому всегде лучше сначала сесть и нарисовать все на бумажке. и пошагово подумать - как чего куда кто тыкать будет и что при этом должно произойти. это называется "написание алгоритма"Кнопки интерфейса, такие как "завершить ход", "объявить комбинации" ребят, я реально что-то не продумал.
Re: "Canasta Opening" - карточная игра на Point JS
Ага. Ребята, я вас очень благодарю. Мне главное на примерах во всём разобраться.) Запустил - долго грузит, напомню, если комбинацию или комбинации выложить нельзя, то любую карту игрок сносит в колоду для сноса. Это верно. Кстати есть глюк - не делает ход компьютер. А при нажатии на кнопку "комбинации" - вообще карты не показывает. Где-то ошибка возможно в коде отрисовки.
AlexeyOK- Сообщения : 50
Дата регистрации : 2018-01-08
Re: "Canasta Opening" - карточная игра на Point JS
ДЖОКЕРЫ: Джокер заменяет собой любую карту в комбинациях. Красный джокер может идти только в красную МАСТЬ (буби,червы), чёрный джокер может идти только в чёрную МАСТЬ(пики, трефы). Джокер может так же пойти в комбинацию ЗНАЧЕНИЕ только при условии, что в ЗНАЧЕНИИ уже есть минимум 2 "натуральные" карты. Пример две 2-ки любых мастей и любой джокер как 3-я 2-ка.
СНОС ДЖОКЕРА. Если джокера сносит игрок в "колоду для сноса" (редко,но могут возникнуть и такие ситуации), то следующий игрок не может "завалить" "колоду для сноса". Он должен покрыть джокера любой другой своей картой, даже джокером, если таковой у него имеется.
СНОС ДЖОКЕРА. Если джокера сносит игрок в "колоду для сноса" (редко,но могут возникнуть и такие ситуации), то следующий игрок не может "завалить" "колоду для сноса". Он должен покрыть джокера любой другой своей картой, даже джокером, если таковой у него имеется.
AlexeyOK- Сообщения : 50
Дата регистрации : 2018-01-08
Re: "Canasta Opening" - карточная игра на Point JS
Найди нормальную игровую колоду, а то как-то несолидно смотрится, а фон однотонный сделай. А ещё лучше нарисуй места для карточных стеков на фоне - будет как в реальной жизни тогда.
Dessan- Юный падаван
- Сообщения : 426
Дата регистрации : 2017-12-25
Re: "Canasta Opening" - карточная игра на Point JS
ну потому что я туда спрайтов на 18 мегабайт напхал)) надо картинки карт нормальные подобрать, чтобы и читались хорошо и выглядели нормально и в размер былиЗапустил - долго грузит
это не глюк. там просто тупо нет такого функционала. не написан.Кстати есть глюк - не делает ход компьютер
хз. может ты не туда тыкаешь. сначала выбираешь карты для комбинации мышкойнажатии на кнопку "комбинации" - вообще карты не показывает
потом нажимаешь на кнопку "комбинация" и он выкладывает ее на стол
ну почему-то 2 из 3-х карты выкладывает. надо проверять код. где-то я пока оптимизировал, косяка упорол видимо.
Страница 3 из 6 • 1, 2, 3, 4, 5, 6
Страница 3 из 6
Права доступа к этому форуму:
Вы не можете отвечать на сообщения