From 82ef9edaee06a252485b1177303a8e32e00f66ae Mon Sep 17 00:00:00 2001 From: dsc Date: Fri, 31 Dec 2010 19:29:59 -0800 Subject: [PATCH] Adds Buff & Stat class --- doc/notes.md | 1 - src/Y/class.cjs | 25 +++++++- src/Y/types/array.cjs | 12 ++-- src/Y/types/string.cjs | 6 +- src/Y/utils.cjs | 14 ++-- src/ezl/layer/layer.cjs | 12 ++-- src/tanks/constants.cjs | 39 +++++++++++ src/tanks/effects/buff.cjs | 60 +++++++++++++++++ src/tanks/effects/stat.cjs | 127 +++++++++++++++++++++++++++++++++++++ src/tanks/game.cjs | 20 +++--- src/tanks/globals.js | 14 ++++ src/tanks/map/map.cjs | 19 +++++- src/tanks/map/pathmap.cjs | 24 +------ src/tanks/map/trajectory.cjs | 2 +- src/tanks/map/traversal.cjs | 4 +- src/tanks/thing/bullet.cjs | 8 +- src/tanks/thing/tank.cjs | 12 ++-- src/tanks/thing/thing.cjs | 48 +++++++++++--- src/tanks/thing/wall.cjs | 2 +- www/header.html | 1 + www/test/shapes/test-shapes.js | 4 +- 21 files changed, 371 insertions(+), 83 deletions(-) create mode 100644 src/tanks/constants.cjs create mode 100644 src/tanks/effects/stat.cjs create mode 100644 src/tanks/mixins/configurable.cjs create mode 100644 src/tanks/mixins/informative.cjs create mode 100644 src/tanks/mixins/meronomic.cjs create mode 100644 src/tanks/mixins/speciated.cjs create mode 100644 src/tanks/mixins/usable.cjs delete mode 100644 src/tanks/thing/zone.cjs diff --git a/doc/notes.md b/doc/notes.md index 2c03c50..fc55836 100644 --- a/doc/notes.md +++ b/doc/notes.md @@ -6,7 +6,6 @@ - Config-driven unit-types (name, stats, properties; pointers to behavior scripts, assets) - Game scoring - Support touch events (for iPad?) -- Migrate A* code into PathMap # Code Notes diff --git a/src/Y/class.cjs b/src/Y/class.cjs index 73015eb..6848b76 100644 --- a/src/Y/class.cjs +++ b/src/Y/class.cjs @@ -195,10 +195,33 @@ Class.fn.subclass = YFunction(subclass); }); +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. */ -var YBase = new Class("YBase", { +YBase = new Class("YBase", { __y__ : true }); diff --git a/src/Y/types/array.cjs b/src/Y/types/array.cjs index 8b6fc0a..0f2700c 100644 --- a/src/Y/types/array.cjs +++ b/src/Y/types/array.cjs @@ -2,7 +2,7 @@ var Y = require('Y/y').Y , del = require('Y/delegate') , type = require('Y/type') , op = require('Y/op') -, mixin = require('Y/utils').mixin +, mixInto = require('Y/utils').mixInto , YCollection = require('Y/types/collection').YCollection , _Array = Array @@ -19,15 +19,15 @@ YCollection.subclass('YArray', function(YArray){ var newYArray = YArray.instantiate.bind(YArray); - mixin({ target:YArray, donor:_Array, context:'_o', + mixInto({ target:YArray, donor:_Array, context:'_o', names:'indexOf lastIndexOf shift pop join'.split(' ') }); - mixin({ target:YArray, donor:_Array, context:'_o', chain:true, + mixInto({ target:YArray, donor:_Array, context:'_o', chain:true, names:'push unshift sort splice reverse'.split(' ') }); - mixin({ target:YArray, donor:_Array, context:'_o', fnFirst:true, wrap:newYArray, + mixInto({ target:YArray, donor:_Array, context:'_o', fnFirst:true, wrap:newYArray, names:'map forEach filter'.split(' ') }); - mixin({ target:YArray, donor:_Array, context:'_o', fnFirst:true, + mixInto({ target:YArray, donor:_Array, context:'_o', fnFirst:true, names:['reduce', 'some', 'every'] }); - mixin({ target:YArray, donor:_Array, context:'_o', wrap:newYArray, + mixInto({ target:YArray, donor:_Array, context:'_o', wrap:newYArray, names:['slice'] }); diff --git a/src/Y/types/string.cjs b/src/Y/types/string.cjs index 4339f9a..5a82ff5 100644 --- a/src/Y/types/string.cjs +++ b/src/Y/types/string.cjs @@ -1,5 +1,5 @@ var YCollection = require('Y/types/collection').YCollection -, mixin = require('Y/utils').mixin +, mixInto = require('Y/utils').mixInto , op = require('Y/op') , core = require('Y/core') , del = require('Y/delegate') @@ -10,9 +10,9 @@ exports['YString'] = YCollection.subclass('YString', function(YString){ var newYString = YString.instantiate.bind(YString); - mixin({ target:YString, donor:String, context:'_o', wrap:newYString, + mixInto({ target:YString, donor:String, context:'_o', wrap:newYString, names:'slice substr substring concat replace toLowerCase toUpperCase'.split(' ') }); - mixin({ target:YString, donor:String, context:'_o', + mixInto({ target:YString, donor:String, context:'_o', names:'split indexOf lastIndexOf charAt charCodeAt'.split(' ') }); function trim(val){ diff --git a/src/Y/utils.cjs b/src/Y/utils.cjs index a27df65..0f01984 100644 --- a/src/Y/utils.cjs +++ b/src/Y/utils.cjs @@ -32,8 +32,8 @@ function bindAll(o, names){ var -This = mixin['This'] = {}, -Target = mixin['Target'] = {}, +This = mixInto['This'] = {}, +Target = mixInto['Target'] = {}, defaults = { /** * {Object|Function} target Required. Target object onto which methods will be added. If this a Function, it's prototype will be used. @@ -51,10 +51,10 @@ defaults = { 'names' : null, /** - * {mixin.This|mixin.Target|String} [context=mixin.This] + * {mixInto.This|mixInto.Target|String} [context=mixInto.This] * Sets the call context for the function. - * - {mixin.This}: (Default) Use runtime `this` as context. - * - {mixin.Target}: Use `target` as context. + * - {mixInto.This}: (Default) Use runtime `this` as context. + * - {mixInto.Target}: Use `target` as context. * - {String}: Names a property on `this` to use. If specified and property is false-y, `this` is used. */ 'context' : This, @@ -81,7 +81,7 @@ defaults = { */ 'fnFirst' : false }; -function mixin(options){ +function mixInto(options){ var o = core.extend({}, defaults, options) , target = o.target , donor = o.donor @@ -123,4 +123,4 @@ function mixin(options){ } exports['bindAll'] = bindAll; -exports['mixin'] = mixin; +exports['mixInto'] = mixInto; diff --git a/src/ezl/layer/layer.cjs b/src/ezl/layer/layer.cjs index 75d5408..beaa2ac 100644 --- a/src/ezl/layer/layer.cjs +++ b/src/ezl/layer/layer.cjs @@ -64,8 +64,8 @@ Y.subclass('Layer', { this.negBleed = new Loc(0,0); this.posBleed = new Loc(0,0); - this.boundingBox = new BoundingBox(0,0, 0,0, this.originX,this.originY); - this._origin = this.boundingBox.origin; + this.bbox = new BoundingBox(0,0, 0,0, this.originX,this.originY); + this._origin = this.bbox.origin; this.transform = { rotate : 0, @@ -172,7 +172,7 @@ Y.subclass('Layer', { this.layerWidth = w; this.layerHeight = h; - var bb = this.boundingBox.resize(w,h) + var bb = this.bbox.resize(w,h) , nb = this.negBleed, pb = this.posBleed // HTMLCanvas.{width,height} is a long @@ -204,7 +204,7 @@ Y.subclass('Layer', { this.layerWidth = w; - var bb = this.boundingBox.resize(w, this.layerHeight) + var bb = this.bbox.resize(w, this.layerHeight) // , ro = bb.relOrigin , nb = this.negBleed , cw = this.canvasWidth = Math.ceil(w + nb.x + this.posBleed.x); // HTMLCanvas.width is a long @@ -230,7 +230,7 @@ Y.subclass('Layer', { this.layerHeight = h; - var bb = this.boundingBox.resize(this.layerWidth, h) + var bb = this.bbox.resize(this.layerWidth, h) // , ro = bb.relOrigin , nb = this.negBleed , ch = this.canvasHeight = Math.ceil(h + nb.y + this.posBleed.y); // HTMLCanvas.height is a long @@ -279,7 +279,7 @@ Y.subclass('Layer', { x = ('left' in x ? x.left : x.x); } - var bbox = this.boundingBox.relocate(x,y); + var bbox = this.bbox.relocate(x,y); this.css({ 'left' : bbox.x1, 'top' : bbox.y1 diff --git a/src/tanks/constants.cjs b/src/tanks/constants.cjs new file mode 100644 index 0000000..d6eba26 --- /dev/null +++ b/src/tanks/constants.cjs @@ -0,0 +1,39 @@ +//#exports PathingType StatInvariant +require('Y').Y.extend(exports, { + + /// Pathing Constants /// + /** How this object interacts with the world. */ + PathingType : { + + /** Does not obstruct other objects. */ + PASSABLE : 0, + + /** Does not obstruct other objects, but still collides with them. */ + ZONE : 1, + + /** Obstructs other blockers with its BoundingBox. */ + BLOCKING : 2, + + /** Potentially obstructs other objects, but requires a special test once a BoundingBox collision has been detected. */ + IRREGULAR : 3 + + }, + + /** + * Invariant to restore for the current value when modifying the base or max of a Stat. + * @see {tanks.effects.stat.Stat} for the default behavior of its methods. + */ + StatInvariant : { + + /** Do not change current value. */ + NONE : 1, + + /** Keep current value at the same ratio it was before the change. */ + RATIO : 2, + + /** Apply the full change to the current value. */ + FULL : 3 + + } + +}); \ No newline at end of file diff --git a/src/tanks/effects/buff.cjs b/src/tanks/effects/buff.cjs index e69de29..84375bb 100644 --- a/src/tanks/effects/buff.cjs +++ b/src/tanks/effects/buff.cjs @@ -0,0 +1,60 @@ +var Y = require('Y').Y +, + + +// Events: +// - live.{affect,stack} +// - die.{expire,dismiss,dispel} +Buff = +exports['Buff'] = +Y.subclass('Buff', { + // __mixins__: [ Informative, Speciated, Meronomic, Usable ], // Configurable? + + + /// Configurable /// + priority : 0, // Order of stat and effect application (lower is earlier) + stats : { + timeout : -1, + stacked : 1, + threat : 1 + }, + stat_mods : {}, // {stat : Number|Function} Modifications to stats + // 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 + target : null, // Agent to which the buff applies + + + + init : function initBuff(owner, target){ + this.owner = owner; + this.game = owner.game; + this.target = target; + this.created = this.game.NOW; + // XXX: Speciated mixin must clone objects + }, + + applyStatMods : function applyStatMods(modifier){ + modifier = modifier || 1; + Y(this.stat_mods).forEach(function(mod, name){ + var keyparts = name.split('_') + , key = parts[0] + , part = parts[1] || 'val' + ; + this.target.stats[key].modifyPart(part, modifier * mod); + }, this); + return this; + }, + + removeStatMods : function removeStatMods(){ + return this.applyStatMods(-1); + } + + // XXX: toString implemented by Informative? + +}) + + + diff --git a/src/tanks/effects/stat.cjs b/src/tanks/effects/stat.cjs new file mode 100644 index 0000000..3da9b06 --- /dev/null +++ b/src/tanks/effects/stat.cjs @@ -0,0 +1,127 @@ +var Y = require('Y').Y + +, StatInvariant = require('tanks/constants').StatInvariant + +, NONE = StatInvariant.NONE +, RATIO = StatInvariant.RATIO +, FULL = StatInvariant.FULL +, + + + +Stat = +exports['Stat'] = +Y.subclass('Stat', { + // __mixins__: [ Informative, Speciated, Meronomic, Usable ], // Configurable? + + integer : true, // if true, current value is rounded after a change + + base : 0, + val : 0, + max : 0, + + + init : function initStat(base, val, max, isFloat){ + this.base = base; + this.val = val !== undefined ? val : base; + this.max = max !== undefined ? max : base; + this.integer = !isFloat; + }, + + clone : function clone(){ + return new Stat(this.base, this.val, this.max, !this.integer); + }, + + /** + * Resets max value and current value to base value. + * @return {this} + */ + reset : function reset(){ + this.val = this.max = this.base; + return this; + }, + + /** + * @param {Number} dv Amount to add to current value. + * @return {this} + */ + modify : function modify(dv){ + var v = Math.min(this.max, this.val+dv); + this.val = (this.integer ? Math.round(v) : v); + return this; + }, + + /** + * @param {Number} dv Amount to add to base and max value. + * @param {StatInvariant} [inv=FULL] Invariant to restore for current value. + * @return {this} + */ + modifyBase : function modifyBase(dv, inv){ + this.base += dv; + return this.modifyMax(dv, inv || FULL); + }, + + /** + * @param {Number} dv Amount to add to current value. + * @param {StatInvariant} [inv=FULL] Invariant to restore for current value. + * @return {this} + */ + modifyMax : function modifyMax(dv, inv){ + var v = this.val + , oldmax = this.max; + this.max += dv; + + switch ( inv ) { + case NONE: break; + + case RATIO: + v = (v / oldmax) * this.max; + break; + + case FULL: + default: + v += dv; + break; + } + this.val = (this.integer ? Math.round(v) : v); + + return this; + }, + + modifyPart : function modifyPart(part, dv, inv){ + var method = + (part === 'max' ? 'modifyMax' : + (part === 'base' ? 'modifyBase' : 'modify')); + return this[method](dv, inv); + }, + + toString : function(){ + return this.val+'/'+this.max+(this.max !== this.base ? ' ['+this.base+']' : ''); + } + +}) +; + +Stat.fn.modifyVal = Stat.fn.modify; + + +Stat['from'] = +function fromValue(v){ + if ( v instanceof Stat ) + return v.clone(); + else if ( Y.isArray(v) ) + return new Stat(v[0], v[1], v[2], v[3]); + else + return new Stat(v); +}; + +/** + * Accepts any number of objects which are combined to make the new map of names to stats. + */ +exports['createStats'] = +function createStats(o){ + var stats = Y({}); + return stats + .extend.apply(stats, Y(arguments)) + .map(Stat.from); +}; diff --git a/src/tanks/game.cjs b/src/tanks/game.cjs index 3678225..b6d99ad 100644 --- a/src/tanks/game.cjs +++ b/src/tanks/game.cjs @@ -86,11 +86,11 @@ Y.subclass('Game', { var d = evt.data , self = this; - NOW = d.now; - ELAPSED = d.elapsed; - TICKS = d.ticks; - SECONDTH = ELAPSED / 1000; - SQUARETH = REF_SIZE * SECONDTH + NOW = this.NOW = d.now; + ELAPSED = this.ELAPSED = d.elapsed; + TICKS = this.TICKS = d.ticks; + SECONDTH = this.SECONDTH = ELAPSED / 1000; + SQUARETH = this.SQUARETH = REF_SIZE * SECONDTH this.active.invoke('updateCooldowns', ELAPSED, NOW); this.active.invoke('act', ELAPSED, NOW); @@ -103,7 +103,7 @@ Y.subclass('Game', { if ( this.player.dead ) this.gameover = 'lose'; - else if ( !this.units.filter('_.align !== 1 && !_.dead'.lambda()).size() ) + else if ( !this.units.filter('_.align !== 1 && !_.dead').size() ) this.gameover = 'win'; if ( this.gameover ) @@ -121,16 +121,16 @@ Y.subclass('Game', { return running; }, + + + // *** Agent Management *** // + addAnimation : function addAnimation(animation){ this.animations.push(animation); this.level.append(animation); return animation; }, - - - // *** Agent Management *** // - addThing : function addThing(unit, col,row){ if (unit instanceof Event) unit = unit.trigger; diff --git a/src/tanks/globals.js b/src/tanks/globals.js index cb949e5..b3863ba 100644 --- a/src/tanks/globals.js +++ b/src/tanks/globals.js @@ -19,6 +19,20 @@ var undefined , ELAPSED = MS_PER_FRAME // Time (ms) since previous tick , TICKS = 0 // Ticks since start of game +/// Pathing Constants (from tanks/map/map) /// + +/** Does not obstruct other objects. */ +, PASSABLE = 0 + +/** Does not obstruct other objects, but still collides with them. */ +, ZONE = 1 + +/** Obstructs other blockers with its BoundingBox. */ +, BLOCKING = 2 + +/** Potentially obstructs other objects, but requires a special test once a BoundingBox collision has been detected. */ +, IRREGULAR = 3 + /// Common Components of Computation /// diff --git a/src/tanks/map/map.cjs b/src/tanks/map/map.cjs index 5860a7a..feec7a3 100644 --- a/src/tanks/map/map.cjs +++ b/src/tanks/map/map.cjs @@ -23,8 +23,9 @@ QuadTree.subclass('Map', { addBlocker : function addBlocker(obj){ this.removeBlocker(obj); - var bb = obj.boundingBox; - if (obj.blocking && bb) + var pt = obj.blocking + , bb = obj.bbox ; + if (pt !== undefined && bb) obj.region = this.set(bb.x1,bb.y1, bb.x2,bb.y2, obj); return obj; }, @@ -35,6 +36,20 @@ QuadTree.subclass('Map', { delete obj.region; } return obj; + }, + + getBlockers : function getBlockers(x1,y1, x2,y2, ignore){ + if (x1 && x1.x1 !== undefined) { + ignore = y1; + y2 = x1.y2; x2 = x1.x2; + y1 = x1.y1; x1 = x1.x1; + } + var bs = this.get(x1,y1, x2,y2) + .filter('_.blocking === BLOCKING'); + if (ignore && bs.length) + return bs.remove.apply(bs, ignore || []); + else + return bs; } diff --git a/src/tanks/map/pathmap.cjs b/src/tanks/map/pathmap.cjs index c82075b..ceac819 100644 --- a/src/tanks/map/pathmap.cjs +++ b/src/tanks/map/pathmap.cjs @@ -40,15 +40,13 @@ Map.subclass('PathMap', { init : function init(level, x1,y1, x2,y2, capacity) { x1 -= 1; y1 -= 1; x2 += 1; y2 += 1; QuadTree.init.call(this, x1,y1, x2,y2, capacity); - + this._squares = {}; this.level = level; this.game = level.game; this.walls = level.walls; this.allWalls = level.allWalls; - this._squares = {}; - this.game.addEventListener('ready', this.setup.bind(this, x1,y1, x2,y2)); }, @@ -70,23 +68,9 @@ Map.subclass('PathMap', { this.boundaryWalls = Y.map(BWs, 'this.level.addWall.apply(this.level, _)', this); }, - getBlockers : function getBlockers(x1,y1, x2,y2, ignore){ - if (x1 && x1.x1 !== undefined) { - ignore = y1; - y2 = x1.y2; x2 = x1.x2; - y1 = x1.y1; x1 = x1.x1; - } - var bs = this.get(x1,y1, x2,y2) - .filter('_.blocking === 2'); // map.BLOCKING - if (ignore && bs.length) - return bs.remove.apply(bs, ignore || []); - else - return bs; - }, - wallObstructs : function wallObstructs(line){ return this.walls.some(function(wall){ - return wall.boundingBox.intersects(line); + return wall.bbox.intersects(line); }, this); }, @@ -160,7 +144,7 @@ Map.subclass('PathMap', { // Ensure we don't get stuck on a corner on our first step var first = path.first() - , bb = agent.boundingBox.relocated( vec.lerp(0.5, agent.loc,first) ) + , bb = agent.bbox.relocated( vec.lerp(0.5, agent.loc,first) ) , blockers = this.getBlockers(bb, [agent]); if (blockers.length) @@ -279,7 +263,7 @@ Y.subclass('Square', new Vec(0,0), { _blocked : function blocked(){ var pm = this.pathmap , agent = pm._agent - // , bb = agent.boundingBox + // , bb = agent.bbox // , origin = bb.relOrigin // , left = origin.x, right = bb.width - left diff --git a/src/tanks/map/trajectory.cjs b/src/tanks/map/trajectory.cjs index 72b4f9a..dcd416a 100644 --- a/src/tanks/map/trajectory.cjs +++ b/src/tanks/map/trajectory.cjs @@ -73,7 +73,7 @@ Line.subclass('Trajectory', { intersects : function intersects(x,y){ var o = x; if (o instanceof Thing) - return o.boundingBox.intersects(this); + return o.bbox.intersects(this); if (o instanceof Rect) return o.intersects(this); diff --git a/src/tanks/map/traversal.cjs b/src/tanks/map/traversal.cjs index c51d193..5f37d2a 100644 --- a/src/tanks/map/traversal.cjs +++ b/src/tanks/map/traversal.cjs @@ -21,7 +21,7 @@ Y.subclass('Traversal', { this.thing = thing; this.game = thing.game; this.pathmap = thing.game.pathmap; - this.bbox = thing.boundingBox.clone(); + this.bbox = thing.bbox.clone(); this.trajectory = trajectory || thing.trajectory; }, @@ -119,7 +119,7 @@ Y.subclass('Traversal', { rewind : function rewind(blocker){ var tr = this.trajectory , bb = this.bbox, st = this.start - , B = blocker.boundingBox + , B = blocker.bbox , to = this.to ; // Figure out which boundary of the blocker we crossed and calculate diff --git a/src/tanks/mixins/configurable.cjs b/src/tanks/mixins/configurable.cjs new file mode 100644 index 0000000..e69de29 diff --git a/src/tanks/mixins/informative.cjs b/src/tanks/mixins/informative.cjs new file mode 100644 index 0000000..e69de29 diff --git a/src/tanks/mixins/meronomic.cjs b/src/tanks/mixins/meronomic.cjs new file mode 100644 index 0000000..e69de29 diff --git a/src/tanks/mixins/speciated.cjs b/src/tanks/mixins/speciated.cjs new file mode 100644 index 0000000..e69de29 diff --git a/src/tanks/mixins/usable.cjs b/src/tanks/mixins/usable.cjs new file mode 100644 index 0000000..e69de29 diff --git a/src/tanks/thing/bullet.cjs b/src/tanks/thing/bullet.cjs index 22a02cc..be66bf0 100644 --- a/src/tanks/thing/bullet.cjs +++ b/src/tanks/thing/bullet.cjs @@ -8,14 +8,14 @@ var Y = require('Y').Y , Circle = shape.Circle , config = require('tanks/config').config -, thing = require('tanks/thing/thing') , map = require('tanks/map/map') +, stat = require('tanks/effects/stat') + +, Thing = require('tanks/thing/thing').Thing , Wall = require('tanks/thing/wall').Wall , Trajectory = require('tanks/map/trajectory').Trajectory , Traversal = require('tanks/map/traversal').Traversal , Explosion = require('tanks/fx/explosion').Explosion -, fillStats = thing.fillStats -, Thing = thing.Thing , @@ -67,7 +67,7 @@ Thing.subclass('Bullet', { }, createStats : function createStats(){ - this.stats = Y({}, fillStats(this.owner.stats), fillStats(this.stats) ); + this.stats = stat.createStats(this.owner.stats, this.stats); }, remove : function remove(){ diff --git a/src/tanks/thing/tank.cjs b/src/tanks/thing/tank.cjs index 9e69127..7dccbcc 100644 --- a/src/tanks/thing/tank.cjs +++ b/src/tanks/thing/tank.cjs @@ -212,7 +212,7 @@ Thing.subclass('Tank', function(Tank){ , wall = this.closestOf(this.game.pathmap.allWalls) , wmid = wall.midpoint - , lvl = this.game.level.boundingBox, w = lvl.width, h = lvl.height + , lvl = this.game.level.bbox, w = lvl.width, h = lvl.height , x = ((mid.x - wmid.x) > 0 ? w : 0) , y = ((mid.y - wmid.y) > 0 ? h : 0) , to = this.currentMove = trj.near(x,y); @@ -239,7 +239,7 @@ Thing.subclass('Tank', function(Tank){ fn = (fn || kTrue).toFunction(); var within = BULLET_MOVE_PER_FRAME*ticks - , bb = this.boundingBox + , bb = this.bbox , x1 = bb.x1 - within, y1 = bb.y1 - within , x2 = bb.x2 + within, y2 = bb.y2 + within ; @@ -281,7 +281,7 @@ Thing.subclass('Tank', function(Tank){ bullets = ( Y.isArray(bullets) ? bullets : [bullets] ); wiggle = wiggle || 0; - var tank = this, bb = this.boundingBox + var tank = this, bb = this.bbox , w = bb.width+wiggle, h = bb.height+wiggle ; // , w = (bb.width+wiggle)/2, h = (bb.height+wiggle)/2 ; @@ -319,7 +319,7 @@ Thing.subclass('Tank', function(Tank){ // var barrel = this.barrel // , loc = this.loc - // , bb = this.boundingBox + // , bb = this.bbox // , w2 = bb.width/2, h2 = bb.height/2 // , x0 = bb.x1+w2, y0 = bb.y1+h2 // @@ -327,7 +327,7 @@ Thing.subclass('Tank', function(Tank){ // , sin = Math.sin(theta), cos = Math.cos(theta) // // , x1 = x0 + w2*cos, y1 = y0 + h2*sin - // , sz = (barrel.boundingBox.width - w2)/2 + WIGGLE + // , sz = (barrel.bbox.width - w2)/2 + WIGGLE // , blockers = this.game.pathmap.get(x1-sz,y1-sz, x1+sz,y1+sz).remove(this) ; @@ -365,7 +365,7 @@ Thing.subclass('Tank', function(Tank){ , theta = barrel.transform.rotate , sin = Math.sin(theta), cos = Math.cos(theta) - , len = barrel.boundingBox.width + WIGGLE + , len = barrel.bbox.width + WIGGLE , x = loc.x + len*cos , y = loc.y + len*sin diff --git a/src/tanks/thing/thing.cjs b/src/tanks/thing/thing.cjs index 53945e3..6bcbc38 100644 --- a/src/tanks/thing/thing.cjs +++ b/src/tanks/thing/thing.cjs @@ -10,6 +10,7 @@ var Y = require('Y').Y , config = require('tanks/config').config , map = require('tanks/map/map') +, stat = require('tanks/effects/stat') , THING_ID = 0 , @@ -19,19 +20,24 @@ 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' + var k_ = k.rtrim('_max') + , k_max = k_+'_max' + , k_base = k_+'_base' ; - if ( k.endsWith('_max') ) { - if ( _stats[k_] === undefined ) - _stats[k_] = v; + if ( _stats[k_] === undefined ) + _stats[k_] = v; - } else if ( _stats[k_max] === undefined ) + if ( _stats[k_max] === undefined ) _stats[k_max] = v; + if ( _stats[k_base] === undefined ) + _stats[k_base] = _stats[k_max]; + return _stats; - }, Y.extend({}, stats)); + }, {}); } , @@ -71,7 +77,7 @@ exports['Thing'] = new evt.Class('Thing', { // Location loc : null, - boundingBox : null, + bbox : null, // Rotation (rads) rotation : 0, @@ -100,13 +106,33 @@ exports['Thing'] = new evt.Class('Thing', { createBoundingBox : function createBoundingBox(){ - this.boundingBox = new BoundingBox(0,0, this.width,this.height, this.originX,this.originY); + this.bbox = new BoundingBox(0,0, this.width,this.height, this.originX,this.originY); }, createStats : function createStats(){ - this.stats = fillStats(this.stats); + 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') ) + + }, + + _applyBuffStats : function _applyBuffStats(buff){ + Y(buff.stat_mods).forEach(this._applyStatMod, this); + }, + + _applyStatMod : function _applyStatMod(v, k){ + this.target.modifyStat(k, v); + } + + createCooldowns : function createCooldowns(){ this.cooldowns = { 'attack': new Cooldown(1000 * this.stats.speed) @@ -130,7 +156,7 @@ exports['Thing'] = new evt.Class('Thing', { if (x === undefined && y === undefined) return this.loc; - var bb = this.boundingBox.relocate(x,y) // in-place + var bb = this.bbox.relocate(x,y) // in-place , loc = this.loc = bb.absOrigin , mid = this.midpoint = bb.midpoint ; diff --git a/src/tanks/thing/wall.cjs b/src/tanks/thing/wall.cjs index b710e38..2349ea8 100644 --- a/src/tanks/thing/wall.cjs +++ b/src/tanks/thing/wall.cjs @@ -65,7 +65,7 @@ Thing.subclass('Wall', { }, toString : function(){ - var bb = this.boundingBox + var bb = this.bbox , x1,y1, x2,y2; if (bb){ x1 = bb.x1; y1 = bb.y1; diff --git a/src/tanks/thing/zone.cjs b/src/tanks/thing/zone.cjs deleted file mode 100644 index e69de29..0000000 diff --git a/www/header.html b/www/header.html index 5170b15..ea7a063 100644 --- a/www/header.html +++ b/www/header.html @@ -2,6 +2,7 @@ The Littlest Battletank + diff --git a/www/test/shapes/test-shapes.js b/www/test/shapes/test-shapes.js index 8fc9afa..746fc0a 100644 --- a/www/test/shapes/test-shapes.js +++ b/www/test/shapes/test-shapes.js @@ -41,13 +41,13 @@ $(function(){ .fromPoints(100,100, 150,150) .fill('#E73075') .appendTo(plot); - R.title(R.boundingBox+''); + R.title(R.bbox+''); C = new shape.Circle(25) .position(150,150) .fill('#2E62C9') .appendTo(plot); - C.title(C.boundingBox+''); + C.title(C.bbox+''); grid.draw(); -- 1.7.0.4