var $ = function(_undefind) { function Selector(elements) { this.length = elements.length; for (var i = 0, l = this.length; l > i; i++) this[i] = elements[i]; } function $(selector) { return tag.test(selector) ? new Selector([ document.createElementNS("http://www.w3.org/2000/svg", tag.exec(selector)[1]) ]) : "string" == typeof selector ? new Selector(document.querySelectorAll(selector)) : selector instanceof NodeList ? new Selector(selector) : selector instanceof Element ? new Selector([ selector ]) : selector.addEventListener ? new Selector([ selector ]) : selector instanceof Selector ? selector : new Selector([]); } var fn = Selector.prototype; fn.each = function(callback) { for (var i = 0, l = this.length; l > i; i++) callback(this[i], i); return this; }, fn.on = function(eventName, eventHandler) { return this.each(function(el) { el.addEventListener(eventName, eventHandler); }); }, fn.off = function(eventName, eventHandler) { return this.each(function(el) { el.removeEventListener(eventName, eventHandler); }); }, fn.trigger = function(eventName, data) { return this.each(function(el) { event = new CustomEvent(eventName, data), el.dispatchEvent(event); }); }, fn.css = function(name, value) { if (Object(name) === name) { for (var prop in name) this.css(prop, name[prop]); return this; } return null != value ? this.each(function(el) { el.style[name] = value; }) : this.length ? getComputedStyle(this[0]).getPropertyValue(name) : _undefind; }, fn.show = function() { return this.css("display", "block"); }, fn.hide = function() { return this.css("display", "none"); }, fn.text = function(text) { return null != text ? this.each(function(el) { el.textContent = text; }) : this.length ? this[0].textContent : _undefind; }, fn.html = function(html) { return null != html ? this.each(function(el) { for (;el.firstChild; ) el.removeChild(el.firstChild); var fragment = document.createElement("div"); fragment.innerHTML = "" + html + ""; for (var svg = fragment.firstChild, node = svg.firstChild; node; ) el.appendChild(node.cloneNode(!0)), node = node.nextSibling; }) : this.length ? this[0].innerHTML : _undefind; }, fn.remove = function() { return this.each(function(el) { el.parentNode && el.parentNode.removeChild(el); }); }, fn.attr = function(name, value) { if (Object(name) === name) { for (var prop in name) this.attr(prop, name[prop]); return this; } return null != value ? this.each(function(el) { el.setAttribute(name, value); }) : this.length ? this[0].getAttribute(name) : _undefind; }, fn.removeAttr = function(name) { return this.each(function(el) { el.removeAttribute(name); }); }, fn.append = function(target) { return this.each(function(el) { target instanceof Selector ? target.each(function(child) { el.appendChild(child); }) : el.appendChild(target); }); }, fn.empty = function() { return this.each(function(el) { for (;el.firstChild; ) el.removeChild(el.firstChild); }); }, fn.eq = function(idx) { return new Selector(idx >= this.length ? [] : [ this[idx] ]); }, fn.find = function(selector) { var result = []; return this.each(function(el) { Array.prototype.push.apply(result, el.querySelectorAll(selector)); }), new Selector(result); }, fn.parent = function() { var result = []; return this.each(function(el) { result.push(el.parentNode); }), new Selector(result); }, fn.first = function() { return new Selector(this.length ? [ this[0] ] : []); }, fn.last = function() { return new Selector(this.length ? [ this[this.length - 1] ] : []); }, fn.clone = function() { var result = []; return this.each(function(el) { result.push(el.cloneNode(!0)); }), new Selector(result); }, fn.width = function() { return this.length ? this[0].getBoundingClientRect().width : _undefind; }, fn.height = function() { return this.length ? this[0].getBoundingClientRect().height : _undefind; }, fn.position = function() { if (this.length) { var clientRect = this[0].getBoundingClientRect(); return { top: clientRect.top, right: clientRect.right, bottom: clientRect.bottom, left: clientRect.left }; } return _undefind; }; var defaultAnim = { "class": "anim", begin: "indefinite" }, anim = function(anim) { return $("").attr(anim); }; fn.animate = function(anims) { var callbacks = [], thenable = { then: function(complete) { return callbacks.push(complete), thenable; } }; return anims = $.extend({}, defaultAnim, anims), this.each(function(el) { var $el = $(el), $anim = $el.find(".anim"); $anim.length ? $anim.attr(anims) : ($el.append(anim(anims)[0]), $anim = $el.find(".anim")), el.timerId = setTimeout(function() { $el.attr(anims.attributeName, anims.to), $el.removeAttr("animated"), callbacks.forEach(function(c) { c(); }), callbacks = []; }, 1e3 * parseFloat(anims.dur)), $el.attr("animated", !0), $anim[0].beginElement(); }), thenable; }; var animDelay = 62.5; fn.move = function(anims) { return this.each(function(el) { function tick() { if (!el.paused) { var cur = from + step; (to > from ? to >= cur : cur >= to) ? ($el.attr(property, cur), from = cur) : clearInterval(timer); } } var property = anims.attributeName, dur = anims.dur, to = parseInt(anims.to), $el = $(el), from = parseInt($el.attr(property)), step = (to - from) / (1e3 * dur / animDelay); el.timer = setInterval(tick, animDelay); }); }; var defaultTrf = { "class": "trf", type: "translate", dur: "0.3", calcMode: "spline", keySplines: "0.215 0.61 0.355 1", additive: "replace", attributeName: "transform", begin: "indefinite", keyTimes: "0; 1" }, trf = function(trf) { return $("").attr(trf); }; fn.transform = function(trfs) { var callbacks = [], thenable = { then: function(complete) { return callbacks.push(complete), thenable; } }; return trfs = $.extend({}, defaultTrf, trfs), this.each(function(el) { var $el = $(el), $anim = $el.find(".trf"); $anim.length ? $anim.attr(trfs) : ($el.append(trf(trfs)[0]), $anim = $el.find(".trf")), el.timerId = setTimeout(function() { $el.attr("transform", trfs.type + "(" + trfs.to + ")"), $el.removeAttr("animated"), callbacks.forEach(function(c) { c(); }), callbacks = []; }, 1e3 * parseFloat(trfs.dur) - 20), $el.attr("animated", !0), $anim[0].beginElement(); }), thenable; }, fn.stop = function() { return this.each(function(el) { $(el).find(".anim, .trf").each(function(anim) { anim.endElement(); }), clearTimeout(el.timerId), clearInterval(el.timer); }); }, fn.pause = function() { return $("svg")[0].pauseAnimations(), this.each(function(el) { el.paused = !0; }); }, fn.resume = function() { return $("svg")[0].unpauseAnimations(), this.each(function(el) { el.paused = !1; }); }; var tag = /^<(.+)\/>$/; return $.extend = function(target) { for (var obj, properties, i = 1, l = arguments.length; l > i; i++) { obj = arguments[i], properties = Object.keys(obj); for (var property, j = properties.length; j--; ) property = properties[j], target[property] = obj[property]; } return target; }, $.inherit = function(child, parent) { function ctor() { this.constructor = child, this.__super__ = parent.prototype; } return ctor.prototype = parent.prototype, child.prototype = new ctor(), child; }, $.mixin = function(plagin) { $.extend(fn, plagin); }, $.timestamp = 1400668550599, $.load = function(url, complete) { url = url + "?q=" + $.timestamp; var result = localStorage.getItem(url); if (null == result) { var xhr = new XMLHttpRequest(); xhr.open("GET", url, !0), xhr.onload = function() { localStorage.setItem(url, xhr.responseText), complete(xhr.responseText); }, xhr.send(); } else complete(result); }, $.rand = function(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); }, $; }(), Core = function() { var scope = { apiUrl: "ws://localhost:8080/ws/", gameId: 1000001, defaultSessionId: "7hc6Vl0CpxvngjiQQWDspxUtKmhF1zCbT155+M73XhFcKw9e6jkNWLSLM8up4ZQbSUGJXKOphb0YNu4yDRKZkbkiyY1yZukqXFj4nAfvSUNuWx0352VWfLlKZWldHb1na7d7sA==", CARD_SOURCE: "../app/svg/Card.svg", CARD_SMALL_SOURCE: "../app/svg/Card-small.svg", CARD_COLORS: [ "#CE290F", "#3B5998", "#48AF5E", "#F8E81C" ], SKIN_NAMES: [ "Alina", "Gabrielo", "Mustafa" ] }; return function(module) { module(scope); }; }(); Core(function(scope) { function Controller() { this.proxyAll(), this.refreshElements(); } var isIE = window.navigator.msPointerEnabled; $.extend(Controller.prototype, { proxy: function(func) { return func.bind(this); }, proxyAll: function() { if (this.proxies) for (var method, i = this.proxies.length; i--; ) method = this.proxies[i], this[method] = this.proxy(this[method]); }, withDelay: function(func, timeout) { return setTimeout(this.proxy(func), timeout || 0); }, $: function(selector) { return this.$el.find(selector); }, refreshElements: function() { if (this.elements) for (var element in this.elements) this[element] = this.$(this.elements[element]); }, on: function(eventType, handler) { return this.$el.on(eventType, handler), this; }, off: function(eventType, handler) { return this.$el.off(eventType, handler), this; }, clientX: function(e) { return isIE ? e.pageX : document.createTouch ? e.changedTouches[0].clientX : e.clientX; }, clientY: function(e) { return isIE ? e.pageY : document.createTouch ? e.changedTouches[0].clientY : e.clientY; }, intersect: function(x, y) { var pos = this.$el.position(); return pos.top < y && pos.bottom > y && pos.left < x && pos.right > x; } }), scope.Controller = Controller; }), Core(function(scope) { function ApiProvider(options) { options = options || {}, this.url = options.url, this.sessionId = options.sessionId, this.gameId = options.gameId, this.proxies = [ "init", "handleMessage", "actionTake" ], this.proxyAll(), this.socket = new WebSocket(this.url), this.$socket = $(this.socket), this.$socket.on("open", this.init), this.$socket.on("message", this.handleMessage); } var eventMap = [ "okey_game_info", "okey_game_started", "okey_game_player_state", "okey_next_turn", "okey_tile_discarded", "okey_tile_taken", "okey_revealed", "player_left", "game_paused" ], session = /\('session_attach'\),'([^)]+)'\)/, userName = /document.user\s?=\s?'([^']+)'/; $.extend(ApiProvider.prototype, { proxy: function(func) { return func.bind(this); }, proxyAll: function() { if (this.proxies) for (var method, i = this.proxies.length; i--; ) method = this.proxies[i], this[method] = this.proxy(this[method]); }, on: function(eventType, handler) { this.$socket.on(eventType, handler); }, off: function(eventType, handler) { this.$socket.off(eventType, handler); }, init: function() { this.socket.send([ "N2O", "" ]), setInterval(this.proxy(function() { this.socket.send("PING"); }), 4e3); }, handleMessage: function(e) { var msg = JSON.parse(e.data); if (msg.eval) { var curSession, user; (curSession = session.exec(msg.eval)) && (this.sessionId = curSession[1]), (user = userName.exec(msg.eval)) && (scope.user = user[1]); } msg.data ? (msg = dec(msg.data), this.emitEvent(this.beutify(this.parse(msg)))) : msg.eval && (this.socket.send(enc(tuple(atom("client"), tuple(atom("session_attach"), this.sessionId)))), this.socket.send(enc(tuple(atom("client"), tuple(atom("join_game"), this.gameId))))); }, parse: function(msg) { if (Array.isArray(msg)) { if (msg.every(function(el, i) { return i % 2 == 0 || Object(el.value) === el.value; }) || msg.length % 2 != 0) { for (var result = [], i = 0, l = msg.length; l > i; i++) result.push(this.parse(msg[i])); return result; } if (msg.length > 2 && msg.every(function(el) { return null != el && "object" != typeof el || null != el.value && "object" != typeof el.value; })) { var result = {}; return result[this.parse(msg[0])] = this.parse(msg.slice(1)), result; } for (var result = {}, i = 0, l = msg.length; l > i; i += 2) { { this.parse(msg[i]); } result[this.parse(msg[i])] = this.parse(msg[i + 1]); } return result; } return msg.value && Object(msg.value) === msg.value && msg.value[0] && msg.value.length ? this.parse(msg.value[0]) : null != msg.value ? msg.value : msg; }, beutify: function(msg) { var result = {}; for (var prop in msg) { var tempObj = msg[prop]; if (Array.isArray(tempObj)) { for (var obj, i = tempObj.length; i--; ) if (obj = tempObj[i], Array.isArray(obj)) result[obj[0]] = obj[1]; else if (Object(obj) === obj) for (var p in obj) result[p] = obj[p]; else result[i] = obj; msg[prop] = result; } } return msg; }, emitEvent: function(msg) { for (var event, i = eventMap.length; i--; ) event = eventMap[i], msg[event] && this.$socket.trigger(event, { detail: msg[event] }); }, actionTake: function(card) { var from = null != card.value ? 1 : 0; this.socket.send(enc(tuple(atom("client"), tuple(atom("game_action"), this.gameId, atom("okey_take"), { pile: from })))); }, actionDiscard: function(card) { this.socket.send(enc(tuple(atom("client"), tuple(atom("game_action"), this.gameId, atom("okey_discard"), { tile: tuple(atom("OkeyPiece"), scope.CARD_COLORS.indexOf(card.color) + 1, card.value) })))); }, reveal: function(card, hand) { this.socket.send(enc(tuple(atom("client"), tuple(atom("game_action"), this.gameId, atom("okey_reveal"), { discarded: tuple(atom("OkeyPiece"), scope.CARD_COLORS.indexOf(card.color) + 1, card.value), hand: hand })))); }, pause: function(resume) { this.socket.send(enc(tuple(atom("client"), tuple(atom("pause_game"), atom("undefined"), this.gameId, atom(resume ? "resume" : "pause"))))); } }), scope.ApiProvider = ApiProvider; }), Core(function(scope) { function culcShift() { sizeX = $svg[0].viewBox.baseVal.width / innerWidth, sizeY = $svg[0].viewBox.baseVal.height / innerHeight, size = Math.max(sizeX, sizeY) || 1; } function Draggable(root, options) { options = options || {}, this.$el = $(root), this.revert = options.revert, this.elements = {}, this.proxies = [ "onDown", "onMove", "onUp" ], this.__super__.constructor.call(this), this.enable(); } var sizeX, sizeY, size, moved, $svg = $("svg"); culcShift(), $(window).on("resize", culcShift), $(window).on("orientationchange", culcShift), $.inherit(Draggable, scope.Controller), $.extend(Draggable.prototype, { storeTrf: function() { var trf = this.$el.attr("transform"); this.initTrf = trf ? trf.slice(10, -1).split(/\s+/) : [ 0, 0 ]; }, disable: function() { this.$el.off(document.createTouch ? "touchstart" : "mousedown", this.onDown), this.$el.css({ cursor: "default" }); }, enable: function() { this.$el.on(document.createTouch ? "touchstart" : "mousedown", this.onDown), this.$el.attr("style", "cursor: -moz-grab; cursor: -webkit-grab; cursor: grab;"); }, onDown: function(e, silent) { e.preventDefault(), moved || (moved = !1, this.$el.attr("style", "cursor: -moz-grabbing; cursor: -webkit-grabbing; cursor: grabbing;"), this.$el[0].parentNode.appendChild(this.$el[0]), this.x = this.clientX(e), this.y = this.clientY(e), this.trf = this.$el.attr("transform"), this.trf && (this.trf = this.trf.slice(10, -1).split(/\s+/)), this.storeTrf(), silent || (document.createTouch ? (this.$el.on("touchmove", this.onMove), this.$el.on("touchend", this.onUp)) : ($("body").on("mousemove", this.onMove), $("body").on("mouseup", this.onUp)), this.$el.trigger("dragstart"))); }, onMove: function(e, silent) { e.preventDefault(), moved = !0, this.dx = ((this.curX = this.clientX(e)) - this.x) * size, this.dy = ((this.curY = this.clientY(e)) - this.y) * size, this.trf && (this.dx += 0 | this.trf[0], this.dy += 0 | this.trf[1]), this.$el.attr("transform", "translate(" + this.dx + " " + this.dy + ")"), silent || this.$el.trigger("dragmove", { detail: { x: this.curX, y: this.curY, event: e } }); }, onUp: function(e, silent) { if (e.preventDefault(), this.$el.attr("style", "cursor: -moz-grab; cursor: -webkit-grab; cursor: grab;"), moved) { for (var droped, item, dropList = scope.Droppable.list, i = 0, l = dropList.length; l > i; i++) if (item = dropList[i], item.intersect(this.curX, this.curY)) { droped = item.drop(this, this.curX, this.curY); break; } droped || (this.$el.transform({ from: [ this.dx, this.dy ].join(" "), to: this.initTrf.join(" ") }), silent || this.$el.trigger("revert")), silent || this.$el.trigger("dragstop", { detail: { x: this.curX, y: this.curY, event: e } }), moved = !1; } document.createTouch ? (this.$el.off("touchmove", this.onMove), this.$el.off("touchend", this.onUp)) : ($("body").off("mousemove", this.onMove), $("body").off("mouseup", this.onUp)); } }), scope.Draggable = Draggable, $.mixin({ draggable: function() { return this.each(function(el) { new Draggable(el); }); } }); }), Core(function(scope) { function Droppable(root, options) { options = options || {}, this.$el = $(root), this.accept = options.accept || function() { return !0; }, this.onDrop = options.drop || function() {}, this.elements = {}, this.proxies = [], this.__super__.constructor.call(this), this.activate(); } Droppable.list = [], $.inherit(Droppable, scope.Controller), $.extend(Droppable.prototype, { drop: function(target, x, y) { return this.accept(target, x, y) ? (this.onDrop(target, x, y), !0) : !1; }, activate: function() { Droppable.list.push(this); }, release: function() { var i; ~(i = Droppable.list.indexOf(this)) && Droppable.list.splice(i, 1); } }), scope.Droppable = Droppable, $.mixin({ droppable: function(options) { return this.each(function(el) { new Droppable(el, options); }); } }); }), Core(function(scope) { function Timer(root, options) { options = options || {}, this.duration = options.duration, this.curTime = this.duration, this.$el = $(root), this.elements = { $value: "#value", $progress: "#progress" }, this.proxies = [ "tick" ], this.__super__.constructor.call(this), this.$value.text(this.duration), defHeight = this.$progress.attr("height"); } var defHeight; $.inherit(Timer, scope.Controller), $.extend(Timer.prototype, { from: function(time) { this.$value.text(this.curTime = Math.round(time / 1e3)); }, start: function() { this.$progress.move({ attributeName: "height", to: "0", dur: this.curTime }), this.timerId = this.withDelay(this.tick, 1e3); }, tick: function() { return this.paused ? void (this.timerId = this.withDelay(this.tick, 1e3)) : void (this.curTime-- > 0 && (this.$value.text(this.curTime), this.timerId = this.withDelay(this.tick, 1e3))); }, reset: function() { this.$progress.stop().attr({ height: defHeight }), this.$value.text(this.curTime = this.duration), clearTimeout(this.timerId); }, pause: function() { this.paused = !0, this.$progress.pause(); }, resume: function() { this.paused = !1, this.$progress.resume(); } }), scope.Timer = Timer; }), Core(function(scope) { function Player(options) { options = options || {}, this.name = options.name, this.position = options.position, this.noSkin = options.noSkin, this.skin = options.skin || scope.SKIN_NAMES[$.rand(0, scope.SKIN_NAMES.length - 1)], this.$el = $("#player-" + this.position), this.elements = { $timer: "#timer", $name: "#name", $nameWrapper: "#name rect", $nameText: "#name text" }, this.proxies = [ "loadSkin" ], this.__super__.constructor.call(this), this.$el.show(), this.$timer.hide(), this.$name.show(), this.$nameText.text(this.name); var nameWrapperWidth = this.$nameText.width() / $("#Page-1").width() * 100 + 2 * (this.$nameText.position().left - this.$nameWrapper.position().left) / $("#Page-1").width() * 100; this.$nameWrapper.attr({ width: nameWrapperWidth + "%" }), this.initTimer(), "me" == this.position || this.noSkin || $.load("../app/svg/" + [ "Person", this.position, this.skin ].join("-") + ".svg", this.loadSkin); } $.inherit(Player, scope.Controller), $.extend(Player.prototype, { loadSkin: function(result) { var $result = $("").html(result); this.$el.append($result[0].firstChild), this.unselect(); }, initTimer: function() { this.timer = new scope.Timer(this.$timer, { duration: 30 }); }, select: function() { this.$nameWrapper.attr({ fill: "#517ECE" }), this.$nameText.attr({ fill: "#FFFFFF" }), this.$timer.show(), this.$("#Selection").show(), this.timer.start(); }, unselect: function() { this.$nameWrapper.attr({ fill: "#FFFFFF" }), this.$nameText.attr({ fill: "#48AF5E" }), this.$timer.hide(), this.$("#Selection").hide(), this.timer.reset(); } }), scope.Player = Player; }), Core(function(scope) { function Hand(root, options) { options = options || {}, this.$el = $(root), this.elements = { $topCard: "#top-card", $rollUp: "#roll-up", $rollDown: "#roll-down", $container: "#container", $back: "#back", $cards: "#cards" }, this.proxies = [ "show", "hide" ], this.__super__.constructor.call(this), this.$rollUp.on("click", this.show), this.$rollDown.on("click", this.hide), this.cards = []; } var trfsMap = [ { backHeight: 74, containerTrf: "0 -44", cardTrf: "0 -38" }, { backHeight: 124, containerTrf: "0 -94", cardTrf: "0 -89" }, { backHeight: 174, containerTrf: "0 -144", cardTrf: "0 -139" } ], defCardTrf = "0 20"; $.inherit(Hand, scope.Controller), $.extend(Hand.prototype, { take: function() { var card = this.cards.pop(); return this.render(), card && card.$el.remove(), card; }, discard: function(tile) { var card = new scope.Card({ color: scope.CARD_COLORS[tile[1] - 1], value: tile[2] }); this.cards.push(card), this.render(), card.drag(), card.dragHandler.disable(), this.$topCard.append(card.$el[0]); }, pop: function() { this.cards.pop(), this.render(); }, show: function() { var count = this.cards.length - 1; count > 0 && (this.$container.transform({ to: trfsMap[4 > count ? count - 1 : 2].containerTrf, from: "0 50", dur: .355, calcMode: "linear" }), this.$back.animate({ attributeName: "height", to: trfsMap[4 > count ? count - 1 : 2].backHeight, dur: .355 }), this.$cards.find("g").each(function(el, i) { 3 > i && $(el).transform({ to: trfsMap[i].cardTrf, from: "0 20", dur: .6, calcmode: "linear" }); }), this.shown = !0); }, hide: function() { var count = this.cards.length - 1; count > 0 && (this.$container.transform({ to: "0 50", from: trfsMap[4 > count ? count - 1 : 2].containerTrf, dur: .5, calcMode: "linear" }), this.$back.animate({ attributeName: "height", to: 0, dur: .5 }), this.$cards.find("g").each(function(el, i) { 3 > i && $(el).transform({ to: defCardTrf, from: trfsMap[4 > count ? count - 1 : 2].cardTrf, dur: .6, calcmode: "linear" }); }), this.shown = !1); }, render: function() { var history = this.cards.slice(0, this.cards.length - 1); this.$cards.empty(), this.shown && this.hide(), history.reverse().forEach(function(card) { card = card.clone(), card.template(scope.CARD_SMALL_SOURCE), card.$el.attr("transform", "translate(" + defCardTrf + ")"), this.$cards.append(card.$el[0]); }, this); }, clear: function() { this.cards.forEach(function(card) { card.$el.remove(); }), this.cards = [], this.render(); } }), scope.Hand = Hand; }), Core(function(scope) { function Card(options) { options = options || {}, this.value = options.value, this.color = options.color, this.selected = !1, this.pos = {}, this.elements = { $circle: "circle", $text: "text", $overlay: ".overlay" }, this.proxies = [ "toggle", "selectGroup", "dragGroup", "clearGroup", "revertGroup" ], this.template(scope.CARD_SOURCE), this.$el.on("mousedown", this.toggle), this.$el.on("revert", this.revertGroup), this.$el.on("dragstop", this.clearGroup), this.$overlay.on("mousedown", this.selectGroup); } var selStart = !1; $(window).on("keydown", function(e) { e.ctrlKey && (selStart = !0); }), $(window).on("keyup", function() { selStart = !1; }), Card.selected = [], Card.uncheckAll = function() { for (var i = Card.selected.length; i--; ) Card.selected[i].uncheck(); }, $("body").on("mousedown", Card.uncheckAll), $.inherit(Card, scope.Controller), $.extend(Card.prototype, { template: function(source) { $.load(source, this.proxy(this.load)); }, load: function(result) { this.$el = (this.$el || $("")).attr({ "class": "card" }).css({ cursor: "default" }).html(result), this.__super__.constructor.call(this), this.render(); }, render: function() { null == this.value && null == this.color ? (this.$circle.hide(), this.$text.hide()) : 0 == this.value ? (this.$circle.hide(), this.$text.show().attr({ fill: this.color, y: 36 }).text("*")) : (this.$circle.show().attr("fill", this.color), this.$text.show().attr("fill", this.color).text(this.value)); }, drag: function() { this.dragHandler = new scope.Draggable(this.$el), this.dragHandler.owner = this; }, centerX: function() { var pos = this.$el.position(), width = this.$el.width(); return Math.round(pos.left + width / 2); }, toggle: function(e) { e.stopPropagation(), selStart ? this.nearSelectGroup() ? this.selected && !this.betweenSelected() ? this.uncheck() : this.check() : (Card.uncheckAll(), this.check()) : ~Card.selected.indexOf(this) || Card.uncheckAll(); }, check: function() { this.$overlay.css("display", ""), this.selected = !0, deck.cards[this.pos.y][this.pos.x] = null, Card.selected.push(this); }, uncheck: function() { this.$overlay.css("display", "none"), this.selected = !1, deck.cards[this.pos.y][this.pos.x] = this; var i; ~(i = Card.selected.indexOf(this)) && Card.selected.splice(i, 1); }, selectGroup: function(e) { if (!selStart) { for (var card, i = 0, l = Card.selected.length; l > i; i++) card = Card.selected[i], card != this && card.dragHandler.onDown(e, !0); this.$el.on("dragmove", this.dragGroup); } }, dragGroup: function(e) { for (var card, i = 0, l = Card.selected.length; l > i; i++) card = Card.selected[i], card != this && card.dragHandler.onMove(e.detail.event, !0); }, clearGroup: function() { this.$el.off("dragmove", this.dragGroup), selStart || Card.uncheckAll(); }, nearSelectGroup: function() { return Card.selected.some(function(card) { return Math.abs(card.pos.x - this.pos.x) <= 1 && card.pos.y == this.pos.y; }, this); }, betweenSelected: function() { Card.selected.sort(function(a, b) { return (a.pos.x < b.pos.x) - (b.pos.x < a.pos.x); }); var idx = Card.selected.indexOf(this); return -1 != idx && 0 != idx && idx != Card.selected.length - 1; }, revertGroup: function() { for (var card, i = 0, l = Card.selected.length; l > i; i++) card = Card.selected[i], card != this && card.$el.transform({ from: [ card.dragHandler.dx, card.dragHandler.dy ].join(" "), to: card.dragHandler.initTrf.join(" ") }), scope.deck.cards[card.pos.y][card.pos.x] = card; }, clone: function() { return new Card({ color: this.color, value: this.value }); }, log: function() {} }), scope.Card = Card; }), Core(function(scope) { function Deck(root, options) { options = options || {}, this.$el = $(root), this.elements = { $dropPlace: "#deck" }, this.proxies = [ "select", "track", "place" ], this.cards = [ [], [] ], this.trfs = [ [], [] ], this.__super__.constructor.call(this), this.$dropPlace.droppable({ accept: this.place }); } var padding = { top: 5, left: 5 }; $.inherit(Deck, scope.Controller); var prevX, prevY, selected; $.extend(Deck.prototype, { each: function(callback) { for (var i = 0; 15 > i; i++) for (var j = 0; 2 > j; j++) if (callback.call(this, this.cards[j][i], i, j) === !1) return; }, fill: function(tiles) { var count = 0; this.each(function(c, i, j) { if (null != c && (this.cards[j][i] = null, c.$el.remove()), 0 == j && count < tiles.length) { var tile = tiles[count], card = new scope.Card({ color: scope.CARD_COLORS[tile[1] - 1], value: tile[2] }); card.pos = { x: i, y: j }, card.on("dragstart", this.select), card.on("dragmove", this.track), this.cards[j][i] = card, count++; } this.trfs[j][i] = { x: 42 * i + padding.left, y: 71 * j + padding.top }; }); }, render: function() { this.each(function(card, i, j) { null != card && (card.$el.attr("transform", "translate(" + this.trfs[j][i].x + " " + this.trfs[j][i].y + ")"), card.drag(), this.$el.append(card.$el[0])); }); }, track: function(e) { this.each(function(card, i, j) { if (card && card.$el[0] != e.target && card.intersect(e.detail.x, e.detail.y) && !card.$el.attr("animated") && scope.Card.selected.length < 2) { var shift = e.detail.x > card.centerX() ? i + 1 : i - 1; return shift = shift > 14 ? shift - 2 : shift, shift = 0 > shift ? shift + 2 : shift, prevX = i, prevY = j, this.move({ i: i, j: j }, { i: shift, j: j }), !1; } }); }, move: function(fst, snd) { var card, trfs = this.trfs, i = snd.i, cond = function(i) { return fst.i < snd.i ? 14 >= i : i >= 0; }, _cond = function(j, i) { return fst.i < snd.i ? i > j : j > i; }, op = function() { fst.i < snd.i ? i++ : i--; }, _op = function() { fst.i < snd.i ? j++ : j--; }, direction = function(j) { return fst.i < snd.i ? j + (scope.Card.selected.length || 1) : j - (scope.Card.selected.length || 1); }, _direction = function(j) { return fst.i < snd.i ? j - 1 : j + 1; }; if (scope.Card.selected.length < 2) for (;cond(i); op()) if (null == this.cards[snd.j][i] || this.cards[snd.j][i] == selected) { for (var j = _direction(i); _cond(j, i); _op()) card = this.cards[fst.j][j], card != selected && (card.$el.transform({ from: [ trfs[fst.j][j].x, trfs[fst.j][j].y ].join(" "), to: [ trfs[fst.j][direction(j)].x, trfs[fst.j][direction(j)].y ].join(" ") }), selected && (selected.dragHandler.initTrf = [ trfs[fst.j][j].x, trfs[fst.j][j].y ]), ((this.cards[fst.j][j] = this.cards[fst.j][direction(j)]) || {}).pos = { x: j, y: fst.j }, (this.cards[fst.j][direction(j)] = card).pos = { x: direction(j), y: fst.j }); break; } }, select: function(e) { selected = null, this.each(function(card) { return card && card.$el[0] == e.target ? (selected = card, !1) : void 0; }); }, place: function(target, x, y) { var trfs = this.trfs, pos = this.$dropPlace.position(), width = this.$dropPlace.width(), height = this.$dropPlace.height(), placeWidth = Math.round(width / 15), placeHeight = Math.round(height / 2), truePosX = Math.floor((x - pos.left) / placeWidth), posY = Math.floor((y - pos.top) / placeHeight); scope.Card.selected.sort(function(a, b) { return (a.pos.x > b.pos.x) - (b.pos.x > a.pos.x); }); var dropResult, idx = scope.Card.selected.indexOf(target.owner), cards = scope.Card.selected.length ? scope.Card.selected.concat() : [ target.owner ]; if (cards.every(function(card, i) { return posX = truePosX + (i - idx) * (card != target.owner), null == this.cards[posY][posX] || this.cards[posY][posX] == card; }, this)) for (var card, i = 0, l = cards.length; l > i; i++) card = cards[i], posX = truePosX + (i - idx) * (card != target.owner), (dropResult = null == this.cards[posY][posX] || this.cards[posY][posX] == selected) && (this.cards[posY][posX] != card && (null != card.pos.x && null != card.pos.y ? this.cards[card.pos.y][card.pos.x] = this.cards[card.pos.y][card.pos.x] == card ? null : this.cards[card.pos.y][card.pos.x] : (this.$el.trigger("take", { detail: { card: card } }), this.justTaken = !0), (this.cards[posY][posX] = card).pos = { x: posX, y: posY }), function(card) { card.$el.transform({ from: card.$el.attr("transform").slice(10, -1), to: [ trfs[posY][posX].x, trfs[posY][posX].y ].join(" ") }).then(function() { card.dragHandler.storeTrf(); }); }(card)); return dropResult; }, remove: function(tile) { return selected && selected.color == scope.CARD_COLORS[tile[1] - 1] && selected.value == tile[2] ? (this.cards[selected.pos.y][selected.pos.x] = null, selected.$el.remove(), selected.off("dragmove", this.track), !1) : void this.each(function(card, i, j) { return card && card.color == scope.CARD_COLORS[tile[1] - 1] && card.value == tile[2] ? (this.cards[j][i] = null, card.$el.remove(), card.off("dragmove", this.track), !1) : void 0; }); }, insert: function(tile) { this.justTaken ? this.justTaken = !1 : this.each(function(card, i, j) { return card ? void 0 : (card = new scope.Card({ color: scope.CARD_COLORS[tile[1] - 1], value: tile[2] }), card.pos = { x: i, y: j }, card.on("dragstart", this.select), card.on("dragmove", this.track), this.cards[j][i] = card, card.$el.attr("transform", "translate(" + this.trfs[j][i].x + " " + this.trfs[j][i].y + ")"), card.drag(), this.$el.append(card.$el[0]), !1); }); }, length: function() { var count = 0; return this.each(function(card) { null != card && (count += 1); }), count; }, hand: function(discarded) { return result = [ [], [] ], this.each(function(card, i, j) { card && card != discarded && result[j].push(tuple(atom("OkeyPiece"), scope.CARD_COLORS.indexOf(card.color) + 1, card.value)); }), result; }, dir: function() { for (var i = 0; 15 > i; i++) this.cards[0][i] && this.cards[0][i].log(); for (var i = 0; 15 > i; i++) this.cards[1][i] && this.cards[1][i].log(); } }), scope.deck = new Deck("#deck-root"); }), Core(function(scope) { $.load(scope.CARD_SOURCE, function() { function fadeOut() { $(this).animate({ attributeName: "opacity", from: 1, to: 0, dur: .3 }); } function fadeIn() { $(this).animate({ attributeName: "opacity", from: 0, to: 1, dur: .3 }); } function addFadeOut() { $(this).on(document.createTouch ? "touchend" : "mouseup", fadeOut); } function removeFadeOut() { $(this).off(document.createTouch ? "touchend" : "mouseup", fadeOut); } function createCentralCard() { centralCard = new scope.Card(), centralCard.$el.attr({ opacity: 0, transform: "translate(298 -115)" }).on(document.createTouch ? "touchstart" : "mousedown", fadeIn).on(document.createTouch ? "touchend" : "mouseup", fadeOut), centralCard.drag(), centralCard.dragHandler.enable(), centralCard.on("dragstart", deck.select).on("dragmove", removeFadeOut).on("dragstop", addFadeOut).on("dragmove", deck.track).on("revert", fadeOut), deck.$el.append(centralCard.$el[0]); } function init(e) { if (ended = !1, scope.deck.fill(e.detail.tiles), scope.deck.render(), centralCard.dragHandler.disable(), centralCard.$el.off(document.createTouch ? "touchstart" : "mousedown", fadeIn).off(document.createTouch ? "touchend" : "mouseup", fadeOut), e.detail.gosterge && "null" != e.detail.gosterge) { var gosterge = new scope.Card({ color: scope.CARD_COLORS[e.detail.gosterge[1] - 1], value: e.detail.gosterge[2] }); gosterge.$el.attr("transform", "translate(16 0)"), $gosterge.append(gosterge.$el); } var piles = e.detail.piles; if (piles && "null" != piles) for (var i = 0; i < piles.length, pile; i++) { pile = piles[i]; for (var name in pile) for (var playerPile = pile[name], hand = playersLeftHandsMap[name], j = playerPile.length; j--; ) hand.discard(playerPile[j]); } e.detail.whos_move && "null" != e.detail.whos_move && (e.detail.next_turn_in && "null" != e.detail.next_turn_in && playersMap[e.detail.whos_move].timer.from(e.detail.next_turn_in), e.detail.paused && (playersMap[e.detail.whos_move].timer.pause(), $overlay.show()), playersMap[e.detail.whos_move].select()); } window.deck = scope.deck; var centralCard, apiProvider = new scope.ApiProvider({ url: scope.apiUrl, gameId: scope.gameId, sessionId: scope.defaultSessionId }); createCentralCard(), deck.on("take", function(e) { e.detail.card.$el.off(document.createTouch ? "touchstart" : "mousedown", fadeIn).off(document.createTouch ? "touchend" : "mouseup", fadeOut), centralCard.off("dragmove", removeFadeOut).off("dragstop", addFadeOut).off("revert", fadeOut), ~playersLeftHandsMap[scope.user].cards.indexOf(e.detail.card) && playersLeftHandsMap[scope.user].pop(), apiProvider.actionTake(e.detail.card); }); var $gosterge = $("#gosterge"), ended = !0; apiProvider.on("okey_game_started", init), apiProvider.on("okey_game_player_state", init); var playersPositions = [ [ "me", "right", "center", "left" ], [ "left", "me", "right", "center" ], [ "center", "left", "me", "right" ], [ "right", "center", "left", "me" ] ], playersMap = {}, playersRightHandsMap = {}, playersLeftHandsMap = {}; apiProvider.on("okey_game_info", function(e) { if (!scope.started) { for (var playerInfo, players = e.detail.players, i = 0; i < players.length; i++) if (playerInfo = players[i].PlayerInfo, playerInfo[0] == scope.user) { playersPositions = playersPositions[i]; break; } for (var playerInfo, i = 0, l = players.length; l > i; i++) { playerInfo = players[i].PlayerInfo, playersMap[playerInfo[0]] = playersMap[playerInfo[0]] || new scope.Player({ position: playersPositions[i], name: [ playerInfo[2], playerInfo[3] ].join(" ") }); var prevPlayer = i == players.length - 1 ? players[0] : players[i + 1]; for (var prop in playersLeftHandsMap) playersLeftHandsMap[prop].clear(); playersLeftHandsMap[prevPlayer.PlayerInfo[0]] = playersRightHandsMap[playerInfo[0]] = new scope.Hand("#" + [ "player", playersPositions[i], "hand" ].join("-")), "me" == playersPositions[i] && playersRightHandsMap[playerInfo[0]].$el.droppable({ accept: function() { return playerTurn && deck.length() > 14; }, drop: function(target) { apiProvider.actionDiscard(target.owner); } }); } scope.started = !0; } }), window.playersRightHandsMap = playersRightHandsMap, window.playersLeftHandsMap = playersLeftHandsMap; var playerTurn = !1; apiProvider.on("okey_next_turn", function(e) { for (var playerName in playersMap) playersMap[playerName].unselect(); if (playersMap[e.detail.player].select(), e.detail.player == scope.user) { playerTurn = !0; var cards = playersLeftHandsMap[e.detail.player].cards; if (cards.length) { var card = cards[cards.length - 1]; deck.$el.append(card.$el[0]), card.$el.attr({ transform: "translate(16 -65)" }), card.dragHandler.enable(), card.on("dragstart", deck.select), card.on("dragmove", deck.track); } deck.length() < 15 ? (centralCard.dragHandler.enable(), centralCard.$el.on(document.createTouch ? "touchstart" : "mousedown", fadeIn).on(document.createTouch ? "touchend" : "mouseup", fadeOut), centralCard.on("dragmove", removeFadeOut).on("dragstop", addFadeOut).on("revert", fadeOut)) : (centralCard.dragHandler.disable(), centralCard.$el.off(document.createTouch ? "touchstart" : "mousedown", fadeIn).off(document.createTouch ? "touchend" : "mouseup", fadeOut)); } else playerTurn = !1, centralCard.dragHandler.disable(), centralCard.$el.off(document.createTouch ? "touchstart" : "mousedown", fadeIn).off(document.createTouch ? "touchend" : "mouseup", fadeOut); }), apiProvider.on("okey_tile_discarded", function(e) { if ("object" == typeof e.detail.tile) { var c = new scope.Card({ color: scope.CARD_COLORS[e.detail.tile[1] - 1], value: e.detail.tile[2] }); c.log(); } e.detail.player == scope.user && deck.remove(e.detail.tile), playersRightHandsMap[e.detail.player].discard(e.detail.tile); }); var $pile = $("#pile"), $fullPile = $pile.find("g").clone(), $wholeCards = $("#whole-cards"), $fullWholeCards = $("#whole-cards > g").clone(); apiProvider.on("okey_tile_taken", function(e) { if ("object" == typeof e.detail.revealed) { var c = new scope.Card({ color: scope.CARD_COLORS[e.detail.revealed[1] - 1], value: e.detail.revealed[2] }); c.log(); } if (e.detail.pile && !deck.justTaken && playersLeftHandsMap[e.detail.player].take(), 0 === e.detail.pile && e.detail.player == scope.user && (centralCard.color = scope.CARD_COLORS[e.detail.revealed[1] - 1], centralCard.value = e.detail.revealed[2], centralCard.render(), createCentralCard()), 0 === e.detail.pile) { var $topCard = $pile.find("g"); if ($topCard.length > 1) $topCard.last().remove(); else { $topCard.last().remove(), $pile.append($fullPile); var $miniPile = $wholeCards.find("g"); $miniPile.length ? $miniPile.first().remove() : $wholeCards.append($fullWholeCards); } } e.detail.player == scope.user && deck.insert(e.detail.revealed), centralCard.dragHandler.disable(), centralCard.$el.off(document.createTouch ? "touchstart" : "mousedown", fadeIn).off(document.createTouch ? "touchend" : "mouseup", fadeOut); var cards = playersLeftHandsMap[scope.user].cards; if (cards.length) { var card = cards[cards.length - 1]; card.dragHandler.disable(); } }), apiProvider.on("okey_revealed", function(e) { ended = !0, alert(e.detail.player), deck.fill([]); for (var hand in playersLeftHandsMap) playersLeftHandsMap[hand].clear(); for (var playerName in playersMap) playersMap[playerName].unselect(); $gosterge.remove(); }), apiProvider.on("player_left", function(e) { var playerInfo = e.detail.replacement.PlayerInfo; playersMap[playerInfo[0]] = new scope.Player({ position: playersMap[e.detail.player].position, name: [ playerInfo[2], playerInfo[3] ].join(" "), noSkin: !0 }), delete playersMap[e.detail.player], playersRightHandsMap[playerInfo[0]] = playersRightHandsMap[e.detail.player], delete playersRightHandsMap[e.detail.player], playersLeftHandsMap[playerInfo[0]] = playersLeftHandsMap[e.detail.player], delete playersLeftHandsMap[e.detail.player]; }), $("#pause").on("click", function() { apiProvider.pause(); }); var whoPausedGame, $overlay = $("#overlay"); $overlay.on("click", function() { whoPausedGame == scope.user && apiProvider.pause(!0); }), apiProvider.on("game_paused", function(e) { if (whoPausedGame = e.detail[3], "pause" == e.detail[2]) { $overlay.show(); for (var player in playersMap) playersMap[player].timer.pause(); var player = playersMap[e.detail[3]]; $overlay.find("text").text(player.name + " paused the game"); } else { $overlay.hide(); for (var player in playersMap) playersMap[player].timer.resume(); } }), $("#table-ellipse").droppable({ accept: function(target) { return 1 === apiProvider.socket.readyState && deck.length() > 14 && target.owner != centralCard && !ended && scope.Card.selected.length <= 1; }, drop: function(target) { apiProvider.reveal(target.owner, deck.hand(target.owner)); } }); }); var leftFlag = !1; $("#Left-Menu").css("cursor", "pointer").on("click", function() { leftFlag ? ($("#Tournaments").transform({ to: "10 575", from: "44 465" }), $("#Promos").transform({ to: "10 575", from: "122 538" }), leftFlag = !1) : ($("#Tournaments").transform({ from: "10 575", to: "44 465" }), $("#Promos").transform({ from: "10 575", to: "122 538" }), leftFlag = !0); }); var rightFlag = !1; $("#Right-Menu").css("cursor", "pointer").on("click", function() { rightFlag ? ($("#Play").transform({ to: "975 575", from: "946, 461" }), $("#Create").transform({ to: "975 575", from: "864 526" }), rightFlag = !1) : ($("#Play").transform({ from: "975 575", to: "946, 461" }), $("#Create").transform({ from: "975 575", to: "864 526" }), rightFlag = !0); }); });