<commit_before>// @flow
import type { PluginInterface } from '../types';

/**
 * Project deps
 * @private
 */
const Promise = require('bluebird');
const Errors = require('common-errors');
const assert = require('assert');
const is = require('is');
const _require = require('../utils/require');

const { ActionTransport, PluginsTypes } = require('../constants');
const getAMQPRouterAdapter = require('./amqp/router/adapter');
const verifyPossibility = require('./router/verifyAttachPossibility');

/**
 * Helpers Section
 */
const NULL_UUID = '00000000-0000-0000-0000-000000000000';

/**
 * Calculate priority based on message expiration time.
 * Logic behind it is to give each expiration a certain priority bucket
 * based on the amount of priority levels in the RabbitMQ queue.
 * @param {number} expiration - Current expiration (retry) time.
 * @param {number} maxExpiration - Max possible expiration (retry) time.
 * @returns {number} Queue Priority Level.
 */
function calculatePriority(expiration, maxExpiration) {
  const newExpiration = Math.min(expiration, maxExpiration);
  return 100 - Math.floor((newExpiration / maxExpiration) * 100);
}

/**
 * Plugin Name
 * @type {String}
 */
exports.name = 'amqp';

/**
 * Plugin Type
 * @type {String}
 */
exports.type = PluginsTypes.transport;

/**
 * Attaches plugin to the MService class.
 * @param {Object} config - AMQP plugin configuration.
 */
exports.attach = function attachAMQPPlugin(config: Object): PluginInterface {
  const service = this;

  const AMQPTransport = _require('@microfleet/transport-amqp');
  const Backoff = require('@microfleet/transport-amqp/lib/utils/recovery');

  if (is.fn(service.validateSync)) {
    assert.ifError(service.validateSync('amqp', config).error);
  }

  // init logger if service is enabled
  const logger = service._log && service._log.child({ namespace: '@microfleet/transport-amqp' });

  // initializes custom onComplete function
  if (config.retry && config.retry.enabled === true) {
    assert.equal(
      config.transport.bindPersistantQueueToHeadersExchange, true,
      'config.transport.bindPersistantQueueToHeadersExchange must be set to true'
    );
    assert.ok(config.retry.queue || config.transport.queue, '`retry.queue` or `transport.queue` must be truthy string');
    assert.equal(typeof config.transport.onComplete, 'undefined', 'transport.onComplete must be undefined');
    assert.equal(typeof config.transport.neck, 'number', 'neck must be set to >= 0');
    assert.ok(config.transport.neck >= 0, 'neck must be set for the retry to work');
    assert.equal(typeof config.retry.predicate, 'function', '`retry.predicate` must be defined');

    // adds queue setup connector - will be initialized after AMQP is connected
    service.retryQueue = config.retry.queue || `x-delay-${config.transport.queue}`;

    // cache vars for faster access
    const { retry } = config.retry;
    const { predicate, maxRetries } = retry;
    const backoff = new Backoff({ qos: retry });

    /**
      * Composes onComplete handler for QoS enabled Subscriber.
      * Allows one to set custom fast-rejection policy.
      * Relies on certain configuration options of the initialized service.
      *
      * @param {Error} err - Possible error.
      * @param {Mixed} data - Anything that is a response.
      * @param {string} actionName - In-flight action name.
      * @param {Object} message - An amqp-coffee raw message.
      */
    config.transport.onComplete = function onComplete(err, data, actionName, message) {
      const { properties } = message;
      const { headers } = properties;

      // reassign back so that response can be routed properly
      if (headers['x-original-correlation-id'] !== undefined) {
        properties.correlationId = headers['x-original-correlation-id'];
      }

      if (headers['x-original-reply-to'] !== undefined) {
        properties.replyTo = headers['x-original-reply-to'];
      }

      if (!err) {
        if (logger !== undefined) logger.info('Sent, ack: [%s]', actionName);
        message.ack();
        return data;
      }

      // check for current try
      err.retryAttempt = (headers['x-retry-count'] || 0);
      const retryCount = err.retryAttempt + 1;

      // quite complex, basicaly verifies that these are not logic errors
      // and that if there were no other problems - that we haven't exceeded max retries
      if (predicate(err, actionName) || retryCount > maxRetries) {
        // we must ack, otherwise message would be returned to sender with reject
        // instead of promise.reject
        message.ack();
        if (logger !== undefined) {
          const logLevel = err.retryAttempt === 0 ? 'warn' : 'error';
          logger[logLevel]({ err, properties }, 'Failed: [%s]', actionName);
        }
        return Promise.reject(err);
      }

      // assume that predefined accounts must not fail - credentials are correct
      if (logger !== undefined) logger.warn({ err, properties }, 'Retry: [%s]', actionName);

      // retry message options
      const expiration = backoff.get('qos', retryCount);
      const retryMessageOptions: any = {
        skipSerialize: true,
        confirm: true,
        mandatory: true,
        expiration: expiration.toString(),
        priority: calculatePriority(expiration, retry.max),
        headers: {
          'routing-key': actionName,
          'x-retry-count': retryCount,
          'x-original-error': String(err),
        },
      };

      // deal with special routing properties
      const { replyTo, correlationId } = properties;

      // correlation id is used in routing stuff back from DLX, so we have to "hide" it
      // same with replyTo
      if (replyTo !== undefined) {
        retryMessageOptions.headers['x-original-reply-to'] = replyTo;
      }

      if (correlationId !== undefined) {
        retryMessageOptions.headers['x-original-correlation-id'] = correlationId;
      }

      return service.amqp
        .send(service.retryQueue, message.raw, retryMessageOptions)
        .catch((e) => {
          if (logger !== undefined) logger.error({ err: e }, 'Failed to queue retried message');
          message.retry();
          return Promise.reject(err);
        })
        .then(() => {
          if (logger !== undefined) logger.debug('queued retry message');
          message.ack();

          // enrich error
          err.scheduledRetry = true;

          // reset correlation id
          // that way response will actually come, but won't be routed in the private router
          // of the sender
          properties.correlationId = NULL_UUID;

          // reject with an error, yet a retry will still occur
          return Promise.reject(err);
        });
    };
  }

  if (config.router && config.router.enabled === true) {
    verifyPossibility(service.router, ActionTransport.amqp);
    service.AMQPRouter = getAMQPRouterAdapter(service.router, config);
    // allow ms-amqp-transport to discover routes
    config.transport.listen = Object.keys(service.router.routes.amqp);
  }

  return {

    /**
     * Generic AMQP Connector.
     * @returns {Promise<AMQPTransport>} Opens connection to AMQP.
     */
    connect: function connectToAMQP() {
      if (service._amqp) {
        return Promise.reject(new Errors.NotPermittedError('amqp was already started'));
      }

      // if service.router is present - we will consume messages
      // if not - we will only create a client
      return AMQPTransport
        .connect({
          ...config.transport,
          tracer: service._tracer,
          log: logger || null,
        }, service.AMQPRouter)
        .tap((amqp) => {
          // create extra queue for retry logic based on RabbitMQ DLX & headers exchanges
          if (config.retry && config.retry.enabled === true) {
            // in case defaults were overwritten - throw here
            assert.ok(amqp.config.headersExchange.exchange, 'transport.headersExchange.exchange must be set');

            return amqp.createQueue({
              queue: service.retryQueue,
              autoDelete: false,
              durable: true,
              router: null,
              arguments: {
                'x-dead-letter-exchange': amqp.config.headersExchange.exchange,
                'x-max-priority': 100, // to support proper priorities
              },
            });
          }

          return null;
        })
        .tap((amqp) => {
          service._amqp = amqp;
          service.emit('plugin:connect:amqp', amqp);
        });
    },

    /**
     * Generic AMQP disconnector.
     * @returns {Promise<void>} Closes connection to AMQP.
     */
    close: function disconnectFromAMQP() {
      if (!service._amqp || !(service._amqp instanceof AMQPTransport)) {
        return Promise.reject(new Errors.NotPermittedError('amqp was not started'));
      }

      const amqp = service._amqp;
      return amqp.close()
        .tap(() => {
          service._amqp = null;
          service.emit('plugin:close:amqp');
        });
    },

  };
};
<commit_msg>chore(amqp): invalid destructuring typo<commit_after>// @flow
import type { PluginInterface } from '../types';

/**
 * Project deps
 * @private
 */
const Promise = require('bluebird');
const Errors = require('common-errors');
const assert = require('assert');
const is = require('is');
const _require = require('../utils/require');

const { ActionTransport, PluginsTypes } = require('../constants');
const getAMQPRouterAdapter = require('./amqp/router/adapter');
const verifyPossibility = require('./router/verifyAttachPossibility');

/**
 * Helpers Section
 */
const NULL_UUID = '00000000-0000-0000-0000-000000000000';

/**
 * Calculate priority based on message expiration time.
 * Logic behind it is to give each expiration a certain priority bucket
 * based on the amount of priority levels in the RabbitMQ queue.
 * @param {number} expiration - Current expiration (retry) time.
 * @param {number} maxExpiration - Max possible expiration (retry) time.
 * @returns {number} Queue Priority Level.
 */
function calculatePriority(expiration, maxExpiration) {
  const newExpiration = Math.min(expiration, maxExpiration);
  return 100 - Math.floor((newExpiration / maxExpiration) * 100);
}

/**
 * Plugin Name
 * @type {String}
 */
exports.name = 'amqp';

/**
 * Plugin Type
 * @type {String}
 */
exports.type = PluginsTypes.transport;

/**
 * Attaches plugin to the MService class.
 * @param {Object} config - AMQP plugin configuration.
 */
exports.attach = function attachAMQPPlugin(config: Object): PluginInterface {
  const service = this;

  const AMQPTransport = _require('@microfleet/transport-amqp');
  const Backoff = require('@microfleet/transport-amqp/lib/utils/recovery');

  if (is.fn(service.validateSync)) {
    assert.ifError(service.validateSync('amqp', config).error);
  }

  // init logger if service is enabled
  const logger = service._log && service._log.child({ namespace: '@microfleet/transport-amqp' });

  // initializes custom onComplete function
  if (config.retry && config.retry.enabled === true) {
    assert.equal(
      config.transport.bindPersistantQueueToHeadersExchange, true,
      'config.transport.bindPersistantQueueToHeadersExchange must be set to true'
    );
    assert.ok(config.retry.queue || config.transport.queue, '`retry.queue` or `transport.queue` must be truthy string');
    assert.equal(typeof config.transport.onComplete, 'undefined', 'transport.onComplete must be undefined');
    assert.equal(typeof config.transport.neck, 'number', 'neck must be set to >= 0');
    assert.ok(config.transport.neck >= 0, 'neck must be set for the retry to work');
    assert.equal(typeof config.retry.predicate, 'function', '`retry.predicate` must be defined');

    // adds queue setup connector - will be initialized after AMQP is connected
    service.retryQueue = config.retry.queue || `x-delay-${config.transport.queue}`;

    // cache vars for faster access
    const { retry } = config;
    const { predicate, maxRetries } = retry;
    const backoff = new Backoff({ qos: retry });

    /**
      * Composes onComplete handler for QoS enabled Subscriber.
      * Allows one to set custom fast-rejection policy.
      * Relies on certain configuration options of the initialized service.
      *
      * @param {Error} err - Possible error.
      * @param {Mixed} data - Anything that is a response.
      * @param {string} actionName - In-flight action name.
      * @param {Object} message - An amqp-coffee raw message.
      */
    config.transport.onComplete = function onComplete(err, data, actionName, message) {
      const { properties } = message;
      const { headers } = properties;

      // reassign back so that response can be routed properly
      if (headers['x-original-correlation-id'] !== undefined) {
        properties.correlationId = headers['x-original-correlation-id'];
      }

      if (headers['x-original-reply-to'] !== undefined) {
        properties.replyTo = headers['x-original-reply-to'];
      }

      if (!err) {
        if (logger !== undefined) logger.info('Sent, ack: [%s]', actionName);
        message.ack();
        return data;
      }

      // check for current try
      err.retryAttempt = (headers['x-retry-count'] || 0);
      const retryCount = err.retryAttempt + 1;

      // quite complex, basicaly verifies that these are not logic errors
      // and that if there were no other problems - that we haven't exceeded max retries
      if (predicate(err, actionName) || retryCount > maxRetries) {
        // we must ack, otherwise message would be returned to sender with reject
        // instead of promise.reject
        message.ack();
        if (logger !== undefined) {
          const logLevel = err.retryAttempt === 0 ? 'warn' : 'error';
          logger[logLevel]({ err, properties }, 'Failed: [%s]', actionName);
        }
        return Promise.reject(err);
      }

      // assume that predefined accounts must not fail - credentials are correct
      if (logger !== undefined) logger.warn({ err, properties }, 'Retry: [%s]', actionName);

      // retry message options
      const expiration = backoff.get('qos', retryCount);
      const retryMessageOptions: any = {
        skipSerialize: true,
        confirm: true,
        mandatory: true,
        expiration: expiration.toString(),
        priority: calculatePriority(expiration, retry.max),
        headers: {
          'routing-key': actionName,
          'x-retry-count': retryCount,
          'x-original-error': String(err),
        },
      };

      // deal with special routing properties
      const { replyTo, correlationId } = properties;

      // correlation id is used in routing stuff back from DLX, so we have to "hide" it
      // same with replyTo
      if (replyTo !== undefined) {
        retryMessageOptions.headers['x-original-reply-to'] = replyTo;
      }

      if (correlationId !== undefined) {
        retryMessageOptions.headers['x-original-correlation-id'] = correlationId;
      }

      return service.amqp
        .send(service.retryQueue, message.raw, retryMessageOptions)
        .catch((e) => {
          if (logger !== undefined) logger.error({ err: e }, 'Failed to queue retried message');
          message.retry();
          return Promise.reject(err);
        })
        .then(() => {
          if (logger !== undefined) logger.debug('queued retry message');
          message.ack();

          // enrich error
          err.scheduledRetry = true;

          // reset correlation id
          // that way response will actually come, but won't be routed in the private router
          // of the sender
          properties.correlationId = NULL_UUID;

          // reject with an error, yet a retry will still occur
          return Promise.reject(err);
        });
    };
  }

  if (config.router && config.router.enabled === true) {
    verifyPossibility(service.router, ActionTransport.amqp);
    service.AMQPRouter = getAMQPRouterAdapter(service.router, config);
    // allow ms-amqp-transport to discover routes
    config.transport.listen = Object.keys(service.router.routes.amqp);
  }

  return {

    /**
     * Generic AMQP Connector.
     * @returns {Promise<AMQPTransport>} Opens connection to AMQP.
     */
    connect: function connectToAMQP() {
      if (service._amqp) {
        return Promise.reject(new Errors.NotPermittedError('amqp was already started'));
      }

      // if service.router is present - we will consume messages
      // if not - we will only create a client
      return AMQPTransport
        .connect({
          ...config.transport,
          tracer: service._tracer,
          log: logger || null,
        }, service.AMQPRouter)
        .tap((amqp) => {
          // create extra queue for retry logic based on RabbitMQ DLX & headers exchanges
          if (config.retry && config.retry.enabled === true) {
            // in case defaults were overwritten - throw here
            assert.ok(amqp.config.headersExchange.exchange, 'transport.headersExchange.exchange must be set');

            return amqp.createQueue({
              queue: service.retryQueue,
              autoDelete: false,
              durable: true,
              router: null,
              arguments: {
                'x-dead-letter-exchange': amqp.config.headersExchange.exchange,
                'x-max-priority': 100, // to support proper priorities
              },
            });
          }

          return null;
        })
        .tap((amqp) => {
          service._amqp = amqp;
          service.emit('plugin:connect:amqp', amqp);
        });
    },

    /**
     * Generic AMQP disconnector.
     * @returns {Promise<void>} Closes connection to AMQP.
     */
    close: function disconnectFromAMQP() {
      if (!service._amqp || !(service._amqp instanceof AMQPTransport)) {
        return Promise.reject(new Errors.NotPermittedError('amqp was not started'));
      }

      const amqp = service._amqp;
      return amqp.close()
        .tap(() => {
          service._amqp = null;
          service.emit('plugin:close:amqp');
        });
    },

  };
};
<|endoftext|>


<commit_before>	game.PlayerEntity = me.Entity.extend({
		// classes have both letters capital
		init:function(x, y, settings){
			this._super(me.Entity, 'init', [x, y, {
				// this._super reaches to the constructor of entity
				image: "player",
				width: 64,
				// how much space is reserved for the image
				height: 64,
				spritewidth: "64",
				// passing main info size of image
				spriteheight: "64",
				getShape: function(){
					return(new me.Rect(0, 0, 64, 64)).toPolygon();
														//method:toPolygon make the Rectangle polygon,
														// sode note all methods also fallow the naming convention that the first word is lower case and the socond is capital
				}
			}]);

			this.body.setVelocity(5,20);
			// movement speed vurticle velocity has benn set to 20
			// to allow the character to touch the ground
		},

		update: function(delta) {
			if(me.input.isKeyPressed("right")){
				// adds to position of x by the velocity defined above in
				// aesVelocity() and multiplying it by me.timer.tick.
				// me.timer.tick makes the movement look smooth
				this.body.vel.x += this.body.accel.x * me.timer.tick;

			}else{
				this.body.vel.x = 0;
			}

			this.body.update (delta);
			return true;
		}
	});<commit_msg>push 6 character animation<commit_after>	game.PlayerEntity = me.Entity.extend({
		// classes have both letters capital
		init:function(x, y, settings){
			this._super(me.Entity, 'init', [x, y, {
				// this._super reaches to the constructor of entity
				image: "player",
				width: 64,
				// how much space is reserved for the image
				height: 64,
				spritewidth: "64",
				// passing main info size of image
				spriteheight: "64",
				getShape: function(){
					return(new me.Rect(0, 0, 64, 64)).toPolygon();
				//method:toPolygon make the Rectangle polygon,
				// sode note all methods also fallow the naming convention that the first word is lower case and the socond is capital
				}
			}]);

			this.body.setVelocity(5,20);
			// movement speed vurticle velocity has benn set to 20
			// to allow the character to touch the ground

			  this.renderable.addAnimation("idle", [78]);
			  this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80);

			  this.renderable.setCurrentAnimation("idle");
			  this.renderable.setCurrentAnimation("walk");
		},

		update: function(delta) {
			if(me.input.isKeyPressed("right")){
				// adds to position of x by the velocity defined above in
				// aesVelocity() and multiplying it by me.timer.tick.
				// me.timer.tick makes the movement look smooth
				this.body.vel.x += this.body.accel.x * me.timer.tick;
				this.flipX(true);

			}else{
				this.body.vel.x = 0;
			}

			if(this.body.vel.x !== 0){
			if(!this.renderable.isCurrentAnimation("walk")) {
				this.renderable.setCurrentAnimation("walk");
			}
		}else{
			this.renderable.setCurrentAnimation("idle");
		}

			this.body.update (delta);

			this._super(me.Entity,"update",[delta]);
			return true;
		}
	});<|endoftext|>


<commit_before>import { _ } from 'meteor/underscore';
import { Meteor } from 'meteor/meteor';
import { check, Match } from 'meteor/check';
import { Counts } from 'meteor/tmeasday:publish-counts';

class PaginationFactory {
  constructor(collection, settingsIn) {
    if (!(this instanceof Meteor.Pagination)) {
      // eslint-disable-next-line max-len
      throw new Meteor.Error(4000, 'The Meteor.Pagination instance has to be initiated with `new`');
    }

    const settings = _.extend(
      {
        name : collection._name,
        filters: {},
        dynamic_filters() {
          return {};
        },
      },

      settingsIn || {}
    );
    console.log(settings.name);

    if (typeof settings.filters !== 'object') {
      // eslint-disable-next-line max-len
      throw new Meteor.Error(4001, 'Invalid filters provided. Server side filters need to be an object!');
    }

    if (typeof settings.dynamic_filters !== 'function') {
      // eslint-disable-next-line max-len
      throw new Meteor.Error(4002, 'Invalid dynamic filters provided. Server side dynamic filters needs to be a function!');
    }

    this.publish(collection, settings);
  }

  publish(collection, settings) {
    console.log(collection);
    console.log(settings);

    Meteor.publish(settings.name, function addPub(query = {}, optionsInput = {}) {
      check(query, Match.Optional(Object));
      check(optionsInput, Match.Optional(Object));

      const self = this;
      let options = optionsInput;
      let findQuery = {};
      let filters = [];

      if (!_.isEmpty(query)) {
        filters.push(query);
      }

      if (!_.isEmpty(settings.filters)) {
        filters.push(settings.filters);
      }

      const dynamic_filters = settings.dynamic_filters.call(self);

      if (typeof dynamic_filters === 'object') {
        if (!_.isEmpty(dynamic_filters)) {
          filters.push(dynamic_filters);
        }
      } else {
        // eslint-disable-next-line max-len
        throw new Meteor.Error(4002, 'Invalid dynamic filters return type. Server side dynamic filters needs to be a function that returns an object!');
      }

      if (typeof settings.transform_filters === 'function') {
        filters = settings.transform_filters.call(self, filters, options);
      }

      if (typeof settings.transform_options === 'function') {
        options = settings.transform_options.call(self, filters, options);
      }

      if (filters.length > 0) {
        if (filters.length > 1) {
          findQuery.$and = filters;
        } else {
          findQuery = filters[0];
        }
      }

      Counts.publish(
        self,
        `sub_count_${self._subscriptionId}`,
        collection.find(findQuery),
        { noReady: true }
      );

      if (options.debug) {
        console.log(
          'Pagination',
          settings.name,
          'find',
          JSON.stringify(findQuery),
          JSON.stringify(options)
        );
      }

      const handle = collection.find(findQuery, options).observeChanges({
        added(id, fields) {
          const newFields = {};

          self.added(collection._name, id, fields);

          newFields[`sub_${self._subscriptionId}`] = 1;
          self.changed(collection._name, id, newFields);
        },
        changed(id, fields) {
          self.changed(collection._name, id, fields);
        },
        removed(id) {
          self.removed(collection._name, id);
        },
      });

      self.ready();

      self.onStop(() => {
        handle.stop();
      });
    });
  }
}

Meteor.Pagination = PaginationFactory;
<commit_msg>removed unnecessary console.log statements<commit_after>import { _ } from 'meteor/underscore';
import { Meteor } from 'meteor/meteor';
import { check, Match } from 'meteor/check';
import { Counts } from 'meteor/tmeasday:publish-counts';

class PaginationFactory {
  constructor(collection, settingsIn) {
    if (!(this instanceof Meteor.Pagination)) {
      // eslint-disable-next-line max-len
      throw new Meteor.Error(4000, 'The Meteor.Pagination instance has to be initiated with `new`');
    }

    const settings = _.extend(
      {
        name : collection._name,
        filters: {},
        dynamic_filters() {
          return {};
        },
      },

      settingsIn || {}
    );

    if (typeof settings.filters !== 'object') {
      // eslint-disable-next-line max-len
      throw new Meteor.Error(4001, 'Invalid filters provided. Server side filters need to be an object!');
    }

    if (typeof settings.dynamic_filters !== 'function') {
      // eslint-disable-next-line max-len
      throw new Meteor.Error(4002, 'Invalid dynamic filters provided. Server side dynamic filters needs to be a function!');
    }

    this.publish(collection, settings);
  }

  publish(collection, settings) {

    Meteor.publish(settings.name, function addPub(query = {}, optionsInput = {}) {
      check(query, Match.Optional(Object));
      check(optionsInput, Match.Optional(Object));

      const self = this;
      let options = optionsInput;
      let findQuery = {};
      let filters = [];

      if (!_.isEmpty(query)) {
        filters.push(query);
      }

      if (!_.isEmpty(settings.filters)) {
        filters.push(settings.filters);
      }

      const dynamic_filters = settings.dynamic_filters.call(self);

      if (typeof dynamic_filters === 'object') {
        if (!_.isEmpty(dynamic_filters)) {
          filters.push(dynamic_filters);
        }
      } else {
        // eslint-disable-next-line max-len
        throw new Meteor.Error(4002, 'Invalid dynamic filters return type. Server side dynamic filters needs to be a function that returns an object!');
      }

      if (typeof settings.transform_filters === 'function') {
        filters = settings.transform_filters.call(self, filters, options);
      }

      if (typeof settings.transform_options === 'function') {
        options = settings.transform_options.call(self, filters, options);
      }

      if (filters.length > 0) {
        if (filters.length > 1) {
          findQuery.$and = filters;
        } else {
          findQuery = filters[0];
        }
      }

      Counts.publish(
        self,
        `sub_count_${self._subscriptionId}`,
        collection.find(findQuery),
        { noReady: true }
      );

      if (options.debug) {
        console.log(
          'Pagination',
          settings.name,
          'find',
          JSON.stringify(findQuery),
          JSON.stringify(options)
        );
      }

      const handle = collection.find(findQuery, options).observeChanges({
        added(id, fields) {
          const newFields = {};

          self.added(collection._name, id, fields);

          newFields[`sub_${self._subscriptionId}`] = 1;
          self.changed(collection._name, id, newFields);
        },
        changed(id, fields) {
          self.changed(collection._name, id, fields);
        },
        removed(id) {
          self.removed(collection._name, id);
        },
      });

      self.ready();

      self.onStop(() => {
        handle.stop();
      });
    });
  }
}

Meteor.Pagination = PaginationFactory;
<|endoftext|>


<commit_before>//Electron's entry point (web-based RIDE doesn't load it)
const rq=require,fs=rq('fs'),path=rq('path'),{spawn}=rq('child_process'),ps=process,{env}=ps,
      repr=JSON.stringify,el=rq('electron'),D={}
//Detect platform: https://nodejs.org/api/process.html#process_process_platform
// https://stackoverflow.com/questions/19877924/what-is-the-list-of-possible-values-for-navigator-platform-as-of-today
D.win=/^win/i.test(ps.platform);D.mac=ps.platform=='darwin'
if(!env.RIDE_SPAWN&&!D.win){
  var mapl=path.dirname(ps.execPath)+(D.mac?'/../Resources/Dyalog/mapl':'/../mapl')
  if(fs.existsSync(mapl))env.RIDE_SPAWN=D.lastSpawnedExe=mapl
}
const dbf=el.app.getPath('userData')+'/winstate.json' //json "database" file for storing preferences
let db={};try{if(fs.existsSync(dbf))db=JSON.parse(fs.readFileSync(dbf,'utf8'))}catch(e){console.error(e)}
let tid;const sv=_=>{if(!tid)tid=setTimeout(svNow,2000)} //save (throttled)
const svNow=_=>{ //save now
  tid=0;try{const b=elw.getBounds(),h={main:[b.x-dx,b.y-dy,b.width,b.height,elw.isMaximized()],devTools:elw.isDevToolsOpened()}
            fs.writeFileSync(dbf,JSON.stringify(h))}catch(e){console.error(e)}
}
let dx=0,dy=0 //used to correct for bad coords misreported by Electron (NW.js has the same problem)
el.app.on('ready',_=>{
  var x,y,width,height
  if(db.main){
    [x,y,width,height]=db.main
    const b=el.screen.getDisplayMatching({x,y,width,height}).bounds
    const vw=Math.max(0,Math.min(x+width ,b.x+b.width )-Math.max(x,b.x))
    const vh=Math.max(0,Math.min(y+height,b.y+b.height)-Math.max(y,b.y))
    if(width*height>2*vw*vh){
      //saved window position is now mostly off screen
      x=y=null;width=Math.min(width,b.width);height=Math.min(height,b.height)
    }
  }
  let w=global.elw=new el.BrowserWindow({x,y,width,height,show:0,icon:'style/img/D.png'})
  db.main[4]&&w.maximize()
  el.Menu.setApplicationMenu(null);w.loadURL(`file://${__dirname}/index.html`)
  w.on('move',sv).on('resize',sv).on('maximize',sv).on('unmaximize',sv)
   .on('close',_=>{tid&&clearTimeout(tid);svNow()}).on('closed',_=>{w=global.elw=0})
   .on('show',_=>{if(x){const q=w.getPosition();dx=q[0]-x;dy=q[1]-y}}).show()
  if(D.win){const fix=_=>{setTimeout(_=>{
              if(w.isMaximized()){w.unmaximize();w.maximize()}
              else{const a=w.getSize();w.setSize(a[0],a[1]-1);w.setSize(a[0],a[1])}
            },100)}
            w.on('page-title-updated',fix).on('blur',fix)}
  db.devTools&&w.webContents.openDevTools()
})
el.app.on('window-all-closed',_=>el.app.quit())

global.ev=x=>eval(x)
global.js=(i,x)=>el.BrowserWindow.fromId(i).webContents.executeJavaScript(x)
const inc=x=>x+1
<commit_msg>fixed uncaught error when winstate doesn't exist<commit_after>//Electron's entry point (web-based RIDE doesn't load it)
const rq=require,fs=rq('fs'),path=rq('path'),{spawn}=rq('child_process'),ps=process,{env}=ps,
      repr=JSON.stringify,el=rq('electron'),D={}
//Detect platform: https://nodejs.org/api/process.html#process_process_platform
// https://stackoverflow.com/questions/19877924/what-is-the-list-of-possible-values-for-navigator-platform-as-of-today
D.win=/^win/i.test(ps.platform);D.mac=ps.platform=='darwin'
if(!env.RIDE_SPAWN&&!D.win){
  var mapl=path.dirname(ps.execPath)+(D.mac?'/../Resources/Dyalog/mapl':'/../mapl')
  if(fs.existsSync(mapl))env.RIDE_SPAWN=D.lastSpawnedExe=mapl
}
const dbf=el.app.getPath('userData')+'/winstate.json' //json "database" file for storing preferences
let db={};try{if(fs.existsSync(dbf))db=JSON.parse(fs.readFileSync(dbf,'utf8'))}catch(e){console.error(e)}
let tid;const sv=_=>{if(!tid)tid=setTimeout(svNow,2000)} //save (throttled)
const svNow=_=>{ //save now
  tid=0;try{const b=elw.getBounds(),h={main:[b.x-dx,b.y-dy,b.width,b.height,elw.isMaximized()],devTools:elw.isDevToolsOpened()}
            fs.writeFileSync(dbf,JSON.stringify(h))}catch(e){console.error(e)}
}
let dx=0,dy=0 //used to correct for bad coords misreported by Electron (NW.js has the same problem)
el.app.on('ready',_=>{
  var x,y,width,height
  if(db.main){
    [x,y,width,height]=db.main
    const b=el.screen.getDisplayMatching({x,y,width,height}).bounds
    const vw=Math.max(0,Math.min(x+width ,b.x+b.width )-Math.max(x,b.x))
    const vh=Math.max(0,Math.min(y+height,b.y+b.height)-Math.max(y,b.y))
    if(width*height>2*vw*vh){
      //saved window position is now mostly off screen
      x=y=null;width=Math.min(width,b.width);height=Math.min(height,b.height)
    }
    db.main[4]&&w.maximize()
  }
  let w=global.elw=new el.BrowserWindow({x,y,width,height,show:0,icon:'style/img/D.png'})
  el.Menu.setApplicationMenu(null);w.loadURL(`file://${__dirname}/index.html`)
  w.on('move',sv).on('resize',sv).on('maximize',sv).on('unmaximize',sv)
   .on('close',_=>{tid&&clearTimeout(tid);svNow()}).on('closed',_=>{w=global.elw=0})
   .on('show',_=>{if(x){const q=w.getPosition();dx=q[0]-x;dy=q[1]-y}}).show()
  if(D.win){const fix=_=>{setTimeout(_=>{
              if(w.isMaximized()){w.unmaximize();w.maximize()}
              else{const a=w.getSize();w.setSize(a[0],a[1]-1);w.setSize(a[0],a[1])}
            },100)}
            w.on('page-title-updated',fix).on('blur',fix)}
  db.devTools&&w.webContents.openDevTools()
})
el.app.on('window-all-closed',_=>el.app.quit())

global.ev=x=>eval(x)
global.js=(i,x)=>el.BrowserWindow.fromId(i).webContents.executeJavaScript(x)
const inc=x=>x+1
<|endoftext|>


<commit_before>game.PlayerEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "player",
                width: 64,
                height: 64,
                spritewidth: "64",
                spriteheight: "64",
                getShape: function() {
                    return(new me.Rect(0, 0, 64, 64)).toPolygon();
                }
        }]);

        this.body.setVelocity(5, 20);
        me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

        this.renderable.addAnimation("idle", [78]);
        this.renderable.addAnimation("walk", [117, 118, 119,120, 121, 122, 123, 124, 125], 80);
        this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72], 80);

        this.renderable.setCurrentAnimation("idle");

    },

    update: function(delta) {
        if(me.input.isKeyPressed("right")){

            this.body.vel.x += this.body.accel.x * me.timer.tick;

            this.flipX(true);
        }
        else if(me.input.isKeyPressed("left")){
            this.body.vel.x -= this.body.accel.x * me.timer.tick;
            this.flipX(false);
        }
        else{
            this.body.vel.x = 0;
        }
        if(me.input.isKeyPressed("up") && !this.jumping && !this.falling){
            this.jumping = true;
            this.body.vel.y -= this.body.accel.y * me.timer.tick;
            this.jumping = false;
        }

                if(me.input.isKeyPressed("attack")){
            if(!this.renderable.isCurrentAnimation("attack")){
                this.renderable.setCurrentAnimation("attack", "idle");
                this.renderable.setAnimationFrame();
            }
        }
        else if(this.body.vel.x !== 0){
        if(!this.renderable.isCurrentAnimation("walk")){
            this.renderable.setCurrentAnimation("walk");

          }
        }else if(!this.renderable.isCurrentAnimation("attack")){
            this.renderable.setCurrentAnimation("idle");
        }

        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    }
});

game.PlayerBaseEntity = me.Entity.extend({
    init : function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function(){
                    return (new me.Rect(0, 0, 100, 70)).toPolygon();
                }
        }]);
    this.broken = false;
    this.health = 10;
    this.alwaysUpdate = true;
    this.body.onCollision = this.onCollision.bind(this);

    this.type = "PlayerBaseEntity";

    this.renderable.addAnimation("idle", [0]);
    this.renderable.addAnimation("broken", [1]);
    this.renderable.setCurrentAnimation("idle");

    },

    update:function(delta){
        if(this.health<=0){
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    onCollision: function() {

    }

});
game.EnemyBaseEntity = me.Entity.extend({
    init : function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function(){
                    return (new me.Rect(0, 0, 100, 70)).toPolygon();
                }
        }]);
    this.broken = false;
    this.health = 10;
    this.alwaysUpdate = true;
    this.body.onCollision = this.onCollision.bind(this);

    this.type = "PlayerBaseEntity";

    this.renderable.addAnimation("idle", [0]);
    this.renderable.addAnimation("broken", [1]);
    this.renderable.setCurrentAnimation("idle");

    },

    update:function(delta){
        if(this.health<=0){
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    onCollision: function() {

    }

});<commit_msg>14-17 without comments<commit_after>game.PlayerEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "player",
                width: 64,
                height: 64,
                spritewidth: "64",
                spriteheight: "64",
                getShape: function() {
                    return(new me.Rect(0, 0, 64, 64)).toPolygon();
                }
        }]);

        this.body.setVelocity(5, 20);
        this.facing = "right";
        this.now = new Date().getTime();
        this.lastHit = this.now  ;
        this.lastAttack = new Date().getTime();
        me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

        this.renderable.addAnimation("idle", [78]);
        this.renderable.addAnimation("walk", [117, 118, 119,120, 121, 122, 123, 124, 125], 80);
        this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72], 80);

        this.renderable.setCurrentAnimation("idle");

    },

    update: function(delta) {
        this.now = new Date().getTime();
        if(me.input.isKeyPressed("right")){
            this.body.vel.x += this.body.accel.x * me.timer.tick;
            this.facing = "right";
            this.flipX(true);
        }
        else if(me.input.isKeyPressed("left")){
            this.body.vel.x -= this.body.accel.x * me.timer.tick;
            this.facing = "left";
            this.flipX(false);
        }
        else{
            this.body.vel.x = 0;
        }
        if(me.input.isKeyPressed("up") && !this.jumping && !this.falling){
            this.jumping = true;
            this.body.vel.y -= this.body.accel.y * me.timer.tick;
            this.jumping = false;
        }

        if(me.input.isKeyPressed("attack")){
            if(!this.renderable.isCurrentAnimation("attack")){
                this.renderable.setCurrentAnimation("attack", "idle");
                this.renderable.setAnimationFrame();
            }
        }
        else if(this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")){
        if(!this.renderable.isCurrentAnimation("walk")){
            this.renderable.setCurrentAnimation("walk");

          }
        }else if(!this.renderable.isCurrentAnimation("attack")){
            this.renderable.setCurrentAnimation("idle");
        }

        me.collision.check(this, true, this.collideHandler.bind(this), true);
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    collideHandler: function(response) {
        if(response.b.type==='EnemyBaseEntity'){
            var ydif = this.pos.y - response.b.pos.y;
            var xdif = this.pos.x -response.b.pos.x;

            if(ydif<-40 && xdif< 70 && xdif>-35){
                this.body.falling = false;
                this.body.vel.y = -1;
            }
            else if(xdif>-35 && this.facing==='right' && (xdif<0) && ydif>-50) {
                this.body.vel.x = 0;
                this.pos.x = this.pos.x -1;
            }
            else if(xdif<70 && this.facing==='left' && (xdif>0)) {
                this.body.vel.x = 0;
                this.pos.x = this.pos.x +1;
            }

            if(this.rederable.isCurrentAnimation("attack") && this.now-this.lastHit >= 800){
                this.lastHit = this.now;
                response.b.loseHealth();
            }
        }
    }
});

game.PlayerBaseEntity = me.Entity.extend({
    init : function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function(){
                    return (new me.Rect(0, 0, 100, 70)).toPolygon();
                }
        }]);
    this.broken = false;
    this.health = 10;
    this.alwaysUpdate = true;
    this.body.onCollision = this.onCollision.bind(this);

    this.type = "PlayerBaseEntity";

    this.renderable.addAnimation("idle", [0]);
    this.renderable.addAnimation("broken", [1]);
    this.renderable.setCurrentAnimation("idle");

    },

    update:function(delta){
        if(this.health<=0){
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    onCollision: function() {

    }

});
game.EnemyBaseEntity = me.Entity.extend({
    init : function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function(){
                    return (new me.Rect(0, 0, 100, 70)).toPolygon();
                }
        }]);
    this.broken = false;
    this.health = 10;
    this.alwaysUpdate = true;
    this.body.onCollision = this.onCollision.bind(this);

    this.type = "EnemyBaseEntity";

    this.renderable.addAnimation("idle", [0]);
    this.renderable.addAnimation("broken", [1]);
    this.renderable.setCurrentAnimation("idle");

    },

    update:function(delta){
        if(this.health<=0){
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

        this._super(me.Entity, "update", [delta]);
        return true;
    },

    onCollision: function() {

    },

    loseHealth: function() {
        this.health--;
    }

});<|endoftext|>


<commit_before>/*
  Setup user details for exception handling
 */

App.then(function(app) {
    App.CurrentUser.find('current').then(function(user) {
        if (typeof Raven == 'object') {
            Raven.setUser({
                id: user.get('id_for_ember'),
                name: user.get('full_name'),
                email: user.get('email'),
            });
        }
    });

    // Override the BB project / status search list
    // TODO: we should just define the 'list' when initializing
    //       and then BB should use it when setting up the list
    App.ProjectPhase.find().then(function(data){
        var list = [
            {id: 5, name: gettext("Running campaigns")},
            {id: [7,8], name: gettext("Finished campaigns")}
        ];
        App.ProjectPhaseSelectView.reopen({
            content: list
        });
    });

    // Facebook API ID
    if (FACEBOOK_AUTH_ID)
        App.set('appId', FACEBOOK_AUTH_ID);

    app.appLogin = function (fbResponse) {
        console.log("app login");

        var _this = this,
            currentUsercontroller = App.__container__.lookup('controller:currentUser');

        return Ember.RSVP.Promise(function (resolve, reject) {
            var hash = {
              url: "/api/social-login/facebook/",
              dataType: "json",
              type: 'post',
              data: fbResponse
            };

            hash.success = function (response) {
                App.AuthJwt.processSuccessResponse(response).then(function (user) {
                    // If success
                    $('.modal-fullscreen-close').click();
                    currentUsercontroller.send('setFlash', gettext('Welcome to the 1%Club'));
                    currentUsercontroller.set('model', user);
                    Ember.run(null, resolve, user);
                 }, function (error) {
                    // If failed
                    Ember.run(null, reject, error);
                });
            };

            hash.error = function (response) {
                currentUsercontroller.send('setFlash', gettext('Something went wrong :-('), 'error');
                var error = JSON.parse(response.responseText);
                Ember.run(null, reject, error);
            };

            Ember.$.ajax(hash);
        });
    };
});

/*
  Bluebottle Route Overrides
 */

App.ApplicationRoute.reopen(App.LogoutJwtMixin, Ember.FacebookMixin, {
    init: function () {
        this._super();

        // Set the facebook appId
        // TODO: move this to the server side settings
        this.set('appId', '1438115069790112');
    },

    actions: {
        addDonation: function (project, fundraiser) {
            var route = this;
            App.CurrentOrder.find('current').then(function(order) {
                var store = route.get('store');

                var projectHasDonation = order.get('donations').anyBy('project', project);
                var fundraiserHasDonation = false;
                if(fundraiser !== undefined){
                    fundraiserHasDonation = order.get('donations').anyBy('fundraiser', fundraiser);
                }

                // TODO: functional test this.
                // *  Donate directly to project: check if no direct donations exist
                // *  Donate through fundraiser: check if donation for that fundraiser exists
                // *  We can have the same project multiple times, but all different fundraisers

                if (fundraiserHasDonation ||
                    (projectHasDonation && !fundraiserHasDonation && fundraiser === undefined)) {
                    // Donation for this already exists in this order.
                } else {
                    var donation = store.createRecord(App.CurrentOrderDonation);
                    donation.set('project', project);
                    if(fundraiser !== undefined){
                        donation.set('fundraiser', fundraiser);
                    }
                    donation.set('order', order);
                    donation.save();
                }
                route.transitionTo('currentOrder.donationList');
            });
        }
    }
});

/*
  Bluebottle Controller Overrides
 */
App.ApplicationController.reopen({
    needs: ['currentOrder', 'myProjectList'],

    missingCurrentUser: function () {
        // FIXME: should call the clearJwtToken action here but it isn't being called.
        delete localStorage['jwtToken'];
        App.set('jwtToken', null);
    },
});

App.EventMixin = Em.Mixin.create({

  bindScrolling: function(opts) {
    var onScroll, self = this;

    onScroll = function() {
      var scrollTop = $(this).scrollTop();
      return self.scrolled(scrollTop);
    };

    $(window).bind('scroll', onScroll);
    $(document).bind('touchmove', onScroll);
  },

  unbindScrolling: function () {
    $(window).unbind('scroll');
    $(document).unbind('touchmove');
  },

  bindMobileClick: function() {
    toggleMenu = function() {
      $('.mobile-nav-holder').toggleClass('is-active');
    };

    closeMenu = function(event) {
      $('.mobile-nav-holder').removeClass('is-active');
    };

    $('.mobile-nav-btn').bind('click', toggleMenu);
    $('#content').bind('hover', closeMenu);
  }
});

/*
  Bluebottle View Overrides
*/

App.ApplicationView.reopen(App.EventMixin, {
    setBindScrolling: function() {
        this.bindScrolling();
    }.on('didInsertElement'),

    setUnbindScrolling: function() {
        this.unbindScrolling();
    }.on('didInsertElement'),

    setBindClick: function() {
        this.bindMobileClick();
    }.on('didInsertElement'),

    scrolled: function(dist) {
        top = $('#content').offset();
        elm = top.screen.availTop;

        if (dist <= 53) {
            $('#header').removeClass('is-scrolled');
            $('.nav-member-dropdown').removeClass('is-scrolled');
            $('.mobile-nav-holder').removeClass('is-scrolled');
            $('#content').append('

');
        } else {
            $('#header').addClass('is-scrolled');
            $('.nav-member-dropdown').addClass('is-scrolled');
            $('.mobile-nav-holder').addClass('is-scrolled');
        }
    }
});
<commit_msg>removed console log statement<commit_after>/*
  Setup user details for exception handling
 */

App.then(function(app) {
    App.CurrentUser.find('current').then(function(user) {
        if (typeof Raven == 'object') {
            Raven.setUser({
                id: user.get('id_for_ember'),
                name: user.get('full_name'),
                email: user.get('email'),
            });
        }
    });

    // Override the BB project / status search list
    // TODO: we should just define the 'list' when initializing
    //       and then BB should use it when setting up the list
    App.ProjectPhase.find().then(function(data){
        var list = [
            {id: 5, name: gettext("Running campaigns")},
            {id: [7,8], name: gettext("Finished campaigns")}
        ];
        App.ProjectPhaseSelectView.reopen({
            content: list
        });
    });

    // Facebook API ID
    if (FACEBOOK_AUTH_ID)
        App.set('appId', FACEBOOK_AUTH_ID);

    app.appLogin = function (fbResponse) {
        var _this = this,
            currentUsercontroller = App.__container__.lookup('controller:currentUser');

        return Ember.RSVP.Promise(function (resolve, reject) {
            var hash = {
              url: "/api/social-login/facebook/",
              dataType: "json",
              type: 'post',
              data: fbResponse
            };

            hash.success = function (response) {
                App.AuthJwt.processSuccessResponse(response).then(function (user) {
                    // If success
                    $('.modal-fullscreen-close').click();
                    currentUsercontroller.send('setFlash', gettext('Welcome to the 1%Club'));
                    currentUsercontroller.set('model', user);
                    Ember.run(null, resolve, user);
                 }, function (error) {
                    // If failed
                    Ember.run(null, reject, error);
                });
            };

            hash.error = function (response) {
                currentUsercontroller.send('setFlash', gettext('Something went wrong :-('), 'error');
                var error = JSON.parse(response.responseText);
                Ember.run(null, reject, error);
            };

            Ember.$.ajax(hash);
        });
    };
});

/*
  Bluebottle Route Overrides
 */

App.ApplicationRoute.reopen(App.LogoutJwtMixin, Ember.FacebookMixin, {
    init: function () {
        this._super();

        // Set the facebook appId
        // TODO: move this to the server side settings
        this.set('appId', '1438115069790112');
    },

    actions: {
        addDonation: function (project, fundraiser) {
            var route = this;
            App.CurrentOrder.find('current').then(function(order) {
                var store = route.get('store');

                var projectHasDonation = order.get('donations').anyBy('project', project);
                var fundraiserHasDonation = false;
                if(fundraiser !== undefined){
                    fundraiserHasDonation = order.get('donations').anyBy('fundraiser', fundraiser);
                }

                // TODO: functional test this.
                // *  Donate directly to project: check if no direct donations exist
                // *  Donate through fundraiser: check if donation for that fundraiser exists
                // *  We can have the same project multiple times, but all different fundraisers

                if (fundraiserHasDonation ||
                    (projectHasDonation && !fundraiserHasDonation && fundraiser === undefined)) {
                    // Donation for this already exists in this order.
                } else {
                    var donation = store.createRecord(App.CurrentOrderDonation);
                    donation.set('project', project);
                    if(fundraiser !== undefined){
                        donation.set('fundraiser', fundraiser);
                    }
                    donation.set('order', order);
                    donation.save();
                }
                route.transitionTo('currentOrder.donationList');
            });
        }
    }
});

/*
  Bluebottle Controller Overrides
 */
App.ApplicationController.reopen({
    needs: ['currentOrder', 'myProjectList'],

    missingCurrentUser: function () {
        // FIXME: should call the clearJwtToken action here but it isn't being called.
        delete localStorage['jwtToken'];
        App.set('jwtToken', null);
    },
});

App.EventMixin = Em.Mixin.create({

  bindScrolling: function(opts) {
    var onScroll, self = this;

    onScroll = function() {
      var scrollTop = $(this).scrollTop();
      return self.scrolled(scrollTop);
    };

    $(window).bind('scroll', onScroll);
    $(document).bind('touchmove', onScroll);
  },

  unbindScrolling: function () {
    $(window).unbind('scroll');
    $(document).unbind('touchmove');
  },

  bindMobileClick: function() {
    toggleMenu = function() {
      $('.mobile-nav-holder').toggleClass('is-active');
    };

    closeMenu = function(event) {
      $('.mobile-nav-holder').removeClass('is-active');
    };

    $('.mobile-nav-btn').bind('click', toggleMenu);
    $('#content').bind('hover', closeMenu);
  }
});

/*
  Bluebottle View Overrides
*/

App.ApplicationView.reopen(App.EventMixin, {
    setBindScrolling: function() {
        this.bindScrolling();
    }.on('didInsertElement'),

    setUnbindScrolling: function() {
        this.unbindScrolling();
    }.on('didInsertElement'),

    setBindClick: function() {
        this.bindMobileClick();
    }.on('didInsertElement'),

    scrolled: function(dist) {
        top = $('#content').offset();
        elm = top.screen.availTop;

        if (dist <= 53) {
            $('#header').removeClass('is-scrolled');
            $('.nav-member-dropdown').removeClass('is-scrolled');
            $('.mobile-nav-holder').removeClass('is-scrolled');
            $('#content').append('

');
        } else {
            $('#header').addClass('is-scrolled');
            $('.nav-member-dropdown').addClass('is-scrolled');
            $('.mobile-nav-holder').addClass('is-scrolled');
        }
    }
});
<|endoftext|>


<commit_before>'use strict'
const {app, BrowserWindow, ipcMain} = require('electron')
const {Game} = require('./main/game')
const {Player} = require('./main/player')
const {WindowGraph} = require('./main/windows')
const socket = require('socket.io-client')('https://haunted-server.herokuapp.com')
// const socket = require('socket.io-client')('http://localhost:5000')

let debug = true
let game = new Game()
let windowGraph = new WindowGraph(BrowserWindow, debug, __dirname)
let queueWindow

/**
 * Function that opens the main menu window
 */
function createWindow () {
  windowGraph.startWindow()
}

/**
 * Loads the game queue window after emiting and getting
 * a callback of the avaiable players.
 * @param {integer} id The id of the current window
 */
function loadGameQueueWindow (id) {
  socket.emit('get-characters', (characters) => {
    // game.availableCharacters = characters
    let mainWin = windowGraph.windows[0]
    queueWindow = windowGraph.gameQueueWindow(mainWin, {
      parentWinId: mainWin.id,
      characters: characters
    })
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    socket.emit('leave-game', game.player.id)
    app.quit()
  }
})

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  createWindow()
})

/**
 * Sets Electron's default menu to null
 */
app.on('browser-window-created', (event, window) => {
  window.setMenu(null)
})

/**
 * Begining of Socket Events
 * Events should be listed in alphabetical order
 */

/**
 * Socket event to handle incoming message to get the available
 * characters for the selected game instance.
 * @param {array} characters Array of characters that are available to use.
 */
socket.on('available-characters', (characters) => {
  game.availableCharacters = characters
  // loadGameQueueWindow()
})

/**
 * Socket event to handle incoming message to get the available
 * games from the server and display them in a new window
 */
socket.on('get-games', (games) => {
  // let win = windowGraph.windows.find((element) => {
  //   return element.id === 0
  // })
  let win = windowGraph.windows[0]
  windowGraph.joinGameWindow(win, {parentWinId: win.id, games: games})
})

socket.on('selected-characters', (characters) => {
  if (queueWindow) {
    queueWindow.window.webContents.send('selected-characters', {characters: characters})
  }
})

/**
 * Socket event to handle incoming message from the server
 * to start the game one all players have filled up the game queue
 */
socket.on('start-game', (start) => {
  windowGraph.gameWindow()
  for (let i = 0; i < windowGraph.windows.length - 1; i++) {
    windowGraph.windows[i].window.close()
  }
})

/**
 * Socket event to handle incoming message from the server
 * to update the chat log
 */
socket.on('updateChatLog', (msg) => {
  game.chatLog = msg
})

/**
 * End of Socket Events and Begining of Main Events
 * Main Events should be listed in alphabetical order
 */

/**
 * Event that creates a window displaying a message
 * telling the player to wait for another player to join
 * the game. Also closes previous modal window
 */
ipcMain.on('host', (event, msg) => {
  socket.emit('host-game', msg.name, (error, playerID) => {
    if (error) {
      event.sender.send('error', error)
    } else {
      // let mainWin = windowGraph.windows.find((element) => {
      //   return element.id === 0
      // })
      game.addPlayer(new Player(playerID))
      let hostWin = windowGraph.windows.find((element) => {
        return element.id === msg.id
      })
      hostWin.window.close()
      loadGameQueueWindow()
    }
  })
})

/**
 * Event to create a window that allows the player to
 * create a new game
 */
ipcMain.on('host-game', (event, id) => {
  let win = windowGraph.windows.find((element) => {
    return element.id === id
  })
  windowGraph.hostGameWindow(win, {parentWinId: win})
})

/**
 * Event that emits a Socket message telling the server
 * which game instance you want to join
 */
ipcMain.on('join', (event, data) => {
  socket.emit('join', data.game.id, (playerID) => {
    game.gameId = data.game.id
    game.addPlayer(new Player(playerID))
    let joinWin = windowGraph.windows.find((element) => {
      return element.id === data.id
    })
    joinWin.window.close()
    loadGameQueueWindow()
  })
})

/**
 * Event that emits a Socket message to the server to get
 * the available games to join
 */
ipcMain.on('join-game', (event, index) => {
  socket.emit('get', 'get the game')
})

/**
 * Event that emits a Socket message informing the server of a player
 * collision with a door.
 */
ipcMain.on('door-collision', (event, direction) => {
  console.log('before socket emit')
  socket.emit('room-request', direction, (room) => {
    console.log('before event sender')
    event.sender.send('the-room', room)
  })
})

/**
 * Event to create the options menu
 */
ipcMain.on('options', (event, index) => {
  // let win = windowGraph.windows.find((element) => {
  //   return element.id === 0
  // })
  let win = windowGraph.windows[0]
  windowGraph.optionsWindow(win, {parentWinId: win.id})
})

/**
 * Event that opens up a modal menu window.
 * Called from the index/game window.
 * Activated when player pauses the game
 * Send message back telling game window to unpause
 * the game when paused variable is set to false
 * from resume-game Event.
 */
ipcMain.on('pause-game', (event, id) => {
  game.paused = true
  let win = windowGraph.windows.find((element) => {
    return element.id === id
  })
  windowGraph.ingameWindow(win, {parentWinId: id})
  if (!game.paused) {
    event.sender.send('un-pause', game.paused)
  }
})

/**
 * Event that closes all windows in the windows array in the WindowGraph
 * class.
 */
ipcMain.on('quit-game', (event) => {
  for (let win of windowGraph.windows) {
    win.window.close()
  }
})

/**
 * Event that closes all windows and reopens the main menu
 * window.
 */
ipcMain.on('quit-to-main-window', (event, data) => {
  socket.emit('leave-game', game.player.id)
  windowGraph.startWindow()
  for (let i = 0; i < windowGraph.windows.length - 1; i++) {
    windowGraph.windows[i].window.close()
  }
})

/**
 * Event that closes modal menu window and resumes the
 * game
 */
ipcMain.on('resume-game', (event, id) => {
  game.paused = false
  windowGraph.windows.find((element) => {
    return element.id === id
  }).window.close()
})

ipcMain.on('select-character', (event, charID) => {
  // socket.emit('select-character', charID)
  socket.emit('select-character', charID, (characters, selectedCharacter) => {
    event.sender.send('selected-characters', {
      characters: characters,
      selectedCharacter: selectedCharacter
    })
  })
})

ipcMain.on('start', (event) => {
  socket.emit('start', game.gameId)
})

/**
 * Event to send the updated chat log from the server
 * to the Renderer at index.
 */
ipcMain.on('update-chat-log', (event) => {
  event.returnValue = game.chatLog
  // event.sender.send('updated-chat-log', chatLog)
})
<commit_msg>refactor<commit_after>'use strict'
const {app, BrowserWindow, ipcMain} = require('electron')
const {Game} = require('./main/game')
const {Player} = require('./main/player')
const {WindowGraph} = require('./main/windows')
const socket = require('socket.io-client')('https://haunted-server.herokuapp.com')
// const socket = require('socket.io-client')('http://localhost:5000')

let debug = true
let game = new Game()
let windowGraph = new WindowGraph(BrowserWindow, debug, __dirname)
let queueWindow

/**
 * Function that opens the main menu window
 */
function createWindow () {
  windowGraph.startWindow()
}

/**
 * Loads the game queue window after emiting and getting
 * a callback of the avaiable players.
 * @param {integer} id The id of the current window
 */
function loadGameQueueWindow (id) {
  socket.emit('get-characters', (characters) => {
    // game.availableCharacters = characters
    let mainWin = windowGraph.windows[0]
    queueWindow = windowGraph.gameQueueWindow(mainWin, {
      parentWinId: mainWin.id,
      characters: characters
    })
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    if (game.gameId) {
      socket.emit('leave-game', (game.gameId, game.player.id))
    }
    app.quit()
  }
})

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  createWindow()
})

/**
 * Sets Electron's default menu to null
 */
app.on('browser-window-created', (event, window) => {
  window.setMenu(null)
})

/**
 * Begining of Socket Events
 * Events should be listed in alphabetical order
 */

/**
 * Socket event to handle incoming message to get the available
 * characters for the selected game instance.
 * @param {array} characters Array of characters that are available to use.
 */
socket.on('available-characters', (characters) => {
  game.availableCharacters = characters
  // loadGameQueueWindow()
})

/**
 * Socket event to handle incoming message to get the available
 * games from the server and display them in a new window
 */
socket.on('get-games', (games) => {
  // let win = windowGraph.windows.find((element) => {
  //   return element.id === 0
  // })
  let win = windowGraph.windows[0]
  windowGraph.joinGameWindow(win, {parentWinId: win.id, games: games})
})

socket.on('selected-characters', (characters) => {
  if (queueWindow) {
    queueWindow.window.webContents.send('selected-characters', {characters: characters})
  }
})

/**
 * Socket event to handle incoming message from the server
 * to start the game one all players have filled up the game queue
 */
socket.on('start-game', (start) => {
  windowGraph.gameWindow()
  for (let i = 0; i < windowGraph.windows.length - 1; i++) {
    windowGraph.windows[i].window.close()
  }
})

/**
 * Socket event to handle incoming message from the server
 * to update the chat log
 */
socket.on('updateChatLog', (msg) => {
  game.chatLog = msg
})

/**
 * End of Socket Events and Begining of Main Events
 * Main Events should be listed in alphabetical order
 */

/**
 * Event that creates a window displaying a message
 * telling the player to wait for another player to join
 * the game. Also closes previous modal window
 */
ipcMain.on('host', (event, msg) => {
  socket.emit('host-game', msg.name, (error, playerID) => {
    if (error) {
      event.sender.send('error', error)
    } else {
      // let mainWin = windowGraph.windows.find((element) => {
      //   return element.id === 0
      // })
      game.addPlayer(new Player(playerID))
      let hostWin = windowGraph.windows.find((element) => {
        return element.id === msg.id
      })
      hostWin.window.close()
      loadGameQueueWindow()
    }
  })
})

/**
 * Event to create a window that allows the player to
 * create a new game
 */
ipcMain.on('host-game', (event, id) => {
  let win = windowGraph.windows.find((element) => {
    return element.id === id
  })
  windowGraph.hostGameWindow(win, {parentWinId: win})
})

/**
 * Event that emits a Socket message telling the server
 * which game instance you want to join
 */
ipcMain.on('join', (event, data) => {
  socket.emit('join', data.game.id, (playerID) => {
    game.gameId = data.game.id
    game.addPlayer(new Player(playerID))
    let joinWin = windowGraph.windows.find((element) => {
      return element.id === data.id
    })
    joinWin.window.close()
    loadGameQueueWindow()
  })
})

/**
 * Event that emits a Socket message to the server to get
 * the available games to join
 */
ipcMain.on('join-game', (event, index) => {
  socket.emit('get', 'get the game')
})

/**
 * Event that emits a Socket message informing the server of a player
 * collision with a door.
 */
ipcMain.on('door-collision', (event, direction) => {
  console.log('before socket emit')
  socket.emit('room-request', direction, (room) => {
    console.log('before event sender')
    event.sender.send('the-room', room)
  })
})

/**
 * Event to create the options menu
 */
ipcMain.on('options', (event, index) => {
  // let win = windowGraph.windows.find((element) => {
  //   return element.id === 0
  // })
  let win = windowGraph.windows[0]
  windowGraph.optionsWindow(win, {parentWinId: win.id})
})

/**
 * Event that opens up a modal menu window.
 * Called from the index/game window.
 * Activated when player pauses the game
 * Send message back telling game window to unpause
 * the game when paused variable is set to false
 * from resume-game Event.
 */
ipcMain.on('pause-game', (event, id) => {
  game.paused = true
  let win = windowGraph.windows.find((element) => {
    return element.id === id
  })
  windowGraph.ingameWindow(win, {parentWinId: id})
  if (!game.paused) {
    event.sender.send('un-pause', game.paused)
  }
})

/**
 * Event that closes all windows in the windows array in the WindowGraph
 * class.
 */
ipcMain.on('quit-game', (event) => {
  for (let win of windowGraph.windows) {
    win.window.close()
  }
})

/**
 * Event that closes all windows and reopens the main menu
 * window.
 */
ipcMain.on('quit-to-main-window', (event, data) => {
  socket.emit('leave-game', (game.gameId, game.player.id))
  windowGraph.startWindow()
  for (let i = 0; i < windowGraph.windows.length - 1; i++) {
    windowGraph.windows[i].window.close()
  }
})

/**
 * Event that closes modal menu window and resumes the
 * game
 */
ipcMain.on('resume-game', (event, id) => {
  game.paused = false
  windowGraph.windows.find((element) => {
    return element.id === id
  }).window.close()
})

ipcMain.on('select-character', (event, charID) => {
  // socket.emit('select-character', charID)
  socket.emit('select-character', charID, (characters, selectedCharacter) => {
    event.sender.send('selected-characters', {
      characters: characters,
      selectedCharacter: selectedCharacter
    })
  })
})

ipcMain.on('start', (event) => {
  socket.emit('start', game.gameId)
})

/**
 * Event to send the updated chat log from the server
 * to the Renderer at index.
 */
ipcMain.on('update-chat-log', (event) => {
  event.returnValue = game.chatLog
  // event.sender.send('updated-chat-log', chatLog)
})
<|endoftext|>


<commit_before>// player's class
game.PlayerEntity = me.Entity.extend ({
	//constructor function
	init: function(x, y, settings){
		//reachers the constructor function for enitity
		this._super(me.Entity, 'init', [x, y, {
			//settings. shows the player
			image: "player",
			//sets aside a width of 64 pixels for the sprite
			width: 64,
			//sets aside a height of 64 pixels for the sprite
			height: 64,
			//gives the sprite a width of 64.
			spritewidth : "64",
			//gives the sprite a width of 64
			spriteheight: "64",
			getShape: function(){
				//returns a rectangle of what the player walks into
				return(new me.Rect(0, 0, 64, 64)).toPolygon();
			}
		}]);
		//sets movemet speed. allows player to move horizantally and vertically
		this.body.setVelocity(5, 20);
		//keeps track of what direction the character is facing
		this.facing = "right";
		//checks what time it is in the game
		this.now = new Date().getTime();
		this.lastHit = this.now;
		//sets delay on when the player can hit
		this.lastAttack = new Date().getTime();
		//makesit so the player is always on the screen
		me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);
		//gives player animation while standing
		this.renderable.addAnimation("idle", [78]);
		//gives player animation while walking
		this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80);
		//gives player animation while attacking
		this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72], 80);
		//the player's start animation
		this.renderable.setCurrentAnimation("idle");
	},

	//delata is the change in time that's happening
	update: function(delta){
		this.now = new Date().getTime();
		if(me.input.isKeyPressed("right")){
			//when right key is pressed, adds to the position of my x by the velocity defined above in setVelocity and multiplying it by me.timer.tick
			//me.timer.tick makes the movement look smooth
			this.body.vel.x += this.body.accel.x * me.timer.tick;
			this.facing = "right";
			this.flipX(true);
		}

		else if(me.input.isKeyPressed("left")){
			//when left key is pressed, adds to the position of my x by the velocity defined above in setVelocity and multiplying it by me.timer.tick
			//me.timer.tick makes the movement look smooth
			this.facing = "left";
			this.body.vel.x -= this.body.accel.x * me.timer.tick;
			this.flipX(false);
		}

		//if the right key isn't being pressed, the player doesn't move
		else{
			this.body.vel.x = 0;
		}

		//when up key is pressed, player jumps
		if(me.input.isKeyPressed("jump")){
			if(!this.body.jumping && !this.body.falling){
				this.body.jumping = true;
				this.body.vel.y -= this.body.accel.y * me.timer.tick;
			}
		}
		//runs if the attack key is pressed
		if(me.input.isKeyPressed("attack")){
			if(!this.renderable.isCurrentAnimation("attack")){
				//sets current animation to attack. goes back to idle oncethe attack is over it goes back to idle
				this.renderable.setCurrentAnimation("attack", "idle")
				//makes it so that next time the button is pressed the player starts from the first animation, not where it left off
				this.renderable.setAnimationFrame();
			}
		}
		//runs if the player is moving horizantally
		else if(this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")){
			//runs if the player isn't already running the walk animation
			if(!this.renderable.isCurrentAnimation("walk")){
				//gives the player the walking animation
				this.renderable.setCurrentAnimation("walk");
			}
		}
		//runs if player is standing still
		else if(!this.renderable.isCurrentAnimation("attack")){
			//gives the player the idle animation
			this.renderable.setCurrentAnimation("idle");
		}

		me.collision.check(this, true, this.collideHandler.bind(this), true);
		//tells above code to work
		this.body.update(delta);

		this._super(me.Entity, "update", [delta]);
		return true
	},

	collideHandler: function(response){
		if(response.b.type==='EnemyBaseEntity'){
			var ydif = this.pos.y - response.b.pos.y;
			var xdif = this.pos.x - response.b.pos.x;
		}
		//player will collide witht the top of the base
		if(ydif<-40 && xdif< 70 && xdif>-35){
			this.body.falling = false;
			this.body.vel.y = -1;
		}
		//player will colide with the base while facing to the right
		else if(xdif>-35 && this.facing==='right' && (xdif<0)){
			this.body.vel.x = 0;
			this.pos.x = this.pos.x -1;
		}
		//player will colide with the base while facing to the left
		else if(xdif<70 && this.facing==='left' && (ydif>0)){
			this.body.vel.x = 0;
			this.pos.x = this.pos.x +1;
		}

		//sets how long the base has to be hit before it will break
		if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= 1000){
			this.lastHit = this.now;
			response.b.loseHealth();
		}
	}

});

//tower class
game.PlayerBaseEntity = me.Entity.extend({
	init: function(x, y, settings){
		//reachers the constructor function for tower
		this._super(me.Entity, 'init', [x, y, {
			//settings. shoes the tower
			image: "tower",
			//sets aside a width of 100 pixels for the tower
			width: 100,
			//sets aside a height of 100 pixels for the tower
			height: 100,
			//gives the tower a width of 100.
			spritewidth : "100",
			//gives the tower a width of 100
			spriteheight: "100",
			getShape: function(){
				//returns a rectangle of what the tower walks into
				return(new me.Rect(0, 0, 100, 200)).toPolygon();
			}
		}]);
		//says that tower hasn't been destroyed
		this.broken = false;
		//gives tower a "health" of ten
		this.health = 10;
		//makes sure the tower's status is always updating, eben when it isn't on the map
		this.alwaysUpdate = true;
		//makes teh tower collidable
		this.body.onCollision = this.onCollision.bind(this);
		//checks what player is running into
		this.type = "PlayerBaseEntity";
		//adds the defualt animatin for the game
		this.renderable.addAnimation("idle", [0]);
		//adds the animation for when the tower is broken
		this.renderable.addAnimation("broken", [1]);
		//sets the desfault animation
		this.renderable.setCurrentAnimation("idle");

	},

	update:function(delta){
		//runs if health is less than or equal to 0
		if(this.health<=0){
			//makes the tower "broken"
			this.broken = true;
			//sets animation for "broken"
			this.renderable.setCurrentAnimation("broken");
		}
		//updates tower status
		this.body.update(delta);

		this._super(me.Entity, "update", [delta]);
		return true;
	},
	//function that runs when base is touched
	onCollision: function(){

	}
});

//tower class
game.EnemyBaseEntity = me.Entity.extend({
	init: function(x, y, settings){
		//reachers the constructor function for tower
		this._super(me.Entity, 'init', [x, y, {
			//settings. shoes the tower
			image: "tower",
			//sets aside a width of 100 pixels for the tower
			width: 100,
			//sets aside a height of 100 pixels for the tower
			height: 100,
			//gives the tower a width of 100.
			spritewidth : "100",
			//gives the tower a width of 100
			spriteheight: "100",
			getShape: function(){
				//returns a rectangle of what the tower walks into
				return(new me.Rect(0, 0, 100, 70)).toPolygon();
			}
		}]);
		//says that tower hasn't been destroyed
		this.broken = false;
		//gives tower a "health" of ten
		this.health = 10;
		//makes sure the tower's status is always updating, eben when it isn't on the map
		this.alwaysUpdate = true;
		//makes teh tower collidable
		this.body.onCollision = this.onCollision.bind(this);
		//checks what player is running into
		this.type = "EnemyBaseEntity";
		//adds the defualt animatin for the game
		this.renderable.addAnimation("idle", [0]);
		//adds the animation for when the tower is broken
		this.renderable.addAnimation("broken", [1]);
		//sets the default animation
		this.renderable.setCurrentAnimation("idle");
	},

	update:function(delta){
		//runs if health is less than or equal to 0
		if(this.health<=0){
			//makes the tower "broken"
			this.broken = true;
			//sets animation for "broken"
			this.renderable.setCurrentAnimation("broken");
		}
		//updates tower status
		this.body.update(delta);

		this._super(me.Entity, "update", [delta]);
		return true;
	},
	//function that runs when base is touched
	onCollision: function(){

	},

	loseHealth: function(){
		this.health--;
	}
});

game.EnemyCreep = me.Entity.extend({
	init: function(x, y, settings){
		this._super(me.Entity, 'init', [x, y, {
			//settings. shoes the player
			image: "player",
			//sets aside a width of 32 pixels for the sprite
			width: 32,
			//sets aside a height of 64 pixels for the sprite
			height: 64,
			//gives the sprite a width of 32
			spritewidth : "32",
			//gives the sprite a width of 64
			spriteheight: "64",
			getShape: function(){
				//returns a rectangle of what the player walks into
				return(new me.Rect(0, 0, 32, 64)).toPolygon();
			}
		}]);
		this.health = 10;
		this.alwaysUpdate = true;

		this.setVelocity(3, 20);

		this.type = "EnemyCreep";

		this.renderable.addAnimation("walk", [3,4,5], 80);
		this.renderable.setCurrentAnimation("walk");
	},

	update: function(){

	}
});<commit_msg>Video 18 comments<commit_after>// player's class
game.PlayerEntity = me.Entity.extend ({
	//constructor function
	init: function(x, y, settings){
		//reachers the constructor function for enitity
		this._super(me.Entity, 'init', [x, y, {
			//settings. shows the player
			image: "player",
			//sets aside a width of 64 pixels for the sprite
			width: 64,
			//sets aside a height of 64 pixels for the sprite
			height: 64,
			//gives the sprite a width of 64.
			spritewidth : "64",
			//gives the sprite a width of 64
			spriteheight: "64",
			getShape: function(){
				//returns a rectangle of what the player walks into
				return(new me.Rect(0, 0, 64, 64)).toPolygon();
			}
		}]);
		//sets movemet speed. allows player to move horizantally and vertically
		this.body.setVelocity(5, 20);
		//keeps track of what direction the character is facing
		this.facing = "right";
		//checks what time it is in the game
		this.now = new Date().getTime();
		this.lastHit = this.now;
		//sets delay on when the player can hit
		this.lastAttack = new Date().getTime();
		//makesit so the player is always on the screen
		me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);
		//gives player animation while standing
		this.renderable.addAnimation("idle", [78]);
		//gives player animation while walking
		this.renderable.addAnimation("walk", [117, 118, 119, 120, 121, 122, 123, 124, 125], 80);
		//gives player animation while attacking
		this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72], 80);
		//the player's start animation
		this.renderable.setCurrentAnimation("idle");
	},

	//delata is the change in time that's happening
	update: function(delta){
		this.now = new Date().getTime();
		if(me.input.isKeyPressed("right")){
			//when right key is pressed, adds to the position of my x by the velocity defined above in setVelocity and multiplying it by me.timer.tick
			//me.timer.tick makes the movement look smooth
			this.body.vel.x += this.body.accel.x * me.timer.tick;
			this.facing = "right";
			this.flipX(true);
		}

		else if(me.input.isKeyPressed("left")){
			//when left key is pressed, adds to the position of my x by the velocity defined above in setVelocity and multiplying it by me.timer.tick
			//me.timer.tick makes the movement look smooth
			this.facing = "left";
			this.body.vel.x -= this.body.accel.x * me.timer.tick;
			this.flipX(false);
		}

		//if the right key isn't being pressed, the player doesn't move
		else{
			this.body.vel.x = 0;
		}

		//when up key is pressed, player jumps
		if(me.input.isKeyPressed("jump")){
			if(!this.body.jumping && !this.body.falling){
				this.body.jumping = true;
				this.body.vel.y -= this.body.accel.y * me.timer.tick;
			}
		}
		//runs if the attack key is pressed
		if(me.input.isKeyPressed("attack")){
			if(!this.renderable.isCurrentAnimation("attack")){
				//sets current animation to attack. goes back to idle oncethe attack is over it goes back to idle
				this.renderable.setCurrentAnimation("attack", "idle")
				//makes it so that next time the button is pressed the player starts from the first animation, not where it left off
				this.renderable.setAnimationFrame();
			}
		}
		//runs if the player is moving horizantally
		else if(this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")){
			//runs if the player isn't already running the walk animation
			if(!this.renderable.isCurrentAnimation("walk")){
				//gives the player the walking animation
				this.renderable.setCurrentAnimation("walk");
			}
		}
		//runs if player is standing still
		else if(!this.renderable.isCurrentAnimation("attack")){
			//gives the player the idle animation
			this.renderable.setCurrentAnimation("idle");
		}

		me.collision.check(this, true, this.collideHandler.bind(this), true);
		//tells above code to work
		this.body.update(delta);

		this._super(me.Entity, "update", [delta]);
		return true
	},

	collideHandler: function(response){
		if(response.b.type==='EnemyBaseEntity'){
			var ydif = this.pos.y - response.b.pos.y;
			var xdif = this.pos.x - response.b.pos.x;
		}
		//player will collide witht the top of the base
		if(ydif<-40 && xdif< 70 && xdif>-35){
			this.body.falling = false;
			this.body.vel.y = -1;
		}
		//player will colide with the base while facing to the right
		else if(xdif>-35 && this.facing==='right' && (xdif<0)){
			this.body.vel.x = 0;
			this.pos.x = this.pos.x -1;
		}
		//player will colide with the base while facing to the left
		else if(xdif<70 && this.facing==='left' && (ydif>0)){
			this.body.vel.x = 0;
			this.pos.x = this.pos.x +1;
		}

		//sets how long the base has to be hit before it will break
		if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= 1000){
			this.lastHit = this.now;
			response.b.loseHealth();
		}
	}

});

//tower class
game.PlayerBaseEntity = me.Entity.extend({
	init: function(x, y, settings){
		//reachers the constructor function for tower
		this._super(me.Entity, 'init', [x, y, {
			//settings. shoes the tower
			image: "tower",
			//sets aside a width of 100 pixels for the tower
			width: 100,
			//sets aside a height of 100 pixels for the tower
			height: 100,
			//gives the tower a width of 100.
			spritewidth : "100",
			//gives the tower a width of 100
			spriteheight: "100",
			getShape: function(){
				//returns a rectangle of what the tower walks into
				return(new me.Rect(0, 0, 100, 200)).toPolygon();
			}
		}]);
		//says that tower hasn't been destroyed
		this.broken = false;
		//gives tower a "health" of ten
		this.health = 10;
		//makes sure the tower's status is always updating, eben when it isn't on the map
		this.alwaysUpdate = true;
		//makes teh tower collidable
		this.body.onCollision = this.onCollision.bind(this);
		//checks what player is running into
		this.type = "PlayerBaseEntity";
		//adds the defualt animatin for the game
		this.renderable.addAnimation("idle", [0]);
		//adds the animation for when the tower is broken
		this.renderable.addAnimation("broken", [1]);
		//sets the desfault animation
		this.renderable.setCurrentAnimation("idle");

	},

	update:function(delta){
		//runs if health is less than or equal to 0
		if(this.health<=0){
			//makes the tower "broken"
			this.broken = true;
			//sets animation for "broken"
			this.renderable.setCurrentAnimation("broken");
		}
		//updates tower status
		this.body.update(delta);

		this._super(me.Entity, "update", [delta]);
		return true;
	},
	//function that runs when base is touched
	onCollision: function(){

	}
});

//tower class
game.EnemyBaseEntity = me.Entity.extend({
	init: function(x, y, settings){
		//reachers the constructor function for tower
		this._super(me.Entity, 'init', [x, y, {
			//settings. shoes the tower
			image: "tower",
			//sets aside a width of 100 pixels for the tower
			width: 100,
			//sets aside a height of 100 pixels for the tower
			height: 100,
			//gives the tower a width of 100.
			spritewidth : "100",
			//gives the tower a width of 100
			spriteheight: "100",
			getShape: function(){
				//returns a rectangle of what the tower walks into
				return(new me.Rect(0, 0, 100, 70)).toPolygon();
			}
		}]);
		//says that tower hasn't been destroyed
		this.broken = false;
		//gives tower a "health" of ten
		this.health = 10;
		//makes sure the tower's status is always updating, eben when it isn't on the map
		this.alwaysUpdate = true;
		//makes teh tower collidable
		this.body.onCollision = this.onCollision.bind(this);
		//checks what player is running into
		this.type = "EnemyBaseEntity";
		//adds the defualt animatin for the game
		this.renderable.addAnimation("idle", [0]);
		//adds the animation for when the tower is broken
		this.renderable.addAnimation("broken", [1]);
		//sets the default animation
		this.renderable.setCurrentAnimation("idle");
	},

	update:function(delta){
		//runs if health is less than or equal to 0
		if(this.health<=0){
			//makes the tower "broken"
			this.broken = true;
			//sets animation for "broken"
			this.renderable.setCurrentAnimation("broken");
		}
		//updates tower status
		this.body.update(delta);

		this._super(me.Entity, "update", [delta]);
		return true;
	},
	//function that runs when base is touched
	onCollision: function(){

	},

	loseHealth: function(){
		this.health--;
	}
});

game.EnemyCreep = me.Entity.extend({
	init: function(x, y, settings){
		this._super(me.Entity, 'init', [x, y, {
			//settings. shoes the player
			image: "player",
			//sets aside a width of 32 pixels for the sprite
			width: 32,
			//sets aside a height of 64 pixels for the sprite
			height: 64,
			//gives the sprite a width of 32
			spritewidth : "32",
			//gives the sprite a width of 64
			spriteheight: "64",
			getShape: function(){
				//returns a rectangle of what the player walks into
				return(new me.Rect(0, 0, 32, 64)).toPolygon();
			}
		}]);
		//sets health for enemy
		this.health = 10;
		this.alwaysUpdate = true;

		//sets speed for enemy
		this.setVelocity(3, 20);

		//sets enemy type
		this.type = "EnemyCreep";

		//creates walking animation for enemy
		this.renderable.addAnimation("walk", [3,4,5], 80);
		this.renderable.setCurrentAnimation("walk");
	},

	update: function(){

	}
});<|endoftext|>