, upperPat = /^[A-Z]+$/
-, symbolPat = /^[^a-zA-Z]+$/
+, symbolPat = /^[^a-zA-Z0-9]+$/
,
camelToSpaces =
exports['camelToSpaces'] =
if (o === undefined || o === null)
return String(o);
var T = type(o);
- return T.className || (T !== Function ? T.name : basicTypeName(o));
+ return T.className || (T !== Function ? T.name || "Function" : basicTypeName(o));
}
var arrayLike = isArray.types = [];
return ( fn && isFunction(fn) ) ? unwrap(fn[WRAPS]) || fn : fn;
}
+/**
+ * @return {Function} A function which flips the first and second arguments
+ * before calling the original.
+ */
+function flip(fn){
+ fn = _Function.toFunction(fn);
+
+ var f = fn.__flipped__;
+ if (f) return f;
+
+ f = fn.__flipped__ =
+ function flipped(){
+ var args = arguments
+ , hd = args[0];
+ args[0] = args[1];
+ args[1] = hd;
+ return fn.apply(this, args);
+ };
+ return wraps(f, fn);
+}
+
function curry(fn){
if (fn.__curried__)
return fn.apply(this, slice.call(arguments,1));
function methodize(fn) {
- fn = fn.toFunction();
+ fn = _Function.toFunction(fn);
var g = fn.__genericized__
, m = fn.__methodized__ ;
if (m) return m;
}
function genericize(fn) {
- fn = fn.toFunction();
+ fn = _Function.toFunction(fn);
var g = fn.__genericized__
, m = fn.__methodized__ ;
if (g) return g;
}
-/**
- * Filter the arguments passed to the wrapper function
- */
-// YF.prototype.mask = mask;
-// function mask(){
+// function guard(test, otherwise){
//
// }
-[ wraps, unwrap, getName,
+[ wraps, unwrap, getName, flip,
curry, compose, chain, bind, partial,
methodize, genericize, memoize, aritize, limit
].map(function(fn){
, core = require('Y/core')
, del = require('Y/delegate')
, slice = core.slice
+
+, upperPat = /^[A-Z]+$/
+, symbolPat = /^[^a-zA-Z0-9_\$]+$/
;
exports['YString'] =
return s.lastIndexOf(val) === (s.length - val.length);
},
+ 'capitalize' : function capitalize(){
+ var s = this._o+'';
+ return s.charAt(0).toUpperCase()+s.slice(1);
+ },
+
+ /**
+ * Converts a camelCase string into a snake_case string.
+ * @param {Boolean} nameSafe If true, keeps only characters valid in function names.
+ * @return {String} The snake_case string.
+ *
+ * Y('petGrumpyCamels').camelToSnake() === 'pet_grumpy_camels'
+ */
+ 'camelToSnake' : function camelToSnake(nameUnsafe){
+ return this.reduce(
+ function(out, ch, i){
+ if ( !nameUnsafe && symbolPat.test(ch) )
+ return out;
+ if ( upperPat.test(ch) )
+ out += '_';
+ return out + ch.toLowerCase();
+ }, '');
+ },
+
+ /**
+ * Converts a snake_case string into a camelCase string. (All non-alphanumeric
+ * characters are treated as separators for the purposes of camelizing.)
+ * @param {Boolean} [nameUnsafe=false] Does not strip characters invalid in function names.
+ * (Underscores are always removed.)
+ * @return {String} The camelCase string.
+ *
+ * Y('feed_happy_snakes').snakeToCamel() === 'feedHappySnakes'
+ */
+ 'snakeToCamel' : function snakeToCamel(nameUnsafe){
+ return this.reduce(
+ function(state, ch, i){
+ var isSymbol = symbolPat.test(ch);
+ if ( ch === '_' )
+ isSymbol = true;
+ else if (!isSymbol || nameUnsafe)
+ state.out += (state.prev ? ch.toUpperCase() : ch);
+ state.prev = isSymbol;
+ return state;
+ },
+ {
+ out : '',
+ prev : false
+
+ }).out;
+ },
+
'compare' : function compare(n){
var m = this._o;
return (m > n ? 1 :
, objToString = _Object[P].toString
, classToString = function toString(){ return this.className+"()"; }
-, classMagic = [ '__static__', '__mixins__', '__emitter__', '__bases__', '__initialise__' ]
-, mixinSkip = [ '__mixin_skip__', 'onMixin', 'onInit', 'init' ].concat(classMagic)
-, classStatics = [ 'instantiate', 'fabricate', 'subclass' ]
+
+, classStatics = [ 'instantiate', 'fabricate', 'subclass' ]
+, classMagic = [
+ '__bases__', '__initialise__', '__class__', 'constructor', 'className',
+ '__emitter__', '__static__', '__mixins__'
+ ] //.concat(classStatics)
+, mixinSkip = [ '__mixin_skip__', '__mixin_skip', 'onMixin', 'onInit', 'init'
+ ].concat(classMagic)
,
eval(constructor);
// Copy Class statics
- for (var i=0, L=classStatics.length; i<L; ++i) {
- var k = classStatics[i];
- NewClass[k] = ClassFactory[k];
- }
+ // for (var i=0, L=classStatics.length; i<L; ++i) {
+ // var k = classStatics[i];
+ // NewClass[k] = ClassFactory[k];
+ // }
// Copy parent methods, then add new instance methods
for (var k in parentMembers)
// prototype.constructor = prototype.__class__ = NewClass;
}
- var mixins = members.__mixins__
- , statics = members.__static__
+ var mixins = NewClass.__mixins__ = Y([]).concat(members.__mixins__||[], SuperClass.__mixins__||[]).unique()
+ , statics = NewClass.__static__ = {}
+ , pstatics = SuperClass.__static__
+ , mstatics = members.__static__
;
- if (mixins && hasOwn.call(members,'__mixins__'))
+ for (var k in pstatics)
+ if ( hasOwn.call(pstatics,k) && classMagic.indexOf(k) === -1 ) {
+ var desc = getDesc(pstatics,k);
+ setDesc(NewClass, k, desc);
+ setDesc(statics, k, desc);
+ }
+
+ if (mixins.length)
mixin(NewClass, mixins);
- if (statics)
- for (var k in statics) {
- if ( hasOwn.call(statics,k) && classMagic.indexOf(k) === -1 )
- setDesc(NewClass, k, getDesc(statics,k));
+ for (var k in mstatics)
+ if ( hasOwn.call(mstatics,k) && classMagic.indexOf(k) === -1 ) {
+ var desc = getDesc(mstatics,k);
+ setDesc(NewClass, k, desc);
+ setDesc(statics, k, desc);
}
-
// Notify parent of the subclass
ParentEmitter.fire('subclass',
NewClass, {
return instance;
}
-Class.instantiate = Y(instantiate).methodize();
-Class.fabricate = Y.Class.fabricate;
+var CST = Class.__static__ = {};
+CST.instantiate = Class.instantiate = Y(instantiate).methodize();
+CST.fabricate = Class.fabricate = Y.Class.fabricate;
/**
* Class/Instance method of Classes, not to be confused with Evt.subclass, which is a static method.
*/
+CST.subclass =
Class.subclass =
Class.fn.subclass =
Y(function subclass(className, members){
}
}
-})
-,
+});
+
/**
* Mixes a Mixin into another Class.
*/
-mixin =
-exports['mixin'] =
-function mixin(cls, mxn){
+function mixin(cls, _mxn){
var proto = cls.fn
- , mxns = (Y.isArray(mxn) ? mxn : Y(arguments, 1))
+ , mxns = (Y.isArray(_mxn) ? _mxn.slice(0) : Y(arguments, 1))
;
- mxns.forEach(function(mxn){
+ mxns.reverse().forEach(function(mxn){
mxn = (typeof mxn === "string") ? lookupClass(mxn) : mxn;
if ( !mxn )
var mproto = (typeof mxn === "function") ? mxn.fn : mxn
, bases = cls.__bases__
- , statics = mproto.__static__
+ , cstatic = cls.__static__
+ , statics = mxn.__static__
, onInit = mproto.onInit
;
core.extend(proto, core.filter(mproto, mproto.__mixin_skip, mproto));
- if (bases)
- bases.push(mxn);
+ if (bases && bases.indexOf(mxn) === -1)
+ bases.unshift(mxn);
// Add mixin statics to class constructor
- if (statics)
- core.extend(cls, statics);
+ if (statics){
+ for (var k in statics)
+ if ( hasOwn.call(statics,k) && classMagic.indexOf(k) === -1 ) {
+ var desc = getDesc(statics,k);
+ setDesc(cls, k, desc);
+ setDesc(cstatic, k, desc);
+ }
+ }
// 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 });
+ if ( isFunction(mxn.fire) )
+ mxn.fire('mixin', cls, { 'mixin':mxn, 'cls':cls });
});
return cls;
}
-;
+
Mixin.addEventListener('subclass',
function onMixinSubclass(evt){
, onMixin = members.onMixin
;
- if ( hasOwn.call(members,'onMixin') && isFunction(onMixin) )
+ if ( isFunction(onMixin) )
mxn.addEventListener('mixin', onMixin);
+
+ console.log('Mixin.subclass()', mxn, '<', d.parent, 'onMixin:', onMixin);
});
exports['instantiate'] = instantiate;
exports['fabricate'] = Y.fabricate;
exports['lookupClass'] = lookupClass;
+exports['mixin'] = mixin;
var Y = require('Y').Y
+, evt = require('evt')
, mul = Y.op.curried.mul
+
+, Speciated = require('tanks/mixins/speciated').Speciated
+, Meronomic = require('tanks/mixins/meronomic').Meronomic
,
// - die.{expire,dismiss,dispel}
Buff =
exports['Buff'] =
-Y.subclass('Buff', {
- // __mixins__: [ Informative, Speciated, Meronomic, Usable ], // Configurable?
+evt.subclass('Buff', {
+ __mixins__: [ Speciated, Meronomic ], // Configurable, Usable
/// Configurable ///
stacked : 1,
threat : 1
},
- stat_mods : {}, // {stat : Number|Function} Modifications to stats // TODO: functions
+ // {stat : Number|Function} Modifications to stats
+ // TODO: functions
+ stat_mods : {
+ move : 2
+ },
// effects : [], // {Function...} Effects to trigger on affect // XXX: not sure why i need this...
// triggers : {}, // {event : Effect} // maybe
tanks = {
'config' : require('tanks/config').config,
'ui' : require('tanks/ui'),
+ 'mixins' : require('tanks/mixins'),
'Game' : require('tanks/game').Game,
'game' : null,
game.addThing(new Tank(2), 8,1);
I = game.addThing(new Item(), 8,8);
-
- // DATA = $('<pre id="data" style="position:absolute;top:0;left:0;width:200px;"></pre>').appendTo('body');
- // E = game.addThing(new Thing(2), 0,0);
- // var i = 0;
- // function testBulletSpeed(){
- // B = P.shoot(0,475);
- // var start = new Date().getTime()
- // , startClock = NOW
- // , startX = B.loc.x;
- // B.bounces = 1;
- // console.log(i+' B.movePerMs='+B.movePerMs+', move='+B.stats.move);
- //
- // B.addEventListener('destroy', function(evt){
- // var elapsed = (new Date().getTime() - start)/1000
- // , clock = (NOW - startClock)/1000
- // , distance = startX - B.loc.x ;
- // DATA.text(DATA.text()+elapsed.toFixed(3)+'\t'+clock.toFixed(3)+'\t'+distance.toFixed(3)+'\t'+(distance/elapsed).toFixed(3)+'\n');
- // if (++i < 20) testBulletSpeed();
- // });
- // }
- // game.addEventListener('start', function(evt){
- // DATA.text('elapsed\tclock\tpx\tpx/s\n');
- // testBulletSpeed();
- // });
},
addWall : function addWall(x,y, w,h, isBoundary){
+var Y = require('Y').Y
+, Mixin = require('evt').Mixin
+,
+
+Configurable =
+exports['Configurable'] =
+Mixin.subclass('Configurable', {
+
+ onInit : function initConfigurable(evt){
+
+ }
+
+});
--- /dev/null
+require('Y').Y.extend(exports, {
+ 'Speciated' : require('tanks/mixins/speciated').Speciated,
+ 'Meronomic' : require('tanks/mixins/meronomic').Meronomic
+});
+var Y = require('Y').Y
+, Mixin = require('evt').Mixin
+,
+
+Informative =
+exports['Informative'] =
+Mixin.subclass('Informative', {
+
+
+ onInit : function initInformative(evt){
+ var instance = evt.data.instance;
+
+ },
+
+ toString : function(){
+ return this.className+'()';
+ }
+
+});
+var Y = require('Y').Y
+, Mixin = require('evt').Mixin
+,
+
+Meronomic =
+exports['Meronomic'] =
+Mixin.subclass('Meronomic', {
+
+ onInit : function initMeronomic(evt){
+
+ }
+
+});
+var Y = require('Y').Y
+, Mixin = require('evt').Mixin
+,
+
+Speciated =
+exports['Speciated'] =
+Mixin.subclass('Speciated', {
+
+ lol : 1,
+
+ __static__ : {
+ __known__ : null,
+
+ speciate : function speciate(id, props){
+ props = props || {};
+ props.__species__ = id;
+ delete props.id;
+
+ var cls = this
+ , speciesName = Y(Y(id+'').capitalize()).snakeToCamel()
+ , Species = cls.__known__[id] = cls.subclass(speciesName, props)
+ ;
+ Species.__species_props__ = props;
+ return Species;
+ },
+
+ lookupSpecies : function lookupSpecies(id){
+ var cls = this;
+ return cls.__known__[id];
+ },
+
+ createSpeciesInstance : function createSpeciesInstance(id){
+ var args = Y(arguments,1)
+ , cls = this
+ , Species = cls.__known__[id];
+ return Species.instantiate.apply(Species, args);
+ }
+
+ },
+
+ onMixin : function mixSpeciated(evt){
+ var cls = evt.data.cls;
+ cls.__known__ = {};
+ console.log('mixSpeciated()', 'cls:', cls, 'mxn:', evt.data.mixin);
+ },
+
+ // onInit : function initSpeciated(evt){
+ // var d = evt.data
+ // , instance = d.instance
+ // , Species = d.cls
+ // , props = Species.__species_props__
+ // ;
+ // // for (var k in props) {
+ // // var v = props[k];
+ // // if ( Y.isArray(v) || typeof v === "object" )
+ // // instance[k] = Y(v).clone();
+ // // }
+ // },
+
+ toString : function(){
+ return this.className+'(name='+this.name+', id='+this.id+', tags=['+this.tags+'])';
+ }
+
+});
<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/mixins/speciated.js" type="text/javascript"></script>
+<script src="build/tanks/mixins/meronomic.js" type="text/javascript"></script>
<script src="build/tanks/map/traversal.js" type="text/javascript"></script>
+<script src="build/tanks/mixins.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>
<script src="build/tanks/ui/configui.js" type="text/javascript"></script>