Layer =
exports['Layer'] =
Y.subclass('Layer', {
- _cssClasses : 'ezl layer',
+ /// Class Defaults ///
+
+ // _layer* is applied to this.layer (the DOM Element)
+ _layerHtml : '<div/>', // HTML that will become the layer
+ _layerId : null, // HTML id attribute
+ _layerAttrs : null, // HTML attributes
+ _layerClasses : 'ezl layer',// CSS classes
+
+ originX : 0,
+ originY : 0,
+
+ hasCanvas : true, // Whether to create a canvas
+ useCanvasScaling : false, // Default to CSS3 scaling
+ alwaysClearDrawing : true, // Whether to clear the canvas content before redraw
+ alwaysClearAttrs : false, // Whether to remove all canvas attributes (CONTEXT_ATTRS)
+ // and transforms (scale, rotate, translate) and reset defaults before redraw
+
+
+
+ /// State ///
canvas : null,
parent : null,
_origin : null, // rotational origin
transform : null, // Object
- /// Defaults ///
-
- hasCanvas : true, // Whether to create a canvas
- useCanvasScaling : false, // Default to CSS3 scaling
- alwaysClearDrawing : true, // Whether to clear the canvas content before redraw
- alwaysClearAttrs : false, // Whether to remove all canvas attributes (CONTEXT_ATTRS)
- // and transforms (scale, rotate, translate) and reset defaults before redraw
-
- originX : 0,
- originY : 0,
-
-
/// Setup ///
init : function init(props, attrs, html){
- if (props)
- Y.core.extend(this, props);
+ if (props !== undefined && props !== null) {
+ switch (typeof props) {
+ case 'boolean' : this.hasCanvas = props; break;
+ case 'string' : this._layerHtml = props; break;
+ case 'object' : Y.core.extend(this, props); break;
+ }
+ }
this.children = new Y.YArray();
this.animActive = new Y.YArray();
translate : new Loc(0,0) // translates canvas
};
- this.layer = jQuery(html || '<div/>')
- .addClass(this._cssClasses)
+ this.layer = jQuery(html || this._layerHtml)
+ .addClass(this._layerClasses)
.data('layer', this);
this.layer[0].layer = this;
- if (attrs) this.layer.attr(attrs);
+
+ if (this._layerAttrs) this.layer.attr(this._layerAttrs);
+ if (this._layerId) this.layer.attr('id', this._layerId);
+ if (attrs) this.layer.attr(attrs);
if (this.hasCanvas) {
this.canvas = jQuery('<canvas />')
Polygon =
exports['Polygon'] =
Shape.subclass('Polygon', {
- _cssClasses : 'ezl layer shape polygon',
+ _layerClasses : 'ezl layer shape polygon',
/**
* Expects two arrays of coordinate-halfs, which could be zipped
Triangle =
exports['Triangle'] =
Polygon.subclass('Triangle', {
- _cssClasses : 'ezl layer shape polygon triangle',
+ _layerClasses : 'ezl layer shape polygon triangle',
init : function initTriangle(x1,y1, x2,y2){
Polygon.init.call(this, [x1,x2], [y1,y2]);
Quad =
exports['Quad'] =
Polygon.subclass('Quad', {
- _cssClasses : 'ezl layer shape polygon quad',
+ _layerClasses : 'ezl layer shape polygon quad',
init : function initQuad(x1,y1, x2,y2, x3,y3){
Polygon.init.call(this, [x1,x2,x3], [y1,y2,y3]);
--- /dev/null
+var Y = require('Y').Y
+, op = require('Y/op')
+, deepcopy = require('Y/types/object').deepcopy
+
+, evt = require('evt')
+, Item = require('tanks/thing/item').Item
+
+, kNull = op.K(null)
+,
+
+Container =
+exports['Container'] =
+evt.subclass('Container', {
+ __bind__ : [],
+
+ name : null, // Name of this container
+ max : 1, // Container capacity
+ reqs : null, // Array of tag requirements to be stored here
+ equips : false, // Whether held items are equipped
+
+ size : 0, // Number of items in container
+ items : null, // item id -> 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);
+ },
+
+
+ /**
+ * @return {Boolean} Whether this container will accept this item.
+ */
+ canAddItem : function canAddItem(item){
+ return this.size < this.max && ( !item || !this.reqs || this.reqs.intersect(item.tags) );
+ },
+
+ getItem : function getItem(idx){
+ if (idx === undefined || idx === null)
+ return idx;
+ if (idx instanceof Item)
+ return idx;
+ else
+ return this.slots[idx];
+ },
+
+ hasItem : function hasItem(id){
+ if (id instanceof Item) id = id.__id__;
+ return !!this.items[id];
+ },
+
+
+
+ /**
+ * @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<max; v=slots[++i])
+ if (v === undefined)
+ return i;
+
+ return -1;
+ },
+
+
+ /**
+ * Inserts item into backpack at index, updating metadata.
+ * @protected
+ * @param {Item} item
+ * @param {Number} [idx] Backpack position at which to insert item. If missing, first open slot will be used.
+ * @return {Boolean}
+ */
+ _putItem : function putItem(item, idx){
+ if (!item) return false;
+
+ // item = this.getItem(item);
+ var slots = this.slots
+ , idx = ( (typeof idx == "number") ? idx : this.getEmptySlot() )
+
+ , id = item.__id__
+ , ui = item.ui
+ ;
+
+ // Backpack bounds check
+ if ( idx < 0 || idx >= this.max )
+ return false;
+
+ if ( this.items[id] )
+ delete slots[ui.bpIdx]; // Already in backpack? Remove from current slot
+ else
+ this.size++; // Otherwise increment size
+
+ slots[idx] = item;
+ ui.bpIdx = idx;
+ this.items[id] = item;
+
+ 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;
+ },
+
+
+ _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;
+ },
+
+ // TODO: update UI; UI to inform item on activation
+ /**
+ * @param {Item} item
+ * @return {this}
+ */
+ addItem : function addItem(item){
+ if ( this.hasItem(item) )
+ return this;
+
+ item = this.getItem(item);
+ var idx = this.getEmptySlot();
+
+ // TODO: UI feedback on failure
+ if ( !this._putItem(item, idx) )
+ return this;
+
+ return this._fireItemChange('item.acquire', item, { 'idx':idx });
+ },
+
+ 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
+ ;
+
+ if ( !this._putItem(item, idx) )
+ return this;
+
+ idx = item.ui.bpIdx;
+ this._fireItemChange('item.move', item, { 'idx':idx, 'oldIdx':oldIdx });
+
+ if ( displacedItem && displacedItem !== item ) {
+ displacedItem.ui.bpIdx = null;
+ this._putItem(displacedItem, oldIdx);
+ this._fireItemChange('item.move', displacedItem, { 'idx':displacedItem.ui.bpIdx, 'oldIdx':idx });
+ }
+
+ return true;
+ },
+
+ 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, { 'idx':idx });
+ return item;
+ },
+
+ dropItem : function dropItem(idx){
+ item = this.getItem(item);
+ var idx = item ? item.ui.bpIdx : -1;
+
+ // TODO: UI feedback on failure
+ if ( this._removeItem(item) )
+ return this;
+
+ this._fireItemChange('item.lose.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._fireItemChange('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._fireItemChange('item.unequip', item, { 'slot':slot, 'idx':idx });
+ }
+ return this;
+ }
+
+
+
+
+});