Compare commits

..

No commits in common. "main" and "card-modules" have entirely different histories.

21 changed files with 193 additions and 467 deletions

View file

@ -7,24 +7,15 @@
<link rel="stylesheet" href="skin.css" type="text/css"/>
</head>
<body>
<ul id="sidebar" class="unactive"></ul>
<div id="login" class="on">
<div id="reception" class="on">
<h1>KoiKoi</h1>
<form id="loginForm">
<form id="login">
<input type="submit" name="submitButton" hidden disabled/>
<p id="join">
<label for="you"></label><input type="text" name="you"/>
<input type="submit" name="join" disabled/>
</p>
</form>
<form id="accountLoader">
<input type="submit" name="submitButton" hidden disabled/>
<p>or</p>
<p id="loadAccount">
<label for="pickFile"></label><input type="file" name="pickFile" accept="application/json,.json"/>
<input type="submit" name="doLoad" disabled/>
</p>
</form>
</div>
<div id="hall">
<form id="room">
@ -43,11 +34,6 @@
<ul></ul>
</div>
</div>
<div id="settings">
<p id="export">
<span></span><a download="koikoi.json" href=""></a>
</p>
</div>
<div id="dialog">
</div>
<p id="error"></p>

View file

@ -11,7 +11,7 @@ function HandCard(name) {
return card;
function onClick() {
if(State.globalState.playing && State.globalState.step == "ToPlay") {
if(State.state.playing && State.state.step == "ToPlay") {
if(State.getSelected() != undefined) {
State.select(false);
} else {

View file

@ -17,7 +17,7 @@ function RiverCard(name) {
var withCard = State.getSelected().value.name;
State.select(false);
State.play(
State.globalState.step == 'ToPlay' ?
State.state.step == 'ToPlay' ?
{capture: [withCard, name]} : {choose: name}
);
}

View file

@ -1,7 +1,6 @@
import * as Dom from UnitJS.Dom;
import I18n;
var sidebar = document.getElementById('sidebar');
var current = document.querySelector("body > div.on");
var errorBox = document.getElementById('error');
errorBox.addEventListener('click', function() {
@ -11,10 +10,15 @@ errorBox.addEventListener('click', function() {
return {
error: error,
dialog: dialog,
register: register,
select: select
};
function select(name) {
current.className = "";
current = document.getElementById(name);
current.className = "on";
}
function closeAndRun(dialog, action) {
return function() {
dialog.className = '';
@ -43,17 +47,3 @@ function error(message) {
errorBox.textContent = message;
errorBox.className = "on";
}
function register(name) {
sidebar.appendChild(Dom.make('li', {
onClick: function() {select(name);},
textContent: name
}));
}
function select(name) {
sidebar.className = "";
current.className = "";
current = document.getElementById(name);
current.className = "on";
}

View file

@ -5,7 +5,7 @@ import * as TurnedCard from GUI.Card.TurnedCard;
import * as Screen from GUI.Screen;
import {animate, catchUp, delay, getQueue} from GUI.Screen.Game.Animation;
import {
dom, init as initState, play, select, sets, globalState
dom, init as initState, play, select, sets, state
} from GUI.Screen.Game.State;
import Hanafuda;
import I18n;
@ -27,33 +27,31 @@ function init(gameID) {
initMessageHandlers();
Async.run(
Async.bind(
getSavedStates(gameID),
function(states) {
getSavedState(gameID),
function(o) {
return Async.sequence(
startSession(),
previously(states)
setGame(o)
);
}
)
);
}
function backToMain() {
window.location = '..';
}
function fail(errorCode) {
return function(f) {
Screen.dialog({
text: I18n.get(errorCode),
answers: [{label: 'backToMain', action: backToMain}]
answers: [
{label: 'backToMain', action: function() {window.location = '..';}}
]
});
}
}
function getSavedStates(gameID) {
var states = Save.get('games.state.Game#' + gameID);
return states != undefined ? Async.wrap(states) : fail('gameNotFound');
function getSavedState(gameID) {
var gameState = Save.get('games.message.Game#' + gameID);
return gameState != undefined ? Async.wrap(gameState) : fail('gameNotFound');
}
function startSession() {
@ -66,79 +64,66 @@ function startSession() {
}
}
function previously(states) {
if(states.former != undefined && states.latest.logs.length > 0) {
return Async.sequence(
setGame(states.former),
handleGameMessage(states.latest)
);
} else {
return setGame(states.latest);
}
}
function initMessageHandlers() {
window.addEventListener('focus', catchUp);
Messaging.addEventListener(["Game"], function(o) {
if(o.state.public.coordinates.gameID == globalState.game.public.coordinates.gameID) {
delay(handleGameMessage(o.state));
if(document.hasFocus() && getQueue().length == 1) {
catchUp();
} else {
StatusHandler.set("♪");
}
delay(handleGameMessage(o));
if(document.hasFocus() && getQueue().length == 1) {
catchUp();
} else {
StatusHandler.set("♪");
}
});
}
function handleGameMessage(state) {
if(state.public.coordinates.turn == 0) {
if(state.logs.length > 0) { // but still some logs, from the previous round
return Async.sequence(applyDiff(state), setGame(state)); // so play the diff, then set the new round
function handleGameMessage(o) {
if(o.state.public.gameState.turns == 0 || state.game == null) {
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(state); // directly set a whole new game
return setGame(o); // directly set a whole new game
}
} else {
return applyDiff(state);
return applyDiff(o);
}
}
function setGame(state) {
function setGame(o) {
return function(f) {
setStatus(state);
setCaptures(state);
setStatus(o.state);
setCaptures(o.state);
[
[sets.river, state.public.river, RiverCard.make],
[sets.you.hand, state.playerHand, HandCard.make]
[sets.river, o.state.public.river, RiverCard.make],
[sets.you.hand, o.state.playerHand, HandCard.make]
].forEach(function(args) {setCardSet.apply(null, args)});
setTheirCards(state);
handleStep(state)(f);
setTheirCards(o.state);
handleStep(o)(f);
};
}
function handleStep(state) {
function handleStep(o) {
return function(f) {
handleTurnedCard(state, f);
if(globalState.step == "Scored") {
if(globalState.playing) {
askKoikoi(state, f);
handleTurnedCard(o, f);
if(state.step == "Scored") {
if(state.playing) {
askKoikoi(o, f);
} else {
theyScored(state, f);
theyScored(o, f);
}
} else if (globalState.step == "Over") {
gameEnd(state, f);
} else if (state.step == "Over") {
gameEnd(o, f);
} else {
f();
}
};
}
function handleTurnedCard(state, f) {
if(globalState.step == "Turned") {
setTurned(state.public.step.contents);
function handleTurnedCard(o, f) {
if(state.step == "Turned") {
setTurned(o.state.public.step.contents);
} else {
if(globalState.step == "ToPlay" && state.public.playing == state.public.oyake) {
dom.rest.className = ["card", "turn" + state.public.coordinates.turn].join(' ');
if(state.step == "ToPlay" && o.state.public.playing == o.state.public.oyake) {
rest.className = ["card", "turn" + o.state.public.gameState.turns].join(' ');
}
if(deck.lastChild.id != "rest") {
deck.removeChild(deck.lastChild);
@ -146,7 +131,7 @@ function handleTurnedCard(state, f) {
}
}
function askKoikoi(state, f) {
function askKoikoi(o, f) {
Screen.dialog({
text: I18n.get('youScored'),
answers: [
@ -156,52 +141,59 @@ function askKoikoi(state, f) {
});
}
function theyScored(state, f) {
function theyScored(o, f) {
Screen.dialog({
text: I18n.get('theyScored')(players.get(state.public.playing)),
text: I18n.get('theyScored')(players.get(o.state.public.playing)),
answers: [
{label: 'ok', action: f}
]
});
}
function gameEnd(state, f) {
function gameEnd(o, f) {
var winner, maxScore;
for(var key in state.public.scores) {
if(maxScore == undefined || state.public.scores[key] > maxScore) {
for(var key in o.state.public.scores) {
if(maxScore == undefined || o.state.public.scores[key] > maxScore) {
winner = key;
maxScore = state.public.scores[key];
maxScore = o.state.public.scores[key];
}
}
Screen.dialog({
text: I18n.get(Session.is(winner) ? 'won' : 'lost'),
answers: [{label: 'endGame', action: backToMain}]
answers: [{
label: 'endGame',
action: function() {
Messaging.send({tag: "Quit"});
Screen.select('reception');
f();
}
}]
});
}
function applyDiff(state) {
function applyDiff(o) {
return Async.sequence.apply(null,
state.logs.map(animate).concat(
Async.apply(setStatus, state),
handleStep(state)
o.logs.map(animate).concat(
Async.apply(setStatus, o.state),
handleStep(o)
)
);
}
function setStatus(game) {
Dom.clear(dom.status);
globalState.game = game;
globalState.step = game.public.step.tag;
if(game.public.coordinates.month != globalState.month) {
globalState.month = game.public.coordinates.month;
state.game = game;
state.step = game.public.step.tag;
if(game.public.month != state.month) {
state.month = game.public.month;
}
dom.status.appendChild(
Dom.make('li', {textContent: I18n.get('monthFlower')(I18n.get(globalState.month))})
Dom.make('li', {textContent: I18n.get('monthFlower')(I18n.get(state.month))})
);
var turn = null;
globalState.playing = Session.is(game.public.playing);
if(globalState.playing) {
sets.you.hand.dom.classList.toggle("yourTurn", globalState.step == "ToPlay");
state.playing = Session.is(game.public.playing);
if(state.playing) {
sets.you.hand.dom.classList.toggle("yourTurn", state.step == "ToPlay");
turn = I18n.get("yourTurn");
} else {
sets.you.hand.dom.classList.remove("yourTurn");
@ -239,7 +231,7 @@ function setCardSet(set, cardNames, constructor) {
function setTheirCards(game) {
var turnsTheyPlayed = Math.floor(
(game.public.coordinates.turn + (Session.is(game.public.oyake) ? 0 : 1)) / 2
(game.public.gameState.turns + (Session.is(game.public.oyake) ? 0 : 1)) / 2
);
Dom.clear(sets.them.hand.dom);
for(var i = 0; i < 8 - turnsTheyPlayed; i++) {
@ -248,8 +240,8 @@ function setTheirCards(game) {
}
function setTurned(cardName) {
globalState.turnedCard = TurnedCard.make(cardName);
if(globalState.playing) {
select(globalState.turnedCard);
state.turnedCard = TurnedCard.make(cardName);
if(state.playing) {
select(state.turnedCard);
}
}

View file

@ -14,6 +14,38 @@ return {
getQueue: getQueue
};
function animate(movement) {
return Async.bind(
Async.apply(function() {
var card;
var movingCards = [];
var side = (State.state.playing) ? 'you' : 'them';
var dest = State.sets.river;
if(movement.captures != undefined) {
card = Card.make(movement.played);
dest = State.sets[side];
movingCards.push([State.sets.river, dest, Card.make(movement.captures)]);
} else {
card = RiverCard.make(movement.played);
}
if(movement.source == 'Hand') {
movingCards.push([State.sets[side].hand, dest, card]);
} else {
var cardSet = {};
cardSet[card.value.name] = State.state.turnedCard || TurnedCard.make(card.value.name);
State.state.turnedCard = null;
movingCards.push([{card: cardSet, dom: State.dom.deck}, dest, card]);
}
return movingCards;
}),
function(movingCards) {
return Async.parallel.apply(null,
movingCards.map(function(args) { return moveCard.apply(null, args); })
);
}
);
}
function catchUp() {
if(queue.length > 0) {
var length = queue.length;
@ -34,48 +66,6 @@ function getQueue() {
return queue;
}
function animate(movement) {
return Async.bind(
Async.apply(cardMoves, movement),
function(movingCards) {
return Async.parallel.apply(null, movingCards);
}
)
}
function handleCaptures(movement, movingCards, side) {
if(movement.captures != undefined) {
var dest = State.sets[side];
movingCards.push(moveCard('river', dest, Card.make(movement.captures)));
return {card: Card.make(movement.played), dest: dest};
} else {
return {card: RiverCard.make(movement.played), dest: State.sets.river};
}
}
function handleSource(movement, movingCards, side, cardLeft) {
if(movement.source == 'Hand') {
movingCards.push(moveCard(side, cardLeft.dest, cardLeft.card));
} else {
var cardSet = {};
var name = cardLeft.card.value.name;
cardSet[name] = State.globalState.turnedCard || TurnedCard.make(name);
State.globalState.turnedCard = null;
movingCards.push(
moveCard({card: cardSet, dom: State.dom.deck}, cardLeft.dest, cardLeft.card)
);
}
}
function cardMoves(movement) {
var card;
var movingCards = [];
var side = (State.globalState.playing) ? 'you' : 'them';
var cardLeft = handleCaptures(movement, movingCards, side);
handleSource(movement, movingCards, side, cardLeft);
return movingCards;
}
function insertCard(toSet, card) {
if(toSet.dom != undefined) {
toSet.card[card.value.name] = card;
@ -85,54 +75,34 @@ function insertCard(toSet, card) {
}
}
function getSource(fromSet, card) {
var source, origin;
if(fromSet == 'river') {
source = State.sets.river;
} else if(typeof fromSet == 'object') {
source = fromSet;
} else {
source = State.sets[fromSet].hand;
if(fromSet == 'them') {
origin = source.dom.children[source.dom.children.length - 1];
}
}
origin = origin || source.card[card.value.name].dom;
delete source.card[card.value.name];
return {dom: source.dom, origin: origin};
}
function offsetInPlaceOf(referenceCard, targetCard) {
var from = referenceCard.getBoundingClientRect();
var to = targetCard.getBoundingClientRect();
targetCard.style.left = (from.left - to.left) + 'px';
targetCard.style.top = (from.top - to.top) + 'px';
targetCard.classList.add('moving');
targetCard.style.visibility = null;
}
function resetPostion(card) {
return function() {card.dom.style.left = 0; card.dom.style.top = 0;};
}
function cleanUpMove(source, card, slot) {
return function() {
source.dom.removeChild(slot);
card.dom.classList.remove('moving');
};
}
function moveCard(fromSet, toSet, card) {
var source = getSource(fromSet, card);
var from, originalCard;
var slot = Dom.make('li', {class: ['card', 'slot']});
source.dom.replaceChild(slot, source.origin);
if (fromSet.card[card.value.name] != undefined) {
originalCard = fromSet.card[card.value.name].dom;
delete fromSet.card[card.value.name];
} else {
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);
offsetInPlaceOf(slot, card.dom)
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(resetPostion(card)),
Async.apply(function() {
card.dom.style.left = 0;
card.dom.style.top = 0;
}),
Async.wait(1000),
Async.apply(cleanUpMove(source, card, slot))
Async.apply(function() {
fromSet.dom.removeChild(slot);
card.dom.classList.remove('moving');
})
);
}

View file

@ -9,7 +9,7 @@ var dom = {
};
var selected;
var sets = {};
var globalState = {
var state = {
game: null,
playing: false,
step: null,
@ -25,7 +25,7 @@ return {
play: play,
select: select,
sets: sets,
globalState: globalState
state: state
};
function init() {
@ -64,7 +64,7 @@ function play(move) {
Messaging.send({
tag: "Play",
move: move,
onGame: globalState.game
onGame: state.game
});
}

View file

@ -1,7 +1,6 @@
import * as Dom from UnitJS.Dom;
import Games;
import I18n;
import register from GUI.Screen;
import * as Players from GUI.Screen.Hall.Players;
import * as GamesGUI from GUI.Screen.Hall.Games;
import Messaging;
@ -12,7 +11,6 @@ return {
};
function init() {
register('hall');
Players.init();
GamesGUI.init();
Messaging.addEventListener(["Okaeri"], function(o) {
@ -26,7 +24,7 @@ function init() {
});
Messaging.addEventListener(["LogOut"], function(o) {
// Just in case there was a game proposal from that player, in which case the game proposal's ID is the player's ID
Games.metadata.remove(o.from);
Games.entries.remove(o.from);
refresh();
});
Messaging.addEventListener(["Relay", "Invitation"], function(o) {
@ -35,12 +33,12 @@ function init() {
GamesGUI.refresh();
});
Messaging.addEventListener(["Relay", "Answer"], function(o) {
var gameEntry = Games.metadata.get(o.from);
var gameEntry = Games.entries.get(o.from);
if(gameEntry != undefined) {
if(!o.message.accept) {
gameEntry.answer = false;
} else {
Games.metadata.remove(o.from);
Games.entries.remove(o.from);
}
GamesGUI.refresh();
}

View file

@ -32,7 +32,7 @@ function gameProposal(game) {
if(game.value.answer != undefined) {
properties.textContent = I18n.get('refusedGame')(game.value.vs.name);
properties.class = 'clickable';
properties.onClick = function() {Games.metadata.remove(game.key); refresh();};
properties.onClick = function() {Games.entries.remove(game.key); refresh();};
} else {
properties.textContent = I18n.get('proposedGame')(
game.value.yourTurn,
@ -60,7 +60,7 @@ function pendingGame(game) {
function answer(key, accept) {
return function() {
Messaging.send({tag: "Answer", accept: accept, to: key});
Games.metadata.remove(key);
Games.entries.remove(key);
refresh();
}
}
@ -79,7 +79,7 @@ function answerDialog(key) {
}
function refresh() {
var sortedGames = Games.metadata.getAll();
var sortedGames = Games.entries.getAll();
list.refresh(sortedGames);
if(sortedGames.length < 1) {
list.message.textContent = I18n.get('noGames');

View file

@ -1,53 +1,37 @@
import I18n;
import GUI.ConnectedForm;
import {dialog, register, select} from GUI.Screen;
import Games;
import select from GUI.Screen;
import Messaging;
import Session;
import Save;
var login;
var loginForm;
var accountLoader;
var accountLoaderForm;
var form;
return {
init: init
};
function init() {
register('login');
initLogin();
initLoader();
login = GUI.ConnectedForm.get('login');
form = login.root;
initDOM();
initMessageHandlers();
restoreName();
var name = Save.get('player.name');
if(name != undefined && name.length > 0) {
form.you.value = name;
login.enable();
}
}
function initLogin() {
login = GUI.ConnectedForm.get('loginForm');
loginForm = login.root;
loginForm.getElementsByTagName('label')[0].textContent = I18n.get('pickName');
loginForm.join.value = I18n.get('join');
loginForm.addEventListener('submit', function(e) {
function initDOM() {
form.getElementsByTagName('label')[0].textContent = I18n.get('pickName');
form.join.value = I18n.get('join');
form.addEventListener('submit', function(e) {
e.preventDefault();
if(!Session.isLoggedIn()) {
Session.start(loginForm.you.value);
} else {
Messaging.send({tag: 'Hello', name: loginForm.you.value});
}
});
loginForm.you.addEventListener("input", validate);
}
function initLoader() {
accountLoader = GUI.ConnectedForm.get('accountLoader');
accountLoaderForm = accountLoader.root;
accountLoaderForm.getElementsByTagName('label')[0].textContent = I18n.get('pickFile');
accountLoaderForm.doLoad.value = I18n.get('doLoad');
accountLoaderForm.addEventListener('submit', loadAccountConfirm);
accountLoaderForm.pickFile.addEventListener("input", function() {
accountLoader.enable();
Session.start(form.you.value);
});
form.you.addEventListener("input", validate);
}
function initMessageHandlers() {
@ -58,44 +42,6 @@ function initMessageHandlers() {
});
}
function loadAccountConfirm(e) {
e.preventDefault();
if(Save.get('player') != undefined) {
dialog({
text: I18n.get('warnExistingAccount'),
answers: [
{label: 'confirmReplace', action: loadAccount},
{label: 'cancel', action: function() {}}
]
});
} else {
loadAccount();
}
}
function loadAccount() {
var fileReader = new FileReader();
fileReader.addEventListener('load', function() {
Save.set(null, JSON.parse(fileReader.result));
var name = restoreName();
Games.reload();
Messaging.reset();
if(name != undefined) {
Session.start(name);
}
});
fileReader.readAsText(accountLoaderForm.pickFile.files[0]);
}
function restoreName() {
var name = Save.get('player.name');
if(name != undefined && name.length > 0) {
loginForm.you.value = name;
login.enable();
return name;
}
}
function validate(e) {
login.enable(e.target.value != "");
}

View file

@ -1,25 +0,0 @@
import I18n;
import register from GUI.Screen;
import Save;
var button;
return {
init: init
};
function init() {
register('settings');
var exportRoot = document.getElementById('export');
var label = exportRoot.getElementsByTagName('span')[0];
button = exportRoot.getElementsByTagName('a')[0];
label.textContent = I18n.get('exportLabel');
button.textContent = I18n.get('doExport');
button.addEventListener('click', doExport);
}
function doExport() {
var data = encodeURIComponent(JSON.stringify(Save.get()));
button.href = 'data:application/json,' + data;
}

View file

@ -1,4 +1,3 @@
import Flower from Hanafuda;
import Messaging;
import player from Room;
import Save;
@ -6,79 +5,16 @@ import Session;
import Table;
import Time;
var states = Table.make(function(o) {return 0;});
var metadata = Table.make(function(o) {return o.value.date;});
reload();
var entries = Table.make(function(o) {return o.value.date;});
entries.insertAll(Save.get('games.entry') || {});
initMessageHandlers();
return {
metadata: metadata,
proposal: proposal,
reload: reload
entries: entries,
proposal: proposal
};
function initMessageHandlers() {
Messaging.addEventListener(["Game"], function(o) {
var gameID = o.state.public.coordinates.gameID;
pushState(gameID, o.state);
metadata.insert(gameID, getMetadata(o.state));
metadata.save('games.metadata');
});
Messaging.addEventListener(["LogIn"], function(o) {
var gamesAgainst = states.getAll(
function(game) {return isAgainst(game.value, o.from);}
);
gamesAgainst.forEach(function(game) {
Messaging.send({
tag: "Sync",
latestKnown: game.value.latest.public.coordinates,
to: o.from
});
});
});
Messaging.addEventListener(["Relay", "Sync"], function(o) {
var gameID = o.message.latestKnown.gameID;
var state = states.get(gameID);
if(state != undefined) {
switch(compare(state.latest.public.coordinates, o.message.latestKnown)) {
case -1: Messaging.send({tag: "Yield", onGameID: gameID, to: o.from});
case 1: Messaging.send({tag: "Share", gameSave: state.latest});
}
}
});
Messaging.addEventListener(["Relay", "Yield"], function(o) {
var gameID = o.message.onGameID;
var state = states.get(gameID);
if(state != undefined && isAgainst(state, o.from)) {
Messaging.send({tag: "Share", gameSave: state.latest});
}
});
}
function isAgainst(state, playerID) {
return state.latest.public.nextPlayer[Session.getKey()] == playerID;
}
function compare(gameCoordinatesA, gameCoordinatesB) {
var monthIndexA = Flower[gameCoordinatesA.month];
var monthIndexB = Flower[gameCoordinatesB.month];
if(monthIndexA < monthIndexB) {
return -1;
} else if(monthIndexA > monthIndexB) {
return 1;
} else if(gameCoordinatesA.turn < gameCoordinatesB.turn) {
return -1;
} else if(gameCoordinatesA.turn > gameCoordinatesB.turn) {
return 1;
} else {
return 0;
}
}
function getMetadata(state) {
function makeEntry(state) {
var sessionKey = Session.getKey();
return Time.timestamp({
vs: player(state.public.nextPlayer[sessionKey]),
@ -87,23 +23,18 @@ function getMetadata(state) {
}
function proposal(playerID, yourTurn) {
metadata.insert(
entries.insert(
playerID,
Time.timestamp({vs: player(playerID), yourTurn: yourTurn})
);
}
function pushState(gameID, newState) {
if(states.get(gameID) == undefined) {
states.insert(gameID, {});
}
var state = states.get(gameID);
state.former = state.latest;
state.latest = newState;
states.save('games.state');
}
function reload() {
states.load('games.state');
metadata.load('games.metadata');
function initMessageHandlers() {
Messaging.addEventListener(["Game"], function(o) {
var gameID = o.state.public.gameState.gameID;
var entry = makeEntry(o.state);
Save.set("games.message." + gameID, o);
Save.set("games.entry." + gameID, entry);
entries.insert(gameID, entry);
});
}

View file

@ -1,7 +1,6 @@
import * as Login from GUI.Screen.Login;
import * as Hall from GUI.Screen.Hall;
import * as Game from GUI.Screen.Game;
import * as Settings from GUI.Screen.Settings;
var gamePath = window.location.pathname.match(/\/game\/([0-9A-Fa-f]+)/);
@ -10,5 +9,4 @@ if(gamePath) {
} else {
Login.init();
Hall.init();
Settings.init();
}

View file

@ -20,7 +20,6 @@ init();
return {
addEventListener: addEventListener,
isOn: isOn,
reset: reset,
send: send
};
@ -137,9 +136,3 @@ function ping() {
}
}, keepAlivePeriod * s);
}
function reset() {
on = false; // this should be handled by the close event but when other operations are performed right after the reset, the event might not have had time to fire and the other functions, in particular send(), will assume the socket is still open and fail to actually send them instead of gently queueing them for when connectivity goes back up
reconnectDelay = 0.125; // since we're forcing the connection to close, there's no reason to assume the server went down so we manually lower the reconnectDelay to make the reconnection more fluid (there's no point making the user wait the usual 1 s. and the worse that could happen is we overflow the server a little with 3 connection attempts in 1 s.)
ws.close();
}

View file

@ -14,21 +14,19 @@ function player(key) {
return {id: key, name: players.get(key)};
}
function enterAll(o) {
for(key in o) {
enterPlayer(key, o[key]);
}
}
function enterPlayer(key, name) {
if(!Session.is(key)) {
players.insert(key, name);
}
}
function initMessageHandlers() {
Messaging.addEventListener(["Okaeri"], function(o) {enterAll(o.room);});
Messaging.addEventListener(["Welcome"], function(o) {enterAll(o.room);});
Messaging.addEventListener(["LogIn"], function(o) {enterPlayer(o.from, o.as);});
Messaging.addEventListener(["LogOut"], function(o) {players.remove(o.from);});
Messaging.addEventListener(["Okaeri"], function(o) {
players.insertAll(o.room);
});
Messaging.addEventListener(["Welcome"], function(o) {
players.insertAll(o.room);
});
Messaging.addEventListener(["LogIn"], function(o) {
if(!Session.is(o.from)) {
players.insert(o.from, o.as);
}
});
Messaging.addEventListener(["LogOut"], function(o) {
players.remove(o.from);
});
}

View file

@ -27,8 +27,6 @@ function get(key) {
} else {
return null;
}
} else {
return save;
}
}

View file

@ -17,8 +17,6 @@ Messaging.addEventListener(["LogIn"], function(o) {
}
});
Messaging.addEventListener('close', function() {loggedIn = false;});
return {
is: is,
getKey: getKey,

View file

@ -1,4 +1,3 @@
import Save;
import of from UnitJS.Fun;
import {compare, of, proj} from UnitJS.Fun;
@ -9,9 +8,7 @@ function Table(sortCriterion) {
getAll: getAll,
insert: insert,
insertAll: insertAll,
load: load,
remove: remove,
save
remove: remove
};
function get(key) {
@ -25,6 +22,7 @@ function Table(sortCriterion) {
.sort(compare(sortCriterion));
}
function insert(key, value) {
items[key] = value;
}
@ -35,17 +33,9 @@ function Table(sortCriterion) {
}
}
function load(path) {
items = Save.get(path) || {};
}
function remove(key) {
delete items[key];
}
function save(path) {
Save.set(path, items);
}
}
return {

View file

@ -15,14 +15,9 @@ return {
accept: "Let's go !",
alone: "No one to play with yet ! Wait a little",
backToMain: "Back to main menu",
cancel: "Cancel",
confirmReplace: "Yes, do replace my existing account",
decline: "No thanks",
doExport: "Save",
doLoad: "Load",
endRound: "End the round",
endGame: "Return to main menu",
exportLabel: "Save your account data to load it somewhere else",
gameNotFound: "You followed a fishy link, this game is no more",
join: "Join",
invite: "Invite",
@ -41,7 +36,6 @@ return {
var whose = yourTurn ? 'your' : name + "'s";
return 'Game vs. ' + name + ' (' + whose + ' turn)';
},
pickFile: "Load an existing account",
pickName: "Pick a name you like",
playing: function(name) {
return name + " is playing";
@ -51,7 +45,7 @@ return {
if(yourTurn) {
return name + proposed;
} else {
return "You" + proposed + " to " + name;
return "You" + proposed + " to " + name;
}
},
questionAccept: "Do you want to start the game ?",
@ -62,7 +56,6 @@ return {
theyScored: function(name) {
return name + " scored";
},
warnExistingAccount: "Your current account will be erased and lost forever",
won: "You won !",
yourTurn: "Your turn",
youScored: "You scored ! Do you want to get your points and end the round or KoiKoi ?"
@ -83,14 +76,9 @@ return {
accept: "C'est parti !",
alone: "Personne pour jouer pour l'instant ! Attendez un peu",
backToMain: "Retourner au menu principal",
cancel: "Annuler",
confirmReplace: "Oui, remplacer mon compte",
decline: "Non merci",
doExport: "Télécharger",
doLoad: "Charger",
endRound: "Finir la manche",
endGame: "Retourner au menu principal",
exportLabel: "Télécharger les données de votre compte pour les charger ailleurs",
gameNotFound: "Ce lien est louche, la partie n'est plus",
join: "Entrer",
invite: "Inviter",
@ -109,7 +97,6 @@ return {
var whose = yourTurn ? 'vous' : name;
return 'Partie en cours contre ' + name + ' (à ' + whose + ')';
},
pickFile: "Charger un compte existant",
pickName: "Choisissez votre nom",
playing: function(name) {
return "C'est à " + name;
@ -130,7 +117,6 @@ return {
theyScored: function(name) {
return name + " a marqué";
},
warnExistingAccount: "Le compte existant sera remplacé et perdu à tout jamais",
won: "Vous avez gagné !",
yourTurn: "À vous",
youScored: "Vous avez marqué ! Voulez-vous empocher vos gains et terminer la manche ou faire KoiKoi ?"

View file

@ -1,4 +1,4 @@
body > div, ul#sidebar.unactive {
body > div {
display: none;
}
@ -52,18 +52,3 @@ body > div.on {
#error.on {
display: block;
}
ul#sidebar {
position: fixed;
top: 0;
right: 0;
margin: 0;
padding: 0;
list-style: none;
}
ul#sidebar > li {
cursor: pointer;
float: left;
padding: 0.5em 1em;
}

View file

@ -1,8 +0,0 @@
#export a {
padding: 0.5em;
margin: 0 1em;
border-radius: 0.5em;
text-decoration: none;
background: #35e;
color: #fff;
}