From 6667db814c190e3fed92f0baddf0e0e6687d11d8 Mon Sep 17 00:00:00 2001
From: exane <raco0n@gmx.de>
Date: Thu, 18 Jun 2015 15:06:13 +0200
Subject: [PATCH] much stuff

---
 assets/data/abilities.js               |  12 ++-
 gulpfile.js                            |   2 +-
 package.json                           |   9 +-
 public/index.html                      |  22 +++-
 public/js/backbone.modal-min.js        | 123 ++++++++++++++++++++++
 public/js/client.js                    | 137 +++++++++++++------------
 public/scss/_backbone.modal.sass       |  25 +++++
 public/scss/_backbone.modal.theme.sass | 130 +++++++++++++++++++++++
 public/scss/_style.sass                |  45 ++++++++
 public/scss/main.scss                  |  16 ++-
 server/Battle.js                       |  17 +--
 server/Battleside.js                   |  78 +++++++++-----
 server/Card.js                         |  11 ++
 server/Deck.js                         |  12 +--
 server/Hand.js                         |   1 +
 server/Room.js                         |  32 +-----
 server/_server.js                      |   2 -
 17 files changed, 522 insertions(+), 152 deletions(-)
 create mode 100644 public/js/backbone.modal-min.js
 create mode 100644 public/scss/_backbone.modal.sass
 create mode 100644 public/scss/_backbone.modal.theme.sass
 create mode 100644 public/scss/_style.sass
 delete mode 100644 server/_server.js

diff --git a/assets/data/abilities.js b/assets/data/abilities.js
index 12ac982..c4e8b64 100644
--- a/assets/data/abilities.js
+++ b/assets/data/abilities.js
@@ -51,8 +51,7 @@ module.exports = {
     }
   },
   "weather_fog": {
-    onEachTurn: function(args) {
-      card = args[0]
+    onEachTurn: function(card) {
       var targetRow = card.constructor.TYPE.RANGED;
       var forcedPower = 1;
       var field1 = this.field[targetRow].get();
@@ -66,7 +65,6 @@ module.exports = {
       });
     },
     onEachCardPlace: function(card) {
-      card = args[0]
       var targetRow = card.constructor.TYPE.RANGED;
       var forcedPower = 1;
       var field1 = this.field[targetRow].get();
@@ -122,5 +120,13 @@ module.exports = {
   },
   "decoy": {
     replaceWith: true
+  },
+  "foltest_leader1": {
+    onActivate: function() {
+      var cards = this.deck.find("key", "impenetrable_fog")
+      if(!cards.length) return;
+      var card = this.deck.removeFromDeck(cards[0]);
+      this.placeCard(card);
+    }
   }
 }
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
index cbf1ac8..43c0d8e 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -26,7 +26,7 @@ gulp.task('browserify', function(){
 });
 
 gulp.task('sass', function(){
-  gulp.src('./public/scss/*.scss')
+  gulp.src('./public/scss/main.scss')
   .pipe(sass({
     outputStyle: 'compressed'
   }).on("error", function(err){
diff --git a/package.json b/package.json
index cbb8435..28f86cb 100644
--- a/package.json
+++ b/package.json
@@ -10,17 +10,18 @@
   "devDependencies": {
     "babelify": "^6.1.2",
     "browserify": "^10.2.4",
+    "connect": "3.0.1",
+    "express": "4.12.3",
     "gulp": "^3.9.0",
     "gulp-livereload": "^3.8.0",
     "gulp-sass": "^2.0.1",
     "handlebars": "^3.0.3",
     "jquery": "^2.1.4",
-    "promise": "^7.0.1",
-    "shortid": "^2.2.2",
-    "connect": "3.0.1",
-    "express": "4.12.3",
     "minimist": "1.1.0",
+    "promise": "^7.0.1",
     "serve-static": "1.8.0",
+    "shortid": "^2.2.2",
+    "underscore": "^1.8.3",
     "vinyl-source-stream": "^1.1.0"
   },
   "scripts": {
diff --git a/public/index.html b/public/index.html
index 329c79d..33d7bda 100644
--- a/public/index.html
+++ b/public/index.html
@@ -131,11 +131,9 @@
     </div>
   </div>
   <div class="col-xs-3">
-    {{#if preview}}
     <div class="col-xs-12 card-preview">
-      <img src="{{preview}}">
+      <!--<img src="{{preview}}">-->
     </div>
-    {{/if}}
     <div class="col-xs-12 right-side right-side-foe foe">
       <div class="col-xs-5 field-discard field-single">
         discard deck
@@ -200,6 +198,24 @@
     <button class="button-pass">Pass</button>
   </div>
 </script>
+<script type="text/template" id="modal-template">
+  <div class="bbm-modal__topbar">
+    <h3 class="bbm-modal__title">Discard of {{openDiscard.name}}</h3>
+  </div>
+  <div class="bbm-modal__section">
+    {{#each openDiscard.discard}}
+    <div class="card" data-key="{{_key}}" data-id="{{_id}}">
+      <img src="../assets/cards/{{_data.img}}.png">
+    </div>
+    {{/each}}
+  </div>
+  <div class="bbm-modal__bottombar">
+    <div class="bbm-button bbm-close">close</div>
+  </div>
+</script>
+<script type="text/template" id="preview-template">
+  <img src="{{src}}">
+</script>
 <script src="../build/app.js"></script>
 </body>
 </html>
diff --git a/public/js/backbone.modal-min.js b/public/js/backbone.modal-min.js
new file mode 100644
index 0000000..3a79acc
--- /dev/null
+++ b/public/js/backbone.modal-min.js
@@ -0,0 +1,123 @@
+(function(){
+  var a = function(a, b){
+    return function(){
+      return a.apply(b, arguments)
+    }
+  }, b = {}.hasOwnProperty, c = function(a, c){
+    function d(){
+      this.constructor = a
+    }
+
+    for(var e in c)b.call(c, e) && (a[e] = c[e]);
+    return d.prototype = c.prototype, a.prototype = new d, a.__super__ = c.prototype, a
+  }, d = [].indexOf || function(a){
+    for(var b = 0, c = this.length; c > b; b++)if(b in this && this[b] === a)return b;
+    return -1
+  };
+  !function(a){
+    return "function" == typeof define && define.amd ? define(["underscore", "backbone", "exports"], a) : "object" == typeof exports ? a(require("underscore"), require("backbone"), exports) : a(_, Backbone, {})
+  }(function(b, e, f){
+    return f = function(f){
+      function g(){
+        this.triggerCancel = a(this.triggerCancel, this), this.triggerSubmit = a(this.triggerSubmit, this), this.triggerView = a(this.triggerView, this), this.clickOutsideElement = a(this.clickOutsideElement, this), this.clickOutside = a(this.clickOutside, this), this.checkKey = a(this.checkKey, this), this.rendererCompleted = a(this.rendererCompleted, this), this.args = Array.prototype.slice.apply(arguments), e.View.prototype.constructor.apply(this, this.args), this.setUIElements()
+      }
+
+      return c(g, f), g.prototype.prefix = "bbm", g.prototype.animate = !0, g.prototype.keyControl = !0, g.prototype.showViewOnRender = !0, g.prototype.render = function(a){
+        var c, d;
+        return c = this.serializeData(), (!a || b.isEmpty(a)) && (a = 0), this.$el.addClass("" + this.prefix + "-wrapper"), this.modalEl = e.$("<div />").addClass("" + this.prefix + "-modal"), this.template && this.modalEl.html(this.buildTemplate(this.template, c)), this.$el.html(this.modalEl), this.viewContainer ? (this.viewContainerEl = this.modalEl.find(this.viewContainer), this.viewContainerEl.addClass("" + this.prefix + "-modal__views")) : this.viewContainerEl = this.modalEl, e.$(":focus").blur(), (null != (d = this.views) ? d.length : void 0) > 0 && this.showViewOnRender && this.openAt(a), "function" == typeof this.onRender && this.onRender(), this.delegateModalEvents(), this.$el.fadeIn && this.animate ? (this.modalEl.css({opacity: 0}), this.$el.fadeIn({
+          duration: 100,
+          complete: this.rendererCompleted
+        })) : this.rendererCompleted(), this
+      }, g.prototype.rendererCompleted = function(){
+        var a;
+        return this.keyControl && (e.$("body").on("keyup.bbm", this.checkKey), this.$el.on("mouseup.bbm", this.clickOutsideElement), this.$el.on("click.bbm", this.clickOutside)), this.modalEl.css({opacity: 1}).addClass("" + this.prefix + "-modal--open"), "function" == typeof this.onShow && this.onShow(), null != (a = this.currentView) && "function" == typeof a.onShow ? a.onShow() : void 0
+      }, g.prototype.setUIElements = function(){
+        var a;
+        if(this.template = this.getOption("template"), this.views = this.getOption("views"), null != (a = this.views) && (a.length = b.size(this.views)), this.viewContainer = this.getOption("viewContainer"), this.animate = this.getOption("animate"), b.isUndefined(this.template) && b.isUndefined(this.views))throw new Error("No template or views defined for Backbone.Modal");
+        if(this.template && this.views && b.isUndefined(this.viewContainer))throw new Error("No viewContainer defined for Backbone.Modal")
+      }, g.prototype.getOption = function(a){
+        return a ? this.options && d.call(this.options, a) >= 0 && null != this.options[a] ? this.options[a] : this[a] : void 0
+      }, g.prototype.serializeData = function(){
+        var a;
+        return a = {}, this.model && (a = b.extend(a, this.model.toJSON())), this.collection && (a = b.extend(a, {items: this.collection.toJSON()})), a
+      }, g.prototype.delegateModalEvents = function(){
+        var a, c, d, e, f, g, h;
+        this.active = !0, a = this.getOption("cancelEl"), f = this.getOption("submitEl"), f && this.$el.on("click", f, this.triggerSubmit), a && this.$el.on("click", a, this.triggerCancel), h = [];
+        for(c in this.views)b.isString(c) && "length" !== c ? (d = c.match(/^(\S+)\s*(.*)$/), g = d[1], e = d[2], h.push(this.$el.on(g, e, this.views[c], this.triggerView))) : h.push(void 0);
+        return h
+      }, g.prototype.undelegateModalEvents = function(){
+        var a, c, d, e, f, g, h;
+        this.active = !1, a = this.getOption("cancelEl"), f = this.getOption("submitEl"), f && this.$el.off("click", f, this.triggerSubmit), a && this.$el.off("click", a, this.triggerCancel), h = [];
+        for(c in this.views)b.isString(c) && "length" !== c ? (d = c.match(/^(\S+)\s*(.*)$/), g = d[1], e = d[2], h.push(this.$el.off(g, e, this.views[c], this.triggerView))) : h.push(void 0);
+        return h
+      }, g.prototype.checkKey = function(a){
+        if(this.active)switch(a.keyCode) {
+          case 27:
+            return this.triggerCancel(a);
+          case 13:
+            return this.triggerSubmit(a)
+        }
+      }, g.prototype.clickOutside = function(){
+        var a;
+        return (null != (a = this.outsideElement) ? a.hasClass("" + this.prefix + "-wrapper") : void 0) && this.active ? this.triggerCancel() : void 0
+      }, g.prototype.clickOutsideElement = function(a){
+        return this.outsideElement = e.$(a.target)
+      }, g.prototype.buildTemplate = function(a, c){
+        var d;
+        return (d = "function" == typeof a ? a : b.template(e.$(a).html()))(c)
+      }, g.prototype.buildView = function(a, c){
+        var d;
+        if(a)return c && b.isFunction(c) && (c = c()), b.isFunction(a) ? (d = new a(c || this.args[0]), d instanceof e.View ? {
+          el: d.render().$el,
+          view: d
+        } : {el: a(c || this.args[0])}) : {view: a, el: a.$el}
+      }, g.prototype.triggerView = function(a){
+        var c, d, e, f, g, h, i;
+        if(null != a && "function" == typeof a.preventDefault && a.preventDefault(), f = a.data, d = this.buildView(f.view, f.viewOptions), this.currentView && (this.previousView = this.currentView, !(null != (i = f.openOptions) ? i.skipSubmit : void 0))){
+          if(("function" == typeof(g = this.previousView).beforeSubmit ? g.beforeSubmit(a) : void 0) === !1)return;
+          "function" == typeof(h = this.previousView).submit && h.submit()
+        }
+        this.currentView = d.view || d.el, c = 0;
+        for(e in this.views)f.view === this.views[e].view && (this.currentIndex = c), c++;
+        return f.onActive && (b.isFunction(f.onActive) ? f.onActive(this) : b.isString(f.onActive) && this[f.onActive].call(this, f)), this.shouldAnimate ? this.animateToView(d.el) : (this.shouldAnimate = !0, this.$(this.viewContainerEl).html(d.el))
+      }, g.prototype.animateToView = function(a){
+        var b, c, d, f, g, h, i;
+        return f = {
+          position: "relative",
+          top: -9999,
+          left: -9999
+        }, g = e.$("<tester/>").css(f), g.html(this.$el.clone().css(f)), 0 !== e.$("tester").length ? e.$("tester").replaceWith(g) : e.$("body").append(g), b = g.find(this.viewContainer ? this.viewContainer : "." + this.prefix + "-modal"), b.removeAttr("style"), d = b.outerHeight(), b.html(a), c = b.outerHeight(), d === c ? (this.$(this.viewContainerEl).html(a), "function" == typeof(h = this.currentView).onShow && h.onShow(), null != (i = this.previousView) && "function" == typeof i.destroy ? i.destroy() : void 0) : this.animate ? (this.$(this.viewContainerEl).css({opacity: 0}), this.$(this.viewContainerEl).animate({height: c}, 100, function(b){
+          return function(){
+            var c, d;
+            return b.$(b.viewContainerEl).css({opacity: 1}).removeAttr("style"), b.$(b.viewContainerEl).html(a), "function" == typeof(c = b.currentView).onShow && c.onShow(), null != (d = b.previousView) && "function" == typeof d.destroy ? d.destroy() : void 0
+          }
+        }(this))) : this.$(this.viewContainerEl).css({height: c}).html(a)
+      }, g.prototype.triggerSubmit = function(a){
+        var b, c;
+        return null != a && a.preventDefault(), e.$(a.target).is("textarea") || this.beforeSubmit && this.beforeSubmit(a) === !1 || this.currentView && this.currentView.beforeSubmit && this.currentView.beforeSubmit(a) === !1 ? void 0 : this.submit || (null != (b = this.currentView) ? b.submit : void 0) || this.getOption("submitEl") ? (null != (c = this.currentView) && "function" == typeof c.submit && c.submit(), "function" == typeof this.submit && this.submit(), this.regionEnabled ? this.trigger("modal:destroy") : this.destroy()) : this.triggerCancel()
+      }, g.prototype.triggerCancel = function(a){
+        return null != a && a.preventDefault(), this.beforeCancel && this.beforeCancel() === !1 ? void 0 : ("function" == typeof this.cancel && this.cancel(), this.regionEnabled ? this.trigger("modal:destroy") : this.destroy())
+      }, g.prototype.destroy = function(){
+        var a;
+        return e.$("body").off("keyup.bbm", this.checkKey), this.$el.off("mouseup.bbm", this.clickOutsideElement), this.$el.off("click.bbm", this.clickOutside), e.$("tester").remove(), "function" == typeof this.onDestroy && this.onDestroy(), this.shouldAnimate = !1, this.modalEl.addClass("" + this.prefix + "-modal--destroy"), a = function(a){
+          return function(){
+            var b;
+            return null != (b = a.currentView) && "function" == typeof b.remove && b.remove(), a.remove()
+          }
+        }(this), this.$el.fadeOut && this.animate ? (this.$el.fadeOut({duration: 200}), b.delay(function(){
+          return a()
+        }, 200)) : a()
+      }, g.prototype.openAt = function(a){
+        var c, d, e, f, g;
+        b.isNumber(a) ? c = a : b.isNumber(a._index) && (c = a._index), e = 0;
+        for(f in this.views)if("length" !== f)if(b.isNumber(c))e === c && (g = this.views[f]), e++;
+        else if(b.isObject(a))for(d in this.views[f])a[d] === this.views[f][d] && (g = this.views[f]);
+        return g && (this.currentIndex = b.indexOf(this.views, g), this.triggerView({data: b.extend(g, {openOptions: a})})), this
+      }, g.prototype.next = function(a){
+        return null == a && (a = {}), this.currentIndex + 1 < this.views.length ? this.openAt(b.extend(a, {_index: this.currentIndex + 1})) : void 0
+      }, g.prototype.previous = function(a){
+        return null == a && (a = {}), this.currentIndex - 1 < this.views.length - 1 ? this.openAt(b.extend(a, {_index: this.currentIndex - 1})) : void 0
+      }, g
+    }(e.View), e.Modal = f, e.Modal
+  })
+}).call(this);
\ No newline at end of file
diff --git a/public/js/client.js b/public/js/client.js
index 0f797ca..aefd75a 100644
--- a/public/js/client.js
+++ b/public/js/client.js
@@ -1,6 +1,7 @@
 /*("http://localhost:16918")*/
 var socketCluster = require("socketcluster-client");
 var Backbone = require("backbone");
+require("./backbone.modal-min");
 var Handlebars = require("handlebars");
 var $ = require("jquery");
 //var Lobby = require("./client-lobby");
@@ -97,11 +98,11 @@ var App = Backbone.Router.extend({
 
 var SideView = Backbone.View.extend({
   el: ".container",
-  template: Handlebars.compile('<div class="card" data-key="{{_key}}" data-id="{{_id}}">' +
+  template: Handlebars.compile('<div class="card{{#if _disabled}} disabled{{/if}}" data-key="{{_key}}" data-id="{{_id}}">' +
   '<img src="../assets/cards/{{_data.img}}.png">' +
   '</div>'),
   templateCards: Handlebars.compile('{{#each this}}' +
-  '<div class="card" data-key="{{_key}}" data-id="{{_id}}">' +
+  '<div class="card{{#if _disabled}} disabled{{/if}}" data-key="{{_key}}" data-id="{{_id}}">' +
   '{{#if _boost}}<span>+{{_boost}}</span>{{/if}}' +
   '<img src="../assets/cards/{{_data.img}}.png">' +
   '</div>' +
@@ -206,6 +207,7 @@ var SideView = Backbone.View.extend({
 var BattleView = Backbone.View.extend({
   className: "container",
   template: Handlebars.compile($("#battle-template").html()),
+  templatePreview: Handlebars.compile($("#preview-template").html()),
   initialize: function(options){
     var self = this;
     var user = this.user = options.user;
@@ -214,54 +216,14 @@ var BattleView = Backbone.View.extend({
 
     $(this.el).prependTo('body');
 
-    this.listenTo(user, "change:showPreview", this.render);
+    this.listenTo(user, "change:showPreview", this.renderPreview);
     this.listenTo(user, "change:waiting", this.render);
     this.listenTo(user, "change:passing", this.render);
+    this.listenTo(user, "change:openDiscard", this.render);
 
     this.$hand = this.$el.find(".field-hand");
     this.$preview = this.$el.find(".card-preview");
 
-    /*//this.battleChannel = app.socket.subscribe()
-
-    app.receive("update:hand", function(data){
-      if(user.get("roomSide") == data._roomSide){
-        self.handCards = JSON.parse(data.cards);
-        self.render();
-      }
-    });
-
-    app.receive("update:info", function(data){
-      var _side = data._roomSide;
-      var infoData = data.info;
-      var leader = data.leader;
-
-
-      var side = yourSide;
-      if(user.get("roomSide") != _side){
-        side = otherSide;
-      }
-      side.infoData = infoData;
-      side.leader = leader;
-      side.render();
-    });
-
-    app.receive("update:fields", function(data){
-      var close, ranged, siege;
-      var _side = data._roomSide;
-
-      var side = yourSide;
-      if(user.get("roomSide") != _side){
-        side = otherSide;
-      }
-
-
-      side.field.close = data.close;
-      side.field.ranged = data.ranged;
-      side.field.siege = data.siege;
-      side.field.weather = data.weather;
-
-      side.render();
-    })*/
 
     var interval = setInterval(function(){
       if(!user.get("room")) return;
@@ -275,15 +237,15 @@ var BattleView = Backbone.View.extend({
     yourSide = this.yourSide = new SideView({side: ".player", app: this.app, battleView: this});
     otherSide = this.otherSide = new SideView({side: ".foe", app: this.app, battleView: this});
 
-    /*yourSide = this.yourSide = new SideView({side: ".player", app: app, battleView: this});
-    otherSide = this.otherSide = new SideView({side: ".foe", app: app, battleView: this});*/
   },
   events: {
     "mouseover .card": "onMouseover",
     "mouseleave .card": "onMouseleave",
     "click .field-hand": "onClick",
     "click .battleside.player": "onClickDecoy",
-    "click .button-pass": "onPassing"
+    "click .button-pass": "onPassing",
+    "click .field-discard": "openDiscard",
+    "click .field-leader": "clickLeader"
   },
   onPassing: function(){
     if(this.user.get("passing")) return;
@@ -294,11 +256,21 @@ var BattleView = Backbone.View.extend({
   onClick: function(e){
     if(!!this.user.get("waiting")) return;
     if(!!this.user.get("passing")) return;
+
     var self = this;
     var $card = $(e.target).closest(".card");
     var id = $card.data("id");
     var key = $card.data("key");
 
+    if(!!this.user.get("waitForDecoy")){
+      if(id === this.user.get("waitForDecoy")){
+        this.user.set("waitForDecoy", false);
+        this.app.send("cancel:decoy");
+        this.render();
+      }
+      return;
+    }
+
     this.app.send("play:cardFromHand", {
       id: id
     });
@@ -306,17 +278,7 @@ var BattleView = Backbone.View.extend({
     if(key === "decoy"){
       console.log("its decoy!!!");
       this.user.set("waitForDecoy", id);
-      /*
-            this.$el.find(".battleside.player").on("click", ".card", function(e) {
-              console.log("replacement card found: ");
-              var $card = $(e.target).closest(".card");
-              var _id = $card.data("id");
-              self.app.send("decoy:replaceWith", {
-                oldCard: id,
-                newCard: _id
-              })
-              self.$el.find(".battleside.player").off("click");
-            });*/
+      this.render();
     }
   },
   onClickDecoy: function(e){
@@ -336,22 +298,54 @@ var BattleView = Backbone.View.extend({
   onMouseleave: function(e){
     this.user.set("showPreview", null);
   },
+  openDiscard: function(e){
+    var $discard = $(e.target).closest(".field-discard");
+    console.log("opened discard");
+    var side;
+    if($discard.parent().hasClass("player")){
+      side = this.yourSide;
+    } else {
+      side = this.otherSide;
+    }
+    this.user.set("openDiscard", {
+      discard: side.infoData.discard,
+      name: side.infoData.name
+    });
+  },
   render: function(){
     var self = this;
     this.$el.html(this.template({
-      cards: self.handCards,
-      preview: self.user.get("showPreview")
+      cards: self.handCards/*,
+      preview: self.user.get("showPreview")*/
     }));
     if(!(this.otherSide && this.yourSide)) return;
     this.otherSide.render();
     this.yourSide.render();
-    /* this.$el()
-    if(!(this.yourSide && this.otherSide))
-      return this;
-    this.yourSide.render();
-    this.otherSide.render();*/
+
+
+    if(this.user.get("openDiscard")){
+      var modal = new Modal({model: this.user});
+      this.$el.prepend(modal.render().el);
+    }
+
+    if(this.user.get("waitForDecoy")){
+      var id = this.user.get("waitForDecoy");
+      this.$el.find("[data-id='" + id + "']").addClass("activeCard");
+    }
     return this;
   },
+  renderPreview: function(){
+    this.$el.find(".card-preview").html(this.templatePreview({src: this.user.get("showPreview")}))
+  },
+  clickLeader: function(e) {
+    var $card = $(e.target).closest(".field-leader");
+    console.log("click leader");
+    if(!$card.parent().hasClass("player")) return;
+    if($card.hasClass("disabled")) return;
+
+
+    this.app.send("activate:leader")
+  },
   setUpBattleEvents: function(channelName){
     this.battleChannel = this.app.socket.subscribe(channelName);
     var self = this;
@@ -363,6 +357,7 @@ var BattleView = Backbone.View.extend({
       if(event === "update:hand"){
         if(user.get("roomSide") == data._roomSide){
           self.handCards = JSON.parse(data.cards);
+          self.user.set("handCards", self.handCards);
           self.render();
         }
       }
@@ -377,6 +372,9 @@ var BattleView = Backbone.View.extend({
         }
         side.infoData = infoData;
         side.leader = leader;
+
+        side.infoData.discard = JSON.parse(side.infoData.discard);
+
         side.render();
       }
       else if(event === "update:fields"){
@@ -396,6 +394,14 @@ var BattleView = Backbone.View.extend({
   }
 });
 
+var Modal = Backbone.Modal.extend({
+  template: Handlebars.compile($("#modal-template").html()),
+  cancelEl: ".bbm-close",
+  cancel: function(){
+    this.model.set("openDiscard", false);
+  }
+});
+
 var User = Backbone.Model.extend({
   defaults: {
     name: ""
@@ -432,6 +438,7 @@ var User = Backbone.Model.extend({
       var waiting = data.waiting;
       self.set("waiting", waiting);
     })
+
     app.receive("set:passing", function(data){
       var passing = data.passing;
       self.set("passing", passing);
diff --git a/public/scss/_backbone.modal.sass b/public/scss/_backbone.modal.sass
new file mode 100644
index 0000000..8b1a6fe
--- /dev/null
+++ b/public/scss/_backbone.modal.sass
@@ -0,0 +1,25 @@
+/* Modal positioning */
+.bbm-wrapper
+  box-sizing: border-box
+  position: fixed
+  left: 0
+  top: 0
+  width: 100%
+  height: 100%
+  z-index: 100
+  padding: 50px 10px
+
+  *
+    box-sizing: border-box
+
+  overflow: auto
+
+.bbm-modal
+  border-radius: 3px
+  margin: auto
+  width: auto
+  max-width: 550px
+
+.bbm-views
+  width: 100%
+  box-sizing: border-box
diff --git a/public/scss/_backbone.modal.theme.sass b/public/scss/_backbone.modal.theme.sass
new file mode 100644
index 0000000..2832091
--- /dev/null
+++ b/public/scss/_backbone.modal.theme.sass
@@ -0,0 +1,130 @@
+.bbm-wrapper
+  background: rgba(0,0,0,.75)
+  -webkit-transition: background-color .3s
+
+.bbm-modal
+  background: white
+  box-shadow: 0 0px 6px rgba(0,0,0,.6), 0 1px 2px rgba(0,0,0,.9)
+
+
+/* BLOCKS */
+.bbm-modal__topbar,
+.bbm-modal__bottombar
+  padding: 0 30px
+
+.bbm-modal__topbar
+  border-bottom: 1px solid rgba(0,0,0,.1)
+  margin:
+    bottom: 30px
+
+  >ul
+    list-style: none
+    text-align: center
+    padding: 0
+    margin: 0
+
+.bbm-modal__tab
+  display: inline-block
+  padding: 15px 10px
+
+  a
+    font:
+      size: 16px
+      weight: bold
+    color: #999
+
+    &:hover,
+    &.active
+      color: #222
+
+.bbm-modal__title
+  padding: 20px 0 19px
+  margin: 0
+  font:
+    weight: normal
+    size: 22px
+  line-height: 1em
+  color: #312D3A
+
+.bbm-modal__section
+  padding: 0 30px
+  margin-top: 0px
+  font:
+    size: 16px
+  line-height: 26px
+  color: #575656
+
+  p
+    font:
+      size: 16px
+    line-height: 26px
+    color: #575656
+
+    &:last-child
+      padding: 0
+      margin-bottom: 0
+
+  a
+    color: #FF643C
+
+  h3
+    margin: 0
+    font-size: 20px
+    line-height: 1em
+
+.bbm-modal__bottombar
+  border-top: 1px solid rgba(0,0,0,.1)
+  padding: 18px
+  text-align: right
+  margin-top: 30px
+
+
+/* MODULES */
+.bbm-group
+  content: ""
+  display: table
+  clear: both
+
+.bbm-button
+  display: inline-block
+  color: rgba(49,45,58,.8)
+  text-decoration: none
+  font:
+    size: 14px
+    weight: 500
+  position: relative
+  line-height: 1em
+  padding: 10px 14px
+  border-radius: 3px
+  background: #FCFCFC
+  cursor: default
+
+  background-image: -o-linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.15) 100%)
+  background-image: -moz-linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.15) 100%)
+  background-image: -webkit-linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.15) 100%)
+  background-image: -ms-linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.15) 100%)
+  background-image: linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.15) 100%)
+
+  -moz-box-shadow:    0px 1px 1px 0px rgba(0,0,0,0.10), inset 0px 0px 0px 1px rgba(0,0,0,0.20)
+  -webkit-box-shadow: 0px 1px 1px 0px rgba(0,0,0,0.10), inset 0px 0px 0px 1px rgba(0,0,0,0.20)
+  box-shadow:         0px 1px 1px 0px rgba(0,0,0,0.10), inset 0px 0px 0px 1px rgba(0,0,0,0.20)
+
+  &.inactive
+    opacity: .5
+    pointer-events: none
+
+  &:active
+    background-image: -o-linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.25) 100%)
+    background-image: -moz-linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.25) 100%)
+    background-image: -webkit-linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.25) 100%)
+    background-image: -ms-linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.25) 100%)
+    background-image: linear-gradient(rgba(70,30,170,0) 0%, rgba(65,61,75,.25) 100%)
+
+    -moz-box-shadow:    inset 0px 1px 2px 0px rgba(0,0,0,0.50), inset 0px 0px 0px 1px rgba(0,0,0,0.20)
+    -webkit-box-shadow: inset 0px 1px 2px 0px rgba(0,0,0,0.50), inset 0px 0px 0px 1px rgba(0,0,0,0.20)
+    box-shadow:         inset 0px 1px 2px 0px rgba(0,0,0,0.50), inset 0px 0px 0px 1px rgba(0,0,0,0.20)
+
+
+/* ANIMATIONS */
+
+/* Open modal */
diff --git a/public/scss/_style.sass b/public/scss/_style.sass
new file mode 100644
index 0000000..7563485
--- /dev/null
+++ b/public/scss/_style.sass
@@ -0,0 +1,45 @@
+// Custom styling here
+
+a
+  text-decoration: none
+  font-style: normal
+
+// Add icons to tabs
+.bbm-modal__tab
+  padding: 0
+
+  a
+    display: block
+    padding:
+      top: 55px
+      bottom: 10px
+      left: 20px
+      right: 20px
+    position: relative
+    font:
+      size: 13px
+
+    &:before
+      position: absolute
+      content: ""
+      background: url(img/tab-icons.png)
+      left: 50%
+      top: 10px
+      margin:
+        left: -20px
+      width: 40px
+      height: 40px
+      opacity: .5
+
+    &.active
+      opacity: 1
+
+      &:before
+        opacity: 1
+
+
+  &:last-child
+    margin-left: -5px
+    a
+      &:before
+        background-position: -40px
\ No newline at end of file
diff --git a/public/scss/main.scss b/public/scss/main.scss
index cbe1eb0..b30cc86 100644
--- a/public/scss/main.scss
+++ b/public/scss/main.scss
@@ -1,3 +1,7 @@
+//@import "style";
+@import "backbone.modal";
+@import "backbone.modal.theme";
+
 $height: 600px;
 $game-height: 800px;
 
@@ -91,12 +95,22 @@ $game-height: 800px;
     margin-left: 30px;
     cursor: default;
   }
+
+  &.disabled {
+    opacity: 0.5;
+  }
+
+  &.activeCard {
+    position: relative;
+    z-index: 11;
+    transform: scale(1.5,1.5) !important;
+  }
 }
 
 .card-preview {
   position: absolute;/*
   display: none;*/
-  z-index: 10;
+  z-index: 110;
 }
 
 i {
diff --git a/server/Battle.js b/server/Battle.js
index e67d210..3f02d65 100644
--- a/server/Battle.js
+++ b/server/Battle.js
@@ -80,6 +80,10 @@ var Battle = (function(){
     /*if(__flag instanceof  Battleside) {
       side = __flag;
     }*/
+    if(!(side instanceof Battleside)){
+      console.trace("side is not a battleside!");
+      return
+    }
     if(side.isPassing()){
       if(__flag){
         return this.startNextRound();
@@ -87,10 +91,7 @@ var Battle = (function(){
       return this.switchTurn(side.foe, 1);
     }
 
-    /*PubSub.publish("onEachTurn");*/
     this.runEvent("EachTurn");
-    /*
-        PubSub.publish("turn/" + side.getID());*/
     this.runEvent("Turn" + side.getID());
     console.log("current Turn: ", side.getName());
 
@@ -100,6 +101,7 @@ var Battle = (function(){
     var loser = this.checkRubies();
     if(this.checkIfIsOver()){
       console.log("its over!");
+      this.update();
       return;
     }
 
@@ -153,6 +155,7 @@ var Battle = (function(){
       obj.cb = obj.cb.bind(ctx)
       obj.cb.apply(ctx, obj.onArgs.concat(args));
     });
+    this.update();
   }
 
   r.on = function(eventid, cb, ctx, args){
@@ -161,9 +164,10 @@ var Battle = (function(){
     var event = "on" + eventid;
 
     var obj = {};
-    if(!ctx) {
+    if(!ctx){
       obj.cb = cb;
-    } else {
+    }
+    else {
       obj.cb = cb.bind(ctx);
     }
     obj.onArgs = args;
@@ -187,6 +191,7 @@ var Battle = (function(){
 
   r.off = function(eventid){
     var event = "on" + eventid;
+    if(!this.events[event]) return;
     this.events[event].forEach(function(e){
       e = null;
     });
@@ -215,7 +220,7 @@ var Battle = (function(){
     //tie
     this.p1.removeRuby();
     this.p2.removeRuby();
-    return 0;
+    return Math.random() > 0.5 ? this.p1 : this.p2;
   }
 
 
diff --git a/server/Battleside.js b/server/Battleside.js
index 5360f04..9047ea8 100644
--- a/server/Battleside.js
+++ b/server/Battleside.js
@@ -4,7 +4,6 @@ var Deck = require("./Deck");
 var Hand = require("./Hand");
 var Card = require("./Card");
 var Field = require("./Field");
-//var PubSub = require("pubsub-js");
 
 
 var Battleside;
@@ -37,6 +36,22 @@ Battleside = (function(){
     this.off = this.battle.off.bind(this.battle);
 
 
+    this.receive("activate:leader", function(){
+      if(self._isWaiting) return;
+      if(self.isPassing()) return;
+
+      console.log("leader activated");
+
+      var leaderCard = self.getLeader();
+      if(leaderCard.isDisabled()) return;
+
+
+      var ability = leaderCard.getAbility();
+
+      ability.onActivate.apply(self);
+      leaderCard.setDisabled(true);
+      self.update();
+    })
     this.receive("play:cardFromHand", function(data){
       if(self._isWaiting) return;
       if(self.isPassing()) return;
@@ -51,14 +66,15 @@ Battleside = (function(){
       if(card === -1) throw new Error("decoy:replace | unknown card");
       self.runEvent("Decoy:replaceWith", self, [card]);
     })
-    this.receive("set:passing", function() {
+    this.receive("cancel:decoy", function(){
+      self.off("Decoy:replaceWith");
+    })
+    this.receive("set:passing", function(){
       self.setPassing(true);
-      self.update();/*
-      PubSub.publish("nextTurn");*/
+      self.update();
       self.runEvent("NextTurn", null, [self.foe]);
     })
 
-    /*PubSub.subscribe("turn/" + this.getID(), this.onTurnStart.bind(this));*/
     this.on("Turn" + this.getID(), this.onTurnStart, this);
   };
   var r = Battleside.prototype;
@@ -69,11 +85,7 @@ Battleside = (function(){
    */
   r._name = null;
   r._discard = null;
-  /*r.leaderField = null;
-  r.closeField = null;
-  r._range = null;
-  r._siege = null;
-  r._field = null;*/
+
   r._rubies = 2;
   r._score = 0;
   r._isWaiting = null;
@@ -89,7 +101,7 @@ Battleside = (function(){
   r.battle = null;
   r.deck = null;
 
-  r.isPassing = function() {
+  r.isPassing = function(){
     return this._passing;
   }
 
@@ -97,7 +109,7 @@ Battleside = (function(){
     this.field[Card.TYPE.WEATHER] = p2.field[Card.TYPE.WEATHER] = Field(Card.TYPE.WEATHER);
   }
 
-  r.findCardOnFieldByID = function(id) {
+  r.findCardOnFieldByID = function(id){
     for(var key in this.field) {
       var field = this.field[key];
       var card = field.getCard(id);
@@ -106,7 +118,7 @@ Battleside = (function(){
     return -1;
   }
 
-  r.setPassing = function(b) {
+  r.setPassing = function(b){
     this._passing = b;
     this.send("set:passing", {passing: this._passing}, true);
   }
@@ -129,6 +141,10 @@ Battleside = (function(){
     this.field[Card.TYPE.LEADER].add(leaderCard[0]);
   }
 
+  r.getLeader = function(){
+    return this.field[Card.TYPE.LEADER].get()[0];
+  }
+
   r.getID = function(){
     return this.n;
   }
@@ -158,19 +174,20 @@ Battleside = (function(){
       lives: this._rubies,
       score: this.calcScore(),
       hand: this.hand.length(),
+      discard: this.getDiscard(true),
       passing: this._passing
     }
   }
 
-  r.getRubies = function() {
+  r.getRubies = function(){
     return this._rubies;
   }
 
-  r.getScore = function() {
+  r.getScore = function(){
     return +this.calcScore();
   }
 
-  r.removeRuby = function() {
+  r.removeRuby = function(){
     this._rubies--;
   }
 
@@ -210,14 +227,14 @@ Battleside = (function(){
   r.playCard = function(card){
     if(card === null || card === -1) return;
 
-    this.hand.remove(card);
-
     if(!this.placeCard(card)) return;
 
+    this.hand.remove(card);
+
     this.update();
 
 
-    this.runEvent("NextTurn", this, [this.foe]);
+    this.runEvent("NextTurn", null, [this.foe]);
   }
 
   r.placeCard = function(card){
@@ -251,7 +268,7 @@ Battleside = (function(){
       if(ability.replaceWith){
         obj._canclePlacement = true;
 
-        this.on("Decoy:replaceWith", function(replaceCard) {
+        this.on("Decoy:replaceWith", function(replaceCard){
           if(replaceCard.getType() == Card.TYPE.LEADER ||
           replaceCard.getType() == Card.TYPE.WEATHER ||
           replaceCard.getType() == Card.TYPE.SPECIAL){
@@ -261,11 +278,12 @@ Battleside = (function(){
           self.off("Decoy:replaceWith");
           var field = self.field[replaceCard.getType()];
 
+
           field.replaceWith(replaceCard, card);
 
           self.hand.add(replaceCard);
-/*
-          self.update();*/
+          self.hand.remove(card);
+          self.update();
 
           self.runEvent("NextTurn", null, [self.foe]);
         })
@@ -278,6 +296,7 @@ Battleside = (function(){
         this.on("EachCardPlace", ability.onEachCardPlace, this, [card]);
       }
 
+      this.update();
     }
   }
 
@@ -290,7 +309,7 @@ Battleside = (function(){
     }
   }
 
-  r.clearMainFields = function() {
+  r.clearMainFields = function(){
     var cards1 = this.field[Card.TYPE.CLOSE_COMBAT].removeAll();
     var cards2 = this.field[Card.TYPE.RANGED].removeAll();
     var cards3 = this.field[Card.TYPE.SIEGE].removeAll();
@@ -299,14 +318,21 @@ Battleside = (function(){
     this.addToDiscard(cards);
   }
 
-  r.addToDiscard = function(cards) {
+  r.addToDiscard = function(cards){
     var self = this;
-    cards.forEach(function(card) {
+    cards.forEach(function(card){
       self._discard.push(card);
     });
   }
 
-  r.resetNewRound = function() {
+  r.getDiscard = function(json){
+    if(json){
+      return JSON.stringify(this._discard);
+    }
+    return this._discard;
+  }
+
+  r.resetNewRound = function(){
     this.clearMainFields();
     this.setPassing(false);
   }
diff --git a/server/Card.js b/server/Card.js
index dca0d1b..a096643 100644
--- a/server/Card.js
+++ b/server/Card.js
@@ -9,9 +9,11 @@ var Card = (function(){
     /**
      * constructor here
      */
+    this.setDisabled(false);
     this.channel = {};
     this._key = key;
     this._data = CardData[key];
+    this._data.key = key;
     this._boost = 0;
     this._forcedPower = -1;
     this._init();
@@ -29,6 +31,7 @@ var Card = (function(){
   r._owner = null;
   r._boost = null;
   r._forcedPower = null;
+  r._disabled = null;
   Card.__id = 0;
   Card.TYPE = {
     CLOSE_COMBAT: 0,
@@ -97,6 +100,14 @@ var Card = (function(){
     this._boost += nr;
   }
 
+  r.isDisabled = function() {
+    return this._disabled;
+  }
+
+  r.setDisabled = function(b) {
+    this._disabled = b;
+  }
+
   r.getProperty = function(prop){
     return this._data[prop];
   }
diff --git a/server/Deck.js b/server/Deck.js
index e657a1e..2978da8 100644
--- a/server/Deck.js
+++ b/server/Deck.js
@@ -44,19 +44,12 @@ var Deck = (function(){
     return this._deck;
   }
 
-  r.draw = function(times){
+  r.draw = function(){
     if(!this._deck.length) return 0;
     var card = this.pop();
     return card;
   }
 
-  /*
-    r._loadCards = function(){
-      var n = this._originalDeck.length;
-      for(var i = 0; i < n; i++) {
-        this._deck.push(CardManager().add(this._originalDeck[i], this._owner));
-      }
-    }*/
 
   r._loadCards = function(){
     this._deck = this.getDeck().map(function(cardkey){
@@ -77,7 +70,6 @@ var Deck = (function(){
       if(card.getProperty(key) == val){
         res.push(card);
       }
-
     });
     return res;
   }
@@ -93,7 +85,7 @@ var Deck = (function(){
       }*/
       var c = this.getDeck()[i];
       if(c.getID() === card.getID()){
-        return this.getDeck().splice(i, 1);
+        return this.getDeck().splice(i, 1)[0];
       }
     }
     return -1;
diff --git a/server/Hand.js b/server/Hand.js
index 06e9a94..95323d0 100644
--- a/server/Hand.js
+++ b/server/Hand.js
@@ -42,6 +42,7 @@ var Hand = (function(){
   r.remove = function(id){
     var n = this.length();
 
+    //console.trace(id);
     id = id instanceof Card ? id.getID() : id;
 
     for(var i = 0; i < n; i++) {
diff --git a/server/Room.js b/server/Room.js
index 83fd37e..d17529d 100644
--- a/server/Room.js
+++ b/server/Room.js
@@ -56,23 +56,6 @@ var Room = (function(){
   r.isOpen = function(){
     return !(this._users.length >= 2);
   }
-/*
-
-  r.send = function(event, data){
-    */
-/*this.socket.publish(this._id + "|" + event, data);
-    this.socket.publish(this._id, {
-      event: event,
-      data: data
-    });
-    var subs = this.socket.subscriptions();
-    subs.forEach(function(sub) {
-
-    });*//*
-
-    this._channel.publish(event, data);
-  }
-*/
 
   r.getPlayers = function(){
     return this._users;
@@ -92,26 +75,13 @@ var Room = (function(){
     if(this.bothReady()){
       this._battle.init();
     }
-    /*
-    if(!this.checkIfReady()) return;
 
-    this._users[0].send("init:battle", {side: "p1"});
-    this._users[1].send("init:battle", {side: "p2"});
-    if(!this.checkIfReady()) return;
-    this._battle.init();*/
   }
 
   r.bothReady = function(){
     return !!this._ready[this._users[0].getID()] && !!this._ready[this._users[1].getID()];
   }
-  /*
-    r.checkIfReady = function(){
-      for(var i = 0; i < this._users.length; i++) {
-        if(!this._ready[this._users[i].getID()]) return false;
-      }
-      return true;
-    }*/
-
+  
 
   return Room;
 })();
diff --git a/server/_server.js b/server/_server.js
deleted file mode 100644
index d00d4a7..0000000
--- a/server/_server.js
+++ /dev/null
@@ -1,2 +0,0 @@
-var socket = require("./Socket")();
-