dodge : 1.00 # dodge an incoming bullet
shootIncoming : 0.25 # shoot down incoming bullet
shootEnemy : 0.75 # shoot at enemy tank if in range
+ barrel:
+ width : unit.width * 0.75
+ height : unit.height / 6
+ originX : 2
+ originY : 50%
+ x : 50%
+ y : 50%
art:
map_icon: ''
inv_icon: ''
}
Y.extend( exports, { 'repeat':repeat, 'setupRepeater':setupRepeater });
-Y.extend( Y['event'], exports );
+Y['polyevent'] = exports;
+
+Y.extend( Y['event'], { 'PolyEmitter':PolyEmitter, 'PolyEvent':PolyEvent, 'repeat':repeat, 'setupRepeater':setupRepeater });
K : function(k){ return function(){ return k; }; },
kObject : function(){ return {}; },
kArray : function(){ return []; },
+ kThis : function(){ return this; },
val : function(def,o){ return o !== undefined ? o : def; },
ok : function(o){ return o !== undefined && o !== null; },
first : function(a){ return a; },
this['unique'] =
function unique(){
- return this.reduce(
+ return new YArray( this._o.reduce(
function(acc, v, i){
if (acc.indexOf(v) === -1)
acc.push(v);
return acc;
- }, new YArray(), this);
+ }, [], this) );
};
YArray.flatten = flatten;
}, new this.__class__() );
},
- amap : function amap( fn ){
+ 'amap' : function amap( fn ){
var cxt = arguments[1] || this;
return this.reduce(function(acc, v, k, o){
return acc.push(fn.call(cxt, v, k, o));
return -1;
},
+ 'lastIndexOf' : function lastIndexOf( value ){
+ var o = this._o
+ , idx = -1;
+ for ( var name in o )
+ if ( o[name] === value )
+ idx = name;
+ return idx;
+ },
+
'has' : function has( value ){
return ( this.indexOf(value) !== -1 );
},
}, true);
},
- 'any' : function any( fn ){
+ 'some' : function some( fn ){
var self = this, fn = fn || op.bool;
return this.reduce(function(acc, v, k, o){
return acc || fn.call(self, v, k, o);
'intersect' : function intersect(a){
var A = Y(a);
return this.filter(A.has, A);
- }
+ },
+
+ // /**
+ // * Set Union (A v B)
+ // * @param {Array|Object|YCollection} a Comparison collection.
+ // * @return {YArray} A new YArray of all elements in both collections, but without duplicates.
+ // */
+ // 'union' : function union(a){
+ // return this.clone().extend(a).unique();
+ // },
+ //
+ // /**
+ // * Set Difference (A - B)
+ // * @param {Array|Object|YCollection} a Comparison collection.
+ // * @return {YArray} A new YArray of only elements in this not in supplied collection.
+ // */
+ // 'difference' : function difference(a){
+ // var A = Y(a);
+ // return this.filter(Y(A.has).compose(op.not), A);
+ // },
+ //
+ // // Symmetric Difference
+ // 'xor' : function xor(a){
+ // return this.difference(a).extend( Y(a).difference(this) );
+ // }
});
// TODO: Throw errors on invalid values
- if (isFunction(target)) target = target.prototype;
- if (isFunction(donor)) donor = donor.prototype;
- if (!isArray(names)) names = [names];
+ if (typeof target == 'function') target = target.prototype;
+ if (typeof donor == 'function') donor = donor.prototype;
+ if (!isArray(names)) names = [names];
// Need a closure to capture the name
names.forEach(function(name){
var fn = donor[name];
- if ( !(isFunction(fn) && (o.override || !(name in target))) )
+ if ( !(typeof fn == 'function' && (o.override || !(name in target))) )
return;
- target[name] = function(){
+ var wrapper = target[name] = function(){
var A = arguments, r, context;
if (o.fnFirst)
r = fn.apply(context, A);
return (o.chain ? this : (o.wrap ? o.wrap(r) : r));
};
+ wrapper.name = name; // works in webkit
});
return o;
CONTEXT_ATTRS = Y('globalAlpha globalCompositeOperation strokeStyle fillStyle lineWidth lineCap lineJoin miterLimit shadowOffsetX shadowOffsetY shadowBlur shadowColor'.split(' ')),
FAUX_ACCESSORS = Y('width height position stroke fill origin rotate scale translate title'.split(' '))
, _X = 0, _Y = 1
+, CALC_LOC = new Loc(0,0)
,
if (x === null || x === undefined) x = bb.x1;
if (y === null || y === undefined) y = bb.y1;
- var bb = this.bbox;
+ var p = this.parent
+ , bb = this.bbox
+ , sx = (typeof x == 'string') // TODO: store and recalc on w/h change
+ , sy = (typeof y == 'string')
+ ;
+ if (sx || sy) {
+ if (!p) return this;
+ var xy = CALC_LOC.setXY(x,y).absolute(p.realWidth, p.realHeight);
+ x = xy.x;
+ y = xy.y;
+ }
+
if (x === bb.x1 && y === bb.y1)
return this;
--- /dev/null
+var Y = require('Y').Y
+, op = require('Y/op')
+, proxy = require('Y/utils').proxy
+, YCollection = require('Y/types/collection').YCollection
+, slice = Array.prototype.slice
+,
+
+
+Set =
+exports['Set'] =
+YCollection.subclass('Set', null, function setupSet(Set){
+ Y.extend(this, {
+ _byId : {},
+ });
+
+ this['init'] =
+ function initSet(){
+ this._o = new Y.YArray();
+ this._byId = {};
+ if ( arguments.length )
+ this.update( arguments );
+ };
+
+ var size =
+ this['size'] =
+ function size(){
+ return this._o.length;
+ };
+
+ this['attr'] = op.attr.methodize();
+ Object.defineProperty(this, 'length', { 'get':size });
+
+ this['clone'] =
+ function clone(){
+ return new Set(this._o);
+ };
+
+ this['clear'] =
+ function clear(){
+ this._o = new Y.YArray();
+ this._byId = {};
+ return this;
+ };
+
+ this['indexOf'] =
+ this['lastIndexOf'] =
+ function unsupported(){
+ throw new Error(arguments.callee.name+' is unsupported for type '+this.className+'!');
+ };
+
+ function _getIdSafe(v){
+ switch (typeof v) {
+ case 'undefined':
+ return undefined;
+ break;
+
+ case 'boolean':
+ case 'string':
+ case 'number':
+ return v;
+ break;
+
+ case 'object':
+ case 'function':
+ default:
+ if ( !('__id__' in v) )
+ return undefined;
+ else
+ return v.__id__;
+ break;
+ }
+ }
+
+ this['_getId'] =
+ function _getId(v){
+ var id = _getIdSafe(v);
+ if (id === undefined)
+ throw new Error('All Set elements must be hashable! v='+v);
+ else
+ return id;
+ };
+
+ this['has'] =
+ function has(v){
+ return (_getIdSafe(v) in this._byId);
+ };
+
+ function addIt(v){
+ var id = this._getId(v);
+
+ if (!(id in this._byId)) {
+ this._byId[id] = v;
+ this._o.push(v);
+ }
+
+ return this;
+ }
+
+ this['add'] =
+ this['push'] =
+ this['unshift'] =
+ function add(v){
+ var L = arguments.length;
+
+ if (L === 1)
+ addIt.call(this, v);
+ else if (L > 1)
+ slice.call(arguments,0).forEach(addIt, this);
+
+ return this;
+ };
+
+ this['update'] =
+ this['extend'] =
+ function update(vs){
+ Y(vs).forEach(addIt, this);
+ return this;
+ };
+
+ this['join'] =
+ function join(vs){
+ return this.clone().update(vs);
+ };
+
+ function removeIt(v){
+ var id = this._getId(v);
+
+ if ( id in this._byId ) {
+ delete this._byId[id];
+ this._o.splice(this._o.indexOf(v), 1);
+ }
+
+ return this;
+ }
+
+ this['remove'] =
+ this['discard'] =
+ function remove(v){
+ var L = arguments.length;
+
+ if (L === 1)
+ removeIt.call(this, v);
+ else if (L > 1)
+ slice.call(arguments,0).forEach(removeIt, this);
+
+ return this;
+ };
+
+ this['shift'] =
+ this['pop'] =
+ function shift(){
+ if (!this._o.length) return;
+
+ var v = this._o.shift()
+ , id = this._getId(v);
+ delete this._byId[id];
+ return v;
+ };
+
+ this['unique'] = op.kThis;
+
+ /**
+ * Tests if `a` is a Collection and has all elements in common with the set.
+ * Sets are equal if and only if their intersection has the same size as both sets.
+ * @param {Collection} a
+ * @return {Boolean}
+ */
+ this['equals'] =
+ function equals(a){
+ if (!a) return false;
+ var L = this._o.length;
+ return (L === a.length) && (L === this.intersect(a).length);
+ };
+
+ /**
+ * Tests if the set has no elements in common with `a`.
+ * Sets are disjoint if and only if their intersection is the empty set.
+ * @param {Collection} a
+ * @return {Boolean}
+ */
+ this['isDisjoint'] =
+ function isDisjoint(a){
+ if (!a) return true;
+ return !Y(a).some(this.has, this);
+ };
+
+ /**
+ * Test whether every element in the set is in `a`.
+ * @param {Collection} a
+ * @return {Boolean}
+ */
+ this['isSubset'] =
+ function isSubset(a){
+ if (!a) return false;
+ var A = Y(a);
+ return this.every(A.has, A);
+ };
+
+ /**
+ * Test whether every element in `a` is in the set.
+ * @param {Collection} a
+ * @return {Boolean}
+ */
+ this['isSuperset'] =
+ function isSuperset(a){
+ if (!a) return false;
+ return Y(a).every(this.has, this);
+ };
+
+ this['toString'] = function(){
+ return "Set(["+this._o+"])";
+ };
+
+});
+
+var YArray = Y.YArray
+, newSet = Set.instantiate;
+
+proxy({ target:Set, donor:YArray, context:'_o',
+ names:['sort', 'zip'] });
+proxy({ target:Set, donor:YArray, context:'_o', wrap:newSet,
+ names:['concat'] });
+proxy({ target:Set, donor:YArray, context:'_o', fnFirst:true, wrap:newSet,
+ names:'map forEach filter intersect union difference xor'.split(' ') });
+proxy({ target:Set, donor:YArray, context:'_o', fnFirst:true,
+ names:'reduce some every'.split(' ') });
_inSubrange : function _inSubrange(x1,y1, x2,y2){
if (arguments.length === 4)
- return this._ranges.invoke('containsRange', x1,y1, x2,y2).any();
+ return this._ranges.invoke('containsRange', x1,y1, x2,y2).some();
else
- return this._ranges.invoke('contains', x1,y1).any();
+ return this._ranges.invoke('contains', x1,y1).some();
},
// XXX: Hm. Should this be contains ALL or contains ANY for the range query?
*/
canAddItem : function canAddItem(item, bag){
if (bag === undefined)
- return this._bags.invoke('canAddItem', item).any();
+ return this._bags.invoke('canAddItem', item).some();
bag = this.getBag(bag);
return bag && bag.canAddItem(item);
},
attack : function attack(x,y){
if ( x === undefined || y === undefined ) {
- var theta = this.barrel.transform.rotate
+ var theta = this.barrelShape.transform.rotate
, sin = Math.sin(theta), cos = Math.cos(theta)
, t = this.getTurretLoc();
x = t.x + REF_SIZE*cos;
, constants = require('tanks/constants')
, BoundsType = constants.BoundsType
, DensityType = constants.DensityType
-, LinearTrajectory = require('tanks/map/pathing/linear-trajectory').LinearTrajectory
+, LinearTrajectory = require('tanks/map/pathing/linear-trajectory').LinearTrajectory
, Traversal = require('tanks/map/pathing/traversal').Traversal
, Thing = require('tanks/thing/thing').Thing
, Bullet = require('tanks/thing/bullet').Bullet
, Lootable = require('tanks/mixins/lootable').Lootable
+, Barrel = require('tanks/fx/barrel').Barrel
, _X = 0, _Y = 1
,
barrel : '#D43B24'
},
+ barrel: {
+ width : 'unit.width * 0.75',
+ height : 'unit.height / 6',
+ originX : 2,
+ originY : '50%',
+ x : '50%',
+ y : '50%'
+ },
+
// Bounding box
width : REF_SIZE*0.55,
height : REF_SIZE*0.55,
return null; // console.log('squelch!', blockers);
if (!xydef) {
- var theta = this.barrel.transform.rotate
+ var theta = this.barrelShape.transform.rotate
, sin = Math.sin(theta), cos = Math.cos(theta);
x = tx + REF_SIZE*cos;
y = ty + REF_SIZE*sin;
function getTurretLoc(){
var WIGGLE = 2
, loc = this.loc
- , barrel = this.barrel
+ , barrel = this.barrelShape
, theta = barrel.transform.rotate
, sin = Math.sin(theta), cos = Math.cos(theta)
var colors = this.colors
, w = this.width, w2 = w/2
, h = this.height, h2 = h/2
-
, r = w / 4
- , bw = w * 0.75
- , bh = h / 6
;
this.shape =
.fill(colors.turret)
.appendTo( this.shape ) ;
- this.barrel =
- new Rect(bw,bh)
- .position(w2-2, h2-bh/2)
- .origin(2, bh/2)
- .fill(colors.barrel)
- .appendTo( this.shape ) ;
+ var b = Y.map(this.barrel, calcValue, this);
+
+ this.barrelShape =
+ new Barrel(b.width,b.height, b.originX,b.originY)
+ .appendTo( this.shape ) // have to append early to avoid problems with relative positioning
+ .position(b.x, b.y)
+ // .position(w2-2, h2-bh/2)
+ // .origin(2, bh/2)
+ .fill( colors.barrel ) ;
return this;
};
this['rotateBarrel'] =
function rotateBarrel(x,y){
- this.barrel.rotate(this.angleTo(x,y));
+ this.barrelShape.rotate(this.angleTo(x,y));
return this;
};
, y = off.top + h/2 - pageY
, theta = Math.atan2(-y,-x)
;
- this.barrel.rotate(theta);
+ this.barrelShape.rotate(theta);
return this;
};
});
+var NUM_OR_PERCENT = /^\s*[\d\.]+\s*%?\s*$/;
+function calcValue(v){
+ var unit = this;
+ return ( NUM_OR_PERCENT.test(v) ? v : eval(v) );
+}
+