From 47a46590732927a52d0dc54dcf75ed906e9caf42 Mon Sep 17 00:00:00 2001 From: dsc Date: Mon, 17 Jan 2011 00:36:16 -0800 Subject: [PATCH] Adds inventory UI. --- data/types/buffs.yaml | 6 +- data/types/items.yaml | 6 +- data/types/levels.yaml | 72 ++++++++++++++++- data/types/units.yaml | 4 +- src/Y/modules/y.scaffold.cjs | 2 +- src/ezl/layer/layer.cjs | 8 ++- src/ezl/widget/cooldown.cjs | 4 +- src/tanks/game.cjs | 73 ++++++++++++----- src/tanks/globals.js | 2 +- src/tanks/map/level.cjs | 6 +- src/tanks/map/pathing/trajectory.cjs | 52 +++++++++---- src/tanks/map/rock.cjs | 2 +- src/tanks/map/wall.cjs | 1 + src/tanks/mixins/inventoried.cjs | 21 +++-- src/tanks/mixins/quantified.cjs | 9 +-- src/tanks/mixins/speciated.cjs | 3 +- src/tanks/thing/bullet.cjs | 2 +- src/tanks/thing/item.cjs | 15 ++-- src/tanks/thing/tank.cjs | 1 - src/tanks/ui/index.cjs | 1 + src/tanks/ui/inventory/backpack.cjs | 143 ++++++++++++++++++++++++++++++---- src/tanks/ui/inventory/index.cjs | 4 + src/tanks/ui/main.cjs | 2 +- www/css/lttl.css | 33 ++++---- www/css/tipsy.css | 2 +- www/game.html | 2 +- www/header.html | 3 +- www/img/items/green-sq.png | Bin 0 -> 6197 bytes 28 files changed, 356 insertions(+), 123 deletions(-) create mode 100644 www/img/items/green-sq.png diff --git a/data/types/buffs.yaml b/data/types/buffs.yaml index 9a555e6..2280501 100644 --- a/data/types/buffs.yaml +++ b/data/types/buffs.yaml @@ -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: '' diff --git a/data/types/items.yaml b/data/types/items.yaml index 2c3146b..90e0e87 100644 --- a/data/types/items.yaml +++ b/data/types/items.yaml @@ -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' diff --git a/data/types/levels.yaml b/data/types/levels.yaml index 44a9f2a..875e7ba 100644 --- a/data/types/levels.yaml +++ b/data/types/levels.yaml @@ -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] + diff --git a/data/types/units.yaml b/data/types/units.yaml index 85f4ebb..e461135 100644 --- a/data/types/units.yaml +++ b/data/types/units.yaml @@ -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: diff --git a/src/Y/modules/y.scaffold.cjs b/src/Y/modules/y.scaffold.cjs index 4fdbfe7..ea0f200 100644 --- a/src/Y/modules/y.scaffold.cjs +++ b/src/Y/modules/y.scaffold.cjs @@ -141,7 +141,7 @@ function create(config, el){ var g = groups[chain] = jQuery('
') - .attr('id', chain) + .attr('id', 'group-'+chain) .addClass('group') .append( jQuery('').text(chain.split('.').pop()) ) .appendTo(el); diff --git a/src/ezl/layer/layer.cjs b/src/ezl/layer/layer.cjs index 7af06de..48b71b6 100644 --- a/src/ezl/layer/layer.cjs +++ b/src/ezl/layer/layer.cjs @@ -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('
') + this.layer = jQuery(html || '
') .addClass(this._cssClasses) .data('layer', this); this.layer[0].layer = this; + if (attrs) this.layer.attr(attrs); if (this.hasCanvas) { this.canvas = jQuery('') diff --git a/src/ezl/widget/cooldown.cjs b/src/ezl/widget/cooldown.cjs index e94b51b..d7429a4 100644 --- a/src/ezl/widget/cooldown.cjs +++ b/src/ezl/widget/cooldown.cjs @@ -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(); diff --git a/src/tanks/game.cjs b/src/tanks/game.cjs index 582ed8e..08c7d0a 100644 --- a/src/tanks/game.cjs +++ b/src/tanks/game.cjs @@ -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; diff --git a/src/tanks/globals.js b/src/tanks/globals.js index 24b2520..9475af0 100644 --- a/src/tanks/globals.js +++ b/src/tanks/globals.js @@ -1,7 +1,7 @@ var undefined , Y = require('Y').Y -, GRID_ELEMENT = '#viewport' +, GAME_ELEMENT = '#game' , REF_SIZE = 50 , CELL_SIZE = REF_SIZE diff --git a/src/tanks/map/level.cjs b/src/tanks/map/level.cjs index 50fa1ab..21944c9 100644 --- a/src/tanks/map/level.cjs +++ b/src/tanks/map/level.cjs @@ -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; } diff --git a/src/tanks/map/pathing/trajectory.cjs b/src/tanks/map/pathing/trajectory.cjs index deafe60..fc3f14f 100644 --- a/src/tanks/map/pathing/trajectory.cjs +++ b/src/tanks/map/pathing/trajectory.cjs @@ -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)+']'; } diff --git a/src/tanks/map/rock.cjs b/src/tanks/map/rock.cjs index 6ee11dc..4cac56d 100644 --- a/src/tanks/map/rock.cjs +++ b/src/tanks/map/rock.cjs @@ -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); } } } diff --git a/src/tanks/map/wall.cjs b/src/tanks/map/wall.cjs index 19a7306..5c5e37a 100644 --- a/src/tanks/map/wall.cjs +++ b/src/tanks/map/wall.cjs @@ -38,6 +38,7 @@ Thing.subclass('Wall', { // inactive active : false, createCooldowns : op.nop, + tick : op.nop, stats : { hp : Infinity, diff --git a/src/tanks/mixins/inventoried.cjs b/src/tanks/mixins/inventoried.cjs index 8579128..9b33bbe 100644 --- a/src/tanks/mixins/inventoried.cjs +++ b/src/tanks/mixins/inventoried.cjs @@ -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; } diff --git a/src/tanks/mixins/quantified.cjs b/src/tanks/mixins/quantified.cjs index 2c71ec3..95a3e4b 100644 --- a/src/tanks/mixins/quantified.cjs +++ b/src/tanks/mixins/quantified.cjs @@ -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); diff --git a/src/tanks/mixins/speciated.cjs b/src/tanks/mixins/speciated.cjs index ef1e62f..c204417 100644 --- a/src/tanks/mixins/speciated.cjs +++ b/src/tanks/mixins/speciated.cjs @@ -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 diff --git a/src/tanks/thing/bullet.cjs b/src/tanks/thing/bullet.cjs index 1401851..fe85c15 100644 --- a/src/tanks/thing/bullet.cjs +++ b/src/tanks/thing/bullet.cjs @@ -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 diff --git a/src/tanks/thing/item.cjs b/src/tanks/thing/item.cjs index 33d6b49..87ed9c6 100644 --- a/src/tanks/thing/item.cjs +++ b/src/tanks/thing/item.cjs @@ -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){ diff --git a/src/tanks/thing/tank.cjs b/src/tanks/thing/tank.cjs index 24d3a30..1dad30d 100644 --- a/src/tanks/thing/tank.cjs +++ b/src/tanks/thing/tank.cjs @@ -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)); diff --git a/src/tanks/ui/index.cjs b/src/tanks/ui/index.cjs index a73ff83..c70c957 100644 --- a/src/tanks/ui/index.cjs +++ b/src/tanks/ui/index.cjs @@ -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 diff --git a/src/tanks/ui/inventory/backpack.cjs b/src/tanks/ui/inventory/backpack.cjs index 1f0e0fb..996049d 100644 --- a/src/tanks/ui/inventory/backpack.cjs +++ b/src/tanks/ui/inventory/backpack.cjs @@ -1,35 +1,144 @@ +//#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('
'); - this.slots = this.inv.backpack.map(function(item, i){ - var el = jQuery('
'); - return el; - }, this); + // console.log(this+'.setItem('+item+')', item.activateGauge); + + var icon = item.art && item.art.inv_icon + , src = this.itemEl = + jQuery('') + .width(this.artWidth) + .height(this.artHeight) + .appendTo(this.inner.layer) + ; + if (icon) src.attr('src', icon); + src.attr('title', ''+item.name+'
'+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+')'; } -}); +}) +; diff --git a/src/tanks/ui/inventory/index.cjs b/src/tanks/ui/inventory/index.cjs index e69de29..c7604fa 100644 --- a/src/tanks/ui/inventory/index.cjs +++ b/src/tanks/ui/inventory/index.cjs @@ -0,0 +1,4 @@ +require('Y').Y +.extend(exports, { + 'Backpack' : require('tanks/ui/inventory/backpack').Backpack +}); \ No newline at end of file diff --git a/src/tanks/ui/main.cjs b/src/tanks/ui/main.cjs index ec2f85d..d1994d6 100644 --- a/src/tanks/ui/main.cjs +++ b/src/tanks/ui/main.cjs @@ -113,7 +113,7 @@ function setupGame(){ function teardownGame(){ game.destroy(); - $('#viewport').empty(); + // $('#viewport').empty(); } diff --git a/www/css/lttl.css b/www/css/lttl.css index ee74a81..2a30da3 100644 --- a/www/css/lttl.css +++ b/www/css/lttl.css @@ -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; } +*/ + diff --git a/www/css/tipsy.css b/www/css/tipsy.css index ec1fe63..50af9e5 100644 --- a/www/css/tipsy.css +++ b/www/css/tipsy.css @@ -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; } diff --git a/www/game.html b/www/game.html index 30ac013..8b13789 100644 --- a/www/game.html +++ b/www/game.html @@ -1 +1 @@ -
+ diff --git a/www/header.html b/www/header.html index ea7a063..b2b0b95 100644 --- a/www/header.html +++ b/www/header.html @@ -4,7 +4,8 @@ The Littlest Battletank - + + diff --git a/www/img/items/green-sq.png b/www/img/items/green-sq.png new file mode 100644 index 0000000000000000000000000000000000000000..6581378bbd961cdcaf7b31cb59a6ca71207fe7a1 GIT binary patch literal 6197 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 TjVHy?00000NkvXXu0mjf9bnUH literal 0 HcmV?d00001 -- 1.7.0.4