<commit_before> game.PlayerEntity = me.Entity.extend({
 	init: function(x, y, settings) {
    	this.setSuper();
      this.setPlayerTimers();
      this.setAttributes ();
      this.type = "PlayerEntity";
      this.setFlags();

    	me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

      this.addAnimation();

      this.renderable.setCurrentAnimation("idle");

	},
      // this is what sets the super class
      setSuper: function(){
        this._super(me.Entity, 'init', [x, y, {
        image: "player",
        width: 64,
        height: 64,
        spritewidth: "64",
        spriteheight: "64",

        getShape: function() {
         return(new me.Rect(0, 0, 64, 64)).toPolygon();
          }
    }]);

      },

      setPlayerTimers: function(){
      this.now = new Date().getTime();
      this.lastHit = this.now;
      this.lastAttack = new Date().getTime();

      },

      setAttributes: function(){
        this.health = game.data.playerHealth;
        this.body.setVelocity(game.data.playerMoveSpeed, 20);
        this.attack = game.data.playerAttack;
      },

      setFlags: function(){
        this.facing = "right";
        this.dead = false;
      },

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

 	    update: function(delta){
 	    	this.now = new Date().getTime();

        if(this.health <= 0){
          this.dead = true;
        }

        if(me.input.isKeyPressed ("right")){
 	         	// sets position of my x by adding the velocity defined above in setvelocity() and multiplying it by me.timer.tick
 	        	this.body.vel.x += this.body.accel.x * me.timer.tick;
 	        	this.facing = "right";
 	        	this.flipX(true);
 	        } else if(me.input.isKeyPressed("left")){
 	        	this.facing.left = "left";
 	        	this.body.vel.x -= this.body.accel.x * me.timer.tick;
 	        	this.flipX(false);
 	        }else{
              this.body.vel.x = 0;
 	      }

 	      if(me.input.isKeyPressed("jump")){
          if(!this.body.jumping  && !this.body.falling){
            this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
             this.body.jumping = true;

        }
        }

 	        if(me.input.isKeyPressed("attack")){
 	      	  if(!this.renderable.isCurrentAnimation("attack")){
 	      		// sets the current animation to attack and once it is over, goes back to idle animation
 	      		this.renderable.setCurrentAnimation("attack", "idle");
 	      		// the line of code below makes it so that, this sequence, we begin from the first animation, not wherever we left off when we switched
 	      		this.renderable.setAnimationFrame();
 	      }

 	    }

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

            }

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

          }

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

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

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

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

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

 	    	    if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= game.data.playerAttackTimer){
 	    			this.lastHit = this.now;
 	    			response.b.loseHealth(game.data.playerAttack);
 	    	}
 	    }else if(response.b.type==='EnemyCreep') {
          var xdif = this.pos.x - response.b.pos.x;
          var ydif = this.pos.y - response.b.pos.y;

          if (xdif>0) {
             // this.pos.x = this.pos.x + 1;
              if(this.facing==="left"){
                this.body.vel.x = 0;
              }
          }else{
            // this.pos.x = this.pos.x - 1;
             if(this.facing==="right"){
                this.body.vel.x = 0;
              }
          }
          if(this.renderable.isCurrentAnimation('attack') && this.now-this.lastHit >= game.data.playerAttackTimer
              && (Math.abs(ydif) <=40) &&
              (((xdif>0) && this.facing==="left") || ((xdif<0) && this.facing==="right")))
          {
            this.lastHit = this.now;
            // if the creeps health is less then our attack excecute code in if statement
            if(response.b.health <= game.data.playerAttack) {
              // adds one gold for a creep kill
                game.data.gold += 1;
                console.log("Current gold: " + game.data.gold);
            }

            response.b.loseHealth(game.data.playerAttack);
          }
      }
 	 }

   });

// END OF UPDATE FUNCTION ABOVE!!!!!!

 //the reason why this is a class, it gets to have both letters be capital
 // the init: is our constructor function
 // for entities it wants 3 parameters
 // the difference between the spriteheight and width vs the regular height and width is that sprite width and sprite height are passing the main info.
 // the regular width and the height is telling the screen what ammount of space to preserve
// this is for the player to move right
//velocity represnts our current position
// me.timer.tick makes the movement look smooth
//adds to the position of my x by the velocity defined above
//delta is the change in time that has happened
//the speed is 80 miliseconds
// what the If (!this statment is saying is, that we dont want to start the walk animation, if we are already walking
//// if we dont add this line the animations wont be able to animate on the fly
// this.flipX fixes the characters turning

//This.broken is the variable we make to say that the tower is not destroyed
//this.health represents how much health you begin with
//this.type is for later collisions
//what the if statement does, is it looks at your health and determines if you are dead
// always call the super in update functions
//we then set the animations on the player and enemy base
// when we break the tower we want to set the animation to broken
//renderable is a class that they built in melon js, we use it to do most animations
//me.game.viewport allows us to follow the player
// This.facing keeps track of hich direction, your character is going
//me.collision is basically just checking for collisions
//what is going on is we are passing our parameter to our function collide.handler
//response.a represents our player
// response.b represents whatever we are colliding with
//vary dif represents the difference between my players y position and the bases y position
// what we want to happen is our Y variable to be dealt with first
// we have not used attack var yet
//this.health-- makes the health go down one
//the attack animation will detect collisions over and over
//this.now keeps track of the time in the game
//this.lastAttack is for a hit delay
//everytime you call for an update you want to change this.now
// our GameManager is not something that will appear on the screen
//It is not an entity it is just something we are using
//we want to make sure the game manager is continuosuly updating
//math.round checks to see if we have a multiple of 10
// this is mod %, it will check and see if we have a multiple of 10
// We want the creeps to drop to the ground and begin walking
// delta represents time as a parameter
//We want the creeps to drop to the ground and begin walking
// delta represents time as a parameter
// this.attacking lets us know if the nemy is currently attacking
// this.pos.x keeps moving the creep
// we do not want our creep to hit multiple things
//we put an if else statement so it can only be hitting one of those things
//To the right the x value will be bigger
//The position change will only happen when the creep is attacking
//  what we want our if else statement in our player function to do is to hurt the creep only when we are attacking
// we are working on the ways we can attack the creeps
// | | this represents and
// If we make the number smaller in Playerattack timer, the player can attack faster and if we make the number bigger the player can attack slower
// now we can just adjust everything in the game.js file
// we are making an if else statement in the game manager to see if the player is dead
// we are using the reset player function
// renderable fuctions draw instead of update
//renderer is the parameter of the draw function
//we put the coordinates of where we are in the draw function
//we need the event handler to be listening for someone to press the enter button
//without an event handler we cannot check any other way
//we also need to make sure we unbind the key also
// gold will be aquired each game and can be used to buy, power ups
// we have other variables to keep track of how the experience is spent
// we are using local variables to make sure we are keeping track of things such as the experience on the fly

//In video 29 we are basically editing our code and making it shorter
// When the code is trimmed down the way it was, we can manage all of the code more easily
// we split most of our functions into seperate java script files <commit_msg>Video 30 commented<commit_after> game.PlayerEntity = me.Entity.extend({
 	init: function(x, y, settings) {
    	this.setSuper();
      this.setPlayerTimers();
      this.setAttributes ();
      this.type = "PlayerEntity";
      this.setFlags();

    	me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

      this.addAnimation();

      this.renderable.setCurrentAnimation("idle");

	},
      // this is what sets the super class
      setSuper: function(){
        this._super(me.Entity, 'init', [x, y, {
        image: "player",
        width: 64,
        height: 64,
        spritewidth: "64",
        spriteheight: "64",

        getShape: function() {
         return(new me.Rect(0, 0, 64, 64)).toPolygon();
          }
    }]);

      },

      setPlayerTimers: function(){
      this.now = new Date().getTime();
      this.lastHit = this.now;
      this.lastAttack = new Date().getTime();

      },

      setAttributes: function(){
        this.health = game.data.playerHealth;
        this.body.setVelocity(game.data.playerMoveSpeed, 20);
        this.attack = game.data.playerAttack;
      },

      setFlags: function(){
        this.facing = "right";
        this.dead = false;
      },

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

 	    update: function(delta){
 	    	this.now = new Date().getTime();

        if(this.health <= 0){
          this.dead = true;
        }

        if(me.input.isKeyPressed ("right")){
 	         	// sets position of my x by adding the velocity defined above in setvelocity() and multiplying it by me.timer.tick
 	        	this.body.vel.x += this.body.accel.x * me.timer.tick;
 	        	this.facing = "right";
 	        	this.flipX(true);
 	        } else if(me.input.isKeyPressed("left")){
 	        	this.facing.left = "left";
 	        	this.body.vel.x -= this.body.accel.x * me.timer.tick;
 	        	this.flipX(false);
 	        }else{
              this.body.vel.x = 0;
 	      }

 	      if(me.input.isKeyPressed("jump")){
          if(!this.body.jumping  && !this.body.falling){
            this.body.vel.y = -this.body.maxVel.y * me.timer.tick;
             this.body.jumping = true;

        }
        }

 	        if(me.input.isKeyPressed("attack")){
 	      	  if(!this.renderable.isCurrentAnimation("attack")){
 	      		// sets the current animation to attack and once it is over, goes back to idle animation
 	      		this.renderable.setCurrentAnimation("attack", "idle");
 	      		// the line of code below makes it so that, this sequence, we begin from the first animation, not wherever we left off when we switched
 	      		this.renderable.setAnimationFrame();
 	      }

 	    }

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

            }

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

          }

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

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

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

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

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

 	    	    if(this.renderable.isCurrentAnimation("attack") && this.now-this.lastHit >= game.data.playerAttackTimer){
 	    			this.lastHit = this.now;
 	    			response.b.loseHealth(game.data.playerAttack);
 	    	}
 	    }else if(response.b.type==='EnemyCreep') {
          var xdif = this.pos.x - response.b.pos.x;
          var ydif = this.pos.y - response.b.pos.y;

          if (xdif>0) {
             // this.pos.x = this.pos.x + 1;
              if(this.facing==="left"){
                this.body.vel.x = 0;
              }
          }else{
            // this.pos.x = this.pos.x - 1;
             if(this.facing==="right"){
                this.body.vel.x = 0;
              }
          }
          if(this.renderable.isCurrentAnimation('attack') && this.now-this.lastHit >= game.data.playerAttackTimer
              && (Math.abs(ydif) <=40) &&
              (((xdif>0) && this.facing==="left") || ((xdif<0) && this.facing==="right")))
          {
            this.lastHit = this.now;
            // if the creeps health is less then our attack excecute code in if statement
            if(response.b.health <= game.data.playerAttack) {
              // adds one gold for a creep kill
                game.data.gold += 1;
                console.log("Current gold: " + game.data.gold);
            }

            response.b.loseHealth(game.data.playerAttack);
          }
      }
 	 }

   });

// END OF UPDATE FUNCTION ABOVE!!!!!!

 //the reason why this is a class, it gets to have both letters be capital
 // the init: is our constructor function
 // for entities it wants 3 parameters
 // the difference between the spriteheight and width vs the regular height and width is that sprite width and sprite height are passing the main info.
 // the regular width and the height is telling the screen what ammount of space to preserve
// this is for the player to move right
//velocity represnts our current position
// me.timer.tick makes the movement look smooth
//adds to the position of my x by the velocity defined above
//delta is the change in time that has happened
//the speed is 80 miliseconds
// what the If (!this statment is saying is, that we dont want to start the walk animation, if we are already walking
//// if we dont add this line the animations wont be able to animate on the fly
// this.flipX fixes the characters turning

//This.broken is the variable we make to say that the tower is not destroyed
//this.health represents how much health you begin with
//this.type is for later collisions
//what the if statement does, is it looks at your health and determines if you are dead
// always call the super in update functions
//we then set the animations on the player and enemy base
// when we break the tower we want to set the animation to broken
//renderable is a class that they built in melon js, we use it to do most animations
//me.game.viewport allows us to follow the player
// This.facing keeps track of hich direction, your character is going
//me.collision is basically just checking for collisions
//what is going on is we are passing our parameter to our function collide.handler
//response.a represents our player
// response.b represents whatever we are colliding with
//vary dif represents the difference between my players y position and the bases y position
// what we want to happen is our Y variable to be dealt with first
// we have not used attack var yet
//this.health-- makes the health go down one
//the attack animation will detect collisions over and over
//this.now keeps track of the time in the game
//this.lastAttack is for a hit delay
//everytime you call for an update you want to change this.now
// our GameManager is not something that will appear on the screen
//It is not an entity it is just something we are using
//we want to make sure the game manager is continuosuly updating
//math.round checks to see if we have a multiple of 10
// this is mod %, it will check and see if we have a multiple of 10
// We want the creeps to drop to the ground and begin walking
// delta represents time as a parameter
//We want the creeps to drop to the ground and begin walking
// delta represents time as a parameter
// this.attacking lets us know if the nemy is currently attacking
// this.pos.x keeps moving the creep
// we do not want our creep to hit multiple things
//we put an if else statement so it can only be hitting one of those things
//To the right the x value will be bigger
//The position change will only happen when the creep is attacking
//  what we want our if else statement in our player function to do is to hurt the creep only when we are attacking
// we are working on the ways we can attack the creeps
// | | this represents and
// If we make the number smaller in Playerattack timer, the player can attack faster and if we make the number bigger the player can attack slower
// now we can just adjust everything in the game.js file
// we are making an if else statement in the game manager to see if the player is dead
// we are using the reset player function
// renderable fuctions draw instead of update
//renderer is the parameter of the draw function
//we put the coordinates of where we are in the draw function
//we need the event handler to be listening for someone to press the enter button
//without an event handler we cannot check any other way
//we also need to make sure we unbind the key also
// gold will be aquired each game and can be used to buy, power ups
// we have other variables to keep track of how the experience is spent
// we are using local variables to make sure we are keeping track of things such as the experience on the fly
//In video 29 we are basically editing our code and making it shorter
// When the code is trimmed down the way it was, we can manage all of the code more easily
// we split most of our functions into seperate java script files
// attributes is for anything different involving leveling up, move speed, health percentage, defense, and more
// flags are things that are either one way or another
// we sorted everything into their own group so everything is more neater<|endoftext|>


<commit_before>//class
game.PlayerEntity = me.Entity.extend({
	//setting function
	init: function(x, y, settings) {
		//extending the function
		this._super(me.Entity, 'init', [x, y, {
			//setting the player image and its width and height
			image: "player",
			width: 64,
			height: 64,
			spritewidth: "64",
			spriteheight: "64",

			getShape: function(){
				//new shift
				//rectangle to make the character walk into it
				//setting it to the right size
				return (new me.Rect (0, 0, 64, 64)).toPolygon();
			}
		}]);
		//setting the velocity
		this.body.setVelocity(5, 20);
		//keeps track of which direction your character is going
		this.facing = "right";

		this.now = new Date().getTime();
		this.lastHit = this.now;
		this.lastAttack = new Date().getTime();
		me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH)
		this.renderable.addAnimation("idle" , [78]);
		this.renderable.addAnimation("walk", [117, 118 , 119 , 120 , 121 , 122 , 123 , 124 , 125], 80);
		this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72], 80);
		this.renderable.setCurrentAnimation("idle");
	},

	update: function(delta){
		this.now = new Date().getTime();
		//checking if the right key is pressed
		if (me.input.isKeyPressed("right")) {
			//adds to  the position of my x by the velocity defined above in
			//setVelocity() and multiplying it by me.timer.tick
			//me.timer.tick makes the movement look smooth
			this.body.vel.x += this.body.accel.x * me.timer.tick;

			this.facing = "right";
			this.flipX(true);

			//if other key is pressed it wont work
		}else if (me.input.isKeyPressed("left")){
			this.facing = "left";
			this.body.vel.x -=this.body.accel.x * me.timer.tick;
			this.flipX(false);
		}else{
			this.body.vel.x = 0;
		}
if(me.input.isKeyPressed("jump") && !this.body.jumping && !this.body.falling) {
this.jumping = true;
this.body.vel.y -= this.body.accel.y * me.timer.tick;
}

if(me.input.isKeyPressed("attack")){

	if(!this.renderable.isCurrentAnimation("attack")){
		console.log(!this.renderable.isCurrentAnimation("attack"));
		//sets the current animation to attack and once that is over
	//goes back to the idle animation
	this.renderable.setCurrentAnimation("attack" , "idle");
	//makes it so that the next time we start this sequence we begin
	//from the first animation, not wherever we left off when we
	//switched to another animation
	this.renderable.setAnimationFrame();
	}
}

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

	me.collision.check(this, true, this.collideHandler.bind(this), true);
		//updating the game
		this.body.update(delta);

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

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

if (ydif<-40 && xdif< 70 && xdif>-35){
this.body.falling = false;
this.body.vel.y = -1;
}

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

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

game.EnemyBaseEntity = me.Entity.extend({
	init: function(x , y, settings) {
		this._super(me.Entity, 'init', [x, y, {
			image: "tower",
			width: 100,
			height: 100,
			spritewidth: "100",
			spriteheight: "100",
			getShape: function() {
				return (new me.Rect(0, 0, 100, 80)).toPolygon();
			}
		}]);

		this.broken = false;
		this.health = 10;
		this.alwaysUpdate = true;
		this.body.onCollision = this.onCollision.bind(this);
		this.type = "EnemyBaseEntity";
		this.renderable.addAnimation("idle" , [0]);
		this.renderable.addAnimation("broken" , [1]);
		this.renderable.setCurrentAnimation("idle");
	},

	update:function(delta){
		if (this.health<=0) {
			this.broken = true;
			this.renderable.setCurrentAnimation("broken");
		}
		this.body.update(delta);
		this._super(me.Entity, "update", [delta]);
		return true;
	},
	onCollision: function(){

	}
});

game.PlayerBaseEntity = me.Entity.extend({
	init: function(x , y, settings) {
		this._super(me.Entity, 'init', [x, y, {
			image: "tower",
			width: 100,
			height: 100,
			spritewidth: "100",
			spriteheight: "100",
			getShape: function() {
				return (new me.Rect(0, 0, 100, 80)).toPolygon();
			}
		}]);

		this.broken = false;
		this.health = 10;
		this.alwaysUpdate = true;
		this.body.onCollision = this.onCollision.bind(this);
		this.type = "PlayerBaseEntity";

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

	update:function(delta){
		if (this.health<=0) {
			this.broken = true;
			this.renderable.setCurrentAnimation("broken");
		}
		this.body.update(delta);
		this._super(me.Entity, "update", [delta]);
		return true;
	},
	onCollision: function(){

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

game.EnemyCreep = me.Entity.extend({
	init: function(x, y, settings){
		this._super(me.Entity, 'init', [x, y, {
			image: "creep1",
			width: 32,
			height: 64,
			spritewidth: "32",
			spriteheight: "64",
			getShape: function(){
				return (new me.Rect(0, 0, 32, 64)).toPolygon();
			}
		}]);
		this.health = 10;
		this.alwaysUpdate = true;

		this.body.setVelocity(3, 20);
		this.type = "EnemyCreep";
		this.renderable.addAnimation("walk", [3, 4, 5], 80);
		this.renderable.setCurrentAnimation("walk");
	},
	update: function(){

	}
})

game.GameManager = Object.extend({
init: function(x, y, settings){
this.now = new Date().getTime();
this.lastCreep = new Date().getTime();
this.alwaysUpdate = true;
},
update: function(){
this.now = new Date().getTime();

if(Math.round(this.now/1000)%10 ===0 && (this.now - this.lastCreep >= 1000)){
	this.lastCreep = this.now;
	var creepe = me.pool.pull("EnemyCreep", 1000, 0, {});
	me.game.world.addChild(Creepe, 5);
	}
	return true;
}
});<commit_msg>Commented video 8<commit_after>//class
game.PlayerEntity = me.Entity.extend({
	//setting function
	init: function(x, y, settings) {
		//extending the function
		this._super(me.Entity, 'init', [x, y, {
			//setting the player image and its width and height
			image: "player",
			width: 64,
			height: 64,
			spritewidth: "64",
			spriteheight: "64",

			getShape: function(){
				//new shift
				//rectangle to make the character walk into it
				//setting it to the right size
				return (new me.Rect (0, 0, 64, 64)).toPolygon();
			}
		}]);
		//setting the velocity
		this.body.setVelocity(5, 20);
		//keeps track of which direction your character is going
		this.facing = "right";

		this.now = new Date().getTime();
		this.lastHit = this.now;
		this.lastAttack = new Date().getTime();
		me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH)
		//adding the pictures of the characters
		this.renderable.addAnimation("idle" , [78]);
		this.renderable.addAnimation("walk", [117, 118 , 119 , 120 , 121 , 122 , 123 , 124 , 125], 80);
		this.renderable.addAnimation("attack", [65, 66, 67, 68, 69, 70, 71, 72], 80);
		this.renderable.setCurrentAnimation("idle");
	},

	update: function(delta){
		this.now = new Date().getTime();
		//checking if the right key is pressed
		if (me.input.isKeyPressed("right")) {
			//adds to  the position of my x by the velocity defined above in
			//setVelocity() and multiplying it by me.timer.tick
			//me.timer.tick makes the movement look smooth
			this.body.vel.x += this.body.accel.x * me.timer.tick;

			//flipping the character
			this.facing = "right";
			this.flipX(true);

			//if other key is pressed it wont work
		}else if (me.input.isKeyPressed("left")){
			this.facing = "left";
			this.body.vel.x -=this.body.accel.x * me.timer.tick;
			this.flipX(false);
		}else{
			this.body.vel.x = 0;
		}
if(me.input.isKeyPressed("jump") && !this.body.jumping && !this.body.falling) {
this.jumping = true;
this.body.vel.y -= this.body.accel.y * me.timer.tick;
}

if(me.input.isKeyPressed("attack")){

	if(!this.renderable.isCurrentAnimation("attack")){
		console.log(!this.renderable.isCurrentAnimation("attack"));
		//sets the current animation to attack and once that is over
	//goes back to the idle animation
	this.renderable.setCurrentAnimation("attack" , "idle");
	//makes it so that the next time we start this sequence we begin
	//from the first animation, not wherever we left off when we
	//switched to another animation
	this.renderable.setAnimationFrame();
	}
}

		else if(this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")){
			//sets the animation of walking
			if(!this.renderable.isCurrentAnimation("walk")){
				this.renderable.setCurrentAnimation("walk");
			}
		}else if (!this.renderable.isCurrentAnimation("attack")){
			//when no keys are pressed the character sets to idle
			this.renderable.setCurrentAnimation("idle");
		}

	me.collision.check(this, true, this.collideHandler.bind(this), true);
		//updating the game
		this.body.update(delta);

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

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

if (ydif<-40 && xdif< 70 && xdif>-35){
this.body.falling = false;
this.body.vel.y = -1;
}

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

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

game.EnemyBaseEntity = me.Entity.extend({
	init: function(x , y, settings) {
		this._super(me.Entity, 'init', [x, y, {
			image: "tower",
			width: 100,
			height: 100,
			spritewidth: "100",
			spriteheight: "100",
			getShape: function() {
				return (new me.Rect(0, 0, 100, 80)).toPolygon();
			}
		}]);

		this.broken = false;
		this.health = 10;
		this.alwaysUpdate = true;
		this.body.onCollision = this.onCollision.bind(this);
		this.type = "EnemyBaseEntity";
		this.renderable.addAnimation("idle" , [0]);
		this.renderable.addAnimation("broken" , [1]);
		this.renderable.setCurrentAnimation("idle");
	},

	update:function(delta){
		if (this.health<=0) {
			this.broken = true;
			this.renderable.setCurrentAnimation("broken");
		}
		this.body.update(delta);
		this._super(me.Entity, "update", [delta]);
		return true;
	},
	onCollision: function(){

	}
});

game.PlayerBaseEntity = me.Entity.extend({
	init: function(x , y, settings) {
		this._super(me.Entity, 'init', [x, y, {
			image: "tower",
			width: 100,
			height: 100,
			spritewidth: "100",
			spriteheight: "100",
			getShape: function() {
				return (new me.Rect(0, 0, 100, 80)).toPolygon();
			}
		}]);

		this.broken = false;
		this.health = 10;
		this.alwaysUpdate = true;
		this.body.onCollision = this.onCollision.bind(this);
		this.type = "PlayerBaseEntity";

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

	update:function(delta){
		if (this.health<=0) {
			this.broken = true;
			this.renderable.setCurrentAnimation("broken");
		}
		this.body.update(delta);
		this._super(me.Entity, "update", [delta]);
		return true;
	},
	onCollision: function(){

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

game.EnemyCreep = me.Entity.extend({
	init: function(x, y, settings){
		this._super(me.Entity, 'init', [x, y, {
			image: "creep1",
			width: 32,
			height: 64,
			spritewidth: "32",
			spriteheight: "64",
			getShape: function(){
				return (new me.Rect(0, 0, 32, 64)).toPolygon();
			}
		}]);
		this.health = 10;
		this.alwaysUpdate = true;

		this.body.setVelocity(3, 20);
		this.type = "EnemyCreep";
		this.renderable.addAnimation("walk", [3, 4, 5], 80);
		this.renderable.setCurrentAnimation("walk");
	},
	update: function(){

	}
})

game.GameManager = Object.extend({
init: function(x, y, settings){
this.now = new Date().getTime();
this.lastCreep = new Date().getTime();
this.alwaysUpdate = true;
},
update: function(){
this.now = new Date().getTime();

if(Math.round(this.now/1000)%10 ===0 && (this.now - this.lastCreep >= 1000)){
	this.lastCreep = this.now;
	var creepe = me.pool.pull("EnemyCreep", 1000, 0, {});
	me.game.world.addChild(Creepe, 5);
	}
	return true;
}
});<|endoftext|>


<commit_before>game.PlayerEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "player",
                width: 64,
                height: 64,
                spritewidth: "64",
                spriteheight: "64",
                getShape: function() {
                    return(new me.Rect(0, 0, 64, 64)).toPolygon();
                }
            }]);
            this.type = "PlayerEntity";
            this.health = game.data.playerHealth;
            this.body.setVelocity(game.data.playerMoveSpeed, 20);
            //Keeps track of which direction your character is going
            this.facing = "right";
            this.now = new Date().getTime();
            this.lastHit = this.now;
            this.dead = false;
            this.lastAttack = new Date().getTime();
            me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

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

    update: function(delta) {
        this.now = new Date().getTime();

        if(this.health <= 0){
            this.dead = true;
        }

        if (me.input.isKeyPressed("right")) {
            //adds to the position of my x by the velocity defined above in
            //setVelocity() and multiplying its by me.timertick.
            //me.timer.tick makes the movement look smooth
            this.body.vel.x += this.body.accel.x * me.timer.tick;
            this.facing = "right";
            this.flipX(true);
        } else if (me.input.isKeyPressed("left")) {
            this.facing = "left";
            this.body.vel.x -= this.body.accel.x * me.timer.tick;
            this.flipX(false);
        } else {
            this.body.vel.x = 0;
        }

        if (me.input.isKeyPressed("jump") && !this.body.jumping && !this.body.falling) {
            this.body.jumping = true;
            this.body.vel.y -= this.body.accel.y * me.timer.tick;
        }

        if (me.input.isKeyPressed("attack")) {
            if (!this.renderable.isCurrentAnimation("attack")) {
                //Sets the current animation to attack and once that is over
                //goes back to the idle animation
                this.renderable.setCurrentAnimation("attack", "idle");
                //Makes it so that the next time we start this sequence we begin
                //from the first animation, not whereever we left off when we
                //switched to another animation
                this.renderable.setAnimationFrame();
            }
        }
        else if (this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")) {
            if (this.renderable.isCurrentAnimation("walk")) {
                this.renderable.setCurrentAnimation("walk");
            }
        } else if (!this.renderable.isCurrentAnimation("attack")) {
            this.renderable.setCurrentAnimation("idle");
        }
        me.collision.check(this, true, this.collideHandler.bind(this), true);
        this.body.update(delta);

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

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

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

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

            if (this.renderable.isCurrentAnimation("attack")&& this.now-this.lastHit >= game.data.playerAttackTimer){
                console.log("tower Hit");
                this.LastHit = this.now;
                response.b.loseHealth(game.data.playerAttack);
        }
    }else if(response.b.type==='EnemyCreep'){
        var xdif = this.pos.x - response.b.pos.x;
        var ydif = this.pos.y - response.b.pos.y;

        if (xdif>0){
           // this.pos.x = this.pos.x + 1;
            if(this.facing==="left"){
                this.body.vel.x = 0;
            }
        }else{
           // this.pos.x - this.pos.x - 1;
            if(this.facing==="right"){
                this.body.vel.x = 0;
            }
        }
        if(this.renderable.isCurrentAnimation("attack") &&this.now-this.lastHit >= game.playerAttackTimer
               && (Math.abs(xdif)<=40) &&
               (((xdif>0) && this.facing==="left") || ((xdif<0) && this.facing==="right"))
               ){
           this.lastHit = this.now;
           response.b.loseHealth(game.data.playerAttack);
        }
      }

   }
});

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

        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },
    update: function(delta) {
        if (this.health <= 0) {
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);

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

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

    onCollision: function() {

    }

});

game.EnemyBaseEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "tower",
                width: 100,
                height: 100,
                spritewidth: "100",
                spriteheight: "100",
                getShape: function() {
                    return (new me.Rect(0, 0, 100, 70)).toPolygon();
                }
            }]);
        this.broken = false;
        this.health = game.data.enemyBaseHealth;
        this.alwaysUpdate = true;
        this.body.onCollision = this.onCollision.bind(this);
        this.type = "EnemyBaseEntity";
        this.renderable.addAnimation("idle", [0]);
        this.renderable.addAnimation("broken", [1]);
        this.renderable.setCurrentAnimation("idle");
    },
    update: function(delta) {
        if (this.health <= 0) {
            this.broken = true;
            this.renderable.setCurrentAnimation("broken");
        }
        this.body.update(delta);
        this._super(me.Entity, "update", [delta]);
        return true;
    },
    onCollision: function() {

    }

});

game.EnemyCreep = me.Entity.extend({
    init: function(x, y, settings){
        this._super(me.Entity, 'init', [x, y,{
             image: "creep1",
             width: 32,
             height: 64,
             spritewidth: "32",
             spriteheight: "64",
             getShape: function(){
                 return (new me.Rect(0, 0, 32, 64)).toPolygon();
             }
        }]);
    this.health = game.data.enemyCreepHealth;
    this.alwaysUpdate = true;
    //this.attacking lets us know if the enemy is currently attacking
    this.attacking = false;
    //Keeps track of when our creep last attacked anything
    this.lastAttacking = new Date().getTime();
    //Keep track of the last time our creep hit anything
    this.lastHit = new Date().getTime();
    this.now = new Date().getTime();
    this.body.setVelocity(3, 20);

    this.type = "EnemyCreep";

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

    },

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

    update: function(delta){
        console.log(this.health);
        if(this.health <= 0){
            me.game.world.removeChild(this);
        }

       this.now = new Date().getTime();

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

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

        this.body.update(delta);

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

    collideHandler: function(response){
        if(response.b.type==='PlayerBase'){
            this.attacking=true;
          // this.lastAttacking=this.now;
           this.body.vel.x = 0;
           //Kepps moving the creep to the right to maintain its position
           this.pos.x = this.pos.x + 1;
           //checks that it has been at least 1 second since this creep hit a base
           if((this.now-this.lastHit >= 1000 )){
               //update the lasthit timer
               this.lastHit = this.now;
               //makes the player base call its loseHealth function and passes it a
               //damage of 1
               response.b.loseHealth(1);
           }
        }else if (response.b.type==='PlayerEntity'){
            var xdif = this.pos.x - response.b.pos.x;

            this.attacking=true;
            // this.lastAttacking=this.now;
           this.body.vel.x = 0;
            //Kepps moving the creep to the right to maintain its position

           this.pos.x = this.pos.x + 1;
           //checks that it has been at least 1 second since this creep hit a base
           if((this.now-this.lastHit >= 1000 ) && xdif>0){
               //update the lasthit timer
               this.lastHit = this.now;
               //makes the player call its loseHealth function and passes it a
               //damage of 1
               response.b.loseHealth(game.data.enemyCreepAttack);
           }
       }else if (response.b.type==='PlayerEntity'){

       }
   }

});

game.GameManager = Object.extend({
    init: function(x, y, settings){
        this.now = new Date().getTime();
        this.lastCreep = new Date().getTime();

        this.alwaysUpddate = true;
    },

    update: function(){
        this.now = new Date().getTime();

        if(game.data.player.dead){
            me.game.world.removeChild(game.data.player);
            me.state.current().resetPlayer(10, 0);
        }

        if(Math.round(this.now/1000)%10 ===0 && (this.now - this.lastCreep >= 1000)){
         this.lastCreep = this.now;
         var lazarus = me.pool.pull("EnemyCreep", 1000, 0, {});
         me.game.world.addChild(lazarus, 5);
        }

        return true;
    }
});

        <commit_msg>llkjn<commit_after>game.PlayerEntity = me.Entity.extend({
    init: function(x, y, settings) {
        this._super(me.Entity, 'init', [x, y, {
                image: "player",
                width: 64,
                height: 64,
                spritewidth: "64",
                spriteheight: "64",
                getShape: function() {
                    return(new me.Rect(0, 0, 64, 64)).toPolygon();
                }
            }]);
            this.type = "PlayerEntity";
            this.health = game.data.playerHealth;
            this.body.setVelocity(game.data.playerMoveSpeed, 20);
            //Keeps track of which direction your character is going
            this.facing = "right";
            this.now = new Date().getTime();
            this.lastHit = this.now;
            this.dead = false;
            this.attack = game.data.playerAttack;
            this.lastAttack = new Date().getTime();
            me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);

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

    update: function(delta) {
        this.now = new Date().getTime();

        if(this.health <= 0){
            this.dead = true;
        }

        if (me.input.isKeyPressed("right")) {
            //adds to the position of my x by the velocity defined above in
            //setVelocity() and multiplying its by me.timertick.
            //me.timer.tick makes the movement look smooth
            this.body.vel.x += this.body.accel.x * me.timer.tick;
            this.facing = "right";
            this.flipX(true);
        } else if (me.input.isKeyPressed("left")) {
            this.facing = "left";
            this.body.vel.x -= this.body.accel.x * me.timer.tick;
            this.flipX(false);
        } else {
            this.body.vel.x = 0;
        }

        if (me.input.isKeyPressed("jump") && !this.body.jumping && !this.body.falling) {
            this.body.jumping = true;
            this.body.vel.y -= this.body.accel.y * me.timer.tick;
        }

        if (me.input.isKeyPressed("attack")) {
            if (!this.renderable.isCurrentAnimation("attack")) {
                //Sets the current animation to attack and once that is over
                //goes back to the idle animation
                this.renderable.setCurrentAnimation("attack", "idle");
                //Makes it so that the next time we start this sequence we begin
                //from the first animation, not whereever we left off when we
                //switched to another animation
                this.renderable.setAnimationFrame();
            }
        }
        else if (this.body.vel.x !== 0 && !this.renderable.isCurrentAnimation("attack")) {
            if (this.renderable.isCurrentAnimation("walk")) {
                this.renderable.setCurrentAnimation("walk");
            }
        } else if (!this.renderable.isCurrentAnimation("attack")) {
            this.renderable.setCurrentAnimation("idle");
        }
        me.collision.check(this, true, this.collideHandler.bind(this), true);
        this.body.update(delta);

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

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

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

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

            if (this.renderable.isCurrentAnimation("attack")&& this.now-this.lastHit >= game.data.playerAttackTimer){

                this.LastHit = this.now;
                response.b.loseHealth(game.data.playerAttack);
        }
    }else if(response.b.type==='EnemyCreep'){
        var xdif = this.pos.x - response.b.pos.x;
        var ydif = this.pos.y - response.b.pos.y;

        if (xdif>0){
           // this.pos.x = this.pos.x + 1;
            if(this.facing==="left"){
                this.body.vel.x = 0;
            }
        }else{
           // this.pos.x - this.pos.x - 1;
            if(this.facing==="right"){
                this.body.vel.x = 0;
            }
        }
        if(this.renderable.isCurrentAnimation("attack") &&this.now-this.lastHit >= game.playerAttackTimer
               && (Math.abs(xdif)<=40) &&
               (((xdif>0) && this.facing==="left") || ((xdif<0) && this.facing==="right"))
               ){
           this.lastHit = this.now;
           //if the creeps health is less than our attack, execute in if statement
           if(response.b.health <= game.data.playerAttack){
               //adds one gold for creep kill
               game.data.gold += 1;
               console.log("Current gold: " + game.data.gold);

           }

           response.b.loseHealth(game.data.playerAttack);
        }
      }

   }
});

<|endoftext|>


<commit_before>/*jshint bitwise: false*/
/*exported Harmonic*/
var Harmonic = (function() {
  'use strict';

  var config = {
    // Cell count on a side.
    cellCount: Math.pow( 2, 6 )
  };

  var CellType = {
    UNTYPED: 1,
    BOUNDARY: 2,
    INTERIOR: 4,
    EXTERIOR: 8
  };

  function clamp( value, min, max ) {
    return Math.min( Math.max( value, min ), max );
  }

  /**
   * Find the parameter of the point (x, y) as projected on the line segment
   * form by (x0, y0) - (x1, y1).
   */
  function closestPointOnLineParameter( x, y, x0, y0, x1, y1 ) {
    var dx = x1 - x0,
        dy = y1 - y0;

    // Check for line degeneracy.
    if ( !dx && !dy ) {
      return null;
    }

    var lengthSquared = dx * dx + dy * dy;

    return ( ( x - x0 ) * ( x1 - x0 ) + ( y - y0 ) * ( y1 - y0 ) ) / lengthSquared;
  }

  /**
   * Marks all cells which lie on the Bresenham line rasterization as
   * BOUNDARY cells.
   *
   * Scan-converts the univariate linear B-spline basis function
   * ("hat function" basis) for cell vertex weights.
   *   - The basis function is linearly interpolated from 1 at the primary
   *     vertex to 0 at the previous/next vertices:
   *
   *                                o              1
   *                              /   \
   *                            /       \
   *                     -----o           o-----   0
   *     vertex index:   (i - 1)    i    (i + 1)
   *
   * Vertices are expected to be normalized to grid units. That is, a grid
   * cell will have world dimensions equal to column width and row height, but
   * local dimensions of 1 by 1.
   *
   * i0 and i1 are vertex weight indices.
   *
   * Assumes a square grid.
   */
  function bresenham( grid, count, x0, y0, x1, y1, i0, i1, vertexCount ) {
    var x = x0,
        y = y0;

    var dx = Math.abs( x1 - x0 ),
        dy = Math.abs( y1 - y0 );

    // Steps.
    var sx = x0 < x1 ? 1 : -1,
        sy = y0 < y1 ? 1 : -1;

    var error = dx - dy;

    var error2;
    var cell, parameter;
    var i;
    while ( true ) {
      cell = grid[ y * count + x ];
      cell.type = CellType.BOUNDARY;

      // Populate boundary cell weights if empty.
      if ( !cell.weights.length ) {
        for ( i = 0; i < vertexCount; i++ ) {
          cell.weights.push(0);
        }
      }

      // Calculate weight.
      parameter = closestPointOnLineParameter( x, y, x0, y0, x1, y1 );
      cell.weights[ i0 ] = 1 - parameter;
      cell.weights[ i1 ] = parameter;

      if ( x === x1 && y === y1 ) {
        return;
      }

      error2 = 2 * error;
      if ( error2 > -dy ) {
        error -= dy;
        x += sx;
      }

      if ( error2 < dx ) {
        error += dx;
        y += sy;
      }
    }
  }

  /**
   * Flood fill to mark all EXTERIOR cells.
   *
   * Adapted from:
   * http://lodev.org/cgtutor/floodfill.html
   */
  function scanLineFill( grid, width, height, x, y ) {
    var stack = [
      [ x, y ]
    ];

    var point;
    var yi;
    var left, right;
    var leftIndex, rightIndex;
    while ( stack.length ) {
      point = stack.pop();
      x = point[0];
      y = point[1];
      yi = y;

      // Find top extent.
      while ( yi >= 0 && grid[ yi * width + x ].type === CellType.UNTYPED ) {
        yi--;
      }

      yi++;

      left = false;
      right = false;
      // Fill downwards.
      while ( yi < height && grid[ yi * width + x ].type === CellType.UNTYPED ) {
        grid[ yi * width + x ].type = CellType.EXTERIOR;

        // Check left/right neighbors for empty cells.
        // Left.
        if ( x > 0 ) {
          leftIndex = yi * width + ( x - 1 );
          if ( !left && grid[ leftIndex ].type === CellType.UNTYPED ) {
            // Push segemnt start.
            stack.push( [ x - 1, yi ] );
            left = true;
          } else if ( left && grid[ leftIndex ].type !== CellType.UNTYPED ) {
            // End segment.
            left = false;
          }
        }

        // Right.
        if ( x < width - 1 ) {
          rightIndex = yi * width + ( x + 1 );
          if ( !right && grid[ rightIndex ].type === CellType.UNTYPED ) {
            // Push segemnt start.
            stack.push( [ x + 1, yi ] );
            right = true;
          } else if ( right && grid[ rightIndex ].type !== CellType.UNTYPED ) {
            // End segment.
            right = false;
          }
        }

        yi++;
      }
    }
  }

  function dimensions( vertices ) {
    var xmin = Number.POSITIVE_INFINITY,
        ymin = Number.POSITIVE_INFINITY,
        xmax = Number.NEGATIVE_INFINITY,
        ymax = Number.NEGATIVE_INFINITY;

    var x, y;
    for ( var i = 0, il = 0.5 * vertices.length; i < il; i++ ) {
      x = vertices[ 2 * i ];
      y = vertices[ 2 * i + 1 ];

      if ( x < xmin ) { xmin = x; }
      if ( x > xmax ) { xmax = x; }
      if ( y < ymin ) { ymin = y; }
      if ( y > ymax ) { ymax = y; }
    }

    return {
      x: xmin,
      y: ymin,
      width: xmax - xmin,
      height: ymax - ymin
    };
  }

  function convert2d( x, y, vertices ) {
    var vertexCount = 0.5 * vertices.length;
    var aabb = dimensions( vertices );

    var cellCount = config.cellCount;

    var scaleX = cellCount / aabb.width,
        scaleY = cellCount / aabb.height;

    var cells = [];

    var i, il;
    for ( i = 0, il = cellCount * cellCount; i < il; i++ ) {
      cells.push({
        type: CellType.UNTYPED,
        weights: []
      });
    }

    // Determine boundaries.
    var xmin = aabb.x,
        ymin = aabb.y;

    var x0, y0, x1, y1;
    for ( i = 0; i < vertexCount; i++ ) {
      x0 = vertices[ 2 * i ];
      y0 = vertices[ 2 * i + 1 ];
      x1 = vertices[ 2 * ( ( i + 1 ) % vertexCount ) ];
      y1 = vertices[ 2 * ( ( i + 1 ) % vertexCount ) + 1 ];

      // Normalize line to grid.
      x0 = Math.floor( clamp( ( x0 - xmin ) * scaleX, 0, cellCount - 1 ) );
      y0 = Math.floor( clamp( ( y0 - ymin ) * scaleY, 0, cellCount - 1 ) );
      x1 = Math.floor( clamp( ( x1 - xmin ) * scaleX, 0, cellCount - 1 ) );
      y1 = Math.floor( clamp( ( y1 - ymin ) * scaleY, 0, cellCount - 1 ) );

      // Draw boundary line and initialize weights array of boundary cells.
      bresenham(
        cells, cellCount,
        x0, y0, x1, y1,
        i, ( i + 1 ) % vertexCount,
        vertexCount
      );
    }

    /**
     * Flood fill from edges.
     *
     * Starting from each corner, we move clockwise amd flood-fill from
     * UNTYPED cells.
     *
     * We end at cellCount - 1 to avoid re-flood-filling starting corners.
     */
    var j;
    var lastIndex = cellCount - 1;
    for ( i = 0; i < lastIndex; i++ ) {
      // Top left to top right.
      if ( cells[i].type === CellType.UNTYPED ) {
        scanLineFill( cells, cellCount, cellCount, i, 0 );
      }

      // Top right to bottom right.
      if ( cells[ i * cellCount + lastIndex ].type === CellType.UNTYPED ) {
        scanLineFill( cells, cellCount, cellCount, lastIndex, i );
      }

      j = cellCount - i - 1;
      // Bottom right to bottom left.
      if ( cells[ lastIndex * cellCount + j ].type === CellType.UNTYPED ) {
        scanLineFill( cells, cellCount, cellCount, j, lastIndex );
      }

      // Bottom left to top left.
      if ( cells[ j * cellCount ].type === CellType.UNTYPED ) {
        scanLineFill( cells, cellCount, cellCount, 0, j );
      }
    }

    // Mark all interior cells.
    var weights = [];
    for ( i = 0; i < vertexCount; i++ ) {
      weights.push(0);
    }

    for ( i = 0, il = cellCount * cellCount; i < il; i++ ) {
      if ( cells[i].type === CellType.UNTYPED ) {
        cells[i].type = CellType.INTERIOR;
        cells[i].weights = weights.slice();
      }
    }

    return {
      cells: cells,
      width: 1 / scaleX,
      height: 1 / scaleY
    };
  }

  return {
    CellType: CellType,
    dimensions: dimensions,

    config: config,
    convert2d: convert2d
  };
}) ();
<commit_msg>harmonic: Add Laplacian smoothing function.<commit_after>/*jshint bitwise: false*/
/*exported Harmonic*/
var Harmonic = (function() {
  'use strict';

  var config = {
    // Cell count on a side.
    cellCount: Math.pow( 2, 6 )
  };

  var CellType = {
    UNTYPED: 1,
    BOUNDARY: 2,
    INTERIOR: 4,
    EXTERIOR: 8
  };

  function clamp( value, min, max ) {
    return Math.min( Math.max( value, min ), max );
  }

  /**
   * Find the parameter of the point (x, y) as projected on the line segment
   * form by (x0, y0) - (x1, y1).
   */
  function closestPointOnLineParameter( x, y, x0, y0, x1, y1 ) {
    var dx = x1 - x0,
        dy = y1 - y0;

    // Check for line degeneracy.
    if ( !dx && !dy ) {
      return null;
    }

    var lengthSquared = dx * dx + dy * dy;

    return ( ( x - x0 ) * ( x1 - x0 ) + ( y - y0 ) * ( y1 - y0 ) ) / lengthSquared;
  }

  /**
   * Marks all cells which lie on the Bresenham line rasterization as
   * BOUNDARY cells.
   *
   * Scan-converts the univariate linear B-spline basis function
   * ("hat function" basis) for cell vertex weights.
   *   - The basis function is linearly interpolated from 1 at the primary
   *     vertex to 0 at the previous/next vertices:
   *
   *                                o              1
   *                              /   \
   *                            /       \
   *                     -----o           o-----   0
   *     vertex index:   (i - 1)    i    (i + 1)
   *
   * Vertices are expected to be normalized to grid units. That is, a grid
   * cell will have world dimensions equal to column width and row height, but
   * local dimensions of 1 by 1.
   *
   * i0 and i1 are vertex weight indices.
   *
   * Assumes a square grid.
   */
  function bresenham( grid, count, x0, y0, x1, y1, i0, i1, vertexCount ) {
    var x = x0,
        y = y0;

    var dx = Math.abs( x1 - x0 ),
        dy = Math.abs( y1 - y0 );

    // Steps.
    var sx = x0 < x1 ? 1 : -1,
        sy = y0 < y1 ? 1 : -1;

    var error = dx - dy;

    var error2;
    var cell, parameter;
    var i;
    while ( true ) {
      cell = grid[ y * count + x ];
      cell.type = CellType.BOUNDARY;

      // Populate boundary cell weights if empty.
      if ( !cell.weights.length ) {
        for ( i = 0; i < vertexCount; i++ ) {
          cell.weights.push(0);
        }
      }

      // Calculate weight.
      parameter = closestPointOnLineParameter( x, y, x0, y0, x1, y1 );
      cell.weights[ i0 ] = 1 - parameter;
      cell.weights[ i1 ] = parameter;

      if ( x === x1 && y === y1 ) {
        return;
      }

      error2 = 2 * error;
      if ( error2 > -dy ) {
        error -= dy;
        x += sx;
      }

      if ( error2 < dx ) {
        error += dx;
        y += sy;
      }
    }
  }

  /**
   * Flood fill to mark all EXTERIOR cells.
   *
   * Adapted from:
   * http://lodev.org/cgtutor/floodfill.html
   */
  function scanLineFill( grid, width, height, x, y ) {
    var stack = [
      [ x, y ]
    ];

    var point;
    var yi;
    var left, right;
    var leftIndex, rightIndex;
    while ( stack.length ) {
      point = stack.pop();
      x = point[0];
      y = point[1];
      yi = y;

      // Find top extent.
      while ( yi >= 0 && grid[ yi * width + x ].type === CellType.UNTYPED ) {
        yi--;
      }

      yi++;

      left = false;
      right = false;
      // Fill downwards.
      while ( yi < height && grid[ yi * width + x ].type === CellType.UNTYPED ) {
        grid[ yi * width + x ].type = CellType.EXTERIOR;

        // Check left/right neighbors for empty cells.
        // Left.
        if ( x > 0 ) {
          leftIndex = yi * width + ( x - 1 );
          if ( !left && grid[ leftIndex ].type === CellType.UNTYPED ) {
            // Push segemnt start.
            stack.push( [ x - 1, yi ] );
            left = true;
          } else if ( left && grid[ leftIndex ].type !== CellType.UNTYPED ) {
            // End segment.
            left = false;
          }
        }

        // Right.
        if ( x < width - 1 ) {
          rightIndex = yi * width + ( x + 1 );
          if ( !right && grid[ rightIndex ].type === CellType.UNTYPED ) {
            // Push segemnt start.
            stack.push( [ x + 1, yi ] );
            right = true;
          } else if ( right && grid[ rightIndex ].type !== CellType.UNTYPED ) {
            // End segment.
            right = false;
          }
        }

        yi++;
      }
    }
  }

  /**
   * Laplacian smooth.
   */
  function smooth( cells, width, vertexCount ) {
    // Empty temporary array to prevent reading undefined arrays.
    var empty = [];

    var sum, sumDifference;
    var meanDifference = Number.POSITIVE_INFINITY;
    var count = cells.length;
    var left, right, top, bottom;
    var cell;
    var x, y;
    var i, j;
    for ( i = 0; i < count; i++ ) {
      cell = cells[i];
      cell.previousWeights = cell.weights.slice();

      if ( cell.type !== CellType.INTERIOR ) {
        continue;
      }

      x = i % width;
      y = Math.floor( i / width );

      // Left.
      left = cells[ y * width + ( x - 1 ) ];
      left = left ? left.previousWeights : empty;
      // Right.
      right = cells[ y * width + ( x + 1 ) ];
      right = right ? right.previousWeights : empty;
      // Top.
      top = cells[ ( y - 1 ) * width + x ];
      top = top ? top.previousWeights : empty;
      // Bottom.
      bottom = cells[ ( y + 1 ) * width + x ];
      bottom = bottom ? bottom.previousWeights : empty;

      for ( j = 0; j < vertexCount; j++ ) {
        sum =  left[j]   || 0;
        sum += bottom[j] || 0;
        sum += top[j]    || 0;
        sum += right[j]  || 0;
        // Normalize.
        sum *= 0.25;

        cell.weights[j] = sum;
      }
    }
  }

  function dimensions( vertices ) {
    var xmin = Number.POSITIVE_INFINITY,
        ymin = Number.POSITIVE_INFINITY,
        xmax = Number.NEGATIVE_INFINITY,
        ymax = Number.NEGATIVE_INFINITY;

    var x, y;
    for ( var i = 0, il = 0.5 * vertices.length; i < il; i++ ) {
      x = vertices[ 2 * i ];
      y = vertices[ 2 * i + 1 ];

      if ( x < xmin ) { xmin = x; }
      if ( x > xmax ) { xmax = x; }
      if ( y < ymin ) { ymin = y; }
      if ( y > ymax ) { ymax = y; }
    }

    return {
      x: xmin,
      y: ymin,
      width: xmax - xmin,
      height: ymax - ymin
    };
  }

  function convert2d( x, y, vertices ) {
    var vertexCount = 0.5 * vertices.length;
    var aabb = dimensions( vertices );

    var cellCount = config.cellCount;

    var scaleX = cellCount / aabb.width,
        scaleY = cellCount / aabb.height;

    var cells = [];

    var i, il;
    for ( i = 0, il = cellCount * cellCount; i < il; i++ ) {
      cells.push({
        type: CellType.UNTYPED,
        previousWeights: [],
        weights: []
      });
    }

    // Determine boundaries.
    var xmin = aabb.x,
        ymin = aabb.y;

    var x0, y0, x1, y1;
    for ( i = 0; i < vertexCount; i++ ) {
      x0 = vertices[ 2 * i ];
      y0 = vertices[ 2 * i + 1 ];
      x1 = vertices[ 2 * ( ( i + 1 ) % vertexCount ) ];
      y1 = vertices[ 2 * ( ( i + 1 ) % vertexCount ) + 1 ];

      // Normalize line to grid.
      x0 = Math.floor( clamp( ( x0 - xmin ) * scaleX, 0, cellCount - 1 ) );
      y0 = Math.floor( clamp( ( y0 - ymin ) * scaleY, 0, cellCount - 1 ) );
      x1 = Math.floor( clamp( ( x1 - xmin ) * scaleX, 0, cellCount - 1 ) );
      y1 = Math.floor( clamp( ( y1 - ymin ) * scaleY, 0, cellCount - 1 ) );

      // Draw boundary line and initialize weights array of boundary cells.
      bresenham(
        cells, cellCount,
        x0, y0, x1, y1,
        i, ( i + 1 ) % vertexCount,
        vertexCount
      );
    }

    /**
     * Flood fill from edges.
     *
     * Starting from each corner, we move clockwise amd flood-fill from
     * UNTYPED cells.
     *
     * We end at cellCount - 1 to avoid re-flood-filling starting corners.
     */
    var j;
    var lastIndex = cellCount - 1;
    for ( i = 0; i < lastIndex; i++ ) {
      // Top left to top right.
      if ( cells[i].type === CellType.UNTYPED ) {
        scanLineFill( cells, cellCount, cellCount, i, 0 );
      }

      // Top right to bottom right.
      if ( cells[ i * cellCount + lastIndex ].type === CellType.UNTYPED ) {
        scanLineFill( cells, cellCount, cellCount, lastIndex, i );
      }

      j = cellCount - i - 1;
      // Bottom right to bottom left.
      if ( cells[ lastIndex * cellCount + j ].type === CellType.UNTYPED ) {
        scanLineFill( cells, cellCount, cellCount, j, lastIndex );
      }

      // Bottom left to top left.
      if ( cells[ j * cellCount ].type === CellType.UNTYPED ) {
        scanLineFill( cells, cellCount, cellCount, 0, j );
      }
    }

    // Mark all interior cells.
    var weights = [];
    for ( i = 0; i < vertexCount; i++ ) {
      weights.push(0);
    }

    var cell;
    for ( i = 0, il = cells.length; i < il; i++ ) {
      cell = cells[i];
      if ( cell.type === CellType.UNTYPED ) {
        cell.type = CellType.INTERIOR;
        cell.previousWeights = weights.slice();
        cell.weights = weights.slice();
      }
    }

    smooth( cells, cellCount, vertexCount );

    return {
      cells: cells,
      width: 1 / scaleX,
      height: 1 / scaleY
    };
  }

  return {
    CellType: CellType,
    dimensions: dimensions,

    config: config,
    convert2d: convert2d
  };
}) ();
<|endoftext|>


<commit_before>import Browser from 'mobiledoc-kit/utils/browser';
import Component from '@ember/component';
import layout from '../templates/components/koenig-card';
import {computed} from '@ember/object';
import {htmlSafe} from '@ember/string';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';

const TICK_HEIGHT = 8;

export default Component.extend({
    koenigUi: service(),

    layout,
    attributeBindings: ['_style:style'],
    classNameBindings: ['selectedClass'],

    // attrs
    editor: null,
    icon: null,
    iconClass: 'ih5 absolute stroke-midgrey-l2 mt1 nl15 kg-icon',
    toolbar: null,
    isSelected: false,
    isEditing: false,
    hasEditMode: true,
    headerOffset: 0,
    showSelectedOutline: true,

    // properties
    showToolbar: false,
    toolbarWidth: 0,
    toolbarHeight: 0,

    // internal properties
    _lastIsEditing: false,

    // closure actions
    selectCard() {},
    deselectCard() {},
    editCard() {},
    // hooks - when attached these will be fired on the individual card components
    onSelect() {},
    onDeselect() {},
    onEnterEdit() {},
    onLeaveEdit() {},

    shouldShowToolbar: computed('showToolbar', 'koenigUi.{captionHasFocus,isDragging}', function () {
        return this.showToolbar && !this.koenigUi.captionHasFocus && !this.koenigUi.isDragging;
    }),

    toolbarStyle: computed('shouldShowToolbar', 'toolbarWidth', 'toolbarHeight', function () {
        let showToolbar = this.shouldShowToolbar;
        let width = this.toolbarWidth;
        let height = this.toolbarHeight;
        let styles = [];

        styles.push(`top: -${height}px`);
        styles.push(`left: calc(50% - ${width / 2}px)`);

        if (!showToolbar) {
            styles.push('pointer-events: none !important');
        }

        return htmlSafe(styles.join('; '));
    }),

    iconTop: computed('headerOffset', function () {
        return this.headerOffset + 24;
    }),

    selectedClass: computed('isSelected', 'showSelectedOutline', function () {
        return this.isSelected && this.showSelectedOutline ? 'kg-card-selected' : '';
    }),

    didReceiveAttrs() {
        this._super(...arguments);

        let isSelected = this.isSelected;
        let isEditing = this.isEditing;
        let hasEditMode = this.hasEditMode;

        // TODO: replace with Spirit classes
        let baseStyles = 'cursor: default; caret-color: auto;';
        this.set('_style', htmlSafe(`${baseStyles} ${this.style}`));

        if (isSelected !== this._lastIsSelected) {
            if (isSelected) {
                this._fireWhenRendered(this._onSelect);
            } else {
                this._fireWhenRendered(this._onDeselect);
            }
        }

        if (isEditing !== this._lastIsEditing) {
            if (!hasEditMode) {
                isEditing = false;
            } else if (isEditing) {
                this._onEnterEdit();
            } else {
                this._onLeaveEdit();
            }
        }

        // show the toolbar immediately if it changes whilst the card is selected
        // caters for situations such as only showing image style buttons once an
        // image has been uploaded
        if (isSelected && this._lastIsSelected && this.toolbar && this.toolbar !== this._lastToolbar) {
            run.scheduleOnce('afterRender', this, this._showToolbar);
        }

        this._lastIsSelected = isSelected;
        this._lastIsEditing = isEditing;
        this._lastToolbar = this.toolbar;
    },

    didInsertElement() {
        this._super(...arguments);
        this._setToolbarProperties();
        this._createMutationObserver(
            this.element,
            run.bind(this, this._inputFocus),
            run.bind(this, this._inputBlur)
        );
    },

    willDestroyElement() {
        this._super(...arguments);
        window.removeEventListener('keydown', this._onKeydownHandler);
        window.removeEventListener('click', this._onClickHandler);
        this._removeMousemoveHandler();

        if (this._mutationObserver) {
            this._mutationObserver.disconnect();
        }

        if (this._hasDisabledContenteditable) {
            this.editor.element.contentEditable = true;
        }
    },

    mouseDown(event) {
        let {isSelected, isEditing, hasEditMode} = this;

        // if we perform an action we want to prevent the mousedown from
        // triggering a cursor position change which can result in multiple
        // card select calls getting the component into an odd state. We also
        // manually show the toolbar so that we're not relying on mousemove
        if (!isSelected && !isEditing) {
            this.selectCard();
            this.set('showToolbar', true);

            // in most situations we want to prevent default behaviour which
            // can cause an underlying cursor position change but inputs and
            // textareas are different and we want the focus to move to them
            // immediately when clicked
            let targetTagName = event.target.tagName;
            let allowedTagNames = ['INPUT', 'TEXTAREA'];
            let allowClickthrough = !!event.target.closest('[data-kg-allow-clickthrough]');
            if (!allowedTagNames.includes(targetTagName) && !allowClickthrough) {
                event.preventDefault();
            }

            // don't trigger edit mode immediately
            this._skipMouseUp = true;
        }

        // don't trigger select->edit transition for clicks in the caption or
        // when clicking out of the caption
        if (isSelected && hasEditMode) {
            let allowClickthrough = !!event.target.closest('[data-kg-allow-clickthrough]');
            if (allowClickthrough || this.koenigUi.captionHasFocus) {
                this._skipMouseUp = true;
            }
        }
    },

    // lazy-click to enter edit mode
    mouseUp(event) {
        let {isSelected, isEditing, hasEditMode, _skipMouseUp} = this;

        if (!_skipMouseUp && hasEditMode && isSelected && !isEditing && !this.koenigUi.isDragging) {
            this.editCard();
            this.set('showToolbar', true);
            event.preventDefault();
        }

        this._skipMouseUp = false;
    },

    doubleClick() {
        let allowClickthrough = !!event.target.closest('[data-kg-allow-clickthrough]');
        if (this.hasEditMode && !this.isEditing && !allowClickthrough) {
            this.editCard();
            this.set('showToolbar', true);
        }
    },

    _onSelect() {
        this._fireWhenRendered(this._showToolbar);
        this._showToolbar();
        this.onSelect();

        this._onClickHandler = run.bind(this, this._handleClick);
        window.addEventListener('click', this._onClickHandler);
    },

    _onDeselect() {
        window.removeEventListener('click', this._onClickHandler);
        this._hideToolbar();
        this.onDeselect();
    },

    _onEnterEdit() {
        this._onKeydownHandler = run.bind(this, this._handleKeydown);
        window.addEventListener('keydown', this._onKeydownHandler);

        // store a copy of the payload for later comparison
        this._snapshotPayload = JSON.stringify(this.payload);

        this.onEnterEdit();
    },

    _onLeaveEdit() {
        window.removeEventListener('keydown', this._onKeydownHandler);

        // if the payload has changed since entering edit mode then store a snapshot
        let newPayload = JSON.stringify(this.payload);
        if (newPayload !== this._snapshotPayload) {
            this.editor.run(() => {
                this.saveCard(this.payload);
            });
        }

        delete this._snapshotPayload;

        this.onLeaveEdit();
    },

    _setToolbarProperties() {
        if (this.toolbar) {
            // select the last toolbar in the element because card contents/captions
            // may have their own toolbar elements
            let toolbar = this.element.querySelector(':scope > [data-kg-toolbar="true"]');
            let {width, height} = toolbar.getBoundingClientRect();

            this.setProperties({
                toolbarWidth: width,
                toolbarHeight: height + TICK_HEIGHT
            });
        }
    },

    _showToolbar() {
        // only show a toolbar if we have one
        if (this.toolbar) {
            this._setToolbarProperties();

            if (!this.showToolbar && !this._onMousemoveHandler) {
                this._onMousemoveHandler = run.bind(this, this._handleMousemove);
                window.addEventListener('mousemove', this._onMousemoveHandler);
            }
        }
    },

    _hideToolbar() {
        this.set('showToolbar', false);
        this._removeMousemoveHandler();
    },

    _handleKeydown(event) {
        if (
            this.isEditing
            && event.key === 'Escape'
            || (Browser.isMac() && event.key === 'Enter' && event.metaKey)
            || (!Browser.isMac() && event.key === 'Enter' && event.ctrlKey)
        ) {
            // run the select card routine with isEditing=false to exit edit mode
            this.selectCard(false);
            event.preventDefault();
        }
    },

    // exit edit mode any time we have a click outside of the card unless it's
    // a click inside one of our modals or on the plus menu
    _handleClick(event) {
        let {target, path} = event;

        // Safari doesn't expose MouseEvent.path
        if (!path) {
            path = event.composedPath();
        }

        let searchPath = function (selector) {
            return element => element.closest && element.closest(selector);
        };

        // check if the click was in the card, on the plus menu, or on a modal
        if (this.element.contains(target)
            || path.find(searchPath(`#${this.element.id}`))
            || path.find(searchPath('[data-kg="plus-menu"]'))
            || path.find(searchPath('.liquid-destination'))) {
            return;
        }

        // if an element in the editor is clicked then cursor placement will
        // deselect or keep this card selected as necessary
        if (this.editor.element.contains(target)) {
            return;
        }

        this.deselectCard();
    },

    _handleMousemove() {
        if (!this.showToolbar) {
            this.set('showToolbar', true);
            this._removeMousemoveHandler();
        }
    },

    _removeMousemoveHandler() {
        window.removeEventListener('mousemove', this._onMousemoveHandler);
        this._onMousemoveHandler = null;
    },

    // convenience method for when we only want to run a method when our
    // elements have been rendered
    _fireWhenRendered(method) {
        if (this.element) {
            run.bind(this, method)();
        } else {
            run.scheduleOnce('afterRender', this, method);
        }
    },

    // Firefox can't handle inputs inside of a contenteditable element so we
    // need to watch for any inputs being added so that we can attach focus/blur
    // event handlers that can disable contenteditable on the editor element
    _createMutationObserver(target, focusCallback, blurCallback) {
        function addInputFocusListeners(mutation) {
            function addInputFocusListener(element) {
                if (!inputElements.includes(element)) {
                    inputElements.push(element);
                    element.addEventListener('focus', focusCallback, false);
                    element.addEventListener('blur', blurCallback, false);
                }
            }

            if (mutation.type === 'childList') {
                Array.prototype.forEach.call(
                    mutation.target.querySelectorAll('input[type="text"]'),
                    addInputFocusListener
                );
            }
        }

        function removeFromElements(element) {
            inputElements.splice(inputElements.indexOf(element), 1);
        }

        function removeInputFocusListener(element) {
            element.removeEventListener('focus', focusCallback, false);
            element.removeEventListener('blur', blurCallback, false);
            removeFromElements(element);
        }

        function mutationObserved(mutations) {
            mutations.forEach(addInputFocusListeners);
        }

        function createMutationObserver(target) {
            let config = {
                childList: true,
                subtree: true
            };

            let observer = new MutationObserver(mutationObserved);
            observer.observe(target, config); // eslint-disable-line ghost/ember/no-observers
            return observer;
        }

        let inputElements = [];
        let observer = createMutationObserver(target);

        return {
            disconnect() {
                if ('disconnect' in observer) {
                    observer.disconnect(); // eslint-disable-line ghost/ember/no-observers
                    inputElements.forEach(removeInputFocusListener);
                }
            }
        };
    },

    _inputFocus() {
        this._hasDisabledContenteditable = true;
        this.editor.element.contentEditable = false;
    },

    _inputBlur() {
        this._hasDisabledContenteditable = false;
        this.editor.element.contentEditable = true;
    }
});
<commit_msg>Fixed "undefined" appearing in markdown card styles<commit_after>import Browser from 'mobiledoc-kit/utils/browser';
import Component from '@ember/component';
import layout from '../templates/components/koenig-card';
import {computed} from '@ember/object';
import {htmlSafe} from '@ember/string';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';

const TICK_HEIGHT = 8;

export default Component.extend({
    koenigUi: service(),

    layout,
    attributeBindings: ['_style:style'],
    classNameBindings: ['selectedClass'],

    // attrs
    editor: null,
    icon: null,
    iconClass: 'ih5 absolute stroke-midgrey-l2 mt1 nl15 kg-icon',
    toolbar: null,
    isSelected: false,
    isEditing: false,
    hasEditMode: true,
    headerOffset: 0,
    showSelectedOutline: true,

    // properties
    showToolbar: false,
    toolbarWidth: 0,
    toolbarHeight: 0,

    // internal properties
    _lastIsEditing: false,

    // closure actions
    selectCard() {},
    deselectCard() {},
    editCard() {},
    // hooks - when attached these will be fired on the individual card components
    onSelect() {},
    onDeselect() {},
    onEnterEdit() {},
    onLeaveEdit() {},

    shouldShowToolbar: computed('showToolbar', 'koenigUi.{captionHasFocus,isDragging}', function () {
        return this.showToolbar && !this.koenigUi.captionHasFocus && !this.koenigUi.isDragging;
    }),

    toolbarStyle: computed('shouldShowToolbar', 'toolbarWidth', 'toolbarHeight', function () {
        let showToolbar = this.shouldShowToolbar;
        let width = this.toolbarWidth;
        let height = this.toolbarHeight;
        let styles = [];

        styles.push(`top: -${height}px`);
        styles.push(`left: calc(50% - ${width / 2}px)`);

        if (!showToolbar) {
            styles.push('pointer-events: none !important');
        }

        return htmlSafe(styles.join('; '));
    }),

    iconTop: computed('headerOffset', function () {
        return this.headerOffset + 24;
    }),

    selectedClass: computed('isSelected', 'showSelectedOutline', function () {
        return this.isSelected && this.showSelectedOutline ? 'kg-card-selected' : '';
    }),

    didReceiveAttrs() {
        this._super(...arguments);

        let isSelected = this.isSelected;
        let isEditing = this.isEditing;
        let hasEditMode = this.hasEditMode;

        // TODO: replace with Spirit classes
        let baseStyles = 'cursor: default; caret-color: auto;';
        this.set('_style', htmlSafe(`${baseStyles} ${this.style || ''}`));

        if (isSelected !== this._lastIsSelected) {
            if (isSelected) {
                this._fireWhenRendered(this._onSelect);
            } else {
                this._fireWhenRendered(this._onDeselect);
            }
        }

        if (isEditing !== this._lastIsEditing) {
            if (!hasEditMode) {
                isEditing = false;
            } else if (isEditing) {
                this._onEnterEdit();
            } else {
                this._onLeaveEdit();
            }
        }

        // show the toolbar immediately if it changes whilst the card is selected
        // caters for situations such as only showing image style buttons once an
        // image has been uploaded
        if (isSelected && this._lastIsSelected && this.toolbar && this.toolbar !== this._lastToolbar) {
            run.scheduleOnce('afterRender', this, this._showToolbar);
        }

        this._lastIsSelected = isSelected;
        this._lastIsEditing = isEditing;
        this._lastToolbar = this.toolbar;
    },

    didInsertElement() {
        this._super(...arguments);
        this._setToolbarProperties();
        this._createMutationObserver(
            this.element,
            run.bind(this, this._inputFocus),
            run.bind(this, this._inputBlur)
        );
    },

    willDestroyElement() {
        this._super(...arguments);
        window.removeEventListener('keydown', this._onKeydownHandler);
        window.removeEventListener('click', this._onClickHandler);
        this._removeMousemoveHandler();

        if (this._mutationObserver) {
            this._mutationObserver.disconnect();
        }

        if (this._hasDisabledContenteditable) {
            this.editor.element.contentEditable = true;
        }
    },

    mouseDown(event) {
        let {isSelected, isEditing, hasEditMode} = this;

        // if we perform an action we want to prevent the mousedown from
        // triggering a cursor position change which can result in multiple
        // card select calls getting the component into an odd state. We also
        // manually show the toolbar so that we're not relying on mousemove
        if (!isSelected && !isEditing) {
            this.selectCard();
            this.set('showToolbar', true);

            // in most situations we want to prevent default behaviour which
            // can cause an underlying cursor position change but inputs and
            // textareas are different and we want the focus to move to them
            // immediately when clicked
            let targetTagName = event.target.tagName;
            let allowedTagNames = ['INPUT', 'TEXTAREA'];
            let allowClickthrough = !!event.target.closest('[data-kg-allow-clickthrough]');
            if (!allowedTagNames.includes(targetTagName) && !allowClickthrough) {
                event.preventDefault();
            }

            // don't trigger edit mode immediately
            this._skipMouseUp = true;
        }

        // don't trigger select->edit transition for clicks in the caption or
        // when clicking out of the caption
        if (isSelected && hasEditMode) {
            let allowClickthrough = !!event.target.closest('[data-kg-allow-clickthrough]');
            if (allowClickthrough || this.koenigUi.captionHasFocus) {
                this._skipMouseUp = true;
            }
        }
    },

    // lazy-click to enter edit mode
    mouseUp(event) {
        let {isSelected, isEditing, hasEditMode, _skipMouseUp} = this;

        if (!_skipMouseUp && hasEditMode && isSelected && !isEditing && !this.koenigUi.isDragging) {
            this.editCard();
            this.set('showToolbar', true);
            event.preventDefault();
        }

        this._skipMouseUp = false;
    },

    doubleClick() {
        let allowClickthrough = !!event.target.closest('[data-kg-allow-clickthrough]');
        if (this.hasEditMode && !this.isEditing && !allowClickthrough) {
            this.editCard();
            this.set('showToolbar', true);
        }
    },

    _onSelect() {
        this._fireWhenRendered(this._showToolbar);
        this._showToolbar();
        this.onSelect();

        this._onClickHandler = run.bind(this, this._handleClick);
        window.addEventListener('click', this._onClickHandler);
    },

    _onDeselect() {
        window.removeEventListener('click', this._onClickHandler);
        this._hideToolbar();
        this.onDeselect();
    },

    _onEnterEdit() {
        this._onKeydownHandler = run.bind(this, this._handleKeydown);
        window.addEventListener('keydown', this._onKeydownHandler);

        // store a copy of the payload for later comparison
        this._snapshotPayload = JSON.stringify(this.payload);

        this.onEnterEdit();
    },

    _onLeaveEdit() {
        window.removeEventListener('keydown', this._onKeydownHandler);

        // if the payload has changed since entering edit mode then store a snapshot
        let newPayload = JSON.stringify(this.payload);
        if (newPayload !== this._snapshotPayload) {
            this.editor.run(() => {
                this.saveCard(this.payload);
            });
        }

        delete this._snapshotPayload;

        this.onLeaveEdit();
    },

    _setToolbarProperties() {
        if (this.toolbar) {
            // select the last toolbar in the element because card contents/captions
            // may have their own toolbar elements
            let toolbar = this.element.querySelector(':scope > [data-kg-toolbar="true"]');
            let {width, height} = toolbar.getBoundingClientRect();

            this.setProperties({
                toolbarWidth: width,
                toolbarHeight: height + TICK_HEIGHT
            });
        }
    },

    _showToolbar() {
        // only show a toolbar if we have one
        if (this.toolbar) {
            this._setToolbarProperties();

            if (!this.showToolbar && !this._onMousemoveHandler) {
                this._onMousemoveHandler = run.bind(this, this._handleMousemove);
                window.addEventListener('mousemove', this._onMousemoveHandler);
            }
        }
    },

    _hideToolbar() {
        this.set('showToolbar', false);
        this._removeMousemoveHandler();
    },

    _handleKeydown(event) {
        if (
            this.isEditing
            && event.key === 'Escape'
            || (Browser.isMac() && event.key === 'Enter' && event.metaKey)
            || (!Browser.isMac() && event.key === 'Enter' && event.ctrlKey)
        ) {
            // run the select card routine with isEditing=false to exit edit mode
            this.selectCard(false);
            event.preventDefault();
        }
    },

    // exit edit mode any time we have a click outside of the card unless it's
    // a click inside one of our modals or on the plus menu
    _handleClick(event) {
        let {target, path} = event;

        // Safari doesn't expose MouseEvent.path
        if (!path) {
            path = event.composedPath();
        }

        let searchPath = function (selector) {
            return element => element.closest && element.closest(selector);
        };

        // check if the click was in the card, on the plus menu, or on a modal
        if (this.element.contains(target)
            || path.find(searchPath(`#${this.element.id}`))
            || path.find(searchPath('[data-kg="plus-menu"]'))
            || path.find(searchPath('.liquid-destination'))) {
            return;
        }

        // if an element in the editor is clicked then cursor placement will
        // deselect or keep this card selected as necessary
        if (this.editor.element.contains(target)) {
            return;
        }

        this.deselectCard();
    },

    _handleMousemove() {
        if (!this.showToolbar) {
            this.set('showToolbar', true);
            this._removeMousemoveHandler();
        }
    },

    _removeMousemoveHandler() {
        window.removeEventListener('mousemove', this._onMousemoveHandler);
        this._onMousemoveHandler = null;
    },

    // convenience method for when we only want to run a method when our
    // elements have been rendered
    _fireWhenRendered(method) {
        if (this.element) {
            run.bind(this, method)();
        } else {
            run.scheduleOnce('afterRender', this, method);
        }
    },

    // Firefox can't handle inputs inside of a contenteditable element so we
    // need to watch for any inputs being added so that we can attach focus/blur
    // event handlers that can disable contenteditable on the editor element
    _createMutationObserver(target, focusCallback, blurCallback) {
        function addInputFocusListeners(mutation) {
            function addInputFocusListener(element) {
                if (!inputElements.includes(element)) {
                    inputElements.push(element);
                    element.addEventListener('focus', focusCallback, false);
                    element.addEventListener('blur', blurCallback, false);
                }
            }

            if (mutation.type === 'childList') {
                Array.prototype.forEach.call(
                    mutation.target.querySelectorAll('input[type="text"]'),
                    addInputFocusListener
                );
            }
        }

        function removeFromElements(element) {
            inputElements.splice(inputElements.indexOf(element), 1);
        }

        function removeInputFocusListener(element) {
            element.removeEventListener('focus', focusCallback, false);
            element.removeEventListener('blur', blurCallback, false);
            removeFromElements(element);
        }

        function mutationObserved(mutations) {
            mutations.forEach(addInputFocusListeners);
        }

        function createMutationObserver(target) {
            let config = {
                childList: true,
                subtree: true
            };

            let observer = new MutationObserver(mutationObserved);
            observer.observe(target, config); // eslint-disable-line ghost/ember/no-observers
            return observer;
        }

        let inputElements = [];
        let observer = createMutationObserver(target);

        return {
            disconnect() {
                if ('disconnect' in observer) {
                    observer.disconnect(); // eslint-disable-line ghost/ember/no-observers
                    inputElements.forEach(removeInputFocusListener);
                }
            }
        };
    },

    _inputFocus() {
        this._hasDisabledContenteditable = true;
        this.editor.element.contentEditable = false;
    },

    _inputBlur() {
        this._hasDisabledContenteditable = false;
        this.editor.element.contentEditable = true;
    }
});
<|endoftext|>


<commit_before><%= app_name %>.Templates = {
    <%= formatted_templates.join(",\n\t") %>
}<commit_msg>Added semi-colon to templates<commit_after><%= app_name %>.Templates = {
    <%= formatted_templates.join(",\n\t") %>
};<|endoftext|>


<commit_before>'use strict';

function draw_logic(){
    // Draw layers.
    var loop_counter = layers.length - 1;
    do{
        if(loop_counter <= 0){
            break;
        }

        // Draw layer.
        canvas_buffer.fillStyle = layers[loop_counter]['color'];
        canvas_buffer.fillRect(
          layers[loop_counter]['x'],
          layers[loop_counter]['y'],
          100,
          100
        );
    }while(loop_counter--);
}

function generate_layers(){
    layers.length = 0;

    // Generate 100 layers.
    var loop_counter = 99;
    do{
        layers.push({
          'color': '#' + random_hex(),
          'x': random_integer({
            'max': canvas_width,
          }) - 50,
          'y': random_integer({
            'max': canvas_height,
          }) - 50,
        });
    }while(loop_counter--);

    update_target();
}

function logic(){
    var loop_counter = layers.length - 1;
    do{
        if(loop_counter <= 0){
            break;
        }

        // Calculate movement towards previous layer.
        var previous = loop_counter - 1;
        var speed = math_move_2d({
          'multiplier': 3,
          'x0': layers[loop_counter]['x'],
          'y0': layers[loop_counter]['y'],
          'x1': layers[previous]['x'],
          'y1': layers[previous]['y'],
        });

        // Move towards previous layer.
        layers[loop_counter]['x'] += speed['x'];
        layers[loop_counter]['y'] += speed['y'];
    }while(loop_counter--);
}

function update_target(){
    layers[0]['x'] = input_mouse['x'] - 50;
    layers[0]['y'] = input_mouse['y'] - 50;
}

var layers = [];

window.onload = function(){
    canvas_init();
    input_init({
      'keybinds': {
        'all': {
          'todo': generate_layers,
        },
      },
      'mousebinds': {
        'mousedown': {
          'todo': function(){
              generate_layers();
              update_target();
          },
        },
        'mousemove': {
          'todo': update_target,
        },
      },
    });

    generate_layers();
};
<commit_msg>added layer_size and layer_speed<commit_after>'use strict';

function draw_logic(){
    // Draw layers.
    var loop_counter = layers.length - 1;
    do{
        if(loop_counter <= 0){
            break;
        }

        // Draw layer.
        canvas_buffer.fillStyle = layers[loop_counter]['color'];
        canvas_buffer.fillRect(
          layers[loop_counter]['x'],
          layers[loop_counter]['y'],
          layer_size,
          layer_size
        );
    }while(loop_counter--);
}

function generate_layers(){
    layers.length = 0;

    // Generate 100 layers.
    var loop_counter = 99;
    do{
        layers.push({
          'color': '#' + random_hex(),
          'x': random_integer({
            'max': canvas_width,
          }) - layer_size / 2,
          'y': random_integer({
            'max': canvas_height,
          }) - layer_size / 2,
        });
    }while(loop_counter--);

    update_target();
}

function logic(){
    var loop_counter = layers.length - 1;
    do{
        if(loop_counter <= 0){
            break;
        }

        // Calculate movement towards previous layer.
        var previous = loop_counter - 1;
        var speed = math_move_2d({
          'multiplier': layer_speed,
          'x0': layers[loop_counter]['x'],
          'y0': layers[loop_counter]['y'],
          'x1': layers[previous]['x'],
          'y1': layers[previous]['y'],
        });

        // Move towards previous layer.
        layers[loop_counter]['x'] += speed['x'];
        layers[loop_counter]['y'] += speed['y'];
    }while(loop_counter--);
}

function update_target(){
    layers[0]['x'] = input_mouse['x'] - layer_size / 2;
    layers[0]['y'] = input_mouse['y'] - layer_size / 2;
}

var layer_size = 100;
var layer_speed = 3;
var layers = [];

window.onload = function(){
    canvas_init();
    input_init({
      'keybinds': {
        'all': {
          'todo': generate_layers,
        },
      },
      'mousebinds': {
        'mousedown': {
          'todo': function(){
              generate_layers();
              update_target();
          },
        },
        'mousemove': {
          'todo': update_target,
        },
      },
    });

    generate_layers();
};
<|endoftext|>