<commit_before>
canvasHeight = 450;
$(function(){
	animText = new AnimText(c);
	myCanvas.height = canvasHeight;
	renderer = new Renderer();
	window.curLevel = new TestLevel();
	curLevel.cutSceneEnd();
	curLevel.init();
	addJQueryElems($('button'), 'button');
	$('#resetExp').click(function(){curLevel.reset()});
	$('#toSim').click(function(){nextPrompt()});
	$('#toLastStep').click(function(){prevPrompt()});
	$('#previous').click(function(){prevPrompt()});
	$('#next').click(function(){nextPrompt()});
});

myCanvas.width = $('#main').width();

function TestLevel(){
	this.setStds();
	this.wallSpeed = 1;
	this.readouts = {};
	this.compMode = 'Isothermal';//is this used?

	addSpecies(['spc1', 'spc2', 'spc3', 'spc4', 'spc5', 'spc6']);
	this.yMin = 30;
	this.yMax = 350;
}
_.extend(TestLevel.prototype,
			LevelTools,
{
	init: function() {
		this.readout = new Readout('mainReadout', 30, myCanvas.width-130, 25, '13pt calibri', Col(255,255,255), 'left');
		$('#mainHeader').html('Level template');
		showPrompt(0, 0, true);
	},
	sections: [
				{
			sceneData: {
				walls: [
					{pts: [P(50, 50), P(400, 50), P(400, 350), P(50, 350)], handler: 'staticAdiabatic', handle: 'wally', border: {type: 'open', thickness: 5, yMin: 30}}
				],
				dots: [
					{spcName: 'spc1', pos: P(55, 55), dims: V(200, 200), count: 1, temp: 400, returnTo: 'wally', tag: 'wally'},
					{spcName: 'spc3', pos: P(55, 55), dims: V(200, 200), count: 1, temp: 400, returnTo: 'wally', tag: 'wally'}
				],
				objs: [
					{
						type: 'AuxImage',
						attrs: {handle: 'picci', slotNum: 1, imgFunc: 'img(img/work/block0Pic1.jpg)'}
					}
					// {
						// type: 'DragWeights',
						// attrs: {handle: 'draggy', wallInfo: 'wally', weightDefs: [{count: 2, pressure: 1}], pInit: 1}
					// },
					// {
						// type: 'Piston',
						// attrs: {handle: 'pistony', wallInfo: 'wally', min: 2, init: 4, max: 6}
					// }

				],
				dataDisplay: [
					{wallInfo: 'wally', data:'pInt', readout: 'mainReadout'}
				],
				cmmds: [
					//{type: 'DragWeights', handle: 'draggy', cmmd: 'dropAllOntoPiston', args: ['instant']}
				]
			},
			prompts: [
				{
					sceneData: {
						objs: [
							{
								type: 'AuxImage',
								attrs: {handle: 'piccy', slotNum: 1, imgFunc: 'img(img/refresh.gif)'}
							}

						],
						// listeners: [

							// {dataSet: {wallInfo: 'wally', data: 'pExt'}, is: 'equalTo', checkVal: 1, alertUnsatisfied: 'booo', satisfyCmmds: [{type: 'DragWeights', handle: 'draggy', cmmd: 'freeze'}]}

						// ],
						dataDisplay: [
							{wallInfo: "wally", data:'temp', readout: 'mainReadout'}
						]
					},
					quiz: [
						{
							type: 'textSmall',
							label: 'foo',
							text: 'hello',
							answer: 5,
							messageWrong: 'hello'

						}
					],
					title: 'wooo!',
					text: 'Hello, my lovlies! $$ \\frac{1}{2} $$  That was mathematical!'
				},
				{
					sceneData: undefined,
					title: 'wooo!',
					text: 'Why did the $$ \\int_3^\\frac{2}{3} 5dx $$ walk across the road?'
				},
				{
					sceneData: undefined,
					title: 'hello',
					text: 'this is text',
					quiz: [
						{
							type: 'multChoice',
							options: [
								{text: '$$x=5$$', isCorrect: true},

							]
						}

					]
				}
			]
		},
		{
			sceneData: {
				walls: [
					{pts: [P(50, 50), P(400, 50), P(400, 350), P(50, 350)], handler: 'staticAdiabatic', handle: 'wapple'}
				],
				dots: [
					{spcName: 'spc1', pos: P(55, 55), dims: V(200, 200), count: 199, temp: 300, returnTo: 'wapple', tag: 'wapple'}
				],
			},
			prompts: [
				{
					text: 'foo',
					title: 'goo'
				}

			]

		}

	]

}
)<commit_msg>added liq for demo<commit_after>
canvasHeight = 450;
$(function(){
	animText = new AnimText(c);
	myCanvas.height = canvasHeight;
	renderer = new Renderer();
	window.curLevel = new TestLevel();
	curLevel.cutSceneEnd();
	curLevel.init();
	addJQueryElems($('button'), 'button');
	$('#resetExp').click(function(){curLevel.reset()});
	$('#toSim').click(function(){nextPrompt()});
	$('#toLastStep').click(function(){prevPrompt()});
	$('#previous').click(function(){prevPrompt()});
	$('#next').click(function(){nextPrompt()});
});

myCanvas.width = $('#main').width();

function TestLevel(){
	this.setStds();
	this.wallSpeed = 1;
	this.readouts = {};
	this.compMode = 'Isothermal';//is this used?

	addSpecies(['spc1', 'spc2', 'spc3', 'spc4', 'spc5', 'spc6']);
	this.yMin = 30;
	this.yMax = 350;
}
_.extend(TestLevel.prototype,
			LevelTools,
{
	init: function() {
		this.readout = new Readout('mainReadout', 30, myCanvas.width-130, 25, '13pt calibri', Col(255,255,255), 'left');
		$('#mainHeader').html('Level template');
		showPrompt(0, 0, true);
	},
	sections: [
				{
			sceneData: {
				walls: [
					{pts: [P(50, 50), P(400, 50), P(400, 350), P(50, 350)], handler: 'staticAdiabatic', handle: 'wally', border: {type: 'open', thickness: 5, yMin: 30}}
				],
				dots: [
					{spcName: 'spc1', pos: P(55, 55), dims: V(200, 200), count: 1, temp: 400, returnTo: 'wally', tag: 'wally'},
					{spcName: 'spc3', pos: P(55, 55), dims: V(200, 200), count: 1, temp: 400, returnTo: 'wally', tag: 'wally'}
				],
				objs: [
					{
						type: 'AuxImage',
						attrs: {handle: 'picci', slotNum: 1, imgFunc: 'img(img/work/block0Pic1.jpg)'}
					},
					{
						type: 'Liquid',
						attrs:{wallInfo: 'wally', handle: 'swishy', tempInit: 330, spcInfo: {spc1: {count: 500, spcVol: .5, cP:75, antoineCoeffs: {a: 8.07, b: 1730.6, c: 233.4-273.15}, hVap: 40.65}, spc3: {count: 1000, spcVol: .7, cP:80, antoineCoeffs: {a: 8.20, b: 1642.89, c: 230.3-273.15}, hVap: 38.6}}, actCoeffType: 'twoSfxMrg', actCoeffInfo: {a: 3}}
					}
					// {
						// type: 'DragWeights',
						// attrs: {handle: 'draggy', wallInfo: 'wally', weightDefs: [{count: 2, pressure: 1}], pInit: 1}
					// },
					// {
						// type: 'Piston',
						// attrs: {handle: 'pistony', wallInfo: 'wally', min: 2, init: 4, max: 6}
					// }

				],
				dataDisplay: [
					{wallInfo: 'wally', data:'pInt', readout: 'mainReadout'}
				],
				cmmds: [
					//{type: 'DragWeights', handle: 'draggy', cmmd: 'dropAllOntoPiston', args: ['instant']}
				]
			},
			prompts: [
				{
					sceneData: {
						objs: [
							{
								type: 'AuxImage',
								attrs: {handle: 'piccy', slotNum: 1, imgFunc: 'img(img/refresh.gif)'}
							}

						],
						// listeners: [

							// {dataSet: {wallInfo: 'wally', data: 'pExt'}, is: 'equalTo', checkVal: 1, alertUnsatisfied: 'booo', satisfyCmmds: [{type: 'DragWeights', handle: 'draggy', cmmd: 'freeze'}]}

						// ],
						dataDisplay: [
							{wallInfo: "wally", data:'temp', readout: 'mainReadout'}
						]
					},
					quiz: [
						{
							type: 'textSmall',
							label: 'foo',
							text: 'hello',
							answer: 5,
							messageWrong: 'hello'

						}
					],
					title: 'wooo!',
					text: 'Hello, my lovlies! $$ \\frac{1}{2} $$  That was mathematical!'
				},
				{
					sceneData: undefined,
					title: 'wooo!',
					text: 'Why did the $$ \\int_3^\\frac{2}{3} 5dx $$ walk across the road?'
				},
				{
					sceneData: undefined,
					title: 'hello',
					text: 'this is text',
					quiz: [
						{
							type: 'multChoice',
							options: [
								{text: '$$x=5$$', isCorrect: true},

							]
						}

					]
				}
			]
		},
		{
			sceneData: {
				walls: [
					{pts: [P(50, 50), P(400, 50), P(400, 350), P(50, 350)], handler: 'staticAdiabatic', handle: 'wapple'}
				],
				dots: [
					{spcName: 'spc1', pos: P(55, 55), dims: V(200, 200), count: 199, temp: 300, returnTo: 'wapple', tag: 'wapple'}
				],
			},
			prompts: [
				{
					text: 'foo',
					title: 'goo'
				}

			]

		}

	]

}
)<|endoftext|>


<commit_before>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
  Base class for entities. Includes world position, rendering information, etc.
*/
foam.CLASS({
  package: 'tabletop',
  name: 'Entity',
  extends: 'foam.mlang.Expressions',
  axioms: [
    foam.pattern.Pooled.create(),
  ],
  requires: [
    'tabletop.EntityController',
    'tabletop.Sprite',
    'tabletop.ImageSprite',
    'tabletop.HP',
  ],
  imports: [
    'worldDAO',
    'audioManager',
    'canvas',
    'worldWidth',
    'worldHeight',
  ],

  properties: [
    {
      name: 'id',
      factory: function() { return this.$UID; }
    },
    { /** World coords */
      class: 'Simple',
      name: 'x',
    },
    { /** World coords */
      class: 'Simple',
      name: 'y',
    },
    { /** World relative */
      class: 'Simple',
      name: 'rotation',
    },

    { /** x velocity, world units/sec */
      class: 'Simple',
      name: 'vx',
    },
    { /** y velocity, world units/sec */
      class: 'Simple',
      name: 'vy',
    },
    { /** rotational velocity, radians/sec */
      class: 'Simple',
      name: 'vrotation',
    },

    { /** x acceleration, world units/sec */
      class: 'Simple',
      name: 'ax',
    },
    { /** y acceleration, world units/sec */
      class: 'Simple',
      name: 'ay',
    },
    { /** rotational acceleration, radians/sec */
      class: 'Simple',
      name: 'arotation',
    },

    { /** Computed, true if a new moveStep() call is needed */
      name: 'moveRequired',
      getter: function() {
        return !! (this.vx || this.vy || this.vrotation ||
          this.ax || this.ay || this.arotation);
      }
    },

    { /** Bounding box size (radius from x,y) */
      name: 'br',
    },
    { /** Axis aligned bounding box, World coords */
      name: 'bx',
      getter: function() {
        return this.x - this.br;
      }
    },
    { /** AABB, World coords */
      name: 'by',
      getter: function() {
        return this.y - this.br;
      }
    },
    { /** AABB, World coords */
      name: 'bx2',
      getter: function() {
        return this.x + this.br;
      }
    },
    { /** AABB, World coords */
      name: 'by2',
      getter: function() {
        return this.y + this.br;
      }
    },
    {
      /** AABB, third dimension: player, bullet, enemy, etc. */
      class: 'Simple',
      name: 'bplane',
    },
    {
      /** AABB, by default objects occupy a single plane */
      name: 'bplane2',
      getter: function() { return this.bplane; }
    },
    {
      /** The EntityManager that owns this entity. */
      name: 'manager'
    },
    {
      /** The renderable Sprite for this entity. */
      name: 'sprite',
      factory: function() {
        return this.ImageSprite.create();
      },
      adapt: function(old,nu) {
        if ( ! nu.cls_ ) {
          return this.ImageSprite.create(nu);
        }
        return nu;
      }
    },
    {
      /** The controller responsible to moving/targetting the entity */
      name: 'controller',
    },
    {
      /** the object pool this entity should be returned to */
      name: 'objectPool'
    },
    {
      /** The single plane to check for collisions against // TODO: allow multiple? */
      class: 'Simple',
      name: 'collisionPlane',
    },
    {
      /** The bounding box of the collision target area. (search
        for entities in this box when colliding) */
      name: 'targetBounds_',
      factory: function() {
        var obj = Object.create(this.BOUNDS_WRAPPER);
        obj.owner_ = this;
        return obj;
      }
    },
    {
      /** select from this DAO to get the entities that overlap this one */
      name: 'overlappingEntities',
      factory: function() {
        return this.worldDAO.where(this.INTERSECTS(
          this.worldDAO.space,
          this.BY_REF(this.targetBounds_)
        ));
      }
    },
    {
      /** Experimental alternative to overlappingEntities that avoids some object creation.
         Call this.worldDAO.select(sink, this.overlappingEntitiesOptions_); */
      name: 'overlappingEntitiesOptions_',
      factory: function() {
        return foam.dao.DAOOptions.create({ where: this.INTERSECTS(
          this.worldDAO.space,
          this.BY_REF(this.targetBounds_)
        )});
      }
    },
    {
      name: 'hitpoints',
      factory: function() {
        return this.HP.create();
      }
    },
  ],

  constants: {
    /** Experimental proxy thing, to change the apparent bplane of the object to its collisionPlane */
    BOUNDS_WRAPPER: (function() {
        var obj = {};
        Object.defineProperty(obj, 'bx', { get: function() { return this.owner_.bx; } });
        Object.defineProperty(obj, 'by', { get: function() { return this.owner_.by; } });

        Object.defineProperty(obj, 'bx2', { get: function() { return this.owner_.bx2; } });
        Object.defineProperty(obj, 'by2', { get: function() { return this.owner_.by2; } });
        // redirect collisionPlane's value into bplane for colliding
        Object.defineProperty(obj, 'bplane', { get: function() { return this.owner_.collisionPlane; } });
        Object.defineProperty(obj, 'bplane2', { get: function() { return this.owner_.collisionPlane; } });
        return obj;
      })()
  },

  methods: [
    function init() {
      this.x = this.x || 0;
      this.y = this.y || 0;
      this.rotation = this.rotation || 0;
      this.vx = this.vx || 0;
      this.vy = this.vy || 0;
      this.vrotation = this.vrotation || 0;
      this.ax = this.ax || 0;
      this.ay = this.ay || 0;
      this.arotation = this.arotation || 0;

      this.br = this.br || 10;
      this.bplane = this.bplane || 0;
      this.collisionPlane = this.collisionPlane || 0;
    },

    /** Applies movement and physics calculations required for a frame. */
    function moveStep(/* number // seconds since the last frame */ ft) {
      this.controller && this.controller.frameStep(this, ft);
    },

    function install() {
      this.worldDAO.put(this);
      this.sprite.install();
    },

    function uninstall() {
      this.worldDAO.remove(this);
      this.sprite.uninstall();
      //this.objectPool && this.objectPool.push(this);
      this.destroy();
    }
  ],
  listeners: [
    {
      /** This is standing in for buggy direct bindings */
      name: 'updateSprite',
      //isFramed: true, // ends up taking too much time
      code: function() {
        var s = this.sprite;
        s.x = this.x;
        s.y = this.y;
        s.rotation = this.rotation;
      }
    }
  ]
});

foam.CLASS({
  package: 'tabletop',
  name: 'EntityController',
  imports: [ 'worldDAO' ],
  axioms: [ foam.pattern.Singleton.create() ],

  constants: {
    ENTITY_SINK: {
      put: null,
      remove: function() {},
      error: function() {},
      eof: function() {},
    },
  },

  methods: [
    function frameStep(
      /* tabletop.Entity // the entity to adjust */ e,
      /* number // seconds since the last frame  */ ft) {
      this.move(e, ft);
      this.collide(e, ft);
      e.updateSprite();
      this.worldUpdate(e);

    },

    /** Applies movement and physics calculations required for a frame. */
    function move(e, ft) {
      /** Changes velocity of the given entity. */
      e.vx += e.ax * ft;
      e.vy += e.ay * ft;
      e.vrotation += e.arotation * ft;

      /** Changes position of the given entity. */
      e.x += e.vx * ft;
      e.y += e.vy * ft;
      e.rotation += e.vrotation * ft;
    },

    function collide(e, ft) {
      var collideWith = this.collideWith;
      // TODO: radius check too
      var s = Object.create(this.ENTITY_SINK);
      s.put = function(o) {
        collideWith(e, o, ft);
      }
      e.overlappingEntities.select(s);
    },

    function collideWith(e, o, ft) {
      if ( e === o ) return;

      //play impact sound
      e.audioManager.play("impact", e);

      // position angle
      var ax = e.x - o.x, ay = e.y - o.y;
      var len = Math.sqrt(ax*ax+ay*ay) || 1;
      ax = ax / len; // normal vector for direction between the ents
      ay = ay / len;

      // velocity based
      var dx = (e.vx - o.vx),
          dy = (e.vy - o.vy);
      var vlen = (Math.sqrt(dx*dx+dy*dy) || 1) / 2;

      e.vx = (ax * vlen);
      e.vy = (ay * vlen);
      o.vx = -ax * vlen;
      o.vy = -ay * vlen;
    },
    function worldUpdate(e) {
      this.worldDAO.put(e);
    }
  ]
});

/**
  Interface for entity Sprites. Sprites can form trees, so a single
  Sprite for an Entity may have many sub-sprites inside, which the entity
  may control (turrets, for instance)
*/
foam.CLASS({
  package: 'tabletop',
  name: 'Sprite',
  properties: [
    { /** Rendering coords */
      name: 'x'
    },
    { /** Rendering coords */
      name: 'y'
    },
    { /** Parent sprite relative */
      name: 'rotation'
    },
//     {
//       /** The entity that owns this sprite. */
//       name: 'entity'
//     },
    // TODO: image, offset....
  ],
  methods: [
    /** Adds the sprite to the scene */
    function install() {

    },
    /** Removes the sprite from the scene */
    function uninstall() {

    }
  ],
});

/**
  Base class for a thing that manages a group of entities. Such things include
  human players, computer enemy waves, and bullet groups.
*/
foam.CLASS({
  package: 'tabletop',
  name: 'EntityManager',
  requires: [
    'tabletop.Entity',
  ],
  properties: [
    {
      /** The group of managed entities */
      name: 'entities',
      class: 'foam.core.Array',
      of: 'tabletop.Entity',
    }
  ],
});
foam.CLASS({
  package: 'tabletop',
  name: 'HP',
  properties: [
    {
      /** order for default damage application */
      name: 'order',
      value: 0,
    },
    {
      /** base starting HP */
      name: 'basehp',
      value: 1,
    },
    {
      /** current HP */
      name: 'currhp',
      value: 1,
    },
    {
      /** any special modifers or changes when damage is applied (damage reduction, order of damage applications, etc...) */
      name: 'process',
      value: false,
    },
    {
      /** does not receive damage from listed sources */
      name: 'immunities',
      value: false,
    },
    {
      /** things that happen when damage is taken */
      name: 'consequences',
      value: false,
    },
    {
      /** things that happen when the entity is destroyed */
      name: 'destruct',
      factory: function () {return this.uninstall()},
    },
  ],
});
<commit_msg>Fixed HP adapt<commit_after>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
  Base class for entities. Includes world position, rendering information, etc.
*/
foam.CLASS({
  package: 'tabletop',
  name: 'Entity',
  extends: 'foam.mlang.Expressions',
  axioms: [
    foam.pattern.Pooled.create(),
  ],
  requires: [
    'tabletop.EntityController',
    'tabletop.Sprite',
    'tabletop.ImageSprite',
    'tabletop.HP',
  ],
  imports: [
    'worldDAO',
    'audioManager',
    'canvas',
    'worldWidth',
    'worldHeight',
  ],

  properties: [
    {
      name: 'id',
      factory: function() { return this.$UID; }
    },
    { /** World coords */
      class: 'Simple',
      name: 'x',
    },
    { /** World coords */
      class: 'Simple',
      name: 'y',
    },
    { /** World relative */
      class: 'Simple',
      name: 'rotation',
    },

    { /** x velocity, world units/sec */
      class: 'Simple',
      name: 'vx',
    },
    { /** y velocity, world units/sec */
      class: 'Simple',
      name: 'vy',
    },
    { /** rotational velocity, radians/sec */
      class: 'Simple',
      name: 'vrotation',
    },

    { /** x acceleration, world units/sec */
      class: 'Simple',
      name: 'ax',
    },
    { /** y acceleration, world units/sec */
      class: 'Simple',
      name: 'ay',
    },
    { /** rotational acceleration, radians/sec */
      class: 'Simple',
      name: 'arotation',
    },

    { /** Computed, true if a new moveStep() call is needed */
      name: 'moveRequired',
      getter: function() {
        return !! (this.vx || this.vy || this.vrotation ||
          this.ax || this.ay || this.arotation);
      }
    },

    { /** Bounding box size (radius from x,y) */
      name: 'br',
    },
    { /** Axis aligned bounding box, World coords */
      name: 'bx',
      getter: function() {
        return this.x - this.br;
      }
    },
    { /** AABB, World coords */
      name: 'by',
      getter: function() {
        return this.y - this.br;
      }
    },
    { /** AABB, World coords */
      name: 'bx2',
      getter: function() {
        return this.x + this.br;
      }
    },
    { /** AABB, World coords */
      name: 'by2',
      getter: function() {
        return this.y + this.br;
      }
    },
    {
      /** AABB, third dimension: player, bullet, enemy, etc. */
      class: 'Simple',
      name: 'bplane',
    },
    {
      /** AABB, by default objects occupy a single plane */
      name: 'bplane2',
      getter: function() { return this.bplane; }
    },
    {
      /** The EntityManager that owns this entity. */
      name: 'manager'
    },
    {
      /** The renderable Sprite for this entity. */
      name: 'sprite',
      factory: function() {
        return this.ImageSprite.create();
      },
      adapt: function(old,nu) {
        if ( ! nu.cls_ ) {
          return this.ImageSprite.create(nu);
        }
        return nu;
      }
    },
    {
      /** The controller responsible to moving/targetting the entity */
      name: 'controller',
    },
    {
      /** the object pool this entity should be returned to */
      name: 'objectPool'
    },
    {
      /** The single plane to check for collisions against // TODO: allow multiple? */
      class: 'Simple',
      name: 'collisionPlane',
    },
    {
      /** The bounding box of the collision target area. (search
        for entities in this box when colliding) */
      name: 'targetBounds_',
      factory: function() {
        var obj = Object.create(this.BOUNDS_WRAPPER);
        obj.owner_ = this;
        return obj;
      }
    },
    {
      /** select from this DAO to get the entities that overlap this one */
      name: 'overlappingEntities',
      factory: function() {
        return this.worldDAO.where(this.INTERSECTS(
          this.worldDAO.space,
          this.BY_REF(this.targetBounds_)
        ));
      }
    },
    {
      /** Experimental alternative to overlappingEntities that avoids some object creation.
         Call this.worldDAO.select(sink, this.overlappingEntitiesOptions_); */
      name: 'overlappingEntitiesOptions_',
      factory: function() {
        return foam.dao.DAOOptions.create({ where: this.INTERSECTS(
          this.worldDAO.space,
          this.BY_REF(this.targetBounds_)
        )});
      }
    },
    {
      name: 'hitpoints',
      factory: function() {
        return this.HP.create();
      },
      adapt: function(old,nu) {
        if ( ! nu.cls_ ) {
          return this.HP.create(nu);
        }
        return nu;
      }
    },
  ],

  constants: {
    /** Experimental proxy thing, to change the apparent bplane of the object to its collisionPlane */
    BOUNDS_WRAPPER: (function() {
        var obj = {};
        Object.defineProperty(obj, 'bx', { get: function() { return this.owner_.bx; } });
        Object.defineProperty(obj, 'by', { get: function() { return this.owner_.by; } });

        Object.defineProperty(obj, 'bx2', { get: function() { return this.owner_.bx2; } });
        Object.defineProperty(obj, 'by2', { get: function() { return this.owner_.by2; } });
        // redirect collisionPlane's value into bplane for colliding
        Object.defineProperty(obj, 'bplane', { get: function() { return this.owner_.collisionPlane; } });
        Object.defineProperty(obj, 'bplane2', { get: function() { return this.owner_.collisionPlane; } });
        return obj;
      })()
  },

  methods: [
    function init() {
      this.x = this.x || 0;
      this.y = this.y || 0;
      this.rotation = this.rotation || 0;
      this.vx = this.vx || 0;
      this.vy = this.vy || 0;
      this.vrotation = this.vrotation || 0;
      this.ax = this.ax || 0;
      this.ay = this.ay || 0;
      this.arotation = this.arotation || 0;

      this.br = this.br || 10;
      this.bplane = this.bplane || 0;
      this.collisionPlane = this.collisionPlane || 0;
    },

    /** Applies movement and physics calculations required for a frame. */
    function moveStep(/* number // seconds since the last frame */ ft) {
      this.controller && this.controller.frameStep(this, ft);
    },

    function install() {
      this.worldDAO.put(this);
      this.sprite.install();
    },

    function uninstall() {
      this.worldDAO.remove(this);
      this.sprite.uninstall();
      //this.objectPool && this.objectPool.push(this);
      this.destroy();
    }
  ],
  listeners: [
    {
      /** This is standing in for buggy direct bindings */
      name: 'updateSprite',
      //isFramed: true, // ends up taking too much time
      code: function() {
        var s = this.sprite;
        s.x = this.x;
        s.y = this.y;
        s.rotation = this.rotation;
      }
    }
  ]
});

foam.CLASS({
  package: 'tabletop',
  name: 'EntityController',
  imports: [ 'worldDAO' ],
  axioms: [ foam.pattern.Singleton.create() ],

  constants: {
    ENTITY_SINK: {
      put: null,
      remove: function() {},
      error: function() {},
      eof: function() {},
    },
  },

  methods: [
    function frameStep(
      /* tabletop.Entity // the entity to adjust */ e,
      /* number // seconds since the last frame  */ ft) {
      this.move(e, ft);
      this.collide(e, ft);
      e.updateSprite();
      this.worldUpdate(e);

    },

    /** Applies movement and physics calculations required for a frame. */
    function move(e, ft) {
      /** Changes velocity of the given entity. */
      e.vx += e.ax * ft;
      e.vy += e.ay * ft;
      e.vrotation += e.arotation * ft;

      /** Changes position of the given entity. */
      e.x += e.vx * ft;
      e.y += e.vy * ft;
      e.rotation += e.vrotation * ft;
    },

    function collide(e, ft) {
      var collideWith = this.collideWith;
      // TODO: radius check too
      var s = Object.create(this.ENTITY_SINK);
      s.put = function(o) {
        collideWith(e, o, ft);
      }
      e.overlappingEntities.select(s);
    },

    function collideWith(e, o, ft) {
      if ( e === o ) return;

      //play impact sound
      e.audioManager.play("impact", e);

      // position angle
      var ax = e.x - o.x, ay = e.y - o.y;
      var len = Math.sqrt(ax*ax+ay*ay) || 1;
      ax = ax / len; // normal vector for direction between the ents
      ay = ay / len;

      // velocity based
      var dx = (e.vx - o.vx),
          dy = (e.vy - o.vy);
      var vlen = (Math.sqrt(dx*dx+dy*dy) || 1) / 2;

      e.vx = (ax * vlen);
      e.vy = (ay * vlen);
      o.vx = -ax * vlen;
      o.vy = -ay * vlen;
    },
    function worldUpdate(e) {
      this.worldDAO.put(e);
    }
  ]
});

/**
  Interface for entity Sprites. Sprites can form trees, so a single
  Sprite for an Entity may have many sub-sprites inside, which the entity
  may control (turrets, for instance)
*/
foam.CLASS({
  package: 'tabletop',
  name: 'Sprite',
  properties: [
    { /** Rendering coords */
      name: 'x'
    },
    { /** Rendering coords */
      name: 'y'
    },
    { /** Parent sprite relative */
      name: 'rotation'
    },
//     {
//       /** The entity that owns this sprite. */
//       name: 'entity'
//     },
    // TODO: image, offset....
  ],
  methods: [
    /** Adds the sprite to the scene */
    function install() {

    },
    /** Removes the sprite from the scene */
    function uninstall() {

    }
  ],
});

/**
  Base class for a thing that manages a group of entities. Such things include
  human players, computer enemy waves, and bullet groups.
*/
foam.CLASS({
  package: 'tabletop',
  name: 'EntityManager',
  requires: [
    'tabletop.Entity',
  ],
  properties: [
    {
      /** The group of managed entities */
      name: 'entities',
      class: 'foam.core.Array',
      of: 'tabletop.Entity',
    }
  ],
});
foam.CLASS({
  package: 'tabletop',
  name: 'HP',
  properties: [
    {
      /** order for default damage application */
      name: 'order',
      value: 0,
    },
    {
      /** base starting HP */
      name: 'basehp',
      value: 1,
    },
    {
      /** current HP */
      name: 'currhp',
      value: 1,
    },
    {
      /** any special modifers or changes when damage is applied (damage reduction, order of damage applications, etc...) */
      name: 'process',
      value: false,
    },
    {
      /** does not receive damage from listed sources */
      name: 'immunities',
      value: false,
    },
    {
      /** things that happen when damage is taken */
      name: 'consequences',
      value: false,
    },
    {
      /** things that happen when the entity is destroyed */
      name: 'destruct',
      factory: function () {return this.uninstall()},
    },
  ],
});
<|endoftext|>


<commit_before>/**
 * This file is used to configure your common browserify bundle.
 *
 * If you add common packages that should be shared between multiple scripts,
 * add their names to the common.packages array below and they will be
 * automatically included.
 *
 * All common packages are automatically excluded from your browserified
 * script builds.
 *
 * If you change this configuration, you *must* restart the web server.
 */

module.exports = {
	common: {
		bundle: 'common.js',
		packages: [
			'react',
			'react-router'
		]
	}
};
<commit_msg>Instructions tweak<commit_after>/**
 * This file is used to configure your common browserify bundle.
 *
 * If you add common packages that should be shared between multiple scripts,
 * add their names to the common.packages array below and they will be
 * automatically included.
 *
 * All common packages are automatically excluded from your browserified
 * script builds.
 *
 * When you change this configuration, you *must* restart the web server.
 */

module.exports = {
	common: {
		bundle: 'common.js',
		packages: [
			'react',
			'react-router'
		]
	}
};
<|endoftext|>


<commit_before>require("./polyfill");

var sourceMapSupport = require("source-map-support");
var to5              = require("./index");
var _                = require("lodash");

sourceMapSupport.install({
  retrieveSourceMap: function (source) {
    var map = maps && maps[source];
    if (map) {
      return {
        url: null,
        map: map
      };
    } else {
      return null;
    }
  }
});

//

var blacklist  = [];

var blacklistTest = function (transformer, code) {
  try {
    if (_.isFunction(code)) {
      code();
    } else {
      new Function(code);
    }
    blacklist.push(transformer);
  } catch (err) {
    if (err.name !== "SyntaxError") throw err;
  }
};

blacklistTest("arrayComprehension", "var foo = [for (foo of bar) foo * foo];");
blacklistTest("arrowFunctions", "var foo = x => x * x;");
blacklistTest("classes", "class Foo {}");
blacklistTest("computedPropertyNames", "var foo = { [foo]: bar };");
//blacklistTest("constants", "const foo = 0;");
blacklistTest("defaultParamaters", "var foo = function (bar = 0) {};");
blacklistTest("destructuring", "var { x, y } = { x: 0, y: 0 };");
blacklistTest("forOf", "for (var foo of bar) {}");
blacklistTest("generators", "function* foo() {}");
blacklistTest("letScoping", "let foo = 0;");
blacklistTest("modules", 'import foo from "from";');
blacklistTest("propertyMethodAssignment", "{ get foo() {} }");
blacklistTest("propertyNameShorthand", "var foo = { x, y };");
blacklistTest("restParameters", "function foo(...bar) {}");
blacklistTest("spread", "foo(...bar);");
blacklistTest("templateLiterals", "`foo`");
blacklistTest("unicodeRegex", function () { new RegExp("foo", "u"); });

//

var ignoreRegex = /node_modules/;
var onlyRegex;
var whitelist   = [];
var exts        = {};
var maps        = {};
var old         = require.extensions[".js"];

var loader = function (m, filename) {
  if ((ignoreRegex && ignoreRegex.test(filename)) || (onlyRegex && !onlyRegex.test(filename))) {
    return old.apply(this, arguments);
  }

  var result = to5.transformFileSync(filename, {
    whitelist: whitelist,
    blacklist: blacklist,
    sourceMap: true
  });

  maps[filename] = result.map;

  m._compile(result.code, filename);
};

var hookExtensions = function (_exts) {
  _.each(exts, function (old, ext) {
    require.extensions[ext] = old;
  });

  exts = {};

  _.each(_exts, function (ext) {
    exts[ext] = require.extensions[ext];
    require.extensions[ext] = loader;
  });
};

hookExtensions([".es6", ".js"]);

module.exports = function (opts) {
  // normalise options
  opts = opts || {};
  if (_.isRegExp(opts)) opts = { ignore: opts };
  if (opts.ignoreRegex != null) opts.ignore = opts.ignoreRegex;

  if (opts.only != null) onlyRegex = opts.only;
  if (opts.ignore != null) ignoreRegex = opts.ignore;

  if (opts.extensions) hookExtensions(opts.extensions);

  if (opts.blacklist) blacklist = opts.blacklist;
  if (opts.whitelist) whitelist = opts.whitelist;
};
<commit_msg>fix up templateLiterals blacklist check<commit_after>require("./polyfill");

var sourceMapSupport = require("source-map-support");
var to5              = require("./index");
var _                = require("lodash");

sourceMapSupport.install({
  retrieveSourceMap: function (source) {
    var map = maps && maps[source];
    if (map) {
      return {
        url: null,
        map: map
      };
    } else {
      return null;
    }
  }
});

//

var blacklist  = [];

var blacklistTest = function (transformer, code) {
  try {
    if (_.isFunction(code)) {
      code();
    } else {
      new Function(code);
    }
    blacklist.push(transformer);
  } catch (err) {
    if (err.name !== "SyntaxError") throw err;
  }
};

blacklistTest("arrayComprehension", "var foo = [for (foo of bar) foo * foo];");
blacklistTest("arrowFunctions", "var foo = x => x * x;");
blacklistTest("classes", "class Foo {}");
blacklistTest("computedPropertyNames", "var foo = { [foo]: bar };");
//blacklistTest("constants", "const foo = 0;");
blacklistTest("defaultParamaters", "var foo = function (bar = 0) {};");
blacklistTest("destructuring", "var { x, y } = { x: 0, y: 0 };");
blacklistTest("forOf", "for (var foo of bar) {}");
blacklistTest("generators", "function* foo() {}");
blacklistTest("letScoping", "let foo = 0;");
blacklistTest("modules", 'import foo from "from";');
blacklistTest("propertyMethodAssignment", "{ get foo() {} }");
blacklistTest("propertyNameShorthand", "var foo = { x, y };");
blacklistTest("restParameters", "function foo(...bar) {}");
blacklistTest("spread", "foo(...bar);");
blacklistTest("templateLiterals", "var foo = `foo`;");
blacklistTest("unicodeRegex", function () { new RegExp("foo", "u"); });

//

var ignoreRegex = /node_modules/;
var onlyRegex;
var whitelist   = [];
var exts        = {};
var maps        = {};
var old         = require.extensions[".js"];

var loader = function (m, filename) {
  if ((ignoreRegex && ignoreRegex.test(filename)) || (onlyRegex && !onlyRegex.test(filename))) {
    return old.apply(this, arguments);
  }

  var result = to5.transformFileSync(filename, {
    whitelist: whitelist,
    blacklist: blacklist,
    sourceMap: true
  });

  maps[filename] = result.map;

  m._compile(result.code, filename);
};

var hookExtensions = function (_exts) {
  _.each(exts, function (old, ext) {
    require.extensions[ext] = old;
  });

  exts = {};

  _.each(_exts, function (ext) {
    exts[ext] = require.extensions[ext];
    require.extensions[ext] = loader;
  });
};

hookExtensions([".es6", ".js"]);

module.exports = function (opts) {
  // normalise options
  opts = opts || {};
  if (_.isRegExp(opts)) opts = { ignore: opts };
  if (opts.ignoreRegex != null) opts.ignore = opts.ignoreRegex;

  if (opts.only != null) onlyRegex = opts.only;
  if (opts.ignore != null) ignoreRegex = opts.ignore;

  if (opts.extensions) hookExtensions(opts.extensions);

  if (opts.blacklist) blacklist = opts.blacklist;
  if (opts.whitelist) whitelist = opts.whitelist;
};
<|endoftext|>


<commit_before>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh'),
	TCPWrapper = require('../Misc/TCPWrapper');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events emitted by this class

// server-connect
// server-close
// sever-error

// client-change
// client-cache-updated

// single-message

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// The groups the client has joined
	this._groups = {};

	// Client and group cache
	this._client_cache = new neigh.NeighborManager();
	this._group_cache = {}

	// ----------------
	// Server socket

	this._server_sock = undefined;

	// When socket is ready try to find server
	this.on('listening', function(){
		self.findServer();

		var message = new msgs.Message(
			msgs.types.CLIENT_ADVERTISEMENT,
			self.getProfile(),
			"I'm Here..."
		);

		self.sendUDP(self._channel, message.toString());

	});
};
inherits(Client, Base);

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

Client.prototype.getClientCache = function() {
	return this._client_cache.getNeighbors();
}

Client.prototype.setAlias = function(alias) {
	var message = new msgs.Message(
		msgs.types.CLIENT_CHANGE,
		this.getProfile(),
		{
			old_name: this.alias,
			new_name: alias
		}

	);
	this.sendUDP(this._channel, message.toString());
	this.alias = alias;
}

// function updateAlias
// updates the alias of a neighbor
// @param uuid neighbor id
// @param alias the new alias
// @return undefined
Client.prototype._updateAlias = function(uuid, alias){
	var neighbor = this.getClientCache()[uuid].data;
	neighbor.alias = message.new_name;
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	// Fixes the channel of the sender
	data.sender.channel = new addrs.Channel(remote.address, remote.port);

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			console.log('Server answered...');
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_ADVERTISEMENT:
			// Save client in cache
			this._client_cache.addNeighbor(new neigh.Neighbor(data.sender.uuid, data.sender));
			this.emit('client-cache-update');
			break;

		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		case msgs.types.CLIENT_CHANGE:
			// Update client data
			this._updateAlias(data.sender.uuid, data.extras);
			this.emit('client-cache-update');
			break;

		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_ADVERTISEMENT,
				this.getProfile()
			);
			this.sendUDP(data.sender.channel, message.toString());
			break;

		// ----------------
		// Group messages

		case msgs.types.GROUP_CREATE_OK:
			// Group was created, save it in neighbor-group list
			this._group_cache.addNeighbor(new neigh.Neighbor(data.extras.uuid, data.extras));
			break;

		case msgs.types.GROUP_JOIN_OK:
			// Somebody joined a group
			// Probably a group we joined too!
			this.emit('client-group-join', data.sender);
			break;

		case msgs.types.GROUP_LEAVE_OK:
			// Somebody is leaving a group
			// Probably a group we joined too!
			this.emit('client-group-leave', data.sender);
			break;

		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			this.emit('client-group-message', data);
			break;

		case msgs.types.SINGLE_MESSAGE:
			// We received an unicast message
			this.emit('client-message', data);
			break;
	} // switch

} // messageHandler

// ----------------
// Server related

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);

	this.sendUDP(addrs.channels.server, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {
	var self = this;
	var addr = address + ':' + port;

	// Initializes socket
	if (this._server_sock) {
		this._server_sock.end();
		this._server_sock.destroy();
	}
	this._server_sock = new net.Socket();

	this._server_sock.connect(port, address);

	// Message handling
	var tcp_wrapper = new TCPWrapper(this._server_sock);
	tcp_wrapper.on('message', function(message) {
		self._tcpMessageHandler(message);
	});

	// Connection status
	this._server_sock.on('connect', function() {
		self.emit('server-connect');
	});

	this._server_sock.on('close', function() {
		self.emit('server-close');
	});

	this._server_sock.on('error', function(err) {
		self.emit('server-error', err);
	});
}

Client.prototype.createGroup = function(group_name) {
	// Sends a GROUP_CREATE message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_CREATE,
			this.getProfile(),
			{ name: group_name }
		);

		this._server_sock.write(message.toString());
	}
}

Client.prototype.joinGroup = function(group_uuid) {
	// Sends a GROUP_JOIN message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_JOIN,
			this.getProfile(),
			{ uuid: group_uuid }
		);

		this._server_sock.write(message.toString());
	}
}

Client.prototype.leaveGroup = function(group_uuid) {
	// Sends GROUP_LEAVE message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_LEAVE,
			this.getProfile(),
			{ uuid: group_uuid }
		);

		this._server_sock.write(message.toString());
	}
}

// function updateGroupCache
// updates the group cache asynchronically
// emits 'group-cache-update' when it's done
Client.prototype.updateGroupCache = function() {
	// Sends GROUP_SOLICITATION message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_SOLICITATION,
			this.getProfile()
		);

		this._server_sock.write(message.toString());
	}
}

// function getGroups
// @returns an object of the groups the client has joined
Client.prototype.getGroups = function() {
	return JSON.parse(JSON.stringify(this._groups));
}

// function getGroupCache
// @returns an object of neighboring groups (cached list)
Client.prototype.getGroupCache = function() {
	return JSON.parse(JSON.stringify(this._group_cache));
}

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	console.log('Message from TCP:');
	console.log(data);

	switch(data.type) {

		// GROUP_ADVERTISEMENT
		case msgs.types.GROUP_ADVERTISEMENT:
			this._group_cache = data.extras;
			this.emit('group-cache-update');
			break;

		// GROUP_*_OK
		case msgs.types.GROUP_CREATE_OK:
			// We created the group, we join it
			this._groups[data.extras.uuid] = data.extras;
			// Tell everyone that we just created a group
			var message = new msgs.Message(
				msgs.types.GROUP_CREATE_OK,
				this.getProfile(),
				data.extras
			);
			this.sendUDP(this._channel, message.toString());
			this.emit('group-create', data.extras);

		case msgs.types.GROUP_JOIN_OK:
			this._groups[data.extras.uuid] = data.extras;
			this._sock.addMembership(data.extras.channel.address);
			// Tell group that we joined
			var message = new msgs.Message(
				msgs.types.GROUP_JOIN_OK,
				this.getProfile(),
				'Joined!'
			);
			this.sendUDP(data.extras.channel, message.toString());
			this.emit('group-join', data.extras);
			break;

		case msgs.types.GROUP_LEAVE_OK:
			delete this._groups[data.extras.uuid];
			// Tell group that we left
			var message = new msgs.Message(
				msgs.types.GROUP_LEAVE_OK,
				this.getProfile(),
				'Left!'
			);
			this.sendUDP(data.extras.channel, message.toString());
			this._sock.dropMembership(data.extras.channel.address);
			this.emit('group-leave', data.extras);
			break;

		// GROUP_*_ERR
		case msgs.types.GROUP_CREATE_ERR:
			break;
		case msgs.types.GROUP_JOIN_ERR:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// ----------------
// Exports
// ----------------

module.exports = Client;<commit_msg>Added debug prints<commit_after>var
	dgram = require('dgram'),
	EventEmitter = require('events').EventEmitter,
	inherits = require('util').inherits,
	net = require('net'),
	uuid = require('uuid'),

	Base = require('./Base'),
	addrs = require('../Misc/addresses'),
	msgs = require('../Misc/messages'),
	neigh = require('../Misc/neigh'),
	TCPWrapper = require('../Misc/TCPWrapper');

// ----------------
// Client class
// ----------------
// Main client class
// Inherits from: EventEmitter

// ----------------
// Events emitted by this class

// server-connect
// server-close
// sever-error

// client-change
// client-cache-updated

// single-message

// listening
// close

// ----------------
// Class declaration

function Client(chan) {
	Base.call(this, chan);

	var self = this;

	// The groups the client has joined
	this._groups = {};

	// Client and group cache
	this._client_cache = new neigh.NeighborManager();
	this._group_cache = {}

	// ----------------
	// Server socket

	this._server_sock = undefined;

	// When socket is ready try to find server
	this.on('listening', function(){
		self.findServer();

		var message = new msgs.Message(
			msgs.types.CLIENT_ADVERTISEMENT,
			self.getProfile(),
			"I'm Here..."
		);

		self.sendUDP(self._channel, message.toString());

	});
};
inherits(Client, Base);

// @override
Client.prototype.close = function() {
	Base.prototype.close.call(this);
	if (this._server_sock)
		this._server_sock.end();
}

// function updateClientCache
// Sends a CLIENT_SOLICITATION message to the
// channel to which this client is connected
Client.prototype.updateClientCache = function() {
	var message = new msgs.Message(
		msgs.types.CLIENT_SOLICITATION,
		this.getProfile()
	);

	this.sendUDP(this._channel, message.toString());
}

Client.prototype.getClientCache = function() {
	return this._client_cache.getNeighbors();
}

Client.prototype.setAlias = function(alias) {
	var message = new msgs.Message(
		msgs.types.CLIENT_CHANGE,
		this.getProfile(),
		{
			old_name: this.alias,
			new_name: alias
		}

	);
	this.sendUDP(this._channel, message.toString());
	this.alias = alias;
}

// function updateAlias
// updates the alias of a neighbor
// @param uuid neighbor id
// @param alias the new alias
// @return undefined
Client.prototype._updateAlias = function(uuid, alias){
	var neighbor = this.getClientCache()[uuid].data;
	neighbor.alias = message.new_name;
}

// function _messageHandler
// @param message buffer of the message
// @remote object that contains the address and port of the sender
// @returns undefined
Client.prototype._messageHandler = function(message, remote) {

	var data = JSON.parse(message.toString());

	// Checks that this message isn't comming from us
	if (data.sender.uuid == this._uuid) return;

	// Fixes the channel of the sender
	data.sender.channel = new addrs.Channel(remote.address, remote.port);

	switch(data.type) {

		// ----------------
		// Server messages
		case msgs.types.SERVER_ADVERTISEMENT:
			console.log('Server answered...');
			this.connect(remote.address, remote.port);
			break;

		// ----------------
		// General messages handling

		case msgs.types.CLIENT_ONLINE:
		case msgs.types.CLIENT_ADVERTISEMENT:
			// Save client in cache
			this._client_cache.addNeighbor(new neigh.Neighbor(data.sender.uuid, data.sender));
			this.emit('client-cache-update');
			break;

		case msgs.types.CLIENT_OFFLINE:
			// Delete client from list of neighbors
			break;

		case msgs.types.CLIENT_CHANGE:
			// Update client data
			this._updateAlias(data.sender.uuid, data.extras);
			this.emit('client-cache-update');
			break;

		case msgs.types.CLIENT_SOLICITATION:
			// Tell client we are online
			var message = new msgs.Message(
				msgs.types.CLIENT_ADVERTISEMENT,
				this.getProfile()
			);
			this.sendUDP(data.sender.channel, message.toString());
			break;

		// ----------------
		// Group messages

		case msgs.types.GROUP_CREATE_OK:
			// Group was created, save it in neighbor-group list
			this._group_cache.addNeighbor(new neigh.Neighbor(data.extras.uuid, data.extras));
			break;

		case msgs.types.GROUP_JOIN_OK:
			// Somebody joined a group
			// Probably a group we joined too!
			this.emit('client-group-join', data.sender);
			break;

		case msgs.types.GROUP_LEAVE_OK:
			// Somebody is leaving a group
			// Probably a group we joined too!
			this.emit('client-group-leave', data.sender);
			break;

		case msgs.types.GROUP_MESSAGE:
			// Messages to a group
			this.emit('client-group-message', data);
			break;

		case msgs.types.SINGLE_MESSAGE:
			// We received an unicast message
			this.emit('client-message', data);
			break;
	} // switch

} // messageHandler

// ----------------
// Server related

// function findServer
// tries to find a server by sending a SERVER_SOLICITATION
// message. Fires server-found event.
Client.prototype.findServer = function() {
	var message = new msgs.Message(
		msgs.types.SERVER_SOLICITATION,
		this.getProfile(),
		"Server solicitation..."
	);

	this.sendUDP(addrs.channels.server, message.toString());
}

// function connect
// stablish a TCP connection to given address and port.
// Used for connecting to a server
Client.prototype.connect = function(address, port) {
	var self = this;
	var addr = address + ':' + port;

	// Initializes socket
	if (this._server_sock) {
		this._server_sock.end();
		this._server_sock.destroy();
	}
	this._server_sock = new net.Socket();

	this._server_sock.connect(port, address);

	// Message handling
	var tcp_wrapper = new TCPWrapper(this._server_sock);
	tcp_wrapper.on('message', function(message) {
		self._tcpMessageHandler(message);
	});

	// Connection status
	this._server_sock.on('connect', function() {
		self.emit('server-connect');
	});

	this._server_sock.on('close', function() {
		console.log('Closed');
		self.emit('server-close');
	});

	this._server_sock.on('error', function(err) {
		console.log(err);
		self.emit('server-error', err);
	});
}

Client.prototype.createGroup = function(group_name) {
	// Sends a GROUP_CREATE message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_CREATE,
			this.getProfile(),
			{ name: group_name }
		);

		this._server_sock.write(message.toString());
	}
}

Client.prototype.joinGroup = function(group_uuid) {
	// Sends a GROUP_JOIN message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_JOIN,
			this.getProfile(),
			{ uuid: group_uuid }
		);

		this._server_sock.write(message.toString());
	}
}

Client.prototype.leaveGroup = function(group_uuid) {
	// Sends GROUP_LEAVE message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_LEAVE,
			this.getProfile(),
			{ uuid: group_uuid }
		);

		this._server_sock.write(message.toString());
	}
}

// function updateGroupCache
// updates the group cache asynchronically
// emits 'group-cache-update' when it's done
Client.prototype.updateGroupCache = function() {
	// Sends GROUP_SOLICITATION message

	if (this._server_sock.writable) {

		var message = new msgs.Message(
			msgs.types.GROUP_SOLICITATION,
			this.getProfile()
		);

		this._server_sock.write(message.toString());
	}
}

// function getGroups
// @returns an object of the groups the client has joined
Client.prototype.getGroups = function() {
	return JSON.parse(JSON.stringify(this._groups));
}

// function getGroupCache
// @returns an object of neighboring groups (cached list)
Client.prototype.getGroupCache = function() {
	return JSON.parse(JSON.stringify(this._group_cache));
}

// function _tcpMessageHandler
// handles the messages comming from the server
// @param data the data received
// @returns undefined
Client.prototype._tcpMessageHandler = function(data) {

	// JSON parse
	data = JSON.parse(data.toString());

	console.log('Message from TCP:');
	console.log(data);

	switch(data.type) {

		// GROUP_ADVERTISEMENT
		case msgs.types.GROUP_ADVERTISEMENT:
			this._group_cache = data.extras;
			this.emit('group-cache-update');
			break;

		// GROUP_*_OK
		case msgs.types.GROUP_CREATE_OK:
			// We created the group, we join it
			this._groups[data.extras.uuid] = data.extras;
			// Tell everyone that we just created a group
			var message = new msgs.Message(
				msgs.types.GROUP_CREATE_OK,
				this.getProfile(),
				data.extras
			);
			this.sendUDP(this._channel, message.toString());
			this.emit('group-create', data.extras);

		case msgs.types.GROUP_JOIN_OK:
			this._groups[data.extras.uuid] = data.extras;
			this._sock.addMembership(data.extras.channel.address);
			// Tell group that we joined
			var message = new msgs.Message(
				msgs.types.GROUP_JOIN_OK,
				this.getProfile(),
				'Joined!'
			);
			this.sendUDP(data.extras.channel, message.toString());
			this.emit('group-join', data.extras);
			break;

		case msgs.types.GROUP_LEAVE_OK:
			delete this._groups[data.extras.uuid];
			// Tell group that we left
			var message = new msgs.Message(
				msgs.types.GROUP_LEAVE_OK,
				this.getProfile(),
				'Left!'
			);
			this.sendUDP(data.extras.channel, message.toString());
			this._sock.dropMembership(data.extras.channel.address);
			this.emit('group-leave', data.extras);
			break;

		// GROUP_*_ERR
		case msgs.types.GROUP_CREATE_ERR:
			break;
		case msgs.types.GROUP_JOIN_ERR:
			break;
		case msgs.types.GROUP_LEAVE_OK:
			break;
	}
}

// ----------------
// Exports
// ----------------

module.exports = Client;<|endoftext|>


<commit_before>var Controller = require('../controllers/user.controller');
var express = require('express');
var Router = express.Router();

Router
  //  /users routes
  .get('/users', Controller.getAllUsers)

  .post('/users/signup', Controller.signUp)

  .post('/users/login', Controller.login)

  // /users/username routes
  .get('/users/:username', Controller.getUser)

  .put('/users/:username', Controller.updateUser)

  .delete('/users/:username', Controller.removeUser);

module.exports = Router;<commit_msg>Implement route for api end points<commit_after>var Controller = require('../controllers/user.controller');
var express = require('express');
var Router = express.Router();

Router
  //  /users routes
  .get('/', Controller.getAllUsers)

  .post('/signup', Controller.signUp)

  .post('/login', Controller.login)

  // /username routes
  .get('/:username', Controller.getUser)

  .put('/:username', Controller.updateUser)

  .delete('/:username', Controller.removeUser);

  // .post('/authenticate', Controller.verifyToken);

module.exports = Router;
<|endoftext|>


<commit_before>if (typeof module !== "undefined") {
    var Polynomial = require('kld-polynomial').Polynomial,
        affine = require('kld-affine'),
        Matrix2D = affine.Matrix2D,
        Point2D = affine.Point2D;
}

/**
 *  CubicBezier2D
 *
 *  @param {Point2D} p1
 *  @param {Point2D} p2
 *  @param {Point2D} p3
 *  @param {Point2D} p3
 *  @returns {CubicBezier2D}
 */
function CubicBezier2D(p1, p2, p3, p4) {
    Object.defineProperties(this, {
        "p1": {
            value: p1,
            writable: false,
            enumerable: true,
            configurable: false
        },
        "p2": {
            value: p2,
            writable: false,
            enumerable: true,
            configurable: false
        },
        "p3": {
            value: p3,
            writable: false,
            enumerable: true,
            configurable: false
        },
        "p4": {
            value: p4,
            writable: false,
            enumerable: true,
            configurable: false
        }
    });
    // this.p1 = p1;
    // this.p2 = p2;
    // this.p3 = p3;
    // this.p4 = p4;
}

CubicBezier2D.prototype.getBernsteinPolynomials = function() {
    var a, b, c;        // temporary variables
    var c3, c2, c1, c0; // coefficients of cubic

    // Start with Bezier using Bernstein polynomials for weighting functions:
    //     (1-t^3)P1 + 3t(1-t)^2P2 + 3t^2(1-t)P3 + t^3P4
    //
    // Expand and collect terms to form linear combinations of original Bezier
    // controls.  This ends up with a vector cubic in t:
    //     (-P1+3P2-3P3+P4)t^3 + (3P1-6P2+3P3)t^2 + (-3P1+3P2)t + P1
    //             /\                  /\                /\       /\
    //             ||                  ||                ||       ||
    //             c3                  c2                c1       c0

    // Calculate the coefficients
    a = this.p1.multiply(-1);
    b = this.p2.multiply(3);
    c = this.p3.multiply(-3);
    c3 = a.add(b.add(c.add(this.p4)));

    a = this.p1.multiply(3);
    b = this.p2.multiply(-6);
    c = this.p3.multiply(3);
    c2 = a.add(b.add(c));

    a = this.p1.multiply(-3);
    b = this.p2.multiply(3);
    c1 = a.add(b);

    c0 = this.p1;

    return {
        x: new Polynomial(c3.x, c2.x, c1.x, c0.x),
        y: new Polynomial(c3.y, c2.y, c1.y, c0.y)
    }
};

CubicBezier2D.prototype.getBoundingBox = function() {

};

CubicBezier2D.prototype.getAlignedBoundingBox = function() {

};

CubicBezier2D.prototype.getAlignedBezier = function() {
    var matrix = new Matrix2D();

    // move p1 to the origin
    matrix = matrix.translate(this.p1.x, this.p1.y);

    // rotate vector from p1 to p4 to x-axis
    matrix = matrix.rotateFromVector(Vector2D.fromPoints(this.p1, this.p4));

    // reverse transforms
    matrix = matrix.inverse();

    // apply to each point and create new Bezier
    return new CubicBezier2D(
        this.p1.transform(matrix),
        this.p2.transform(matrix),
        this.p3.transform(matrix),
        this.p4.transform(matrix)
    );
};

CubicBezier2D.prototype.tesselate = function() {

};

CubicBezier2D.prototype.toString = function() {
    return (
        "M" + this.p1.x + "," + this.p1.y + " " +
        "C" + this.p2.x + "," + this.p2.y +
        " " + this.p3.x + "," + this.p3.y +
        " " + this.p4.x + "," + this.p4.y
    );
};

if (typeof module !== "undefined") {
    module.exports = CubicBezier2D;
}
<commit_msg>Add ability to get a cubic bezier's bbox<commit_after>if (typeof module !== "undefined") {
    var Polynomial = require('kld-polynomial').Polynomial,
        affine = require('kld-affine'),
        Matrix2D = affine.Matrix2D,
        Point2D = affine.Point2D,
        Rectangle2D = require('./Rectangle2D');
}

/**
 *  CubicBezier2D
 *
 *  @param {Point2D} p1
 *  @param {Point2D} p2
 *  @param {Point2D} p3
 *  @param {Point2D} p3
 *  @returns {CubicBezier2D}
 */
function CubicBezier2D(p1, p2, p3, p4) {
    Object.defineProperties(this, {
        "p1": {
            value: p1,
            writable: false,
            enumerable: true,
            configurable: false
        },
        "p2": {
            value: p2,
            writable: false,
            enumerable: true,
            configurable: false
        },
        "p3": {
            value: p3,
            writable: false,
            enumerable: true,
            configurable: false
        },
        "p4": {
            value: p4,
            writable: false,
            enumerable: true,
            configurable: false
        }
    });
    // this.p1 = p1;
    // this.p2 = p2;
    // this.p3 = p3;
    // this.p4 = p4;
}

CubicBezier2D.prototype.getBernsteinPolynomials = function() {
    var a, b, c;        // temporary variables
    var c3, c2, c1, c0; // coefficients of cubic

    // Start with Bezier using Bernstein polynomials for weighting functions:
    //     (1-t^3)P1 + 3t(1-t)^2P2 + 3t^2(1-t)P3 + t^3P4
    //
    // Expand and collect terms to form linear combinations of original Bezier
    // controls.  This ends up with a vector cubic in t:
    //     (-P1+3P2-3P3+P4)t^3 + (3P1-6P2+3P3)t^2 + (-3P1+3P2)t + P1
    //             /\                  /\                /\       /\
    //             ||                  ||                ||       ||
    //             c3                  c2                c1       c0

    // Calculate the coefficients
    a = this.p1.multiply(-1);
    b = this.p2.multiply(3);
    c = this.p3.multiply(-3);
    c3 = a.add(b.add(c.add(this.p4)));

    a = this.p1.multiply(3);
    b = this.p2.multiply(-6);
    c = this.p3.multiply(3);
    c2 = a.add(b.add(c));

    a = this.p1.multiply(-3);
    b = this.p2.multiply(3);
    c1 = a.add(b);

    c0 = this.p1;

    return {
        x: new Polynomial(c3.x, c2.x, c1.x, c0.x),
        y: new Polynomial(c3.y, c2.y, c1.y, c0.y)
    };
};

/**
 *  getBoundingBox
 *
 *  @returns {Rectangle2D}
 */
CubicBezier2D.prototype.getBoundingBox = function() {
    var polys = this.getBernsteinPolynomials();
    var dx = polys.x.getDerivative();
    var dy = polys.y.getDerivative();
    var roots = dx.getRootsInInterval(0, 1);
    roots = roots.concat(dy.getRootsInInterval(0, 1));
    // var roots = dx.getRoots();
    // roots = roots.concat(dy.getRoots());

    var min = this.p1.min(this.p4);
    var max = this.p1.max(this.p4);

    roots.forEach(function(t) {
        if (0 <= t && t <= 1) {
            var testPoint = new Point2D(
                polys.x.eval(t),
                polys.y.eval(t)
            );

            min = min.min(testPoint);
            max = max.max(testPoint);
        }
    });

    return new Rectangle2D(
        min.x,
        min.y,
        max.x - min.x,
        max.y - min.y
    );
};

CubicBezier2D.prototype.getAlignedBoundingBox = function() {

};

CubicBezier2D.prototype.getAlignedBezier = function() {
    var matrix = new Matrix2D();

    // move p1 to the origin
    matrix = matrix.translate(this.p1.x, this.p1.y);

    // rotate vector from p1 to p4 to x-axis
    matrix = matrix.rotateFromVector(Vector2D.fromPoints(this.p1, this.p4));

    // reverse transforms
    matrix = matrix.inverse();

    // apply to each point and create new Bezier
    return new CubicBezier2D(
        this.p1.transform(matrix),
        this.p2.transform(matrix),
        this.p3.transform(matrix),
        this.p4.transform(matrix)
    );
};

CubicBezier2D.prototype.tesselate = function() {

};

CubicBezier2D.prototype.toString = function() {
    return (
        "M" + this.p1.x + "," + this.p1.y + " " +
        "C" + this.p2.x + "," + this.p2.y +
        " " + this.p3.x + "," + this.p3.y +
        " " + this.p4.x + "," + this.p4.y
    );
};

if (typeof module !== "undefined") {
    module.exports = CubicBezier2D;
}
<|endoftext|>


<commit_before>const puppeteer = require('puppeteer')
const cheerio = require('cheerio')
const db = require('./db.js')

// 暂时不用这种方式获取数据
const dom2json = function(domStr) {
    return new Promise((resolve, reject) => {
        try {
            const $ = cheerio.load(domStr)
            let jsonData = []
            // console.log('tr list length: ', $('tr').length)
            // console.log($('#tb').html())
            $('#tb > tr').each((index, element) => {
                // if (index > 10) {
                //     return
                // }
                // console.log('element is: ', element)
                const dataItem = []
                $(element).find('td').each((i, ele) => {
                    // console.log('ele text: ', $(ele).text())
                    dataItem[i] = $(ele).text()
                })
                if (dataItem.length > 0) {
                    jsonData.push(dataItem)
                }
                // console.log('jsonData is: ', jsonData)

                // console.log('innerText is: ', colList[0].text())
            })
            // console.log('data length is: ', jsonData.length)
            resolve(jsonData)
            // console.log('jsonData is: ', jsonData)
        } catch(e) {
            reject(e.message)
        }
    })
}

const start = async function() {
    const browser = await puppeteer.launch()
    const page = await browser.newPage()
    // await page.goto('http://r.creditcard.gzcb.com.cn/zzshua/tb.html')
    await page.goto('http://r.creditcard.gzcb.com.cn/zzshua/tb.html', {"waitUntil" : "networkidle2"});
    console.log('page loaded!')
    const pageHtml = await page.content()
    // const jsonData = await dom2json(pageHtml).catch(e => {
    //     console.log(e)
    // })
    const jsonData = await page.evaluate(() => {
        let arrTemp = arr0.concat(arr)
        let arrRst = arrTemp.map(ele => {
            return [ele]
        })
        return arrRst
    })
    const rst = await db.saveData(jsonData).catch(e => {
        console.log(e)
    })
    console.log(rst)
    // console.log(123)
    await page.close()
    await browser.close()
}

start()<commit_msg>add no sandbox args<commit_after>const puppeteer = require('puppeteer')
const cheerio = require('cheerio')
const db = require('./db.js')

// 暂时不用这种方式获取数据
const dom2json = function(domStr) {
    return new Promise((resolve, reject) => {
        try {
            const $ = cheerio.load(domStr)
            let jsonData = []
            // console.log('tr list length: ', $('tr').length)
            // console.log($('#tb').html())
            $('#tb > tr').each((index, element) => {
                // if (index > 10) {
                //     return
                // }
                // console.log('element is: ', element)
                const dataItem = []
                $(element).find('td').each((i, ele) => {
                    // console.log('ele text: ', $(ele).text())
                    dataItem[i] = $(ele).text()
                })
                if (dataItem.length > 0) {
                    jsonData.push(dataItem)
                }
                // console.log('jsonData is: ', jsonData)

                // console.log('innerText is: ', colList[0].text())
            })
            // console.log('data length is: ', jsonData.length)
            resolve(jsonData)
            // console.log('jsonData is: ', jsonData)
        } catch(e) {
            reject(e.message)
        }
    })
}

const start = async function() {
    const browser = await puppeteer.launch({args: ['--no-sandbox']})
    const page = await browser.newPage()
    // await page.goto('http://r.creditcard.gzcb.com.cn/zzshua/tb.html')
    await page.goto('http://r.creditcard.gzcb.com.cn/zzshua/tb.html', {"waitUntil" : "networkidle2"});
    console.log('page loaded!')
    const pageHtml = await page.content()
    // const jsonData = await dom2json(pageHtml).catch(e => {
    //     console.log(e)
    // })
    const jsonData = await page.evaluate(() => {
        let arrTemp = arr0.concat(arr)
        let arrRst = arrTemp.map(ele => {
            return [ele]
        })
        return arrRst
    })
    const rst = await db.saveData(jsonData).catch(e => {
        console.log(e)
    })
    console.log(rst)
    // console.log(123)
    await page.close()
    await browser.close()
}

start()<|endoftext|>


<commit_before>/**
 * Load config from a directory into a Sails app
 */

var buildDictionary = require('sails-build-dictionary');
var _ = require('lodash');
module.exports = function (sails, dir) {
    buildDictionary.aggregate({
        dirname: dir,
        exclude: ['locales', 'local.js', 'local.json', 'local.coffee', 'local.litcoffee'],
        excludeDirs: /(locales|env)$/,
        filter: /(.+)\.(js|json|coffee|litcoffee)$/,
        identity: false
    }, function (err, configs) {
        sails.config = _.merge(configs, sails.config, function (a, b) {
            if (_.isArray(a)) {
                return a.concat(b);
            }
        });
    });
};
<commit_msg>Update config loader to include env configs<commit_after>/**
 * Load config from a directory into a Sails app
 */

var buildDictionary = require('sails-build-dictionary');
var async = require('async');

var _ = require('lodash');
module.exports = function (sails, dir) {
  async.auto({

    'config/*': function loadOtherConfigFiles (cb) {
      buildDictionary.aggregate({
        dirname: dir,
        exclude: ['locales', 'local.js', 'local.json', 'local.coffee', 'local.litcoffee'],
        excludeDirs: /(locales|env)$/,
        filter: /(.+)\.(js|json|coffee|litcoffee)$/,
        identity: false
      }, cb)
    },

    'config/local' : function loadLocalOverrideFile (cb) {
      buildDictionary.aggregate({
        dirname: dir,
        filter: /local\.(js|json|coffee|litcoffee)$/,
        identity: false
      }, cb);
    },

    'config/env/**': ['config/local', function loadEnvConfigFolder (cb) {
      var env = sails.config.environment || async_data['config/local'].environment || 'development';
      buildDictionary.aggregate({
        dirname: dir + '/env/' + env,
        optional: true,
        filter: /(.+)\.(js|json|coffee|litcoffee)$/,
        identity: false
      }, cb)
    }],

    'config/env/*' : ['config/local', function loadEnvConfigFile (cb, async_data) {
      var env = sails.config.environment || async_data['config/local'].environment || 'development';
      buildDictionary.aggregate({
        dirname: dir + '/env',
        filter: new RegExp("^" + env + "\\.(js|json|coffee|litcoffee)$"),
        optional: true,
        identity: false
      }, cb);
    }]

  }, function (err, async_data) {

    if (err) { throw err; }

    // Merge the configs, with env/*.js files taking precedence over others, and local.js
    // taking precedence over everything
    var configs = _.merge(
        async_data['config/*'],
        async_data['config/env/**'],
        async_data['config/env/*'],
        async_data['config/local']
    );

    sails.config = _.merge(configs, sails.config, function (a, b) {
      if (_.isArray(a)) {
        return a.concat(b);
      }
    });

  });

};
<|endoftext|>


<commit_before>/**
 * The GameCore class provides the base to build games on.
 * @name GameCore
 * @constructor GameCore
 * @example
 * var myGame = new GameCore({
 *   canvasId: 'myCanvas',
 *   update: function(millis){
 *     // do updating of game state
 *   },
 *   draw: function(context){
 *     // do drawing of the game
 *   }
 * });
 *
 * //start the game
 * myGame.run();
 */

define([
  'dcl',
  'dcl/advise',
  'dcl/bases/Mixer',
  'lodash',
  './InputManager',
  './ResourceManager',
  './shims/RAF'
], function(dcl, advise, Mixer, _, InputManager, ResourceManager){

  'use strict';

  return dcl(Mixer, {
    /**
     * A map of static constants for internal use
     * @type {Object}
     * @memberOf GameCore#
     * @property {Number} FONT_SIZE Default font size used in default draw functions
     */
    statics: {
      FONT_SIZE: 24
    },
    /**
     * Whether or not the game should be running its loop
     * @type {Boolean}
     * @memberOf GameCore#
     * @default
     */
    isRunning: false,
    /**
     * The id of the canvas element to use render the game on
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    canvasId: null,
    /**
     * Max number of milliseconds between updates. (in case user switches tabs and requestAnimationFrame pauses)
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    maxStep: 40,
    /**
     * The type of context to request from the canvas.  2d or 3d
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    contextType: '2d',
    /**
     * The height of the Game and canvas
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    height: 0,
    /**
     * The width of the Game and canvas
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    width: 0,
    /**
     * The ResourceManager to be used for game
     * @type {ResourceManager}
     * @memberOf GameCore#
     * @default
     */
    resourceManager: null,
    /**
     * The InputManager to be used for game
     * @type {InputManager}
     * @memberOf GameCore#
     * @default
     */
    inputManager: null,
    /**
     * The style to be used for the foreground while game resources are loading
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    loadingForeground: '#00F',
    /**
     * The style to be used for the background while game resources are loading
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    loadingBackground: '#FFF',
    /**
     * The ID of a DOM element that contains the game's canvas
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    gameAreaId: null,
    /**
     * The percentage (0 to 1.0) of the height and width the canvas should use to fill in its container DOM element
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    canvasPercentage: 0,
    /**
     * Request ID of the most recent animation frame
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    requestId: null,

    constructor: function(){
      /**
       * Can be overriden to do things before the update is called, used by BoxGame to update Box state before update is called.
       * @function preUpdate
       * @memberOf GameCore#
       * @param {Number} elapsedTime Elapsed time in milliseconds
       * @deprecated Deprecated in favor of beforeUpdate
       */
      /**
       * Can be overriden to do things before the update is called, used by BoxGame to update Box state before update is called.
       * @function beforeUpdate
       * @memberOf GameCore#
       * @param {Number} elapsedTime Elapsed time in milliseconds
       * @deprecated Deprecated in favor of beforeUpdate
       */
      var before = this.preUpdate || this.beforeUpdate;
      if(before){
        advise.before(this, 'update', before);
      }
    },

    /**
     * Sets the height on your GameCore instance and on your canvas reference
     * @function
     * @memberOf GameCore#
     * @param {Number} newHeight The new height desired
     */
    setHeight: function(newHeight){
      this.height = newHeight;
      this.canvas.height = newHeight;
    },

    /**
     * Sets the width on your GameCore instance and on your canvas reference
     * @function
     * @memberOf GameCore#
     * @param {Number} newWidth The new width desired
     */
    setWidth: function(newWidth){
      this.width = newWidth;
      this.canvas.width = newWidth;
    },

    /**
     * Signals the game loop that it's time to quit
     * @function
     * @memberOf GameCore#
     */
    stop: function() {
      window.cancelAnimationFrame(this.requestId);
      this.requestId = null;
      this.isRunning = false;
    },

    /**
     * Launches the game.
     * @function
     * @memberOf GameCore#
     */
    run: function() {
      if(!this.isRunning){
        this.init();
        this.loadResources(this.resourceManager);
        this.initInput(this.inputManager);
        this.launchLoop();
      }
    },

    /**
     * Can be overidden in GameCore subclasses to load images and sounds
     * @function
     * @memberOf GameCore#
     * @param {ResourceManager} resourceManager
     */
    loadResources: function(resourceManager){},

    /**
     * Sets the screen mode and initiates and objects.
     * @function
     * @memberOf GameCore#
     */
    init: function() {
      if(!this.canvas){
        this.canvas = document.getElementById(this.canvasId);
      }
      if(!this.canvas){
        alert('Sorry, your browser does not support canvas.  I recommend any browser but Internet Explorer');
        return;
      }
      if(!this.context){
        this.context = this.canvas.getContext(this.contextType);
      }
      if(!this.context){
        alert('Sorry, your browser does not support a ' + this.contextType + ' drawing surface on canvas.  I recommend any browser but Internet Explorer');
        return;
      }

      this.setHeight(this.height || this.canvas.height);
      this.setWidth(this.width || this.canvas.width);

      if(!this.inputManager){
        //handle resizing if gameArea and canvasPercentage are specified
        if(this.gameAreaId && this.canvasPercentage){
          this.inputManager = new InputManager({
            canvas: this.canvas,
            gameArea: document.getElementById(this.gameAreaId),
            canvasPercentage: this.canvasPercentage
          });
        }else{
          this.inputManager = new InputManager({
            canvas: this.canvas
          });
        }
      }

      this.inputManager.resize();

      if(!this.resourceManager){
        this.resourceManager = new ResourceManager();
      }
      this.loadResources(this.resourceManager);

      this.isRunning = true;
    },

    /**
     * Can be overidden in the subclasses to map user input to actions
     * @function
     * @memberOf GameCore#
     * @param {InputManager} inputManager
     */
    initInput: function(inputManager) {},

    /**
     * Can be overidden in the subclasses to deal with user input before updating the game state
     * @function
     * @memberOf GameCore#
     * @param {InputManager} inputManager
     * @param {Number} elapsedTime Elapsed time in milliseconds
     */
    handleInput: function(inputManager,elapsedTime) {},

    /**
     * Runs through the game loop until stop() is called.
     * @function
     * @memberOf GameCore#
     */
    gameLoop: function() {
      this.currTime = new Date().getTime();
      this.elapsedTime = Math.min(this.currTime - this.prevTime, this.maxStep);
      this.prevTime = this.currTime;

      //it's using a resource manager, but resources haven't finished
      if(this.resourceManager && !this.resourceManager.resourcesReady()){
        this.updateLoadingScreen(this.elapsedTime);
        this.drawLoadingScreen(this.context);
      } else {
        this.handleInput(this.inputManager,this.elapsedTime);
        if(!this.paused){
          // update
          this.update(this.elapsedTime);
        }
        // draw the screen
        this.context.save();
        this.draw(this.context);
        this.context.restore();
      }
    },

    /**
     * Launches the game loop.
     * @function
     * @memberOf GameCore#
     */
    launchLoop: function(){
      this.elapsedTime = 0;
      var startTime = Date.now();
      this.currTime = startTime;
      this.prevTime = startTime;

      //need to keep the context defined here so the game loop has access to it
      this.loopRunner = _.bind(this.loopRunner, this);
      this.requestId = window.requestAnimationFrame(this.loopRunner);
    },

    loopRunner: function(){
      this.gameLoop();
      this.requestId = window.requestAnimationFrame(this.loopRunner);
    },

    /**
     * Should be overridden to update the state of the game/animation based on the amount of elapsed time that has passed.
     * @function
     * @memberOf GameCore#
     * @param {Number} elapsedTime Elapsed time in milliseconds
     */
    update: function(elapsedTime) {},

    /**
     * Can be overridden to update the state of the game/animation while a custom loading screen is displayed.
     * @function
     * @memberOf GameCore#
     * @param {Number} elapsedTime Elapsed time in milliseconds
     */
    updateLoadingScreen: function(elapsedTime) {},

    /**
     * Draws to the screen. Subclasses or instances must override this method to paint items to the screen.
     * @function
     * @memberOf GameCore#
     * @param {Context} context An HTML5 canvas drawing context.
     */
    draw: function(context){
      if(this.contextType === '2d'){
        context.font = "14px sans-serif";
        context.fillText("This game does not have its own draw function!", 10, 50);
      }
    },

    /**
     * Draws the progress of the resource manger to the screen while loading.
     * Subclasses or instances may override for custom loading animations.
     * @function
     * @memberOf GameCore#
     * @param {Context} context An HTML5 canvas drawing context.
     */
    drawLoadingScreen: function(context){
      if(this.resourceManager && (this.contextType === '2d')){
        context.fillStyle = this.loadingBackground;
        context.fillRect(0,0, this.width,this.height);

        context.fillStyle = this.loadingForeground;
        context.strokeStyle = this.loadingForeground;

        var textPxSize = Math.floor(this.height/12);

        context.font = "bold " + textPxSize + "px sans-serif";

        context.fillText("Loading... " + this.resourceManager.getPercentComplete() + "%", this.width * 0.1, this.height * 0.55);

        context.strokeRect(this.width * 0.1, this.height * 0.7, this.width * 0.8, this.height * 0.1);
        context.fillRect(this.width * 0.1, this.height * 0.7, (this.width * 0.8) * this.resourceManager.getPercentComplete()/100, this.height * 0.1);

        context.lineWidth = 4;
      }
    }
  });

});
<commit_msg>Remove redundant loadResources call<commit_after>/**
 * The GameCore class provides the base to build games on.
 * @name GameCore
 * @constructor GameCore
 * @example
 * var myGame = new GameCore({
 *   canvasId: 'myCanvas',
 *   update: function(millis){
 *     // do updating of game state
 *   },
 *   draw: function(context){
 *     // do drawing of the game
 *   }
 * });
 *
 * //start the game
 * myGame.run();
 */

define([
  'dcl',
  'dcl/advise',
  'dcl/bases/Mixer',
  'lodash',
  './InputManager',
  './ResourceManager',
  './shims/RAF'
], function(dcl, advise, Mixer, _, InputManager, ResourceManager){

  'use strict';

  return dcl(Mixer, {
    /**
     * A map of static constants for internal use
     * @type {Object}
     * @memberOf GameCore#
     * @property {Number} FONT_SIZE Default font size used in default draw functions
     */
    statics: {
      FONT_SIZE: 24
    },
    /**
     * Whether or not the game should be running its loop
     * @type {Boolean}
     * @memberOf GameCore#
     * @default
     */
    isRunning: false,
    /**
     * The id of the canvas element to use render the game on
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    canvasId: null,
    /**
     * Max number of milliseconds between updates. (in case user switches tabs and requestAnimationFrame pauses)
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    maxStep: 40,
    /**
     * The type of context to request from the canvas.  2d or 3d
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    contextType: '2d',
    /**
     * The height of the Game and canvas
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    height: 0,
    /**
     * The width of the Game and canvas
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    width: 0,
    /**
     * The ResourceManager to be used for game
     * @type {ResourceManager}
     * @memberOf GameCore#
     * @default
     */
    resourceManager: null,
    /**
     * The InputManager to be used for game
     * @type {InputManager}
     * @memberOf GameCore#
     * @default
     */
    inputManager: null,
    /**
     * The style to be used for the foreground while game resources are loading
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    loadingForeground: '#00F',
    /**
     * The style to be used for the background while game resources are loading
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    loadingBackground: '#FFF',
    /**
     * The ID of a DOM element that contains the game's canvas
     * @type {String}
     * @memberOf GameCore#
     * @default
     */
    gameAreaId: null,
    /**
     * The percentage (0 to 1.0) of the height and width the canvas should use to fill in its container DOM element
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    canvasPercentage: 0,
    /**
     * Request ID of the most recent animation frame
     * @type {Number}
     * @memberOf GameCore#
     * @default
     */
    requestId: null,

    constructor: function(){
      /**
       * Can be overriden to do things before the update is called, used by BoxGame to update Box state before update is called.
       * @function preUpdate
       * @memberOf GameCore#
       * @param {Number} elapsedTime Elapsed time in milliseconds
       * @deprecated Deprecated in favor of beforeUpdate
       */
      /**
       * Can be overriden to do things before the update is called, used by BoxGame to update Box state before update is called.
       * @function beforeUpdate
       * @memberOf GameCore#
       * @param {Number} elapsedTime Elapsed time in milliseconds
       * @deprecated Deprecated in favor of beforeUpdate
       */
      var before = this.preUpdate || this.beforeUpdate;
      if(before){
        advise.before(this, 'update', before);
      }
    },

    /**
     * Sets the height on your GameCore instance and on your canvas reference
     * @function
     * @memberOf GameCore#
     * @param {Number} newHeight The new height desired
     */
    setHeight: function(newHeight){
      this.height = newHeight;
      this.canvas.height = newHeight;
    },

    /**
     * Sets the width on your GameCore instance and on your canvas reference
     * @function
     * @memberOf GameCore#
     * @param {Number} newWidth The new width desired
     */
    setWidth: function(newWidth){
      this.width = newWidth;
      this.canvas.width = newWidth;
    },

    /**
     * Signals the game loop that it's time to quit
     * @function
     * @memberOf GameCore#
     */
    stop: function() {
      window.cancelAnimationFrame(this.requestId);
      this.requestId = null;
      this.isRunning = false;
    },

    /**
     * Launches the game.
     * @function
     * @memberOf GameCore#
     */
    run: function() {
      if(!this.isRunning){
        this.init();
        this.loadResources(this.resourceManager);
        this.initInput(this.inputManager);
        this.launchLoop();
      }
    },

    /**
     * Can be overidden in GameCore subclasses to load images and sounds
     * @function
     * @memberOf GameCore#
     * @param {ResourceManager} resourceManager
     */
    loadResources: function(resourceManager){},

    /**
     * Sets the screen mode and initiates and objects.
     * @function
     * @memberOf GameCore#
     */
    init: function() {
      if(!this.canvas){
        this.canvas = document.getElementById(this.canvasId);
      }
      if(!this.canvas){
        alert('Sorry, your browser does not support canvas.  I recommend any browser but Internet Explorer');
        return;
      }
      if(!this.context){
        this.context = this.canvas.getContext(this.contextType);
      }
      if(!this.context){
        alert('Sorry, your browser does not support a ' + this.contextType + ' drawing surface on canvas.  I recommend any browser but Internet Explorer');
        return;
      }

      this.setHeight(this.height || this.canvas.height);
      this.setWidth(this.width || this.canvas.width);

      if(!this.inputManager){
        //handle resizing if gameArea and canvasPercentage are specified
        if(this.gameAreaId && this.canvasPercentage){
          this.inputManager = new InputManager({
            canvas: this.canvas,
            gameArea: document.getElementById(this.gameAreaId),
            canvasPercentage: this.canvasPercentage
          });
        }else{
          this.inputManager = new InputManager({
            canvas: this.canvas
          });
        }
      }

      this.inputManager.resize();

      if(!this.resourceManager){
        this.resourceManager = new ResourceManager();
      }

      this.isRunning = true;
    },

    /**
     * Can be overidden in the subclasses to map user input to actions
     * @function
     * @memberOf GameCore#
     * @param {InputManager} inputManager
     */
    initInput: function(inputManager) {},

    /**
     * Can be overidden in the subclasses to deal with user input before updating the game state
     * @function
     * @memberOf GameCore#
     * @param {InputManager} inputManager
     * @param {Number} elapsedTime Elapsed time in milliseconds
     */
    handleInput: function(inputManager,elapsedTime) {},

    /**
     * Runs through the game loop until stop() is called.
     * @function
     * @memberOf GameCore#
     */
    gameLoop: function() {
      this.currTime = new Date().getTime();
      this.elapsedTime = Math.min(this.currTime - this.prevTime, this.maxStep);
      this.prevTime = this.currTime;

      //it's using a resource manager, but resources haven't finished
      if(this.resourceManager && !this.resourceManager.resourcesReady()){
        this.updateLoadingScreen(this.elapsedTime);
        this.drawLoadingScreen(this.context);
      } else {
        this.handleInput(this.inputManager,this.elapsedTime);
        if(!this.paused){
          // update
          this.update(this.elapsedTime);
        }
        // draw the screen
        this.context.save();
        this.draw(this.context);
        this.context.restore();
      }
    },

    /**
     * Launches the game loop.
     * @function
     * @memberOf GameCore#
     */
    launchLoop: function(){
      this.elapsedTime = 0;
      var startTime = Date.now();
      this.currTime = startTime;
      this.prevTime = startTime;

      //need to keep the context defined here so the game loop has access to it
      this.loopRunner = _.bind(this.loopRunner, this);
      this.requestId = window.requestAnimationFrame(this.loopRunner);
    },

    loopRunner: function(){
      this.gameLoop();
      this.requestId = window.requestAnimationFrame(this.loopRunner);
    },

    /**
     * Should be overridden to update the state of the game/animation based on the amount of elapsed time that has passed.
     * @function
     * @memberOf GameCore#
     * @param {Number} elapsedTime Elapsed time in milliseconds
     */
    update: function(elapsedTime) {},

    /**
     * Can be overridden to update the state of the game/animation while a custom loading screen is displayed.
     * @function
     * @memberOf GameCore#
     * @param {Number} elapsedTime Elapsed time in milliseconds
     */
    updateLoadingScreen: function(elapsedTime) {},

    /**
     * Draws to the screen. Subclasses or instances must override this method to paint items to the screen.
     * @function
     * @memberOf GameCore#
     * @param {Context} context An HTML5 canvas drawing context.
     */
    draw: function(context){
      if(this.contextType === '2d'){
        context.font = "14px sans-serif";
        context.fillText("This game does not have its own draw function!", 10, 50);
      }
    },

    /**
     * Draws the progress of the resource manger to the screen while loading.
     * Subclasses or instances may override for custom loading animations.
     * @function
     * @memberOf GameCore#
     * @param {Context} context An HTML5 canvas drawing context.
     */
    drawLoadingScreen: function(context){
      if(this.resourceManager && (this.contextType === '2d')){
        context.fillStyle = this.loadingBackground;
        context.fillRect(0,0, this.width,this.height);

        context.fillStyle = this.loadingForeground;
        context.strokeStyle = this.loadingForeground;

        var textPxSize = Math.floor(this.height/12);

        context.font = "bold " + textPxSize + "px sans-serif";

        context.fillText("Loading... " + this.resourceManager.getPercentComplete() + "%", this.width * 0.1, this.height * 0.55);

        context.strokeRect(this.width * 0.1, this.height * 0.7, this.width * 0.8, this.height * 0.1);
        context.fillRect(this.width * 0.1, this.height * 0.7, (this.width * 0.8) * this.resourceManager.getPercentComplete()/100, this.height * 0.1);

        context.lineWidth = 4;
      }
    }
  });

});
<|endoftext|>