Fixes config; shores up fences and drywall.
authordsc <david.schoonover@gmail.com>
Sun, 9 Jan 2011 17:20:59 +0000 (09:20 -0800)
committerdsc <david.schoonover@gmail.com>
Sun, 9 Jan 2011 17:20:59 +0000 (09:20 -0800)
data/types/levels.yaml
src/Y/modules/y.scaffold.cjs
src/ezl/layer/layer.cjs
src/tanks/effects/stat.cjs
src/tanks/map/drywall.cjs
src/tanks/map/fence.cjs
src/tanks/map/wall.cjs
src/tanks/thing/player.cjs
src/tanks/ui/configui.cjs
src/tanks/ui/main.cjs

index dc0aa88..47aa321 100644 (file)
@@ -35,7 +35,13 @@ types:
           - type: fence
             args: [210,210, 30,30]
           - type: drywall
-            args: [50,350, 100,100]
+            args: [50,350, 50,50]
+          - type: drywall
+            args: [100,350, 50,50]
+          - type: drywall
+            args: [50,400, 50,50]
+          - type: drywall
+            args: [100,400, 50,50]
           - type: drywall
             args: [150,300, 50,50]
         units:
index a17a77e..4fdbfe7 100644 (file)
@@ -53,6 +53,7 @@ Y.subclass('Field', {
     init : function initField(chain, def, val, options){
         options = options || {};
         this.__emitter__ = new Emitter(this);
+        this.onChange = this.onChange.bind(this);
         
         this.id    = chain;
         this.def   = def;
@@ -72,7 +73,7 @@ Y.subclass('Field', {
         this.build()
             .update(this.val);
         
-        jQuery(this.selector).live('change', this.onChange.bind(this));
+        jQuery(this.selector).live('change', this.onChange);
     },
     
     build : function build(){
@@ -99,7 +100,7 @@ Y.subclass('Field', {
     },
     
     update : function update(val){
-        var el = jQuery(this.selector);
+        var el = jQuery(this.selector).add(this.elField);
         if (val !== this.val) {
             this.old = this.val;
             this.val = val;
@@ -107,7 +108,7 @@ Y.subclass('Field', {
                 'key'    : this.id,
                 'oldval' : this.old,
                 'newval' : this.val,
-                'el'     : jQuery(this.selector)
+                'el'     : el
             });
             el.val(val);
         }
@@ -118,7 +119,7 @@ Y.subclass('Field', {
     },
     
     onChange : function onChange(evt){
-        var el = jQuery(this.selector);
+        var el = jQuery(evt.target);
         if (this.type === 'checkbox')
             this.update( el.attr('checked') );
         else
@@ -157,9 +158,11 @@ function create(config, el){
             fields[chain] = field;
             group.append(field.el);
             config.addEventListener('set:'+chain, function onConfigSet(evt){
+                // console.log('Config at '+evt.data.key+' changed!', field, evt.newval, evt);
                 field.update(evt.data.newval);
             });
             field.addEventListener('change', function onFieldChange(evt){
+                // console.log('Field '+evt.data.key+' changed!', field, evt.newval, evt);
                 config.set(evt.data.key, evt.data.newval);
             });
             
index 97dcdd3..3cae1c7 100644 (file)
@@ -27,7 +27,7 @@ Y.subclass('Layer', {
     ctx        : null,
     animActive : null,
     animQueue  : null,
-    
+    _erased    : null,
     
     layerWidth  : 0,  canvasWidth : 0,
     layerHeight : 0,  canvasHeight : 0,
@@ -60,6 +60,7 @@ Y.subclass('Layer', {
         this.children   = new Y.YArray();
         this.animActive = new Y.YArray();
         this.animQueue  = new Y.YArray();
+        this._erased    = new Y.YArray();
         
         this.loc      = new Loc(0,0);
         this.negBleed = new Loc(0,0);
@@ -135,7 +136,7 @@ Y.subclass('Layer', {
      */
     empty : function empty(ctx){
         this.children.invoke('remove');
-        this.clear(ctx);
+        this.clear(false, ctx);
         return this;
     },
     
@@ -485,6 +486,7 @@ Y.subclass('Layer', {
             this._openPath(_ctx);
             this.render(_ctx);
             this._closePath(_ctx);
+            this._erased.forEach(this._erase, this);
         }
         
         this.children.invoke('draw', ctx, force);
@@ -533,10 +535,30 @@ Y.subclass('Layer', {
         return this;
     },
     
+    erase : function erase(x,y, w,h, alsoChildren){
+        this._erased.push({ 'x':x,'y':y, 'w':w,'h':h, 'alsoChildren':alsoChildren });
+        this.dirty = true;
+        if (alsoChildren)
+            this.children.invoke('erase', x,y, w,h, alsoChildren);
+        return this;
+    },
+    
+    _erase : function _erase(args){
+        var x = args.x, y = args.y
+        ,   w = args.w, h = args.h;
+        
+        if (w < 0) w = this.canvas.width()  + w;
+        if (h < 0) h = this.canvas.height() + h;
+        
+        this.ctx.beginPath();
+        this.ctx.clearRect(x,y, w,h);
+        this.ctx.closePath();
+    },
+    
     /**
      * Clears this layer and optionally all children.
      */
-    clear : function clear(ctx, clearChildren){
+    clear : function clear(alsoChildren, ctx){
         var w = this.canvas.width()
         ,   h = this.canvas.height();
         ctx = ctx || this.ctx;
@@ -544,7 +566,7 @@ Y.subclass('Layer', {
         ctx.setTransform(1,0,0,1,0,0);
         ctx.clearRect(-w,-h, 2*w,2*h);
         ctx.closePath();
-        if (clearChildren)
+        if (alsoChildren)
             this.children.invoke('clear');
         return this;
     },
index aa3f972..82209f9 100644 (file)
@@ -44,17 +44,25 @@ Y.subclass('Stat', {
     },
     
     /**
-     * @param {Number} dv Amount to add to current value.
+     * @param {Number} v New value for this stat. Values above the max will be set to max.
      * @return {this}
      */
-    modify : function modify(dv){
-        var v = Math.min(this.max, this.val+dv);
+    set : function set(v){
+        var v = Math.min(this.max, v);
         this.val = (this.integer ? Math.round(v) : v);
         this.ratio = this.val / this.max;
         return this;
     },
     
     /**
+     * @param {Number} dv Amount to add to current value. Values above the max will be set to max.
+     * @return {this}
+     */
+    modify : function modify(dv){
+        return this.set(this.val+dv);
+    },
+    
+    /**
      * @param {Number} dv Amount to add to base and max value.
      * @param {StatInvariant} [inv=FULL] Invariant to restore for current value.
      * @return {this}
index d4f8156..4d2c4c4 100644 (file)
@@ -10,91 +10,43 @@ var Y     = require('Y').Y
 Drywall =
 exports['Drywall'] =
 Wall.subclass('Drywall', {
-    minSplitSize : 25,
+    // config
+    minSplitSize : null,
+    get canSplit() { return (this.width > this.minSplitSize); },
     
+    // instance
     isReflective : false,
     isBoundary   : false,
-    isSplittable : true,
     
-    fillColors : [[139,49,20], [245,154,180], [255,246,174]],
-    
-    fillStyle    : 'rgba(249,190,0, 0.25)',
-    strokeStyle  : 'rgba(249,190,0, 0.5)',
+    fillStyle    : 'rgba(196,167,158, 0.25)',
+    strokeStyle  : 'rgba(0,0,0, 0.25)',
     lineWidth    : 1,
     
     stats : {
-        hp : 3,
+        hp : 1,
     },
     
     
+    
     init : function initDrywall(x,y, w,h, hp){
-        this.stats = Y.extend({}, this.stats);
-        this.stats.hp = hp || this.stats.hp;
-        
-        var line = Math.round(Math.min(w,h) * 0.2);
-        this.lineWidth = clamp(line, 1, 3);
-        
+        this.lineWidth = clamp(Math.round(Math.min(w,h) * 0.2), 1, 3);
         Wall.init.call(this, x,y, w,h, this.isBoundary);
-        this.updateColor();
-    },
-    
-    updateColor : function updateColor(){
-        var L = this.fillColors.length-1
-        ,   i = clamp(Math.floor(this.stats.hp.ratio*L), 0, L)
-        ,   color = this.fillColors[i]
-        ;
-        this.fillStyle   = 'rgba('+color.join(',')+', 0.25)';
-        this.strokeStyle = 'rgba('+color.join(',')+', 0.50)';
-        console.log(this+'color = '+this.fillStyle+' ('+i+')');
-        return this;
     },
     
-    dealDamage : function dealDamage(d, source){
-        Wall.fn.dealDamage.apply(this, arguments);
-        if (!this.dead) {
-            var old = this.fillStyle;
-            if (old !== this.updateColor().fillStyle)
-                this.render();
-        }
-        return this;
-    },
-    
-    split : function split(gap){
-        if (!this.isSplittable || this.width <= this.minSplitSize)
+    divide : function divide(){
+        if (!this.canSplit)
             return this;
         
         var _x = this.loc.x,   _y = this.loc.y
         ,   mx = _x+this.width, my = _y+this.height
         ,   size = this.width * 0.5
-        ,   gapX = gap ? gap.x : Infinity
-        ,   gapY = gap ? gap.y : Infinity
-        ,   hp = Math.max(Math.round(this.stats.hp.max * 0.5), 1.0)
-        
-        ,   x, y, nextX, nextY, wall
+        ,   x, y, wall
         ;
-        
-        // console.group(this+'.split()');
-        // console.log('gap: ('+gapX+','+gapY+')');
-        // console.log('loc: '+this.loc);
-        // console.log('dim: w='+this.width+'; h='+this.height+'; size='+size);
-        // console.log('max: x='+mx+'; y='+my);
-        for (x = _x; x<mx; x=nextX) {
-            nextX = x + size;
-            for (y = _y; y<my; y=nextY){
-                nextY = y + size;
-                wall = new Drywall(x,y, size,size, hp);
-                if ( !(x <= gapX && gapX <= nextX && y <= gapY && gapY <= nextY) ) {
-                    // console.log('Drywall('+x+','+y+', '+size+','+size+', '+hp+')');
-                    
-                } else {
-                    // console.log('Gap! ('+x+' <= '+gapX+' <= '+nextX+') && ('+y+' <= '+gapY+' <= '+nextY+')');
-                    wall.dead = true;
-                    wall.split(gap).remove();
-                    this.game.killThing(wall);
-                }
+        for (x = _x; x<mx; x+=size) {
+            for (y = _y; y<my; y+=size){
+                wall = new Drywall(x,y, size,size);
             }
         }
-        // console.groupEnd();
         return this;
     },
     
@@ -102,11 +54,10 @@ Wall.subclass('Drywall', {
     
 });
 
+// Divide on death (if possible)
 Drywall.addEventListener('destroy', function(evt){
-    var d = evt.data
-    ,   killer = d.killer
-    ,   side = d.side
-    ,   gap  = killer && side && side.intersection(killer.trajectory);
-    if (gap) evt.data.unit.split(gap);
+    evt.data.unit.divide();
 });
+
 config.updateOnChange('map.minSplitSize', Drywall.fn);
+
index aad4fa8..d985260 100644 (file)
@@ -1,4 +1,5 @@
 var Y = require('Y').Y
+,   Rect  = require('ezl/shape').Rect
 
 ,   constants   = require('tanks/constants')
 ,   BoundsType  = constants.BoundsType
@@ -12,9 +13,13 @@ exports['Fence'] =
 Wall.subclass('Fence', {
     
     isReflective : false,
-    fillStyle    : 'rgba(0,0,0, 0.25)',
-    strokeStyle  : 'transparent',
-    lineWidth    : 0,
+    
+    shadowFillStyle : 'rgba(0,0,0, 0.10)',
+    shadowSize      : 10,
+    
+    fillStyle       : 'rgba(0,0,0, 0.25)',
+    strokeStyle     : 'rgba(0,0,0, 0.25)',
+    lineWidth       : 0,
     
     blocking : BoundsType.BLOCKING,
     density  : DensityType.SPARSE,
@@ -26,6 +31,38 @@ Wall.subclass('Fence', {
         Wall.init.call(this, x,y, w,h, this.isBoundary);
     },
     
+    render : function render(parent){
+        if (this.isBoundary)
+            return this;
+        
+        if (this.shape) {
+            parent = parent || this.shape.parent;
+            this.shape.remove();
+        }
+        
+        if (!parent)
+            return this;
+        
+        this.shape =
+            new Rect(this.width, this.height)
+                .position(this.loc.x, this.loc.y)
+                .fill(this.fillStyle)
+                .stroke(this.strokeStyle, this.lineWidth)
+                .appendTo( parent );
+        
+        var ss = this.shadowSize;
+        this.shadow =
+            new Rect(this.width, this.height)
+                .position(0,0)
+                .fill(this.shadowFillStyle)
+                .stroke(this.strokeStyle, this.lineWidth)
+                .erase(ss,ss, -ss,-ss)
+                .appendTo( this.shape );
+        
+        return this;
+    },
+    
+    
     toString : Wall.fn.toString
     
 });
index 4438ce6..44cb227 100644 (file)
@@ -34,11 +34,6 @@ Thing.subclass('Wall', {
     strokeStyle  : 'transparent',
     lineWidth    : 0,
     
-    renderWidth   : 0,
-    renderHeight  : 0,
-    renderOffsetX : 0,
-    renderOffsetY : 0,
-    
     
     // inactive
     active : false,
@@ -83,8 +78,8 @@ Thing.subclass('Wall', {
             return this;
         
         this.shape =
-            new Rect( this.renderWidth || this.width, this.renderHeight || this.height )
-                .position(this.loc.x + this.renderOffsetX, this.loc.y + this.renderOffsetY)
+            new Rect(this.width, this.height)
+                .position(this.loc.x, this.loc.y)
                 .fill(this.fillStyle)
                 .stroke(this.strokeStyle, this.lineWidth)
                 .appendTo( parent );
@@ -112,7 +107,6 @@ Wall.register('wall', Wall);
 Wall.addEventListener('subclass', 
     function(evt){
         var subcls = evt.data.child;
-        // console.log('Wall.register('+Y(subcls.className).camelToSnake()+', '+subcls.className+')');
         Wall.register(Y(subcls.className).camelToSnake(), subcls);
     });
 
index 617e498..78586c0 100644 (file)
@@ -199,3 +199,4 @@ exports['Key'] = {
     }
 };
 
+
index f7846df..21af19d 100644 (file)
@@ -23,13 +23,14 @@ function initConfigUi(){
     });
     
     // Apply ordering
-    Y(data.groups).invoke('remove');
+    var groupsSeen = {};
     Y(ordering).forEach(function(k){
-        data.groups[k].appendTo(el);
+        var g = groupsSeen[k] = data.groups[k];
+        g.appendTo(el);
     });
     // Attach leftovers
     Y(data.groups).forEach(function(g, k){
-        if ( !g.parent().length )
+        if ( !groupsSeen[k] )
             g.appendTo(el);
     });
     
index 4a9e494..2fdd6d9 100644 (file)
@@ -11,6 +11,7 @@ var Y            = require('Y').Y
 ,   configui     = require('tanks/ui/configui')
 ,   Game         = require('tanks/game').Game
 ,   Tank         = require('tanks/thing').Tank
+,   Player       = require('tanks/thing/player').Player
 
 ,   HIDE = 0, SHOW = 1, TOGGLE = 2
 
@@ -34,29 +35,17 @@ function main(){
     overlay = $('#overlay');
     updateOverlay( config.get('ui.overlayOnPause') );
     config.addEventListener('set:ui.overlayOnPause', function(evt){ updateOverlay(evt.newval); });
+    config.addEventListener('set:ui.debug.showFpsGraph', function(evt){ updateUI('#info', evt.newval); });
     
-    /// Debug ///
-    if (qkv.ai) {
-        $('#welcome').hide();
-        $('#ai').toggle();
-        $('#ai textarea')[0].focus();
-    }
-    if (qkv.debug || config.get('debug.showFpsGraph')) updateUI('#info', TOGGLE);
+    Player.addEventListener('create', function(evt){ P = evt.data.instance; });
     
-    $('#ai .ready').bind('click', function(evt){
-        try {
-            var script = $('#customtank').val();
-            Tank.prototype.act = eval('(function(){ with(this){'+script+'} })');
-            $('#ai').hide();
-            startGame();
-        } catch(e) {
-            alert('AI Error!\n'+e);
-        }
-    });
+    /// Debug ///
+    if (qkv.debug || config.get('debug.showFpsGraph'))
+        updateUI('#info', SHOW);
     
     // Show debug menus
-    $(document).bind('keydown', 'ctrl+d', function(evt){ updateUI('.debug', TOGGLE); });
-    $(document).bind('keydown', 'ctrl+i', function(evt){ updateUI('#info', TOGGLE); });
+    $(document).bind('keydown', 'ctrl+d', function(evt){ updateUI('.debug',  TOGGLE); });
+    $(document).bind('keydown', 'ctrl+i', function(evt){ updateUI('#info',   TOGGLE); });
     $(document).bind('keydown', 'ctrl+c', function(evt){ updateUI('#config', TOGGLE); });
     
     // Don't fire on clicks in the debug menu
@@ -79,7 +68,6 @@ function main(){
             .find('.box')
             .html('<h1>You Win!</h1><p></p><div class="restart pinkbutton rounded">Play Again</div>');
     
-    
     // Bind to all future restart buttons
     $('#gameover .restart')
         .live('click', function(evt){
@@ -89,7 +77,7 @@ function main(){
             startGame();
         });
     
-    
+    // Load all data files
     cfg.dataLoader()
         .addEventListener('complete', function(evt){
             $('#loading').hide();
@@ -282,6 +270,14 @@ function updateInfo(){
     return false;
 }
 
+function parseVisibility(v){
+    if (typeof v === 'number')
+        return v;
+    if (typeof v === 'string')
+        return parseInt(v);
+    return (v ? SHOW : HIDE);
+}
+
 jQuery.fn.center = function centerJQ(){
     var body = $('body');
     this.css({
@@ -303,6 +299,7 @@ function updateOverlay(show){
 }
 
 function updateUI(selector, action){
+    action = parseVisibility(action);
     var el = $(selector);
     
     if (action === TOGGLE){