Adds inventory UI.
authordsc <david.schoonover@gmail.com>
Mon, 17 Jan 2011 08:36:16 +0000 (00:36 -0800)
committerdsc <david.schoonover@gmail.com>
Mon, 17 Jan 2011 08:36:16 +0000 (00:36 -0800)
28 files changed:
data/types/buffs.yaml
data/types/items.yaml
data/types/levels.yaml
data/types/units.yaml
src/Y/modules/y.scaffold.cjs
src/ezl/layer/layer.cjs
src/ezl/widget/cooldown.cjs
src/tanks/game.cjs
src/tanks/globals.js
src/tanks/map/level.cjs
src/tanks/map/pathing/trajectory.cjs
src/tanks/map/rock.cjs
src/tanks/map/wall.cjs
src/tanks/mixins/inventoried.cjs
src/tanks/mixins/quantified.cjs
src/tanks/mixins/speciated.cjs
src/tanks/thing/bullet.cjs
src/tanks/thing/item.cjs
src/tanks/thing/tank.cjs
src/tanks/ui/index.cjs
src/tanks/ui/inventory/backpack.cjs
src/tanks/ui/inventory/index.cjs
src/tanks/ui/main.cjs
www/css/lttl.css
www/css/tipsy.css
www/game.html
www/header.html
www/img/items/green-sq.png [new file with mode: 0644]

index 9a555e6..2280501 100644 (file)
@@ -1,7 +1,7 @@
 name: buffs
 defaults:
     symbol: tanks/effects/buff.Buff
-    timeout: -1 # the Infinity literal is not valid JSON
+    timeout: -1 # the YAML .Inf (Infinity literal) is not valid JSON according to the native decoders
     priority: 0
     stack_limit: 1
 types:
@@ -9,9 +9,9 @@ types:
         name: Speed Up
         desc: Speeds up your tank temporarily.
         tags: [ 'movement' ]
-        timeout: 5.0
+        timeout: 3.0
         stats:
-            move: 2.0
+            move: 0.5
         effects: []
         art:
             icon: ''
index 2c3146b..90e0e87 100644 (file)
@@ -8,9 +8,11 @@ types:
         tags: [ 'movement' ]
         passives: []
         effects: [ 'speedup' ]
+        # effects:
+        #   - include: speedup
         cooldowns:
-            activate: 10
+            activate: 30.0
         art:
             map_icon: ''
-            inv_icon: ''
+            inv_icon: '/img/items/green-sq.png'
     
index 44a9f2a..875e7ba 100644 (file)
@@ -15,6 +15,67 @@ types:
         desc: A test level.
         width: 500
         height: 500
+        bounds:
+          - [-50,-50, 600,50]
+          - [-50,0, 50,500]
+          - [501,0, 50,500]
+          - [-50,501, 600,50]
+        walls:
+          - type: wall
+            args: [300,50, 50,200] # [x,y, w,h]
+          - type: wall
+            args: [300,350, 50,100]
+          - type: wall
+            args: [100,100, 50,50]
+         
+          - type: fence
+            args: [360,210, 30,30]
+          - type: rock
+            args: [400,200, 25,25]
+          - type: rock
+            args: [425,225, 25,25]
+          - type: fence
+            args: [460,210, 30,30]
+         
+          - type: fence
+            args: [10,210, 30,30]
+          - type: fence
+            args: [110,210, 30,30]
+          - type: fence
+            args: [210,210, 30,30]
+         
+          - type: rock
+            args: [50,350, 50,50]
+          - type: rock
+            args: [100,350, 50,50]
+          - type: rock
+            args: [50,400, 50,50]
+          - type: rock
+            args: [100,400, 50,50]
+          - type: rock
+            args: [150,300, 50,50]
+        units:
+          - type: player
+            align: 1
+            loc: [375,475]
+          - type: green
+            align: 2
+            loc: [75,25]
+          - type: green
+            align: 2
+            loc: [175,25]
+          # - type: green
+          #   align: 2
+          #   loc: [425,125]
+        items:
+          - type: nitro
+            loc: [325,475]
+    
+    three_test:
+        name: Three Test
+        desc: A more complex test level.
+        width: 500
+        height: 500
         # bounds: [[-1,-1], [501,-1], [501,351], [351,351], [351,501], [-1,501]]
         # bounds:
         #     top:    [[-50,-50, 600,50]]
@@ -104,10 +165,10 @@ types:
          
           - type: fence
             args: [360,210, 30,30]
-          - type: rock
-            args: [400,200, 25,25]
-          - type: rock
-            args: [425,225, 25,25]
+          # - type: rock
+          #   args: [400,200, 25,25]
+          # - type: rock
+          #   args: [425,225, 25,25]
           - type: fence
             args: [460,210, 30,30]
          
@@ -131,7 +192,7 @@ types:
         units:
           - type: blue
             align: 1
-            loc: [425,425]
+            loc: [475,425]
           - type: blue
             align: 1
             loc: [125,475]
@@ -171,3 +232,4 @@ types:
           - type: green
             align: 2
             loc: [225,325]
+
index 85f4ebb..e461135 100644 (file)
@@ -50,8 +50,8 @@ types:
             speed : 0.5
             shots : 3
         ai:
-            path          : 1.0
-            dodge         : 1.0
+            path          : 1.00
+            dodge         : 0.75
             shootIncoming : 0.25
             shootEnemy    : 0.75
         colors:
index 4fdbfe7..ea0f200 100644 (file)
@@ -141,7 +141,7 @@ function create(config, el){
             var g = 
             groups[chain] = 
                     jQuery('<fieldset/>')
-                        .attr('id', chain)
+                        .attr('id', 'group-'+chain)
                         .addClass('group')
                         .append( jQuery('<legend/>').text(chain.split('.').pop()) )
                         .appendTo(el);
index 7af06de..48b71b6 100644 (file)
@@ -57,7 +57,10 @@ Y.subclass('Layer', {
     
     /// Setup ///
     
-    init : function init(){
+    init : function init(props, attrs, html){
+        if (props)
+            Y.core.extend(this, props);
+        
         this.children   = new Y.YArray();
         this.animActive = new Y.YArray();
         this.animQueue  = new Y.YArray();
@@ -76,10 +79,11 @@ Y.subclass('Layer', {
             translate : new Loc(0,0) // translates canvas
         };
         
-        this.layer = jQuery('<div/>')
+        this.layer = jQuery(html || '<div/>')
             .addClass(this._cssClasses)
             .data('layer', this);
         this.layer[0].layer = this;
+        if (attrs) this.layer.attr(attrs);
         
         if (this.hasCanvas) {
             this.canvas = jQuery('<canvas />')
index e94b51b..d7429a4 100644 (file)
@@ -46,9 +46,9 @@ Layer.subclass('CooldownGauge', function setupCooldownGauge(CooldownGauge){
         var p = cool.ratio()
         ,   w = this.layerWidth, h = this.layerHeight
         ,   x = w*0.5, y = h*0.5
-        ,   amt = HALF_PI + (1 - p)*PI_AND_HALF;
+        ,   amt = -HALF_PI + (1 - p)*TWO_PI;
         
-        ctx.arc(x,y, w, HALF_PI, amt, false);
+        ctx.arc(x,y, w, -HALF_PI, amt, false);
         ctx.lineTo(x,y);
         ctx.lineTo(x,0);
         ctx.fill();
index 582ed8e..08c7d0a 100644 (file)
@@ -14,6 +14,7 @@ var Y         = require('Y').Y
 ,   Level     = require('tanks/map/level').Level
 ,   Grid      = require('tanks/ui/grid').Grid
 ,   PathMapUI = require('tanks/ui/pathmapui').PathMapUI
+,   Backpack  = require('tanks/ui/inventory/backpack').Backpack
 
 ,   Thing  = thing.Thing
 ,   Tank   = thing.Tank
@@ -41,37 +42,50 @@ Y.subclass('Game', {
         if (levelId) this.levelId = levelId;
         
         this.byId = {};
+        this.toTick     = new Y.YArray();
         this.active     = new Y.YArray();
         this.units      = new Y.YArray();
         this.bullets    = new Y.YArray();
         this.animations = new Y.YArray();
         
-        this.viewport = $(GRID_ELEMENT);
+        // this.el = $(GAME_ELEMENT);
         this.loop = new EventLoop(FRAME_RATE, this);
         
         this.root =
-            new Layer()
-                .appendTo(this.viewport);
+            new Layer({ hasCanvas:false }, { 'id':'game' })
+                .prependTo( $('body') );
+        // this.root.shape.remove();
+        // this.root.layer.attr('id', 'viewport');
+        
+        this.viewport = 
+            new Layer({ hasCanvas:false }, { 'id':'viewport' })
+                .appendTo( this.root );
+        
         this.level =
             Level.create(this.levelId, this, CAPACITY, REF_SIZE)
-                .appendTo(this.root);
+                .appendTo( this.viewport );
         this.grid =
             new Grid(this.level, REF_SIZE)
-                .prependTo(this.root);
+                .prependTo( this.viewport );
         this.viewport
             .width(this.level.width)
             .height(this.level.height);
         
         this.map = this.level.map;
         this.map.ui = new PathMapUI(this, this.map);
-        this.root.append(this.map.ui);
+        this.viewport.append(this.map.ui);
         
         // automatically keep track of units
-        Thing.addEventListener('created', this.addThing);
-        Thing.addEventListener('destroy', this.killThing);
+        Thing.addEventListener('created', this.addUnit);
+        Thing.addEventListener('destroy', this.killUnit);
         this.addEventListener('tick', this.tick);
         
         this.level.setup();
+        if (this.player) {
+            this.backpack = new Backpack(this.player)
+                    .appendTo( this.root )
+                    .refresh();
+        }
         
         if (replayFile) {
             this.isReplay = true;
@@ -81,8 +95,10 @@ Y.subclass('Game', {
     },
     
     destroy : function destroy(){
-        Thing.removeEventListener('created', this.addThing);
-        Thing.removeEventListener('destroy', this.killThing);
+        Thing.removeEventListener('created', this.addUnit);
+        Thing.removeEventListener('destroy', this.killUnit);
+        this.root.remove();
+        // this.backpack && this.backpack.remove();
         this.stop();
         this.resetGlobals();
     },
@@ -100,6 +116,7 @@ Y.subclass('Game', {
     
     draw : function draw(){
         this.root.draw();
+        // this.backpack.draw();
     },
     
     /**
@@ -116,8 +133,8 @@ Y.subclass('Game', {
         SECONDTH = this.SECONDTH = ELAPSED / 1000;
         SQUARETH = this.SQUARETH = REF_SIZE * SECONDTH;
         
-        this.active.invoke('updateCooldowns', ELAPSED, NOW);
-        this.active.invoke('act', ELAPSED, NOW);
+        this.toTick.invoke('tick', ELAPSED, NOW, TICKS);
+        this.active.invoke('act',  ELAPSED, NOW, TICKS);
         this.animations = this.animations.filter(this.tickAnimations, this);
         
         this.draw();
@@ -154,7 +171,7 @@ Y.subclass('Game', {
     },
     
     tickAnimations : function tickAnimations(animation){
-        var running = animation.tick(ELAPSED, NOW);
+        var running = animation.tick(ELAPSED, NOW, TICKS);
         if (!running)
             animation.remove();
         return running;
@@ -170,18 +187,21 @@ Y.subclass('Game', {
         return animation;
     },
     
-    noteThing : function noteThing(unit){
+    noteUnit : function noteUnit(unit){
         unit.game = this;
         if (unit.dead) return unit;
         
-        if ( unit.active && !this.byId[unit.__id__] ) {
+        if ( !this.byId[unit.__id__] ) {
             this.byId[unit.__id__] = unit;
-            this.active.push(unit);
             
+            if (unit.active)
+                this.active.push(unit);
             if (unit.isProjectile)
                 this.bullets.push(unit);
             if (unit.isCombatant)
                 this.units.push(unit);
+            if (unit.tick)
+                this.toTick.push(unit);
         }
         
         if (unit instanceof Player) {
@@ -194,13 +214,13 @@ Y.subclass('Game', {
         return unit;
     },
     
-    addThing : function addThing(unit, x,y){
+    addUnit : function addUnit(unit, x,y){
         if (unit instanceof Event)
             unit = unit.trigger;
         
         if (unit.dead) return unit;
         
-        this.noteThing(unit);
+        this.noteUnit(unit);
         
         if (x !== undefined) {
             unit.position(x,y);
@@ -214,22 +234,31 @@ Y.subclass('Game', {
         return unit;
     },
     
-    killThing : function killThing(unit){
+    killUnit : function killUnit(unit){
         if (unit instanceof Event)
             unit = unit.data.unit;
         
         delete this.byId[unit.__id__];
-        this.active.remove(unit);
         this.map.removeBlocker(unit);
         
-        if (unit instanceof Bullet)
+        if (unit.active)
+            this.active.remove(unit);
+        if (unit.tick)
+            this.toTick.remove(unit);
+        if (unit.isProjectile)
             this.bullets.remove(unit);
-        else
+        if (unit.isCombatant)
             this.units.remove(unit);
         
         return unit;
     },
     
+    removeUnitFromMap : function removeUnitFromMap(unit){
+        unit.remove();
+        this.map.removeBlocker(unit);
+        return unit;
+    },
+    
     moveThingTo : function moveThingTo(agent, x,y){
         this.map.removeBlocker(agent);
         if (agent.dead) return agent;
index 24b2520..9475af0 100644 (file)
@@ -1,7 +1,7 @@
 
 var undefined
 ,   Y = require('Y').Y
-,   GRID_ELEMENT  = '#viewport'
+,   GAME_ELEMENT  = '#game'
 
 ,   REF_SIZE      = 50
 ,   CELL_SIZE     = REF_SIZE
index 50fa1ab..21944c9 100644 (file)
@@ -51,17 +51,17 @@ new evt.Class('Level', {
             // if (isReplay && x.type === 'player')
             //     return null;
             var obj = data[x.type].instantiate(x.align);
-            return game.addThing(obj, x.loc[0], x.loc[1]);
+            return game.addUnit(obj, x.loc[0], x.loc[1]);
         });
         
         var data = tanks.data.items;
         this.items.map(function(x){
             var obj = data[x.type].instantiate();
-            return game.addThing(obj, x.loc[0], x.loc[1]);
+            return game.addUnit(obj, x.loc[0], x.loc[1]);
         });
         
         // I =
-        // game.addThing(Item.create('nitro'), 8,8);
+        // game.addUnit(Item.create('nitro'), 8,8);
         
         return this;
     }
index deafe60..fc3f14f 100644 (file)
@@ -70,21 +70,6 @@ Line.subclass('Trajectory', {
     },
     
     
-    canSee : function canSee(obj, ignore){
-        ignore = [this.owner].concat(ignore || []);
-        // var blockers = this.map.denseWalls
-        //         .apply('remove', ignore)
-        //         .filter(this.intersects)
-        //         .sort( this.compare )
-        var blockers = this.map.denseWalls
-        ,   blockers = blockers.apply('remove', ignore).concat([ obj ])
-        ,   blockers = blockers.filter(this.intersects)
-        ,   blockers = blockers.sort(this.compare)
-        ,   blocker = blockers.first()
-        ;
-        return !!(blocker === obj);
-    },
-    
     intersects : function intersects(x,y){
         var o = x;
         if (o.bbox)
@@ -199,6 +184,21 @@ Line.subclass('Trajectory', {
         return ( t <= ft && (dw <= w || dh <= h) );
     },
     
+    canSee : function canSee(obj, ignore){
+        ignore = [this.owner].concat(ignore || []);
+        // var blockers = this.map.denseWalls
+        //         .apply('remove', ignore)
+        //         .filter(this.intersects)
+        //         .sort( this.compare )
+        var blockers = this.map.denseWalls
+                .apply('remove', ignore).concat([ obj ])
+                .filter(this.intersects)
+                .sort(this.compare)
+        ,   blocker = blockers.first()
+        ;
+        return !!(blocker === obj);
+    },
+    
     pathBlocked : function pathBlocked(obj, ignore){
         // var walls, blockers
         // if (this.owner.isProjectile)
@@ -218,6 +218,28 @@ Line.subclass('Trajectory', {
         return (blocker === obj ? false : blocker);
     },
     
+    calcIntersectTraj : function calcIntersectTraj(fireLoc, speed){
+        // targetVelocityVector = math.Vector3(0, 0, 0) * aTargetSpeed
+        // interceptVelocityVector = math.Vector3(0, 0, 0) * aBulletSpeed
+        //    
+        // tDelta = aTargetPosition - aFiringPosition
+        //    
+        // Vr = targetVelocityVector - interceptVelocityVector
+        // a = Vr.Dot( Vr ) - aBulletSpeed * aBulletSpeed
+        // b = 2 * Vr.Dot( tDelta )
+        // c = tDelta.Dot ( tDelta )
+        //    
+        // deter = b * b - 4 * ( a * c )
+        //    
+        // if deter < 0:
+        //   return -1
+        // else:
+        //   ETN = 2 * ( c / pdmath.sqrt(deter) - b )
+        //   return ETN
+        
+    },
+    
+    
     toString : function(){
         return 'T['+this.p1+', '+this.p2+', slope='+this.slope.toFixed(3)+']';
     }
index 6ee11dc..4cac56d 100644 (file)
@@ -61,7 +61,7 @@ Wall.subclass('Rock', {
                 if ( gapOk && (x <= gapX && gapX <= nextX) && (y <= gapY && gapY <= nextY) ) {
                     rock.dead = true; // Don't recursively fire destroy event
                     rock.divide(gap).remove();
-                    this.game.killThing(rock);
+                    this.game.killUnit(rock);
                 }
             }
         }
index 19a7306..5c5e37a 100644 (file)
@@ -38,6 +38,7 @@ Thing.subclass('Wall', {
     // inactive
     active : false,
     createCooldowns : op.nop,
+    tick : op.nop,
     
     stats : {
         hp    : Infinity,
index 8579128..9b33bbe 100644 (file)
@@ -20,7 +20,7 @@ Mixin.subclass('Inventoried', {
             'item1' : 'consumable',
             'item2' : 'consumable'
         },
-        max       : 10,     // Backpack capacity
+        max       : 12,     // Backpack capacity
         size      : 0,      // Number of items
         items     : null,   // item id -> Item { backpack:backpack[i], slot:slotName }
         backpack  : null,   // Array of positions of items in backpack: backpack idx -> item id
@@ -153,8 +153,8 @@ Mixin.subclass('Inventoried', {
     },
     
     
-    _fireItemChange : function _fireItemChange(evt, item){
-        var data = { 'unit':this, 'item':item };
+    _fireItemChange : function _fireItemChange(evt, item, data){
+        data = Y.extend({ 'unit':this, 'item':item }, data || {});
         this.fire(evt, item, data);
         item.fire(evt, this, data);
         return this;
@@ -167,33 +167,36 @@ Mixin.subclass('Inventoried', {
      */
     addItem : function addItem(item){
         item = this.getItem(item);
+        var idx = this.getEmptySlot();
         
         // TODO: UI feedback on failure
-        if ( !this._putItem(item) )
+        if ( !this._putItem(item, idx) )
             return this;
         
-        return this._fireItemChange('item.acquire', item);
+        return this._fireItemChange('item.acquire', item, { 'idx':idx });
     },
     
     removeItem : function removeItem(item){
         item = this.getItem(item);
+        var idx = item && item.backpack;
         
         // TODO: UI feedback on failure
         if ( this._removeItem(item) )
             return this;
         
-        this._fireItemChange('item.lose', item);
+        this._fireItemChange('item.lose', item, { 'idx':idx });
         return item;
     },
     
     dropItem : function dropItem(idx){
         item = this.getItem(item);
+        var idx = item && item.backpack;
         
         // TODO: UI feedback on failure
         if ( this._removeItem(item) )
             return this;
         
-        this._fireItemChange('item.lose.drop', item);
+        this._fireItemChange('item.lose.drop', item, { 'idx':idx });
         return item;
     },
     
@@ -221,7 +224,7 @@ Mixin.subclass('Inventoried', {
         eqs[slot] = item;
         item.slot = slot;
         
-        return this._fireItemChange('item.equip', item);
+        return this._fireItemChange('item.equip', item, { 'slot':slot });
     },
     
     unequipSlot : function unequipSlot(slot, idx){
@@ -236,7 +239,7 @@ Mixin.subclass('Inventoried', {
             
             eqs[slot] = null;
             item.slot = null;
-            this._fireItemChange('item.unequip', item); // Add slot data
+            this._fireItemChange('item.unequip', item, { 'slot':slot, 'idx':idx });
         }
         return this;
     }
index 2c71ec3..95a3e4b 100644 (file)
@@ -33,13 +33,6 @@ Mixin.subclass('Quantified', {
     },
     
     createCooldowns : function createCooldowns(){
-        // this._cooldowns = Y({
-        //     'attack': new Cooldown(1000 * this.stats.speed.val)
-        // });
-        // this._ai = Y(this.ai).map(function(freq, k){
-        //     return new Cooldown(1000 * freq);
-        // });
-        
         this._cooldowns = Y(this.cooldowns).map(this._createCooldown, this);
         this.cooldowns = this._cooldowns.end();
         
@@ -53,7 +46,7 @@ Mixin.subclass('Quantified', {
         return new Cooldown(1000 * freq);
     },
     
-    updateCooldowns : function updateCooldowns(elapsed, now){
+    tick : function tick(elapsed, now){
         this._cooldowns.invoke('tick', elapsed, now);
         this._ai.invoke('tick', elapsed, now);
         this.buffs.invoke('tick', elapsed, now);
index ef1e62f..c204417 100644 (file)
@@ -43,9 +43,10 @@ Mixin.subclass('Speciated', {
             props = props || {};
             props.__species__ = id;
             
-            if (props.inherit) {
+            if (props.include) {
                 var parent = this.lookup(props.inherit);
                 props = deepcopy(Y.extend({}, parent.__species_props__, props));
+                delete props.include;
             }
             
             var cls = this
index 1401851..fe85c15 100644 (file)
@@ -77,7 +77,7 @@ Thing.subclass('Bullet', {
     },
     
     createCooldowns : op.nop,
-    updateCooldowns : op.nop,
+    tick : op.nop,
     
     setTarget : function setTarget(x,y){
         var loc = this.loc
index 33d6b49..87ed9c6 100644 (file)
@@ -30,7 +30,7 @@ Thing.subclass('Item', {
     dealDamage : op.nop,
     
     // inactive
-    active     : true,
+    active     : false,
     
     
     /// Instance Properties ///
@@ -82,18 +82,16 @@ Thing.subclass('Item', {
     activate : function activate(){
         console.log(this+' activated!');
         
-        if (!this.owner) return this;
-        this.currentBuffs.extend( this.effects.invoke('instantiate', this.owner) );
+        if ( this.owner && this.cooldowns.activate.activate() ) {
+            this.currentBuffs.extend( this.effects.invoke('instantiate', this.owner) );
+        }
         return this;
     },
     
-    onActivate : function onActivate(evt){
-        console.log(this+' onActivate!');
-    },
-    
     onCollide : function onCollide(evt){
         var unit = evt.data.unit;
-        if (unit.hasInventory && unit.canAddItem()) unit.addItem(this);
+        if (unit.hasInventory && unit.canAddItem())
+            unit.addItem(this);
     },
     
     onAcquired : function onAcquired(evt){
@@ -101,6 +99,7 @@ Thing.subclass('Item', {
         // console.log(this.owner+' acquired '+this+' ('+this.desc+')!');
         this.currentBuffs = this.passives.invoke('instantiate', this.owner);
         this.remove(); // removes map object
+        this.game.map.removeBlocker(this); // remove map zone
     },
     
     onLost : function onLost(evt){
index 24d3a30..1dad30d 100644 (file)
@@ -180,7 +180,6 @@ Thing.subclass('Tank', function(Tank){
         p.addEventListener('destroy', this.onBulletDeath);
         return p;
     };
-    
     function filterShoot(v){
         return (v !== this)
             && (v.density === DensityType.BOUNDARY || (v.isWall && v.density === DensityType.DENSE));
index a73ff83..c70c957 100644 (file)
@@ -3,3 +3,4 @@ var Y = require('Y').Y;
 exports['PathMapUI'] = require('tanks/ui/pathmapui').PathMapUI;
 exports['main'] = require('tanks/ui/main');
 exports['config'] = require('tanks/ui/configui');
+exports['inventory'] = require('tanks/ui/inventory');
\ No newline at end of file
index 1f0e0fb..996049d 100644 (file)
+//#ensure "jquery.tipsy"
 var Y = require('Y').Y
 ,   Layer = require('ezl/layer/layer').Layer
 ,
 
-BackpackSlot =
-exports['BackpackSlot'] =
-Layer.subclass('BackpackSlot', {
+
+Backpack =
+exports['Backpack'] =
+Layer.subclass('Backpack', {
+    _cssClasses : 'backpack hud',
     hasCanvas : false,
     
-    init : function initBackpackSlot(){
+    
+    init : function initBackpack(unit){
+        Layer.init.call(this);
         
+        this.unit = unit;
+        this.layer.attr('id', 'backpack');
+        var inv = this.inventory = unit.inventory
+        ,   bp  = inv.backpack
+        ;
+        this.slots = new Y(0, inv.max).map(function(idx){
+            var item = bp[idx];
+            return new BackpackSlot(this, idx).appendTo(this);
+        }, this);
+        
+        this.onItemUpdated = this.onItemUpdated.bind(this);
+        unit.addEventListener('item.acquire', this.onItemUpdated);
+        unit.addEventListener('item.lose',    this.onItemUpdated);
+    },
+    
+    refresh : function refresh(){
+        this.slots.invoke('refresh');
+        return this;
+    },
+    
+    onItemUpdated : function onItemUpdated(evt){
+        var d = evt.data;
+        console.log(this+'.onItemUpdated(idx='+d.idx+', item='+d.item+')');
+        this.slots[d.idx].refresh();
+    },
+    
+    // onItemAcquired : function onItemAcquired(evt){
+    //     var d = evt.data;
+    //     console.log('onItemAcquired(idx=%s, item=%s)', d.idx, d.item);
+    //     this.slots[d.idx].setItem( d.item );
+    // },
+    
+    // onItemLost : function onItemLost(evt){
+    //     var d = evt.data;
+    //     console.log('onItemLost(idx=%s, item=%s)', d.idx, d.item);
+    //     this.slots[d.idx].removeItem();
+    // },
+    
+    toString : function(){
+        return this.className+'(unit='+this.unit+')';
     }
     
 })
+,
 
 
-Backpack =
-exports['Backpack'] =
-Layer.subclass('Backpack', {
-    hasCanvas : false,
+BackpackSlot =
+exports['BackpackSlot'] =
+Layer.subclass('BackpackSlot', {
+    _cssClasses : 'backpack hud slot',
+    hasCanvas  : false,
+    artWidth   : 50,
+    artHeight  : 50,
     
-    init : function initBackpack(unit){
+    idx      : -1,
+    backpack : null,
+    item     : null,
+    
+    
+    init : function initBackpackSlot(backpack, idx){
         Layer.init.call(this);
+        this.backpack = backpack;
+        this.inventory = backpack.inventory;
+        this.idx = idx;
+        this.layer.addClass('slot'+idx);
+        this.inner =
+            new Layer({ hasCanvas:false })
+                .appendTo(this)
+                .position(8, 8);
+        this.onActivate = this.onActivate.bind(this);
+    },
+    
+    refresh : function refresh(){
+        var item = this.inventory.backpack[this.idx];
+        if (item)
+            this.setItem(item);
+        else
+            this.removeItem();
+    },
+    
+    setItem : function setItem(item){
+        if (!item) return this;
         
-        this.unit = unit;
-        this.inventory = unit.inventory;
+        this.removeItem();
+        this.item = item;
+        this.layer.addClass('occupied');
         
-        var layer = this.layer = jQuery('<div class="backpack" />');
-        this.slots = this.inv.backpack.map(function(item, i){
-            var el = jQuery('<div class="slot slot'+i+(item ? ' occupied' : '')+'" />');
-            return el;
-        }, this);
+        // console.log(this+'.setItem('+item+')', item.activateGauge);
+        
+        var icon = item.art && item.art.inv_icon
+        ,   src = this.itemEl =
+            jQuery('<img class="item" />')
+                .width(this.artWidth)
+                .height(this.artHeight)
+                .appendTo(this.inner.layer)
+        ;
+        if (icon) src.attr('src', icon);
+        src.attr('title', '<b>'+item.name+'</b><br/>'+item.desc);
+        src.tipsy({ 'html':true, 'gravity':$.fn.tipsy.autoNS });
+        
+        this.layer.click(this.onActivate);
+        
+        this.inner.append(item.activateGauge);
+        // item.activateGauge.draw();
+        
+        return this;
+    },
+    
+    removeItem : function removeItem(){
+        if (this.item) {
+            this.inner.empty();
+            this.item = null;
+            this.itemEl = null;
+        }
+        return this;
+    },
+    
+    onActivate : function onActivate(evt){
+        console.log(this+'.onActivate()!');
+        this.item.activate();
+    },
+    
+    toString : function(){
+        return this.className+'(idx='+this.idx+', item='+this.item+')';
     }
     
-});
+})
+;
index e69de29..c7604fa 100644 (file)
@@ -0,0 +1,4 @@
+require('Y').Y
+.extend(exports, {
+    'Backpack' : require('tanks/ui/inventory/backpack').Backpack
+});
\ No newline at end of file
index ec2f85d..d1994d6 100644 (file)
@@ -113,7 +113,7 @@ function setupGame(){
 
 function teardownGame(){
     game.destroy();
-    $('#viewport').empty();
+    // $('#viewport').empty();
 }
 
 
index ee74a81..2a30da3 100644 (file)
@@ -24,37 +24,34 @@ td { text-align:center; vertical-align:middle; }
     font-size:1.5em; padding:0.5em; background-color:#E73075; color:#fff; text-align:center; text-transform:uppercase;
     border:5px solid #fff; }
 
+/*
 #ai { position:absolute; z-index:2002; width:80%; left:10%; }
     #ai h2 { font-size:1.3em; }
     #ai .box { width:100%; }
     #ai .ready { width:5%; float:left; margin-right:1em; }
     #ai textarea { width:90%; height:100px; }
-
-#viewport { position:relative; margin:1em auto; cursor:crosshair; width:auto; /* width:500px; height:500px;  overflow:hidden; top:50px; left:50px; */ }
-    #viewport .layer.grid { outline:1px solid rgba(255,255,255,0.1); }
+*/
+/* 
+#welcome fieldset { border:1px solid #182B53; padding:1em; }
+#welcome legend { padding:0.5em; text-transform:uppercase; }
+*/
 
 #overlay { position:fixed; top:0; left:0; width:100%; height:100%; background-color:#000; opacity:0.5; z-index:1000; }
-
 .countdown { position:fixed; overflow:hidden; z-index:2000; text-align:center; border:10px solid #fff; color:#fff; }
-
 #loading h2 { text-align:center; }
-
 #welcome .box { cursor:pointer; }
 #notes { /* position:fixed; top:4em; right:1em; color:#BFBFBF;*/ }
     #notes ul, #notes ol, #notes li { list-style:circle ! important; }
     #notes li { margin-left:1em; }
 
 
-/* 
-#welcome fieldset { border:1px solid #182B53; padding:1em; }
-#welcome legend { padding:0.5em; text-transform:uppercase; }
-*/
+#game { position:absolute; width:100%; height:100%; margin:0; padding:0; }
+#viewport { position:relative; margin:1em auto; cursor:crosshair; width:auto; /* width:500px; height:500px;  overflow:hidden; top:50px; left:50px; */ }
+    #viewport .layer.grid { outline:1px solid rgba(255,255,255,0.1); }
+#backpack { position:absolute; bottom:1em; right:1em; width:296px; height:222px; /* top:auto; left:auto; */ }
+    #backpack .slot { float:left; position:relative; width:50px; height:50px; margin:0.25em; /* padding:0; top:auto; left:auto; */ }
+
 
-/* 
-#debug { position:relative; top:1em; right:1em; z-index:5000; }
-    #debug .inner { position:absolute; top:0; right:0; padding:1em; }
-    #debug .inner > * { float:right; margin-right:1em; }
-*/
 
 .debug { z-index:5000; }
     .debug .inner { top:0; right:0; padding:1em; }
@@ -90,3 +87,9 @@ table.grid td { /* outline:1px solid rgba(255,255,255,0.1); */
 
 .ezl.layer.pathmap { z-index:50; }
 
+/* 
+#debug { position:relative; top:1em; right:1em; z-index:5000; }
+    #debug .inner { position:absolute; top:0; right:0; padding:1em; }
+    #debug .inner > * { float:right; margin-right:1em; }
+*/
+
index ec1fe63..50af9e5 100644 (file)
@@ -1,4 +1,4 @@
-.tipsy { padding: 5px; font-size: 10px; position: absolute; z-index: 100000; }
+.tipsy { padding: 5px; font-size: 12px; position: absolute; z-index: 100000; }
   .tipsy-inner { padding: 5px 8px 4px 8px; background-color: black; color: white; max-width: 200px; text-align: center; }
   .tipsy-inner { border-radius: 3px; -moz-border-radius:3px; -webkit-border-radius:3px; }
   .tipsy-arrow { position: absolute; background: url('../img/tipsy.gif') no-repeat top left; width: 9px; height: 5px; }
index 30ac013..8b13789 100644 (file)
@@ -1 +1 @@
-<div id="viewport"></div>
+
index ea7a063..b2b0b95 100644 (file)
@@ -4,7 +4,8 @@
 <title>The Littlest Battletank</title>
 <link rel="shortcut icon" href="/favicon.ico">
 <link rel="stylesheet" href="css/reset.css" type="text/css" media="screen">
-<link rel="stylesheet" href="css/lttl.css" type="text/css" media="screen">
+<link rel="stylesheet" href="css/lttl.css"  type="text/css" media="screen">
+<link rel="stylesheet" href="css/tipsy.css" type="text/css" media="screen">
 </head>
 <body class="lttl tanks">
 
diff --git a/www/img/items/green-sq.png b/www/img/items/green-sq.png
new file mode 100644 (file)
index 0000000..6581378
Binary files /dev/null and b/www/img/items/green-sq.png differ