<commit_before>context('Date Control', () => {
	before(() => {
		cy.login();
		cy.visit('/app/doctype');
		return cy.window().its('frappe').then(frappe => {
			return frappe.xcall('frappe.tests.ui_test_helpers.create_doctype', {
				name: 'Test Date Control',
				fields: [
					{
						"label": "Date",
						"fieldname": "date",
						"fieldtype": "Date",
						"in_list_view": 1
					},
				]
			});
		});
	});
	it('Selecting a date from the datepicker', () => {
		cy.new_form('Test Date Control');
		cy.get_field('date', 'Date').click();
		cy.get('.datepicker--nav-title').click();
		cy.get('.datepicker--nav-title').click({force: true});

		//Inputing values in the date field
		cy.get('.datepicker--years > .datepicker--cells > .datepicker--cell[data-year=2020]').click();
		cy.get('.datepicker--months > .datepicker--cells > .datepicker--cell[data-month=0]').click();
		cy.get('.datepicker--days > .datepicker--cells > .datepicker--cell[data-date=15]').click();

		//Verifying if the selected date is displayed in the date field
		cy.get_field('date', 'Date').should('have.value', '01-15-2020');
	});

	it('Checking next and previous button', () => {
		cy.get_field('date', 'Date').click();

		//Clicking on the next button in the datepicker
		cy.get('.datepicker--nav-action[data-action=next]').click();

		//Selecting a date from the datepicker
		cy.get('.datepicker--cell[data-date=15]').click({force: true});

		//Verifying if the selected date has been displayed in the date field
		cy.get_field('date', 'Date').should('have.value', '02-15-2020');
		cy.wait(500);
		cy.get_field('date', 'Date').click();

		//Clicking on the previous button in the datepicker
		cy.get('.datepicker--nav-action[data-action=prev]').click();

		//Selecting a date from the datepicker
		cy.get('.datepicker--cell[data-date=15]').click({force: true});

		//Verifying if the selected date has been displayed in the date field
		cy.get_field('date', 'Date').should('have.value', '01-15-2020');
	});

	it('Clicking on "Today" button gives todays date', () => {
		cy.get_field('date', 'Date').click();

		//Clicking on "Today" button
		cy.get('.datepicker--button').click();

		//Picking up the todays date
		const todaysDate = Cypress.moment().format('MM-DD-YYYY');
		cy.log(todaysDate);

		//Verifying if clicking on "Today" button matches today's date
		cy.get_field('date', 'Date').should('have.value', todaysDate);
	});

	it.only('Configuring first day of the week', () => {
		//Visiting "System Settings" page
		cy.visit('/app/system-settings/System%20Settings');

		//Visiting the "Date and Number Format" section
		cy.contains('Date and Number Format').click();

		//Changing the configuration for "First day of the week" field
		cy.get('select[data-fieldname="first_day_of_the_week"]').select('Tuesday');
		cy.get('.page-head .page-actions').findByRole('button', {name: 'Save'}).click();
		cy.new_form('Test Date Control');
		cy.get_field('date', 'Date').click();

		//Checking if the first day shown in the datepicker is the one which is configured in the System Settings Page
		cy.get('.datepicker--days-names').eq(0).should('contain.text', 'Tu');
		cy.visit('/app/doctype');

		//Adding filter in the doctype list
		cy.add_filter();
		cy.get('.fieldname-select-area').type('Created On{enter}');
		cy.get('.filter-field > .form-group > .input-with-feedback').click();

		//Checking if the first day shown in the datepicker is the one which is configured in the System Settings Page
		cy.get('.datepicker--days-names').eq(0).should('contain.text', 'Tu');

		//Adding event
		cy.visit('/app/event');
		cy.click_listview_primary_button('Add Event');
		cy.get('textarea[data-fieldname=subject]').type('Test');
		cy.fill_field('starts_on', '01-01-2022 00:00:00', 'Datetime');
		cy.click_listview_primary_button('Save');
		cy.visit('/app/event');
		cy.get('.custom-btn-group > .btn').click();

		//Opening Calendar view for the event created
		cy.get('[data-view="Calendar"] > .grey-link').click();

		//Checking if the calendar view has the first day as the configured day in the System Settings Page
		cy.get('.fc-head-container').eq(0).should('contain.text', 'Tue');

		//Deleting the created event
		cy.visit('/app/event');
		cy.get('.list-row-checkbox').eq(0).click();
		cy.get('.actions-btn-group > .btn').contains('Actions').click();
		cy.get('.actions-btn-group > .dropdown-menu [data-label="Delete"]').click();
		cy.click_modal_primary_button('Yes');
	});
});<commit_msg>test: Added test script for control type "Date"<commit_after>context('Date Control', () => {
	before(() => {
		cy.login();
		cy.visit('/app/doctype');
		return cy.window().its('frappe').then(frappe => {
			return frappe.xcall('frappe.tests.ui_test_helpers.create_doctype', {
				name: 'Test Date Control',
				fields: [
					{
						"label": "Date",
						"fieldname": "date",
						"fieldtype": "Date",
						"in_list_view": 1
					},
				]
			});
		});
	});
	it('Selecting a date from the datepicker', () => {
		cy.new_form('Test Date Control');
		cy.get_field('date', 'Date').click();
		cy.get('.datepicker--nav-title').click();
		cy.get('.datepicker--nav-title').click({force: true});

		//Inputing values in the date field
		cy.get('.datepicker--years > .datepicker--cells > .datepicker--cell[data-year=2020]').click();
		cy.get('.datepicker--months > .datepicker--cells > .datepicker--cell[data-month=0]').click();
		cy.get('.datepicker--days > .datepicker--cells > .datepicker--cell[data-date=15]').click();

		//Verifying if the selected date is displayed in the date field
		cy.get_field('date', 'Date').should('have.value', '01-15-2020');
	});

	it('Checking next and previous button', () => {
		cy.get_field('date', 'Date').click();

		//Clicking on the next button in the datepicker
		cy.get('.datepicker--nav-action[data-action=next]').click();

		//Selecting a date from the datepicker
		cy.get('.datepicker--cell[data-date=15]').click({force: true});

		//Verifying if the selected date has been displayed in the date field
		cy.get_field('date', 'Date').should('have.value', '02-15-2020');
		cy.wait(500);
		cy.get_field('date', 'Date').click();

		//Clicking on the previous button in the datepicker
		cy.get('.datepicker--nav-action[data-action=prev]').click();

		//Selecting a date from the datepicker
		cy.get('.datepicker--cell[data-date=15]').click({force: true});

		//Verifying if the selected date has been displayed in the date field
		cy.get_field('date', 'Date').should('have.value', '01-15-2020');
	});

	it('Clicking on "Today" button gives todays date', () => {
		cy.get_field('date', 'Date').click();

		//Clicking on "Today" button
		cy.get('.datepicker--button').click();

		//Picking up the todays date
		const todays_date = Cypress.moment().format('MM-DD-YYYY');

		//Verifying if clicking on "Today" button matches today's date
		cy.get_field('date', 'Date').should('have.value', todays_date);
	});

	it('Configuring first day of the week', () => {
		//Visiting "System Settings" page
		cy.visit('/app/system-settings/System%20Settings');

		//Visiting the "Date and Number Format" section
		cy.contains('Date and Number Format').click();

		//Changing the configuration for "First day of the week" field
		cy.get('select[data-fieldname="first_day_of_the_week"]').select('Tuesday');
		cy.get('.page-head .page-actions').findByRole('button', {name: 'Save'}).click();
		cy.new_form('Test Date Control');
		cy.get_field('date', 'Date').click();

		//Checking if the first day shown in the datepicker is the one which is configured in the System Settings Page
		cy.get('.datepicker--days-names').eq(0).should('contain.text', 'Tu');
		cy.visit('/app/doctype');

		//Adding filter in the doctype list
		cy.add_filter();
		cy.get('.fieldname-select-area').type('Created On{enter}');
		cy.get('.filter-field > .form-group > .input-with-feedback').click();

		//Checking if the first day shown in the datepicker is the one which is configured in the System Settings Page
		cy.get('.datepicker--days-names').eq(0).should('contain.text', 'Tu');

		//Adding event
		cy.visit('/app/event');
		cy.click_listview_primary_button('Add Event');
		cy.get('textarea[data-fieldname=subject]').type('Test');
		cy.fill_field('starts_on', '01-01-2022 00:00:00', 'Datetime');
		cy.click_listview_primary_button('Save');
		cy.visit('/app/event');
		cy.get('.custom-btn-group > .btn').click();

		//Opening Calendar view for the event created
		cy.get('[data-view="Calendar"] > .grey-link').click();

		//Checking if the calendar view has the first day as the configured day in the System Settings Page
		cy.get('.fc-head-container').eq(0).should('contain.text', 'Tue');

		//Deleting the created event
		cy.visit('/app/event');
		cy.get('.list-row-checkbox').eq(0).click();
		cy.get('.actions-btn-group > .btn').contains('Actions').click();
		cy.get('.actions-btn-group > .dropdown-menu [data-label="Delete"]').click();
		cy.click_modal_primary_button('Yes');
	});
});<|endoftext|>


<commit_before>// AngularFire is an officially supported AngularJS binding for Firebase.
// The bindings let you associate a Firebase URL with a model (or set of
// models), and they will be transparently kept in sync across all clients
// currently using your app. The 2-way data binding offered by AngularJS works
// as normal, except that the changes are also sent to all other clients
// instead of just a server.
//
//      AngularFire 0.5
//      http://angularfire.com
//      License: MIT

"use strict";

var AngularFire;

// Define the `firebase` module under which all AngularFire services will live.
angular.module("firebase", []).value("Firebase", Firebase);

// Define the `$firebase` service that provides synchronization methods.
angular.module("firebase").factory("$firebase", ["$q", "$parse", "$timeout",
  function($q, $parse, $timeout) {
    // The factory returns an object containing the value of the data at
    // the Firebase location provided, as well as several methods. It
    // takes a single argument:
    //
    //   * `ref`:    A Firebase reference. Queries or limits may be applied.
    return function(ref) {
      var af = new AngularFire($q, $parse, $timeout, ref);
      return af.construct();
    };
  }
]);

// Define the `orderByPriority` filter that sorts objects returned by
// $firebase in the order of priority. Priority is defined by Firebase,
// for more info see: https://www.firebase.com/docs/ordered-data.html
angular.module("firebase").filter("orderByPriority", function() {
  return function(input) {
    if (!input.$getIndex || typeof input.$getIndex != "function") {
      return input;
    }

    var sorted = [];
    var index = input.$getIndex();
    if (index.length <= 0) {
      return input;
    }

    for (var i = 0; i < index.length; i++) {
      var val = input[index[i]];
      if (val) {
        val.$id = index[i];
        sorted.push(val);
      }
    }

    return sorted;
  };
});

// The `AngularFire` object that implements synchronization.
AngularFire = function($q, $parse, $timeout, ref) {
  this._q = $q;
  this._bound = false;
  this._parse = $parse;
  this._timeout = $timeout;

  this._index = [];
  this._onChange = [];
  this._onLoaded = [];

  if (typeof ref == "string") {
    throw new Error("Please provide a Firebase reference instead " +
      "of a URL, eg: new Firebase(url)");
  }
  this._fRef = ref;
};

AngularFire.prototype = {
  // This function is called by the factory to create a new explicit sync
  // point between a particular model and a Firebase location.
  construct: function() {
    var self = this;
    var object = {};

    // Establish a 3-way data binding (implicit sync) with the specified
    // Firebase location and a model on $scope. To be used from a controller
    // to automatically synchronize *all* local changes. It take two arguments:
    //
    //    * `$scope`: The scope with which the bound model is associated.
    //    * `name`:   The name of the model.
    //
    // This function also returns a promise, which when resolve will be
    // provided an `unbind` method, a function which you can call to stop
    // watching the local model for changes.
    object.$bind = function(scope, name) {
      return self._bind(scope, name);
    };

    // Add an object to the remote data. Adding an object is the
    // equivalent of calling `push()` on a Firebase reference.
    object.$add = function(item) {
      if (typeof item == "object") {
        self._fRef.ref().push(self._parseObject(item));
      } else {
        self._fRef.ref().push(item);
      }
    };

    // Save the current state of the object to the remote data. Saving an
    // object is the equivalent of calling `update()` on a Firebase reference.
    object.$save = function() {
      self._fRef.ref().update(self._parseObject(self._object));
    };

    // Set the current state of the object to the remote data as-is. Calling
    // this is the equivalent of calling `set()` on a Firebase reference.
    object.$set = function() {
      self._fRef.ref().set(self._parseObject(self._object));
    };

    // Remove this object from the remote data. Calling this is the equivalent
    // of calling `remove()` on a Firebase reference.
    object.$remove = function() {
      self._fRef.ref().remove();
    };

    // Attach an event handler for when the object is changed. You can attach
    // handlers for the following events:
    //
    //  - "change": The provided function will be called whenever the local
    //              object is modified because the remote data was updated.
    //  - "loaded": This function will be called *once*, when the initial
    //              data has been loaded. 'object' will be an empty object ({})
    //              until this function is called.
    object.$on = function(type, callback) {
      switch (type) {
      case "change":
        self._onChange.push(callback);
        break;
      case "loaded":
        self._onLoaded.push(callback);
        break;
      default:
        throw new Error("Invalid event type " + type + " specified");
      }
    };

    // Return the current index, which is a list of key names in an array,
    // ordered by their Firebase priority.
    object.$getIndex = function() {
      return angular.copy(self._index);
    };

    self._object = object;
    self._getInitialValue();

    return self._object;
  },

  // This function is responsible for fetching the initial data for the
  // given reference. If the data returned from the server is an object or
  // array, we'll attach appropriate child event handlers. If the value is
  // a primitive, we'll continue to watch for value changes.
  _getInitialValue: function() {
    var self = this;
    self._fRef.on("value", function(snapshot) {
      var value = snapshot.val();

      switch (typeof value) {
      // For primitive values, simply update the object returned.
      case "string":
      case "number":
      case "boolean":
        self._updatePrimitive(value);
        break;
      // For arrays and objects, switch to child methods.
      case "object":
        self._getChildValues();
        self._fRef.off("value");
        break;
      default:
        throw new Error("Unexpected type from remote data " + typeof value);
      }

      // Call handlers for the "loaded" event.
      self._broadcastEvent("loaded", value);
    });
  },

  // This function attaches child events for object and array types.
  _getChildValues: function() {
    var self = this;
    // Store the priority of the current property as "$priority". This can
    // be used with the `toArray | orderBy:'$priority'` filter to sort objects.
    function _processSnapshot(snapshot, prevChild) {
      var key = snapshot.name();
      var val = snapshot.val();

      // If the item already exists in the index, remove it first.
      var curIdx = self._index.indexOf(key);
      if (curIdx !== -1) {
        self._index.splice(curIdx, 1);
      }

      // Update index. This is used by $getIndex and the orderByPriority filter.
      if (prevChild) {
        var prevIdx = self._index.indexOf(prevChild);
        self._index.splice(prevIdx + 1, 0, key);
      } else {
        self._index.unshift(key);
      }

      // Update local model with priority field, if needed.
      if (snapshot.getPriority() !== null) {
        val.$priority = snapshot.getPriority();
      }
      self._updateModel(key, val);
    }

    self._fRef.on("child_added", _processSnapshot);
    self._fRef.on("child_moved", _processSnapshot);
    self._fRef.on("child_changed", _processSnapshot);
    self._fRef.on("child_removed", function(snapshot) {
      // Remove from index.
      var key = snapshot.name();
      var idx = self._index.indexOf(key);
      self._index.splice(idx, 1);

      // Remove from local model.
      self._updateModel(key, null);
    });
  },

  // Called whenever there is a remote change. Applies them to the local
  // model for both explicit and implicit sync modes.
  _updateModel: function(key, value) {
    var self = this;
    self._timeout(function() {
      if (value == null) {
        delete self._object[key];
      } else {
        self._object[key] = value;
      }

      // Call change handlers.
      self._broadcastEvent("change");

      // If there is an implicit binding, also update the local model.
      if (!self._bound) {
        return;
      }

      var current = self._object;
      var local = self._parse(self._name)(self._scope);
      // If remote value matches local value, don't do anything, otherwise
      // apply the change.
      if (!angular.equals(current, local)) {
        self._parse(self._name).assign(self._scope, angular.copy(current));
      }
    });
  },

  // Called whenever there is a remote change for a primitive value.
  _updatePrimitive: function(value) {
    var self = this;
    self._timeout(function() {
      // Primitive values are represented as a special object {$value: value}.
      self._object.$value = value;

      // Call change handlers.
      self._broadcastEvent("change");

      // If there's an implicit binding, simply update the local scope model.
      if (self._bound) {
        var local = self._parse(self._name)(self._scope);
        if (!angular.equals(value, local)) {
          self._parse(self._name).assign(self._scope, value);
        }
      }
    });
  },

  // If event handlers for a specified event were attached, call them.
  _broadcastEvent: function(evt, param) {
    var cbs;
    switch (evt) {
    case "change":
      cbs = this._onChange;
      break;
    case "loaded":
      cbs = this._onLoaded;
      break;
    default:
      cbs = [];
      break;
    }
    if (cbs.length > 0) {
      for (var i = 0; i < cbs.length; i++) {
        if (typeof cbs[i] == "function") {
          cbs[i](param);
        }
      }
    }
  },

  // This function creates a 3-way binding between the provided scope model
  // and Firebase. All changes made to the local model are saved to Firebase
  // and changes to the remote data automatically appear on the local model.
  _bind: function(scope, name) {
    var self = this;
    var deferred = self._q.defer();

    // _updateModel will take care of updating the local model if _bound
    // is set to true.
    self._name = name;
    self._bound = true;
    self._scope = scope;

    // If the model on $scope is not set yet, make it an object.
    var local = self._parse(name)(scope);
    if (local === undefined) {
      self._parse(name).assign(scope, {});
    } else {
      self._fRef.update(self._parseObject(local));
    }

    // We're responsible for setting up scope.$watch to reflect local changes
    // on the Firebase data.
    var unbind = scope.$watch(name, function() {
      // If the new local value matches the current remote value, we don't
      // trigger a remote update.
      local = self._parseObject(self._parse(name)(scope));
      if (angular.equals(local, self._object)) {
        return;
      }
      // Use update if limits are in effect, set if not.
      if (self._fRef.set) {
        self._fRef.set(local);
      } else {
        self._fRef.ref().update(local);
      }
    }, true);

    // When the scope is destroyed, unbind automatically.
    scope.$on("$destroy", function() {
      unbind();
    });

    // Once we receive the initial value, resolve the promise.
    self._fRef.once("value", function() {
      deferred.resolve(unbind);
    });

    return deferred.promise;
  },

  // Parse a local model, removing all properties beginning with "$" and
  // converting $priority to ".priority".
  _parseObject: function(obj) {
    function _findReplacePriority(item) {
      for (var prop in item) {
        if (item.hasOwnProperty(prop)) {
          if (prop == "$priority") {
            item[".priority"] = item.$priority;
            delete item.$priority;
          } else if (typeof item[prop] == "object") {
            _findReplacePriority(item[prop]);
          }
        }
      }
      return item;
    }

    // We use toJson/fromJson to remove $$hashKey and others. Can be replaced
    // by angular.copy, but only for later versions of AngularJS.
    return angular.fromJson(angular.toJson(_findReplacePriority(obj)));
  }
};
<commit_msg>Added the $child and the $set functions.<commit_after>// AngularFire is an officially supported AngularJS binding for Firebase.
// The bindings let you associate a Firebase URL with a model (or set of
// models), and they will be transparently kept in sync across all clients
// currently using your app. The 2-way data binding offered by AngularJS works
// as normal, except that the changes are also sent to all other clients
// instead of just a server.
//
//      AngularFire 0.5
//      http://angularfire.com
//      License: MIT

"use strict";

var AngularFire;

// Define the `firebase` module under which all AngularFire services will live.
angular.module("firebase", []).value("Firebase", Firebase);

// Define the `$firebase` service that provides synchronization methods.
angular.module("firebase").factory("$firebase", ["$q", "$parse", "$timeout",
  function($q, $parse, $timeout) {
    // The factory returns an object containing the value of the data at
    // the Firebase location provided, as well as several methods. It
    // takes a single argument:
    //
    //   * `ref`:    A Firebase reference. Queries or limits may be applied.
    return function(ref) {
      var af = new AngularFire($q, $parse, $timeout, ref);
      return af.construct();
    };
  }
]);

// Define the `orderByPriority` filter that sorts objects returned by
// $firebase in the order of priority. Priority is defined by Firebase,
// for more info see: https://www.firebase.com/docs/ordered-data.html
angular.module("firebase").filter("orderByPriority", function() {
  return function(input) {
    if (!input.$getIndex || typeof input.$getIndex != "function") {
      return input;
    }

    var sorted = [];
    var index = input.$getIndex();
    if (index.length <= 0) {
      return input;
    }

    for (var i = 0; i < index.length; i++) {
      var val = input[index[i]];
      if (val) {
        val.$id = index[i];
        sorted.push(val);
      }
    }

    return sorted;
  };
});

// The `AngularFire` object that implements synchronization.
AngularFire = function($q, $parse, $timeout, ref) {
  this._q = $q;
  this._bound = false;
  this._parse = $parse;
  this._timeout = $timeout;

  this._index = [];
  this._onChange = [];
  this._onLoaded = [];

  if (typeof ref == "string") {
    throw new Error("Please provide a Firebase reference instead " +
      "of a URL, eg: new Firebase(url)");
  }
  this._fRef = ref;
};

AngularFire.prototype = {
  // This function is called by the factory to create a new explicit sync
  // point between a particular model and a Firebase location.
  construct: function() {
    var self = this;
    var object = {};

    // Establish a 3-way data binding (implicit sync) with the specified
    // Firebase location and a model on $scope. To be used from a controller
    // to automatically synchronize *all* local changes. It take two arguments:
    //
    //    * `$scope`: The scope with which the bound model is associated.
    //    * `name`:   The name of the model.
    //
    // This function also returns a promise, which when resolve will be
    // provided an `unbind` method, a function which you can call to stop
    // watching the local model for changes.
    object.$bind = function(scope, name) {
      return self._bind(scope, name);
    };

    // Add an object to the remote data. Adding an object is the
    // equivalent of calling `push()` on a Firebase reference.
    object.$add = function(item) {
      if (typeof item == "object") {
        self._fRef.ref().push(self._parseObject(item));
      } else {
        self._fRef.ref().push(item);
      }
    };

    // Save the current state of the object to the remote data. Saving an
    // object is the equivalent of calling `update()` on a Firebase reference.
    object.$save = function() {
      self._fRef.ref().update(self._parseObject(self._object));
    };

    // Set the current state of the object to the specified value. Calling
    // this is the equivalent of calling `set()` on a Firebase reference.
    object.$set = function(newValue) {
      self._fRef.ref().set(newValue);
    };

    // Remove this object from the remote data. Calling this is the equivalent
    // of calling `remove()` on a Firebase reference.
    object.$remove = function() {
      self._fRef.ref().remove();
    };

    // Get an AngularFire wrapper for a named child.
    object.$child = function(key) {
        var af = new AngularFire(this._q, this._parse, this._timeout, this._fRef.ref().child(key));
        return af.construct();
    }

    // Attach an event handler for when the object is changed. You can attach
    // handlers for the following events:
    //
    //  - "change": The provided function will be called whenever the local
    //              object is modified because the remote data was updated.
    //  - "loaded": This function will be called *once*, when the initial
    //              data has been loaded. 'object' will be an empty object ({})
    //              until this function is called.
    object.$on = function(type, callback) {
      switch (type) {
      case "change":
        self._onChange.push(callback);
        break;
      case "loaded":
        self._onLoaded.push(callback);
        break;
      default:
        throw new Error("Invalid event type " + type + " specified");
      }
    };

    // Return the current index, which is a list of key names in an array,
    // ordered by their Firebase priority.
    object.$getIndex = function() {
      return angular.copy(self._index);
    };

    self._object = object;
    self._getInitialValue();

    return self._object;
  },

  // This function is responsible for fetching the initial data for the
  // given reference. If the data returned from the server is an object or
  // array, we'll attach appropriate child event handlers. If the value is
  // a primitive, we'll continue to watch for value changes.
  _getInitialValue: function() {
    var self = this;
    self._fRef.on("value", function(snapshot) {
      var value = snapshot.val();

      switch (typeof value) {
      // For primitive values, simply update the object returned.
      case "string":
      case "number":
      case "boolean":
        self._updatePrimitive(value);
        break;
      // For arrays and objects, switch to child methods.
      case "object":
        self._getChildValues();
        self._fRef.off("value");
        break;
      default:
        throw new Error("Unexpected type from remote data " + typeof value);
      }

      // Call handlers for the "loaded" event.
      self._broadcastEvent("loaded", value);
    });
  },

  // This function attaches child events for object and array types.
  _getChildValues: function() {
    var self = this;
    // Store the priority of the current property as "$priority". This can
    // be used with the `toArray | orderBy:'$priority'` filter to sort objects.
    function _processSnapshot(snapshot, prevChild) {
      var key = snapshot.name();
      var val = snapshot.val();

      // If the item already exists in the index, remove it first.
      var curIdx = self._index.indexOf(key);
      if (curIdx !== -1) {
        self._index.splice(curIdx, 1);
      }

      // Update index. This is used by $getIndex and the orderByPriority filter.
      if (prevChild) {
        var prevIdx = self._index.indexOf(prevChild);
        self._index.splice(prevIdx + 1, 0, key);
      } else {
        self._index.unshift(key);
      }

      // Update local model with priority field, if needed.
      if (snapshot.getPriority() !== null) {
        val.$priority = snapshot.getPriority();
      }
      self._updateModel(key, val);
    }

    self._fRef.on("child_added", _processSnapshot);
    self._fRef.on("child_moved", _processSnapshot);
    self._fRef.on("child_changed", _processSnapshot);
    self._fRef.on("child_removed", function(snapshot) {
      // Remove from index.
      var key = snapshot.name();
      var idx = self._index.indexOf(key);
      self._index.splice(idx, 1);

      // Remove from local model.
      self._updateModel(key, null);
    });
  },

  // Called whenever there is a remote change. Applies them to the local
  // model for both explicit and implicit sync modes.
  _updateModel: function(key, value) {
    var self = this;
    self._timeout(function() {
      if (value == null) {
        delete self._object[key];
      } else {
        self._object[key] = value;
      }

      // Call change handlers.
      self._broadcastEvent("change");

      // If there is an implicit binding, also update the local model.
      if (!self._bound) {
        return;
      }

      var current = self._object;
      var local = self._parse(self._name)(self._scope);
      // If remote value matches local value, don't do anything, otherwise
      // apply the change.
      if (!angular.equals(current, local)) {
        self._parse(self._name).assign(self._scope, angular.copy(current));
      }
    });
  },

  // Called whenever there is a remote change for a primitive value.
  _updatePrimitive: function(value) {
    var self = this;
    self._timeout(function() {
      // Primitive values are represented as a special object {$value: value}.
      self._object.$value = value;

      // Call change handlers.
      self._broadcastEvent("change");

      // If there's an implicit binding, simply update the local scope model.
      if (self._bound) {
        var local = self._parse(self._name)(self._scope);
        if (!angular.equals(value, local)) {
          self._parse(self._name).assign(self._scope, value);
        }
      }
    });
  },

  // If event handlers for a specified event were attached, call them.
  _broadcastEvent: function(evt, param) {
    var cbs;
    switch (evt) {
    case "change":
      cbs = this._onChange;
      break;
    case "loaded":
      cbs = this._onLoaded;
      break;
    default:
      cbs = [];
      break;
    }
    if (cbs.length > 0) {
      for (var i = 0; i < cbs.length; i++) {
        if (typeof cbs[i] == "function") {
          cbs[i](param);
        }
      }
    }
  },

  // This function creates a 3-way binding between the provided scope model
  // and Firebase. All changes made to the local model are saved to Firebase
  // and changes to the remote data automatically appear on the local model.
  _bind: function(scope, name) {
    var self = this;
    var deferred = self._q.defer();

    // _updateModel will take care of updating the local model if _bound
    // is set to true.
    self._name = name;
    self._bound = true;
    self._scope = scope;

    // If the model on $scope is not set yet, make it an object.
    var local = self._parse(name)(scope);
    if (local === undefined) {
      self._parse(name).assign(scope, {});
    } else {
      self._fRef.update(self._parseObject(local));
    }

    // We're responsible for setting up scope.$watch to reflect local changes
    // on the Firebase data.
    var unbind = scope.$watch(name, function() {
      // If the new local value matches the current remote value, we don't
      // trigger a remote update.
      local = self._parseObject(self._parse(name)(scope));
      if (angular.equals(local, self._object)) {
        return;
      }
      // Use update if limits are in effect, set if not.
      if (self._fRef.set) {
        self._fRef.set(local);
      } else {
        self._fRef.ref().update(local);
      }
    }, true);

    // When the scope is destroyed, unbind automatically.
    scope.$on("$destroy", function() {
      unbind();
    });

    // Once we receive the initial value, resolve the promise.
    self._fRef.once("value", function() {
      deferred.resolve(unbind);
    });

    return deferred.promise;
  },

  // Parse a local model, removing all properties beginning with "$" and
  // converting $priority to ".priority".
  _parseObject: function(obj) {
    function _findReplacePriority(item) {
      for (var prop in item) {
        if (item.hasOwnProperty(prop)) {
          if (prop == "$priority") {
            item[".priority"] = item.$priority;
            delete item.$priority;
          } else if (typeof item[prop] == "object") {
            _findReplacePriority(item[prop]);
          }
        }
      }
      return item;
    }

    // We use toJson/fromJson to remove $$hashKey and others. Can be replaced
    // by angular.copy, but only for later versions of AngularJS.
    return angular.fromJson(angular.toJson(_findReplacePriority(obj)));
  }
};
<|endoftext|>


<commit_before>const React = require('react');
const walkVars = require('./visitors/vars');
const walkNode = require('./visitors/node');
const ReactJsonSchema = require('./utils/schema2element').default;
const {
  flattenObject,
  getData,
  getNodesByName,
  getVars,
  splitAST,
  translate,
  findWrapTargets,
  walkSchema,
} = require('./utils');

const transformRefs = (refs) => {
  const output = {};
  const keys = ['scrollProgress', 'size', 'position'];
  Object.keys(refs).forEach((ref) => {
    const val = refs[ref];
    keys.forEach((key) => {
      if (val === null || val === undefined) {
        return;
      }
      const results = flattenObject(key, val[key]);
      Object.keys(results).forEach((result) => {
        output['_idyllRefs' + ref + result] = results[result];
      });
    });
  });
  return output;
};

const triggers = []

class Wrapper extends React.PureComponent {
  constructor() {
    super()
    triggers.push((v) => {
      this.setState({value: v.x})
    })
  }

  render() {
    return (

        {
          React.Children.map(this.props.children, c => {
            return React.cloneElement(c, {...this.state})
          })
        }

    )
  }
}

class IdyllDocument extends React.PureComponent {
  constructor(props) {
    super(props);
    this.handleUpdateProps = this.handleUpdateProps.bind(this);

    // Walk the tree, creating the proper components for evererything.
    this.bindings = {};
    this._idyllRefs = {};
    this.updateFuncCache = {};

    const {
      vars,
      derived,
      data,
      elements,
    } = splitAST(props.ast);

    const initialState = {
      ...getVars(vars),
      ...getData(data, props.datasets)
    };
    this.derivedVars = getVars(derived, initialState);

    const state = this.state = {
      ...initialState,
      ...this.getDerivedVars()
    };

    // still sets up bindings and refs
    props.ast.map(walkVars(this, props.datasets));

    const rjs = new ReactJsonSchema();
    rjs.setComponentMap({...props.componentClasses, Wrapper});
    const schema = translate(props.ast);

    const wrapTargets = findWrapTargets(schema, this.state);

    const transformedSchema = walkSchema(
      node => true,
      schema,
      node => {
        if (!wrapTargets.includes(node) || typeof node === 'string') return node;

        const {component, children, key, ...props} = node;

        Object.keys(props).forEach(k => {
          if (state.hasOwnProperty(node[k])) {
            node[k] = state[node[k]]; // update the initial value
          }
        })

        node.updateProps = (newProps) => {
          // TODO: calculate the correct objects to send
          triggers.forEach(f => f({x: newProps.value}))
        }

        return {
          component: Wrapper,
          children: [
            node
          ]
        }
      },
    );

    const kids = rjs.parseSchema({
      component: 'div',
      className: 'idyll-root',
      children: transformedSchema
    });

    this.getChildren = () => {
      return kids;
    }
  }

  handleUpdateProps(nodeID) {
    if (!this.updateFuncCache[nodeID]) {
      this.updateFuncCache[nodeID] = (props) => {
        if (this.bindings[nodeID]) {
          const newState = {};
          Object.keys(props).forEach((propName) => {
            const val = props[propName];
            if (this.bindings[nodeID][propName]) {
              newState[this.bindings[nodeID][propName]] = val;
            }
          });
          this.setStateAndDerived(newState);
        }
      };
    }

    return this.updateFuncCache[nodeID];
  }

  updateDerivedVars(newState) {
    Object.keys(this.derivedVars).forEach((dv) => {
      this.derivedVars[dv].value = this.derivedVars[dv].update(newState, this.state);
    });
  }

  setStateAndDerived(newState) {
    this.updateDerivedVars(newState);
    this.setState(newState);
  }

  getDerivedVars() {
    let dvs = {};
    Object.keys(this.derivedVars).forEach((dv) => {
      dvs[dv] = this.derivedVars[dv].value;
    });
    return dvs;
  }

  componentDidMount() {
    const refKeys = Object.keys(this._idyllRefs);
    if (!refKeys.length) {
      return;
    }
    refKeys.forEach((name) => {
      const ref = this._idyllRefs[name];
      const rect = ref.domNode().getBoundingClientRect();
      this._idyllRefs[name]._node = ref.domNode();
      this._idyllRefs[name].size = {
        x: rect.width,
        y: rect.height
      };

      this._idyllRefs[name].position = {
        top: rect.top,
        left: rect.left,
        right: rect.right,
        bottom:  rect.bottom
      };

      this._idyllRefs[name].absolutePosition = {
        top: rect.top + window.scrollY,
        left: rect.left + window.scrollX,
        right: rect.right + window.scrollX,
        bottom:  rect.bottom + window.scrollY
      };

    });
    this.setState(transformRefs(this._idyllRefs));

    window.addEventListener('scroll', (e) => {
      // calculate current position based on scroll position
      const body = document.body;
      const html = document.documentElement;
      const documentWidth = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth );
      const documentHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
      const windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
      const windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
      const scrollX = window.scrollX;
      const scrollY = window.scrollY;

      const newRefs = {};
      Object.keys(this._idyllRefs).forEach((ref) => {
        const { size, absolutePosition, _node } = this._idyllRefs[ref];

        // 0 percent === top of the div is over the bottom of the window
        const minY = Math.max(0, absolutePosition.top - windowHeight);
        // 100 percent === bottom of div is at top of window
        const maxY = Math.min(documentHeight - windowHeight, absolutePosition.bottom);

        const minX = Math.max(0, absolutePosition.left - windowWidth);
        const maxX = Math.min(documentWidth - windowWidth, absolutePosition.right);

        const rect = _node.getBoundingClientRect();
        newRefs[ref] = {
          scrollProgress: {
            x: minX === maxX ? 1 : Math.max(0, Math.min(1, (scrollX - minX) / (maxX - minX))),
            y: minY === maxY ? 1 : Math.max(0, Math.min(1, (scrollY - minY) / (maxY - minY)))
          },
          position: {
            top: rect.top,
            left: rect.left,
            right: rect.right,
            bottom:  rect.bottom
          }
        };
        this._idyllRefs[ref] = Object.assign({}, this._idyllRefs[ref], newRefs[ref]);
      });

      this.setState(transformRefs(newRefs));
    });
  }

  render() {
    return this.getChildren();
  }
}

module.exports = IdyllDocument;
<commit_msg>Working updates of components with direct var and derived var refs<commit_after>const React = require('react');
const walkVars = require('./visitors/vars');
const walkNode = require('./visitors/node');
const ReactJsonSchema = require('./utils/schema2element').default;
const {
  flattenObject,
  getData,
  getNodesByName,
  getVars,
  splitAST,
  translate,
  findWrapTargets,
  walkSchema,
} = require('./utils');

const transformRefs = (refs) => {
  const output = {};
  const keys = ['scrollProgress', 'size', 'position'];
  Object.keys(refs).forEach((ref) => {
    const val = refs[ref];
    keys.forEach((key) => {
      if (val === null || val === undefined) {
        return;
      }
      const results = flattenObject(key, val[key]);
      Object.keys(results).forEach((result) => {
        output['_idyllRefs' + ref + result] = results[result];
      });
    });
  });
  return output;
};

const triggers = []

class Wrapper extends React.PureComponent {
  constructor() {
    super()
    triggers.push((newState) => {
      let nextState = {}
      Object.keys(this.props.stateKeys).forEach(key => {
        nextState[key] = newState[this.props.stateKeys[key]]
      })
      // TODO: this shouldn't be necessary to prevent unneeded rerenders
      if (JSON.stringify(nextState) !== JSON.stringify(this.state)) {
        this.setState(nextState)
      }
    })
  }

  render() {
    return (

        {
          React.Children.map(this.props.children, c => {
            return React.cloneElement(c, {...this.state})
          })
        }

    )
  }
}

const getDerivedValues = dVars => {
  const o = {}
  Object.keys(dVars).forEach(key => o[key] = dVars[key].value)
  return o
}

class IdyllDocument extends React.PureComponent {
  constructor(props) {
    super(props);
    this.handleUpdateProps = this.handleUpdateProps.bind(this);

    // Walk the tree, creating the proper components for evererything.
    this.bindings = {};
    this._idyllRefs = {};
    this.updateFuncCache = {};

    const {
      vars,
      derived,
      data,
      elements,
    } = splitAST(props.ast);

    const initialState = {
      ...getVars(vars),
      ...getData(data, props.datasets)
    };
    const derivedVars = getVars(derived, initialState);

    let state = this.state = {
      ...initialState,
      ...getDerivedValues(derivedVars)
    };

    // still sets up bindings and refs
    props.ast.map(walkVars(this, props.datasets));

    const rjs = new ReactJsonSchema();
    rjs.setComponentMap({...props.componentClasses, Wrapper});
    const schema = translate(props.ast);

    const wrapTargets = findWrapTargets(schema, this.state);

    const transformedSchema = walkSchema(
      node => true,
      schema,
      node => {
        if (!wrapTargets.includes(node) || typeof node === 'string') return node;

        const {component, children, key, ...props} = node;
        const stateKeys = {}

        Object.keys(props).forEach(k => {
          const stateKey = node[k]
          if (
            state.hasOwnProperty(stateKey) ||
            Object.keys(state).some(sk => typeof stateKey === 'string' && stateKey.includes(sk))
          ) {
            const stateVal = state[stateKey];

            // track which state vars affect this node
            stateKeys[k] = stateKey
            node[k] = stateVal; // assign the initial value
          }
        })

        node.updateProps = (newProps) => {
          const newState = {}
          Object.keys(newProps).forEach(k => {
            if (stateKeys[k]) {
              const stateKey = stateKeys[k]
              newState[stateKey] = newProps[k]
            }
          })
          const newMergedState = {...state, ...newState};
          const newDerivedValues = getDerivedValues(
            getVars(derived, newMergedState)
          )
          const newDocState = {...newMergedState, ...newDerivedValues}

          // update doc state
          state = newDocState

          triggers.forEach(f => f(newDocState))
        }

        return {
          component: Wrapper,
          stateKeys,
          children: [
            node
          ]
        }
      },
    );

    const kids = rjs.parseSchema({
      component: 'div',
      className: 'idyll-root',
      children: transformedSchema
    });

    this.getChildren = () => {
      return kids;
    }
  }

  handleUpdateProps(nodeID) {
    if (!this.updateFuncCache[nodeID]) {
      this.updateFuncCache[nodeID] = (props) => {
        if (this.bindings[nodeID]) {
          const newState = {};
          Object.keys(props).forEach((propName) => {
            const val = props[propName];
            if (this.bindings[nodeID][propName]) {
              newState[this.bindings[nodeID][propName]] = val;
            }
          });
          this.setStateAndDerived(newState);
        }
      };
    }

    return this.updateFuncCache[nodeID];
  }

  updateDerivedVars(newState) {
    Object.keys(this.derivedVars).forEach((dv) => {
      this.derivedVars[dv].value = this.derivedVars[dv].update(newState, this.state);
    });
  }

  setStateAndDerived(newState) {
    this.updateDerivedVars(newState);
    this.setState(newState);
  }

  getDerivedVars() {
    let dvs = {};
    Object.keys(this.derivedVars).forEach((dv) => {
      dvs[dv] = this.derivedVars[dv].value;
    });
    return dvs;
  }

  componentDidMount() {
    const refKeys = Object.keys(this._idyllRefs);
    if (!refKeys.length) {
      return;
    }
    refKeys.forEach((name) => {
      const ref = this._idyllRefs[name];
      const rect = ref.domNode().getBoundingClientRect();
      this._idyllRefs[name]._node = ref.domNode();
      this._idyllRefs[name].size = {
        x: rect.width,
        y: rect.height
      };

      this._idyllRefs[name].position = {
        top: rect.top,
        left: rect.left,
        right: rect.right,
        bottom:  rect.bottom
      };

      this._idyllRefs[name].absolutePosition = {
        top: rect.top + window.scrollY,
        left: rect.left + window.scrollX,
        right: rect.right + window.scrollX,
        bottom:  rect.bottom + window.scrollY
      };

    });
    this.setState(transformRefs(this._idyllRefs));

    window.addEventListener('scroll', (e) => {
      // calculate current position based on scroll position
      const body = document.body;
      const html = document.documentElement;
      const documentWidth = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth );
      const documentHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
      const windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
      const windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
      const scrollX = window.scrollX;
      const scrollY = window.scrollY;

      const newRefs = {};
      Object.keys(this._idyllRefs).forEach((ref) => {
        const { size, absolutePosition, _node } = this._idyllRefs[ref];

        // 0 percent === top of the div is over the bottom of the window
        const minY = Math.max(0, absolutePosition.top - windowHeight);
        // 100 percent === bottom of div is at top of window
        const maxY = Math.min(documentHeight - windowHeight, absolutePosition.bottom);

        const minX = Math.max(0, absolutePosition.left - windowWidth);
        const maxX = Math.min(documentWidth - windowWidth, absolutePosition.right);

        const rect = _node.getBoundingClientRect();
        newRefs[ref] = {
          scrollProgress: {
            x: minX === maxX ? 1 : Math.max(0, Math.min(1, (scrollX - minX) / (maxX - minX))),
            y: minY === maxY ? 1 : Math.max(0, Math.min(1, (scrollY - minY) / (maxY - minY)))
          },
          position: {
            top: rect.top,
            left: rect.left,
            right: rect.right,
            bottom:  rect.bottom
          }
        };
        this._idyllRefs[ref] = Object.assign({}, this._idyllRefs[ref], newRefs[ref]);
      });

      this.setState(transformRefs(newRefs));
    });
  }

  render() {
    return this.getChildren();
  }
}

module.exports = IdyllDocument;
<|endoftext|>


<commit_before>import React from 'react';
import { Router, Route, Link } from 'react-router';
import App from './components/App';
import PoweredBy from './components/Powered-by';
import About from './components/About';

window.React = React;

React.render(
  <Router>
    <Route path="/" component={App}>
      <Route path="about" component={About}/>
      <Route path="/poweredby" component={PoweredBy}/>
    </Route>
  </Router>
  , document.getElementById('content')
);
<commit_msg>Added a slash before the "about" route path<commit_after>import React from 'react';
import { Router, Route, Link } from 'react-router';
import App from './components/App';
import PoweredBy from './components/Powered-by';
import About from './components/About';

window.React = React;

React.render(
  <Router>
    <Route path="/" component={App}>
      <Route path="/about" component={About}/>
      <Route path="/poweredby" component={PoweredBy}/>
    </Route>
  </Router>
  , document.getElementById('content')
);
<|endoftext|>


<commit_before>/*
 *  World.js
 *  2015/03/10
 *  @auther minimo
 *  This Program is MIT license.
 *
 *  マップ管理とユニットの移動、戦闘その他を自動で処理
 *  操作はMainSceneから行う
 *
 */

//マップ管理クラス
tm.define("tactics.World", {
    superClass: tm.app.Object2D,

    //親シーン
    scene: null,

    //マップ番号
    number: 0,

    //ベースレイヤー
    base: null,

    //スプライトレイヤー
    layers: null,

    //ディスプレイリスト
    dispList: null,

    //マップサイズ
    mapW: 17,
    mapH: 33,

    //最大砦数
    maxForts: 20,

    //砦リスト
    forts: null,

    //ユニットリスト
    units: null,

    //砦ＩＤ連番
    fortID: 0,

    //ユニットＩＤ連番
    unitID: 0,
    unitGroupID: 0,

    //ハンディキャップ（相手の戦力増加比率係数）
    handicap: 1.0,

    //派遣戦力レート(10 - 90)
    rate: 50,

    //自動生成用乱数発生器
    mt: null,
    rand: function(min, max) { return this.mt.nextInt(min, max); },

    //処理中フラグ
    busy: false,

    //長押しフラグ
    longPress: false,

    init: function(scene, seed) {
        this.superInit();
        this.scene = scene;

        this.seed = seed || 0;

        this.forts = [];
        this.units = [];
/*
        this.base = tm.display.Sprite("mapbase").setOrigin(0, 0).setPosition(32, 16);
        this.superClass.prototype.addChild.call(this, this.base);
*/
        this.base = tm.display.CanvasElement().setOrigin(0, 0).setPosition(32, 16);
        this.superClass.prototype.addChild.call(this, this.base);
        this.setupMapBase();

        this.dispList = [];

        //表示レイヤー構築（数字が大きい程優先度が高い）
        this.layers = [];
        for (var i = 0; i < LAYER_SYSTEM+1; i++) {
            this.layers[i] = tm.app.Object2D().addChildTo(this.base);
        }

        //マップ構築
        this.buildMap();

        this.time = 0;
    },

    update: function() {
        if (this.busy) return;

        //表示順序ソート
        if (this.time > 10 && this.time%3 == 0) {
            var len = this.dispList.length;
            var dl = [];
            for (var i = 0; i < len; i++) {
                this.dispList[i].remove();
                dl.push(this.dispList[i]);
            }
            dl.sort(function(a, b) {
                if (a.y < b.y) return -1;
                return 0;
            });
            this.dispList = [];
            for (var i = 0; i < len; i++) {
                dl[i].addChildTo(this);
            }
        }
        this.time++;
    },

    //マップの基部作成
    setupMapBase: function() {
        this.map = [];
        for(var y = 0; y < this.mapH; y++) {
            this.map[y] = [];
            for(var x = 0; x < this.mapW; x++) {
                var mx = x*64+(y%2?32:0);
                var my = y*16;
                if (y%2 == 1 && x == this.mapW-1) break;
                this.map[y][x] = tactics.MapChip()
                    .addChildTo(this.base)
                    .setPosition(mx+32, my+16);
            }
        }
    },

    //マップの自動生成
    buildMap: function(seed) {
        this.seed = seed || 0;
        this.mt = new MersenneTwister(this.seed);

        this.enterFort( 1,  2, TYPE_PLAYER, 100, 1, 1);
        this.enterFort(15, 30, TYPE_ENEMY , 100, 1, 1);
        for (var i = 0; i < 10; i++) {
            var x = this.rand(0, this.mapW-1);
            var y = this.rand(0, this.mapH-1);
            var hp = this.rand(70, 200)
            this.enterFort(x, y, TYPE_NEUTRAL, hp, 1, 0);
        }
    },

    //砦の追加
    enterFort: function(x, y, alignment, HP, power, type) {
        var mx = x*64+(y%2?32:0)+32;
        var my = y*16;
        var f = tactics.Fort(alignment, HP, power, type)
            .addChildTo(this)
            .setPosition(mx, my);
        f.mapX = x;
        f.mapY = y;

        //ＩＤ登録
        f.ID = this.fortID;
        this.fortID++;

        //管理用配列に入れる
        this.forts.push(f);
        return f;
    },

    //ユニット投入
    enterUnit: function(from, to, rate) {
        if (!(from instanceof tactics.Fort))return null;
        rate = rate || 0.5;

        var unit = tactics.Unit(from.alignment, 100, 1)
            .addChildTo(this)
            .setPosition(from.x-this.x, from.y-this.y)
            .setDestination(to);
        return unit;
    },

    //スクリーン座標からマップ座標へ変換
    screenToMap: function(x, y){
        //マップ座標のオフセットを反映
        x -= this.base.x;
        y -= this.base.y;

        //マップ座標へ仮変換
        var w = 64, h = 32;
        var mx = Math.floor(x/w);
        var my = Math.floor(y/h)*2;

        //象限の判定
        var qx = Math.floor(x-mx*w);
        var qy = Math.floor(y-my*h/2);

        //第一象限（右上）
        if (qx > 32 && qy < 16) {
            var x2 = qx-32, y2 = qy;
            if (x2/2 > y2) my--;
        } else
        //第二象限（左上）
        if (qx < 32 && qy < 16) {
            var x2 = qx, y2 = qy;
            if (16-x2/2 > y2) {mx--; my--;}
        } else
        //第三象限（左下）
        if (qx < 32 && qy > 16) {
            var x2 = qx, y2 = qy-16;
            if (x2/2 < y2) {mx--; my++;}
        } else
        //第四象限（右下）
        if (qx > 32 && qy > 16) {
            var x2 = qx-32, y2 = qy-16;
            if (16-x2/2 < y2) my++;
        }

        //範囲内にクリッピング
        mx = Math.clamp(mx, 0, this.mapW-1);
        my = Math.clamp(my, 0, this.mapH-1);

    	return {x: mx, y: my};
    },

    //指定スクリーン座標上のマップ表示物を取得
    getMapPoint: function(x, y) {
        //砦を選択しているか判定
        var res = this.getFort(px, py);
        if (res && res.distance < 32) return res.fort;

        //ユニットを選択しているか判定
        var res = this.getUnit(px, py);
        if (res && res.distance < 16) return res.unit;

        //マップ地点を取得
        var mp = this.screenToMap(px, py);
        var x = mp.x*64+(mp.y%2?32:0)+32;
        var y = mp.y*16;
        return {x:x, y:y, mapX:mp.x, mapY:mp.y};
    },

    //指定スクリーン座標から一番近い砦を取得
    getFort: function(x, y){
        if (this.forts.length == 0) return null;
        x = x-this.base.x;
        y = y-this.base.y;
        var bd = 99999999;
        var f = null;
        for (var i = 0; i < this.forts.length; i++) {
            var p = this.forts[i];
            var dx = p.x-x;
            var dy = p.y-y;
            var dis = dx*dx+dy*dy;
            if (dis < bd){
                f = p;
                bd = dis;
            }
        }
        return {fort: f, distance: Math.sqrt(bd)};
    },

    //特定陣営の砦を配列で取得
    getFortGroup: function(alignment) {
        var forts = [];
        for (var i = 0; i < this.forts.length; i++) {
            if (this.forts[i].alignment == alignment) forts.push(this.forts[i]);
        }
        return forts.length == 0? null : forts;
    },

    //特定陣営の惑星を選択／非選択にする
    selectFortGroup: function(alignment, select) {
        for (var i = 0; i < this.forts.length; i++) {
            if (this.forts[i].alignment == alignment) this.forts[i].select = select;
        }
    },

    //指定スクリーン座標から一番近い部隊を取得
    getUnit: function(x, y) {
        if (this.units.length == 0)return null;
        x = x-this.x;
        y = y-this.y;
        var bd = 99999999;
        var unit = null;
        for (var i = 0; i < this.units.length; i++) {
            var u = this.units[i];
            var dx = u.x-x;
            var dy = u.y-y;
            var dis = dx*dx+dy*dy;
            if (dis < bd){
                unit = u;
                bd = dis;
            }
        }
        return {unit: unit, distance: Math.sqrt(bd)};
    },

    //特定のグループＩＤのユニットを配列で取得
    getUnitGroup: function(groupID) {
        var units = [];
        for (var i = 0; i < this.units.length; i++) {
            if (this.units[i].groupID == groupID) units.push(this.units[i]);
        }
        return units.length == 0? null : units;
    },

    //特定のユニットグループを選択／非選択にする
    selectUnitGroup: function(groupID, select) {
        for (var i = 0, len = this.units.length; i < len; i++) {
            var u = this.units[i];
            if (u.groupID == groupID)u.select = select;
        }
    },

    //特定のユニットグループの目標を変更する
    setDestinationUnitGroup: function(groupID, destination) {
        for (var i = 0, len = this.units.length; i < len; i++) {
            var u = this.units[i];
            if (u.groupID == groupID)u.setDestination(destination);
        }
    },

    //惑星戦力合計を算出
    getPowerOfForts: function(alignment) {
        var val = 0;
        for (var i = 0, len = this.forts.length; i < len; i++) {
            var p = this.forts[i];
            if (p.alignment == alignment) val += p.HP;
        }
        return val;
    },

    //部隊戦力合計を算出
    getPowerOfUnits: function(alignment) {
        var val = 0;
        for (var i = 0, len = this.units.length; i < len; i++) {
            var p = this.units[i];
            if (p.alignment == alignment) val += p.HP;
        }
        return val;
    },

    //addChildオーバーライド
    addChild: function(child) {
        //エフェクトレイヤ
        if (child.isEffect) {
            if (!child.isLower) {
                this.layers[LAYER_EFFECT_UPPER].addChild(child);
                return this;
            } else {
                this.layers[LAYER_EFFECT_LOWER].addChild(child);
                return this;
            }
        }

        //フォアグラウンドレイヤ
        if (child.isForeground) {
            this.layers[LAYER_FOREGROUND].addChild(child);
            return this;
        }

        //システム表示レイヤ
        if (child.isSystem) {
            this.layers[LAYER_SYSTEM].addChild(child);
            return this;
        }

        //ユニットをオブジェクトレイヤへ
        if (child instanceof tactics.Unit) {
            child.world = this;
            this.layers[LAYER_OBJECT].addChild(child);
            this.units[this.units.length] = child;
            this.dispList.push(child);
            return this;
        }

        //砦はオブジェクトレイヤへ
        if (child instanceof tactics.Fort) {
            child.world = this;
            this.layers[LAYER_OBJECT].addChild(child);
            this.forts[this.forts.length] = child;
            this.dispList.push(child);
            return this;
        }

        //マップオブジェクト
        if (child instanceof tactics.MapObject) {
            child.world = this;
            this.layers[LAYER_OBJECT].addChild(child);
            this.dispList.push(child);
            return this;
        }

        //どれにも該当しない場合はバックグラウンドへ追加
        this.layers[LAYER_BACKGROUND].addChild(child);
        return this;
    },
});
<commit_msg>表示順序ソートバグ修正<commit_after>/*
 *  World.js
 *  2015/03/10
 *  @auther minimo
 *  This Program is MIT license.
 *
 *  マップ管理とユニットの移動、戦闘その他を自動で処理
 *  操作はMainSceneから行う
 *
 */

//マップ管理クラス
tm.define("tactics.World", {
    superClass: tm.app.Object2D,

    //親シーン
    scene: null,

    //マップ番号
    number: 0,

    //ベースレイヤー
    base: null,

    //スプライトレイヤー
    layers: null,

    //ディスプレイリスト
    dispList: null,

    //マップサイズ
    mapW: 17,
    mapH: 33,

    //最大砦数
    maxForts: 20,

    //砦リスト
    forts: null,

    //ユニットリスト
    units: null,

    //砦ＩＤ連番
    fortID: 0,

    //ユニットＩＤ連番
    unitID: 0,
    unitGroupID: 0,

    //ハンディキャップ（相手の戦力増加比率係数）
    handicap: 1.0,

    //派遣戦力レート(10 - 90)
    rate: 50,

    //自動生成用乱数発生器
    mt: null,
    rand: function(min, max) { return this.mt.nextInt(min, max); },

    //処理中フラグ
    busy: false,

    //長押しフラグ
    longPress: false,

    init: function(scene, seed) {
        this.superInit();
        this.scene = scene;

        this.seed = seed || 0;

        this.forts = [];
        this.units = [];
/*
        this.base = tm.display.Sprite("mapbase").setOrigin(0, 0).setPosition(32, 16);
        this.superClass.prototype.addChild.call(this, this.base);
*/
        this.base = tm.display.CanvasElement().setOrigin(0, 0).setPosition(32, 16);
        this.superClass.prototype.addChild.call(this, this.base);
        this.setupMapBase();

        this.dispList = [];

        //表示レイヤー構築（数字が大きい程優先度が高い）
        this.layers = [];
        for (var i = 0; i < LAYER_SYSTEM+1; i++) {
            this.layers[i] = tm.app.Object2D().addChildTo(this.base);
        }

        //マップ構築
        this.buildMap();

        this.time = 0;
    },

    update: function() {
        if (this.busy) return;

        //表示順序ソート
        if (this.time > 10 && this.time%3 == 0) this.sortDisplayList();

        this.time++;
    },

    //表示順序のソート
    sortDisplayList: function() {
        var len = this.dispList.length;
        var dl = [];
        for (var i = 0; i < len; i++) {
            this.dispList[i].remove();
            dl.push(this.dispList[i]);
        }
        dl.sort(function(a, b) {
            if (a.y < b.y) return -1;
            return 1;
        });
        this.dispList = [];
        for (var i = 0; i < len; i++) {
            dl[i].addChildTo(this);
        }
    },

    //マップの基部作成
    setupMapBase: function() {
        this.map = [];
        for(var y = 0; y < this.mapH; y++) {
            this.map[y] = [];
            for(var x = 0; x < this.mapW; x++) {
                var mx = x*64+(y%2?32:0);
                var my = y*16;
                if (y%2 == 1 && x == this.mapW-1) break;
                this.map[y][x] = tactics.MapChip()
                    .addChildTo(this.base)
                    .setPosition(mx+32, my+16);
            }
        }
    },

    //マップの自動生成
    buildMap: function(seed) {
        this.seed = seed || 0;
        this.mt = new MersenneTwister(this.seed);

        this.enterFort( 1,  2, TYPE_PLAYER, 100, 1, 1);
        this.enterFort(15, 30, TYPE_ENEMY , 100, 1, 1);
        for (var i = 0; i < 10; i++) {
            var x = this.rand(0, this.mapW-1);
            var y = this.rand(0, this.mapH-1);
            var hp = this.rand(70, 200)
            this.enterFort(x, y, TYPE_NEUTRAL, hp, 1, 0);
        }
    },

    //砦の追加
    enterFort: function(x, y, alignment, HP, power, type) {
        var mx = x*64+(y%2?32:0)+32;
        var my = y*16;
        var f = tactics.Fort(alignment, HP, power, type)
            .addChildTo(this)
            .setPosition(mx, my);
        f.mapX = x;
        f.mapY = y;

        //ＩＤ登録
        f.ID = this.fortID;
        this.fortID++;

        //管理用配列に入れる
        this.forts.push(f);
        return f;
    },

    //ユニット投入
    enterUnit: function(from, to, rate) {
        if (!(from instanceof tactics.Fort))return null;
        rate = rate || 0.5;

        var unit = tactics.Unit(from.alignment, 100, 1)
            .addChildTo(this)
            .setPosition(from.x-this.x, from.y-this.y)
            .setDestination(to);
        return unit;
    },

    //スクリーン座標からマップ座標へ変換
    screenToMap: function(x, y){
        //マップ座標のオフセットを反映
        x -= this.base.x;
        y -= this.base.y;

        //マップ座標へ仮変換
        var w = 64, h = 32;
        var mx = Math.floor(x/w);
        var my = Math.floor(y/h)*2;

        //象限の判定
        var qx = Math.floor(x-mx*w);
        var qy = Math.floor(y-my*h/2);

        //第一象限（右上）
        if (qx > 32 && qy < 16) {
            var x2 = qx-32, y2 = qy;
            if (x2/2 > y2) my--;
        } else
        //第二象限（左上）
        if (qx < 32 && qy < 16) {
            var x2 = qx, y2 = qy;
            if (16-x2/2 > y2) {mx--; my--;}
        } else
        //第三象限（左下）
        if (qx < 32 && qy > 16) {
            var x2 = qx, y2 = qy-16;
            if (x2/2 < y2) {mx--; my++;}
        } else
        //第四象限（右下）
        if (qx > 32 && qy > 16) {
            var x2 = qx-32, y2 = qy-16;
            if (16-x2/2 < y2) my++;
        }

        //範囲内にクリッピング
        mx = Math.clamp(mx, 0, this.mapW-1);
        my = Math.clamp(my, 0, this.mapH-1);

    	return {x: mx, y: my};
    },

    //指定スクリーン座標上のマップ表示物を取得
    getMapPoint: function(x, y) {
        //砦を選択しているか判定
        var res = this.getFort(px, py);
        if (res && res.distance < 32) return res.fort;

        //ユニットを選択しているか判定
        var res = this.getUnit(px, py);
        if (res && res.distance < 16) return res.unit;

        //マップ地点を取得
        var mp = this.screenToMap(px, py);
        var x = mp.x*64+(mp.y%2?32:0)+32;
        var y = mp.y*16;
        return {x:x, y:y, mapX:mp.x, mapY:mp.y};
    },

    //指定スクリーン座標から一番近い砦を取得
    getFort: function(x, y){
        if (this.forts.length == 0) return null;
        x = x-this.base.x;
        y = y-this.base.y;
        var bd = 99999999;
        var f = null;
        for (var i = 0; i < this.forts.length; i++) {
            var p = this.forts[i];
            var dx = p.x-x;
            var dy = p.y-y;
            var dis = dx*dx+dy*dy;
            if (dis < bd){
                f = p;
                bd = dis;
            }
        }
        return {fort: f, distance: Math.sqrt(bd)};
    },

    //特定陣営の砦を配列で取得
    getFortGroup: function(alignment) {
        var forts = [];
        for (var i = 0; i < this.forts.length; i++) {
            if (this.forts[i].alignment == alignment) forts.push(this.forts[i]);
        }
        return forts.length == 0? null : forts;
    },

    //特定陣営の惑星を選択／非選択にする
    selectFortGroup: function(alignment, select) {
        for (var i = 0; i < this.forts.length; i++) {
            if (this.forts[i].alignment == alignment) this.forts[i].select = select;
        }
    },

    //指定スクリーン座標から一番近い部隊を取得
    getUnit: function(x, y) {
        if (this.units.length == 0)return null;
        x = x-this.x;
        y = y-this.y;
        var bd = 99999999;
        var unit = null;
        for (var i = 0; i < this.units.length; i++) {
            var u = this.units[i];
            var dx = u.x-x;
            var dy = u.y-y;
            var dis = dx*dx+dy*dy;
            if (dis < bd){
                unit = u;
                bd = dis;
            }
        }
        return {unit: unit, distance: Math.sqrt(bd)};
    },

    //特定のグループＩＤのユニットを配列で取得
    getUnitGroup: function(groupID) {
        var units = [];
        for (var i = 0; i < this.units.length; i++) {
            if (this.units[i].groupID == groupID) units.push(this.units[i]);
        }
        return units.length == 0? null : units;
    },

    //特定のユニットグループを選択／非選択にする
    selectUnitGroup: function(groupID, select) {
        for (var i = 0, len = this.units.length; i < len; i++) {
            var u = this.units[i];
            if (u.groupID == groupID)u.select = select;
        }
    },

    //特定のユニットグループの目標を変更する
    setDestinationUnitGroup: function(groupID, destination) {
        for (var i = 0, len = this.units.length; i < len; i++) {
            var u = this.units[i];
            if (u.groupID == groupID)u.setDestination(destination);
        }
    },

    //惑星戦力合計を算出
    getPowerOfForts: function(alignment) {
        var val = 0;
        for (var i = 0, len = this.forts.length; i < len; i++) {
            var p = this.forts[i];
            if (p.alignment == alignment) val += p.HP;
        }
        return val;
    },

    //部隊戦力合計を算出
    getPowerOfUnits: function(alignment) {
        var val = 0;
        for (var i = 0, len = this.units.length; i < len; i++) {
            var p = this.units[i];
            if (p.alignment == alignment) val += p.HP;
        }
        return val;
    },

    //addChildオーバーライド
    addChild: function(child) {
        //エフェクトレイヤ
        if (child.isEffect) {
            if (!child.isLower) {
                this.layers[LAYER_EFFECT_UPPER].addChild(child);
                return this;
            } else {
                this.layers[LAYER_EFFECT_LOWER].addChild(child);
                return this;
            }
        }

        //フォアグラウンドレイヤ
        if (child.isForeground) {
            this.layers[LAYER_FOREGROUND].addChild(child);
            return this;
        }

        //システム表示レイヤ
        if (child.isSystem) {
            this.layers[LAYER_SYSTEM].addChild(child);
            return this;
        }

        //ユニットをオブジェクトレイヤへ
        if (child instanceof tactics.Unit) {
            child.world = this;
            this.layers[LAYER_OBJECT].addChild(child);
            this.units[this.units.length] = child;
            this.dispList.push(child);
            return this;
        }

        //砦はオブジェクトレイヤへ
        if (child instanceof tactics.Fort) {
            child.world = this;
            this.layers[LAYER_OBJECT].addChild(child);
            this.forts[this.forts.length] = child;
            this.dispList.push(child);
            return this;
        }

        //マップオブジェクト
        if (child instanceof tactics.MapObject) {
            child.world = this;
            this.layers[LAYER_OBJECT].addChild(child);
            this.dispList.push(child);
            return this;
        }

        //どれにも該当しない場合はバックグラウンドへ追加
        this.layers[LAYER_BACKGROUND].addChild(child);
        return this;
    },
});
<|endoftext|>


<commit_before>Risibot.prototype.choseMove = function() {

    if (!this.pokemon || !this.ennemy)
        return -1;

    var dmgComputation = this.AI.getMaxDamageTaken(this.pokemon, this.ennemy);
    var dmgTaken = dmgComputation[4];
    var movesInterests = dmgComputation.slice(0, 4);

    for (var i = 0; i < dmgTaken.length; i++) {
      if (dmgTaken[i] && dmgTaken[i] != NaN)
        dmgTaken[i] = 100 - Math.min(100, this.ennemy.hp - dmgTaken[i]);
    }

    for (var moveType in this.moves) {
        for (var j = 0; j < this.moves[moveType].length; j++) {
            var move = this.moves[moveType][j][0];
            var k = this.moves[moveType][j][1];
            switch (moveType) {
                case 'status':
                    movesInterests[k - 1] = this.AI.evalStatus(move, dmgTaken);
                    break;
                case 'traps':
                    movesInterests[k - 1] = this.AI.evalTraps(move, dmgTaken);
                    break;
                case 'heal':
                    movesInterests[k - 1] = this.AI.evalHeal(move, dmgTaken);
                    break;
                case 'spin':
                    movesInterests[k - 1] = this.AI.evalSpin(move, dmgTaken);
                    break;
                case 'seeds':
                    movesInterests[k - 1] = this.AI.evalSeeds(move, dmgTaken);
                    break;
                case 'defog':
                    movesInterests[k - 1] = this.AI.evalDefog(move, dmgTaken);
                    break;
                case 'roar':
                    movesInterests[k - 1] = this.AI.evalRoar(move, dmgTaken);
                    break;
                case 'painSplit':
                    movesInterests[k - 1] = this.AI.evalPainSplit(move, dmgTaken);
                    break;
            }
            console.log("Risibot: choseMove: Move " + move.name + ".");
        }
    }
    // We delete disabled moves (scarf, disable...)
    var disabledMoves = [1, 1, 1, 1];
    for (var j = 0; j < this.buttonsMoves.length; j++) {
        if (this.buttonsMoves[j])
            disabledMoves[this.buttonsMoves[j].value - 1] = 0;
    }
    // We erase the NaN and disabled moves
    for (j = 0; j < 4; j++) {
        movesInterests[j] = ( (disabledMoves[j] || movesInterests[j] == NaN) ? 0 : movesInterests[j] );
    }
    console.log("Risibot: choseMove: " + movesInterests);
    var choice = getMaxIndex(movesInterests);
    return choice;
};

PokeyI.prototype.evalStatus = function(move, dmgTaken) { // Is this status move worth it ?

  if (this.bot.ennemy.status != "" ||
    (move.status == "par" && this.hasType(this.bot.ennemy, "Electric")) ||
    (move.status == "brn" && this.hasType(this.bot.ennemy, "Fire")) ||
    (move.baseType == "Grass" && this.hasType(this.bot.ennemy, "Grass")) ||
		(move.baseType == "Electric" && this.hasType(this.bot.ennemy, "Ground")) ||
		(move.baseType == "tox" && this.hasType(this.bot.ennemy, "Steel")) ||
    (move.status == "tox" && this.hasType(this.bot.ennemy, "Poison")) ||
		(move.status == "par" && this.hasAbility(this.bot.ennemy, "Limber")) ||
		(move.status == "brn" && this.hasAbility(this.bot.ennemy, "Water Veil")) ||
    (this.hasAbility(this.bot.ennemy, "Magic Bounce")) ||
    (this.hasAbility(this.bot.ennemy, "Synchronize")) ||
		(this.room.battle.yourSide.sideConditions.safeguard)) {
    return 0;
  }

	var isAnnoying = this.getStatusInterest(move.status) / ( (this.canCure(this.bot.ennemy)) ? 2 : 1) ;
	return parseInt( ((isAnnoying + 1) * 30) ); // At most 90. Healing will be greater.
};

PokeyI.prototype.getStatusInterest = function(s) {
	switch (s) {
		case 'par':
			if (this.bot.ennemy.baseStats["spe"] > 120 || this.bot.ennemy.item == "Choice Scarf")
				return 2;
			if (this.bot.ennemy.baseStats["spe"] > 100)
				return 1;
			return 0;
		case 'tox':
			var wallCoef = this.getPotentialWall(this.bot.ennemy);
			return ( (wallCoef >= 20) ? 2 : (wallCoef >= 15) ? 1 : 0 );
		case 'brn':
			if (this.bot.ennemy.baseStats["atk"] > 120 || this.bot.ennemy.item == "Choice Band")
				return 2;
			if (this.bot.ennemy.baseStats["atk"] > 100)
				return 1;
			return 0;
		case 'slp':
			return 1;
	}
	return 0;
}

PokeyI.prototype.evalSpin = function(move, dmgTaken) { // Is this spin worth it ?

  if ((jQuery.isEmptyObject(this.bot.room.battle.mySide.sideConditions) && !this.bot.pokemon.volatiles.leechseed) ||
    this.hasType(this.bot.ennemy, "Ghost")) {
    return 0;
  }
  return 150;
};

PokeyI.prototype.evalTraps = function(move) {

  if (this.getDanger(this.bot.ennemy, this.bot.pokemon) > 100 || this.hasAbility(this.bot.ennemy, "Magic Bounce"))
    return 0;

  switch (move.id) {
    case "stealthrock":
      if (!this.bot.room.battle.yourSide.sideConditions.stealthrock)
        return 150;
      break;
    case "spikes":
      if (!this.bot.room.battle.yourSide.sideConditions.spikes)
        return 150;
      break;
    case "stickyweb":
      if (!this.bot.room.battle.yourSide.sideConditions.stickyweb)
        return 150;
      break;
  }
  console.log("Risibot: evalTraps: Entry hazards are already set.");
  return 0;
};

PokeyI.prototype.evalHeal = function(move) {

  hp = this.bot.pokemon.hp / this.bot.pokemon.hpmax;
  if (hp < 0.25)
    return 1500;
  if (hp < 0.50)
    return 1000;
  if (hp < 0.60)
    return 500;
  if (hp < 0.75)
    return 100;
  if (hp < 0.90)
    return 30;
  return 0;
};

PokeyI.prototype.evalSeeds = function(move) {

  if (this.bot.ennemy.volatiles.leechseed || this.hasType(this.bot.ennemy, "Grass") || this.hasAbility(this.bot.ennemy, "Magic Bounce"))
    return 0;

  var d = this.getDanger(this.bot.ennemy, this.bot.pokemon);
  if (d < 0.3) // Ennemy could switch
    return 100;
  if (d < 0.8) // Ennemy will probably not switch
    return 300;
  if (d < 1.5) // It's crucial to survive
    return 399;
  return 0 // ABORT MISSION
};

PokeyI.prototype.evalDefog = function(move) {

  if (!this.bot.room.battle.mySide.sideConditions)
    return 0;

  var indic = 0;
  for (var condition in this.bot.room.battle.mySide.sideConditions) {
    var c = this.bot.room.battle.mySide.sideConditions[condition][0];
    switch (c) {
      case 'toxicspikes':
      case 'spikes':
        indic += 1;
        break;
      case 'stickyweb':
      case 'stealthrock':
        indic += 2;
        break;
      case 'reflect':
      case 'safeguard':
      case 'lightscreen':
        indic -= 2;
        break;
    }
  }
  for (var condition in this.bot.room.battle.yourSide.sideConditions) {
    var c = this.bot.room.battle.yourSide.sideConditions[condition][0];
    switch (c) {
      case 'toxicspikes':
      case 'spikes':
        indic -= 1;
        break;
      case 'stickyweb':
      case 'stealthrock':
        indic -= 2;
        break;
      case 'reflect':
      case 'safeguard':
      case 'lightscreen':
        indic += 2;
        break;
    }
  }

  if (indic < 0) // Terrain is good for the bot
    return 0;
  else
    return 50 * indic;
};

PokeyI.prototype.evalRoar = function(move) {

  if (this.hasAbility(this.bot.ennemy, "Magic Bounce"))
    return 0;

  coef = 1.0;
  for (c in this.bot.room.battle.yourSide.sideConditions) {
    switch (this.bot.room.battle.yourSide.sideConditions[c]) {
      case 'stealthrock': // Will damage and destabilize
      case 'spikes':
      case 'toxicspikes':
      case 'reflect': // Will temporize
      case 'lightscreen':
      case 'safeguard':
        coef += 1.0;
    }
  }
  for (b in this.bot.ennemy.boosts) {
    coef += this.bot.ennemy.boosts[b];
  }

  coef = Math.max(0.0, coef - this.getDanger(this.bot.ennemy, this.bot.pokemon));

  return 70 * coef;

};

/////////////////// UNSSAFE ZONE //////////////////////////////////////

PokeyI.prototype.evalPainSplit = function(move) { // NOT TESTED NOW

  expectedDamage = this.getMaxDamageTaken(this.bot.pokemon, this.bot.ennemy)[1];
  ennemyHP = parseInt((parseInt(31 + 2 * this.bot.ennemy.baseStats * this.bot.ennemy.level / 100) + 10 + this.bot.ennemy.level) * this.bot.ennemy.hp / 100);

  if (this.isFaster(this.bot.pokemon, this.bot.ennemy)) { // If I should hit first
    newHP = parseInt((ennemyHP + this.bot.pokemon.hp) / 2); // Hp after pain split

    if (newHP < this.bot.pokemon.hp) // We will lose HP
      return 0;

    if (newHP < expectedDamage) { // We will probably die
      ratio = (this.bot.pokemon.hp / this.bot.pokemon.maxhp);
      return (ratio < 0.25) ? 100 : (ratio < 0.5) ? 50 : 0;
    }

    return (newHP / this.bot.pokemon.hp) * 100;
  }

  // If I will hit in second

  expectedHP = this.bot.pokemon.hp - expectedDamage;
  if (expectedHp < 0) // We will die before having done anything
    return 150; // FINAL GAMBIT

  newHP = parseInt((ennemyHP + expectedHP) / 2);

  if (newHP < expectedHP) // We will lose HP
    return 0;

  return (newHP / expectedHP) * 100;
};
<commit_msg>Update moveEvaluations.js<commit_after>Risibot.prototype.choseMove = function() {

  if (!this.pokemon || !this.ennemy)
    return -1;

  var dmgComputation = this.AI.getMaxDamageTaken(this.pokemon, this.ennemy);
  var dmgTaken = dmgComputation[4];
  var movesInterests = dmgComputation.slice(0, 4);

  for (var i = 0; i < dmgTaken.length; i++) {
    if (dmgTaken[i] && dmgTaken[i] != NaN)
      dmgTaken[i] = 100 - Math.min(100, this.ennemy.hp - dmgTaken[i]);
  }

  for (var moveType in this.moves) {
    for (var j = 0; j < this.moves[moveType].length; j++) {
      var move = this.moves[moveType][j][0];
      var k = this.moves[moveType][j][1];
      switch (moveType) {
        case 'status':
          movesInterests[k - 1] = this.AI.evalStatus(move, dmgTaken);
          break;
        case 'traps':
          movesInterests[k - 1] = this.AI.evalTraps(move, dmgTaken);
          break;
        case 'heal':
          movesInterests[k - 1] = this.AI.evalHeal(move, dmgTaken);
          break;
        case 'spin':
          movesInterests[k - 1] = this.AI.evalSpin(move, dmgTaken);
          break;
        case 'seeds':
          movesInterests[k - 1] = this.AI.evalSeeds(move, dmgTaken);
          break;
        case 'defog':
          movesInterests[k - 1] = this.AI.evalDefog(move, dmgTaken);
          break;
        case 'roar':
          movesInterests[k - 1] = this.AI.evalRoar(move, dmgTaken);
          break;
        case 'painSplit':
          movesInterests[k - 1] = this.AI.evalPainSplit(move, dmgTaken);
          break;
      }
      console.log("Risibot: choseMove: Move " + move.name + ".");
    }
  }
  // We delete disabled moves (scarf, disable...)
  var disabledMoves = [1, 1, 1, 1];
  for (var j = 0; j < this.buttonsMoves.length; j++) {
    if (this.buttonsMoves[j])
      disabledMoves[this.buttonsMoves[j].value - 1] = 0;
  }
  // We erase the NaN and disabled moves
  for (j = 0; j < 4; j++) {
    movesInterests[j] = ((disabledMoves[j] || movesInterests[j] == NaN) ? 0 : movesInterests[j]);
  }
  console.log("Risibot: choseMove: " + movesInterests);
  var choice = getMaxIndex(movesInterests);
  return choice;
};

PokeyI.prototype.evalStatus = function(move, dmgTaken) { // Is this status move worth it ?

  if (this.bot.ennemy.status != "" ||
    (move.status == "par" && this.hasType(this.bot.ennemy, "Electric")) ||
    (move.status == "brn" && this.hasType(this.bot.ennemy, "Fire")) ||
    (move.baseType == "Grass" && this.hasType(this.bot.ennemy, "Grass")) ||
    (move.baseType == "Electric" && this.hasType(this.bot.ennemy, "Ground")) ||
    (move.baseType == "tox" && this.hasType(this.bot.ennemy, "Steel")) ||
    (move.status == "tox" && this.hasType(this.bot.ennemy, "Poison")) ||
    (move.status == "par" && this.hasAbility(this.bot.ennemy, "Limber")) ||
    (move.status == "brn" && this.hasAbility(this.bot.ennemy, "Water Veil")) ||
    (this.hasAbility(this.bot.ennemy, "Magic Bounce")) ||
    (this.hasAbility(this.bot.ennemy, "Synchronize")) ||
    (this.room.battle.yourSide.sideConditions.safeguard)) {
    return 0;
  }

  var isAnnoying = this.getStatusInterest(move.status) / ((this.canCure(this.bot.ennemy)) ? 2 : 1);
  return parseInt(((isAnnoying + 1) * 30)); // At most 90. Healing will be greater.
};

PokeyI.prototype.getStatusInterest = function(s) {
  switch (s) {
    case 'par':
      if (this.bot.ennemy.baseStats["spe"] > 120 || this.bot.ennemy.item == "Choice Scarf")
        return 2;
      if (this.bot.ennemy.baseStats["spe"] > 100)
        return 1;
      return 0;
    case 'tox':
      var wallCoef = this.getPotentialWall(this.bot.ennemy);
      return ((wallCoef >= 20) ? 2 : (wallCoef >= 15) ? 1 : 0);
    case 'brn':
      if (this.bot.ennemy.baseStats["atk"] > 120 || this.bot.ennemy.item == "Choice Band")
        return 2;
      if (this.bot.ennemy.baseStats["atk"] > 100)
        return 1;
      return 0;
    case 'slp':
      return 1;
  }
  return 0;
}

PokeyI.prototype.evalSpin = function(move, dmgTaken) { // Is this spin worth it ?

  if ((jQuery.isEmptyObject(this.bot.room.battle.mySide.sideConditions) && !this.bot.pokemon.volatiles.leechseed) ||
    this.hasType(this.bot.ennemy, "Ghost")) {
    return 0;
  }
  return 150;
};

PokeyI.prototype.evalTraps = function(move) {

  if (this.getDanger(this.bot.ennemy, this.bot.pokemon) > 100 || this.hasAbility(this.bot.ennemy, "Magic Bounce"))
    return 0;

  switch (move.id) {
    case "stealthrock":
      if (!this.bot.room.battle.yourSide.sideConditions.stealthrock)
        return 150;
      break;
    case "spikes":
      if (!this.bot.room.battle.yourSide.sideConditions.spikes)
        return 150;
      break;
    case "stickyweb":
      if (!this.bot.room.battle.yourSide.sideConditions.stickyweb)
        return 150;
      break;
  }
  console.log("Risibot: evalTraps: Entry hazards are already set.");
  return 0;
};

PokeyI.prototype.evalHeal = function(move) {

  hp = this.bot.pokemon.hp / this.bot.pokemon.hpmax;
  if (hp < 0.25)
    return 1500;
  if (hp < 0.50)
    return 1000;
  if (hp < 0.60)
    return 500;
  if (hp < 0.75)
    return 100;
  if (hp < 0.90)
    return 30;
  return 0;
};

PokeyI.prototype.evalSeeds = function(move) {

  if (this.bot.ennemy.volatiles.leechseed || this.hasType(this.bot.ennemy, "Grass") || this.hasAbility(this.bot.ennemy, "Magic Bounce"))
    return 0;

  var d = this.getDanger(this.bot.ennemy, this.bot.pokemon);
  if (d < 0.3) // Ennemy could switch
    return 100;
  if (d < 0.8) // Ennemy will probably not switch
    return 300;
  if (d < 1.5) // It's crucial to survive
    return 399;
  return 0 // ABORT MISSION
};

PokeyI.prototype.evalDefog = function(move) {

  if (!this.bot.room.battle.mySide.sideConditions)
    return 0;

  var indic = 0;
  for (var condition in this.bot.room.battle.mySide.sideConditions) {
    var c = this.bot.room.battle.mySide.sideConditions[condition][0];
    switch (c) {
      case 'toxicspikes':
      case 'spikes':
        indic += 1;
        break;
      case 'stickyweb':
      case 'stealthrock':
        indic += 2;
        break;
      case 'reflect':
      case 'safeguard':
      case 'lightscreen':
        indic -= 2;
        break;
    }
  }
  for (var condition in this.bot.room.battle.yourSide.sideConditions) {
    var c = this.bot.room.battle.yourSide.sideConditions[condition][0];
    switch (c) {
      case 'toxicspikes':
      case 'spikes':
        indic -= 1;
        break;
      case 'stickyweb':
      case 'stealthrock':
        indic -= 2;
        break;
      case 'reflect':
      case 'safeguard':
      case 'lightscreen':
        indic += 2;
        break;
    }
  }

  if (indic < 0) // Terrain is good for the bot
    return 0;
  else
    return 50 * indic;
};

PokeyI.prototype.evalRoar = function(move) {

  if (this.hasAbility(this.bot.ennemy, "Magic Bounce"))
    return 0;

  coef = 1.0;
  for (c in this.bot.room.battle.yourSide.sideConditions) {
    switch (this.bot.room.battle.yourSide.sideConditions[c]) {
      case 'stealthrock': // Will damage and destabilize
      case 'spikes':
      case 'toxicspikes':
      case 'reflect': // Will temporize
      case 'lightscreen':
      case 'safeguard':
        coef += 1.0;
    }
  }
  for (b in this.bot.ennemy.boosts) {
    coef += this.bot.ennemy.boosts[b];
  }

  coef = Math.max(0.0, coef - this.getDanger(this.bot.ennemy, this.bot.pokemon));

  return 70 * coef;

};

/////////////////// UNSSAFE ZONE //////////////////////////////////////

PokeyI.prototype.evalPainSplit = function(move) { // NOT TESTED NOW

  expectedDamage = this.getMaxDamageTaken(this.bot.pokemon, this.bot.ennemy)[1];
  ennemyHP = parseInt((parseInt(31 + 2 * this.bot.ennemy.baseStats * this.bot.ennemy.level / 100) + 10 + this.bot.ennemy.level) * this.bot.ennemy.hp / 100);

  if (this.isFaster(this.bot.pokemon, this.bot.ennemy)) { // If I should hit first
    newHP = parseInt((ennemyHP + this.bot.pokemon.hp) / 2); // Hp after pain split

    if (newHP < this.bot.pokemon.hp) // We will lose HP
      return 0;

    if (newHP < expectedDamage) { // We will probably die
      ratio = (this.bot.pokemon.hp / this.bot.pokemon.maxhp);
      return (ratio < 0.25) ? 100 : (ratio < 0.5) ? 50 : 0;
    }

    return (newHP / this.bot.pokemon.hp) * 100;
  }

  // If I will hit in second

  expectedHP = this.bot.pokemon.hp - expectedDamage;
  if (expectedHp < 0) // We will die before having done anything
    return 150; // FINAL GAMBIT

  newHP = parseInt((ennemyHP + expectedHP) / 2);

  if (newHP < expectedHP) // We will lose HP
    return 0;

  return (newHP / expectedHP) * 100;
};
<|endoftext|>


<commit_before>'use strict';

module.exports = {
  module: {
    loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'Redux',
    libraryTarget: 'umd'
  },
  resolve: {
    extensions: ['', '.js']
  }
};
<commit_msg>Initial Commit<commit_after>'use strict';

module.exports = {
  module: {
    loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'TinyDuck',
    libraryTarget: 'umd'
  },
  resolve: {
    extensions: ['', '.js']
  }
};
<|endoftext|>


<commit_before><commit_msg> fix screen<commit_after><|endoftext|>


<commit_before>var d3 = require('d3');
var _ = require('lodash');
var control = require('plugins/tagcloud/vis/components/control/events');
var layoutGenerator = require('plugins/tagcloud/vis/components/layout/generator');
var chartGenerator = require('plugins/tagcloud/vis/components/visualization/generator');

function vis() {
  var events = control();
  var layout = layoutGenerator();
  var chart = chartGenerator();
  var opts = {};
  var listeners = {};
  var size = [250, 250];

  function generator(selection) {
    selection.each(function (data) {
      events.listeners(listeners);

      layout.attr({
        type: opts.layout || 'grid',
        columns: opts.numOfColumns || 0,
        size: size
      });

      chart.options(opts);

      d3.select(this)
        .attr('width', size[0])
        .attr('height', size[1])
        .call(events)
        .call(layout)
        .selectAll('g.chart')
        .call(chart);
    });
  }

  // Public API

  generator.options = function (v) {
    if (!arguments.length) { return opts; }
    opts = _.isPlainObject(v) ? v : opts;
    return generator;
  };

  generator.listeners = function (v) {
    if (!arguments.length) { return listeners; }
    listeners = _.isPlainObject(v) ? v : listeners;
    return generator;
  };

  generator.size = function (v) {
    if (!arguments.length) { return size; }
    size = (_.isArray(v) && _.size(v) === 2) ? v : size;
    return generator;
  };

  return generator;
}

module.exports = vis;
<commit_msg>Closes #6. Fixes issue with scrollbar appearing after resizing visualization.<commit_after>var d3 = require('d3');
var _ = require('lodash');
var control = require('plugins/tagcloud/vis/components/control/events');
var layoutGenerator = require('plugins/tagcloud/vis/components/layout/generator');
var chartGenerator = require('plugins/tagcloud/vis/components/visualization/generator');

function vis() {
  var events = control();
  var layout = layoutGenerator();
  var chart = chartGenerator();
  var opts = {};
  var listeners = {};
  var size = [250, 250];

  function generator(selection) {
    selection.each(function (data) {
      events.listeners(listeners);

      layout.attr({
        type: opts.layout || 'grid',
        columns: opts.numOfColumns || 0,
        size: size
      });

      chart.options(opts);

      d3.select(this)
        .attr('width', '100%')
        .attr('height', size[1])
        .call(events)
        .call(layout)
        .selectAll('g.chart')
        .call(chart);
    });
  }

  // Public API

  generator.options = function (v) {
    if (!arguments.length) { return opts; }
    opts = _.isPlainObject(v) ? v : opts;
    return generator;
  };

  generator.listeners = function (v) {
    if (!arguments.length) { return listeners; }
    listeners = _.isPlainObject(v) ? v : listeners;
    return generator;
  };

  generator.size = function (v) {
    if (!arguments.length) { return size; }
    size = (_.isArray(v) && _.size(v) === 2) ? v : size;
    return generator;
  };

  return generator;
}

module.exports = vis;
<|endoftext|>