Start importing Game Screen module, everything is broken due to class prototype definitions, also start cutting this gigantic module into small ones
This commit is contained in:
parent
66cade4cb2
commit
2563a44c11
15 changed files with 563 additions and 18 deletions
|
@ -3,8 +3,8 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>KoiKoi</title>
|
<title>KoiKoi</title>
|
||||||
<script src="main.js"></script>
|
<script src="../main.js"></script>
|
||||||
<link rel="stylesheet" href="skin.css" type="text/css"/>
|
<link rel="stylesheet" href="../skin.css" type="text/css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="game">
|
<div id="game">
|
||||||
|
|
21
js/GUI/Card.js
Normal file
21
js/GUI/Card.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import Hanafuda;
|
||||||
|
import * as Dom from UnitJS.Dom;
|
||||||
|
|
||||||
|
function Card(name) {
|
||||||
|
this.value = Hanafuda.Card[name];
|
||||||
|
this.name = name;
|
||||||
|
this.dom = Dom.make('li', {
|
||||||
|
class: [
|
||||||
|
"card",
|
||||||
|
"value" + Hanafuda.getValue(this.value),
|
||||||
|
"month" + this.value.flower
|
||||||
|
],
|
||||||
|
onClick: this.onClick()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Card.prototype.onClick = function() {return function() {};};
|
||||||
|
|
||||||
|
return {
|
||||||
|
Card: Card
|
||||||
|
};
|
28
js/GUI/Card/HandCard.js
Normal file
28
js/GUI/Card/HandCard.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
function HandCard() {
|
||||||
|
Card.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
HandCard.prototype.onClick = function() {
|
||||||
|
var card = this;
|
||||||
|
return function() {
|
||||||
|
if(status.playing && status.step == "ToPlay") {
|
||||||
|
if(selected != undefined) {
|
||||||
|
selected.setSelected(false);
|
||||||
|
} else {
|
||||||
|
card.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
HandCard.prototype.setSelected = setSelected;
|
||||||
|
|
||||||
|
HandCard.prototype.play = function() {
|
||||||
|
var matching = matchingInRiver(this.value);
|
||||||
|
if(matching.length > 1) {
|
||||||
|
this.setSelected(true);
|
||||||
|
} else {
|
||||||
|
play({play: this.name});
|
||||||
|
}
|
||||||
|
}
|
27
js/GUI/Card/RiverCard.js
Normal file
27
js/GUI/Card/RiverCard.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
function RiverCard() {
|
||||||
|
Card.apply(this, arguments);
|
||||||
|
this.candidate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RiverCard.prototype.onClick = function() {
|
||||||
|
var card = this;
|
||||||
|
return function() {
|
||||||
|
if(card.candidate) {
|
||||||
|
var withCard = selected.name;
|
||||||
|
selected.setSelected(false);
|
||||||
|
play(
|
||||||
|
status.step == 'ToPlay' ? {capture: [withCard, card.name]} : {choose: card.name}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
RiverCard.prototype.setCandidate = function(yes) {
|
||||||
|
this.candidate = yes;
|
||||||
|
this.dom.classList.toggle("candidate", yes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
RiverCard: RiverCard
|
||||||
|
};
|
13
js/GUI/Card/TurnedCard.js
Normal file
13
js/GUI/Card/TurnedCard.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
function TurnedCard() {
|
||||||
|
Card.apply(this, arguments);
|
||||||
|
this.dom.id = "turned";
|
||||||
|
deck.appendChild(this.dom);
|
||||||
|
}
|
||||||
|
|
||||||
|
TurnedCard.prototype.onClick = Card.prototype.onClick;
|
||||||
|
TurnedCard.prototype.setSelected = setSelected;
|
||||||
|
|
||||||
|
return {
|
||||||
|
TurnedCard: TurnedCard
|
||||||
|
};
|
343
js/GUI/Screen/Game.js
Normal file
343
js/GUI/Screen/Game.js
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
import Hanafuda;
|
||||||
|
import I18n;
|
||||||
|
import Messaging;
|
||||||
|
import players from Room;
|
||||||
|
import * as Screen from GUI.Screen;
|
||||||
|
import Session;
|
||||||
|
import StatusHandler;
|
||||||
|
import * as Async from UnitJS.Async;
|
||||||
|
import * as Dom from UnitJS.Dom;
|
||||||
|
import * as Fun from UnitJS.Fun;
|
||||||
|
|
||||||
|
var deck = document.getElementById("deck");
|
||||||
|
var rest = document.getElementById("rest");
|
||||||
|
var status = {
|
||||||
|
dom: document.getElementById("status"),
|
||||||
|
game: null,
|
||||||
|
playing: false,
|
||||||
|
step: null,
|
||||||
|
month: null
|
||||||
|
};
|
||||||
|
var sets;
|
||||||
|
var selected = null;
|
||||||
|
var turnedCard = null;
|
||||||
|
var queue = [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(state) {
|
||||||
|
sets = buildSets();
|
||||||
|
window.addEventListener('focus', runQueue);
|
||||||
|
Messaging.addEventListener(["Game"], function(o) {
|
||||||
|
queue.push(handleGameMessage(o));
|
||||||
|
if(document.hasFocus() && queue.length == 1) {
|
||||||
|
runQueue();
|
||||||
|
} else {
|
||||||
|
StatusHandler.set("♪");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Async.run(setGame({tag: "Game", state: state, logs: []}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSets() {
|
||||||
|
var sets = {};
|
||||||
|
['river', 'you', 'them'].forEach(function(id) {
|
||||||
|
var dom = document.getElementById(id);
|
||||||
|
if(dom.tagName.toLowerCase() == 'ul') {
|
||||||
|
sets[id] = {card: null, dom: dom};
|
||||||
|
} else {
|
||||||
|
sets[id] = {};
|
||||||
|
for(var i = 0; i < dom.children.length; i++) {
|
||||||
|
if(dom.children[i].tagName.toLowerCase() == 'ul') {
|
||||||
|
sets[id][dom.children[i].className] = {card: {}, dom: dom.children[i]};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return sets;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runQueue() {
|
||||||
|
if(queue.length > 0) {
|
||||||
|
var length = queue.length;
|
||||||
|
Async.run.apply(null, queue.concat(
|
||||||
|
Async.apply(function() {
|
||||||
|
queue = queue.slice(length);
|
||||||
|
runQueue();
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGameMessage(o) {
|
||||||
|
if(o.state.public.turns == 0) {
|
||||||
|
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);
|
||||||
|
[
|
||||||
|
[sets.river, o.state.public.river, RiverCard],
|
||||||
|
[sets.you.hand, o.state.playerHand, HandCard]
|
||||||
|
].forEach(function(args) {setCardSet.apply(null, args)});
|
||||||
|
setTheirCards(o.state);
|
||||||
|
handleStep(o)(f);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleStep(o) {
|
||||||
|
return function(f) {
|
||||||
|
handleTurnedCard(o, f);
|
||||||
|
if(status.step == "Scored") {
|
||||||
|
if(status.playing) {
|
||||||
|
askKoikoi(o, f);
|
||||||
|
} else {
|
||||||
|
theyScored(o, f);
|
||||||
|
}
|
||||||
|
} else if (status.step == "Over") {
|
||||||
|
gameEnd(o, f);
|
||||||
|
} else {
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTurnedCard(o, f) {
|
||||||
|
if(status.step == "Turned") {
|
||||||
|
setTurned(o.state.public.step.contents);
|
||||||
|
} else {
|
||||||
|
if(status.step == "ToPlay" && o.state.public.playing == o.state.public.oyake) {
|
||||||
|
rest.className = ["card", "turn" + o.state.public.turns].join(' ');
|
||||||
|
}
|
||||||
|
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 animate(movement) {
|
||||||
|
return Async.bind(
|
||||||
|
Async.apply(function() {
|
||||||
|
var card;
|
||||||
|
var movingCards = [];
|
||||||
|
var side = (status.playing) ? 'you' : 'them';
|
||||||
|
var dest = sets.river;
|
||||||
|
if(movement.captures != undefined) {
|
||||||
|
card = new Card(movement.played);
|
||||||
|
dest = sets[side];
|
||||||
|
movingCards.push([sets.river, dest, new Card(movement.captures)]);
|
||||||
|
} else {
|
||||||
|
card = new RiverCard(movement.played);
|
||||||
|
}
|
||||||
|
if(movement.source == 'Hand') {
|
||||||
|
movingCards.push([sets[side].hand, dest, card]);
|
||||||
|
} else {
|
||||||
|
var cardSet = {};
|
||||||
|
cardSet[card.name] = turnedCard || new TurnedCard(card.name);
|
||||||
|
turnedCard = null;
|
||||||
|
movingCards.push([{card: cardSet, dom: deck}, dest, card]);
|
||||||
|
}
|
||||||
|
return movingCards;
|
||||||
|
}),
|
||||||
|
function(movingCards) {
|
||||||
|
return Async.parallel.apply(null,
|
||||||
|
movingCards.map(function(args) { return moveCard.apply(null, args); })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveCard(fromSet, toSet, card) {
|
||||||
|
var from, originalCard;
|
||||||
|
var slot = Dom.make('li', {class: ['card', 'slot']});
|
||||||
|
if (fromSet.card[card.name] != undefined) {
|
||||||
|
originalCard = fromSet.card[card.name].dom;
|
||||||
|
delete fromSet.card[card.name];
|
||||||
|
} else {
|
||||||
|
var originalCard = fromSet.dom.children[fromSet.dom.children.length - 1];
|
||||||
|
}
|
||||||
|
from = originalCard.getBoundingClientRect();
|
||||||
|
fromSet.dom.replaceChild(slot, originalCard);
|
||||||
|
card.dom.style.visibility = 'hidden';
|
||||||
|
insertCard(toSet, card);
|
||||||
|
var to = card.dom.getBoundingClientRect();
|
||||||
|
card.dom.style.left = (from.left - to.left) + 'px';
|
||||||
|
card.dom.style.top = (from.top - to.top) + 'px';
|
||||||
|
card.dom.classList.add('moving');
|
||||||
|
card.dom.style.visibility = null;
|
||||||
|
return Async.sequence(
|
||||||
|
Async.wait(10),
|
||||||
|
Async.apply(function() {
|
||||||
|
card.dom.style.left = 0;
|
||||||
|
card.dom.style.top = 0;
|
||||||
|
}),
|
||||||
|
Async.wait(1000),
|
||||||
|
Async.apply(function() {
|
||||||
|
fromSet.dom.removeChild(slot);
|
||||||
|
card.dom.classList.remove('moving');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertCard(toSet, card) {
|
||||||
|
if(toSet.dom != undefined) {
|
||||||
|
toSet.card[card.name] = card;
|
||||||
|
toSet.dom.appendChild(card.dom);
|
||||||
|
} else {
|
||||||
|
insertCard(toSet[card.value.family.class], card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function play(move) {
|
||||||
|
Messaging.send({
|
||||||
|
tag: "Play",
|
||||||
|
move: move,
|
||||||
|
onGame: status.game
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchingInRiver(card) {
|
||||||
|
return Fun.mapFilter(
|
||||||
|
Fun.of(sets.river.card),
|
||||||
|
Fun.defined
|
||||||
|
)(Hanafuda.sameMonth(card).map(Fun.proj('name')));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStatus(game) {
|
||||||
|
Dom.clear(status.dom);
|
||||||
|
status.game = game;
|
||||||
|
status.step = game.public.step.tag;
|
||||||
|
if(game.public.month != status.month) {
|
||||||
|
status.month = game.public.month;
|
||||||
|
}
|
||||||
|
status.dom.appendChild(
|
||||||
|
Dom.make('li', {textContent: I18n.get('monthFlower')(I18n.get(status.month))})
|
||||||
|
);
|
||||||
|
var turn = null;
|
||||||
|
status.playing = Session.is(game.public.playing);
|
||||||
|
if(status.playing) {
|
||||||
|
sets.you.hand.dom.classList.toggle("yourTurn", status.step == "ToPlay");
|
||||||
|
turn = I18n.get("yourTurn");
|
||||||
|
} else {
|
||||||
|
sets.you.hand.dom.classList.remove("yourTurn");
|
||||||
|
turn = I18n.get('playing')(players.get(game.public.playing));
|
||||||
|
}
|
||||||
|
status.dom.appendChild(Dom.make('li', {textContent: turn}));
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
var card = new Card(cardName);
|
||||||
|
byClass[card.value.family.class].appendChild(card.dom);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCardSet(set, cardNames, constructor) {
|
||||||
|
constructor = constructor || Card;
|
||||||
|
set.card = {};
|
||||||
|
Dom.clear(set.dom);
|
||||||
|
cardNames.forEach(function(cardName) {
|
||||||
|
var card = new constructor(cardName);
|
||||||
|
set.card[cardName] = card;
|
||||||
|
set.dom.appendChild(card.dom);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTheirCards(game) {
|
||||||
|
var turnsTheyPlayed = Math.floor(
|
||||||
|
(game.public.turns + (Session.is(game.public.oyake) ? 0 : 1)) / 2
|
||||||
|
);
|
||||||
|
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) {
|
||||||
|
turnedCard = new TurnedCard(cardName);
|
||||||
|
if(status.playing) {
|
||||||
|
selected = turnedCard;
|
||||||
|
showCandidates(Hanafuda.Card[cardName], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCandidates(card, yes) {
|
||||||
|
matchingInRiver(card).forEach(function(riverCard) {riverCard.setCandidate(yes);});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelected(yes) {
|
||||||
|
selected = yes ? this : null;
|
||||||
|
this.dom.classList.toggle('selected', yes);
|
||||||
|
showCandidates(this.value, yes);
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ return {
|
||||||
};
|
};
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
Players.init();
|
||||||
|
GamesGUI.init();
|
||||||
Messaging.addEventListener(["Okaeri"], function(o) {
|
Messaging.addEventListener(["Okaeri"], function(o) {
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,12 +6,17 @@ import players from Room;
|
||||||
import dialog from GUI.Screen;
|
import dialog from GUI.Screen;
|
||||||
import * as Dom from UnitJS.Dom;
|
import * as Dom from UnitJS.Dom;
|
||||||
|
|
||||||
var list = ListSelector.make('games', showGame);
|
var list;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
init: init,
|
||||||
refresh: refresh
|
refresh: refresh
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
list = ListSelector.make('games', showGame);
|
||||||
|
}
|
||||||
|
|
||||||
function showGame(game) {
|
function showGame(game) {
|
||||||
var liContent;
|
var liContent;
|
||||||
if(game.key.match(/^Player#/)) { // Game proposals use the ID of the opponent as ID
|
if(game.key.match(/^Player#/)) { // Game proposals use the ID of the opponent as ID
|
||||||
|
@ -47,7 +52,7 @@ function pendingGame(game) {
|
||||||
Dom.make('span', { textContent: status}),
|
Dom.make('span', { textContent: status}),
|
||||||
Dom.make('a', {
|
Dom.make('a', {
|
||||||
textContent: I18n.get('pendingGame')(game.value.yourTurn, game.value.vs.name),
|
textContent: I18n.get('pendingGame')(game.value.yourTurn, game.value.vs.name),
|
||||||
href: '/game/' + game.key
|
href: '/game/' + game.key.replace(/Game#/, '')
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,18 @@ import Messaging;
|
||||||
import players from Room;
|
import players from Room;
|
||||||
import * as Dom from UnitJS.Dom;
|
import * as Dom from UnitJS.Dom;
|
||||||
|
|
||||||
var form = ConnectedForm.get('room');
|
var form;
|
||||||
var list = ListSelector.make('players', showPlayer);
|
var list;
|
||||||
var them = null;
|
var them;
|
||||||
initDOM();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
init: init,
|
||||||
refresh: refresh
|
refresh: refresh
|
||||||
};
|
};
|
||||||
|
|
||||||
function initDOM() {
|
function init() {
|
||||||
|
form = ConnectedForm.get('room');
|
||||||
|
list = ListSelector.make('players', showPlayer);
|
||||||
form.root.getElementsByTagName('label')[0].textContent = I18n.get('startGameWith');
|
form.root.getElementsByTagName('label')[0].textContent = I18n.get('startGameWith');
|
||||||
form.root.invite.value = I18n.get('invite');
|
form.root.invite.value = I18n.get('invite');
|
||||||
form.root.addEventListener('submit', function(e) {
|
form.root.addEventListener('submit', function(e) {
|
||||||
|
|
|
@ -5,14 +5,16 @@ import Messaging;
|
||||||
import Session;
|
import Session;
|
||||||
import Save;
|
import Save;
|
||||||
|
|
||||||
var login = GUI.ConnectedForm.get('login');
|
var login;
|
||||||
var form = login.root;
|
var form;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init
|
init: init
|
||||||
};
|
};
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
login = GUI.ConnectedForm.get('login');
|
||||||
|
form = login.root;
|
||||||
initDOM();
|
initDOM();
|
||||||
initMessageHandlers();
|
initMessageHandlers();
|
||||||
var name = Save.get('player.name');
|
var name = Save.get('player.name');
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Messaging;
|
import Messaging;
|
||||||
import opponent from Room;
|
import player from Room;
|
||||||
import Save;
|
import Save;
|
||||||
import Session;
|
import Session;
|
||||||
import Table;
|
import Table;
|
||||||
|
@ -17,7 +17,7 @@ return {
|
||||||
function makeEntry(state) {
|
function makeEntry(state) {
|
||||||
var sessionKey = Session.getKey();
|
var sessionKey = Session.getKey();
|
||||||
return Time.timestamp({
|
return Time.timestamp({
|
||||||
vs: opponent(state.public.nextPlayer[sessionKey]),
|
vs: player(state.public.nextPlayer[sessionKey]),
|
||||||
yourTurn: state.public.playing == sessionKey
|
yourTurn: state.public.playing == sessionKey
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ function makeEntry(state) {
|
||||||
function proposal(playerID, yourTurn) {
|
function proposal(playerID, yourTurn) {
|
||||||
entries.insert(
|
entries.insert(
|
||||||
playerID,
|
playerID,
|
||||||
Time.timestamp({vs: opponent(playerID), yourTurn: yourTurn})
|
Time.timestamp({vs: player(playerID), yourTurn: yourTurn})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
78
js/Hanafuda.js
Normal file
78
js/Hanafuda.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
var Flower = Object.freeze({
|
||||||
|
Pine: 0,
|
||||||
|
Plum: 1,
|
||||||
|
Cherry: 2,
|
||||||
|
Wisteria: 3,
|
||||||
|
Iris: 4,
|
||||||
|
Peony: 5,
|
||||||
|
BushClover: 6,
|
||||||
|
SusukiGrass: 7,
|
||||||
|
Chrysanthemum: 8,
|
||||||
|
Maple: 9,
|
||||||
|
Willow: 10,
|
||||||
|
Paulownia: 11
|
||||||
|
});
|
||||||
|
|
||||||
|
var Family = Object.freeze(
|
||||||
|
["Kasu", "Tan", "Tane", "Hikari"].reduce(function(o, name) {
|
||||||
|
o[name] = {class: name[0].toLowerCase() + name.slice(1)};
|
||||||
|
return o;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
|
||||||
|
var CardNames = [
|
||||||
|
"Pine0", "Pine1", "PinePoetry", "Crane",
|
||||||
|
"Plum0", "Plum1", "PlumPoetry", "BushWarbler",
|
||||||
|
"Cherry0", "Cherry1", "CherryPoetry", "CampCurtain",
|
||||||
|
"Wisteria0", "Wisteria1", "WisteriaRed", "Cuckoo",
|
||||||
|
"Iris0", "Iris1", "IrisRed", "EightPlankBridge",
|
||||||
|
"Peony0", "Peony1", "PeonyBlue", "Butterflies",
|
||||||
|
"BushClover0", "BushClover1", "BushCloverRed", "Boar",
|
||||||
|
"SusukiGrass0", "SusukiGrass1", "Geese", "FullMoon",
|
||||||
|
"Chrysanthemum0", "Chrysanthemum1", "ChrysanthemumBlue", "SakeCup",
|
||||||
|
"Maple0", "Maple1", "MapleBlue", "Deer",
|
||||||
|
"Lightning", "WillowRed", "Swallow", "RainMan",
|
||||||
|
"Paulownia0", "Paulownia1", "Sand", "Phoenix"
|
||||||
|
];
|
||||||
|
|
||||||
|
var Card = Object.freeze(
|
||||||
|
CardNames.reduce(function(o, name, i) {
|
||||||
|
o[name] = {
|
||||||
|
id: i,
|
||||||
|
family: findFamily(name, i),
|
||||||
|
flower: Math.floor(i / 4),
|
||||||
|
name: name
|
||||||
|
};
|
||||||
|
return o;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Flower: Flower,
|
||||||
|
Family: Family,
|
||||||
|
Card: Card,
|
||||||
|
getValue: getValue,
|
||||||
|
sameMonth: sameMonth
|
||||||
|
};
|
||||||
|
|
||||||
|
function findFamily(name, i) {
|
||||||
|
if((i % 4 < 2 && i < 41) || (i > 43 && i < 47)) {
|
||||||
|
return Family.Kasu;
|
||||||
|
} else if(name.match(/(Blue|Poetry|Red)/)) {
|
||||||
|
return Family.Tan;
|
||||||
|
} else if(["Crane", "CampCurtain", "FullMoon", "RainMan", "Phoenix"].includes(name)) {
|
||||||
|
return Family.Hikari;
|
||||||
|
} else {
|
||||||
|
return Family.Tane;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValue(card) {
|
||||||
|
var first = 4 * card.flower;
|
||||||
|
return card.id - first;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sameMonth(card) {
|
||||||
|
var first = 4 * card.flower;
|
||||||
|
return [0,1,2,3].map(function(i) {return Card[CardNames[first + i]];});
|
||||||
|
}
|
20
js/Main.js
20
js/Main.js
|
@ -1,5 +1,25 @@
|
||||||
|
import I18n;
|
||||||
|
import * as Screen from GUI.Screen;
|
||||||
import * as Login from GUI.Screen.Login;
|
import * as Login from GUI.Screen.Login;
|
||||||
import * as Hall from GUI.Screen.Hall;
|
import * as Hall from GUI.Screen.Hall;
|
||||||
|
import * as Game from GUI.Screen.Game;
|
||||||
|
import Save;
|
||||||
|
|
||||||
|
var gamePath = window.location.pathname.match(/\/game\/(?<id>[0-9A-Fa-f]+)/);
|
||||||
|
|
||||||
|
if(gamePath) {
|
||||||
|
var gameState = Save.get('games.state.Game#' + gamePath.groups.id);
|
||||||
|
if(gameState != undefined) {
|
||||||
|
Game.init(gameState);
|
||||||
|
} else {
|
||||||
|
Screen.dialog({
|
||||||
|
text: I18n.get('gameNotFound'),
|
||||||
|
answers: [
|
||||||
|
{label: 'backToMain', action: function() {window.location = '..';}}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Login.init();
|
Login.init();
|
||||||
Hall.init();
|
Hall.init();
|
||||||
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ var players = Table.make(function(o) {return o.value});
|
||||||
initMessageHandlers();
|
initMessageHandlers();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
opponent: opponent,
|
player: player,
|
||||||
players: players
|
players: players
|
||||||
};
|
};
|
||||||
|
|
||||||
function opponent(key) {
|
function player(key) {
|
||||||
return {id: key, name: players.get(key)};
|
return {id: key, name: players.get(key)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,11 @@ return {
|
||||||
Wisteria: "wisteria",
|
Wisteria: "wisteria",
|
||||||
accept: "Let's go !",
|
accept: "Let's go !",
|
||||||
alone: "No one to play with yet ! Wait a little",
|
alone: "No one to play with yet ! Wait a little",
|
||||||
|
backToMain: "Back to main menu",
|
||||||
decline: "No thanks",
|
decline: "No thanks",
|
||||||
endRound: "End the round",
|
endRound: "End the round",
|
||||||
endGame: "Return to main menu",
|
endGame: "Return to main menu",
|
||||||
|
gameNotFound: "You followed a fishy link, this game is no more",
|
||||||
join: "Join",
|
join: "Join",
|
||||||
invite: "Invite",
|
invite: "Invite",
|
||||||
koikoi: "KoiKoi !!",
|
koikoi: "KoiKoi !!",
|
||||||
|
@ -72,9 +74,11 @@ return {
|
||||||
Wisteria: "glycines",
|
Wisteria: "glycines",
|
||||||
accept: "C'est parti !",
|
accept: "C'est parti !",
|
||||||
alone: "Personne pour jouer pour l'instant ! Attendez un peu",
|
alone: "Personne pour jouer pour l'instant ! Attendez un peu",
|
||||||
|
backToMain: "Retourner au menu principal",
|
||||||
decline: "Non merci",
|
decline: "Non merci",
|
||||||
endRound: "Finir la manche",
|
endRound: "Finir la manche",
|
||||||
endGame: "Retourner au menu principal",
|
endGame: "Retourner au menu principal",
|
||||||
|
gameNotFound: "Ce lien est louche, la partie n'est plus",
|
||||||
join: "Entrer",
|
join: "Entrer",
|
||||||
invite: "Inviter",
|
invite: "Inviter",
|
||||||
koikoi: "KoiKoi !!",
|
koikoi: "KoiKoi !!",
|
||||||
|
|
Loading…
Reference in a new issue