From 9a6102f56a04fad5613efcb0a23b96f3fe5c63e4 Mon Sep 17 00:00:00 2001 From: dsc Date: Thu, 10 Feb 2011 03:14:36 -0800 Subject: [PATCH] Checkpoint on new inventory. --- data/types/items.yaml | 15 +++++++++++++++ src/Y/core.cjs | 2 +- src/tanks/game.cjs | 2 +- src/tanks/inventory/bag.cjs | 10 +++++----- src/tanks/inventory/bagbag.cjs | 10 ++++------ src/tanks/inventory/container.cjs | 24 ++++++------------------ src/tanks/inventory/inventory.cjs | 6 +++++- src/tanks/map/level.cjs | 8 +++----- src/tanks/ui/inventory/containerui.cjs | 32 ++++++++++++++++++++++++-------- www/css/lttl.css | 5 +++-- www/img/items/backpack.jpg | Bin 0 -> 10816 bytes 11 files changed, 67 insertions(+), 47 deletions(-) create mode 100644 www/img/items/backpack.jpg diff --git a/data/types/items.yaml b/data/types/items.yaml index 9b2505e..911a84b 100644 --- a/data/types/items.yaml +++ b/data/types/items.yaml @@ -1,7 +1,22 @@ name: items defaults: symbol: tanks/thing/item.Item + passives: [] + effects: [] + cooldowns: [] + art: + map_icon: '' + inv_icon: '' types: + backpack: + name: Backpack + bagName: backpack + desc: Your backpack. + tags: [ 'bag', 'backpack' ] + symbol: tanks/inventory/bag.Bag + max: 12 + art: + inv_icon: '/img/items/backpack.jpg' nitro: name: Nitro desc: Speeds up your tank temporarily. diff --git a/src/Y/core.cjs b/src/Y/core.cjs index 706755e..43776b5 100644 --- a/src/Y/core.cjs +++ b/src/Y/core.cjs @@ -115,7 +115,7 @@ function extend( A, B ){ return args.reduce(_extend, A); } function _extend(A, donor){ return reduce(donor, attrvk, A); } -function attrvk(o, v, k){ return attr(o, k, v, o[k]); } +function attrvk(o, v, k){ return (v === undefined && o[k] === undefined) ? o : attr(o, k, v, o[k]); } /** * Fetches the descriptor for each property that is an accessor (getter/setter). diff --git a/src/tanks/game.cjs b/src/tanks/game.cjs index 2fe1856..a6ca65a 100644 --- a/src/tanks/game.cjs +++ b/src/tanks/game.cjs @@ -79,7 +79,7 @@ evt.subclass('Game', { Thing.on('destroy', this.killUnit); this.on('tick', this.tick); - this.level.setup(); + this.level.setup(tanks.data); // if (this.player) { // this.backpack = new Backpack(this.player) diff --git a/src/tanks/inventory/bag.cjs b/src/tanks/inventory/bag.cjs index d535721..ee007ad 100644 --- a/src/tanks/inventory/bag.cjs +++ b/src/tanks/inventory/bag.cjs @@ -15,7 +15,6 @@ Item.subclass('Bag', { /// Setup /// hasUI : true, - uiOptions : null, reqs : null, // highlightIconOnOpen : true, // Whether to highlight the inventory icon when bag is open @@ -24,9 +23,10 @@ Item.subclass('Bag', { ui : null, // ContainerUI - init : function initBag(owner, bagName){ - this.bagName = bagName; - this.owner = owner; + init : function initBag(owner, bagName, options){ + if (options) Y.core.extend(this, options); + if (owner) this.owner = owner; + if (bagName) this.bagName = bagName; Item.init.call(this); }, @@ -60,7 +60,7 @@ Item.subclass('Bag', { onAcquired : function onAcquired(evt, container){ Item.fn.onAcquired.apply(this, arguments); // this.parent = container; - this.showUI(); + // this.showUI(); }, onLost : function onLost(evt){ diff --git a/src/tanks/inventory/bagbag.cjs b/src/tanks/inventory/bagbag.cjs index bec16a8..3c59c7e 100644 --- a/src/tanks/inventory/bagbag.cjs +++ b/src/tanks/inventory/bagbag.cjs @@ -9,13 +9,11 @@ var Y = require('Y') BagBag = exports['BagBag'] = Bag.subclass('BagBag', { - __mixins__ : [], - __bind__ : [], - __static__ : {}, /// Setup /// hasUI : true, - uiOptions : null, + max : 1, + cols : 3, reqs : 'bag', // TODO: parse, enforce reqs // highlightIconOnOpen : true, // Whether to highlight the inventory icon when bag is open @@ -24,9 +22,9 @@ Bag.subclass('BagBag', { ui : null, // ContainerUI - init : function initBagBag(inventory, player){ + init : function initBagBag(inventory, player, options){ this.inventory = inventory; - Bag.init.call(this, player, 'bagbag'); + Bag.init.call(this, player, 'bagbag', options); this.showUI(); if (this.ui) this.ui.layer.addClass('bagbag bag'); } diff --git a/src/tanks/inventory/container.cjs b/src/tanks/inventory/container.cjs index 25b005f..f727d9a 100644 --- a/src/tanks/inventory/container.cjs +++ b/src/tanks/inventory/container.cjs @@ -114,8 +114,8 @@ Mixin.subclass('Container', { // Note item we're displacing, if any , dispItem = this.slots[idx] - , didDisplace = dispItem && dispItem !== item - , sameOwner = this.owner && item.owner && this.owner === item.owner + , didDisplace = !!(dispItem && dispItem !== item) + , sameOwner = !!(this.owner && item.owner && this.owner === item.owner) , newPickup = !(oldBag && sameOwner) , inventoryMove = sameOwner && !this.hasItem(item) , localMove = sameOwner && !inventoryMove @@ -147,7 +147,7 @@ Mixin.subclass('Container', { } var eq = this.equipsContents - , oldEq = oldBag.equipsContents + , oldEq = !!(oldBag && oldBag.equipsContents) , isEquipped = sameOwner && oldEq , evt = 'item'+(newPickup ? '.acquire' : '.move')+(eq ? (!isEquipped ? '.equip' : '') : (isEquipped ? '.unequip' : '')) , dispEvt = 'item.move'+(!eq ? (oldEq ? '.equip' : '') : (!oldEq ? '.unequip' : '')) @@ -158,19 +158,7 @@ Mixin.subclass('Container', { if ( didDisplace ) { oldBag._putItem(dispItem, oldIdx); - oldBag._emitItemChange('item.move', dispItem, { 'idx':oldIdx, 'oldBag':this, 'oldIdx':idx }); - } - - if ( inventoryMove ) { - if ( didDisplace ) { - oldBag._putItem(dispItem, oldIdx); - oldBag._emitItemChange('item.move', dispItem, { 'idx':oldIdx, 'oldBag':this, 'oldIdx':idx }); - } - this._emitItemChange('item.move', item, { 'idx':idx, 'oldBag':inv.bag, 'oldIdx':inv.idx }); - } else { - evt = - dispEvt = 'item.'+(oldBag.equipsContents ? '.equip' : ''); - this._emitItemChange(evt, item, { 'idx':idx, 'oldBag':inv.bag, 'oldIdx':inv.idx }); + oldBag._emitItemChange(dispEvt, dispItem, { 'idx':oldIdx, 'oldBag':this, 'oldIdx':idx }); } return this; @@ -263,7 +251,7 @@ Mixin.subclass('Container', { ; // Bag bounds check - if ( 0 <= idx && idx < this.max ) + if ( idx < 0 || idx >= this.max ) return false; if ( this.items[id] ) @@ -324,7 +312,7 @@ Mixin.subclass('Container', { * @return {this} */ _emitItemChange : function _emitItemChange(evt, item, data){ - data = Y.extend({ 'item':item, 'bag':this, 'unit':this.owner }, data || {}); + data = Y.core.extend({ 'item':item, 'bag':this, 'unit':this.owner }, data || {}); this.emit(evt, item, data, item); item.emit(evt, this, data, this); // unit.emit(evt, item, data); // inventory should take care of this diff --git a/src/tanks/inventory/inventory.cjs b/src/tanks/inventory/inventory.cjs index bd9e8ff..9ea2070 100644 --- a/src/tanks/inventory/inventory.cjs +++ b/src/tanks/inventory/inventory.cjs @@ -60,8 +60,12 @@ evt.subclass('Inventory', { this.bagbag = new BagBag(this, owner); + // TODO: Add saved items + var backpack = tanks.data.items.backpack.instantiate(); + this.bagbag.addItem(backpack); + this.bagbag.ui.refresh(); + // instantiate: - // - backpack // - equip slots // - belt }, diff --git a/src/tanks/map/level.cjs b/src/tanks/map/level.cjs index b0b8425..da9e1ae 100644 --- a/src/tanks/map/level.cjs +++ b/src/tanks/map/level.cjs @@ -33,7 +33,7 @@ new evt.Class('Level', { this.bbox = shape.bbox; }, - setup : function setup(isReplay){ + setup : function setup(repo){ var game = this.game; this.bounds = @@ -46,15 +46,13 @@ new evt.Class('Level', { return Wall.createApply(wall.type, wall.args); }); - var data = tanks.data.units; + var data = repo.units; this.units.map(function(x){ - // if (isReplay && x.type === 'player') - // return null; var obj = data[x.type].instantiate(x.align); return game.addUnit(obj, x.loc[0], x.loc[1]); }); - var data = tanks.data.items; + var data = repo.items; this.items.map(function(x){ var obj = data[x.type].instantiate(); return game.addUnit(obj, x.loc[0], x.loc[1]); diff --git a/src/tanks/ui/inventory/containerui.cjs b/src/tanks/ui/inventory/containerui.cjs index 39936ab..0848264 100644 --- a/src/tanks/ui/inventory/containerui.cjs +++ b/src/tanks/ui/inventory/containerui.cjs @@ -13,30 +13,37 @@ HtmlLayer.subclass('ContainerUI', { __bind__ : [ 'onItemUpdated', 'onDrop' ], _layerClasses : 'item-container hud', + inherit : 'name title showTitle max cols'.split(' '), + name : null, title : null, showTitle : false, defaultContainer : false, max : 1, - reqs : null, + cols : 3, unit : null, - + slots : null, init : function initContainerUI(unit, container, options){ + var keys = (options||{}).inherit || this.inherit; + for (var i=0, L=keys.length, k=keys[i]; i'+(this.title || this.name.toLowerCase())+'' ); this.slots = new Y(0, this.max).map(this._makeSlot, this); + this.layer.append('
'); if (this.defaultContainer) { unit.on('item.acquire', this.onItemUpdated); @@ -50,6 +57,15 @@ HtmlLayer.subclass('ContainerUI', { }, refresh : function refresh(){ + var len = this.slots.length + , el = this.slots[0].layer + , cols = Math.min(this.cols,len) + , rows = Math.ceil(len / cols) + , w = el.outerWidth() + , m = parseInt(el.css('margin-left').slice(0,-2)) + ; + this.layer.width( w*cols + m*2*cols ); + this.slots.invoke('refresh'); this.layer.find('.slot') .droppable({ @@ -94,7 +110,7 @@ HtmlLayer.subclass('ContainerUI', { ContainerUISlot = exports['ContainerUISlot'] = Layer.subclass('ContainerUISlot', { - _layerClasses : 'item-container slot hud ', + _layerClasses : 'item-container slot hud', hasCanvas : false, artWidth : 50, @@ -106,11 +122,11 @@ Layer.subclass('ContainerUISlot', { item : null, - init : function initContainerUISlot(container, idx){ + init : function initContainerUISlot(parent, idx){ Y.bindAll(this, 'onActivate', 'onDragStart'); Layer.init.call(this); - this.container = container; - this.inventory = container.inventory; + this.parent = parent; + this.container = parent.container; this.idx = idx; this.layer.addClass('slot'+idx); this.inner = @@ -199,7 +215,7 @@ Layer.subclass('ContainerUISlot', { }, toString : function(){ - return this.className+'(idx='+this.idx+', item='+this.item+')'; + return 'ContainerUISlot(idx='+this.idx+', item='+this.item+')'; } }) diff --git a/www/css/lttl.css b/www/css/lttl.css index 689c605..210cea6 100644 --- a/www/css/lttl.css +++ b/www/css/lttl.css @@ -48,13 +48,14 @@ td { text-align:center; vertical-align:middle; } #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:304px; height:254px; } -.item-container {} +.item-container { position:absolute; } .item-container h3 { color:#fff; margin:0.25em; padding:0.5em 0; } .item-container .slot { float:left; position:relative; width:50px; height:50px; margin:0.25em; border:1px solid transparent; } .item-container .slot.drophover { border:1px solid #FFF6AE; } +#backpack { position:absolute; bottom:82px; right:1em; /* width:304px; height:254px; */ } +#bagbag { bottom:1em; right:1em; } .debug { z-index:5000; } diff --git a/www/img/items/backpack.jpg b/www/img/items/backpack.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a2c8bfe239c6fc853c2c4e9d7cdcf707092f5123 GIT binary patch literal 10816 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