+game:
+ timeDilation : 1.0
+ gameoverDelay : 1000
+ refSize : &ref_size 50
+debug:
+ showFpsGraph : false
+ # createGridTable : false
+ # showGridCoords : false
+ui:
+ createGridCanvas : true
+ overlayOnPause : true
+ showAttackCooldown : false
+ showCountdown : true
+pathing:
+ gridSquare : *ref_size
+ overlayAiPaths : false
+ overlayPathmap : false
+ traceTrajectories : false
-# Buff definitions
-name: buff
-lookup: .tanks.data.buffs
+name: buffs
defaults:
symbol: tanks/effects/buff.Buff
timeout: -1 # the Infinity literal is not valid JSON
+name: bullets
+defaults:
+ symbol: tanks/thing/bullet.Bullet
+ art:
+ map_icon: ''
+ inv_icon: ''
+types:
+ normal:
+ color: '#FFF6AE'
+ bounceLimit: 1
+ stats:
+ move: 2.25
+ player_normal:
+ color: '#F7ADA6'
+ bounceLimit: 1
+ stats:
+ move: 2.25
-# Item definitions
-name: item
-lookup: .tanks.data.items
+name: items
defaults:
symbol: tanks/thing/item.Item
types:
-# Level definitions
-name: level
-lookup: .tanks.data.levels
+name: levels
defaults:
symbol: tanks/map/level.Level
types:
-# Unit definitions
-name: unit
-lookup: .tanks.data.units
+name: units
defaults:
symbol: tanks/thing/thing.Thing
level: 1
+ projectile: normal
stats:
hp : 1 # health
move : 1.0 # move speed (squares/sec)
desc: "Don't hate the Player, hate the--Wait. No, that's fine."
tags: [ 'tank' ]
symbol: tanks/thing/player.Player
+ # projectile: player_normal
stats:
hp : 1
move : 0.90
--- /dev/null
+/*************************************************
+** jQuery Masonry version 1.3.2
+** Copyright David DeSandro, licensed MIT
+** http://desandro.com/resources/jquery-masonry
+**************************************************/
+;(function($){
+
+ /*!
+ * smartresize: debounced resize event for jQuery
+ * http://github.com/lrbabe/jquery-smartresize
+ *
+ * Copyright (c) 2009 Louis-Remi Babe
+ * Licensed under the GPL license.
+ * http://docs.jquery.com/License
+ *
+ */
+ var event = $.event,
+ resizeTimeout;
+
+ event.special.smartresize = {
+ setup: function() {
+ $(this).bind( "resize", event.special.smartresize.handler );
+ },
+ teardown: function() {
+ $(this).unbind( "resize", event.special.smartresize.handler );
+ },
+ handler: function( event, execAsap ) {
+ // Save the context
+ var context = this,
+ args = arguments;
+
+ // set correct event type
+ event.type = "smartresize";
+
+ if (resizeTimeout) { clearTimeout(resizeTimeout); }
+ resizeTimeout = setTimeout(function() {
+ jQuery.event.handle.apply( context, args );
+ }, execAsap === "execAsap"? 0 : 100);
+ }
+ };
+
+ $.fn.smartresize = function( fn ) {
+ return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
+ };
+
+
+
+ // masonry code begin
+ $.fn.masonry = function(options, callback) {
+
+ // all my sweet methods
+ var msnry = {
+ getBricks : function($wall, props, opts) {
+ var hasItemSelector = (opts.itemSelector === undefined);
+ if ( opts.appendedContent === undefined ) {
+ // if not appendedContent
+ props.$bricks = hasItemSelector ?
+ $wall.children() :
+ $wall.find(opts.itemSelector);
+ } else {
+ // if appendedContent...
+ props.$bricks = hasItemSelector ?
+ opts.appendedContent :
+ opts.appendedContent.filter( opts.itemSelector );
+ }
+ },
+
+ placeBrick : function($brick, setCount, setY, props, opts) {
+ // get the minimum Y value from the columns...
+ var minimumY = Math.min.apply(Math, setY),
+ setHeight = minimumY + $brick.outerHeight(true),
+ i = setY.length,
+ shortCol = i,
+ setSpan = props.colCount + 1 - i;
+ // Which column has the minY value, closest to the left
+ while (i--) {
+ if ( setY[i] == minimumY ) {
+ shortCol = i;
+ }
+ }
+
+ var position = {
+ left: props.colW * shortCol + props.posLeft,
+ top: minimumY
+ };
+
+ // position the brick
+ $brick.applyStyle(position, $.extend(true,{},opts.animationOptions) );
+
+ // apply setHeight to necessary columns
+ for ( i=0; i < setSpan; i++ ) {
+ props.colY[ shortCol + i ] = setHeight;
+ }
+ },
+
+ setup : function($wall, opts, props) {
+ msnry.getBricks($wall, props, opts);
+
+ if ( props.masoned ) {
+ props.previousData = $wall.data('masonry');
+ }
+
+ if ( opts.columnWidth === undefined) {
+ props.colW = props.masoned ?
+ props.previousData.colW :
+ props.$bricks.outerWidth(true);
+ } else {
+ props.colW = opts.columnWidth;
+ }
+
+ props.colCount = Math.floor( $wall.width() / props.colW ) ;
+ props.colCount = Math.max( props.colCount, 1 );
+ },
+
+ arrange : function($wall, opts, props) {
+ var i;
+
+ if ( !props.masoned || opts.appendedContent !== undefined ) {
+ // just the new bricks
+ props.$bricks.css( 'position', 'absolute' );
+ }
+
+ // if masonry hasn't been called before
+ if ( !props.masoned ) {
+ $wall.css( 'position', 'relative' );
+
+ // get top left position of where the bricks should be
+ var $cursor = $( document.createElement('div') );
+ $wall.prepend( $cursor );
+ props.posTop = Math.round( $cursor.position().top );
+ props.posLeft = Math.round( $cursor.position().left );
+ $cursor.remove();
+ } else {
+ props.posTop = props.previousData.posTop;
+ props.posLeft = props.previousData.posLeft;
+ }
+
+ // set up column Y array
+ if ( props.masoned && opts.appendedContent !== undefined ) {
+ // if appendedContent is set, use colY from last call
+ props.colY = props.previousData.colY;
+
+ /*
+ * in the case that the wall is not resizeable,
+ * but the colCount has changed from the previous time
+ * masonry has been called
+ */
+ for ( i = props.previousData.colCount; i < props.colCount; i++) {
+ props.colY[i] = props.posTop;
+ }
+
+ } else {
+ // start new colY array, with starting values set to posTop
+ props.colY = [];
+ i = props.colCount;
+ while (i--) {
+ props.colY.push(props.posTop);
+ }
+ }
+
+ // are we animating the rearrangement?
+ // use plugin-ish syntax for css or animate
+ $.fn.applyStyle = ( props.masoned && opts.animate ) ? $.fn.animate : $.fn.css;
+
+
+ // layout logic
+ if ( opts.singleMode ) {
+ props.$bricks.each(function(){
+ var $brick = $(this);
+ msnry.placeBrick($brick, props.colCount, props.colY, props, opts);
+ });
+ } else {
+ props.$bricks.each(function() {
+ var $brick = $(this),
+ //how many columns does this brick span
+ colSpan = Math.ceil( $brick.outerWidth(true) / props.colW);
+ colSpan = Math.min( colSpan, props.colCount );
+
+ if ( colSpan === 1 ) {
+ // if brick spans only one column, just like singleMode
+ msnry.placeBrick($brick, props.colCount, props.colY, props, opts);
+ } else {
+ // brick spans more than one column
+
+ //how many different places could this brick fit horizontally
+ var groupCount = props.colCount + 1 - colSpan,
+ groupY = [];
+
+ // for each group potential horizontal position
+ for ( i=0; i < groupCount; i++ ) {
+ // make an array of colY values for that one group
+ var groupColY = props.colY.slice(i, i+colSpan);
+ // and get the max value of the array
+ groupY[i] = Math.max.apply(Math, groupColY);
+ }
+
+ msnry.placeBrick($brick, groupCount, groupY, props, opts);
+ }
+ }); // /props.bricks.each(function() {
+ } // /layout logic
+
+ // set the height of the wall to the tallest column
+ props.wallH = Math.max.apply(Math, props.colY);
+ var wallCSS = { height: props.wallH - props.posTop };
+ $wall.applyStyle( wallCSS, $.extend(true,[],opts.animationOptions) );
+
+ // add masoned class first time around
+ if ( !props.masoned ) {
+ // wait 1 millisec for quell transitions
+ setTimeout(function(){
+ $wall.addClass('masoned');
+ }, 1);
+ }
+
+ // provide props.bricks as context for the callback
+ callback.call( props.$bricks );
+
+ // set all data so we can retrieve it for appended appendedContent
+ // or anyone else's crazy jquery fun
+ $wall.data('masonry', props );
+
+ }, // /msnry.arrange
+
+ resize : function($wall, opts, props) {
+ props.masoned = !!$wall.data('masonry');
+ var prevColCount = $wall.data('masonry').colCount;
+ msnry.setup($wall, opts, props);
+ if ( props.colCount != prevColCount ) {
+ msnry.arrange($wall, opts, props);
+ }
+ }
+ };
+
+
+ /*
+ * let's begin
+ * IN A WORLD...
+ */
+ return this.each(function() {
+
+ var $wall = $(this),
+ props = {};
+
+ // checks if masonry has been called before on this object
+ props.masoned = !!$wall.data('masonry');
+
+ var previousOptions = props.masoned ? $wall.data('masonry').options : {},
+ opts = $.extend(
+ {},
+ $.fn.masonry.defaults,
+ previousOptions,
+ options
+ ),
+ resizeOn = previousOptions.resizeable;
+
+ // should we save these options for next time?
+ props.options = opts.saveOptions ? opts : previousOptions;
+
+ //picked up from Paul Irish
+ callback = callback || function(){};
+
+ msnry.getBricks($wall, props, opts);
+
+ // if brickParent is empty, do nothing, go back home and eat chips
+ if ( !props.$bricks.length ) {
+ return this;
+ }
+
+ // call masonry layout
+ msnry.setup($wall, opts, props);
+ msnry.arrange($wall, opts, props);
+
+ // binding window resizing
+ if ( !resizeOn && opts.resizeable ) {
+ $(window).bind('smartresize.masonry', function() { msnry.resize($wall, opts, props); } );
+ }
+ if ( resizeOn && !opts.resizeable ) {
+ $(window).unbind('smartresize.masonry');
+ }
+
+
+ }); // /return this.each(function()
+ }; // /$.fn.masonry = function(options)
+
+
+ // Default plugin options
+ $.fn.masonry.defaults = {
+ singleMode: false,
+ columnWidth: undefined,
+ itemSelector: undefined,
+ appendedContent: undefined,
+ saveOptions: true,
+ resizeable: true,
+ animate: false,
+ animationOptions: {}
+ };
+
+})(jQuery);
\ No newline at end of file
--- /dev/null
+/*************************************************
+** jQuery Masonry version 1.3.2
+** Copyright David DeSandro, licensed MIT
+** http://desandro.com/resources/jquery-masonry
+**************************************************/
+(function(e){var n=e.event,o;n.special.smartresize={setup:function(){e(this).bind("resize",n.special.smartresize.handler)},teardown:function(){e(this).unbind("resize",n.special.smartresize.handler)},handler:function(j,l){var g=this,d=arguments;j.type="smartresize";o&&clearTimeout(o);o=setTimeout(function(){jQuery.event.handle.apply(g,d)},l==="execAsap"?0:100)}};e.fn.smartresize=function(j){return j?this.bind("smartresize",j):this.trigger("smartresize",["execAsap"])};e.fn.masonry=function(j,l){var g=
+{getBricks:function(d,b,a){var c=a.itemSelector===undefined;b.$bricks=a.appendedContent===undefined?c?d.children():d.find(a.itemSelector):c?a.appendedContent:a.appendedContent.filter(a.itemSelector)},placeBrick:function(d,b,a,c,h){b=Math.min.apply(Math,a);for(var i=b+d.outerHeight(true),f=a.length,k=f,m=c.colCount+1-f;f--;)if(a[f]==b)k=f;d.applyStyle({left:c.colW*k+c.posLeft,top:b},e.extend(true,{},h.animationOptions));for(f=0;f<m;f++)c.colY[k+f]=i},setup:function(d,b,a){g.getBricks(d,a,b);if(a.masoned)a.previousData=
+d.data("masonry");a.colW=b.columnWidth===undefined?a.masoned?a.previousData.colW:a.$bricks.outerWidth(true):b.columnWidth;a.colCount=Math.floor(d.width()/a.colW);a.colCount=Math.max(a.colCount,1)},arrange:function(d,b,a){var c;if(!a.masoned||b.appendedContent!==undefined)a.$bricks.css("position","absolute");if(a.masoned){a.posTop=a.previousData.posTop;a.posLeft=a.previousData.posLeft}else{d.css("position","relative");var h=e(document.createElement("div"));d.prepend(h);a.posTop=Math.round(h.position().top);
+a.posLeft=Math.round(h.position().left);h.remove()}if(a.masoned&&b.appendedContent!==undefined){a.colY=a.previousData.colY;for(c=a.previousData.colCount;c<a.colCount;c++)a.colY[c]=a.posTop}else{a.colY=[];for(c=a.colCount;c--;)a.colY.push(a.posTop)}e.fn.applyStyle=a.masoned&&b.animate?e.fn.animate:e.fn.css;b.singleMode?a.$bricks.each(function(){var i=e(this);g.placeBrick(i,a.colCount,a.colY,a,b)}):a.$bricks.each(function(){var i=e(this),f=Math.ceil(i.outerWidth(true)/a.colW);f=Math.min(f,a.colCount);
+if(f===1)g.placeBrick(i,a.colCount,a.colY,a,b);else{var k=a.colCount+1-f,m=[];for(c=0;c<k;c++){var p=a.colY.slice(c,c+f);m[c]=Math.max.apply(Math,p)}g.placeBrick(i,k,m,a,b)}});a.wallH=Math.max.apply(Math,a.colY);d.applyStyle({height:a.wallH-a.posTop},e.extend(true,[],b.animationOptions));a.masoned||setTimeout(function(){d.addClass("masoned")},1);l.call(a.$bricks);d.data("masonry",a)},resize:function(d,b,a){a.masoned=!!d.data("masonry");var c=d.data("masonry").colCount;g.setup(d,b,a);a.colCount!=c&&
+g.arrange(d,b,a)}};return this.each(function(){var d=e(this),b={};b.masoned=!!d.data("masonry");var a=b.masoned?d.data("masonry").options:{},c=e.extend({},e.fn.masonry.defaults,a,j),h=a.resizeable;b.options=c.saveOptions?c:a;l=l||function(){};g.getBricks(d,b,c);if(!b.$bricks.length)return this;g.setup(d,c,b);g.arrange(d,c,b);!h&&c.resizeable&&e(window).bind("smartresize.masonry",function(){g.resize(d,c,b)});h&&!c.resizeable&&e(window).unbind("smartresize.masonry")})};e.fn.masonry.defaults={singleMode:false,
+columnWidth:undefined,itemSelector:undefined,appendedContent:undefined,saveOptions:true,resizeable:true,animate:false,animationOptions:{}}})(jQuery);
\ No newline at end of file
--- /dev/null
+jquery.masonry-1.3.2.js
\ No newline at end of file
@task
-def data():
- "Convert all yaml files to json."
+def build_data():
+ "Convert all yaml files to json"
info('Building data files...')
for dirpath, dirs, files in os.walk(DATA_DIR):
indir = path(dirpath)
out = outdir / f.replace('.yaml', '.json')
with in_.open('rU') as infile, out.open('w') as outfile:
json.dump(yaml.load(infile), outfile, indent=4)
+
+ info('Injecting config JSON...')
+ conf = path('build/tanks/config.js')
+ conf_json = path('build/data/config.json')
+ with conf.open('rU') as f:
+ conf_txt = f.read()
+ with conf_json.open('rU') as jf, conf.open('w') as out:
+ conf_data = jf.read()
+ out.write( conf_txt.replace('/*CONFIG_JSON*/', conf_data) )
@task
-@needs('data')
-def build():
- "Builds the Tanks project"
+def build_scripts():
+ "Builds js modules"
info('Building scripts...')
+ sh('rm build/tanks/config.js')
tags = commonjs(script_tags=True, capture=True)
with path('www/deps.html').open('w') as f:
f.write(tags)
@task
+@needs('build_data')
+@needs('build_scripts')
+def build():
+ "Builds the Tanks project"
+ pass
+
+
+@task
def clean():
"Cleans dep cache and build files"
commonjs(clean=True)
acc, this);
},
+ /**
+ * Iterates over both items and groups of the config object
+ * in order, sorted lexographically on key.
+ */
+ sorted : function sorted(groupFn, itemFn, acc, context){
+ context = context || this;
+ return this._sorted(new Y.YArray(), this._o, groupFn, itemFn, acc, context);
+ },
+
+ _sorted : function _sorted(path, obj, groupFn, itemFn, acc, context){
+ var self = this
+ , keys = (Y.isFunction(obj.keys) ? obj.keys() : Object.keys(obj)).sort();
+ return keys.reduce(function __sorted(acc, k){
+ var chain = path.push(k).join('.')
+ , v = self.getNested(chain)
+ ;
+
+ // Nested object -- recurse
+ if ( Y.isPlainObject(v) ){
+ acc = groupFn.call(context, acc, v, chain, self);
+ acc = self._sorted(path, v, groupFn, itemFn, acc, context);
+
+ // Normal value -- invoke iterator
+ } else
+ acc = itemFn.call(context, acc, v, chain, self);
+
+ path.pop();
+ return acc;
+ }, acc);
+ },
+
getDefault : function getDefault(k, def){
return getNested(this._defaults, k, def);
},
this.id = chain;
this.def = def;
this.val = this.old = val === undefined ? def : val;
- this.key = chain.split('.').pop();
- this.label = camelToSpaces(this.key);
+ this.key = chain.replace('.', '_');
+ this.label = camelToSpaces(chain.split('.').pop());
var T = Y.typeName(def);
this.cast = options.cast || type2parser[T];
this.build()
.update(this.val);
- this.elField.bind('change', this.onChange.bind(this));
+ jQuery(this.selector).live('change', this.onChange.bind(this));
},
build : function build(){
})
.val(this.val)
.appendTo(el);
+ this.selector = 'input[name='+this.key+']';
return this;
},
update : function update(val){
- var el = this.elField;
+ var el = jQuery(this.selector);
if (val !== this.val) {
this.old = this.val;
this.val = val;
'key' : this.id,
'oldval' : this.old,
'newval' : this.val,
- 'el' : this.elField
+ 'el' : jQuery(this.selector)
});
el.val(val);
}
},
onChange : function onChange(evt){
+ var el = jQuery(this.selector);
if (this.type === 'checkbox')
- this.update( this.elField.attr('checked') );
+ this.update( el.attr('checked') );
else
- this.update( this.cast(this.elField.val()) );
+ this.update( this.cast(el.val()) );
}
})
create =
exports['create'] =
function create(config, el){
- var fields = {};
- config.parts(
+ var data = {}
+ , groups = data.groups = {}
+ , fields = data.fields = {};
+ config.sorted(
function createGroup(oldGroup, value, chain){
- return jQuery('<fieldset/>')
+ var g =
+ groups[chain] =
+ jQuery('<fieldset/>')
.attr('id', chain)
.addClass('group')
.append( jQuery('<legend/>').text(chain.split('.').pop()) )
.appendTo(el);
+ return g;
},
function createField(group, value, chain){
var def = config.getDefault(chain)
return group;
},
el);
- return fields;
+ return data;
}
;
if ( o[name] === value )
return name;
return -1;
- }
+ },
+
+ 'unzipped' : function unzipped(){
+ return this.reduce(function(acc, v, k){
+ acc.keys.push(k);
+ acc.values.push(v);
+ return acc;
+ }, { 'keys':[], 'values':[] });
+ },
+ 'keys' : function keys(){
+ return this.unzipped().keys;
+ },
+
+ 'values' : function values(){
+ return this.unzipped().values;
+ }
});
path : '',
- init : function initDataFile(path){
+ init : function initDataFile(path, datastore){
this.path = path;
+ this.datastore = datastore;
},
load : function load(){
var types = Y(data.types)
, defaults = data.defaults || {}
- , lookup = this.resolve(data.lookup)
;
if (!(types && Y.isFunction(types.forEach)))
this.die('Specified types are not iterable! '+data.types);
types.forEach(function(kv, id){
- // TODO: process 'inherits' key -- requires resolving data-type path
var props = Y.extend({}, deepcopy(data.defaults), kv)
, symbol = props.symbol;
this.die('Cannot create types from data (symbol-class '+base+' from "'+symbol+'" is not Speciated)!');
var type = base.speciate(id, props);
- lookup[id] = type;
+ this.datastore[id] = type;
// console.log('Added type '+id+':', type);
}, this);
return;
var job = self.queue.shift();
+ // console.log(self+'.nextJob() --> '+job);
job.addEventListener('complete', function onJobComplete(evt){
// console.log(self+'.onJobComplete('+job+')');
job.removeEventListener('complete', arguments.callee);
// -*- mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; -*-
+//#exports defaults config dataLoader
var Y = require('Y').Y
+, ensure = require('Y/types/object').ensure
, Config = require('Y/modules/y.config').Config
, Vec = require('ezl/math').Vec
/// Config (Inserted Here) ///
+
defaults =
-exports['defaults'] = {
- game : {
- timeDilation : 1.0,
- gameoverDelay : 1000
- },
- ui : {
- createGridCanvas : true,
- createGridTable : false,
- overlayOnPause : true,
- showGridCoords : false,
- showAttackCooldown : false,
- showCountdown : (document.location.host.toString() !== 'tanks.woo')
- },
- pathing : {
- gridSquare : REF_SIZE,
- gridSquareMid : new Vec(REF_SIZE/2, REF_SIZE/2),
- overlayAiPaths : false,
- overlayPathmap : false,
- traceTrajectories : false
- }
-}
+exports['defaults'] = /*CONFIG_JSON*/
,
config =
var sq = evt.data.newval;
config.set('pathing.gridSquareMid', new Vec(sq/2, sq/2));
});
-
+config.set('pathing.gridSquare', config.get('pathing.gridSquare'));
/// Load Data Files ///
-var files =
- 'types/buffs types/items types/units types/levels' // levels game
- .split(' ')
- .map(function(type){
- return new DataFile('build/data/'+type+'.json');
- });
+var loader;
+exports['dataLoader'] = function dataLoader(){
+ if (!loader){
+ var files =
+ 'types/buffs types/items types/bullets types/units types/levels' // levels game
+ .split(' ')
+ .map(function(type){
+ var name = type.split('/').pop();
+ ensure(tanks.data, name);
+ return new DataFile('build/data/'+type+'.json', tanks.data[name]);
+ });
+ loader = new Loader(files);
+ }
+ return loader;
+};
-exports['dataLoader'] = new Loader(files);
},
+ debugTick : function debugTick(evt){
+ try {
+ this.tick(evt);
+ } catch(ex) {
+ console.error('tick('+evt+') '+ex, ex);
+ }
+ },
+
tickAnimations : function tickAnimations(animation){
var running = animation.tick(ELAPSED, NOW);
if (!running)
, Line = math.Line
, config = require('tanks/config').config
-, map = require('tanks/map/map')
-, Map = map.Map
+, PathingType = require('tanks/constants').PathingType
+, Map = require('tanks/map/map').Map
, Wall = require('tanks/thing/wall').Wall
* @private
*/
_filterBlocked : function filterBlocked(v, r){
- return v.blocking === map.BLOCKING && !v.isBoundary;
+ return v.blocking === PathingType.BLOCKING && !v.isBoundary;
},
getNeighbors : function getNeighbors(){
var Y = require('Y').Y
-, map = require('tanks/map/map')
+, PathingType = require('tanks/constants').PathingType
,
Traversal =
var blocking = blocker.blocking;
// All blockers after the first are ignored
- if ( this.ignore.has(blocker) || blocking === map.PASSABLE || this.isBlocked )
+ if ( this.ignore.has(blocker) || blocking === PathingType.PASSABLE || this.isBlocked )
return false;
// Only fire collision with this zone once per traversal
// XXX: Zone will have to manage enterance/exit and provide a method for testing, hm -- this would obviate the main need for this.ignore
- if ( blocking === map.ZONE ) {
+ if ( blocking === PathingType.ZONE ) {
this.ignore.push(blocker);
this.collide(blocker);
return false;
tags : [],
__static__ : {
+ __species_id__ : 0,
+
id2name : function id2name(id){
+ if (typeof id === 'number')
+ return this.className+id;
var name = id+'';
// TODO: all YString methods to return YString :P But it'll proally break shit
name = Y(name).capitalize();
},
speciate : function speciate(id, props){
+ if ( arguments.length < 2 ) {
+ props = id;
+ id = this.__species_id__++;
+ }
+
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; // reserved for instance id
var cls = this
, speciesName = this.id2name(id)
, Circle = shape.Circle
, config = require('tanks/config').config
-, map = require('tanks/map/map')
+, PathingType = require('tanks/constants').PathingType
, stat = require('tanks/effects/stat')
, Thing = require('tanks/thing/thing').Thing
},
// Instance
- blocking : map.BLOCKING,
+ blocking : PathingType.BLOCKING,
isRenderable : true,
bounces : 0,
width : 6,
height : 6,
+ color: '#FFF6AE',
+
stats : {
move : 2.0 // move speed (squares/sec)
},
Thing.init.call(this, owner.align);
- // var loc = owner.getTurretLoc()
- // , x1 = loc.x, y1 = loc.y;
-
this.position(x1,y1);
this.trajectory = new Trajectory(this, x1,y1, x2,y2, this.movePerMs);
;
// Ignore collisions with zones
- if (unit.blocking === map.ZONE)
+ if (unit.blocking === PathingType.ZONE)
return;
// Reflection!
var loc = this.loc;
this.shape = new Circle(this.width/2)
.position(loc.x, loc.y)
- .fill('#FFF6AE')
+ .fill(this.color)
.appendTo( parent );
this.shape.layer.attr('title', ''+loc);
+++ /dev/null
-var Tank = require('tanks/thing/tank').Tank
-,
-
-CustomTank =
-exports['CustomTank'] =
-Tank.subclass('CustomTank', {
-
- init : function initCustomTank(align, script){
- Tank.init.call(this, align);
- this.act = eval('(function(){ with(this){'+script+'} })');
- }
-
-});
--- /dev/null
+var Y = require('Y').Y
+, op = require('Y/op')
+, Rect = require('ezl/shape').Rect
+, Wall = require('tanks/thing/wall').Wall
+,
+
+
+Fence =
+exports['Fence'] =
+Wall.subclass('Fence', {
+ align : 0, // 0 reserved for neutral units
+
+ originX : 0,
+ originY : 0,
+
+ isReflective : true,
+ isRenderable : true,
+
+ // inactive
+ active : false,
+ createCooldowns : op.nop,
+
+ // indestructable
+ dealDamage : op.nop,
+
+ stats : {
+ hp : Infinity,
+ move : 0,
+ power : 0,
+ speed : 0,
+ shots : 0
+ },
+
+ // Instance
+
+ isBoundary : false,
+
+
+
+ init : function initFence(x,y, w,h){
+ this.width = w;
+ this.height = h;
+ this.isBoundary = !!isBoundary;
+ Wall.init.call(this, x,y, w,h);
+ this.position(x,y);
+ },
+
+
+
+ render : function render(parent){
+ if (this.isBoundary)
+ return this;
+
+ if (this.shape)
+ this.shape.remove();
+
+ this.shape =
+ new Rect(this.width, this.height)
+ .position(this.loc.x, this.loc.y)
+ .fill('rgba(0,0,0, 0.25)')
+ .stroke('transparent', 0)
+ .appendTo( parent );
+
+ return this;
+ },
+
+ toString : function(){
+ var bb = this.bbox
+ , x1,y1, x2,y2;
+ if (bb){
+ x1 = bb.x1; y1 = bb.y1;
+ x2 = bb.x2; y2 = bb.y2;
+ } else {
+ x1=y1=x2=y2=NaN;
+ }
+ return this.className+'['+x1+','+y1+', '+x2+','+y2+'](w='+this.width+', h='+this.height+')';
+ }
+});
+
-var Y = require('Y').Y
-, op = require('Y/op')
+var Y = require('Y').Y
+, op = require('Y/op')
-, shape = require('ezl/shape')
-, Rect = shape.Rect
+, shape = require('ezl/shape')
+, Rect = shape.Rect
-, map = require('tanks/map/map')
-, Buff = require('tanks/effects/buff').Buff
-, Thing = require('tanks/thing/thing').Thing
+, PathingType = require('tanks/constants').PathingType
+, Buff = require('tanks/effects/buff').Buff
+, Thing = require('tanks/thing/thing').Thing
, ITEM_SIZE = REF_SIZE * 0.5
,
align : 0, // 0 reserved for neutral units
- blocking : map.ZONE,
+ blocking : PathingType.ZONE,
width : ITEM_SIZE,
height : ITEM_SIZE,
//#ensure "jquery"
//#ensure "jquery.hotkeys"
-var Y = require('Y').Y
-, map = require('tanks/map/map')
-, Tank = require('tanks/thing/tank').Tank
+var Y = require('Y').Y
+, Tank = require('tanks/thing/tank').Tank
, Inventoried = require('tanks/mixins/inventoried').Inventoried
,
Tank.subclass('Player', {
__mixins__ : [ Inventoried ],
- blocking : map.BLOCKING,
-
// Attributes
stats: {
hp : 1, // health
, Rect = shape.Rect
, Circle = shape.Circle
-, map = require('tanks/map/map')
, Thing = require('tanks/thing/thing').Thing
, Bullet = require('tanks/thing/bullet').Bullet
, Trajectory = require('tanks/map/trajectory').Trajectory
},
// Bounding box
- blocking : map.BLOCKING,
width : REF_SIZE*0.55,
height : REF_SIZE*0.55,
shootEnemy : 0.75 // shoot at enemy tank if in range
},
- &nb