From: dsc Date: Mon, 31 Jan 2011 19:54:09 +0000 (-0800) Subject: Checkpoint on new inventory architecture. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=589ad5f4464b89471f3223b16682a787f9d678c8;p=tanks.git Checkpoint on new inventory architecture. --- diff --git a/src/Y/utils.cjs b/src/Y/utils.cjs index 85bbb16..649becd 100644 --- a/src/Y/utils.cjs +++ b/src/Y/utils.cjs @@ -15,7 +15,7 @@ UE.prototype = new Error('Unimplemented!'); function bindName(k){ var v = this[k]; - if ( isFunction(v) ) + if ( typeof v == 'function' ) this[k] = YFunction(v).bind(this); } @@ -24,7 +24,7 @@ function bindAll(o, names){ return o; if (arguments.length === 1) names = core.map(o, op.nth(1)); - else if ( !(names instanceof Array) ) + else if ( !isArray(names) ) names = slice.call(arguments, 1); core.forEach(names, bindName, o); return o; diff --git a/src/evt.cjs b/src/evt.cjs index bb45e16..83a0242 100644 --- a/src/evt.cjs +++ b/src/evt.cjs @@ -86,7 +86,7 @@ function ConstructorTemplate() { 'instance' : instance, 'cls' : cls, 'args' : Y(args) - }); + }, instance); var initialise = instance.__initialise__; if ( isFunction(initialise) ) @@ -129,7 +129,7 @@ function createInitialise(cls){ 'instance' : instance, 'cls' : cls, 'args' : Y(arguments) - }); + }, instance); return instance; } @@ -233,6 +233,7 @@ function Class(className, Parent, members){ // Record for metaprogramming KNOWN_CLASSES[className] = NewClass; + NewClass.__bind__ = prototype.__bind__; var mixins = NewClass.__mixins__ = Y([]).concat(members.__mixins__||[], SuperClass.__mixins__||[]).unique() , statics = NewClass.__static__ = {} , pstatics = SuperClass.__static__ @@ -269,7 +270,7 @@ function Class(className, Parent, members){ } NewClass.instantiate = instantiate.partial(NewClass); - // prototype.__bind__ = Y([]).concat(prototype.__bind__||[], SuperClass.fn.__bind__||[]).unique(); + NewClass.__bind__ = prototype.__bind__ = Y([]).concat(prototype.__bind__||[], SuperClass.__bind__||[]).unique(); // Notify mixins to let them finish up any customization if (mixins.length) @@ -286,7 +287,7 @@ function Class(className, Parent, members){ 'child' : NewClass, 'members' : members, 'prototype' : prototype - }); + }, NewClass); return NewClass; } @@ -298,6 +299,7 @@ Class.__emitter__ = new Emitter(Class); Class.fn = Class.prototype; Class.fn.__class__ = Class.fn.constructor = Class; Class.fn.__bases__ = Class.__bases__ = Y([ Object ]); +Class.fn.__bind__ = Class.__bind__ = Y([]); Class.className = Class.fn.className = "Class"; /* Class Methods */ @@ -380,8 +382,8 @@ function mixinFilter(v, k){ */ function mixin(cls, _mxn){ var proto = cls.fn - , bases = cls.__bases__ - , cbinds = proto.__bind__ + , bases = Y(cls.__bases__ || []) + , cbinds = Y(cls.__bind__ || []) , cstatic = cls.__static__ , mxns = (Y.isArray(_mxn) ? _mxn.slice(0) : Y(arguments, 1)) ; @@ -393,6 +395,7 @@ function mixin(cls, _mxn){ var mproto = (typeof mxn === "function") ? mxn.fn : mxn , statics = mxn.__static__ + , binds = mxn.__bind__ , onCreate = mproto.onCreate , firstMix = (bases && bases.indexOf(mxn) === -1) ; @@ -409,13 +412,17 @@ function mixin(cls, _mxn){ } } + // Add/ensure the mixin is at the front of bases + bases.remove(mxn).unshift(mxn); + + // Collate binds from mixin + if (binds) + cls.__bind__ = proto.__bind__ = cbinds.concat(binds).unique(); + // Only perform these actions the first time we mix into this class if (!firstMix) return; - // Add to bases - bases.unshift(mxn); - // Register onCreate to fire whenever a new instance is initialized if ( isFunction(cls.on) && hasOwn.call(mproto,'onCreate') && isFunction(onCreate) ) cls.on('create', onCreate); diff --git a/src/ezl/layer/layer.cjs b/src/ezl/layer/layer.cjs index 32bd20a..bbfc418 100644 --- a/src/ezl/layer/layer.cjs +++ b/src/ezl/layer/layer.cjs @@ -1,6 +1,9 @@ //#ensure "jquery" var Y = require('Y').Y , op = require('Y/op') + +, evt = require('evt') + , Vec = require('ezl/math/vec').Vec , Loc = require('ezl/loc/loc').Loc , BoundingBox = require('ezl/loc/boundingbox').BoundingBox @@ -16,7 +19,9 @@ FAUX_ACCESSORS = Y('width height position stroke fill origin rotate scale transl Layer = exports['Layer'] = -Y.subclass('Layer', { +new evt.Class('Layer', { + __bind__ : [ 'tick' ], + /// Class Defaults /// // _layer* is applied to this.layer (the DOM Element) @@ -109,7 +114,7 @@ Y.subclass('Layer', { this.canvas = jQuery(); } - this.tick = this.tick.bind(this); + // this.tick = this.tick.bind(this); }, /// Scene Graph Heirarchy /// diff --git a/src/tanks/effects/buff.cjs b/src/tanks/effects/buff.cjs index 65be09b..0c1ea05 100644 --- a/src/tanks/effects/buff.cjs +++ b/src/tanks/effects/buff.cjs @@ -58,13 +58,13 @@ new evt.Class('Buff', { return this; }, - die : function die(reason){ + die : function die(reason, trigger){ this.removeStatMods(); // var evt = 'buff.die.'+reason // We'll add this when we add polymorphic dispatchers var evt = 'buff.die' , data = { 'buff':this, 'unit':this.target, 'owner':this.owner }; - this.emit(evt, this.target, data); - this.target.emit(evt, this, data); + this.emit(evt, trigger||this.target, data, this); + this.target.emit(evt, this, data, this); return this; }, diff --git a/src/tanks/item/bag.cjs b/src/tanks/inventory/bag.cjs similarity index 100% rename from src/tanks/item/bag.cjs rename to src/tanks/inventory/bag.cjs diff --git a/src/tanks/item/bagbag.cjs b/src/tanks/inventory/bagbag.cjs similarity index 100% rename from src/tanks/item/bagbag.cjs rename to src/tanks/inventory/bagbag.cjs diff --git a/src/tanks/item/belt.cjs b/src/tanks/inventory/belt.cjs similarity index 100% rename from src/tanks/item/belt.cjs rename to src/tanks/inventory/belt.cjs diff --git a/src/tanks/inventory/container.cjs b/src/tanks/inventory/container.cjs new file mode 100644 index 0000000..9ab726d --- /dev/null +++ b/src/tanks/inventory/container.cjs @@ -0,0 +1,335 @@ +var Y = require('Y').Y +, op = require('Y/op') +, deepcopy = require('Y/types/object').deepcopy + +, Mixin = require('evt').Mixin +, Item = require('tanks/thing/item').Item + +, kNull = op.K(null) +, + +Container = +exports['Container'] = +Mixin.subclass('Container', { + __bind__ : [], + + + max : 1, // Container capacity + reqs : null, // Array of tag requirements to be stored here + equipsContents : false, // Whether held items are equipped + + owner : null, // Owning unit + size : 0, // Number of items in container + items : null, // item id -> Item + slots : null, // Array of positions of items in container: container idx -> Item + children : null, // Nested containers: container id -> Container + + + onCreate : function initContainer(evt, owner, items){ + this.owner = owner; + this.items = {}; + this.children = {}; + this.slots = new Array(this.max); + + if ( typeof this.reqs == 'string' ) + this.reqs = Y([ this.reqs ]); + + if (items) items.forEach(this.moveItem, this); + }, + + + /** + * @param {Item} [item] If present, also check whether item matches this container's requirements. + * @return {Boolean} Whether this container will accept this item. + */ + canAddItem : function canAddItem(item){ + var reqs = this.reqs; + return this.size < this.max && + ( !item || !reqs || reqs.intersect(item.tags).length === reqs.length ); + }, + + checkReqs : function checkReqs(item){ + var reqs = this.reqs; + return !!item && ( !reqs || reqs.intersect(item.tags).length === reqs.length ); + }, + + getItem : function getItem(idx){ + if ( typeof idx == 'number' ) { + return this.slots[ (idx < 0 ? this.max+idx : idx) ]; + } else { + if (idx && !idx.inv) + idx.inv = new InventoryMeta(); + return idx; + } + }, + + /** + * @param {Number|Item} id The Item or Item ID for which to test. + * @return {Boolean} Whether the item is in this container. + */ + hasItem : function hasItem(id){ + if (id instanceof Item) id = id.__id__; + return !!this.items[id]; + }, + + /** + * Adds an item to this container. + * @param {Item} item + * @return {this} + */ + addItem : function addItem(item){ + if ( this.hasItem(item) ) + return this; + else + return this.moveItem(item, this._getEmptySlot()); + }, + + /** + * Changes the position of the item in this container. + * @param {Item} item Item to move. + * @param {Number} idx Index in the container to which to move item. + * @return {this} + */ + moveItem : function moveItem(item, idx){ + item = this.getItem(item); + if (!item || typeof idx != "number") + return this; + + idx = this._getIdx(idx); + + // Note old slot info before we mutate anything + var inv = item.inv.clone() + , oldIdx = inv.idx + , oldBag = inv.bag + + // Note item we're displacing, if any + , dispItem = this.slots[idx] + , didDisplace = dispItem && dispItem !== item + , sameOwner = this.owner && item.owner && this.owner === item.owner + , newPickup = !(oldBag && sameOwner) + , inventoryMove = sameOwner && !this.hasItem(item) + , localMove = sameOwner && !inventoryMove + + , hasRoom = !(didDisplace && newPickup && this.size >= this.max) + ; + + if ( !hasRoom ) + return this; + + // Check requirements and then attempt transaction + // TODO: if displaced item fails req check, we should try to find it a new home rather than giving up + if ( !( this.checkReqs(item) && ( !didDisplace || oldBag.checkReqs(dispItem) ) + && this._putItem(item, idx, didDisplace)) ) + return this; + + // Updates meta + size + if ( inventoryMove ) + oldBag._removeItem(item, oldIdx); + else if ( newPickup && oldBag ) + oldBag.removeItem(item, { 'oldIdx':oldIdx }); + + if ( didDisplace ) { + this._removeItem(dispItem, idx); + if ( oldBag && sameOwner ) + oldBag._putItem(dispItem, oldIdx); + else + this._putItem(dispItem, this._getEmptySlot()); + } + + var eq = this.equipsContents + , oldEq = oldBag.equipsContents + , isEquipped = sameOwner && oldEq + , evt = 'item'+(newPickup ? '.acquire' : '.move')+(eq ? (!isEquipped ? '.equip' : '') : (isEquipped ? '.unequip' : '')) + , dispEvt = 'item.move'+(!eq ? (oldEq ? '.equip' : '') : (!oldEq ? '.unequip' : '')) + ; + + // metadata clone preserves original values in case of loss (displacement by a new pickup) + this._emitItemChange(evt, item, { 'idx':idx, 'oldBag':inv.bag, 'oldIdx':inv.idx }); + + 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 }); + } + + return this; + }, + + /** + * Removes the item from this container and fires the appropriate events. + * @param {Item|Number} item Item or container index to remove. + * @param {Object} [options] Options are: + * * @option {Number} [oldIdx] In cases where `item.inv` has already been modified, the + * old index of the item is required to be manually supplied to clean up correctly. + * * @option {Boolean} [keepEquipped=false] If true, does not fire item.unequip event. + * * @option {Boolean} [drop=false] If true, Item is dropped and not just removed from + * this container. If Container `equipsContents`, this overrides `options.keepEquipped`. + * @return {Item} The removed item or null on failure. + */ + removeItem : function removeItem(item, options){ + options = options || {}; + item = this.getItem(item); + if (!item) + return item; + + var idx = (options.oldIdx !== undefined ? options.oldIdx : item.inv.idx); + if ( !this._removeItem(item, options.oldIdx) ) + return null; + + var unequip = this.equipsContents && (options.drop || !options.keepEquipped); + this._emitItemChange('item.lose'+(unequip ? '.unequip' : '')+(options.drop ? '.drop' : ''), item, { 'idx':idx }); + + return item; + }, + + + + /** + * @protected + * @return {Integer} Index of first empty slot in this container. + */ + _getEmptySlot : function _getEmptySlot(){ + var slots = this.slots + , max = this.max; + + if (this.size >= max) + return -1; + + for (var i=0, v=slots[i]; i Item - slots : null, // Array of positions of items in container: container idx -> Item - - - init : function initContainer(name, unit, items, options){ - this.name = name; - this.unit = unit; - Y.core.extend(this, options); - - this.items = {}; - this.slots = new Array(inv.max); - - if ( typeof this.reqs == 'string' ) - this.reqs = Y([ this.reqs ]); - - if (items) items.forEach(this.moveItem, this); - }, - - - /** - * @param {Item} [item] If present, also check whether item matches this container's requirements. - * @return {Boolean} Whether this container will accept this item. - */ - canAddItem : function canAddItem(item){ - var reqs = this.reqs; - return this.size < this.max && - ( !item || !reqs || reqs.intersect(item.tags).length === reqs.length ); - }, - - getItem : function getItem(idx){ - if (idx === undefined || idx === null || idx instanceof Item) - return idx; - else - return this.slots[idx]; - }, - - /** - * @param {Number|Item} id The Item or Item ID for which to test. - * @return {Boolean} Whether the item is in this container. - */ - hasItem : function hasItem(id){ - if (id instanceof Item) id = id.__id__; - return !!this.items[id]; - }, - - /** - * Adds an item to this container. - * @param {Item} item - * @return {this} - */ - addItem : function addItem(item){ - if ( this.hasItem(item) ) - return this; - else - return this.moveItem(item, this._getEmptySlot()); - }, - - - /** - * Changes the position of the item in this container. - * @param {Item} item Item to move. - * @param {Number} idx Index in the container to which to move item. - * @return {this} - */ - moveItem : function moveItem(item, idx){ - item = this.getItem(item); - if (!item || typeof idx != "number") - return this; - - // Make note of item we're displacing, if any - var displacedItem = this.slots[idx] - , oldIdx = item.ui.bpIdx - , newItem = !this.hasItem(item) - , evtName = 'item.move' - ; - - if ( !this._putItem(item, idx) ) - return this; - - if (newItem) - if (this.equipContents) - evtName = 'item.equip' - else - evtName = 'item.move' - - idx = item.ui.bpIdx; - this._emitItemChange(evtName, item, { 'idx':idx, 'oldIdx':oldIdx }); - - if ( displacedItem && displacedItem !== item ) { - displacedItem.ui.bpIdx = null; - this._putItem(displacedItem, oldIdx); - this._emitItemChange('item.move', displacedItem, { 'idx':displacedItem.ui.bpIdx, 'oldIdx':idx }); - } - - return this; - }, - - /** - * Removes the item from this container. - * @param {Item|Number} idx Item or container index to remove. - * @param {Boolean} [drop=false] If true, Item is dropped and not just removed from this container. - * @return {Item} The removed item. - */ - removeItem : function removeItem(idx, drop){ - var item = this.getItem(idx); - idx = item ? item.ui.bpIdx : -1; // ensures we have the index if given an Item - - // TODO: UI feedback on failure - if ( !this._removeItem(item) ) - return null; - - this._emitItemChange('item.lose'+(drop ? '.drop' : ''), item, { 'idx':idx }); - return item; - }, - - equipItem : function equipItem(slot, item){ - item = this.getItem(item); - - var inv = this.inventory - , eqs = inv.equipment; - - if ( !(slot in eqs) ) - throw new Error('Unit '+this+' does not have an equipment slot '+slot+'!'); - - if ( !(item instanceof Item) ) - throw new Error('Unit '+this+' cannot equip item '+item+'!'); - - // TODO: Ensure item has right tags for slot - var oldIdx = item.backpack; - this._removeItem(item); - - // TODO: UI feedback - if ( eqs[slot] ) - this.unequipSlot(slot, oldIdx); - - this.items[item.__id__] = item; - eqs[slot] = item; - item.slot = slot; - - return this._emitItemChange('item.equip', item, { 'slot':slot }); - }, - - unequipSlot : function unequipSlot(slot, idx){ - var inv = this.inventory - , eqs = inv.equipment - , item = eqs[slot] - ; - if (item) { - // TODO: UI feedback on failure - if ( !this._putItem(item, idx) ) - return this; - - eqs[slot] = null; - item.slot = null; - this._emitItemChange('item.unequip', item, { 'slot':slot, 'idx':idx }); - } - return this; - }, - - - - /** - * @return {Integer} Index of first empty slot in this unit's backpack. - */ - _getEmptySlot : function _getEmptySlot(){ - var slots = this.slots - , max = this.max; - - if (this.size >= max) - return -1; - - for (var i=0, v=slots[i]; i= this.max ) - return false; - - if ( this.items[id] ) - delete this.slots[ui.bpIdx]; // Already in backpack? Remove from current slot - else - this.size++; // Otherwise increment size - - this.items[id] = item; - this.slots[idx] = item; - ui.bpIdx = idx; - ui.container = this; - - return true; - }, - - - /** - * Removes item from backpack, updating metadata. - * @param {Item} item - * @return {Boolean} - */ - _removeItem : function removeItem(item){ - if (!item) return false; - - // item = this.getItem(item); - var id = item.__id__ - , ui = item.ui - , idx = ui.bpIdx - , slot = ui.equipSlot - , hasItem = !!this.items[id] - ; - - delete this.items[id]; - - if (hasItem) { - // TODO: unequip slot - item.clean(); - delete this.slots[idx]; - this.size--; - return true; - } - - return false; - }, - - - _emitItemChange : function _emitItemChange(evt, item, data){ - data = Y.extend({ 'unit':this, 'item':item }, data || {}); - this.emit(evt, item, data); - item.emit(evt, this, data); - return this; - } - - - -}); diff --git a/src/tanks/mixins/inventoried.cjs b/src/tanks/mixins/inventoried.cjs index ae2ef2f..0de4a80 100644 --- a/src/tanks/mixins/inventoried.cjs +++ b/src/tanks/mixins/inventoried.cjs @@ -29,9 +29,8 @@ Mixin.subclass('Inventoried', { }, - onCreate : function initInventoried(evt){ - var self = evt.data.instance - , clsInv = self.__class__.aggregate('inventory') + onCreate : function initInventoried(evt, self){ + var clsInv = self.__class__.aggregate('inventory') , inv = self.inventory = deepcopy(clsInv) ; inv.items = {}; @@ -262,8 +261,8 @@ Mixin.subclass('Inventoried', { _emitItemChange : function _emitItemChange(evt, item, data){ data = Y.extend({ 'unit':this, 'item':item }, data || {}); - this.emit(evt, item, data); - item.emit(evt, this, data); + this.emit(evt, item, data, item); + item.emit(evt, this, data, this); return this; }, diff --git a/src/tanks/mixins/meronomic.cjs b/src/tanks/mixins/meronomic.cjs index 73dfbab..cfec61c 100644 --- a/src/tanks/mixins/meronomic.cjs +++ b/src/tanks/mixins/meronomic.cjs @@ -6,7 +6,7 @@ Meronomic = exports['Meronomic'] = Mixin.subclass('Meronomic', { - onCreate : function initMeronomic(evt){ + onCreate : function initMeronomic(evt, self){ } diff --git a/src/tanks/mixins/quantified.cjs b/src/tanks/mixins/quantified.cjs index 453f165..b21ac8b 100644 --- a/src/tanks/mixins/quantified.cjs +++ b/src/tanks/mixins/quantified.cjs @@ -9,6 +9,7 @@ var Y = require('Y').Y Quantified = exports['Quantified'] = Mixin.subclass('Quantified', { + __bind__ : [ 'onBuffAcquired', 'onBuffLost' ], stats : {}, cooldowns : {}, @@ -16,11 +17,12 @@ Mixin.subclass('Quantified', { buffs : [], - onCreate : function initQuantified(evt){ - var self = evt.data.instance; + onCreate : function initQuantified(evt, self){ self.buffs = Y([]); - self.on('buff.conjure', self.onBuffAcquired.bind(self)); - self.on('buff.die', self.onBuffLost.bind(self)); + self.on('buff.conjure', self.onBuffAcquired); + self.on('buff.die', self.onBuffLost); + // self.on('buff.conjure', self.onBuffAcquired.bind(self)); + // self.on('buff.die', self.onBuffLost.bind(self)); }, stat : function stat(k){ diff --git a/src/tanks/thing/item.cjs b/src/tanks/thing/item.cjs index c70295c..712a68f 100644 --- a/src/tanks/thing/item.cjs +++ b/src/tanks/thing/item.cjs @@ -18,7 +18,7 @@ Item = exports['Item'] = Thing.subclass('Item', { // __mixins__ : [ ], - __bind__ : [ 'onCollide', 'onAcquired', 'onLost', 'onEquip', 'onUnequip' ], + __bind__ : [ 'onCollide', 'onAcquired', 'onLost', 'onEquip', 'onUnequip', 'onBuffDeath' ], align : 0, // 0 reserved for neutral units @@ -47,39 +47,34 @@ Thing.subclass('Item', { owner : null, // {Unit} Owner when picked up. currentBuffs : null, // {Buff...} Buffs applied to owner + isEquipped : false, - // UI Bookkeeping - inv : { - idx : null, // {Integer} Index in owner's backpack - container : null // {String} Slotname if equipped on owner - }, + // Inventory Bookkeeping + // inv : { + // links : [], // {Array} Pointers to Belts that link to this item + // idx : null, // {Integer} Index in bag + // bag : null // {Container} Containing bag + // }, init : function initItem(){ Thing.init.call(this, 0); - this.clean(); this.effects = this.effects.clone(); this.passives = this.passives.clone(); - this.activeBuffs = new Y.YArray(); - this.passiveBuffs = new Y.YArray(); + this.currentBuffs = new Y.YArray(); + this.currentActive = new Y.YArray(); + this.currentPassive = new Y.YArray(); this.activateGauge = new CooldownGauge(this.cooldowns.activate, REF_SIZE+1,REF_SIZE+1); - this.on('collide', this.onCollide); + this.on('collide', this.onCollide); this.on('item.acquire', this.onAcquired); - this.on('item.lose', this.onLost); - this.on('item.equip', this.onEquip); - }, - - /** - * Resets UI bookkeeping. - */ - clean : function clean(){ - this.inv = Y.core.map(this.inv, kNull); - return this; + this.on('item.lose', this.onLost); + this.on('item.equip', this.onEquip); + this.on('item.unequip', this.onUnequip); }, tick : function tick(elapsed, now, ticks){ @@ -103,23 +98,52 @@ Thing.subclass('Item', { console.log(this+' activated!'); if ( this.owner && this.cooldowns.activate.activate() ) { - this.currentBuffs.extend( this.effects.invoke('instantiate', this.owner) ); + var buffs = this.currentBuffs + , active = this.currentActive + ; + if ( active.length ) + active.invoke('die', 'item.reactivated'); + + var activated = this.effects.invoke('instantiate', this.owner); + activated.invoke('on', 'buff.die', this.onBuffDeath); + buffs.extend(activated); + active.extend(activated); } return this; }, - onEquip : function onEquip(){ + onBuffDeath : function onBuffDeath(evt, buff){ + this.currentBuffs.remove(buff); + this.currentActive.remove(buff); + this.currentPassive.remove(buff); + }, + + onEquip : function onEquip(evt){ console.log(this+' equipped!'); if ( this.owner ) { - // TODO: Note buffs for unequip - this.currentBuffs.extend( this.passives.invoke('instantiate', this.owner) ); + this.isEquipped = true; + var buffs = this.currentBuffs + , passive = this.currentPassive + ; + if ( passive.length ) + passive.invoke('die', 'item.reequipped'); + + var equipped = this.passives.invoke('instantiate', this.owner); + equipped.invoke('on', 'buff.die', this.onBuffDeath); + buffs.extend(equipped); + passive.extend(equipped); } + return this; }, onUnequip : function onUnequip(evt){ console.log(this+' unequipped!'); - // TODO: unequip buffs + this.isEquipped = false; + if ( this.owner ) { + this.currentPassive.invoke('die', 'item.unequipped'); + } + return this; }, // TODO: Add to correct container @@ -129,22 +153,25 @@ Thing.subclass('Item', { unit.addItem(this); }, - onAcquired : function onAcquired(evt){ + onAcquired : function onAcquired(evt, container){ this.owner = evt.data.unit; // 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){ - // if (!this.owner) return; - if ( this.currentBuffs ) - this.currentBuffs.invoke('die', 'item.lost'); - var unit = this.owner; + var current = this.currentBuffs + , unit = this.owner + ; + if ( current.length ) + current.invoke('die', 'item.lost'); + // console.log(unit+' lost '+this+'!'); this.owner = null; - // TODO: game to listen, re-add to level at unit.loc + + if ( /\blost\.drop\b/.test(evt.type) ) + unit.game.addUnit(this, unit.loc); // TODO: stop item from being instantly picked up. }, render : function render(parent){