From: dsc Date: Tue, 4 Jan 2011 11:29:16 +0000 (-0800) Subject: Resolves issue where attack cooldown would be consumed despite inability to fire... X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=5369bb3eb7593b56ee1cdc362a0752173d524f26;p=tanks.git Resolves issue where attack cooldown would be consumed despite inability to fire. Fixes synchronization issue with data files and speciation. --- diff --git a/data/types/buffs.yaml b/data/types/buffs.yaml index 231d445..9109b53 100644 --- a/data/types/buffs.yaml +++ b/data/types/buffs.yaml @@ -10,6 +10,7 @@ types: name: Speed Up desc: Speeds up your tank temporarily. tags: [ 'movement' ] + timeout: 5.0 stats: move: 2.0 effects: [] diff --git a/data/types/units.yaml b/data/types/units.yaml index 8016198..f62f730 100644 --- a/data/types/units.yaml +++ b/data/types/units.yaml @@ -28,7 +28,7 @@ types: tags: [ 'tank' ] symbol: tanks/thing/player.PlayerTank stats: - hp : 1 + hp : 10 move : 0.90 power : 1 speed : 0.5 diff --git a/pavement.py b/pavement.py index d0a9f0a..cfc0082 100755 --- a/pavement.py +++ b/pavement.py @@ -1,6 +1,6 @@ #!/usr/bin/env paver from paver.easy import * -import yaml, json, os +import yaml, json, os, sys BUILD_DIR = path('build') SRC_DIRS = [ path('src')/d for d in ('Y', 'ezl', 'tanks') ] @@ -22,6 +22,7 @@ def commonjs(*args, **kw): @task def data(): "Convert all yaml files to json." + info('Building data files...') for dirpath, dirs, files in os.walk(DATA_DIR): indir = path(dirpath) outdir = BUILD_DIR/dirpath @@ -34,11 +35,11 @@ def data(): with in_.open('rU') as infile, out.open('w') as outfile: json.dump(yaml.load(infile), outfile, indent=4) - @task @needs('data') def build(): "Builds the Tanks project" + info('Building scripts...') tags = commonjs(script_tags=True, capture=True) with path('www/deps.html').open('w') as f: f.write(tags) @@ -49,3 +50,4 @@ def clean(): commonjs(clean=True) build() +default = build diff --git a/src/ezl/util/data/datafile.cjs b/src/ezl/util/data/datafile.cjs index 0623e60..87c40a3 100644 --- a/src/ezl/util/data/datafile.cjs +++ b/src/ezl/util/data/datafile.cjs @@ -9,7 +9,7 @@ var Y = require('Y').Y DataFile = exports['DataFile'] = new evt.Class('DataFile', { - __bind__ : [ 'onLoad' ], + __bind__ : [ 'process' ], path : '', @@ -19,8 +19,8 @@ new evt.Class('DataFile', { }, load : function load(){ - this.fire('load', this); - jQuery.getJSON(this.path, this.onLoad); + this.fire('load'); + jQuery.getJSON(this.path, this.process); return this; }, @@ -46,7 +46,7 @@ new evt.Class('DataFile', { process : function process(data){ this.data = data; this.fire('process', data); - console.group('DataFile: processing '+this.path); + // console.group('DataFile: processing '+this.path); var types = Y(data.types) , defaults = data.defaults || {}; @@ -64,24 +64,19 @@ new evt.Class('DataFile', { delete props.symbol; var base = this.resolve(symbol) , type = base.speciate(id, props); - console.log('Added type '+id+':', type); + // console.log('Added type '+id+':', type); }, this); - console.groupEnd(); - this.fire('complete', this); + // console.groupEnd(); + this.fire('complete'); return this; }, - // TODO: repeat other jq events - onLoad : function onLoad(data){ - console.log(this+'.onLoad()'); - this.process(data); - }, - /** * @private */ die : function die(reason){ + this.fire('error', this, { 'reason':reason }); throw new Error(this+' Error: '+reason); }, diff --git a/src/ezl/util/data/loader.cjs b/src/ezl/util/data/loader.cjs index c5cd6d3..94e4186 100644 --- a/src/ezl/util/data/loader.cjs +++ b/src/ezl/util/data/loader.cjs @@ -85,9 +85,18 @@ new evt.Class('Loader', { nextJob : function nextJob(){ var self = this; // console.log(self+'.nextJob()'); + + if (self.running + && self.queue.length === 0 + && self.inFlight.length === 0 ) { + self.running = false; + self.fire('complete'); + return; + } + if ( !self.running || self.inFlight.length >= self.max - || !self.queue.length ) + || self.queue.length === 0 ) return; var job = self.queue.shift(); @@ -101,11 +110,7 @@ new evt.Class('Loader', { job.load(self); // Recurse until we've got enough in-flight, or we're out of queued jobs - if (!self.queue.length){ - this.running = false; - self.fire('complete'); - } else - self.nextJob(); + self.nextJob(); }, toString : function(){ diff --git a/src/tanks/config.cjs b/src/tanks/config.cjs index 65becea..91c40d3 100644 --- a/src/tanks/config.cjs +++ b/src/tanks/config.cjs @@ -46,14 +46,12 @@ config.addEventListener('set:pathing.gridSquare', function(evt){ /// Load Data Files /// -exports['loadDataFiles'] = - function loadDataFiles(){ - var files = - 'types/buffs types/items types/units' // types/level levels game - .split(' ') - .map(function(type){ - return new DataFile('build/data/'+type+'.json'); - }); - return new Loader(files).start(); - }; +var files = + 'types/buffs types/items types/units' // types/level levels game + .split(' ') + .map(function(type){ + return new DataFile('build/data/'+type+'.json'); + }); + +exports['dataLoader'] = new Loader(files); diff --git a/src/tanks/effects/buff.cjs b/src/tanks/effects/buff.cjs index 3d0b346..0841194 100644 --- a/src/tanks/effects/buff.cjs +++ b/src/tanks/effects/buff.cjs @@ -18,24 +18,20 @@ new evt.Class('Buff', { /// Configurable /// - priority : 0, // Order of stat and effect application (lower is earlier) // TODO: doesn't do anything - timeout : Infinity, - threat : 1, // TODO + priority : 0, // Order of stat and effect application (lower is earlier) // TODO: doesn't do anything + timeout : Infinity, // Duration until expires (seconds) + threat : 1, // TODO - // 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 + stats : {}, // {stat : Number|Function} Modifications to stats // TODO: functions + effects : [], // {Function...} Effects to trigger on affect // XXX: not sure why i need this... + triggers : {}, // {event : Effect} // maybe /// Instance /// name : '', owner : null, // Agent which originated the buff target : null, // Agent to which the buff applies game : null, - created : 0, + created : 0, // Creation timestamp init : function initBuff(target, owner){ @@ -44,7 +40,7 @@ new evt.Class('Buff', { this.owner = owner || target; this.created = this.game.NOW; - this.expires = this.created + this.timeout; + this.expires = this.created + this.timeout*1000; this.applyStatMods(); @@ -82,7 +78,7 @@ new evt.Class('Buff', { applyStatMods : function applyStatMods(modifier){ modifier = (modifier || 1); - Y(this.stat_mods).map(mul(modifier)).forEach(this._applyStatMod, this); + Y(this.stats).map(mul(modifier)).forEach(this._applyStatMod, this); return this; }, @@ -97,7 +93,13 @@ new evt.Class('Buff', { return this.applyStatMods(-1); } -}) +}); +Buff.addEventListener('speciate', + function onSpeciate(evt){ + var NewBuff = evt.data.species; + if (NewBuff.fn.timeout === -1) + NewBuff.fn.timeout = Infinity; + }); diff --git a/src/tanks/map/level.cjs b/src/tanks/map/level.cjs index 7524739..e5f56e9 100644 --- a/src/tanks/map/level.cjs +++ b/src/tanks/map/level.cjs @@ -41,16 +41,18 @@ Rect.subclass('Level', { "this.addWall.apply(this, Y.map(_, '*REF_SIZE'))", this ); - P = - game.player = game.addThing(new PlayerTank(1), 3,9); - // game.addThing(new Tank(1).colors('#4596FF', '#182B53', '#F25522'), 3,9); + P = + game.player = game.addThing(PlayerTank.create('player', 1), 3,9); + // game.addThing(Tank.create('blue', 1).colors('#4596FF', '#182B53', '#F25522'), 3,9); - E = - game.addThing(new Tank(2), 0,7); - game.addThing(new Tank(2), 1,0); - game.addThing(new Tank(2), 8,1); + E1 = + game.addThing(Tank.create('pink', 2), 0,7); + E2 = + game.addThing(Tank.create('pink', 2), 1,0); + E3 = + game.addThing(Tank.create('pink', 2), 8,1); - I = game.addThing(new Item(), 8,8); + I = game.addThing(Item.create('nitro'), 8,8); }, addWall : function addWall(x,y, w,h, isBoundary){ diff --git a/src/tanks/mixins/speciated.cjs b/src/tanks/mixins/speciated.cjs index 9a4ec24..b34d414 100644 --- a/src/tanks/mixins/speciated.cjs +++ b/src/tanks/mixins/speciated.cjs @@ -31,14 +31,16 @@ Mixin.subclass('Speciated', { , Species = this.__known__[id] = cls.subclass(speciesName, props) ; Species.__species_props__ = props; + + cls.fire('speciate', Species, { 'id':id, 'species':Species, 'cls':cls }); return Species; }, - lookupSpecies : function lookupSpecies(id){ + lookup : function lookup(id){ return this.__known__[id]; }, - createSpeciesInstance : function createSpeciesInstance(id){ + create : function create(id){ var args = Y(arguments,1) , Species = this.__known__[id]; return Species.instantiate.apply(Species, args); @@ -51,21 +53,8 @@ Mixin.subclass('Speciated', { cls.__known__ = {}; }, - // onCreate : 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+'])'; + return this.className+'(name='+this.name+', id='+this.__id__+', tags=['+this.tags+'])'; } }); diff --git a/src/tanks/thing/bullet.cjs b/src/tanks/thing/bullet.cjs index c56da30..9797b73 100644 --- a/src/tanks/thing/bullet.cjs +++ b/src/tanks/thing/bullet.cjs @@ -51,14 +51,14 @@ Thing.subclass('Bullet', { * @param {tanks.Unit} owner * @param {math.Line} trajectory */ - init : function initBullet(owner, x2,y2){ + init : function initBullet(owner, x1,y1, x2,y2){ this.owner = owner; this.game = owner.game; Thing.init.call(this, owner.align); - var loc = owner.getTurretLoc() - , x1 = loc.x, y1 = loc.y; + // 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); @@ -118,8 +118,6 @@ Thing.subclass('Bullet', { , unit = d.unit , tvsl = d.traversal , to = tvsl.to - - , isReflective = unit.isReflective ; // Ignore collisions with zones @@ -127,7 +125,7 @@ Thing.subclass('Bullet', { return; // Reflection! - if ( isReflective && this.bounceLimit >= ++this.bounces ) { + if ( unit.isReflective && this.bounceLimit >= ++this.bounces ) { if (!tvsl.side) return console.error('Null reflection line!', 'to:', to, 'blocker:', unit, 'blockers:', tvsl.blockers._o); @@ -151,13 +149,20 @@ Thing.subclass('Bullet', { , start = bsize, end = bsize ; - if (isReflective) { - x = loc.x; - y = loc.y; - } else { + if (unit instanceof Bullet) { x = math.lerp(0.5,loc.x,uloc.x); y = math.lerp(0.5,loc.y,uloc.y); + } else { + x = loc.x; + y = loc.y; } + // if (isReflective) { + // x = loc.x; + // y = loc.y; + // } else { + // x = math.lerp(0.5,loc.x,uloc.x); + // y = math.lerp(0.5,loc.y,uloc.y); + // } if ( unit.dead && asize >= bsize ) end = asize; diff --git a/src/tanks/thing/item.cjs b/src/tanks/thing/item.cjs index 02fbcf9..91f7e52 100644 --- a/src/tanks/thing/item.cjs +++ b/src/tanks/thing/item.cjs @@ -33,15 +33,12 @@ Thing.subclass('Item', { /// Instance Properties /// - type : 'dummy', // {String} Item type identifier (unique, for config lookup) name : 'Dummy', // {String} Display name icon_inv : '', // {String} URL to inventory icon file (TODO) icon_map : '', // {String} URL to map icon file (TODO) // {Buff...} Passive effects (triggered on pickup) - itemBuffs : Y([ - Buff - ]), + itemBuffs : Y([]), // {Function...} Active effects (triggered on activation) effects : Y([]), @@ -94,7 +91,7 @@ Thing.subclass('Item', { onAcquired : function onAcquired(evt){ this.owner = evt.data.unit; - console.log(this.owner+' acquired '+this+'!'); + console.log(this.owner+' acquired '+this+' ('+this.desc+')!'); this.currentBuffs = this.itemBuffs.invoke('instantiate', this.owner); this.destroy(); // removes map object }, @@ -125,7 +122,19 @@ Thing.subclass('Item', { }, toString : function(){ - return this.type+'(id='+this.id+', owner='+this.owner+')'; + return this.className+'(id='+this.id+', owner='+this.owner+')'; } -}) -; +}); + +Item.addEventListener('speciate', + function onSpeciate(evt){ + var NewItem = evt.data.species; + NewItem.fn.itemBuffs = + Y(NewItem.fn.buffs.map(function(buff){ + if (typeof buff == "string") + return Buff.lookup(buff); + else + return buff; + })); + }); + diff --git a/src/tanks/thing/tank.cjs b/src/tanks/thing/tank.cjs index 9a6094c..1762a12 100644 --- a/src/tanks/thing/tank.cjs +++ b/src/tanks/thing/tank.cjs @@ -25,6 +25,7 @@ var Y = require('Y').Y Tank = exports['Tank'] = Thing.subclass('Tank', function(Tank){ + // TODO: lookup projectile on Bullet Y.core.descriptors(this, { bodyColor : '#83BB32', @@ -301,33 +302,25 @@ Thing.subclass('Tank', function(Tank){ */ this['shoot'] = function shoot(x,y){ - var WIGGLE = 3 // additional space which must be clear in front of the barrel - , xydef = (x !== undefined && y !== undefined) - ; + if ( this.nShots >= this.stats.shots.val || !this.cooldowns.attack.ready ) + return null; - if (xydef) this.rotateBarrel(x,y); + var xydef = (x !== undefined && y !== undefined); + if (xydef) + this.rotateBarrel(x,y); - if ( this.nShots >= this.stats.shots.val || !this.cooldowns.attack.activate(this.now) ) - return null; + // Additional space on each side which must be clear around the + // shot to ensure we don't shoot ourself in the foot (literally) + var WIGGLE = 1 + , Projectile = this.projectile + , pw2 = Projectile.fn.width/2, ph2 = Projectile.fn.height/2 - var tloc = this.getTurretLoc() + , tloc = this.getTurretLoc() , tx = tloc.x, ty = tloc.y - , x1 = tx - WIGGLE, y1 = ty - WIGGLE - , x2 = tx + WIGGLE, y2 = ty + WIGGLE - , blockers = this.game.pathmap.get(x1,y1, x1,y1).remove(this) - - // var barrel = this.barrel - // , loc = this.loc - // , bb = this.bbox - // , w2 = bb.width/2, h2 = bb.height/2 - // , x0 = bb.x1+w2, y0 = bb.y1+h2 - // - // , theta = barrel.transform.rotate - // , sin = Math.sin(theta), cos = Math.cos(theta) - // - // , x1 = x0 + w2*cos, y1 = y0 + h2*sin - // , sz = (barrel.bbox.width - w2)/2 + WIGGLE - // , blockers = this.game.pathmap.get(x1-sz,y1-sz, x1+sz,y1+sz).remove(this) + + , x1 = tx - pw2 - WIGGLE, y1 = ty - ph2 - WIGGLE + , x2 = tx + pw2 + WIGGLE, y2 = ty + ph2 + WIGGLE + , blockers = this.game.pathmap.get(x1,y1, x2,y2).remove(this) ; if ( blockers.size() ) @@ -340,12 +333,11 @@ Thing.subclass('Tank', function(Tank){ y = ty + REF_SIZE*sin; } - var ProjectileType = this.projectile - , p = new ProjectileType(this, x,y); - + this.cooldowns.attack.activate(this.now); this.nShots++; - p.addEventListener('destroy', this.onBulletDeath); + var p = new Projectile(this, tx,ty, x,y); + p.addEventListener('destroy', this.onBulletDeath); this.game.addThing(p).render(this.game.level); return p; }; @@ -358,13 +350,17 @@ Thing.subclass('Tank', function(Tank){ this['getTurretLoc'] = function getTurretLoc(){ - var WIGGLE = 9 // 1.4 * 6 for max diagonal + var WIGGLE = 2 , loc = this.loc , barrel = this.barrel , theta = barrel.transform.rotate , sin = Math.sin(theta), cos = Math.cos(theta) - , len = barrel.bbox.width + WIGGLE + + // sqrt(2)/2 * (P.width + WIGGLE) + // is max diagonal to ensure we don't overlap with the firing unit + , pw = this.projectile.fn.width + , len = barrel.bbox.width + 0.707*(pw+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 bc537f6..f8c2305 100644 --- a/src/tanks/thing/thing.cjs +++ b/src/tanks/thing/thing.cjs @@ -47,7 +47,6 @@ new evt.Class('Thing', { // *** Bookkeeping *** // - id : 0, align : 0, // 0 reserved for neutral units dead : false, dirty : true, diff --git a/src/tanks/ui/main.cjs b/src/tanks/ui/main.cjs index 5b8972a..7f42c80 100644 --- a/src/tanks/ui/main.cjs +++ b/src/tanks/ui/main.cjs @@ -23,12 +23,7 @@ qkv = Y(window.location.search.slice(1)).fromKV(); // Main method is only executed once, so we'll setup things // that don't change between games. function main(){ - - // TODO: wait until completed to allow start - // TODO: loading screen - var configLoader = cfg.loadDataFiles(); - - $('#welcome').center(); + $('#welcome').center().hide(); /// Debug /// if (qkv.ai) { @@ -61,6 +56,13 @@ function main(){ // Build and bind config configui.init(); + // Create #loading box + $('#welcome').clone() + .attr('id', 'loading') + // .hide() + // .css({ 'top':'1em', 'left':'1em', 'margin':0, 'width':'auto' }) + .appendTo( $('body') ) + .find('.box').html('

Loading...

'); // Create #pause box $('#welcome').clone() @@ -88,11 +90,14 @@ function main(){ startGame(); }); - setupGame(); - setupUI(); - - // $('#welcome').hide(); - // $('#overlay').hide(); + cfg.dataLoader + .addEventListener('complete', function(evt){ + $('#loading').hide(); + $('#welcome').show(); + setupGame(); + setupUI(); + }) + .start(); } function gameExists(){ return !!tanks.game; } diff --git a/www/commonjs.php b/www/commonjs.php index e9af8be..9a1601f 100644 --- a/www/commonjs.php +++ b/www/commonjs.php @@ -21,5 +21,5 @@ $PYTHONPATH = implode(':', array_unique(array_reduce($PYTHON_SITE_PATHS, 'pyVers function commonjs($src, $root="..") { global $PYTHONPATH; - return shell_exec("cd $root && PYTHONPATH=$PYTHONPATH commonjs $src 2>&1"); + return shell_exec("cd $root && PYTHONPATH=$PYTHONPATH paver -q build 2>&1"); }