2020-01-15 18:01:07 +01:00
|
|
|
import * as Card from GUI.Card;
|
|
|
|
import * as HandCard from GUI.Card.HandCard;
|
|
|
|
import * as RiverCard from GUI.Card.RiverCard;
|
|
|
|
import * as TurnedCard from GUI.Card.TurnedCard;
|
|
|
|
import * as Screen from GUI.Screen;
|
|
|
|
import {animate, catchUp, delay, getQueue} from GUI.Screen.Game.Animation;
|
2020-01-16 16:45:23 +01:00
|
|
|
import {
|
|
|
|
dom, init as initState, play, select, sets, state
|
|
|
|
} from GUI.Screen.Game.State;
|
2020-01-14 17:27:56 +01:00
|
|
|
import Hanafuda;
|
|
|
|
import I18n;
|
|
|
|
import Messaging;
|
|
|
|
import players from Room;
|
2020-01-15 18:01:07 +01:00
|
|
|
import Save;
|
2020-01-14 17:27:56 +01:00
|
|
|
import Session;
|
|
|
|
import StatusHandler;
|
|
|
|
import * as Async from UnitJS.Async;
|
|
|
|
import * as Dom from UnitJS.Dom;
|
|
|
|
import * as Fun from UnitJS.Fun;
|
|
|
|
|
|
|
|
return {
|
|
|
|
init: init
|
|
|
|
}
|
|
|
|
|
2020-01-15 18:01:07 +01:00
|
|
|
function init(gameID) {
|
|
|
|
initState();
|
|
|
|
initMessageHandlers();
|
|
|
|
Async.run(
|
|
|
|
Async.bind(
|
|
|
|
getSavedState(gameID),
|
2020-01-15 18:06:53 +01:00
|
|
|
function(o) {
|
2020-01-15 18:01:07 +01:00
|
|
|
return Async.sequence(
|
|
|
|
startSession(),
|
2020-01-15 18:06:53 +01:00
|
|
|
setGame(o)
|
2020-01-15 18:01:07 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function fail(errorCode) {
|
|
|
|
return function(f) {
|
|
|
|
Screen.dialog({
|
|
|
|
text: I18n.get(errorCode),
|
|
|
|
answers: [
|
|
|
|
{label: 'backToMain', action: function() {window.location = '..';}}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getSavedState(gameID) {
|
2020-01-15 18:06:53 +01:00
|
|
|
var gameState = Save.get('games.message.Game#' + gameID);
|
2020-01-15 18:01:07 +01:00
|
|
|
return gameState != undefined ? Async.wrap(gameState) : fail('gameNotFound');
|
|
|
|
}
|
|
|
|
|
|
|
|
function startSession() {
|
|
|
|
var name = Save.get('player.name');
|
|
|
|
if(name != undefined) {
|
|
|
|
Session.start(name);
|
|
|
|
return Async.wrap();
|
|
|
|
} else {
|
|
|
|
return fail('noNameToPlay');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function initMessageHandlers() {
|
|
|
|
window.addEventListener('focus', catchUp);
|
2020-01-14 17:27:56 +01:00
|
|
|
Messaging.addEventListener(["Game"], function(o) {
|
2020-01-15 18:01:07 +01:00
|
|
|
delay(handleGameMessage(o));
|
|
|
|
if(document.hasFocus() && getQueue().length == 1) {
|
|
|
|
catchUp();
|
2020-01-14 17:27:56 +01:00
|
|
|
} else {
|
|
|
|
StatusHandler.set("♪");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleGameMessage(o) {
|
2020-01-16 16:45:23 +01:00
|
|
|
if(o.state.public.gameState.turns == 0 || state.game == null) {
|
2020-01-14 17:27:56 +01:00
|
|
|
if(o.logs.length > 0) { // but still some logs, from the previous round
|
|
|
|
return Async.sequence(applyDiff(o), setGame(o)); // so play the diff, then set the new round
|
|
|
|
} else {
|
|
|
|
return setGame(o); // directly set a whole new game
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return applyDiff(o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function setGame(o) {
|
|
|
|
return function(f) {
|
|
|
|
setStatus(o.state);
|
|
|
|
setCaptures(o.state);
|
|
|
|
[
|
2020-01-15 18:01:07 +01:00
|
|
|
[sets.river, o.state.public.river, RiverCard.make],
|
|
|
|
[sets.you.hand, o.state.playerHand, HandCard.make]
|
2020-01-14 17:27:56 +01:00
|
|
|
].forEach(function(args) {setCardSet.apply(null, args)});
|
|
|
|
setTheirCards(o.state);
|
|
|
|
handleStep(o)(f);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleStep(o) {
|
|
|
|
return function(f) {
|
|
|
|
handleTurnedCard(o, f);
|
2020-01-15 18:01:07 +01:00
|
|
|
if(state.step == "Scored") {
|
|
|
|
if(state.playing) {
|
2020-01-14 17:27:56 +01:00
|
|
|
askKoikoi(o, f);
|
|
|
|
} else {
|
|
|
|
theyScored(o, f);
|
|
|
|
}
|
2020-01-15 18:01:07 +01:00
|
|
|
} else if (state.step == "Over") {
|
2020-01-14 17:27:56 +01:00
|
|
|
gameEnd(o, f);
|
|
|
|
} else {
|
|
|
|
f();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleTurnedCard(o, f) {
|
2020-01-15 18:01:07 +01:00
|
|
|
if(state.step == "Turned") {
|
2020-01-14 17:27:56 +01:00
|
|
|
setTurned(o.state.public.step.contents);
|
|
|
|
} else {
|
2020-01-15 18:01:07 +01:00
|
|
|
if(state.step == "ToPlay" && o.state.public.playing == o.state.public.oyake) {
|
2020-01-16 16:45:23 +01:00
|
|
|
rest.className = ["card", "turn" + o.state.public.gameState.turns].join(' ');
|
2020-01-14 17:27:56 +01:00
|
|
|
}
|
|
|
|
if(deck.lastChild.id != "rest") {
|
|
|
|
deck.removeChild(deck.lastChild);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function askKoikoi(o, f) {
|
|
|
|
Screen.dialog({
|
|
|
|
text: I18n.get('youScored'),
|
|
|
|
answers: [
|
|
|
|
{label: 'endRound', action: function() {play({koiKoi: false}); f();}},
|
|
|
|
{label: 'koikoi', action: function() {play({koiKoi: true}); f();}}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function theyScored(o, f) {
|
|
|
|
Screen.dialog({
|
|
|
|
text: I18n.get('theyScored')(players.get(o.state.public.playing)),
|
|
|
|
answers: [
|
|
|
|
{label: 'ok', action: f}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function gameEnd(o, f) {
|
|
|
|
var winner, maxScore;
|
|
|
|
for(var key in o.state.public.scores) {
|
|
|
|
if(maxScore == undefined || o.state.public.scores[key] > maxScore) {
|
|
|
|
winner = key;
|
|
|
|
maxScore = o.state.public.scores[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Screen.dialog({
|
|
|
|
text: I18n.get(Session.is(winner) ? 'won' : 'lost'),
|
|
|
|
answers: [{
|
|
|
|
label: 'endGame',
|
|
|
|
action: function() {
|
|
|
|
Messaging.send({tag: "Quit"});
|
|
|
|
Screen.select('reception');
|
|
|
|
f();
|
|
|
|
}
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function applyDiff(o) {
|
|
|
|
return Async.sequence.apply(null,
|
|
|
|
o.logs.map(animate).concat(
|
|
|
|
Async.apply(setStatus, o.state),
|
|
|
|
handleStep(o)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function setStatus(game) {
|
2020-01-15 18:01:07 +01:00
|
|
|
Dom.clear(dom.status);
|
|
|
|
state.game = game;
|
|
|
|
state.step = game.public.step.tag;
|
|
|
|
if(game.public.month != state.month) {
|
|
|
|
state.month = game.public.month;
|
2020-01-14 17:27:56 +01:00
|
|
|
}
|
2020-01-15 18:01:07 +01:00
|
|
|
dom.status.appendChild(
|
|
|
|
Dom.make('li', {textContent: I18n.get('monthFlower')(I18n.get(state.month))})
|
2020-01-14 17:27:56 +01:00
|
|
|
);
|
|
|
|
var turn = null;
|
2020-01-15 18:01:07 +01:00
|
|
|
state.playing = Session.is(game.public.playing);
|
|
|
|
if(state.playing) {
|
|
|
|
sets.you.hand.dom.classList.toggle("yourTurn", state.step == "ToPlay");
|
2020-01-14 17:27:56 +01:00
|
|
|
turn = I18n.get("yourTurn");
|
|
|
|
} else {
|
|
|
|
sets.you.hand.dom.classList.remove("yourTurn");
|
|
|
|
turn = I18n.get('playing')(players.get(game.public.playing));
|
|
|
|
}
|
2020-01-15 18:01:07 +01:00
|
|
|
dom.status.appendChild(Dom.make('li', {textContent: turn}));
|
2020-01-14 17:27:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function setCaptures(game) {
|
|
|
|
for(var key in game.public.players) {
|
|
|
|
var elem = document.getElementById(Session.is(key) ? "you" : "them");
|
|
|
|
elem.getElementsByClassName('score')[0].textContent = game.public.scores[key] + " pts";
|
|
|
|
var byClass = {}
|
|
|
|
Object.values(Hanafuda.Family).forEach(function(family) {
|
|
|
|
byClass[family.class] = elem.getElementsByClassName(family.class)[0];
|
|
|
|
Dom.clear(byClass[family.class]);
|
|
|
|
});
|
|
|
|
game.public.players[key].meld.forEach(function(cardName) {
|
2020-01-15 18:01:07 +01:00
|
|
|
var card = Card.make(cardName);
|
2020-01-14 17:27:56 +01:00
|
|
|
byClass[card.value.family.class].appendChild(card.dom);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function setCardSet(set, cardNames, constructor) {
|
2020-01-16 16:45:23 +01:00
|
|
|
constructor = constructor || Card.make;
|
2020-01-14 17:27:56 +01:00
|
|
|
set.card = {};
|
|
|
|
Dom.clear(set.dom);
|
|
|
|
cardNames.forEach(function(cardName) {
|
2020-01-15 18:01:07 +01:00
|
|
|
var card = constructor(cardName);
|
2020-01-14 17:27:56 +01:00
|
|
|
set.card[cardName] = card;
|
|
|
|
set.dom.appendChild(card.dom);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function setTheirCards(game) {
|
|
|
|
var turnsTheyPlayed = Math.floor(
|
2020-01-15 18:01:07 +01:00
|
|
|
(game.public.gameState.turns + (Session.is(game.public.oyake) ? 0 : 1)) / 2
|
2020-01-14 17:27:56 +01:00
|
|
|
);
|
|
|
|
Dom.clear(sets.them.hand.dom);
|
|
|
|
for(var i = 0; i < 8 - turnsTheyPlayed; i++) {
|
|
|
|
sets.them.hand.dom.appendChild(Dom.make('li', {class: "card"}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function setTurned(cardName) {
|
2020-01-15 18:01:07 +01:00
|
|
|
state.turnedCard = TurnedCard.make(cardName);
|
|
|
|
if(state.playing) {
|
2020-01-16 16:45:23 +01:00
|
|
|
select(state.turnedCard);
|
2020-01-14 17:27:56 +01:00
|
|
|
}
|
|
|
|
}
|