var
/**
- * Everybody's favourite party metaclass!
- */
-Mixin =
-exports['Mixin'] =
-Y.subclass('Mixin', {
- __mixin_skip__ : [ 'mixIntoClass' ],
-
-
-
- /**
- * Mixes this Mixin into another Class.
- */
- mixIntoClass : function mixIntoClass(cls){
-
- },
-
-})
-,
-
-
-/**
* Root-class for all Y-objects.
*/
YBase = new Class("YBase", {
* @return {Object} A.
*/
function accessors(A, B){
- if ( !(A && typeof A === "object") )
+ var t = typeof A;
+ if ( !(A && (t === "object" || t === "function")) )
return A;
if (arguments.length < 2)
* @return {Object} A.
*/
function descriptors(A, B){
- if ( !(A && typeof A === "object") )
+ var t = typeof A;
+ if ( !(A && (t === "object" || t === "function")) )
return A;
if (arguments.length < 2)
function attrvk(o, v, k){ return attr(o, k, v, o[k]); }
function accessors(A, B){
- if ( !(A && typeof A === "object") )
+ var t = typeof A;
+ if ( !(A && (t === "object" || t === "function")) )
return A;
if ( notWrapped(A.accessors) )
}
function descriptors(A,B){
- if ( !(A && typeof A === "object") )
+ var t = typeof A;
+ if ( !(A && (t === "object" || t === "function")) )
return A;
if ( notWrapped(A.descriptors) )
addNames('curry methodize genericize compose chain memoize', yfn);
// Curry all operators
-var op = require('Y/op');
-Y['op'] =
+var op = Y['op'] = require('Y/op');
op['curried'] =
core.reduce(op, function(Yop, fn, k){
Yop[k] = YFunction(fn).curry();
require('Y/types/object'));
addNames('YString', require('Y/types/string'));
addNames('YNumber range', require('Y/types/number'));
-
-var utils = require('Y/utils');
-Y['bindAll'] = utils.bindAll;
+addNames('bindAll', require('Y/utils'));
function addName(name){ Y[name] = this[name]; }
function addNames(names, ns){ names.split(' ').forEach(addName, ns); }
//#ensure "jquery"
-var Y = require('Y').Y
-, Emitter = require('Y/modules/y.event').Emitter
-, op = Y.op
+var Y = require('Y').Y
+, parseBool = require('Y/op').parseBool
+, Emitter = require('Y/modules/y.event').Emitter
, upperPat = /^[A-Z]+$/
,
type2parser = {
- 'Boolean' : op.parseBool,
+ 'Boolean' : parseBool,
'Number' : parseFloat,
'String' : String
}
zrshift : function(x,y){ return x >>> y; },
// values
- nop : function(x){},
+ nop : function(){},
I : function(x){ return x; },
K : function(k){ return function(){ return k; }; },
nth : function(n){ return function(){ return arguments[n]; }; },
Object.defineProperty(this, 'length', { 'get':size });
// Convenience getters for index 0-9
- var thisget = op.thisget
- , thiskvset = op.thiskvset ;
- for (var i=0; i<10; i++)
- Object.defineProperty(this, i, {
- 'get' : thisget.partial(i),
- 'set' : thiskvset.partial(i)
- });
+ // var thisget = op.thisget
+ // , thiskvset = op.thiskvset ;
+ // for (var i=0; i<10; i++)
+ // Object.defineProperty(this, i, {
+ // 'get' : thisget.partial(i),
+ // 'set' : thiskvset.partial(i)
+ // });
- this['toString'] =
- function toString(){
+ this['toString'] = function(){
return "Y[" + arrayToString.call(this._o) + "]";
};
function extendY(){
- del.extend.apply(this, [this._o].concat(slice.call(arguments)));
+ del.extend.apply(this, [this._o].concat(slice.call(arguments,0)));
return this;
}
return r;
},
+ 'extend' : extendY,
+
/**
* Removes all instances of the given values from the collection.
*
*/
var Y = require('Y').Y
+, core = require('Y/core')
, Emitter = require('Y/modules/y.event').Emitter
, unwrap = require('Y/types/function').unwrap
, objToString = _Object[P].toString
, classToString = function toString(){ return this.className+"()"; }
+, classMagic = [ '__static__', '__mixins__', '__emitter__', '__bases__', '__initialise__' ]
+, mixinSkip = [ '__mixin_skip__', 'onMixin', 'onInit', 'init' ].concat(classMagic)
,
/**
* @private
* Private delegating constructor. This function must be redefined for every
- * new class to prevent shared state. All construction is actually done in
- * the methods initialise and init.
+ * new class to prevent shared state.
*
* Fires `create` event prior to initialisation if not subclassing.
+ *
+ * Fires `init` event after calling init(). nb. init() is fired
+ * for proper instances of the class, and instances of subclasses (but
+ * not for the instance created when subclassing).
*/
ConstructorTemplate =
exports['ConstructorTemplate'] =
function ConstructorTemplate() {
- var cls = arguments.callee
- , instance = this;
+ var k, v
+ , cls = arguments.callee
+ , instance = this
+ ;
// Not subclassing
if ( unwrap(cls.caller) !== Y.fabricate ) {
+ // Perform actions that should only happen once in Constructor
+ instance.__emitter__ = new Emitter(instance, cls);
+
cls.fire('create', instance, {
'instance' : instance,
'cls' : cls,
'args' : Y(arguments)
});
- if ( instance.initialise )
- return instance.initialise.apply(instance, arguments);
+ var initialise = instance.__initialise__;
+ if ( isFunction(initialise) )
+ return initialise.apply(instance, arguments);
}
return instance;
,
/**
- * Fires `init` event after calling init(). Note that events are fired
- * for proper instances of the class and instances of subclasses (but
- * not for the instance created when subclassing).
+ * Class must be captured in a closure so we can dispatch events correctly both
+ * on a new instance and off a call from a subclass by invoking
+ * MyClass.init.apply(instance, args).
*/
createInitialise =
exports['createInitialise'] =
-function createInitialise(NewClass){
+function createInitialise(cls){
function initialise(){
var instance = this
- , init = NewClass.prototype.init
+ , binds = cls.fn.__bind__ // list of names to bind
;
- instance.__emitter__ = new Emitter(instance, NewClass);
+ if (binds)
+ Y.bindAll(instance, binds);
- if (init) {
+ var init = cls.fn.init;
+ if ( isFunction(init) ) {
var result = init.apply(instance, arguments);
- if (result) instance = result;
+ if (result) instance = result; // XXX: I think this needs to go away
}
instance.fire('init', instance, {
'instance' : instance,
- 'cls' : NewClass,
+ 'cls' : cls,
'args' : Y(arguments)
});
return instance;
}
return Y(initialise);
-}
-;
+};
+function notClassMagic(v, k){
+ return classMagic.indexOf(k) === -1;
+}
NewClass.prototype = NewClass.fn = prototype;
// Fix Constructors
- NewClass.__super__ = SuperClass; // don't override NewClass.constructor -- it should be Function
+ NewClass.__super__ = SuperClass; // don't override NewClass.constructor -- it should be Function
+ NewClass.__bases__ = NewClass.fn.__bases__ = [SuperClass].concat( SuperClass.__bases__ || [ Class, Object ] );
prototype.constructor = prototype.__class__ = NewClass;
- NewClass.init = prototype.initialise = createInitialise(NewClass);
+ NewClass.init = prototype.__initialise__ = createInitialise(NewClass);
// Add class emitter
var ParentEmitter = (Parent.__emitter__ ? Parent : ClassFactory)
, ClassEmitter = NewClass.__emitter__ = new Emitter(NewClass, ParentEmitter)
;
+ // Record for metaprogramming
+ KNOWN_CLASSES[className] = NewClass;
+
// Either invoke body constructor...
if ( isFunction(members) ) {
members.call(prototype, NewClass);
// Or add new instance methods
- } else for (var k in members) {
- if ( hasOwn.call(members, k) )
- setDesc(prototype, k, getDesc(members,k));
+ } else {
+ var mixins = members.__mixins__
+ , statics = members.__static__
+ ;
+
+ if (mixins && hasOwn.call(members,'__mixins__'))
+ mixin(NewClass, mixins);
+
+ if (statics)
+ core.descriptors( NewClass, core.filter(statics, notClassMagic) );
+
+ core.descriptors( prototype, core.filter(members, notClassMagic) );
+ // for (var k in members) {
+ // if ( hasOwn.call(members,k) && classMagic.indexOf(k) === -1 )
+ // setDesc(prototype, k, getDesc(members,k));
+ // }
+
+ NewClass.__super__ = SuperClass;
+ prototype.constructor = prototype.__class__ = NewClass;
}
- // Record for metaprogramming
- KNOWN_CLASSES[className] = NewClass;
// Notify parent of the subclass
ParentEmitter.fire('subclass',
Class.__emitter__ = new Emitter(Class);
Class.fn = Class.prototype;
Class.fn.__class__ = Class.fn.constructor = Class;
+Class.fn.__bases__ = Class.__bases__ = [ Object ];
Class.className = Class.fn.className = "Class";
/* Class Methods */
});
+function lookupClass(name){
+ return (typeof name === "function") ? name : KNOWN_CLASSES[name];
+}
+
+var
+
+/**
+ * Everybody's favourite party metaclass!
+ */
+Mixin =
+exports['Mixin'] =
+new Class('Mixin', Class, {
+
+ /**
+ * Keys to be skipped by mixIntoClass()
+ */
+ __mixin_skip__ : mixinSkip,
+
+ __mixin_skip : function __mixin_skip(k){
+ var skip = this.__mixin_skip__;
+ return !hasOwn.call(this,k) || (skip && skip.indexOf(k) !== -1);
+ },
+
+ __static__ : {
+ mixInto : function mixIntoClass(cls){
+ var mxn = this;
+ return mixin(cls, mxn);
+ }
+ }
+
+})
+,
+
+/**
+ * Mixes a Mixin into another Class.
+ */
+mixin =
+exports['mixin'] =
+function mixin(cls, mxn){
+ var proto = cls.fn
+ , mxns = (Y.isArray(mxn) ? mxn : Y(arguments, 1))
+ ;
+ mxns.forEach(function(mxn){
+ mxn = (typeof mxn === "string") ? lookupClass(mxn) : mxn;
+
+ if ( !mxn )
+ throw new Error('Cannot mix in non-object! '+mxn);
+
+ var mproto = (typeof mxn === "function") ? mxn.fn : mxn
+ , bases = cls.__bases__
+ , statics = mproto.__static__
+ , onInit = mproto.onInit
+ ;
+
+ core.extend(proto, core.filter(mproto, mproto.__mixin_skip, mproto));
+
+ if (bases)
+ bases.push(mxn);
+
+ // Add mixin statics to class constructor
+ if (statics)
+ core.extend(cls, statics);
+
+ // Register onInit to fire whenever a new instance is initialized
+ if ( hasOwn.call(mproto,'onInit') && isFunction(onInit) )
+ cls.addEventListener('init', onInit);
+
+ // Fire the mixin event on this Mixin
+ if (mxn instanceof Mixin)
+ mxn.fire('mixin', cls, { 'mixin':mxn, 'into':cls });
+ });
+ return cls;
+}
+;
+
+Mixin.addEventListener('subclass',
+ function onMixinSubclass(evt){
+ var d = evt.data
+ , mxn = d.child
+ , members = d.members
+ , onMixin = members.onMixin
+ ;
+
+ if ( hasOwn.call(members,'onMixin') && isFunction(onMixin) )
+ mxn.addEventListener('mixin', onMixin);
+ });
+
+
// Expose
exports['Class'] =
exports['subclass'] = Class;
exports['instantiate'] = instantiate;
exports['fabricate'] = Y.fabricate;
-
+exports['lookupClass'] = lookupClass;
//#ensure "jquery"
var Y = require('Y').Y
+, op = require('Y/op')
, Vec = require('ezl/math/vec').Vec
, Loc = require('ezl/loc/loc').Loc
, BoundingBox = require('ezl/loc/boundingbox').BoundingBox
return anim.tick(elapsed, now);
});
- var childrenRunning = this.children.invoke('tick', elapsed, now).some(Y.op.I)
+ var childrenRunning = this.children.invoke('tick', elapsed, now).some(op.I)
, running = !!this.animActive.length;
if ( !running && this.animQueue.length )
this.animActive.push( this.animQueue.shift().start(now) );
/// Misc ///
- toString : function toString(){
+ toString : function(){
var pos = ((this.layer && this.layer.parent()[0]) ? this.position() : {top:NaN, left:NaN});
return this.className+'['+pos.left+','+pos.top+']( children='+this.children.size()+' )';
}
, 'y' : Y.isNumber(y) ? y+units : y };
},
- toString : function toString(){
+ toString : function(){
var x = this.x, y = this.y;
x = Y.isNumber(x) ? x.toFixed(2) : x;
y = Y.isNumber(y) ? y.toFixed(2) : y;
//#ensure "Y/modules/y.event"
var Y = require('Y').Y
+, op = require('Y/op')
, Emitter = require('Y/modules/y.event').Emitter
, MIN_TICK_INTERVAL = 0 // ms
},
fps : function fps(){
- return 1000 / (this.times.reduce(Y.op.add,0) / this.times.length);
+ return 1000 / (this.times.reduce(op.add,0) / this.times.length);
},
frametime : function frametime(){
- return (this.realtimes.reduce(Y.op.add,0) / this.realtimes.length);
+ return (this.realtimes.reduce(op.add,0) / this.realtimes.length);
}
})
return new Line(x1,y1, x2,y2, this.tdist);
},
- toString : function toString(){
+ toString : function(){
return '['+this.p1+', '+this.p2+', slope='+this.slope.toFixed(3)+']';
}
return new this.__class__(this[X1],this[Y1], this[X2],this[Y2]);
},
- toString : function toString(){
+ toString : function(){
return '['+this.p1+' '+this.p2+']';
}
});
return new this.__class__(this[_X],this[_Y]);
},
- toString : function toString(){
+ toString : function(){
var p = 2, x = this[_X], y = this[_Y];
x = ((x % 1 !== 0) ? x.toFixed(p) : x);
y = ((y % 1 !== 0) ? y.toFixed(p) : y);
_Object['defineProperty'] =
function defineProperty(o, prop, desc){
- if (typeof o !== "object" || o === null)
+ var t = typeof o;
+ if (o === null || !(t === "object" || t === "function"))
throw new TypeError("Object.defineProperty called on non-object: "+o);
desc = cleanDescriptor(desc);
_Object['defineProperties'] =
function defineProperties(o, props) {
- if (typeof o !== "object" || o === null)
+ var t = typeof o;
+ if (o === null || !(t === "object" || t === "function"))
throw new TypeError("Object.defineProperty called on non-object: "+o);
props = Object(props);
//#exports PathingType.{PASSABLE,ZONE,BLOCKING,IRREGULAR}
//#exports StatInvariant.{NONE,RATIO,FULL}
+
require('Y').Y.extend(exports, {
/// Pathing Constants ///
stacked : 1,
threat : 1
},
- stat_mods : {}, // {stat : Number|Function} Modifications to stats
+ stat_mods : {}, // {stat : Number|Function} Modifications to stats // TODO: functions
+ // effects : [], // {Function...} Effects to trigger on affect // XXX: not sure why i need this...
// triggers : {}, // {event : Effect} // maybe
- // effects : [], // {Function...} Effects to trigger on affect // not sure why i need this
/// Instance ///
owner : null, // Agent which originated the buff
return this.applyStatMods(-1);
}
- // XXX: toString implemented by Informative?
+ // XXX: toString implemented by Informative
})
Y.subclass('Stat', {
// __mixins__: [ Informative, Speciated, Meronomic, Usable ], // Configurable?
- integer : true, // if true, current value is rounded after a change
+ integer : false, // if true, current value is rounded after a change
base : 0,
val : 0,
max : 0,
- init : function initStat(base, val, max, isFloat){
+ init : function initStat(base, val, max, isInteger){
this.base = base;
this.val = val !== undefined ? val : base;
this.max = max !== undefined ? max : base;
- this.integer = !isFloat;
+ this.integer = !!isInteger;
},
clone : function clone(){
- return new Stat(this.base, this.val, this.max, !this.integer);
+ return new Stat(this.base, this.val, this.max, this.integer);
},
/**
function fromValue(v){
if ( v instanceof Stat )
return v.clone();
- else if ( Y.isArray(v) )
+ else if ( v instanceof Array )
return new Stat(v[0], v[1], v[2], v[3]);
else
return new Stat(v);
var Y = require('Y').Y
+, op = require('Y/op')
+
, Rect = require('ezl/shape').Rect
+
, Thing = require('tanks/thing/thing').Thing
, Tank = require('tanks/thing/tank').Tank
, Item = require('tanks/thing/item').Item
return wall;
},
- render : Y.op.nop
+ render : op.nop
});
\ No newline at end of file
return neighbors;
},
- toString : function toString(){
+ toString : function(){
var props = [];
if (this.blocked) props.push('blocked');
if (this.visited) props.push('dist='+this.dist);
return (blocker === obj ? false : blocker);
},
- toString : function toString(){
+ toString : function(){
return 'T['+this.p1+', '+this.p2+', slope='+this.slope.toFixed(3)+']';
}
});
var tr = this.trajectory
, or = this.thing.loc
, dt = Math.min(tr.tBound, this.remaining)
- , to = this.to = tr.parametric(tr.tCurrent+dt) // calc how far down the tr we go
+ , to = tr.parametric(tr.tCurrent+dt) // calc how far down the tr we go
;
// Don't overshoot the target
// Reflection!
if ( isReflective && this.bounceLimit >= ++this.bounces ) {
if (!tvsl.side)
- return console.error('Null reflection line!', 'to:', to, 'blockers:', tvsl.blockers);
+ return console.error('Null reflection line!', 'to:', to, 'blocker:', unit, 'blockers:', tvsl.blockers._o);
ng = math.reflect(traj.p2, tvsl.side);
traj.reset(to.x,to.y, ng.x,ng.y);
return;
}
- unit.dealDamage(this.stats.power, this);
+ unit.dealDamage(this.stats.power.val, this);
this.destroy();
// Trigger explosion
height : ITEM_SIZE,
// indestructable
- stats : { hp:Infinity, move:0, power:0 },
+ stats : { hp:Infinity, move:0, power:0, speed:0 },
dealDamage : op.nop,
// inactive
if (!dir) return;
// @see Tank.move()
- this.move( this.loc.moveByDir(dir, this.stats.move * SQUARETH) );
+ this.move( this.loc.moveByDir(dir, this.stats.move.val * SQUARETH) );
},
}
// Try to blow up nearby tanks
- if (ai.shootEnemy.ready && (this.stats.shots - this.nShots > 1)) {
+ if (ai.shootEnemy.ready && (this.stats.shots.val - this.nShots > 1)) {
var t = this.findNearEnemies(71, true).shift();
// console.log('['+TICKS+':'+this.id, this, '] Shoot at enemies?', t);
if (t) {
};
- var kTrue = Y.op.K(true);
+ var kTrue = op.K(true);
this['findNearLike'] =
function findNearLike(ticks, fn){
if (xydef) this.rotateBarrel(x,y);
- if ( this.nShots >= this.stats.shots || !this.cooldowns.attack.activate(this.now) )
+ if ( this.nShots >= this.stats.shots.val || !this.cooldowns.attack.activate(this.now) )
return null;
var tloc = this.getTurretLoc()
this['ableToShoot'] =
function ableToShoot(){
- return this.nShots < this.stats.shots && this.cooldowns.attack.ready;
+ return this.nShots < this.stats.shots.val && this.cooldowns.attack.ready;
};
this['getTurretLoc'] =
var names = Y('bodyColor', 'turretColor', 'barrelColor');
if (arguments.length === 0)
- return names.generate( Y.op.get(this) );
+ return names.generate( Y.op.curried.get(this) );
if (bodyColor) this.bodyColor = bodyColor;
if (turretColor) this.turretColor = turretColor;
'set' : op.set.methodize(),
'attr' : op.attr.methodize(),
- get movePerMs(){ return this.stats.move*REF_SIZE/1000; },
+ get movePerMs(){
+ var stat = this.stats.move;
+ return (typeof stat === "number" ? stat : stat.val)*REF_SIZE/1000;
+ },
this.bbox = new BoundingBox(0,0, this.width,this.height, this.originX,this.originY);
},
- createStats : function createStats(){
- this.stats = stat.createStats(this.stats);
- },
-
- recalculateStats : function recalculateStats(){
- this.stats =
- Y(this.buffs).reduce(this._applyBuffStats, Y(this.stats).map(this._resetStat, this), this);
- },
-
- _resetStat : function _resetStat(v, k, stats){
- k = Y(k);
- if ( k.endsWith('_max') )
-
+ stat : function stat(k){
+ var s = this.stats[k];
+ return s ? s.val : s;
},
- _applyBuffStats : function _applyBuffStats(buff){
- Y(buff.stat_mods).forEach(this._applyStatMod, this);
+ createStats : function createStats(){
+ this.stats = stat.createStats(this.stats);
},
- _applyStatMod : function _applyStatMod(v, k){
- this.target.modifyStat(k, v);
- }
-
-
createCooldowns : function createCooldowns(){
this.cooldowns = {
- 'attack': new Cooldown(1000 * this.stats.speed)
+ 'attack': new Cooldown(1000 * this.stats.speed.val)
};
this.ai = Y(this.ai).map(function(freq, k){
return new Cooldown(1000 * freq);
},
dealDamage : function dealDamage(d, source){
- this.stats.hp -= d;
- if (this.stats.hp <= 0)
+ this.stats.hp.modify(-d);
+ if (this.stats.hp.val <= 0)
this.destroy();
return this;
},
<script src="build/ezl/loop/fps.js" type="text/javascript"></script>
<script src="build/ezl/math/vec.js" type="text/javascript"></script>
<script src="build/ezl/loop/cooldown.js" type="text/javascript"></script>
-<script src="build/ezl/loop/eventloop.js" type="text/javascript"></script>
<script src="build/evt.js" type="text/javascript"></script>
+<script src="build/ezl/loop/eventloop.js" type="text/javascript"></script>
<script src="build/ezl/loc/loc.js" type="text/javascript"></script>
<script src="build/ezl/math/line.js" type="text/javascript"></script>
<script src="build/ezl/math/rect.js" type="text/javascript"></script>
<script src="build/Y/modules/y.kv.js" type="text/javascript"></script>
<script src="build/ezl/util/tree/binaryheap.js" type="text/javascript"></script>
<script src="build/ezl/util/tree/quadtree.js" type="text/javascript"></script>
+<script src="build/tanks/constants.js" type="text/javascript"></script>
<script src="build/Y/modules/y.scaffold.js" type="text/javascript"></script>
<script src="build/Y/modules/y.config.js" type="text/javascript"></script>
<script src="build/Y/modules/y.cookies.js" type="text/javascript"></script>
<script src="build/tanks/map/map.js" type="text/javascript"></script>
+<script src="build/tanks/effects/stat.js" type="text/javascript"></script>
<script src="build/tanks/map/traversal.js" type="text/javascript"></script>
<script src="build/tanks/config.js" type="text/javascript"></script>
<script src="build/tanks/map/pathmap.js" type="text/javascript"></script>