return this._o.length;
};
+ var self = this;
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)
- // });
+ for (var i=0; i<10; i++)
+ (function (j){
+ Object.defineProperty(self, j+'', {
+ 'get' : function(){ return this._o[j]; },
+ 'set' : function(v){ return (this._o[j] = v); },
+ });
+ }).call(this, i);
this['toString'] = function(){
- return "Y[" + arrayToString.call(this._o) + "]";
+ return "Y[" + arrayToString.call(this._o||[]) + "]";
};
/**
var YBase = require('Y/class').YBase
-// , type = require('Y/type')
+, type = require('Y/type')
, core = require('Y/core')
, del = require('Y/delegate')
, op = require('Y/op')
});
},
- // FIXME: del.map
'invoke' : function invoke(name){
var args = slice.call(arguments,1);
return del.map(this, function(o){
- return o && o[name].apply(o, args);
+ return (o && type.isFunction(o[name])) ? o[name].apply(o, args) : null;
});
},
'__bases__', '__initialise__', '__class__', 'constructor', 'className',
'__emitter__', '__static__', '__mixins__'
] //.concat(classStatics)
-, mixinSkip = [ '__mixin_skip__', '__mixin_skip', 'onMixin', 'onInit', 'init'
+, mixinSkip = [ '__mixin_skip__', 'onMixin', 'onInit', 'init'
].concat(classMagic)
+, GLOBAL_ID = 0
,
+
/**
* @private
* Private delegating constructor. This function must be redefined for every
// Not subclassing
if ( unwrap(cls.caller) !== Y.fabricate ) {
+ instance.id = GLOBAL_ID++;
// Perform actions that should only happen once in Constructor
instance.__emitter__ = new Emitter(instance, cls);
// Fix Constructors
NewClass.__super__ = SuperClass; // don't override NewClass.constructor -- it should be Function
- NewClass.__bases__ = NewClass.fn.__bases__ = [SuperClass].concat( SuperClass.__bases__ || [ Class, Object ] );
+ NewClass.__bases__ = NewClass.fn.__bases__ = Y([SuperClass]).concat( SuperClass.__bases__ || [ Class, Object ] );
prototype.constructor = prototype.__class__ = NewClass;
NewClass.init = prototype.__initialise__ = createInitialise(NewClass);
// 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) && classMagic.indexOf(k) === -1 )
- setDesc(prototype, k, getDesc(members,k));
- }
-
- // NewClass.__super__ = SuperClass;
- // prototype.constructor = prototype.__class__ = NewClass;
- }
-
var mixins = NewClass.__mixins__ = Y([]).concat(members.__mixins__||[], SuperClass.__mixins__||[]).unique()
, statics = NewClass.__static__ = {}
, pstatics = SuperClass.__static__
setDesc(statics, k, desc);
}
+ // Either invoke body constructor...
+ if ( isFunction(members) ) {
+ // body fn is responsible for calling mixin, attaching statics, etc
+ members.call(prototype, NewClass);
+
+ // Or add new instance methods
+ } else {
+ for (var k in members)
+ if ( hasOwn.call(members,k) && classMagic.indexOf(k) === -1 )
+ setDesc(prototype, k, getDesc(members,k));
+ }
+
+ // Notify mixins to let them finish up any customization
+ if (mixins.length)
+ mixins.forEach(function(mxn){
+ if ( mxn && isFunction(mxn.fire) )
+ mxn.fire('mixin', NewClass, { 'mixin':mxn, 'cls':NewClass });
+ });
+
// Notify parent of the subclass
ParentEmitter.fire('subclass',
NewClass, {
Class.__emitter__ = new Emitter(Class);
Class.fn = Class.prototype;
Class.fn.__class__ = Class.fn.constructor = Class;
-Class.fn.__bases__ = Class.__bases__ = [ Object ];
+Class.fn.__bases__ = Class.__bases__ = Y([ Object ]);
Class.className = Class.fn.className = "Class";
/* Class Methods */
*/
__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;
});
+function mixinFilter(v, k){
+ var skip = this.__mixin_skip__ || mixinSkip;
+ return hasOwn.call(this,k) && !(skip && skip.indexOf(k) !== -1);
+}
/**
* Mixes a Mixin into another Class.
, onInit = mproto.onInit
;
- core.extend(proto, core.filter(mproto, mproto.__mixin_skip, mproto));
+ core.extend(proto, core.filter(mproto, mixinFilter, mproto));
if (bases && bases.indexOf(mxn) === -1)
bases.unshift(mxn);
if ( hasOwn.call(mproto,'onInit') && isFunction(onInit) )
cls.addEventListener('init', onInit);
- // Fire the mixin event on this Mixin
- if ( isFunction(mxn.fire) )
+ // Fire the mixin event on this Mixin only if we're done constructing the class
+ if ( isFunction(mxn.fire) && mixin.caller !== Class )
mxn.fire('mixin', cls, { 'mixin':mxn, 'cls':cls });
});
return cls;
if ( isFunction(onMixin) )
mxn.addEventListener('mixin', onMixin);
- console.log('Mixin.subclass()', mxn, '<', d.parent, 'onMixin:', onMixin);
+ // console.log('Mixin.subclass()', mxn, '<', d.parent, 'onMixin:', onMixin);
});
, evt = require('evt')
, mul = Y.op.curried.mul
-, Speciated = require('tanks/mixins/speciated').Speciated
-, Meronomic = require('tanks/mixins/meronomic').Meronomic
+, Speciated = require('tanks/mixins/speciated').Speciated
+, Meronomic = require('tanks/mixins/meronomic').Meronomic
+, Quantified = require('tanks/mixins/quantified').Quantified
,
// Events:
-// - live.{affect,stack}
+// - live.affect // stacking will be done with copies and collapsed in the UI
// - die.{expire,dismiss,dispel}
Buff =
exports['Buff'] =
evt.subclass('Buff', {
- __mixins__: [ Speciated, Meronomic ], // Configurable, Usable
+ __mixins__: [ Speciated, Meronomic, Quantified ], // Configurable, Usable
/// Configurable ///
- priority : 0, // Order of stat and effect application (lower is earlier)
+ priority : 0, // Order of stat and effect application (lower is earlier) // TODO
stats : {
- timeout : -1,
- stacked : 1,
- threat : 1
+ timeout : Infinity,
+ threat : 1 // TODO
},
- // {stat : Number|Function} Modifications to stats
+
// TODO: functions
+ // {stat : Number|Function} Modifications to stats
stat_mods : {
move : 2
},
- // 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 // XXX: not sure why i need this...
+ triggers : {}, // {event : Effect} // maybe
/// Instance ///
- owner : null, // Agent which originated the buff
- target : null, // Agent to which the buff applies
+ owner : null, // Agent which originated the buff
+ target : null, // Agent to which the buff applies
+ game : null,
+ created : 0,
-
- init : function initBuff(owner, target){
+ init : function initBuff(target, owner){
this.owner = owner;
this.game = owner.game;
this.target = target;
+
+ this.createStats()
+ // this.createCooldowns();
+
this.created = this.game.NOW;
- // XXX: Speciated mixin must clone objects
+ this.expires = this.created + this.stats.timeout.val;
+
+ this.applyStatMods();
+ this.target.fire('buff.live.acquire', this, { 'buff':this, 'unit':target, 'owner':owner });
},
tick : function tick(elapsed, now){
+ // this.updateCooldowns();
+ if (now < this.expires) {
+ // this.remove();
+ this.die('expire');
+ }
+
+ return this;
+ },
+
+ die : function die(reason){
+ this.removeStatMods();
+ this.target.fire('buff.die.'+reason, this, { 'buff':this, 'unit':target, 'owner':owner });
+ return this;
+ },
+
+ dismiss : function dismiss(){
+ return this.die('dismiss');
+ },
+
+ dispel : function dispel(){
+ return this.die('dispel');
},
applyStatMods : function applyStatMods(modifier){
- modifier = modifier || 1;
+ modifier = (modifier || 1);
Y(this.stat_mods).map(mul(modifier)).forEach(this._applyStatMod, this);
return this;
},
_applyStatMod : function _applyStatMod(mod, name){
var keyparts = name.split('_')
, key = keyparts[0]
- , part = keyparts[1] || 'max'
- ;
+ , part = keyparts[1] || 'max' ;
this.target.stats[key].modifyPart(part, mod);
- return this;
},
removeStatMods : function removeStatMods(){
return this.applyStatMods(-1);
}
- // XXX: toString implemented by Informative
-
})
+var stat = require('tanks/effects/stat');
+
+require('Y').Y.core
+.extend(exports, {
+ 'Buff' : require('tanks/effects/buff').Buff,
+
+ 'Stat' : stat.Stat,
+ 'createStats' : stat.createStats
+});
\ No newline at end of file
// exports.tanks =
tanks = {
- 'config' : require('tanks/config').config,
- 'ui' : require('tanks/ui'),
- 'mixins' : require('tanks/mixins'),
- 'Game' : require('tanks/game').Game,
+ 'config' : require('tanks/config').config,
+ 'constants' : require('tanks/constants'),
+ 'effects' : require('tanks/effects'),
+ 'fx' : require('tanks/fx'),
+ 'mixins' : require('tanks/mixins'),
+ 'map' : require('tanks/map'),
+ 'thing' : require('tanks/thing'),
+ 'ui' : require('tanks/ui'),
- 'game' : null,
+ 'Game' : require('tanks/game').Game,
+ 'game' : null
};
-require('Y').Y.extend(exports, {
- 'Speciated' : require('tanks/mixins/speciated').Speciated,
- 'Meronomic' : require('tanks/mixins/meronomic').Meronomic
+require('Y').Y.core
+.extend(exports, {
+ 'Speciated' : require('tanks/mixins/speciated').Speciated,
+ 'Meronomic' : require('tanks/mixins/meronomic').Meronomic,
+ 'Quantified' : require('tanks/mixins/quantified').Quantified
});
+++ /dev/null
-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+'()';
- }
-
-});
--- /dev/null
+var Y = require('Y').Y
+, Mixin = require('evt').Mixin
+, Cooldown = require('ezl/loop').Cooldown
+, stat = require('tanks/effects/stat')
+,
+
+
+Quantified =
+exports['Quantified'] =
+Mixin.subclass('Quantified', {
+
+ stats : {},
+ cooldowns : {},
+ ai : {},
+
+
+ stat : function stat(k){
+ var s = this.stats[k];
+ return s ? s.val : s;
+ },
+
+ createStats : function createStats(){
+ this.stats = stat.createStats(this.stats);
+ },
+
+ createCooldowns : function createCooldowns(){
+ this._cooldowns = Y({
+ 'attack': new Cooldown(1000 * this.stats.speed.val)
+ });
+ this._ai = Y(this.ai).map(function(freq, k){
+ return new Cooldown(1000 * freq);
+ });
+
+ this.cooldowns = this._cooldowns.end();
+ this.ai = this._ai.end();
+ },
+
+ updateCooldowns : function updateCooldowns(elapsed, now){
+ this._cooldowns.invoke('tick', elapsed, now);
+ this._ai.invoke('tick', elapsed, now);
+ return this;
+ },
+
+
+ // onInit : function initQuantified(evt){
+ // var self = evt.data.instance;
+ // self.createStats();
+ // self.createCooldowns();
+ // },
+
+ onMixin : function onMixin(evt){
+ var cls = evt.data.cls
+ , mxn = evt.data.mixin
+ , proto = cls.fn ;
+ console.log(mxn, '.onMixin()', cls);
+ proto.stats = cls.aggregate('stats');
+ proto.cooldowns = cls.aggregate('cooldowns');
+ proto.ai = cls.aggregate('ai');
+ },
+
+ __static__ : {
+
+ /**
+ * @return The merged pairs at key taken from all bases.
+ */
+ aggregate : function aggregate(key){
+ return this.__bases__
+ .clone()
+ .unshift(this)
+ .reverse()
+ .reduce(function(acc, base){
+ var proto = (base instanceof Function ? base.prototype : base);
+ return Y.extend(acc, proto[key]);
+ }, {});
+ }
+ }
+
+});
Speciated =
exports['Speciated'] =
Mixin.subclass('Speciated', {
-
- lol : 1,
+ name : "",
+ desc : "",
+ tags : [],
__static__ : {
- __known__ : null,
+ id2name : function id2name(id){
+ var name = id+'';
+ // TODO: all YString methods to return YString :P But it'll proally break shit
+ name = Y(name).capitalize();
+ name = Y(name).snakeToCamel();
+ return name;
+ },
speciate : function speciate(id, props){
+ if ( this.__known__[id] )
+ throw new Error('A species of '+this.className+' already exists with the id '+id+'!');
+
props = props || {};
props.__species__ = id;
- delete props.id;
+ delete props.id; // reserved for instance id
var cls = this
- , speciesName = Y(Y(id+'').capitalize()).snakeToCamel()
- , Species = cls.__known__[id] = cls.subclass(speciesName, props)
+ , speciesName = this.id2name(id)
+ , Species = this.__known__[id] = cls.subclass(speciesName, props)
;
Species.__species_props__ = props;
return Species;
},
lookupSpecies : function lookupSpecies(id){
- var cls = this;
- return cls.__known__[id];
+ return this.__known__[id];
},
createSpeciesInstance : function createSpeciesInstance(id){
var args = Y(arguments,1)
- , cls = this
- , Species = cls.__known__[id];
+ , Species = this.__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){
// Attributes
stats : {
- hp : 2, // health
+ hp : 1, // health
move : 0.75, // move speed (squares/sec)
- rotate : HALF_PI, // rotation speed (radians/sec)
power : 1, // attack power
speed : 0.5, // attack cool (sec)
shots : 4 // max projectiles in the air at once
, config = require('tanks/config').config
, map = require('tanks/map/map')
, stat = require('tanks/effects/stat')
-
-, THING_ID = 0
+, Quantified = require('tanks/mixins/quantified').Quantified
,
-fillStats =
-exports['fillStats'] =
-function fillStats(stats){
- return Y.reduce(stats, function(_stats, v, k){
- _stats[k] = v;
-
- k = Y(k);
- var k_ = k.rtrim('_max')
- , k_max = k_+'_max'
- , k_base = k_+'_base'
- ;
- if ( _stats[k_] === undefined )
- _stats[k_] = v;
-
- if ( _stats[k_max] === undefined )
- _stats[k_max] = v;
-
- if ( _stats[k_base] === undefined )
- _stats[k_base] = _stats[k_max];
-
- return _stats;
- }, {});
-}
-,
-
Thing =
-exports['Thing'] = new evt.Class('Thing', {
+exports['Thing'] =
+new evt.Class('Thing', {
+ __mixins__ : [ Quantified ],
+
// Config
showAttackCooldown : null,
// Attributes
stats: {
+ // rotate : HALF_PI, // rotation speed (radians/sec) [UNUSED]
hp : 1, // health
move : 1.0, // move speed (squares/sec)
- rotate : HALF_PI, // rotation speed (radians/sec) [UNUSED]
power : 1, // attack power
speed : 0.5, // attack cool (sec)
- shots : 5 // max projectiles in the air at once
+ shots : 5, // max projectiles in the air at once
+ sight : 5, // distance this unit can see (squares)
+ accuracy : 1.0
+ },
+
+ cooldowns : {
+ attack: 'stats.speed'
},
// AI "Cooldowns" (max frequency of each action per sec)
init : function init(align){
- this.id = THING_ID++;
this.align = align || 0;
this.createBoundingBox();
this.createStats();
this.bbox = new BoundingBox(0,0, this.width,this.height, this.originX,this.originY);
},
- stat : function stat(k){
- var s = this.stats[k];
- return s ? s.val : s;
- },
-
- createStats : function createStats(){
- this.stats = stat.createStats(this.stats);
- },
-
- createCooldowns : function createCooldowns(){
- this._cooldowns = Y({
- 'attack': new Cooldown(1000 * this.stats.speed.val)
- });
- this._ai = Y(this.ai).map(function(freq, k){
- return new Cooldown(1000 * freq);
- });
-
- this.cooldowns = this._cooldowns.end();
- this.ai = this._ai.end();
- },
-
- updateCooldowns : function updateCooldowns(elapsed, now){
- this._cooldowns.invoke('tick', elapsed, now);
- this._ai.invoke('tick', elapsed, now);
- return this;
- },
-
-
position : function position(x,y){
if (x === undefined && y === undefined)
return this.loc;
<script src="build/tanks/globals.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/effects/buff.js" type="text/javascript"></script>
<script src="build/tanks/constants.js" type="text/javascript"></script>
+<script src="build/ezl/util/tree/quadtree.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/map.js" type="text/javascript"></script>
+<script src="build/Y/modules/y.cookies.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>
+<script src="build/tanks/mixins/quantified.js" type="text/javascript"></script>
<script src="build/tanks/thing/thing.js" type="text/javascript"></script>
+<script src="build/tanks/effects/buff.js" type="text/javascript"></script>
+<script src="build/tanks/mixins.js" type="text/javascript"></script>
<script src="build/tanks/map/trajectory.js" type="text/javascript"></script>
+<script src="build/tanks/effects.js" type="text/javascript"></script>
<script src="build/tanks/ui/pathmapui.js" type="text/javascript"></script>
<script src="build/tanks/thing/wall.js" type="text/javascript"></script>
<script src="build/tanks/thing/item.js" type="text/javascript"></script>
<script src="build/tanks/ui/grid.js" type="text/javascript"></script>
<script src="build/tanks/fx/explosion.js" type="text/javascript"></script>
<script src="build/tanks/thing/bullet.js" type="text/javascript"></script>
+<script src="build/tanks/fx.js" type="text/javascript"></script>
<script src="build/tanks/thing/tank.js" type="text/javascript"></script>
<script src="build/tanks/thing/player.js" type="text/javascript"></script>
<script src="build/tanks/map/level.js" type="text/javascript"></script>