- type: fence
args: [210,210, 30,30]
- type: drywall
- args: [50,350, 100,100]
+ args: [50,350, 50,50]
+ - type: drywall
+ args: [100,350, 50,50]
+ - type: drywall
+ args: [50,400, 50,50]
+ - type: drywall
+ args: [100,400, 50,50]
- type: drywall
args: [150,300, 50,50]
units:
init : function initField(chain, def, val, options){
options = options || {};
this.__emitter__ = new Emitter(this);
+ this.onChange = this.onChange.bind(this);
this.id = chain;
this.def = def;
this.build()
.update(this.val);
- jQuery(this.selector).live('change', this.onChange.bind(this));
+ jQuery(this.selector).live('change', this.onChange);
},
build : function build(){
},
update : function update(val){
- var el = jQuery(this.selector);
+ var el = jQuery(this.selector).add(this.elField);
if (val !== this.val) {
this.old = this.val;
this.val = val;
'key' : this.id,
'oldval' : this.old,
'newval' : this.val,
- 'el' : jQuery(this.selector)
+ 'el' : el
});
el.val(val);
}
},
onChange : function onChange(evt){
- var el = jQuery(this.selector);
+ var el = jQuery(evt.target);
if (this.type === 'checkbox')
this.update( el.attr('checked') );
else
fields[chain] = field;
group.append(field.el);
config.addEventListener('set:'+chain, function onConfigSet(evt){
+ // console.log('Config at '+evt.data.key+' changed!', field, evt.newval, evt);
field.update(evt.data.newval);
});
field.addEventListener('change', function onFieldChange(evt){
+ // console.log('Field '+evt.data.key+' changed!', field, evt.newval, evt);
config.set(evt.data.key, evt.data.newval);
});
ctx : null,
animActive : null,
animQueue : null,
-
+ _erased : null,
layerWidth : 0, canvasWidth : 0,
layerHeight : 0, canvasHeight : 0,
this.children = new Y.YArray();
this.animActive = new Y.YArray();
this.animQueue = new Y.YArray();
+ this._erased = new Y.YArray();
this.loc = new Loc(0,0);
this.negBleed = new Loc(0,0);
*/
empty : function empty(ctx){
this.children.invoke('remove');
- this.clear(ctx);
+ this.clear(false, ctx);
return this;
},
this._openPath(_ctx);
this.render(_ctx);
this._closePath(_ctx);
+ this._erased.forEach(this._erase, this);
}
this.children.invoke('draw', ctx, force);
return this;
},
+ erase : function erase(x,y, w,h, alsoChildren){
+ this._erased.push({ 'x':x,'y':y, 'w':w,'h':h, 'alsoChildren':alsoChildren });
+ this.dirty = true;
+ if (alsoChildren)
+ this.children.invoke('erase', x,y, w,h, alsoChildren);
+ return this;
+ },
+
+ _erase : function _erase(args){
+ var x = args.x, y = args.y
+ , w = args.w, h = args.h;
+
+ if (w < 0) w = this.canvas.width() + w;
+ if (h < 0) h = this.canvas.height() + h;
+
+ this.ctx.beginPath();
+ this.ctx.clearRect(x,y, w,h);
+ this.ctx.closePath();
+ },
+
/**
* Clears this layer and optionally all children.
*/
- clear : function clear(ctx, clearChildren){
+ clear : function clear(alsoChildren, ctx){
var w = this.canvas.width()
, h = this.canvas.height();
ctx = ctx || this.ctx;
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(-w,-h, 2*w,2*h);
ctx.closePath();
- if (clearChildren)
+ if (alsoChildren)
this.children.invoke('clear');
return this;
},
},
/**
- * @param {Number} dv Amount to add to current value.
+ * @param {Number} v New value for this stat. Values above the max will be set to max.
* @return {this}
*/
- modify : function modify(dv){
- var v = Math.min(this.max, this.val+dv);
+ set : function set(v){
+ var v = Math.min(this.max, v);
this.val = (this.integer ? Math.round(v) : v);
this.ratio = this.val / this.max;
return this;
},
/**
+ * @param {Number} dv Amount to add to current value. Values above the max will be set to max.
+ * @return {this}
+ */
+ modify : function modify(dv){
+ return this.set(this.val+dv);
+ },
+
+ /**
* @param {Number} dv Amount to add to base and max value.
* @param {StatInvariant} [inv=FULL] Invariant to restore for current value.
* @return {this}
Drywall =
exports['Drywall'] =
Wall.subclass('Drywall', {
- minSplitSize : 25,
+ // config
+ minSplitSize : null,
+ get canSplit() { return (this.width > this.minSplitSize); },
+ // instance
isReflective : false,
isBoundary : false,
- isSplittable : true,
- fillColors : [[139,49,20], [245,154,180], [255,246,174]],
-
- fillStyle : 'rgba(249,190,0, 0.25)',
- strokeStyle : 'rgba(249,190,0, 0.5)',
+ fillStyle : 'rgba(196,167,158, 0.25)',
+ strokeStyle : 'rgba(0,0,0, 0.25)',
lineWidth : 1,
stats : {
- hp : 3,
+ hp : 1,
},
+
init : function initDrywall(x,y, w,h, hp){
- this.stats = Y.extend({}, this.stats);
- this.stats.hp = hp || this.stats.hp;
-
- var line = Math.round(Math.min(w,h) * 0.2);
- this.lineWidth = clamp(line, 1, 3);
-
+ this.lineWidth = clamp(Math.round(Math.min(w,h) * 0.2), 1, 3);
Wall.init.call(this, x,y, w,h, this.isBoundary);
- this.updateColor();
- },
-
- updateColor : function updateColor(){
- var L = this.fillColors.length-1
- , i = clamp(Math.floor(this.stats.hp.ratio*L), 0, L)
- , color = this.fillColors[i]
- ;
- this.fillStyle = 'rgba('+color.join(',')+', 0.25)';
- this.strokeStyle = 'rgba('+color.join(',')+', 0.50)';
- console.log(this+'color = '+this.fillStyle+' ('+i+')');
- return this;
},
- dealDamage : function dealDamage(d, source){
- Wall.fn.dealDamage.apply(this, arguments);
- if (!this.dead) {
- var old = this.fillStyle;
- if (old !== this.updateColor().fillStyle)
- this.render();
- }
- return this;
- },
-
- split : function split(gap){
- if (!this.isSplittable || this.width <= this.minSplitSize)
+ divide : function divide(){
+ if (!this.canSplit)
return this;
var _x = this.loc.x, _y = this.loc.y
, mx = _x+this.width, my = _y+this.height
, size = this.width * 0.5
- , gapX = gap ? gap.x : Infinity
- , gapY = gap ? gap.y : Infinity
- , hp = Math.max(Math.round(this.stats.hp.max * 0.5), 1.0)
-
- , x, y, nextX, nextY, wall
+ , x, y, wall
;
-
- // console.group(this+'.split()');
- // console.log('gap: ('+gapX+','+gapY+')');
- // console.log('loc: '+this.loc);
- // console.log('dim: w='+this.width+'; h='+this.height+'; size='+size);
- // console.log('max: x='+mx+'; y='+my);
- for (x = _x; x<mx; x=nextX) {
- nextX = x + size;
- for (y = _y; y<my; y=nextY){
- nextY = y + size;
- wall = new Drywall(x,y, size,size, hp);
- if ( !(x <= gapX && gapX <= nextX && y <= gapY && gapY <= nextY) ) {
- // console.log('Drywall('+x+','+y+', '+size+','+size+', '+hp+')');
-
- } else {
- // console.log('Gap! ('+x+' <= '+gapX+' <= '+nextX+') && ('+y+' <= '+gapY+' <= '+nextY+')');
- wall.dead = true;
- wall.split(gap).remove();
- this.game.killThing(wall);
- }
+ for (x = _x; x<mx; x+=size) {
+ for (y = _y; y<my; y+=size){
+ wall = new Drywall(x,y, size,size);
}
}
- // console.groupEnd();
return this;
},
});
+// Divide on death (if possible)
Drywall.addEventListener('destroy', function(evt){
- var d = evt.data
- , killer = d.killer
- , side = d.side
- , gap = killer && side && side.intersection(killer.trajectory);
- if (gap) evt.data.unit.split(gap);
+ evt.data.unit.divide();
});
+
config.updateOnChange('map.minSplitSize', Drywall.fn);
+
var Y = require('Y').Y
+, Rect = require('ezl/shape').Rect
, constants = require('tanks/constants')
, BoundsType = constants.BoundsType
Wall.subclass('Fence', {
isReflective : false,
- fillStyle : 'rgba(0,0,0, 0.25)',
- strokeStyle : 'transparent',
- lineWidth : 0,
+
+ shadowFillStyle : 'rgba(0,0,0, 0.10)',
+ shadowSize : 10,
+
+ fillStyle : 'rgba(0,0,0, 0.25)',
+ strokeStyle : 'rgba(0,0,0, 0.25)',
+ lineWidth : 0,
blocking : BoundsType.BLOCKING,
density : DensityType.SPARSE,
Wall.init.call(this, x,y, w,h, this.isBoundary);
},
+ render : function render(parent){
+ if (this.isBoundary)
+ return this;
+
+ if (this.shape) {
+ parent = parent || this.shape.parent;
+ this.shape.remove();
+ }
+
+ if (!parent)
+ return this;
+
+ this.shape =
+ new Rect(this.width, this.height)
+ .position(this.loc.x, this.loc.y)
+ .fill(this.fillStyle)
+ .stroke(this.strokeStyle, this.lineWidth)
+ .appendTo( parent );
+
+ var ss = this.shadowSize;
+ this.shadow =
+ new Rect(this.width, this.height)
+ .position(0,0)
+ .fill(this.shadowFillStyle)
+ .stroke(this.strokeStyle, this.lineWidth)
+ .erase(ss,ss, -ss,-ss)
+ .appendTo( this.shape );
+
+ return this;
+ },
+
+
toString : Wall.fn.toString
});
strokeStyle : 'transparent',
lineWidth : 0,
- renderWidth : 0,
- renderHeight : 0,
- renderOffsetX : 0,
- renderOffsetY : 0,
-
// inactive
active : false,
return this;
this.shape =
- new Rect( this.renderWidth || this.width, this.renderHeight || this.height )
- .position(this.loc.x + this.renderOffsetX, this.loc.y + this.renderOffsetY)
+ new Rect(this.width, this.height)
+ .position(this.loc.x, this.loc.y)
.fill(this.fillStyle)
.stroke(this.strokeStyle, this.lineWidth)
.appendTo( parent );
Wall.addEventListener('subclass',
function(evt){
var subcls = evt.data.child;
- // console.log('Wall.register('+Y(subcls.className).camelToSnake()+', '+subcls.className+')');
Wall.register(Y(subcls.className).camelToSnake(), subcls);
});
});
// Apply ordering
- Y(data.groups).invoke('remove');
+ var groupsSeen = {};
Y(ordering).forEach(function(k){
- data.groups[k].appendTo(el);
+ var g = groupsSeen[k] = data.groups[k];
+ g.appendTo(el);
});
// Attach leftovers
Y(data.groups).forEach(function(g, k){
- if ( !g.parent().length )
+ if ( !groupsSeen[k] )
g.appendTo(el);
});
, configui = require('tanks/ui/configui')
, Game = require('tanks/game').Game
, Tank = require('tanks/thing').Tank
+, Player = require('tanks/thing/player').Player
, HIDE = 0, SHOW = 1, TOGGLE = 2
overlay = $('#overlay');
updateOverlay( config.get('ui.overlayOnPause') );
config.addEventListener('set:ui.overlayOnPause', function(evt){ updateOverlay(evt.newval); });
+ config.addEventListener('set:ui.debug.showFpsGraph', function(evt){ updateUI('#info', evt.newval); });
- /// Debug ///
- if (qkv.ai) {
- $('#welcome').hide();
- $('#ai').toggle();
- $('#ai textarea')[0].focus();
- }
- if (qkv.debug || config.get('debug.showFpsGraph')) updateUI('#info', TOGGLE);
+ Player.addEventListener('create', function(evt){ P = evt.data.instance; });
- $('#ai .ready').bind('click', function(evt){
- try {
- var script = $('#customtank').val();
- Tank.prototype.act = eval('(function(){ with(this){'+script+'} })');
- $('#ai').hide();
- startGame();
- } catch(e) {
- alert('AI Error!\n'+e);
- }
- });
+ /// Debug ///
+ if (qkv.debug || config.get('debug.showFpsGraph'))
+ updateUI('#info', SHOW);
// Show debug menus
- $(document).bind('keydown', 'ctrl+d', function(evt){ updateUI('.debug', TOGGLE); });
- $(document).bind('keydown', 'ctrl+i', function(evt){ updateUI('#info', TOGGLE); });
+ $(document).bind('keydown', 'ctrl+d', function(evt){ updateUI('.debug', TOGGLE); });
+ $(document).bind('keydown', 'ctrl+i', function(evt){ updateUI('#info', TOGGLE); });
$(document).bind('keydown', 'ctrl+c', function(evt){ updateUI('#config', TOGGLE); });
// Don't fire on clicks in the debug menu
.find('.box')
.html('<h1>You Win!</h1><p></p><div class="restart pinkbutton rounded">Play Again</div>');
-
// Bind to all future restart buttons
$('#gameover .restart')
.live('click', function(evt){
startGame();
});
-
+ // Load all data files
cfg.dataLoader()
.addEventListener('complete', function(evt){
$('#loading').hide();
return false;
}
+function parseVisibility(v){
+ if (typeof v === 'number')
+ return v;
+ if (typeof v === 'string')
+ return parseInt(v);
+ return (v ? SHOW : HIDE);
+}
+
jQuery.fn.center = function centerJQ(){
var body = $('body');
this.css({
}
function updateUI(selector, action){
+ action = parseVisibility(action);
var el = $(selector);
if (action === TOGGLE){