<commit_before>define([
	'goo/entities/EntityUtils',
	'goo/entities/components/Component',
	'goo/math/Quaternion',
	'goo/addons/ammo/calculateTriangleMeshShape',
	'goo/shapes/Box',
	'goo/shapes/Quad',
	'goo/shapes/Sphere',
	'goo/renderer/Material',
	'goo/shapes/ShapeCreator',
	'goo/renderer/shaders/ShaderLib',
	'goo/renderer/bounds/BoundingBox',
	'goo/renderer/bounds/BoundingSphere',
	'goo/util/ObjectUtil'
],
/** @lends */
function(
	EntityUtils,
	Component,
	Quaternion,
	calculateTriangleMeshShape,
	Box,
	Quad,
	Sphere,
	Material,
	ShapeCreator,
	ShaderLib,
	BoundingBox,
	BoundingSphere,
	_
) {
	"use strict";

	/*global Ammo */

	/**
	 * @class Adds Ammo physics to a Goo entity.
	 * Ammo is a powerful physics engine converted from the C language project Bullet
	 * use Ammo.js if you need to support any 3D shape (trimesh).
	 * Also see {@link AmmoSystem}.
	 * @extends Component
	 * @param {Object} [settings] The settings object can contain the following properties:
	 * @param {number} [settings.mass=0] (0 means immovable)
	 * @param {boolean} [settings.useBounds=false] use the model bounds or use the real (must-be-convex) vertices
	 * @param {boolean} [settings.useWorldBounds=false] use the model world bounds or use the real (must-be-convex) vertices (this setting is experimental)
	 * @param {boolean} [settings.useWorldTransform=false] use the model world transform instead of local (this setting is experimental)
	 * @param {boolean} [settings.showBounds=false] show the model world bounding box (this setting is experimental)
	 * @example
	 * var entity = EntityUtils.createTypicalEntity(goo.world, ShapeCreator.createBox(20, 10, 1));
	 * entity.setComponent(new AmmoComponent({mass:5}));
	 */
	function AmmoComponent(settings) {
		this.settings = settings = settings || {};

		_.defaults(settings,{
			mass: 0,
			useBounds: false,
			useWorldBounds : false,
			useWorldTransform : false,
			linearFactor : new Ammo.btVector3(1, 1, 1),
			isTrigger : false,
			onInitializeBody : null
		});

		this.mass = settings.mass;
		this.useBounds = settings.useBounds;
		this.useWorldBounds = settings.useWorldBounds;
		this.useWorldTransform = settings.useWorldTransform;
		this.linearFactor = settings.linearFactor;
		this.onInitializeBody = settings.onInitializeBody;
		this.isTrigger = settings.isTrigger;

		this.type = 'AmmoComponent';
		this.ammoTransform = new Ammo.btTransform();
		this.gooQuaternion = new Quaternion();
		this.shape = undefined;
	}
	AmmoComponent.prototype = Object.create(Component.prototype);

	AmmoComponent.prototype.getAmmoShapefromGooShape = function(entity, gooTransform) {
		var shape;

		// Need to abs since negative scales are fine for meshes but not for bounding boxes.
		var scale = [Math.abs(gooTransform.scale.x), Math.abs(gooTransform.scale.y), Math.abs(gooTransform.scale.z)];

		if (entity.meshDataComponent && entity.meshDataComponent.meshData) {
			var meshData = entity.meshDataComponent.meshData;
			if (meshData instanceof Box) {
				shape = new Ammo.btBoxShape(new Ammo.btVector3(meshData.xExtent * scale[0], meshData.yExtent * scale[1], meshData.zExtent * scale[2]));
			} else if (meshData instanceof Sphere) {
				shape = new Ammo.btSphereShape(meshData.radius * scale[0]);
			} else if (meshData instanceof Quad) {
				// there doesn't seem to be a Quad shape in Ammo
				shape = new Ammo.btBoxShape(new Ammo.btVector3(meshData.xExtent, meshData.yExtent, 0.01)); //new Ammo.btPlane();
			} else {
				if (this.useBounds || this.mass > 0) {
					entity.meshDataComponent.computeBoundFromPoints();
					var bound = entity.meshDataComponent.modelBound;
					if (bound instanceof BoundingBox) {
						shape = new Ammo.btBoxShape(new Ammo.btVector3(bound.xExtent * scale[0], bound.yExtent * scale[1], bound.zExtent * scale[2]));
					} else if (bound instanceof BoundingSphere) {
						shape = new Ammo.btSphereShape(bound.radius * scale[0]);
					}
				} else {
					shape = calculateTriangleMeshShape(entity, scale.data); // this can only be used for static meshes, i.e. mass == 0.
				}
			}
		} else {
			var shape = new Ammo.btCompoundShape();
			var c = entity.transformComponent.children;
			for (var i = 0; i < c.length; i++) {
				var childAmmoShape = this.getAmmoShapefromGooShape(c[i].entity, gooTransform);
				var localTrans = new Ammo.btTransform();
				localTrans.setIdentity();
				var gooPos = c[i].transform.translation;
				localTrans.setOrigin(new Ammo.btVector3(gooPos.x, gooPos.y, gooPos.z));
				// TODO: also setRotation ?
				shape.addChildShape(localTrans, childAmmoShape);
			}
		}
		return shape;
	};

	AmmoComponent.prototype.getAmmoShapefromGooShapeWorldBounds = function(entity) {
		var shape;
		var bound = EntityUtils.getTotalBoundingBox(entity);
		this.center = bound.center;
		shape = new Ammo.btBoxShape(new Ammo.btVector3(bound.xExtent, bound.yExtent, bound.zExtent));
		//shape = new Ammo.btBoxShape(new Ammo.btVector3( bound.xExtent*scale, bound.yExtent*scale, bound.zExtent*scale));
		return shape;
	};

	AmmoComponent.prototype.initialize = function(entity) {
		var gooTransform = entity.transformComponent.transform;

		if (this.useWorldTransform) {
			gooTransform = entity.transformComponent.worldTransform;
		}

		var gooPos = gooTransform.translation;

		var ammoTransform = new Ammo.btTransform();
		ammoTransform.setIdentity(); // TODO: is this needed ?
		ammoTransform.setOrigin(new Ammo.btVector3(gooPos.x, gooPos.y, gooPos.z));
		this.gooQuaternion.fromRotationMatrix(gooTransform.rotation);
		var q = this.gooQuaternion;
		ammoTransform.setRotation(new Ammo.btQuaternion(q.x, q.y, q.z, q.w));

		if (this.useWorldBounds) {
			entity._world.process();
			this.shape = this.getAmmoShapefromGooShapeWorldBounds(entity, gooTransform);
			this.difference = this.center.clone().sub(gooTransform.translation).invert();
		} else {
			this.shape = this.getAmmoShapefromGooShape(entity, gooTransform);
		}

		if (false === this.isTrigger) {
			var motionState = new Ammo.btDefaultMotionState(ammoTransform);
			var localInertia = new Ammo.btVector3(0, 0, 0);

			// rigidbody is dynamic if and only if mass is non zero, otherwise static
			if (this.mass !== 0.0) {
				this.shape.calculateLocalInertia(this.mass, localInertia);
			}

			var info = new Ammo.btRigidBodyConstructionInfo(this.mass, motionState, this.shape, localInertia);
			this.localInertia = localInertia;
			this.body = new Ammo.btRigidBody(info);
			this.body.setLinearFactor(this.linearFactor);

			if (this.onInitializeBody) {
				this.onInitializeBody(this.body);
			}
		}
	};

	AmmoComponent.prototype.showBounds = function(entity) {
		// entity.meshRendererComponent.worldBound
		// entity.meshDataComponent.computeBoundFromPoints();
		var bound = EntityUtils.getTotalBoundingBox(entity);
		var bv;
		if (bound.xExtent) {
			bv = EntityUtils.createTypicalEntity(entity._world, ShapeCreator.createBox(bound.xExtent * 2, bound.yExtent * 2, bound.zExtent * 2));
		} else if (bound.radius) {
			bv = EntityUtils.createTypicalEntity(entity._world, ShapeCreator.createSphere(12, 12, bound.radius));
		}
		var material = Material.createMaterial(ShaderLib.simpleLit);
		material.wireframe = true;
		bv.meshRendererComponent.materials.push(material);

		bv.transformComponent.setTranslation(bound.center);
		//entity.transformComponent.attachChild( bv.transformComponent );

		bv.addToWorld();
		this.bv = bv;
	};

	AmmoComponent.prototype.setPhysicalTransform = function(transform) {
		var gooPos = transform.translation;
		this.ammoTransform.setIdentity(); // TODO: is this needed ?
		this.ammoTransform.setOrigin(new Ammo.btVector3(gooPos.x, gooPos.y, gooPos.z));
		this.gooQuaternion.fromRotationMatrix(transform.rotation);
		var q = this.gooQuaternion;
		this.ammoTransform.setRotation(new Ammo.btQuaternion(q.x, q.y, q.z, q.w));
		this.body.setWorldTransform(this.ammoTransform);
	};

	AmmoComponent.prototype.copyPhysicalTransformToVisual = function(entity) {
		var tc = entity.transformComponent;
		if (!this.body) {
			return;
		}
		this.body.getMotionState().getWorldTransform(this.ammoTransform);
		var ammoQuat = this.ammoTransform.getRotation();
		this.gooQuaternion.setd(ammoQuat.x(), ammoQuat.y(), ammoQuat.z(), ammoQuat.w());
		tc.transform.rotation.copyQuaternion(this.gooQuaternion);
		var origin = this.ammoTransform.getOrigin();
		tc.setTranslation(origin.x(), origin.y(), origin.z());
		if (this.settings.showBounds) {
			if (!this.bv) {
				this.showBounds(entity);
			}
			this.bv.transformComponent.transform.rotation.copy(tc.transform.rotation);
			this.bv.transformComponent.setTranslation(tc.transform.translation);
		}
		if (this.difference) {
			tc.addTranslation(this.difference);
		}
	};

	return AmmoComponent;
});<commit_msg>A small fix for the scale change.<commit_after>define([
	'goo/entities/EntityUtils',
	'goo/entities/components/Component',
	'goo/math/Quaternion',
	'goo/addons/ammo/calculateTriangleMeshShape',
	'goo/shapes/Box',
	'goo/shapes/Quad',
	'goo/shapes/Sphere',
	'goo/renderer/Material',
	'goo/shapes/ShapeCreator',
	'goo/renderer/shaders/ShaderLib',
	'goo/renderer/bounds/BoundingBox',
	'goo/renderer/bounds/BoundingSphere',
	'goo/util/ObjectUtil'
],
/** @lends */
function(
	EntityUtils,
	Component,
	Quaternion,
	calculateTriangleMeshShape,
	Box,
	Quad,
	Sphere,
	Material,
	ShapeCreator,
	ShaderLib,
	BoundingBox,
	BoundingSphere,
	_
) {
	"use strict";

	/*global Ammo */

	/**
	 * @class Adds Ammo physics to a Goo entity.
	 * Ammo is a powerful physics engine converted from the C language project Bullet
	 * use Ammo.js if you need to support any 3D shape (trimesh).
	 * Also see {@link AmmoSystem}.
	 * @extends Component
	 * @param {Object} [settings] The settings object can contain the following properties:
	 * @param {number} [settings.mass=0] (0 means immovable)
	 * @param {boolean} [settings.useBounds=false] use the model bounds or use the real (must-be-convex) vertices
	 * @param {boolean} [settings.useWorldBounds=false] use the model world bounds or use the real (must-be-convex) vertices (this setting is experimental)
	 * @param {boolean} [settings.useWorldTransform=false] use the model world transform instead of local (this setting is experimental)
	 * @param {boolean} [settings.showBounds=false] show the model world bounding box (this setting is experimental)
	 * @example
	 * var entity = EntityUtils.createTypicalEntity(goo.world, ShapeCreator.createBox(20, 10, 1));
	 * entity.setComponent(new AmmoComponent({mass:5}));
	 */
	function AmmoComponent(settings) {
		this.settings = settings = settings || {};

		_.defaults(settings,{
			mass: 0,
			useBounds: false,
			useWorldBounds : false,
			useWorldTransform : false,
			linearFactor : new Ammo.btVector3(1, 1, 1),
			isTrigger : false,
			onInitializeBody : null
		});

		this.mass = settings.mass;
		this.useBounds = settings.useBounds;
		this.useWorldBounds = settings.useWorldBounds;
		this.useWorldTransform = settings.useWorldTransform;
		this.linearFactor = settings.linearFactor;
		this.onInitializeBody = settings.onInitializeBody;
		this.isTrigger = settings.isTrigger;

		this.type = 'AmmoComponent';
		this.ammoTransform = new Ammo.btTransform();
		this.gooQuaternion = new Quaternion();
		this.shape = undefined;
	}
	AmmoComponent.prototype = Object.create(Component.prototype);

	AmmoComponent.prototype.getAmmoShapefromGooShape = function(entity, gooTransform) {
		var shape;

		// Need to abs since negative scales are fine for meshes but not for bounding boxes.
		var scale = [Math.abs(gooTransform.scale.x), Math.abs(gooTransform.scale.y), Math.abs(gooTransform.scale.z)];

		if (entity.meshDataComponent && entity.meshDataComponent.meshData) {
			var meshData = entity.meshDataComponent.meshData;
			if (meshData instanceof Box) {
				shape = new Ammo.btBoxShape(new Ammo.btVector3(meshData.xExtent * scale[0], meshData.yExtent * scale[1], meshData.zExtent * scale[2]));
			} else if (meshData instanceof Sphere) {
				shape = new Ammo.btSphereShape(meshData.radius * scale[0]);
			} else if (meshData instanceof Quad) {
				// there doesn't seem to be a Quad shape in Ammo
				shape = new Ammo.btBoxShape(new Ammo.btVector3(meshData.xExtent, meshData.yExtent, 0.01)); //new Ammo.btPlane();
			} else {
				if (this.useBounds || this.mass > 0) {
					entity.meshDataComponent.computeBoundFromPoints();
					var bound = entity.meshDataComponent.modelBound;
					if (bound instanceof BoundingBox) {
						shape = new Ammo.btBoxShape(new Ammo.btVector3(bound.xExtent * scale[0], bound.yExtent * scale[1], bound.zExtent * scale[2]));
					} else if (bound instanceof BoundingSphere) {
						shape = new Ammo.btSphereShape(bound.radius * scale[0]);
					}
				} else {
					shape = calculateTriangleMeshShape(entity, scale); // this can only be used for static meshes, i.e. mass == 0.
				}
			}
		} else {
			var shape = new Ammo.btCompoundShape();
			var c = entity.transformComponent.children;
			for (var i = 0; i < c.length; i++) {
				var childAmmoShape = this.getAmmoShapefromGooShape(c[i].entity, gooTransform);
				var localTrans = new Ammo.btTransform();
				localTrans.setIdentity();
				var gooPos = c[i].transform.translation;
				localTrans.setOrigin(new Ammo.btVector3(gooPos.x, gooPos.y, gooPos.z));
				// TODO: also setRotation ?
				shape.addChildShape(localTrans, childAmmoShape);
			}
		}
		return shape;
	};

	AmmoComponent.prototype.getAmmoShapefromGooShapeWorldBounds = function(entity) {
		var shape;
		var bound = EntityUtils.getTotalBoundingBox(entity);
		this.center = bound.center;
		shape = new Ammo.btBoxShape(new Ammo.btVector3(bound.xExtent, bound.yExtent, bound.zExtent));
		//shape = new Ammo.btBoxShape(new Ammo.btVector3( bound.xExtent*scale, bound.yExtent*scale, bound.zExtent*scale));
		return shape;
	};

	AmmoComponent.prototype.initialize = function(entity) {
		var gooTransform = entity.transformComponent.transform;

		if (this.useWorldTransform) {
			gooTransform = entity.transformComponent.worldTransform;
		}

		var gooPos = gooTransform.translation;

		var ammoTransform = new Ammo.btTransform();
		ammoTransform.setIdentity(); // TODO: is this needed ?
		ammoTransform.setOrigin(new Ammo.btVector3(gooPos.x, gooPos.y, gooPos.z));
		this.gooQuaternion.fromRotationMatrix(gooTransform.rotation);
		var q = this.gooQuaternion;
		ammoTransform.setRotation(new Ammo.btQuaternion(q.x, q.y, q.z, q.w));

		if (this.useWorldBounds) {
			entity._world.process();
			this.shape = this.getAmmoShapefromGooShapeWorldBounds(entity, gooTransform);
			this.difference = this.center.clone().sub(gooTransform.translation).invert();
		} else {
			this.shape = this.getAmmoShapefromGooShape(entity, gooTransform);
		}

		if (false === this.isTrigger) {
			var motionState = new Ammo.btDefaultMotionState(ammoTransform);
			var localInertia = new Ammo.btVector3(0, 0, 0);

			// rigidbody is dynamic if and only if mass is non zero, otherwise static
			if (this.mass !== 0.0) {
				this.shape.calculateLocalInertia(this.mass, localInertia);
			}

			var info = new Ammo.btRigidBodyConstructionInfo(this.mass, motionState, this.shape, localInertia);
			this.localInertia = localInertia;
			this.body = new Ammo.btRigidBody(info);
			this.body.setLinearFactor(this.linearFactor);

			if (this.onInitializeBody) {
				this.onInitializeBody(this.body);
			}
		}
	};

	AmmoComponent.prototype.showBounds = function(entity) {
		// entity.meshRendererComponent.worldBound
		// entity.meshDataComponent.computeBoundFromPoints();
		var bound = EntityUtils.getTotalBoundingBox(entity);
		var bv;
		if (bound.xExtent) {
			bv = EntityUtils.createTypicalEntity(entity._world, ShapeCreator.createBox(bound.xExtent * 2, bound.yExtent * 2, bound.zExtent * 2));
		} else if (bound.radius) {
			bv = EntityUtils.createTypicalEntity(entity._world, ShapeCreator.createSphere(12, 12, bound.radius));
		}
		var material = Material.createMaterial(ShaderLib.simpleLit);
		material.wireframe = true;
		bv.meshRendererComponent.materials.push(material);

		bv.transformComponent.setTranslation(bound.center);
		//entity.transformComponent.attachChild( bv.transformComponent );

		bv.addToWorld();
		this.bv = bv;
	};

	AmmoComponent.prototype.setPhysicalTransform = function(transform) {
		var gooPos = transform.translation;
		this.ammoTransform.setIdentity(); // TODO: is this needed ?
		this.ammoTransform.setOrigin(new Ammo.btVector3(gooPos.x, gooPos.y, gooPos.z));
		this.gooQuaternion.fromRotationMatrix(transform.rotation);
		var q = this.gooQuaternion;
		this.ammoTransform.setRotation(new Ammo.btQuaternion(q.x, q.y, q.z, q.w));
		this.body.setWorldTransform(this.ammoTransform);
	};

	AmmoComponent.prototype.copyPhysicalTransformToVisual = function(entity) {
		var tc = entity.transformComponent;
		if (!this.body) {
			return;
		}
		this.body.getMotionState().getWorldTransform(this.ammoTransform);
		var ammoQuat = this.ammoTransform.getRotation();
		this.gooQuaternion.setd(ammoQuat.x(), ammoQuat.y(), ammoQuat.z(), ammoQuat.w());
		tc.transform.rotation.copyQuaternion(this.gooQuaternion);
		var origin = this.ammoTransform.getOrigin();
		tc.setTranslation(origin.x(), origin.y(), origin.z());
		if (this.settings.showBounds) {
			if (!this.bv) {
				this.showBounds(entity);
			}
			this.bv.transformComponent.transform.rotation.copy(tc.transform.rotation);
			this.bv.transformComponent.setTranslation(tc.transform.translation);
		}
		if (this.difference) {
			tc.addTranslation(this.difference);
		}
	};

	return AmmoComponent;
});<|endoftext|>


<commit_before>#! /usr/bin/env node

var path = require('path')
var Blobs = require('./')
var pull = require('pull-stream')
var toPull = require('stream-to-pull-stream')

var cmd = process.argv[2], arg = process.argv[3]

var dir = path.join(process.env.HOME, 'tmp', 'multiblob')

var blobs = Blobs(dir)

if(cmd === 'add')
  pull(
    toPull.source(process.stdin),
    blobs.add(arg, function (err, hash) {
      if(err) throw err
      console.log(hash)
    })
  )

if(cmd === 'get')
  pull(blobs.get(arg), toPull.sink(process.stdout))

if(cmd === 'has')
  blobs.has(arg, function (err) {
    if(err) throw err
    console.error('okay')
  })

if(cmd === 'ls' || cmd === 'list')
  pull(blobs.ls(), pull.drain(console.log))

if(cmd === 'hash')
  pull(toPull.source(process.stdin), createHash(console.log), pull.drain())

if(cmd === 'resolve')
  console.log(blobs.resolve(arg))
<commit_msg>hash command<commit_after>#! /usr/bin/env node

var path = require('path')
var Blobs = require('./')
var pull = require('pull-stream')
var toPull = require('stream-to-pull-stream')

var u = require('./util')
var createHash = u.createHash

var cmd = process.argv[2], arg = process.argv[3]

var dir = path.join(process.env.HOME, 'tmp', 'multiblob')

var blobs = Blobs(dir)

if(cmd === 'add')
  pull(
    toPull.source(process.stdin),
    blobs.add(arg, function (err, hash) {
      if(err) throw err
      console.log(hash)
    })
  )

if(cmd === 'get')
  pull(blobs.get(arg), toPull.sink(process.stdout))

if(cmd === 'has')
  blobs.has(arg, function (err) {
    if(err) throw err
    console.error('okay')
  })

if(cmd === 'ls' || cmd === 'list')
  pull(blobs.ls(), pull.drain(console.log))

if(cmd === 'hash') {
  var hasher = createHash('sha256')
  pull(toPull.source(process.stdin), hasher, pull.drain(null, function () {
    console.log(hasher.digest)
  }))
}

if(cmd === 'resolve')
  console.log(blobs.resolve(arg))
<|endoftext|>


<commit_before>const readline = require('readline');
const MSMServer = require('./msm').MSMServer;
const express = require('express');
const http = require('http');
const WebSocket = require('ws');

var msmserver = new MSMServer();
msmserver.loadServerList();

//Set up express for static processing (everything will be done over websockets)
var app = express();
//app.use('/web', express.static('public'));
app.use('/web', express.static(__dirname + "/public"));
app.get('/', (req, res) => {
	res.redirect('/web/');
});

//Set up websocket
const server = http.createServer(app);
const wss = new WebSocket.Server({server});

wss.on('connection', (ws) => {
	ws.on('message', (message) => {
		var m = JSON.parse(message);
		if(m.command == "exit"){
			process.exit(0);
		} else{
			msmserver.executeCommand(m.command, m.args, (output, err) => {
				var toSend = { status: null, msg: null };
				if(err){
					toSend.status = "err";
					toSend.msg = err;
				} else if(output){
					toSend.status = "ok";
					toSend.msg = output;
				} else return;
				ws.send(JSON.stringify(toSend));
			});
		}
	});
});
server.listen(8080, () => {
});

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  prompt: '>'
});

rl.on('line', (input) => {
	var args = input.match(/\S+/g) || [];
	if(args[0] == "exit"){
		rl.close();
		process.exit(0);
	} else{
		msmserver.executeCommand(args[0], args.slice(1), (output, err) => {
			if(err) console.log(err);
			else console.log(output);
			rl.prompt();
		});
	}
});
rl.prompt();<commit_msg>Added better splitting for arguments on command line<commit_after>const readline = require('readline');
const MSMServer = require('./msm').MSMServer;
const express = require('express');
const http = require('http');
const WebSocket = require('ws');

var msmserver = new MSMServer();
msmserver.loadServerList();

//Set up express for static processing (everything will be done over websockets)
var app = express();
//app.use('/web', express.static('public'));
app.use('/web', express.static(__dirname + "/public"));
app.get('/', (req, res) => {
	res.redirect('/web/');
});

//Set up websocket
const server = http.createServer(app);
const wss = new WebSocket.Server({server});

wss.on('connection', (ws) => {
	ws.on('message', (message) => {
		var m = JSON.parse(message);
		if(m.command == "exit"){
			process.exit(0);
		} else{
			msmserver.executeCommand(m.command, m.args, (output, err) => {
				var toSend = { status: null, msg: null };
				if(err){
					toSend.status = "err";
					toSend.msg = err;
				} else if(output){
					toSend.status = "ok";
					toSend.msg = output;
				} else return;
				ws.send(JSON.stringify(toSend));
			});
		}
	});
});
server.listen(8080, () => {
});

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  prompt: '>'
});

rl.on('line', (input) => {
	var args = input.match(/\".+\"|\'.+\'|\S+/g) || [];
	for(var i = 0; i < args.length; i++){
		if(args[i].startsWith("\"") || args[i].startsWith("'")){
			args[i] = args[i].substring(1, args[i].length - 1);
		}
	}
	if(args[0] == "exit"){
		rl.close();
		process.exit(0);
	} else{
		msmserver.executeCommand(args[0], args.slice(1), (output, err) => {
			if(err) console.log(err);
			else console.log(output);
			rl.prompt();
		});
	}
});
rl.prompt();<|endoftext|>


<commit_before>import * as THREE from 'three'
import { isNumber } from 'lodash'
import ThreeHelvetick from 'three/examples/fonts/helvetiker_regular.typeface.json'

const loader = new THREE.FontLoader()
const font = loader.parse(ThreeHelvetick)

export default class {
  constructor ({ scene, id, width, height, length, color, edgeColor, pressColor, text }) {
    this.box = this.getBox(width, height, length, color)
    this.edges = this.getEdges(this.box, edgeColor)
    this.text = this.getText(text, height, length)

    this.box.add(this.edges, this.text)

    scene.add(this.box)

    this.id = id
    this.isPressed = false
    this.pressDelta = 10
    this.color = color
    this.pressColor = pressColor
    this.width = width
    this.height = height
    this.length = length
  }
  getBox (width, height, length, color) {
    const geometry = new THREE.BoxBufferGeometry(width, height, length)
    const material = new THREE.MeshBasicMaterial({ color })
    return new THREE.Mesh(geometry, material)
  }
  getEdges (box, edgeColor) {
    const geometry = new THREE.EdgesGeometry(box.geometry)
    const material = new THREE.LineBasicMaterial({ color: edgeColor, linewidth: 4 })

    return new THREE.LineSegments(geometry, material)
  }
  getText (text, height, length) {
    const geometry = new THREE.TextBufferGeometry(text.value, {
      font,
      size: text.size,
      height: 1
    })

    geometry.computeBoundingBox()

    const material = new THREE.MeshBasicMaterial({ color: text.color })
    const mesh = new THREE.Mesh(geometry, material)

    mesh.position.x = -geometry.boundingBox.max.x / 2
    mesh.position.y = height / 2
    mesh.position.z = length / 2 - text.size
    mesh.rotation.x = -Math.PI / 2

    return mesh
  }
  setPosition ({ x, y, z }) {
    isNumber(x) && (this.box.position.x = x)

    if (isNumber(y)) {
      this.box.position.y = y
    }

    if (isNumber(z)) {
      this.box.position.z = z
    }
  }
  press () {
    const { position, material } = this.box

    if (!this.isPressed) {
      this.isPressed = true

      material.color.setHex(this.pressColor)
      position.y -= this.pressDelta
    }
  }
  unpress () {
    const { position, material } = this.box

    if (this.isPressed) {
      this.isPressed = false

      material.color.setHex(this.color)
      position.y += this.pressDelta
    }
  }
}
<commit_msg>correct lineWidth<commit_after>import * as THREE from 'three'
import { isNumber } from 'lodash'
import ThreeHelvetick from 'three/examples/fonts/helvetiker_regular.typeface.json'

const loader = new THREE.FontLoader()
const font = loader.parse(ThreeHelvetick)

export default class {
  constructor ({ scene, id, width, height, length, color, edgeColor, pressColor, text }) {
    this.box = this.getBox(width, height, length, color)
    this.edges = this.getEdges(this.box, edgeColor)
    this.text = this.getText(text, height, length)

    this.box.add(this.edges, this.text)

    scene.add(this.box)

    this.id = id
    this.isPressed = false
    this.pressDelta = 10
    this.color = color
    this.pressColor = pressColor
    this.width = width
    this.height = height
    this.length = length
  }
  getBox (width, height, length, color) {
    const geometry = new THREE.BoxBufferGeometry(width, height, length)
    const material = new THREE.MeshBasicMaterial({ color })
    return new THREE.Mesh(geometry, material)
  }
  getEdges (box, edgeColor) {
    const geometry = new THREE.EdgesGeometry(box.geometry)
    const material = new THREE.LineBasicMaterial({ color: edgeColor, linewidth: 1 })

    return new THREE.LineSegments(geometry, material)
  }
  getText (text, height, length) {
    const geometry = new THREE.TextBufferGeometry(text.value, {
      font,
      size: text.size,
      height: 1
    })

    geometry.computeBoundingBox()

    const material = new THREE.MeshBasicMaterial({ color: text.color })
    const mesh = new THREE.Mesh(geometry, material)

    mesh.position.x = -geometry.boundingBox.max.x / 2
    mesh.position.y = height / 2
    mesh.position.z = length / 2 - text.size
    mesh.rotation.x = -Math.PI / 2

    return mesh
  }
  setPosition ({ x, y, z }) {
    isNumber(x) && (this.box.position.x = x)

    if (isNumber(y)) {
      this.box.position.y = y
    }

    if (isNumber(z)) {
      this.box.position.z = z
    }
  }
  press () {
    const { position, material } = this.box

    if (!this.isPressed) {
      this.isPressed = true

      material.color.setHex(this.pressColor)
      position.y -= this.pressDelta
    }
  }
  unpress () {
    const { position, material } = this.box

    if (this.isPressed) {
      this.isPressed = false

      material.color.setHex(this.color)
      position.y += this.pressDelta
    }
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import Affirmations from './analytics/Affirmations'

export default class Dashboard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: {
        url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/98887/d3pack-flare-short.json',
        elementDelay: 100
      },
      startDelay: 2000
    };
  }
  componentDidMount() {
    console.log('rendering');
  }
  render() {
    var style = {
      width: '100%',
      height: '100%'
    };
    return (

        <Affirmations
          startDelay={this.state.startDelay}
          elementDelay={this.state.data.elementDelay}
          json={this.state.data.url}
        />

    )
  }
}<commit_msg>Update for circles and new sample data<commit_after>import React, { Component } from 'react'
import Circles from './analytics/Circles'

export default class Dashboard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: {
        url: './data/sample.json',
        elementDelay: 100
      },
      startDelay: 2000
    };
  }
  componentDidMount() {
    console.log('rendering');
  }
  render() {
    return (

        <Circles
          startDelay={this.state.startDelay}
          elementDelay={this.state.data.elementDelay}
          json={this.state.data.url}
        />

    )
  }
}<|endoftext|>


<commit_before>//Importing node.js modules
const Discord = require("discord.js");
const SteamCommunity = require("steamcommunity");
const fs = require("fs");

//Instantiating module objects
const client = new Discord.Client();
const community = new SteamCommunity();

//Importing my own files
const utils = require("./lib/utils.js");
const timer = require("./lib/timer.js");    //TODO
const slots = require("./lib/slots.js");    //TODO
const wow = require("./lib/wow.js");
const lbh = require("./lib/lb_archive.js"); //TODO
const dnd = require("./lib/dnd.js");        //TODO
const book = require("./lib/booktext.js");
const math = require("./lib/math/main.js"); //TODO
const words = require("./lib/dictionary.js");
const mtg = require("./lib/mtg.js");

const game = require("./lib/game/game.js");
const gameChat = require("./lib/game/commands.js");

//TODO make a fancy config object that crashes on undefined values
let config = JSON.parse(fs.readFileSync("./config.json").toString("utf-8"));

const raocsgoCommands = require("./lib/raocommands.js");
const whos = JSON.parse(fs.readFileSync("./texts/whois.json").toString("utf-8"));
const whois = raocsgoCommands.whoIsCreator(whos);
//TODO load !help stuff in help file
const jokeList = fs.readFileSync("./texts/jokes.txt").toString("utf-8").split("\n");
const joke = raocsgoCommands.jokesCreator(jokeList);
const graveList = JSON.parse(fs.readFileSync("./texts/graves.json").toString("utf-8"));
const grave = raocsgoCommands.gravesCreator(graveList);
const priceOf = raocsgoCommands.priceOfCreator(community);
//Removed imgOf because of changes to how the SCM sorts its data.

const dictionary = words.loadWords(fs.readFileSync("./texts/dictionary.txt"));
const finallys = words.finallyCreator(dictionary);

const prog = wow.progCreator(config.wow.homeRealm, config.wow.api.key);
const wowT = wow.tokenCreator(config.wow.api.token);

const gameData = JSON.parse(fs.readFileSync("./data/game_data.json").toString("utf-8"));
const g = new game(gameData, (data) => {
  fs.writeFileSync("./data/game_data.json", JSON.stringify(data));
});
setInterval(() => {
  g.save();
}, 1000 * 60 * 30); //save every 30 minutes

const gameCommands = gameChat.gameCommandCreator(g);

//TODO load leaderboard archive
const enchantmentDB = new book.Book("./texts/enchantments.json", ["int", "aug", "aff", "0", "1", "2", "3"]);
const ench = book.enchantmentCreator(enchantmentDB);

const cmds = {
  /**@param {Array} args
   * @param {Function} send
   * **/
  "ping": (args, send) => {
    return send("pong");
  },
  "whois": whois,
  "joke": joke,
  "grave": grave,
  "priceof": priceOf,
  "finally": finallys,
  "ench": ench,
  "game": gameCommands,
  "prog": prog,
  "token": wowT,
  "mtg": mtg.mtgCardImage,
  "mtgsets": mtg.mtgSets,
  "hp": dnd.hpCommand
};

//Enable reading from stdin
process.stdin.setEncoding("utf8");
const consoleCommands = {
  "reload": () => {
    //TODO call reload functions on all modules
    return "Reloaded.";
  },
  "test": () => {

  },
  "stop": () => {
    //call game module to save it
    g.save();
    process.exit(0);
    return "Stopping";
  }
};
process.stdin.on("data", (text) => {
  text = text.replace(/[\n\r\t]/g, "").replace(/ {2+}/g, " ");
  let args = text.split(" ");
  let command = args[0].toLowerCase();
  let echoed;
  if (consoleCommands.hasOwnProperty(command) === true) {
    echoed = consoleCommands[command](...args);
    console.log(echoed);
  } else {
    console.log("Unknown command. Type `help` for help.");
  }
});

//Event listener to trigger when bot starts
client.on("ready", () => {
  console.log("Connected and initialized.");
});

function serverSelector(serverID) {
  let ret = {
    atg: false,
    frz: false,
    rao: false,
    dnd: false
  };
  if (serverID === "167586953061990400") { //RAOCSGO
    ret.rao = true;
  } else if (serverID === "276220128822165505") { //AtG
    ret.atg = true;
  } else if (serverID === "234382619767341056") { //r/Frozen
    ret.frz = true;
  } else if (serverID === "446813545049358336") { //D&D
    ret.dnd = true;
  } else if (serverID === "313169519545679872" || !serverID) { //nass and dmchannel
    ret.atg = true;
    ret.frz = true;
    ret.rao = true;
    ret.dnd = true;
  }
  return ret;
}

//Main event listener for messages
client.on("message", (message) => {

  if (message.author.bot === true) return;

  let loc = message.channel;
  let msg = message.content;

  //send helper functions
  let send = function (text, opts) {
    loc.send(text, opts).catch((err) => {
      console.log(err);
    });
  };
  let sendImg = function (text, img) {
    if (img) {
      send(text, {
        embed: new Discord.RichEmbed().setImage(img)
      });
    } else {
      send(text);
    }
  };

  let server;
  if (loc.guild) {
    server = loc.guild.id;
  }

  for (let command in cmds) {
    if (cmds.hasOwnProperty(command)) {
      if (utils.hascmd(msg, command) || msg === "!" + command) {
        let args = utils.argify(msg, command);
        cmds[command](args, send, serverSelector(server), message.author, sendImg, message.mentions);
      }
    }
  }
  //Special Cases
  if (msg.substring(0, "who is ".length).toLowerCase() === "who is ") {
    let name = msg.substring("who is ".length);
    cmds["whois"](name.split(" "), send, serverSelector(server), message.author, sendImg, message.mentions);
  }
  if (message.channel.name === "botstuff" || message.channel.name === "game") {
    if (msg.substring(0, "g ".length).toLowerCase() === "g ") {
      let args = msg.substring("g ".length);
      cmds["game"](args.split(" "), send, serverSelector(server), message.author, sendImg, message.mentions);
    }
  }

});

client.login(config.discord.key);

<commit_msg>remove unused module<commit_after>//Importing node.js modules
const Discord = require("discord.js");
const SteamCommunity = require("steamcommunity");
const fs = require("fs");

//Instantiating module objects
const client = new Discord.Client();
const community = new SteamCommunity();

//Importing my own files
const utils = require("./lib/utils.js");
const timer = require("./lib/timer.js");    //TODO
const wow = require("./lib/wow.js");
const lbh = require("./lib/lb_archive.js"); //TODO
const dnd = require("./lib/dnd.js");
const book = require("./lib/booktext.js");
const math = require("./lib/math/main.js"); //TODO
const words = require("./lib/dictionary.js");
const mtg = require("./lib/mtg.js");

const game = require("./lib/game/game.js");
const gameChat = require("./lib/game/commands.js");

//TODO make a fancy config object that crashes on undefined values
let config = JSON.parse(fs.readFileSync("./config.json").toString("utf-8"));

const raocsgoCommands = require("./lib/raocommands.js");
const whos = JSON.parse(fs.readFileSync("./texts/whois.json").toString("utf-8"));
const whois = raocsgoCommands.whoIsCreator(whos);
//TODO load !help stuff in help file
const jokeList = fs.readFileSync("./texts/jokes.txt").toString("utf-8").split("\n");
const joke = raocsgoCommands.jokesCreator(jokeList);
const graveList = JSON.parse(fs.readFileSync("./texts/graves.json").toString("utf-8"));
const grave = raocsgoCommands.gravesCreator(graveList);
const priceOf = raocsgoCommands.priceOfCreator(community);
//Removed imgOf because of changes to how the SCM sorts its data.

const dictionary = words.loadWords(fs.readFileSync("./texts/dictionary.txt"));
const finallys = words.finallyCreator(dictionary);

const prog = wow.progCreator(config.wow.homeRealm, config.wow.api.key);
const wowT = wow.tokenCreator(config.wow.api.token);

const gameData = JSON.parse(fs.readFileSync("./data/game_data.json").toString("utf-8"));
const g = new game(gameData, (data) => {
  fs.writeFileSync("./data/game_data.json", JSON.stringify(data));
});
setInterval(() => {
  g.save();
}, 1000 * 60 * 30); //save every 30 minutes

const gameCommands = gameChat.gameCommandCreator(g);

//TODO load leaderboard archive
const enchantmentDB = new book.Book("./texts/enchantments.json", ["int", "aug", "aff", "0", "1", "2", "3"]);
const ench = book.enchantmentCreator(enchantmentDB);

const cmds = {
  /**@param {Array} args
   * @param {Function} send
   * **/
  "ping": (args, send) => {
    return send("pong");
  },
  "whois": whois,
  "joke": joke,
  "grave": grave,
  "priceof": priceOf,
  "finally": finallys,
  "ench": ench,
  "game": gameCommands,
  "prog": prog,
  "token": wowT,
  "mtg": mtg.mtgCardImage,
  "mtgsets": mtg.mtgSets,
  "hp": dnd.hpCommand
};

//Enable reading from stdin
process.stdin.setEncoding("utf8");
const consoleCommands = {
  "reload": () => {
    //TODO call reload functions on all modules
    return "Reloaded.";
  },
  "test": () => {

  },
  "stop": () => {
    //call game module to save it
    g.save();
    process.exit(0);
    return "Stopping";
  }
};
process.stdin.on("data", (text) => {
  text = text.replace(/[\n\r\t]/g, "").replace(/ {2+}/g, " ");
  let args = text.split(" ");
  let command = args[0].toLowerCase();
  let echoed;
  if (consoleCommands.hasOwnProperty(command) === true) {
    echoed = consoleCommands[command](...args);
    console.log(echoed);
  } else {
    console.log("Unknown command. Type `help` for help.");
  }
});

//Event listener to trigger when bot starts
client.on("ready", () => {
  console.log("Connected and initialized.");
});

function serverSelector(serverID) {
  let ret = {
    atg: false,
    frz: false,
    rao: false,
    dnd: false
  };
  if (serverID === "167586953061990400") { //RAOCSGO
    ret.rao = true;
  } else if (serverID === "276220128822165505") { //AtG
    ret.atg = true;
  } else if (serverID === "234382619767341056") { //r/Frozen
    ret.frz = true;
  } else if (serverID === "446813545049358336") { //D&D
    ret.dnd = true;
  } else if (serverID === "313169519545679872" || !serverID) { //nass and dmchannel
    ret.atg = true;
    ret.frz = true;
    ret.rao = true;
    ret.dnd = true;
  }
  return ret;
}

//Main event listener for messages
client.on("message", (message) => {

  if (message.author.bot === true) return;

  let loc = message.channel;
  let msg = message.content;

  //send helper functions
  let send = function (text, opts) {
    loc.send(text, opts).catch((err) => {
      console.log(err);
    });
  };
  let sendImg = function (text, img) {
    if (img) {
      send(text, {
        embed: new Discord.RichEmbed().setImage(img)
      });
    } else {
      send(text);
    }
  };

  let server;
  if (loc.guild) {
    server = loc.guild.id;
  }

  for (let command in cmds) {
    if (cmds.hasOwnProperty(command)) {
      if (utils.hascmd(msg, command) || msg === "!" + command) {
        let args = utils.argify(msg, command);
        cmds[command](args, send, serverSelector(server), message.author, sendImg, message.mentions);
      }
    }
  }
  //Special Cases
  if (msg.substring(0, "who is ".length).toLowerCase() === "who is ") {
    let name = msg.substring("who is ".length);
    cmds["whois"](name.split(" "), send, serverSelector(server), message.author, sendImg, message.mentions);
  }
  if (message.channel.name === "botstuff" || message.channel.name === "game") {
    if (msg.substring(0, "g ".length).toLowerCase() === "g ") {
      let args = msg.substring("g ".length);
      cmds["game"](args.split(" "), send, serverSelector(server), message.author, sendImg, message.mentions);
    }
  }

});

client.login(config.discord.key);

<|endoftext|>


<commit_before>/**
 * Bot
 *
 * Credits
 * CreaturePhil - Lead Development (https://github.com/CreaturePhil)
 * TalkTakesTime - Parser (https://github.com/TalkTakesTime)
 *
 * @license MIT license
 */

var config = exports.config = {
    name: 'Booty-Bot',
    userid: function () {
        return toId(this.name);
    },
    group: '@',
    join: true,
    rooms: ['lobby'],
    punishvals: {
        1: 'warn',
        2: 'mute',
        3: 'hourmute',
        4: 'roomban',
        5: 'ban'
    },
    privaterooms: ['staff']
};

/**
 * On server start, this sets up fake user connection for bot and uses a fake ip.
 * It gets a the fake user from the users list and modifies it properties. In addition,
 * it sets up rooms that bot will join and adding the bot user to Users list and
 * removing the fake user created which already filled its purpose
 * of easily filling  in the gaps of all the user's property.
 */

function joinServer() {
    if (process.uptime() > 5) return; // to avoid running this function again when reloading
    var worker = new(require('./fake-process.js').FakeProcess)();
    Users.socketConnect(worker.server, undefined, '1', '76.19.156.198');

    for (var i in Users.users) {
        if (Users.users[i].connections[0].ip === '76.19.156.198') {

            var bot = Users.users[i];

            bot.name = config.name;
            bot.named = true;
            bot.renamePending = config.name;
            bot.authenticated = true;
            bot.userid = config.userid();
            bot.group = config.group;

            if (config.join === true) {
                for (var all in Rooms.rooms) {
                    if (all != 'global') {
                        bot.roomCount[all] = 1;
                    }
                }
                Users.users[bot.userid] = bot;
                for (var allRoom in Rooms.rooms) {
                    if (allRoom != 'global') {
                        Rooms.rooms[allRoom].users[Users.users[bot.userid]] = Users.users[bot.userid];
                    }
                }
            } else {
                for (var index in config.rooms) {
                    if (index != 'global') {
                        bot.roomCount[joinRooms[index]] = 1;
                    }
                }
                Users.users[bot.userid] = bot;
                for (var jIndex in config.rooms) {
                    if (jIndex != 'global') {
                        Rooms.rooms[jIndex].users[Users.users[bot.userid]] = Users.users[bot.userid];
                    }
                }
            }
            delete Users.users[i];
        }
    }
}

exports.joinServer = joinServer;

joinServer();

const ACTION_COOLDOWN = 3 * 1000;
const FLOOD_MESSAGE_NUM = 5;
const FLOOD_PER_MSG_MIN = 500; // this is the minimum time between messages for legitimate spam. It's used to determine what "flooding" is caused by lag
const FLOOD_MESSAGE_TIME = 6 * 1000;
const MIN_CAPS_LENGTH = 18;
const MIN_CAPS_PROPORTION = 0.8;

var parse = exports.parse = {

    chatData: {},

    processChatData: function (user, room, connection, message) {
        if (user.userid === config.userid()) return;
        var cmd = this.processBotCommands(user, room, connection, message);
        if (cmd) return false;

        message = message.trim().replace(/ +/g, " "); // removes extra spaces so it doesn't trigger stretching
        this.updateSeen(user.userid, 'c', room.title);
        var time = Date.now();
        if (!this.chatData[user]) this.chatData[user] = {
            zeroTol: 0,
            lastSeen: '',
            seenAt: time
        };
        if (!this.chatData[user][room]) this.chatData[user][room] = {
            times: [],
            points: 0,
            lastAction: 0
        };

        this.chatData[user][room].times.push(time);

        var pointVal = 0;
        var muteMessage = '';

        // moderation for flooding (more than x lines in y seconds)
        var isFlooding = (this.chatData[user][room].times.length >= FLOOD_MESSAGE_NUM && (time - this.chatData[user][room].times[this.chatData[user][room].times.length - FLOOD_MESSAGE_NUM]) < FLOOD_MESSAGE_TIME && (time - this.chatData[user][room].times[this.chatData[user][room].times.length - FLOOD_MESSAGE_NUM]) > (FLOOD_PER_MSG_MIN * FLOOD_MESSAGE_NUM));
        if (isFlooding) {
            if (pointVal < 2) {
                pointVal = 2;
                muteMessage = ', flooding';
            }
        }
        // moderation for caps (over x% of the letters in a line of y characters are capital)
        var capsMatch = message.replace(/[^A-Za-z]/g, '').match(/[A-Z]/g);
        if (capsMatch && toId(message).length > MIN_CAPS_LENGTH && (capsMatch.length >= Math.floor(toId(message).length * MIN_CAPS_PROPORTION))) {
            if (pointVal < 1) {
                pointVal = 1;
                muteMessage = ', caps';
            }
        }
        // moderation for stretching (over x consecutive characters in the message are the same)
        var stretchMatch = message.toLowerCase().match(/(.)\1{7,}/g) || message.toLowerCase().match(/(..+)\1{4,}/g); // matches the same character (or group of characters) 8 (or 5) or more times in a row
        if (stretchMatch) {
            if (pointVal < 1) {
                pointVal = 1;
                muteMessage = ', stretching';
            }
        }
        if (pointVal > 0 && !(time - this.chatData[user][room].lastAction < ACTION_COOLDOWN)) {
            var cmd = 'mute';
            // defaults to the next punishment in config.punishVals instead of repeating the same action (so a second warn-worthy
            // offence would result in a mute instead of a warn, and the third an hourmute, etc)
            if (this.chatData[user][room].points >= pointVal && pointVal < 4) {
                this.chatData[user][room].points++;
                cmd = config.punishvals[this.chatData[user][room].points] || cmd;
            } else { // if the action hasn't been done before (is worth more points) it will be the one picked
                cmd = config.punishvals[pointVal] || cmd;
                this.chatData[user][room].points = pointVal; // next action will be one level higher than this one (in most cases)
            }
            if (config.privaterooms.indexOf(room) >= 0 && cmd === 'warn') cmd = 'mute'; // can't warn in private rooms
            // if the bot has % and not @, it will default to hourmuting as its highest level of punishment instead of roombanning
            if (this.chatData[user][room].points >= 4 && config.group === '%') cmd = 'hourmute';
            if (this.chatData[user].zeroTol > 4) { // if zero tolerance users break a rule they get an instant roomban or hourmute
                muteMessage = ', zero tolerance user';
                cmd = config.group !== '%' ? 'roomban' : 'hourmute';
            }
            if (this.chatData[user][room].points >= 2) this.chatData[user].zeroTol++; // getting muted or higher increases your zero tolerance level (warns do not)
            this.chatData[user][room].lastAction = time;
            room.add('|c|' + user.group + user.name + '|' + message);
            CommandParser.parse(('/' + cmd + ' ' + user.userid + muteMessage), room, Users.get(config.name), Users.get(config.name).connections[0]);
            return false;
        }

        return true;
    },

    updateSeen: function (user, type, detail) {
        user = toId(user);
        type = toId(type);
        if (type in {j: 1, l: 1, c: 1} && (config.rooms.indexOf(toId(detail)) === -1 || config.privaterooms.indexOf(toId(detail)) > -1)) return;
        var time = Date.now();
        if (!this.chatData[user]) this.chatData[user] = {
            zeroTol: 0,
            lastSeen: '',
            seenAt: time
        };
        if (!detail) return;
        var msg = '';
        if (type in {j: 1, l: 1, c: 1}) {
            msg += (type === 'j' ? 'joining' : (type === 'l' ? 'leaving' : 'chatting in')) + ' ' + detail.trim() + '.';
        } else if (type === 'n') {
            msg += 'changing nick to ' + ('+%@&#~'.indexOf(detail.trim().charAt(0)) === -1 ? detail.trim() : detail.trim().substr(1)) + '.';
        }
        if (msg) {
            this.chatData[user].lastSeen = msg;
            this.chatData[user].seenAt = time;
        }
    },

    processBotCommands: function (user, room, connection, message) {
        var cmd = '',
            target = '',
            spaceIndex = message.indexOf(' '),
            botDelay = (Math.floor(Math.random() * 6) * 1000);

        var now = Date.now();

        if ((now - user.lastBotCmd) * 0.001 < 30) {
            user.send('Please wait ' + Math.floor((30 - (now - user.lastBotCmd) * 0.001)) + ' seconds until the next command.');
            return true;
        }

        user.lastBotCmd = now;

        if (message.charAt(0) === '!') {
            if (spaceIndex > 0) {
                cmd = message.substr(1, spaceIndex - 1);
                target = message.substr(spaceIndex + 1);
            } else {
                cmd = message.substr(1);
                target = '';
            }
        }

        if (commands[cmd]) {
            var context = {
                sendReply: function (data) {
                    setTimeout(function () {
                        room.add('|c|' + config.group + config.name + '|' + data);
                    }, botDelay);
                },
                sendPm: function (data) {
                    var message = '|pm|' + config.group + config.name + '|' + user.group + user.name + '|' + data;
                    user.send(message);
                },
            };

            if (typeof commands[cmd] === 'function') {
                commands[cmd].call(context, target, room, user, connection, cmd, message);
            }
        }
    },

    getTimeAgo: function (time) {
        time = Date.now() - time;
        time = Math.round(time / 1000); // rounds to nearest second
        var seconds = time % 60;
        var times = [];
        if (seconds) times.push(String(seconds) + (seconds === 1 ? ' second' : ' seconds'));
        var minutes, hours, days;
        if (time >= 60) {
            time = (time - seconds) / 60; // converts to minutes
            minutes = time % 60;
            if (minutes) times = [String(minutes) + (minutes === 1 ? ' minute' : ' minutes')].concat(times);
            if (time >= 60) {
                time = (time - minutes) / 60; // converts to hours
                hours = time % 24;
                if (hours) times = [String(hours) + (hours === 1 ? ' hour' : ' hours')].concat(times);
                if (time >= 24) {
                    days = (time - hours) / 24; // you can probably guess this one
                    if (days) times = [String(days) + (days === 1 ? ' day' : ' days')].concat(times);
                }
            }
        }
        if (!times.length) times.push('0 seconds');
        return times.join(', ');
    },

};

var commands = exports.commands = {

    guide: function (target, room, user) {
        var commands = Object.keys(Bot.commands);
        commands = commands.join(', ').toString();

        this.sendReply('List of bot commands: ' + commands);
    },

    penislength: function (target, room, user) {
        this.sendReply('8.5 inches from the base. Perv.');
    },

    seen: function (target, room, user) {
        if (!target) return;
        if (toId(target) === config.userid()) return this.sendPm('I\'m right here.');
        if (!parse.chatData[toId(target)] || !parse.chatData[toId(target)].lastSeen) {
            return this.sendPm('The user ' + target.trim() + ' has never been seen.');
        }
        return this.sendPm(target.trim() + ' was last seen ' + parse.getTimeAgo(parse.chatData[toId(target)].seenAt) + ' ago, ' + parse.chatData[toId(target)].lastSeen);
    },

    salt: function (target, room, user) {
        if (!global.salt) global.salt = 0;
        salt++;
        this.sendReply(salt + '% salty.');
    },

    who: (function () {
        var reply = [
            "Just another Pokemon Showdown user",
            "A very good competetive pokemon player",
            "A worthy opponent",
            "Generally, a bad user",
            "Generally, a good user",
            "Someone who is better than you",
            "An amazing person",
            "A beautiful person",
            "A person who is probably still a virgin",
            "A leader",
            "A lord helix follower",
            "An annoying person",
            "A person with a salty personality",
            "A Coffee Addict",
            "A Mediocre Player",
        ];

        return function (target, room, user) {
            if (!target) return;
            var message = reply[Math.floor(Math.random() * reply.length)];

            target = toId(target);

            if (target === 'creaturephil') message = 'An experienced **coder** for pokemon showdown. He has coded for over 5 servers such as kill the noise, moxie, aerdeith, nova, etc. Please follow him on github: https://github.com/CreaturePhil';
            if (target === config.userid()) message = 'That\'s me.';
            if (target === 'zarel') message = 'Pokemon Showdown Creator';

            this.sendReply(message);
        };
    })(),

    helix: (function () {
        var reply = [
            "Signs point to yes.",
            "Yes.",
            "Reply hazy, try again.",
            "Without a doubt.",
            "My sources say no.",
            "As I see it, yes.",
            "You may rely on it.",
            "Concentrate and ask again.",
            "Outlook not so good.",
            "It is decidedly so.",
            "Better not tell you now.",
            "Very doubtful.",
            "Yes - definitely.",
            "It is certain.",
            "Cannot predict now.",
            "Most likely.",
            "Ask again later.",
            "My reply is no.",
            "Outlook good.",
            "Don't count on it."
        ];

        return function (target, room, user) {
            if (!target) return;
            var message = reply[Math.floor(Math.random() * reply.length)];

            this.sendPm(message);
        };
    })(),

};<commit_msg>Fix bot command delay and add more cmds<commit_after>/**
 * Bot
 *
 * Credits
 * CreaturePhil - Lead Development (https://github.com/CreaturePhil)
 * TalkTakesTime - Parser (https://github.com/TalkTakesTime)
 *
 * @license MIT license
 */

var config = exports.config = {
    name: 'Booty-Bot',
    userid: function () {
        return toId(this.name);
    },
    group: '@',
    join: true,
    rooms: ['lobby'],
    punishvals: {
        1: 'warn',
        2: 'mute',
        3: 'hourmute',
        4: 'roomban',
        5: 'ban'
    },
    privaterooms: ['staff']
};

/**
 * On server start, this sets up fake user connection for bot and uses a fake ip.
 * It gets a the fake user from the users list and modifies it properties. In addition,
 * it sets up rooms that bot will join and adding the bot user to Users list and
 * removing the fake user created which already filled its purpose
 * of easily filling  in the gaps of all the user's property.
 */

function joinServer() {
    if (process.uptime() > 5) return; // to avoid running this function again when reloading
    var worker = new(require('./fake-process.js').FakeProcess)();
    Users.socketConnect(worker.server, undefined, '1', '76.19.156.198');

    for (var i in Users.users) {
        if (Users.users[i].connections[0].ip === '76.19.156.198') {

            var bot = Users.users[i];

            bot.name = config.name;
            bot.named = true;
            bot.renamePending = config.name;
            bot.authenticated = true;
            bot.userid = config.userid();
            bot.group = config.group;

            if (config.join === true) {
                for (var all in Rooms.rooms) {
                    if (all != 'global') {
                        bot.roomCount[all] = 1;
                    }
                }
                Users.users[bot.userid] = bot;
                for (var allRoom in Rooms.rooms) {
                    if (allRoom != 'global') {
                        Rooms.rooms[allRoom].users[Users.users[bot.userid]] = Users.users[bot.userid];
                    }
                }
            } else {
                for (var index in config.rooms) {
                    if (index != 'global') {
                        bot.roomCount[joinRooms[index]] = 1;
                    }
                }
                Users.users[bot.userid] = bot;
                for (var jIndex in config.rooms) {
                    if (jIndex != 'global') {
                        Rooms.rooms[jIndex].users[Users.users[bot.userid]] = Users.users[bot.userid];
                    }
                }
            }
            delete Users.users[i];
        }
    }
}

exports.joinServer = joinServer;

joinServer();

const ACTION_COOLDOWN = 3 * 1000;
const FLOOD_MESSAGE_NUM = 5;
const FLOOD_PER_MSG_MIN = 500; // this is the minimum time between messages for legitimate spam. It's used to determine what "flooding" is caused by lag
const FLOOD_MESSAGE_TIME = 6 * 1000;
const MIN_CAPS_LENGTH = 18;
const MIN_CAPS_PROPORTION = 0.8;

var parse = exports.parse = {

    chatData: {},

    processChatData: function (user, room, connection, message) {
        if (user.userid === config.userid()) return;
        var cmd = this.processBotCommands(user, room, connection, message);
        if (cmd) return false;

        message = message.trim().replace(/ +/g, " "); // removes extra spaces so it doesn't trigger stretching
        this.updateSeen(user.userid, 'c', room.title);
        var time = Date.now();
        if (!this.chatData[user]) this.chatData[user] = {
            zeroTol: 0,
            lastSeen: '',
            seenAt: time
        };
        if (!this.chatData[user][room]) this.chatData[user][room] = {
            times: [],
            points: 0,
            lastAction: 0
        };

        this.chatData[user][room].times.push(time);

        var pointVal = 0;
        var muteMessage = '';

        // moderation for flooding (more than x lines in y seconds)
        var isFlooding = (this.chatData[user][room].times.length >= FLOOD_MESSAGE_NUM && (time - this.chatData[user][room].times[this.chatData[user][room].times.length - FLOOD_MESSAGE_NUM]) < FLOOD_MESSAGE_TIME && (time - this.chatData[user][room].times[this.chatData[user][room].times.length - FLOOD_MESSAGE_NUM]) > (FLOOD_PER_MSG_MIN * FLOOD_MESSAGE_NUM));
        if (isFlooding) {
            if (pointVal < 2) {
                pointVal = 2;
                muteMessage = ', flooding';
            }
        }
        // moderation for caps (over x% of the letters in a line of y characters are capital)
        var capsMatch = message.replace(/[^A-Za-z]/g, '').match(/[A-Z]/g);
        if (capsMatch && toId(message).length > MIN_CAPS_LENGTH && (capsMatch.length >= Math.floor(toId(message).length * MIN_CAPS_PROPORTION))) {
            if (pointVal < 1) {
                pointVal = 1;
                muteMessage = ', caps';
            }
        }
        // moderation for stretching (over x consecutive characters in the message are the same)
        var stretchMatch = message.toLowerCase().match(/(.)\1{7,}/g) || message.toLowerCase().match(/(..+)\1{4,}/g); // matches the same character (or group of characters) 8 (or 5) or more times in a row
        if (stretchMatch) {
            if (pointVal < 1) {
                pointVal = 1;
                muteMessage = ', stretching';
            }
        }
        if (pointVal > 0 && !(time - this.chatData[user][room].lastAction < ACTION_COOLDOWN)) {
            var cmd = 'mute';
            // defaults to the next punishment in config.punishVals instead of repeating the same action (so a second warn-worthy
            // offence would result in a mute instead of a warn, and the third an hourmute, etc)
            if (this.chatData[user][room].points >= pointVal && pointVal < 4) {
                this.chatData[user][room].points++;
                cmd = config.punishvals[this.chatData[user][room].points] || cmd;
            } else { // if the action hasn't been done before (is worth more points) it will be the one picked
                cmd = config.punishvals[pointVal] || cmd;
                this.chatData[user][room].points = pointVal; // next action will be one level higher than this one (in most cases)
            }
            if (config.privaterooms.indexOf(room) >= 0 && cmd === 'warn') cmd = 'mute'; // can't warn in private rooms
            // if the bot has % and not @, it will default to hourmuting as its highest level of punishment instead of roombanning
            if (this.chatData[user][room].points >= 4 && config.group === '%') cmd = 'hourmute';
            if (this.chatData[user].zeroTol > 4) { // if zero tolerance users break a rule they get an instant roomban or hourmute
                muteMessage = ', zero tolerance user';
                cmd = config.group !== '%' ? 'roomban' : 'hourmute';
            }
            if (this.chatData[user][room].points >= 2) this.chatData[user].zeroTol++; // getting muted or higher increases your zero tolerance level (warns do not)
            this.chatData[user][room].lastAction = time;
            room.add('|c|' + user.group + user.name + '|' + message);
            CommandParser.parse(('/' + cmd + ' ' + user.userid + muteMessage), room, Users.get(config.name), Users.get(config.name).connections[0]);
            return false;
        }

        return true;
    },

    updateSeen: function (user, type, detail) {
        user = toId(user);
        type = toId(type);
        if (type in {j: 1, l: 1, c: 1} && (config.rooms.indexOf(toId(detail)) === -1 || config.privaterooms.indexOf(toId(detail)) > -1)) return;
        var time = Date.now();
        if (!this.chatData[user]) this.chatData[user] = {
            zeroTol: 0,
            lastSeen: '',
            seenAt: time
        };
        if (!detail) return;
        var msg = '';
        if (type in {j: 1, l: 1, c: 1}) {
            msg += (type === 'j' ? 'joining' : (type === 'l' ? 'leaving' : 'chatting in')) + ' ' + detail.trim() + '.';
        } else if (type === 'n') {
            msg += 'changing nick to ' + ('+%@&#~'.indexOf(detail.trim().charAt(0)) === -1 ? detail.trim() : detail.trim().substr(1)) + '.';
        }
        if (msg) {
            this.chatData[user].lastSeen = msg;
            this.chatData[user].seenAt = time;
        }
    },

    processBotCommands: function (user, room, connection, message) {
        var cmd = '',
            target = '',
            spaceIndex = message.indexOf(' '),
            botDelay = (Math.floor(Math.random() * 6) * 1000);

        var now = Date.now();

        if (message.charAt(0) === '!') {

            if ((now - user.lastBotCmd) * 0.001 < 30) {
                user.send('Please wait ' + Math.floor((30 - (now - user.lastBotCmd) * 0.001)) + ' seconds until the next command.');
                return true;
            }

            user.lastBotCmd = now;

            if (spaceIndex > 0) {
                cmd = message.substr(1, spaceIndex - 1);
                target = message.substr(spaceIndex + 1);
            } else {
                cmd = message.substr(1);
                target = '';
            }
        }

        if (commands[cmd]) {
            var context = {
                sendReply: function (data) {
                    setTimeout(function () {
                        room.add('|c|' + config.group + config.name + '|' + data);
                    }, botDelay);
                },
                sendPm: function (data) {
                    var message = '|pm|' + config.group + config.name + '|' + user.group + user.name + '|' + data;
                    user.send(message);
                },
                can: function (permission, target, room) {
                    if (!user.can(permission, target, room)) {
                        setTimeout(function () { user.send("!" + cmd + " - Access denied.") }, botDelay);
                        return false;
                    }
                    return true;
                },
            };

            if (typeof commands[cmd] === 'function') {
                commands[cmd].call(context, target, room, user, connection, cmd, message);
            }
        }
    },

    getTimeAgo: function (time) {
        time = Date.now() - time;
        time = Math.round(time / 1000); // rounds to nearest second
        var seconds = time % 60;
        var times = [];
        if (seconds) times.push(String(seconds) + (seconds === 1 ? ' second' : ' seconds'));
        var minutes, hours, days;
        if (time >= 60) {
            time = (time - seconds) / 60; // converts to minutes
            minutes = time % 60;
            if (minutes) times = [String(minutes) + (minutes === 1 ? ' minute' : ' minutes')].concat(times);
            if (time >= 60) {
                time = (time - minutes) / 60; // converts to hours
                hours = time % 24;
                if (hours) times = [String(hours) + (hours === 1 ? ' hour' : ' hours')].concat(times);
                if (time >= 24) {
                    days = (time - hours) / 24; // you can probably guess this one
                    if (days) times = [String(days) + (days === 1 ? ' day' : ' days')].concat(times);
                }
            }
        }
        if (!times.length) times.push('0 seconds');
        return times.join(', ');
    },

};

var commands = exports.commands = {

    guide: function (target, room, user) {
        var commands = Object.keys(Bot.commands);
        commands = commands.join(', ').toString();

        this.sendReply('List of bot commands: ' + commands);
    },

    say: function (target, room, user) {
        if (!this.can('say')) return;
        this.sendReply(target);
    },

    bottell: function (target, room, user) {
         if (!this.can('bottell')) return;
         var parts = target.split(',');
         if (parts.length < 2) return;
         CommandParser.parse('/tell ' + toId(parts[0]) + ', ' + Tools.escapeHTML(parts[1]), room, Users.get(Bot.config.name), Users.get(Bot.config.name).connections[0]);
    },

    penislength: function (target, room, user) {
        this.sendReply('8.5 inches from the base. Perv.');
    },

    seen: function (target, room, user) {
        if (!target) return;
        if (toId(target) === config.userid()) return this.sendPm('I\'m right here.');
        if (!parse.chatData[toId(target)] || !parse.chatData[toId(target)].lastSeen) {
            return this.sendPm('The user ' + target.trim() + ' has never been seen.');
        }
        return this.sendPm(target.trim() + ' was last seen ' + parse.getTimeAgo(parse.chatData[toId(target)].seenAt) + ' ago, ' + parse.chatData[toId(target)].lastSeen);
    },

    salt: function (target, room, user) {
        if (!global.salt) global.salt = 0;
        salt++;
        this.sendReply(salt + '% salty.');
    },

    who: (function () {
        var reply = [
            "Just another Pokemon Showdown user",
            "A very good competetive pokemon player",
            "A worthy opponent",
            "Generally, a bad user",
            "Generally, a good user",
            "Someone who is better than you",
            "An amazing person",
            "A beautiful person",
            "A person who is probably still a virgin",
            "A leader",
            "A lord helix follower",
            "An annoying person",
            "A person with a salty personality",
            "A Coffee Addict",
            "A Mediocre Player",
        ];

        return function (target, room, user) {
            if (!target) return;
            var message = reply[Math.floor(Math.random() * reply.length)];

            target = toId(target);

            if (target === 'creaturephil') message = 'An experienced **coder** for pokemon showdown. He has coded for over 5 servers such as kill the noise, moxie, aerdeith, nova, etc. Please follow him on github: https://github.com/CreaturePhil';
            if (target === config.userid()) message = 'That\'s me.';
            if (target === 'zarel') message = 'Pokemon Showdown Creator';

            this.sendReply(message);
        };
    })(),

    helix: (function () {
        var reply = [
            "Signs point to yes.",
            "Yes.",
            "Reply hazy, try again.",
            "Without a doubt.",
            "My sources say no.",
            "As I see it, yes.",
            "You may rely on it.",
            "Concentrate and ask again.",
            "Outlook not so good.",
            "It is decidedly so.",
            "Better not tell you now.",
            "Very doubtful.",
            "Yes - definitely.",
            "It is certain.",
            "Cannot predict now.",
            "Most likely.",
            "Ask again later.",
            "My reply is no.",
            "Outlook good.",
            "Don't count on it."
        ];

        return function (target, room, user) {
            if (!target) return;
            var message = reply[Math.floor(Math.random() * reply.length)];

            this.sendPm(message);
        };
    })(),

};<|endoftext|>


<commit_before>import BABYLON from 'babylonjs';
import {EventSubscriptionContext} from '../../event-util';
import {Buttons} from '../input';
import testPower from './powers/testPower';
import testPower2 from './powers/testPower2';
import testPower3 from './powers/testPower3';
import testPower4 from './powers/testPower4';

const zeroVector2 = new BABYLON.Vector2(0, 0);
const maxMana = 5000000;

export default class Hero {
  constructor(
    game, name, meshFileName='omi', speed=20, airSpeed=5, jumpStrength=150, rollGroundSpeed=30, rollAirSpeed=20,
    attack1=testPower, attack2=testPower4, attack3=testPower3, attack4=testPower,
    defense1=testPower, defense2=testPower, defense3=testPower, defense4=testPower){
    this.game = game;
    this.name = name;
    this._mana = maxMana;
    this._joyTarget = this;

    // Get physics impostor ready
    this.initCollider();

    require(`../../../models/heroes/${meshFileName}.blend`).ImportMesh(BABYLON.SceneLoader, null, this.game.scene, loadedMeshes => {
        // Add the mesh
        this.mesh = loadedMeshes[0];//.clone(this.name); // 2 is the index of the player mesh
        // console.log("the player mesh", this.mesh);
        this.mesh.isVisible = true;
        this.mesh.id = this.name;
        this.mesh.parent = this.mask;
        this.mesh.position.y = -3  + 1.9;
        this.mesh.position.z = .6;
        // Add the player mesh to the shadowGenerator
        this.game.shadowGenerator.getShadowMap().renderList.push(this.mesh);
        this.mesh.receiveShadows = true;
        // Add material for debug
        var material = new BABYLON.StandardMaterial("blue_material", game.scene);
        material.diffuseColor = BABYLON.Color3.Blue();
        this.mesh.material = material;

        this.initAnimations();
    });

    // Movement variables
    this.onGround = false;
    this.jumpStrength = jumpStrength;
    this.jumpTimerStart = 20;
    this.jumpTimer = this.jumpTimerStart;
    this.rollTimerStart = 15;
    this.rollTimer = this.rollTimerStart;
    this.speed = speed;
    this.airSpeed = airSpeed;
    this.moveBool = true;
    this.rollGroundSpeed = rollGroundSpeed;
    this.rollAirSpeed = rollAirSpeed;

    // Input
    this.Input = {
      AXIS_X : 0,
      AXIS_Y : 0,
      JUMP : false,
      ROLL : false,
    };

    // InitializePowers
    this.attack1 = new attack1(game, this);
    this.attack2 = new attack2(game, this);
    this.attack3 = new attack3(game, this);
    this.attack4 = new attack4(game, this);

    this.defense1 = new defense1(game, this);
    this.defense2 = new defense2(game, this);
    this.defense3 = new defense3(game, this);
    this.defense4 = new defense4(game, this);

    // Add update loop to Babylon
    this.mesh.registerBeforeRender(() => {
        this.update();
    });
  }

  initAnimations () {
      //console.log('animation range', this.mesh.skeleton.getAnimationRange('run'));
      this.idleAnimation = this.mesh.skeleton.getAnimationRange('idle');
      this.walkAnimation = this.mesh.skeleton.getAnimationRange('walk');
      this.runAnimation = this.mesh.skeleton.getAnimationRange('run');
      this.jumpAnimation = this.mesh.skeleton.getAnimationRange('jump');
      this.powerAnimation = this.mesh.skeleton.getAnimationRange('ability');
      this.rollAnimation = this.mesh.skeleton.getAnimationRange('roll');
      this.rollingAnimation = this.mesh.skeleton.getAnimationRange('rolling');
      const animatable = this.game.scene.beginAnimation(this.mesh.skeleton, 0, 120, true, 2);
      setTimeout(() => {
          animatable.speedRatio /= 8;
      }, 4000);

      this.currentAnimation = null;
      this.currentAnimatable = null;

      this.animatePower = false;
  }

  startAnimationNew(animation, loop=true, blending=.1) {
      if (this.currentAnimation != animation) {
          this.startAnimation(animation, loop, blending);
      }
  }

  startAnimation (animation, loop=true, blending=.1) {
      this.currentAnimation = animation;
      this.currentAnimatable = this.game.scene.beginAnimation(this.mesh.skeleton, animation.from+1, animation.to, loop, 1);
      this.currentAnimatable.enableBlending(blending);
  }

  animations () {
        // walk animation
        var magnitude =
        Math.sqrt(this.body.velocity.x * this.body.velocity.x + this.body.velocity.z * this.body.velocity.z);
        if (this.rollTimer) {
                if (magnitude > 1) {
                    this.startAnimationNew(this.rollingAnimation, true, 10);
                    this.currentAnimatable.speedRatio = 2.6;
                } else {
                    this.startAnimationNew(this.rollAnimation, false);
                    this.currentAnimatable.speedRatio = 2;
                }
        } else if (this.onGround) {
            //console.log("mag: ", magnitude);
            if (magnitude < 1) {// Idle and power
                if (!this.animatePower) {
                    this.startAnimationNew(this.idleAnimation);
                } else {
                    this.startAnimationNew(this.powerAnimation, false);
                    this.currentAnimatable.speedRatio = 1.5;
                }
            } else if (magnitude < 5) { // Walk animation
                this.startAnimationNew(this.walkAnimation);
                this.currentAnimatable.speedRatio = .31 * magnitude;
            } else { // Run animation
                this.startAnimationNew(this.runAnimation);
                this.currentAnimatable.speedRatio = .9 + .02 * magnitude;
            }
      } else {
          this.startAnimationNew(this.jumpAnimation);
          this.currentAnimatable.speedRatio = .8;
      }
  }

  initCollider (width=2) {
    // Merges three spheres to create a capsule
    let detail = 10;

    // Create collision mask m0
    this.mask = this.createSphere('m0', detail, 2.5, 0, 4, .2, .2);

    // create collision mask m1
    this.mask1 = this.createSphere('m1', detail, 2.3, 1.9, 1, .05, .2);
    this.body1 = this.mask1.physicsImpostor.physicsBody;
    //this.body1.fixedRotation = true;
    this.mask1.parent = this.mask;
    this.addCollisionToGroup(this.body1);

    // Create collision mask m2
    this.mask2 = this.createSphere('m2', detail, 2, 1.9+1.7, 1, .05, .2);
    this.body2 = this.mask2.physicsImpostor.physicsBody;
    //this.body2.fixedRotation = true;
    this.addCollisionToGroup(this.body2);
    this.mask2.parent = this.mask;
    //this.body2.type = 2;
    this.mask.physicsImpostor.forceUpdate();
    this.body = this.mask.physicsImpostor.physicsBody;
    this.addCollisionToGroup(this.body);
    this.body.fixedRotation = true;

    this.body.linearDamping = .8;
    this.body.fixedRotation = true;
    this.body.sleepSpeedLimit = .1;
    this.body.updateMassProperties();

    // Testing
      /*
    this.mask2.position.y -= 5;
    this.mask.physicsImpostor.forceUpdate();
    this.body = this.mask.physicsImpostor.physicsBody;
      this.body.updateMassProperties();*/

    this.initGroundCheck();

    console.log('mask', this.mask);
    let visible = false;
    this.mask.isVisible = visible;
    this.mask1.isVisible = visible;
    this.mask2.isVisible = visible;

    this.mask.position.y = 20;

    console.log('body', this.mask.physicsImpostor.physicsBody);
  }

  createSphere (name, detail, size, posY, mass, friction, restitution) {
      // Make sphere mesh
      let sphere = BABYLON.Mesh.CreateSphere(name, detail, size, this.game.scene);
      // Set sphere position
      sphere.position.y += posY;
      sphere.computeWorldMatrix(true);
      // Create collision mask
      sphere.physicsImpostor = new BABYLON.PhysicsImpostor(sphere, BABYLON.PhysicsImpostor.SphereImpostor, {mass:mass, friction:friction, restitution:restitution}, this.game.scene);
      return sphere;
  }

  addCollisionToGroup (impostorBody) {
    impostorBody.collisionFilterGroup = this.game.collisionGroupNormal;
    impostorBody.collisionFilterMask = this.game.collisionGroupGround | this.game.collisionGroupNormal | this.game.collisionGroupFall;
  }

  initGroundCheck() {
    // Create mesh for onGround collision check
    this.groundCheck = BABYLON.Mesh.CreateBox("mask", 2.5, this.game.scene);
    this.groundCheck.isVisible = false;
    this.groundCheck.parent = this.mask;
    this.groundCheck.position.y = -3 + 1.9;
    this.groundCheck.scaling.y = 0.2;
  }

  checkGroundCheck() {
    //TODO: http://schteppe.github.io/cannon.js/examples/threejs_voxel_fps.html use this jump check logic
    // Check for ground
    var jumpableMeshes = this.game.scene.getMeshesByTags("checkJump")
    this.onGround = false;
    for (var i in jumpableMeshes) {
      if (this.groundCheck.intersectsMesh(jumpableMeshes[i], true)){
        this.mesh.material.diffuseColor = new BABYLON.Color3.Red();
        this.onGround = true;
      }
    }
  }

  update () {
    this.checkGroundCheck();

    if (this.moveBool) {
        this.move();
    }

    this.animations();

    this._manageMana();
  }

  // use this to make xbox controller movement is smoove and doesn't go over the speed limit
  getScaleSpeed (movementVector, speed) {
      //console.log('movementvector strength:', movementVector.length());
      return speed * Math.min(1, movementVector.length());
  }

  move () {
    // get normalized vector
    var movementVector = new BABYLON.Vector3(this.Input.AXIS_X,0,this.Input.AXIS_Y);
      //console.log('xbox move:', this.Input.AXIS_X, ', ', this.Input.AXIS_Y, ', scaleSpeed:', Math.min(1, movementVector.length()));
    var normalizedMovementVector = movementVector.clone().normalize();
    //console.log('scale speed:', this.getScaleSpeed(movementVector, this.speed));

    // Rolling is very important
    if (this.Input.ROLL && this.rollTimer == 0) {
        this.rollTimer = this.rollTimerStart;

    } else if (this.rollTimer > 0) {
        this.rollTimer--;
        // Slow the movement after rolling is done
        if (this.rollTimer == 0) {
            let slowDown = -6;
            this.mask.applyImpulse(new BABYLON.Vector3(slowDown * this.body.velocity.x, slowDown * this.body.velocity.y, slowDown * this.body.velocity.z), this.mask.position);
        }
    }
    this.Input.ROLL = false;
    //console.log(this.rollTimer);

    // Movement on ground
    if (this.onGround) {
        movementVector = normalizedMovementVector.scale(this.getScaleSpeed(movementVector, this.rollTimer? this.rollGroundSpeed:this.speed));
    } else { // Movement in air
        movementVector = normalizedMovementVector.scale(this.getScaleSpeed(movementVector, this.rollTimer? this.rollAirSpeed:this.airSpeed));
        if (this.body.velocity.y < 1) {
            movementVector = movementVector.add(new BABYLON.Vector3(0,-5,0));
        }
        if (this.rollTimer) {
            movementVector = movementVector.add(new BABYLON.Vector3(0, -5,0 ));
        }
    }

    // Jump
    if (this.onGround && this.Input.JUMP && this.jumpTimer == 0) {
        //console.log("jump!");
        movementVector = movementVector.add(new BABYLON.Vector3(0,this.jumpStrength,0));
        this.mesh.material.diffuseColor = BABYLON.Color3.Blue();
        this.jumpTimer = this.jumpTimerStart;
    } else if (this.jumpTimer > 0) {
        this.jumpTimer--;
    }
    this.Input.JUMP = false;

    // apply movement at the very end.
    //console.log('ONGROUND:', this.onGround);
    this.mask.applyImpulse(movementVector, this.mask.position);

    if (this.body.velocity.length() > 1 && (this.Input.AXIS_X || this.Input.AXIS_Y) ) {
        this.setRotation();
    }
  }

  setRotation () {
    // Player rotation
    this.mask.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(Math.atan2(this.body.velocity.x, this.body.velocity.z), 0, 0);
  }

  setPlayer(player) {
    (this._inputSubscriptions || {destroy: () => {}}).destroy();
    if (!player) {
      return;
    }
    this._inputSubscriptions = new EventSubscriptionContext(player.input)
      .on('end', () => this.setPlayer())
      .on('joychanged', joyVector => this.handleJoyChanged(joyVector))
      .on('buttondown', button => this.handleButtonDown(button))
      .on('buttonup', button => this.handleButtonUp(button))
    ;
  }

  handleJoyChanged(joyVector) {
      this._joyTarget.joyChanged(joyVector);
  }

    /**
     * Allow the hero to act as a joy target. When this gets
     * called, that means that the hero itself should respond
     * to joy and, e.g., move.
     */
    joyChanged(joyVector) {
        this.Input.AXIS_Y = joyVector.y;
        this.Input.AXIS_X = joyVector.x;
    }

  _handleButton(button, pressed) {
    switch (button) {
    }
  }

  handleButtonDown(button) {
    this._handleButton(button, true);
    switch (button) {
        case Buttons.RB: this.Input.JUMP = true; break;
        case Buttons.LB: this.Input.ROLL = true; break;
        case Buttons.A: this.attack1.buttonDown(0); this.animatePower=true; break;
        case Buttons.B: this.attack2.buttonDown(0); this.animatePower=true; break;
        case Buttons.X: this.attack3.buttonDown(0); this.animatePower=true; break;
        case Buttons.Y: this.attack4.buttonDown(0); this.animatePower=true; break;
    }
  }

  handleButtonUp(button) {
    this._handleButton(button, false);
    switch (button) {
        case Buttons.A: this.attack1.buttonUp(0); this.animatePower=false; break;
        case Buttons.B: this.attack2.buttonUp(0); this.animatePower=false; break;
        case Buttons.X: this.attack3.buttonUp(0); this.animatePower=false; break;
        case Buttons.Y: this.attack4.buttonUp(0); this.animatePower=false; break;
    }
  }

    _manageMana() {
        if (this._mana < maxMana) {
            this._mana = Math.min(maxMana, this._mana + 1);
        }
    }

    /**
     * Returns false if there is insufficient mana.
     */
    consumeMana(amount) {
        if (this._mana < amount) {
            return false;
        }
        this._mana -= amount;
        return true;
    }

    /**
     * Sets the joy target. The joy target must have a joyChanged
     * function accepting a Vector2. If null the hero will start
     * responding to joy again.
     */
    setJoyTarget(target) {
        target = target || this;
        // Send 0 to original target to set it to rest or whatever
        // instead of leaving it stuck at other value. For existing,
        // will stop movement in the hero.
        this.handleJoyChanged(zeroVector2);
        this._joyTarget = target;
        // Emit 0 to help target with preinitializing itself.
        this.handleJoyChanged(zeroVector2);
    }
}
<commit_msg>cannot figure this idea out. I give up on it for now<commit_after>import BABYLON from 'babylonjs';
import {EventSubscriptionContext} from '../../event-util';
import {Buttons} from '../input';
import testPower from './powers/testPower';
import testPower2 from './powers/testPower2';
import testPower3 from './powers/testPower3';
import testPower4 from './powers/testPower4';

const zeroVector2 = new BABYLON.Vector2(0, 0);
const maxMana = 5000000;

export default class Hero {
  constructor(
    game, name, meshFileName='omi', speed=20, airSpeed=5, jumpStrength=150, rollGroundSpeed=30, rollAirSpeed=20,
    attack1=testPower, attack2=testPower4, attack3=testPower3, attack4=testPower,
    defense1=testPower, defense2=testPower, defense3=testPower, defense4=testPower){
    this.game = game;
    this.name = name;
    this._mana = maxMana;
    this._joyTarget = this;

    // Get physics impostor ready
    this.initCollider();

    require(`../../../models/heroes/${meshFileName}.blend`).ImportMesh(BABYLON.SceneLoader, null, this.game.scene, loadedMeshes => {
        // Add the mesh
        this.mesh = loadedMeshes[0];//.clone(this.name); // 2 is the index of the player mesh
        // console.log("the player mesh", this.mesh);
        this.mesh.isVisible = true;
        this.mesh.id = this.name;
        this.mesh.parent = this.mask;
        this.mesh.position.y = -3  + 1.9;
        this.mesh.position.z = .6;
        // Add the player mesh to the shadowGenerator
        this.game.shadowGenerator.getShadowMap().renderList.push(this.mesh);
        this.mesh.receiveShadows = true;
        // Add material for debug
        var material = new BABYLON.StandardMaterial("blue_material", game.scene);
        material.diffuseColor = BABYLON.Color3.Blue();
        this.mesh.material = material;

        this.initAnimations();
    });

    // Movement variables
    this.onGround = false;
    this.jumpStrength = jumpStrength;
    this.jumpTimerStart = 20;
    this.jumpTimer = this.jumpTimerStart;
    this.rollTimerStart = 15;
    this.rollTimer = this.rollTimerStart;
    this.speed = speed;
    this.airSpeed = airSpeed;
    this.moveBool = true;
    this.rollGroundSpeed = rollGroundSpeed;
    this.rollAirSpeed = rollAirSpeed;

    // Input
    this.Input = {
      AXIS_X : 0,
      AXIS_Y : 0,
      JUMP : false,
      ROLL : false,
    };

    // InitializePowers
    this.attack1 = new attack1(game, this);
    this.attack2 = new attack2(game, this);
    this.attack3 = new attack3(game, this);
    this.attack4 = new attack4(game, this);

    this.defense1 = new defense1(game, this);
    this.defense2 = new defense2(game, this);
    this.defense3 = new defense3(game, this);
    this.defense4 = new defense4(game, this);

    // Add update loop to Babylon
    this.mesh.registerBeforeRender(() => {
        this.update();
    });
  }

  initAnimations () {
      //console.log('animation range', this.mesh.skeleton.getAnimationRange('run'));
      this.idleAnimation = this.mesh.skeleton.getAnimationRange('idle');
      this.walkAnimation = this.mesh.skeleton.getAnimationRange('walk');
      this.runAnimation = this.mesh.skeleton.getAnimationRange('run');
      this.jumpAnimation = this.mesh.skeleton.getAnimationRange('jump');
      this.powerAnimation = this.mesh.skeleton.getAnimationRange('ability');
      this.rollAnimation = this.mesh.skeleton.getAnimationRange('roll');
      this.rollingAnimation = this.mesh.skeleton.getAnimationRange('rolling');
      const animatable = this.game.scene.beginAnimation(this.mesh.skeleton, 0, 120, true, 2);
      setTimeout(() => {
          animatable.speedRatio /= 8;
      }, 4000);

      this.currentAnimation = null;
      this.currentAnimatable = null;

      this.animatePower = false;
  }

  startAnimationNew(animation, loop=true, blending=.1) {
      if (this.currentAnimation != animation) {
          this.startAnimation(animation, loop, blending);
      }
  }

  startAnimation (animation, loop=true, blending=.1) {
      this.currentAnimation = animation;
      this.currentAnimatable = this.game.scene.beginAnimation(this.mesh.skeleton, animation.from+1, animation.to, loop, 1);
      this.currentAnimatable.enableBlending(blending);
  }

  animations () {
        // walk animation
        var magnitude =
        Math.sqrt(this.body.velocity.x * this.body.velocity.x + this.body.velocity.z * this.body.velocity.z);
        if (this.rollTimer) {
                if (magnitude > 1) {
                    this.startAnimationNew(this.rollingAnimation, true, 10);
                    this.currentAnimatable.speedRatio = 2.6;
                } else {
                    this.startAnimationNew(this.rollAnimation, false);
                    this.currentAnimatable.speedRatio = 2;
                }
        } else if (this.onGround) {
            //console.log("mag: ", magnitude);
            if (magnitude < 1) {// Idle and power
                if (!this.animatePower) {
                    this.startAnimationNew(this.idleAnimation);
                } else {
                    this.startAnimationNew(this.powerAnimation, false);
                    this.currentAnimatable.speedRatio = 1.5;
                }
            } else if (magnitude < 5) { // Walk animation
                this.startAnimationNew(this.walkAnimation);
                this.currentAnimatable.speedRatio = .31 * magnitude;
            } else { // Run animation
                this.startAnimationNew(this.runAnimation);
                this.currentAnimatable.speedRatio = .9 + .02 * magnitude;
            }
      } else {
          this.startAnimationNew(this.jumpAnimation);
          this.currentAnimatable.speedRatio = .8;
      }
  }

  initCollider (width=2) {
    // Merges three spheres to create a capsule
    const detail = 10;

    // Create collision mask m0
    this.mask = this.createSphere('m0', detail, 2.5, 0, 4, .2, .2);

    // create collision mask m1
    this.mask1 = this.createSphere('m1', detail, 2.3, 1.9, 1, .05, .2);
    this.body1 = this.mask1.physicsImpostor.physicsBody;
    //this.body1.fixedRotation = true;
    this.mask1.parent = this.mask;

    // Create collision mask m2
    this.mask2 = this.createSphere('m2', detail, 2, 1.9+1.7, 1, .05, .2);
    this.body2 = this.mask2.physicsImpostor.physicsBody;
    //this.body2.fixedRotation = true;
    this.mask2.parent = this.mask;
    //this.body2.type = 2;

    //this.updateMassProperties();

    // Testing
    //this.mask2.position.y = -1;

    //this.mask.physicsImpostor.forceUpdate();
    //this.body = this.mask.physicsImpostor.physicsBody;

    this.updatePhysicsImpostor();
    this.updateMassProperties();

    this.initGroundCheck();

    //this.mask2.position.y = -5;
    //this.updatePhysicsImpostor();
    //this.updateMassProperties();

    //this.body2.position.y -= 5;

    console.log('mask', this.mask);
    const visible = true;
    this.mask.isVisible = visible;
    this.mask1.isVisible = visible;
    this.mask2.isVisible = visible;

    this.mask.position.y = 20;

    console.log('body', this.mask.physicsImpostor.physicsBody);
  }

  updatePhysicsImpostor () {
    this.addCollisionToGroup(this.mask.physicsImpostor.physicsBody);
    this.mask.physicsImpostor.forceUpdate();
    this.body = this.mask.physicsImpostor.physicsBody;
  }

  updateMassProperties () {
    this.body.linearDamping = .8;
    this.body.fixedRotation = true;
    this.body.sleepSpeedLimit = .1;
    this.body.updateMassProperties();
  }

  createSphere (name, detail, size, posY, mass, friction, restitution) {
      // Make sphere mesh
      let sphere = BABYLON.Mesh.CreateSphere(name, detail, size, this.game.scene);
      // Set sphere position
      sphere.position.y += posY;
      sphere.computeWorldMatrix(true);
      // Create collision mask
      sphere.physicsImpostor = new BABYLON.PhysicsImpostor(sphere, BABYLON.PhysicsImpostor.SphereImpostor, {mass:mass, friction:friction, restitution:restitution}, this.game.scene);
      return sphere;
  }

  addCollisionToGroup (impostorBody) {
    impostorBody.collisionFilterGroup = this.game.collisionGroupNormal;
    impostorBody.collisionFilterMask = this.game.collisionGroupGround | this.game.collisionGroupNormal | this.game.collisionGroupFall;
  }

  initGroundCheck() {
    // Create mesh for onGround collision check
    this.groundCheck = BABYLON.Mesh.CreateBox("mask", 2.5, this.game.scene);
    this.groundCheck.isVisible = false;
    this.groundCheck.parent = this.mask;
    this.groundCheck.position.y = -3 + 1.9;
    this.groundCheck.scaling.y = 0.2;
  }

  checkGroundCheck() {
    //TODO: http://schteppe.github.io/cannon.js/examples/threejs_voxel_fps.html use this jump check logic
    // Check for ground
    var jumpableMeshes = this.game.scene.getMeshesByTags("checkJump")
    this.onGround = false;
    for (var i in jumpableMeshes) {
      if (this.groundCheck.intersectsMesh(jumpableMeshes[i], true)){
        this.mesh.material.diffuseColor = new BABYLON.Color3.Red();
        this.onGround = true;
      }
    }
  }

  update () {
    this.checkGroundCheck();

    if (this.moveBool) {
        this.move();
    }

    this.animations();

    this._manageMana();
  }

  // use this to make xbox controller movement is smoove and doesn't go over the speed limit
  getScaleSpeed (movementVector, speed) {
      //console.log('movementvector strength:', movementVector.length());
      return speed * Math.min(1, movementVector.length());
  }

  move () {
    // get normalized vector
    var movementVector = new BABYLON.Vector3(this.Input.AXIS_X,0,this.Input.AXIS_Y);
      //console.log('xbox move:', this.Input.AXIS_X, ', ', this.Input.AXIS_Y, ', scaleSpeed:', Math.min(1, movementVector.length()));
    var normalizedMovementVector = movementVector.clone().normalize();
    //console.log('scale speed:', this.getScaleSpeed(movementVector, this.speed));

    // Rolling is very important
    if (this.Input.ROLL && this.rollTimer == 0) {
        this.rollTimer = this.rollTimerStart;

    } else if (this.rollTimer > 0) {
        this.rollTimer--;
        // Slow the movement after rolling is done
        if (this.rollTimer == 0) {
            let slowDown = -5;
            this.mask.applyImpulse(new BABYLON.Vector3(slowDown * this.body.velocity.x, slowDown * this.body.velocity.y, slowDown * this.body.velocity.z), this.mask.position);
        }
    }
    this.Input.ROLL = false;
    //console.log(this.rollTimer);

    // Movement on ground
    if (this.onGround) {
        movementVector = normalizedMovementVector.scale(this.getScaleSpeed(movementVector, this.rollTimer? this.rollGroundSpeed:this.speed));
    } else { // Movement in air
        movementVector = normalizedMovementVector.scale(this.getScaleSpeed(movementVector, this.rollTimer? this.rollAirSpeed:this.airSpeed));
        if (this.body.velocity.y < 1) {
            movementVector = movementVector.add(new BABYLON.Vector3(0,-5,0));
        }
        if (this.rollTimer) {
            movementVector = movementVector.add(new BABYLON.Vector3(0, -5,0 ));
        }
    }

    // Jump
    if (this.onGround && this.Input.JUMP && this.jumpTimer == 0) {
        //console.log("jump!");
        movementVector = movementVector.add(new BABYLON.Vector3(0,this.jumpStrength,0));
        this.mesh.material.diffuseColor = BABYLON.Color3.Blue();
        this.jumpTimer = this.jumpTimerStart;
    } else if (this.jumpTimer > 0) {
        this.jumpTimer--;
    }
    this.Input.JUMP = false;

    // apply movement at the very end.
    //console.log('ONGROUND:', this.onGround);
    this.mask.applyImpulse(movementVector, this.mask.position);

    if (this.body.velocity.length() > 1 && (this.Input.AXIS_X || this.Input.AXIS_Y) ) {
        this.setRotation();
    }
  }

  setRotation () {
    // Player rotation
    this.mask.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(Math.atan2(this.body.velocity.x, this.body.velocity.z), 0, 0);
  }

  setPlayer(player) {
    (this._inputSubscriptions || {destroy: () => {}}).destroy();
    if (!player) {
      return;
    }
    this._inputSubscriptions = new EventSubscriptionContext(player.input)
      .on('end', () => this.setPlayer())
      .on('joychanged', joyVector => this.handleJoyChanged(joyVector))
      .on('buttondown', button => this.handleButtonDown(button))
      .on('buttonup', button => this.handleButtonUp(button))
    ;
  }

  handleJoyChanged(joyVector) {
      this._joyTarget.joyChanged(joyVector);
  }

    /**
     * Allow the hero to act as a joy target. When this gets
     * called, that means that the hero itself should respond
     * to joy and, e.g., move.
     */
    joyChanged(joyVector) {
        this.Input.AXIS_Y = joyVector.y;
        this.Input.AXIS_X = joyVector.x;
    }

  _handleButton(button, pressed) {
    switch (button) {
    }
  }

  handleButtonDown(button) {
    this._handleButton(button, true);
    switch (button) {
        case Buttons.RB: this.Input.JUMP = true; break;
        case Buttons.LB: this.Input.ROLL = true; break;
        case Buttons.A: this.attack1.buttonDown(0); this.animatePower=true; break;
        case Buttons.B: this.attack2.buttonDown(0); this.animatePower=true; break;
        case Buttons.X: this.attack3.buttonDown(0); this.animatePower=true; break;
        case Buttons.Y: this.attack4.buttonDown(0); this.animatePower=true; break;
    }
  }

  handleButtonUp(button) {
    this._handleButton(button, false);
    switch (button) {
        case Buttons.A: this.attack1.buttonUp(0); this.animatePower=false; break;
        case Buttons.B: this.attack2.buttonUp(0); this.animatePower=false; break;
        case Buttons.X: this.attack3.buttonUp(0); this.animatePower=false; break;
        case Buttons.Y: this.attack4.buttonUp(0); this.animatePower=false; break;
    }
  }

    _manageMana() {
        if (this._mana < maxMana) {
            this._mana = Math.min(maxMana, this._mana + 1);
        }
    }

    /**
     * Returns false if there is insufficient mana.
     */
    consumeMana(amount) {
        if (this._mana < amount) {
            return false;
        }
        this._mana -= amount;
        return true;
    }

    /**
     * Sets the joy target. The joy target must have a joyChanged
     * function accepting a Vector2. If null the hero will start
     * responding to joy again.
     */
    setJoyTarget(target) {
        target = target || this;
        // Send 0 to original target to set it to rest or whatever
        // instead of leaving it stuck at other value. For existing,
        // will stop movement in the hero.
        this.handleJoyChanged(zeroVector2);
        this._joyTarget = target;
        // Emit 0 to help target with preinitializing itself.
        this.handleJoyChanged(zeroVector2);
    }
}
<|endoftext|>