Adds Fences; minor refactor to map-like stuff.
authordsc <david.schoonover@gmail.com>
Sun, 9 Jan 2011 10:26:50 +0000 (02:26 -0800)
committerdsc <david.schoonover@gmail.com>
Sun, 9 Jan 2011 10:26:50 +0000 (02:26 -0800)
19 files changed:
data/types/levels.yaml
src/tanks/constants.cjs
src/tanks/map/fence.cjs [new file with mode: 0644]
src/tanks/map/index.cjs
src/tanks/map/level.cjs
src/tanks/map/map.cjs
src/tanks/map/pathing/index.cjs [new file with mode: 0644]
src/tanks/map/pathing/pathmap.cjs [moved from src/tanks/map/pathmap.cjs with 89% similarity]
src/tanks/map/pathing/trajectory.cjs [moved from src/tanks/map/trajectory.cjs with 94% similarity]
src/tanks/map/pathing/traversal.cjs [moved from src/tanks/map/traversal.cjs with 87% similarity]
src/tanks/map/wall.cjs [moved from src/tanks/thing/wall.cjs with 58% similarity]
src/tanks/mixins/quantified.cjs
src/tanks/thing/bullet.cjs
src/tanks/thing/fence.cjs [deleted file]
src/tanks/thing/index.cjs
src/tanks/thing/item.cjs
src/tanks/thing/tank.cjs
src/tanks/thing/thing.cjs
src/tanks/ui/pathmapui.cjs

index df2c2f5..86b4a1f 100644 (file)
@@ -30,10 +30,18 @@ types:
             args: [150,300, 50,50]
           - type: wall
             args: [100,100, 50,50]
+          - type: fence
+            args: [360,210, 130,30]
+          - type: fence
+            args: [10,210, 30,30]
+          - type: fence
+            args: [110,210, 30,30]
+          - type: fence
+            args: [210,210, 30,30]
         units:
           - type: player
             align: 1
-            loc: [275,475]
+            loc: [325,475]
           - type: blue
             align: 1
             loc: [175,475]
index b44aa33..2404b79 100644 (file)
@@ -1,11 +1,11 @@
-//#exports PathingType.{PASSABLE,ZONE,BLOCKING,IRREGULAR}
+//#exports BoundsType.{PASSABLE,ZONE,BLOCKING,IRREGULAR}
+//#exports DensityType.{PASSABLE,BOUNDARY,DENSE,SPARSE,IRREGULAR}
 //#exports StatInvariant.{NONE,RATIO,FULL}
 
 require('Y').Y.extend(exports, {
     
-    /// Pathing Constants ///
-    /** How this object interacts with the world. */
-    PathingType : {
+    /** How to determine the bounds of this object for pathing. */
+    BoundsType : {
         
         /** Does not obstruct other objects. */
         PASSABLE : 0,
@@ -21,6 +21,30 @@ require('Y').Y.extend(exports, {
         
     },
     
+    /**
+     * Governs the kinds of objects this object obstructs.
+     */
+    DensityType : {
+        
+        /** Not an obstruction. */
+        PASSABLE : 0,
+        
+        /** Blocks absolutely everything. No exceptions. */
+        BOUNDARY : 1,
+        
+        /** Blocks everything material (eg, units). */
+        DENSE : 2,
+        
+        /** Does not block small things (eg, projectiles). */
+        SPARSE : 3,
+        
+        /** Blocks based on custom rules. */
+        IRREGULAR : 4
+        
+    },
+    
+    
+    
     /** 
      * Invariant to restore for the current value when modifying the base or max of a Stat.
      * @see {tanks.effects.stat.Stat} for the default behavior of its methods.
diff --git a/src/tanks/map/fence.cjs b/src/tanks/map/fence.cjs
new file mode 100644 (file)
index 0000000..cb1e79b
--- /dev/null
@@ -0,0 +1,31 @@
+var Y = require('Y').Y
+
+,   constants   = require('tanks/constants')
+,   BoundsType  = constants.BoundsType
+,   DensityType = constants.DensityType
+,   Wall        = require('tanks/map/wall').Wall
+,
+
+
+Fence =
+exports['Fence'] =
+Wall.subclass('Fence', {
+    
+    isReflective : false,
+    fillStyle    : 'rgba(0,0,0, 0.25)',
+    strokeStyle  : 'transparent',
+    lineWidth    : 0,
+    
+    blocking : BoundsType.BLOCKING,
+    density  : DensityType.SPARSE,
+    isBoundary : false,
+    
+    
+    
+    init : function initFence(x,y, w,h){
+        Wall.init.call(this, x,y, w,h, this.isBoundary);
+    }
+    
+});
+
+Wall.register('fence', Fence);
index d143552..0b2364f 100644 (file)
@@ -1,9 +1,9 @@
-var Y = require('Y').Y;
-
-Y.extend(exports, {
+require('Y').Y
+.extend(exports, {
+    'pathing'    : require('tanks/map/pathing'),
+    
     'Map'        : require('tanks/map/map').Map,
-    'PathMap'    : require('tanks/map/pathmap').PathMap,
     'Level'      : require('tanks/map/level').Level,
-    'Traversal'  : require('tanks/map/traversal').Traversal,
-    'Trajectory' : require('tanks/map/trajectory').Trajectory
+    'Wall'       : require('tanks/map/wall').Wall,
+    'Fence'      : require('tanks/map/fence').Fence
 });
index 328de4a..c31d975 100644 (file)
@@ -5,12 +5,12 @@ var Y          = require('Y').Y
 ,   Rect       = require('ezl/shape').Rect
 
 ,   Buff       = require('tanks/effects/buff').Buff
-,   PathMap    = require('tanks/map/pathmap').PathMap
+,   PathMap    = require('tanks/map/pathing/pathmap').PathMap
 ,   Thing      = require('tanks/thing/thing').Thing
 ,   Tank       = require('tanks/thing/tank').Tank
 ,   Item       = require('tanks/thing/item').Item
 ,   Player = require('tanks/thing/player').Player
-,   Wall       = require('tanks/thing/wall').Wall
+,   Wall       = require('tanks/map/wall').Wall
 ,   Speciated  = require('tanks/mixins/speciated').Speciated
 
 ,   min = Y(Math.min).limit(2)
index feec7a3..92461b4 100644 (file)
@@ -1,32 +1,45 @@
 //  -*- mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; -*-
 var Y        = require('Y').Y
-,   QuadTree = require('ezl/util/tree/quadtree').QuadTree
+,   QuadTree    = require('ezl/util/tree/quadtree').QuadTree
 
-
-/** Does not obstruct other objects. */
-,   PASSABLE = exports['PASSABLE'] = 0
-
-/** Does not obstruct other objects, but still collides with them. */
-,   ZONE = exports['ZONE'] = 1
-
-/** Obstructs other blockers with its BoundingBox. */
-,   BLOCKING = exports['BLOCKING'] = 2
-
-/** Potentially obstructs other objects, but requires a special test once a BoundingBox collision has been detected. */
-,   IRREGULAR = exports['IRREGULAR'] = 3
+,   constants   = require('tanks/constants')
+,   BoundsType  = constants.BoundsType
+,   DensityType = constants.DensityType
 ,
 
 
 Map =
 exports['Map'] =
 QuadTree.subclass('Map', {
+    allWalls   : null, // All walls in this map
+    innerWalls : null, // Non-boundary walls
+    denseWalls : null, // Non-boundary non-Fences
+    
+    
+    init : function initMap(x1,y1, x2,y2, capacity){
+        this.allWalls   = Y([]);
+        this.innerWalls = Y([]);
+        this.denseWalls = Y([]);
+        QuadTree.init.call(this, x1,y1, x2,y2, capacity);
+    },
     
     addBlocker : function addBlocker(obj){
         this.removeBlocker(obj);
+        
         var pt = obj.blocking
         ,   bb = obj.bbox ;
         if (pt !== undefined && bb)
             obj.region = this.set(bb.x1,bb.y1, bb.x2,bb.y2, obj);
+        
+        if (obj.isWall) {
+            if ( !this.allWalls.has(obj) )
+                this.allWalls.push(obj);
+            if ( !(obj.isBoundary || this.innerWalls.has(obj)) )
+                this.innerWalls.push(obj);
+            if ( obj.density === DensityType.DENSE || obj.density === DensityType.BOUNDARY )
+                this.denseWalls.push(obj);
+        }
+        
         return obj;
     },
     
@@ -35,6 +48,13 @@ QuadTree.subclass('Map', {
             this.remove(obj.region);
             delete obj.region;
         }
+        
+        if (obj.isWall) {
+            this.allWalls.remove(obj);
+            this.innerWalls.remove(obj);
+            this.denseWalls.remove(obj);
+        }
+        
         return obj;
     },
     
@@ -44,13 +64,21 @@ QuadTree.subclass('Map', {
             y2 = x1.y2;  x2 = x1.x2;
             y1 = x1.y1;  x1 = x1.x1;
         }
-        var bs = this.get(x1,y1, x2,y2)
-            .filter('_.blocking === BLOCKING');
+        var bs = this.get(x1,y1, x2,y2).filter(this._filterBlockers, this);
         if (ignore && bs.length)
             return bs.remove.apply(bs, ignore || []);
         else
             return bs;
-    }
+    },
     
+    _filterBlockers : function _filterBlockers(v){
+        return (v.blocking === BoundsType.BLOCKING || v.blocking === BoundsType.IRREGULAR);
+    },
+    
+    wallObstructs : function wallObstructs(line){
+        return this.innerWalls.some(function(wall){
+            return wall.bbox.intersects(line);
+        }, this);
+    }
     
 });
diff --git a/src/tanks/map/pathing/index.cjs b/src/tanks/map/pathing/index.cjs
new file mode 100644 (file)
index 0000000..633d120
--- /dev/null
@@ -0,0 +1,6 @@
+require('Y').Y
+.extend(exports, {
+    'PathMap'    : require('tanks/map/pathing/pathmap').PathMap,
+    'Traversal'  : require('tanks/map/pathing/traversal').Traversal,
+    'Trajectory' : require('tanks/map/pathing/trajectory').Trajectory
+});
similarity index 89%
rename from src/tanks/map/pathmap.cjs
rename to src/tanks/map/pathing/pathmap.cjs
index 3a09ae2..6dc6504 100644 (file)
@@ -9,9 +9,10 @@ var Y          = require('Y').Y
 ,   Line       = math.Line
 
 ,   config     = require('tanks/config').config
-,   PathingType = require('tanks/constants').PathingType
+,   constants   = require('tanks/constants')
+,   BoundsType = constants.BoundsType
+,   DensityType = constants.DensityType
 ,   Map        = require('tanks/map/map').Map
-,   Wall       = require('tanks/thing/wall').Wall
 
 
 ,   SQRT_TWO = Math.sqrt(2)
@@ -37,44 +38,12 @@ Map.subclass('PathMap', {
     
     
     
-    
     init : function init(x1,y1, x2,y2, capacity, buffer_size) {
         this.buffer_size = buffer_size;
         x1 -= buffer_size; y1 -= buffer_size;
         x2 += buffer_size; y2 += buffer_size;
-        QuadTree.init.call(this, x1,y1, x2,y2, capacity);
+        Map.init.call(this, x1,y1, x2,y2, capacity);
         this._squares = {};
-        
-        this.innerWalls = Y([]);
-        this.allWalls = Y([]);
-        
-        // this.game.addEventListener('ready', this.setup.bind(this, x1,y1, x2,y2));
-    },
-    
-    addBlocker : function addBlocker(obj){
-        Map.fn.addBlocker.call(this, obj);
-        if (obj instanceof Wall) {
-            if ( !this.allWalls.has(obj) )
-                this.allWalls.push(obj);
-            if ( !(obj.isBoundary || this.innerWalls.has(obj)) )
-                this.innerWalls.push(obj);
-        }
-        return obj;
-    },
-    
-    removeBlocker : function removeBlocker(obj){
-        Map.fn.removeBlocker.call(this, obj);
-        if (obj instanceof Wall) {
-            this.innerWalls.remove(obj);
-            this.allWalls.remove(obj);
-        }
-        return obj;
-    },
-    
-    wallObstructs : function wallObstructs(line){
-        return this.innerWalls.some(function(wall){
-            return wall.bbox.intersects(line);
-        }, this);
     },
     
     /**
@@ -246,7 +215,8 @@ Y.subclass('Square', new Vec(0,0), {
         if (this.pathId === pathId)
             return this;
         
-        this.pathId = pathId;
+        this.pathId  = pathId;
+        this.agent   = this.pathmap._agent;
         this.blocked = this._blocked();
         
         this.dist      = 0;
@@ -264,8 +234,7 @@ Y.subclass('Square', new Vec(0,0), {
      */
     _blocked : function blocked(){
         var pm    = this.pathmap
-        ,   agent = pm._agent
-        // ,   bb    = agent.bbox
+        // ,   bb    = this.agent.bbox
         
         // ,   origin = bb.relOrigin
         // ,   left = origin.x,  right  = bb.width - left
@@ -280,7 +249,7 @@ Y.subclass('Square', new Vec(0,0), {
         ,   y1 = y,  y2 = y + SIZE
         
         ,   blockers = pm.get(x1,y1, x2,y2)
-                .remove(agent)
+                .remove(this.agent)
                 .filter(this._filterBlocked, this)
         ;
         
@@ -291,7 +260,8 @@ Y.subclass('Square', new Vec(0,0), {
      * @private
      */
     _filterBlocked : function filterBlocked(v, r){
-        return v.blocking === PathingType.BLOCKING && !v.isBoundary;
+        return (v.blocking === BoundsType.BLOCKING  && !v.isBoundary)
+            || (v.blocking === BoundsType.IRREGULAR && v.testCollide(this.agent,this,null) ); // FIXME: hm. calc bbox?
     },
     
     getNeighbors : function getNeighbors(){
similarity index 94%
rename from src/tanks/map/trajectory.cjs
rename to src/tanks/map/pathing/trajectory.cjs
index 9653053..837c758 100644 (file)
@@ -5,7 +5,8 @@ var Y     = require('Y').Y
 ,   Line  = math.Line
 ,   Rect  = math.Rect
 ,   BoundingBox = require('ezl/loc').BoundingBox
-,   Thing = require('tanks/thing/thing').Thing
+
+,   Thing  = require('tanks/thing/thing').Thing
 
 ,   BOUND_SIZE_RATIO = 0.75
 ,
@@ -153,8 +154,13 @@ Line.subclass('Trajectory', {
     },
     
     pathBlocked : function pathBlocked(obj, ignore){
-        var blockers =
-                this.pathmap.innerWalls
+        var walls, blockers;
+        if (this.owner.isProjectile)
+            walls = this.pathmap.denseWalls;
+        else
+            walls = this.pathmap.innerWalls; // FIXME: won't filter out concave intersections with the bounds
+        
+        blockers = walls
                     .concat( this.game.units )
                     .apply('remove', [this.owner].concat(ignore || []) )
                     .filter( this.intersects )
similarity index 87%
rename from src/tanks/map/traversal.cjs
rename to src/tanks/map/pathing/traversal.cjs
index 9d9237b..6f6beda 100644 (file)
@@ -1,5 +1,7 @@
 var Y = require('Y').Y
-,   PathingType = require('tanks/constants').PathingType
+,   constants   = require('tanks/constants')
+,   BoundsType = constants.BoundsType
+,   DensityType = constants.DensityType
 ,
 
 Traversal =
@@ -90,15 +92,26 @@ Y.subclass('Traversal', {
      * Filters found obstructions to keep only those not ignored and blocking.
      */
     checkBlocker : function checkBlocker(blocker){
-        var blocking = blocker.blocking;
+        var blocking = blocker.blocking
+        ,   density  = blocker.density;
         
         // All blockers after the first are ignored
-        if ( this.ignore.has(blocker) || blocking === PathingType.PASSABLE || this.isBlocked )
+        if ( this.isBlocked || this.ignore.has(blocker)
+                // Skip passable objects
+                || (blocking === BoundsType.PASSABLE)
+                
+                // Ask irregular objects if we hit
+                || (blocking === BoundsType.IRREGULAR && !blocker.testCollide(this.thing,this.to,this.bbox))
+                
+                // Filter out Sparse objects if bullet
+                || (density === DensityType.SPARSE && this.thing.isProjectile) )
+        {
             return false;
+        }
         
         // Only fire collision with this zone once per traversal
         // XXX: Zone will have to manage enterance/exit and provide a method for testing, hm -- this would obviate the main need for this.ignore
-        if ( blocking === PathingType.ZONE ) {
+        if ( blocking === BoundsType.ZONE ) {
             this.ignore.push(blocker);
             this.collide(blocker);
             return false;
@@ -111,7 +124,6 @@ Y.subclass('Traversal', {
     
     collide : function collide(blocker){
         var thing = this.thing;
-        
         thing.fire('collide', blocker, { 'traversal':this, 'unit':blocker });
         blocker.fire('collide', thing, { 'traversal':this, 'unit':thing });
     },
similarity index 58%
rename from src/tanks/thing/wall.cjs
rename to src/tanks/map/wall.cjs
index f59831f..a814c75 100644 (file)
@@ -1,10 +1,12 @@
-var Y         = require('Y').Y
-,   op        = require('Y/op')
+var Y  = require('Y').Y
+,   op = require('Y/op')
 
-,   Rect      = require('ezl/shape').Rect
+,   Rect = require('ezl/shape').Rect
 
-,   Thing     = require('tanks/thing/thing').Thing
-,   PathingType = require('tanks/constants').PathingType
+,   Thing       = require('tanks/thing/thing').Thing
+,   constants   = require('tanks/constants')
+,   BoundsType  = constants.BoundsType
+,   DensityType = constants.DensityType
 ,
 
 
@@ -16,9 +18,27 @@ Thing.subclass('Wall', {
     originX : 0,
     originY : 0,
     
-    blocking : PathingType.BLOCKING,
+    width : 0,
+    height : 0,
+    
+    
+    blocking : BoundsType.BLOCKING,
+    density  : DensityType.DENSE,
+    isWall : true,
     isReflective : true,
+    
+    // rendering
+    
     isRenderable : true,
+    fillStyle    : 'rgba(255,255,255, 0.25)',
+    strokeStyle  : 'transparent',
+    lineWidth    : 0,
+    
+    renderWidth   : 0,
+    renderHeight  : 0,
+    renderOffsetX : 0,
+    renderOffsetY : 0,
+    
     
     // inactive
     active : false,
@@ -45,6 +65,8 @@ Thing.subclass('Wall', {
         this.width = w;
         this.height = h;
         this.isBoundary = !!isBoundary;
+        if (isBoundary)
+            this.density = DensityType.BOUNDARY;
         Thing.init.call(this);
         this.position(x,y);
     },
@@ -59,9 +81,10 @@ Thing.subclass('Wall', {
             this.shape.remove();
         
         this.shape =
-            new Rect(this.width, this.height)
-                .position(this.loc.x, this.loc.y)
-                .fill('rgba(255,255,255, 0.25)')
+            new Rect( this.renderWidth || this.width, this.renderHeight || this.height )
+                .position(this.loc.x + this.renderOffsetX, this.loc.y + this.renderOffsetY)
+                .fill(this.fillStyle)
+                .stroke(this.strokeStyle, this.lineWidth)
                 .appendTo( parent );
         
         return this;
index 05f2e4a..0889a07 100644 (file)
@@ -53,14 +53,14 @@ Mixin.subclass('Quantified', {
     onBuffAcquired : function onBuffAcquired(evt){
         var buff = evt.data.buff;
         this.buffs.push(buff);
-        console.log('Buff '+buff+' acquired by '+this);
+        // console.log('Buff '+buff+' acquired by '+this);
         // TODO: update UI
     },
     
     onBuffLost : function onBuffLost(evt){
         var buff = evt.data.buff;
         this.buffs.remove(buff);
-        console.log('Buff '+buff+' lost by '+this);
+        // console.log('Buff '+buff+' lost by '+this);
         // TODO: update UI
     },
     
index 41be7dc..1a48969 100644 (file)
@@ -8,14 +8,12 @@ var Y          = require('Y').Y
 ,   Circle     = shape.Circle
 
 ,   config     = require('tanks/config').config
-,   PathingType = require('tanks/constants').PathingType
+,   BoundsType = require('tanks/constants').BoundsType
 ,   stat       = require('tanks/effects/stat')
-
-,   Thing      = require('tanks/thing/thing').Thing
-,   Wall       = require('tanks/thing/wall').Wall
-,   Trajectory = require('tanks/map/trajectory').Trajectory
-,   Traversal  = require('tanks/map/traversal').Traversal
 ,   Explosion  = require('tanks/fx/explosion').Explosion
+,   Thing      = require('tanks/thing/thing').Thing
+,   Trajectory = require('tanks/map/pathing/trajectory').Trajectory
+,   Traversal  = require('tanks/map/pathing/traversal').Traversal
 ,
 
 
@@ -33,8 +31,9 @@ Thing.subclass('Bullet', {
     },
     
     // Instance
-    blocking : PathingType.BLOCKING,
+    blocking : BoundsType.BLOCKING,
     isRenderable : true,
+    isProjectile : true,
     
     bounces     : 0,
     bounceLimit : 1,
@@ -121,7 +120,7 @@ Thing.subclass('Bullet', {
         ;
         
         // Ignore collisions with zones
-        if (unit.blocking === PathingType.ZONE)
+        if (unit.blocking === BoundsType.ZONE)
             return;
         
         // Reflection!
diff --git a/src/tanks/thing/fence.cjs b/src/tanks/thing/fence.cjs
deleted file mode 100644 (file)
index b08b7b0..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-var Y     = require('Y').Y
-,   op    = require('Y/op')
-,   Rect  = require('ezl/shape').Rect
-,   Wall  = require('tanks/thing/wall').Wall
-,
-
-
-Fence =
-exports['Fence'] =
-Wall.subclass('Fence', {
-    align : 0, // 0 reserved for neutral units
-    
-    originX : 0,
-    originY : 0,
-    
-    isReflective : true,
-    isRenderable : true,
-    
-    // inactive
-    active : false,
-    createCooldowns : op.nop,
-    
-    // indestructable
-    dealDamage : op.nop,
-    
-    stats : {
-        hp    : Infinity,
-        move  : 0,
-        power : 0,
-        speed : 0,
-        shots : 0
-    },
-    
-    // Instance 
-    
-    isBoundary : false,
-    
-    
-    
-    init : function initFence(x,y, w,h){
-        this.width = w;
-        this.height = h;
-        this.isBoundary = !!isBoundary;
-        Wall.init.call(this, x,y, w,h);
-        this.position(x,y);
-    },
-    
-    
-    
-    render : function render(parent){
-        if (this.isBoundary)
-            return this;
-        
-        if (this.shape)
-            this.shape.remove();
-        
-        this.shape =
-            new Rect(this.width, this.height)
-                .position(this.loc.x, this.loc.y)
-                .fill('rgba(0,0,0, 0.25)')
-                .stroke('transparent', 0)
-                .appendTo( parent );
-        
-        return this;
-    },
-    
-    toString : function(){
-        var bb = this.bbox
-        ,   x1,y1, x2,y2;
-        if (bb){
-            x1 = bb.x1; y1 = bb.y1;
-            x2 = bb.x2; y2 = bb.y2;
-        } else {
-            x1=y1=x2=y2=NaN;
-        }
-        return this.className+'['+x1+','+y1+', '+x2+','+y2+'](w='+this.width+', h='+this.height+')';
-    }
-});
-
-Wall.register('fence', Fence);
index d36e903..d1a1bbb 100644 (file)
@@ -3,5 +3,3 @@ exports['Bullet'] = require('tanks/thing/bullet').Bullet;
 exports['Tank']   = require('tanks/thing/tank').Tank;
 exports['Player'] = require('tanks/thing/player').Player;
 exports['Item']   = require('tanks/thing/item').Item;
-exports['Wall']   = require('tanks/thing/wall').Wall;
-exports['Fence']  = require('tanks/thing/fence').Fence;
index 76dd7cc..6457a05 100644 (file)
@@ -4,7 +4,7 @@ var Y         = require('Y').Y
 ,   shape     = require('ezl/shape')
 ,   Rect      = shape.Rect
 
-,   PathingType = require('tanks/constants').PathingType
+,   BoundsType = require('tanks/constants').BoundsType
 ,   Buff      = require('tanks/effects/buff').Buff
 ,   Thing     = require('tanks/thing/thing').Thing
 
@@ -20,7 +20,7 @@ Thing.subclass('Item', {
     
     align : 0, // 0 reserved for neutral units
     
-    blocking : PathingType.ZONE,
+    blocking : BoundsType.ZONE,
     width    : ITEM_SIZE,
     height   : ITEM_SIZE,
     
@@ -91,7 +91,7 @@ Thing.subclass('Item', {
     
     onAcquired : function onAcquired(evt){
         this.owner = evt.data.unit;
-        console.log(this.owner+' acquired '+this+' ('+this.desc+')!');
+        // console.log(this.owner+' acquired '+this+' ('+this.desc+')!');
         this.currentBuffs = this.itemBuffs.invoke('instantiate', this.owner);
         this.destroy(); // removes map object
     },
@@ -101,7 +101,7 @@ Thing.subclass('Item', {
         if ( this.currentBuffs )
             this.currentBuffs.invoke('die', 'item.lost');
         var unit = this.owner;
-        console.log(unit+' lost '+this+'!');
+        // console.log(unit+' lost '+this+'!');
         this.owner = null;
         // TODO: game to listen, re-add to level at unit.loc
     },
index 7dabe64..4c318d5 100644 (file)
@@ -1,5 +1,5 @@
-var Y             = require('Y').Y
-,   op            = require('Y/op')
+var Y  = require('Y').Y
+,   op = require('Y/op')
 
 ,   vec           = require('ezl/math/vec')
 ,   shape         = require('ezl/shape')
@@ -10,13 +10,16 @@ var Y             = require('Y').Y
 ,   Rect          = shape.Rect
 ,   Circle        = shape.Circle
 
-,   Thing         = require('tanks/thing/thing').Thing
-,   Bullet        = require('tanks/thing/bullet').Bullet
-,   Trajectory    = require('tanks/map/trajectory').Trajectory
-,   Traversal     = require('tanks/map/traversal').Traversal
+,   constants   = require('tanks/constants')
+,   BoundsType  = constants.BoundsType
+,   DensityType = constants.DensityType
+,   Trajectory  = require('tanks/map/pathing/trajectory').Trajectory
+,   Traversal   = require('tanks/map/pathing/traversal').Traversal
+,   Thing       = require('tanks/thing/thing').Thing
+,   Bullet      = require('tanks/thing/bullet').Bullet
 
 ,   isBullet = Y.is(Bullet)
-,   BULLET_MOVE_PER_FRAME = MS_PER_FRAME * Bullet.prototype.stats.move*REF_SIZE/1000
+,   BULLET_MOVE_PER_FRAME = MS_PER_FRAME * Bullet.fn.stats.move*REF_SIZE/1000
 ,   _X = 0, _Y = 1
 ,
 
@@ -24,7 +27,6 @@ var Y             = require('Y').Y
 Tank =
 exports['Tank'] =
 Thing.subclass('Tank', function(Tank){
-    // TODO: lookup projectile on Bullet
     
     Y.core.descriptors(this, {
         colors : {
@@ -146,6 +148,65 @@ Thing.subclass('Tank', function(Tank){
     
     
     /**
+     * Fires this agent's cannon. If a target location is omitted, the shot
+     * will be fired in the direction of the tank's current barrel rotation.
+     * 
+     * @param {Number} [x] Target X coordinate.
+     * @param {Number} [y] Target Y coordinate.
+     */
+    this['shoot'] =
+    function shoot(x,y){
+        if ( this.nShots >= this.stats.shots.val || !this.cooldowns.attack.ready )
+            return null;
+        
+        var xydef = (x !== undefined && y !== undefined);
+        if (xydef)
+            this.rotateBarrel(x,y);
+        
+        // Additional space on each side which must be clear around the
+        // shot to ensure we don't shoot ourself in the foot (literally)
+        var WIGGLE = 1
+        ,   Projectile = this.projectile
+        ,   pw2 = Projectile.fn.width/2, ph2 = Projectile.fn.height/2
+        
+        ,   tloc = this.getTurretLoc()
+        ,   tx = tloc.x, ty = tloc.y
+        
+        ,   x1 = tx - pw2 - WIGGLE, y1 = ty - ph2 - WIGGLE
+        ,   x2 = tx + pw2 + WIGGLE, y2 = ty + ph2 + WIGGLE
+        ,   blockers = this.game.pathmap.get(x1,y1, x2,y2).filter(filterShoot, this)
+        ;
+        
+        if ( blockers.size() )
+            return null; // console.log('squelch!', blockers);
+        
+        if (!xydef) {
+            var theta  = this.barrel.transform.rotate
+            ,   sin = Math.sin(theta),  cos = Math.cos(theta);
+            x = tx + REF_SIZE*cos;
+            y = ty + REF_SIZE*sin;
+        }
+        
+        this.cooldowns.attack.activate(this.now);
+        this.nShots++;
+        
+        var p = new Projectile(this, tx,ty, x,y);
+        p.addEventListener('destroy', this.onBulletDeath);
+        return p;
+    };
+    
+    function filterShoot(v){
+        return (v !== this)
+            && (v.density === DensityType.BOUNDARY || (v.isWall && v.density === DensityType.DENSE));
+    }
+    
+    this['ableToShoot'] =
+    function ableToShoot(){
+        return this.nShots < this.stats.shots.val && this.cooldowns.attack.ready;
+    };
+    
+    
+    /**
      * @return {this}
      */
     this['move'] =
@@ -285,7 +346,6 @@ Thing.subclass('Tank', function(Tank){
         
         var tank = this, bb = this.bbox
         ,   w = bb.width+wiggle, h = bb.height+wiggle ;
-        // ,   w = (bb.width+wiggle)/2, h = (bb.height+wiggle)/2 ;
         
         return bullets.filter(function(b){
             var trj = b.trajectory;
@@ -295,61 +355,6 @@ Thing.subclass('Tank', function(Tank){
         });
     };
     
-    /**
-     * Fires this agent's cannon. If a target location is omitted, the shot
-     * will be fired in the direction of the tank's current barrel rotation.
-     * 
-     * @param {Number} [x] Target X coordinate.
-     * @param {Number} [y] Target Y coordinate.
-     */
-    this['shoot'] =
-    function shoot(x,y){
-        if ( this.nShots >= this.stats.shots.val || !this.cooldowns.attack.ready )
-            return null;
-        
-        var xydef = (x !== undefined && y !== undefined);
-        if (xydef)
-            this.rotateBarrel(x,y);
-        
-        // Additional space on each side which must be clear around the
-        // shot to ensure we don't shoot ourself in the foot (literally)
-        var WIGGLE = 1
-        ,   Projectile = this.projectile
-        ,   pw2 = Projectile.fn.width/2, ph2 = Projectile.fn.height/2
-        
-        ,   tloc = this.getTurretLoc()
-        ,   tx = tloc.x, ty = tloc.y
-        
-        ,   x1 = tx - pw2 - WIGGLE, y1 = ty - ph2 - WIGGLE
-        ,   x2 = tx + pw2 + WIGGLE, y2 = ty + ph2 + WIGGLE
-        ,   blockers = this.game.pathmap.get(x1,y1, x2,y2).remove(this)
-        ;
-        
-        if ( blockers.size() )
-            return null; // console.log('squelch!', blockers);
-        
-        if (!xydef) {
-            var theta  = this.barrel.transform.rotate
-            ,   sin = Math.sin(theta),  cos = Math.cos(theta);
-            x = tx + REF_SIZE*cos;
-            y = ty + REF_SIZE*sin;
-        }
-        
-        this.cooldowns.attack.activate(this.now);
-        this.nShots++;
-        
-        var p = new Projectile(this, tx,ty, x,y);
-        p.addEventListener('destroy', this.onBulletDeath);
-        // this.game.addThing(p).render(this.game.level);
-        return p;
-    };
-    
-    
-    this['ableToShoot'] =
-    function ableToShoot(){
-        return this.nShots < this.stats.shots.val && this.cooldowns.attack.ready;
-    };
-    
     this['getTurretLoc'] =
     function getTurretLoc(){
         var WIGGLE = 2
@@ -367,7 +372,6 @@ Thing.subclass('Tank', function(Tank){
         ,   x = loc.x + len*cos
         ,   y = loc.y + len*sin
         ;
-        // console.log('getTurretLoc()', 'loc:', loc, '(x,y):', [x,y]);
         return new Vec(x,y);
     };
     
index 9a0ea6f..975e3d7 100644 (file)
@@ -9,7 +9,9 @@ var Y           = require('Y').Y
 ,   Cooldown    = require('ezl/loop').Cooldown
 
 ,   config      = require('tanks/config').config
-,   PathingType = require('tanks/constants').PathingType
+,   constants   = require('tanks/constants')
+,   BoundsType = constants.BoundsType
+,   DensityType = constants.DensityType
 ,   stat        = require('tanks/effects/stat')
 ,   Quantified  = require('tanks/mixins/quantified').Quantified
 ,   Speciated   = require('tanks/mixins/speciated').Speciated
@@ -52,7 +54,9 @@ new evt.Class('Thing', {
     dirty   : true,
     
     // Properties
-    blocking     : PathingType.BLOCKING,
+    blocking     : BoundsType.BLOCKING,
+    density      : DensityType.DENSE,
+    isProjectile : false,
     isRenderable : false,       // Agent will present itself for rendering when ready // FIXME: stupid hack
     active       : true,        // Agent takes actions?
     isReflective : false,       // Projectiles bounce off agent rather than explode?
index 9bf2d6d..ff188e2 100644 (file)
@@ -5,8 +5,8 @@ var Y         = require('Y').Y
 ,   vec       = require('ezl/math/vec')
 
 ,   config    = require('tanks/config').config
-,   PathingType = require('tanks/constants').PathingType
-,   PathMap   = require('tanks/map/pathmap').PathMap
+,   BoundsType = require('tanks/constants').BoundsType
+,   PathMap   = require('tanks/map/pathing/pathmap').PathMap
 
 ,
 
@@ -81,7 +81,7 @@ Rect.subclass('PathMapUI', {
             return acc;
         acc[r.id] = r;
         
-        if (v.blocking === PathingType.ZONE) {
+        if (v.blocking === BoundsType.ZONE) {
             ctx.fillStyle   = this.zoneFillStyle;
             ctx.strokeStyle = this.zoneStrokeStyle;
             ctx.lineWidth   = this.zoneLineWidth;