"use strict";
/* creepily adorable */
var GO_Paola = function(){
	this.sprite = new Sprite(GO_Paola.spriteSheet,"Paola");
	this.sprite.collision_flags = 
		//DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
		//DEFINE_SPRITE_COLLISION_FLAGS.AIR |
		DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_ACTIVE |
		DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE;
	this.sprite.setBoundingBox(2,0,13,15);
	//sprite.constraints=constraints;
	this.sprite.max_step = 2;
	this.sprite.game_object = this; // no longer a generic GO

	this.hp = 6;
	this.infection = 1;
	this.smoke = [];

	this.controls = new Controls(); // just to init

	this.leftward_move_water = this.d_leftward_move_water;
	this.rightward_move_water = this.d_rightward_move_water;
	this.upward_move_water = this.d_upward_move_water;
	this.downward_move_water = this.d_downward_move_water;
	this.horizontal_move_index=0;
	this.vertical_move_index = 0;

	this.anim_state = this.ANIM_STATES.bob;

	this.control_state = this.CONTROL_STATES.prefight;
	this.control_timer = 0;
	this.last_pattern = 0;
	this.pattern_time = 0;
	this.pattern_duration = 0;

	// patterns get shorter after each use
	this.pattern1tally = 0;
	this.pattern2tally = 0;
	this.pattern3tally = 0;

	this.frame_timer=0;

	this.direction = 1; // +/-1 for facing

	this.target = null;
	this.grace = null;
	this.targetFind=false; // she probably won't be in the map when we init; hopefully when we update

	this.clones = [
		{x:0,y:0, direction:1},
		{x:0,y:0, direction:1},
		{x:0,y:0, direction:1},
		{x:0,y:0, direction:1}
	];
	this.clone_index=0;

	this.barriers = [];

	// for Gracie hit check
	this._heap.penetration = {x:0, y:0};

	// for pattern 4
	this.fragile=false;
	this.gravity_index = 0;

	this.alreadyHit = []; // things we hit while falling; don't process them again

	this.push_counter = 0;

	this.resistance = 1;

	this.seen_push = 0;

	this.held=false;
};
GO_Paola.spriteImg = SDS_Load_Image("art/sheets/sprite/ghostboss.png");
GO_Paola.spriteSheet = new TileSheet(4, 4, 2, 2, GO_Paola.spriteImg);

GO_Paola.prototype = new GameObject(
	new Sprite(
		GO_Paola.spriteSheet,
		"Paola"
	),
	"Paola"
	);

	GO_Paola.prototype.interactions = 
		DEFINE_GAMEOBJECT_INTERACTIONS.CONTROL |
		DEFINE_GAMEOBJECT_INTERACTIONS.CHECK;

	GO_Paola.prototype.checkEvent = function(sourceGO){
		if (sourceGO && sourceGO.sprite && this.control_state!=this.CONTROL_STATES.postfight) this.direction = (sourceGO.sprite.x<this.sprite.x) ? -1 : 1;

		if (!GLOBAL_DIARY.check(2,"MET_PAOLA")) return "Paola_meet_paola";
		else if (GLOBAL_DIARY.check(2,"BOSS_GOOD") && !GLOBAL_DIARY.hasSoul("PAOLA")) return "Paola_revisit";
		else if (this.control_state==this.CONTROL_STATES.prefight) return "Paola_bossfight_1";
		else if (this.control_state==this.CONTROL_STATES.postfight) return "Paola_bossfight_2";
		
		return null;
	};

	// default speeds
	GO_Paola.prototype.d_leftward_move_water = [0,-1,-1];
	GO_Paola.prototype.d_rightward_move_water = [0,1,1];
	GO_Paola.prototype.d_upward_move_water = [0,-1,-1];
	GO_Paola.prototype.d_downward_move_water = [0,1,1];

	GO_Paola.prototype.ANIM_STATES = {
		"bob" : 0,
		"swim" : 1,
		"tickle" : 2,
		"freeze" : 3,
	};
	GO_Paola.prototype.CONTROL_STATES = {
		"prefight" : 0,
		"pattern1" : 1, // watcher in the weeds
		"pattern2" : 2, // ring around the rosie
		"pattern3" : 3, // tag
		"pattern4" : 4, // mary had a little clam
		"split" : 5,
		"postfight" : 6
	};
	GO_Paola.prototype.anim_frames = [
		[0,0,1,1], //"bob" : 
		[0,1,0,2], //"swim" : 
		[3], //"tickle" : 
		[7], //"freeze" 
	];

	GO_Paola.prototype.startFight = function(){
		for (this._heap.i=0; this._heap.i<4; ++this._heap.i){
			this.barriers[this._heap.i] = new GO_Forceblock();

			this.barriers[this._heap.i].sprite.x = 25<<4;
			this.barriers[this._heap.i].sprite.y = (8+this._heap.i)<<4;
			this.barriers[this._heap.i].core.x = 25<<4;
			this.barriers[this._heap.i].core.y = (8+this._heap.i)<<4;

			//this.sprite.map_room.addSprite(this.barriers[this._heap.i].sprite);
			//this.sprite.map_room.addSprite(this.barriers[this._heap.i].core);
			this.barriers[this._heap.i].addToRoom(this.sprite.map_room);
			this.manager.add(this.barriers[this._heap.i]);
		}

		this.switchPattern1();
	};

	GO_Paola.prototype.endFight = function(){
		SDS.bgmName = null;
		SDS.bgm.stop();
		//SDS.bgm = new Chiptune(SDS.bgmName,SDS.bgmchip);
		//SDS.bgm.play(true);
		
		this.control_state = this.CONTROL_STATES.postfight;
		this.controls.held.up=false;
		this.controls.held.down=false;
		this.controls.held.left=false;
		this.controls.held.right=false;

		this.sprite.collision_flags = 
			DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
			DEFINE_SPRITE_COLLISION_FLAGS.AIR |
			//DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_ACTIVE |
			DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE;
		this.interactions = 
			DEFINE_GAMEOBJECT_INTERACTIONS.CHECK;
	};

	GO_Paola.prototype.cleanupFight = function(){

		if (this.grace && this.grace.hp>0){
			this.grace.target_name="Passage_Out"; // or the treasure...
			this.grace.target=null;
		}
		else if (this.grace){
			this._heap.poof = new GO_Poof();
			this._heap.poof.spawnOnSprite(this.grace.sprite,this.manager);
			this._heap.poof=null;//pending pooling

			this.grace.sprite.map_room.removeSprite(this.grace.sprite);
			this.grace.manager._remove(this.grace); // outside the update loop, so do it immediately
		}

		this._heap._necklace = new GO_Necklace();
		this._heap._necklace.sprite.x = (13<<4)+8;
		this._heap._necklace.sprite.y = (9<<4)+8;
		this.sprite.map_room.addSprite(this._heap._necklace.sprite);
		this.manager.add(this._heap._necklace);
		this._heap._necklace=null;

		for (this._heap.i=0; this._heap.i<4; ++this._heap.i){
			//this.sprite.map_room.removeSprite(this.barriers[this._heap.i].sprite);
			//this.sprite.map_room.removeSprite(this.barriers[this._heap.i].core);
			this.barriers[this._heap.i].clearFromRoom(this.sprite.map_room);
			this.manager._remove(this.barriers[this._heap.i]); // outside the update loop, so do it immediately
			this.barriers[this._heap.i] = null;
		}

		if (this.grace && this.grace.hp>0){
			this.dropSoul();
		}
		else{
			this._heap.poof = new GO_Poof();
			this._heap.poof.spawnOnSprite(this.sprite,this.manager);
			this._heap.poof=null;//pending pooling

			this.sprite.map_room.removeSprite(this.sprite);
			this.manager._remove(this); // outside the update loop, so do it immediately
		}
	};

	GO_Paola.prototype.dropSoul = function(){

		this._heap.soul = new GO_Soul("PAOLA");
		this._heap.soul.spawnOnSprite(this.sprite,this.manager);
		this._heap.soul=null;//pending pooling

		this._heap.poof = new GO_Poof();
		this._heap.poof.spawnOnSprite(this.sprite,this.manager);
		this._heap.poof=null;//pending pooling

		this.sprite.map_room.removeSprite(this.sprite);
		this.manager._remove(this); // outside the update loop, so do it immediately
	};

	// Enemy-style coroutines
	GO_Paola.prototype.damage = function(source,points){
		this.hp-=points+1; // points should always be 0 (kickwave)
		

		this._heap.cough = new GO_Smoke();
		this._heap.cough.sprite.x = this.sprite.x;
		this._heap.cough.sprite.y = this.sprite.y;
		//this._heap.cough.launch_dir = {x:this.direction, y:0};
		this._heap.cough.launch_dir.x=0;
		this._heap.cough.launch_dir.y=0;
		this._heap.cough.host_obj = this;

		this.sprite.map_room.addSprite(this._heap.cough.sprite);
		this.manager.add(this._heap.cough);
		this.smoke.push(this._heap.cough);
		this._heap.cough=null;//pending pooling

		//this.infection--;

		if (this.hp>0){
			this.anim_state = this.ANIM_STATES.tickle;
			this.switchSplit();
		}
		return (this.hp<=0);
	};
	GO_Paola.prototype._inflictVal = {hp:1, chi:8};
	GO_Paola.prototype.inflict = function(){
		this.switchSplit();
		return this._inflictVal;
	};

	GO_Paola.prototype.removeSmoke = function(smoke){
		var index = this.smoke.indexOf(smoke);
		if (index!=-1){
			this.smoke.splice(index,1);
			smoke.host_obj=null;
		}
	};
	GO_Paola.prototype.infect = function(){
		//this.infection++;
		this.hp+=1;
	};

	GO_Paola.prototype.tagGracie = function(){
		if (this.grace){
			this.grace.hp--;

			SDS.dlgMgr.open("Grace_c2_hp_"+this.grace.hp,function(index,retval){
				if (retval!=null){
					
				}
			},true);

			if (this.grace.hp<=0) this.endFight();
		}
	}

	GO_Paola.prototype.aiControl = function(){
		switch (this.control_state){
			case this.CONTROL_STATES.prefight:
				this.controlled();
			break;
			case this.CONTROL_STATES.pattern1:
				this.pattern1();
			break;
			case this.CONTROL_STATES.pattern2:
				this.pattern2();
			break;
			case this.CONTROL_STATES.pattern3:
				this.pattern3();
			break;
			case this.CONTROL_STATES.pattern4:
				this.pattern4();
			break;
			case this.CONTROL_STATES.split:
				this.split();
			break;
			case this.CONTROL_STATES.postfight:
				this.controlled();
			break;
			default:
				this.controlled();
			break;
		}
	};

	GO_Paola.prototype.controlled = function(){
		// generic mob style control update
		this._heap.dx = 0;
		this._heap.dy = 0;
		//var old_xs = [];
		//var new_xs = [];
		//var dxs = [];
		//var old_ys = [];
		//var new_ys = [];
		//var dys = [];

		this._heap.leftMoveArr = null;
		this._heap.rightMoveArr = null;
		this._heap.upMoveArr = null;
		this._heap.downMoveArr = null;

		this._heap.oldAnimState = this.anim_state;

		this._heap.i=0;

		
		this.anim_state = this.ANIM_STATES.bob;


		if (this.controls.held.A ){	

		}
		else if (this.controls.held.B){
			
		}
		else{
			this.NPCSwim(this.anim_state);
		}
		

		if (this._heap.oldAnimState != this.anim_state){
			this.frame_timer=0;
		}
		this.frame_timer++;
		this._heap.aniFrame = (this.frame_timer>>2);
		if (this.anim_state==this.ANIM_STATES.swim || this.anim_state==this.ANIM_STATES.bob){
			this._heap.aniFrame = this._heap.aniFrame% this.anim_frames[this.anim_state].length;
		}
		else{
			this._heap.aniFrame = Math.min(this._heap.aniFrame,this.anim_frames[this.anim_state].length-1);
		}

		this.sprite.frame = this.anim_frames[this.anim_state][this._heap.aniFrame];

		this.sprite.frame = this.sprite.frame & 7;
		if (this.direction<0) this.sprite.frame+=8;

		if (this.anim_state==this.ANIM_STATES.swim && (this.control_state==this.CONTROL_STATES.prefight || this.control_state==this.CONTROL_STATES.postfight) ){
			this.sprite.visible = !!(this.frame_timer&1);
		}
		else{
			this.sprite.visible=true;
		}
	}

	GO_Paola.prototype.switchPattern1 = function(){
		this.control_timer = 0;

		this.clone_index = 0;

		this.horizontal_move_index = 0;
		this.vertical_move_index = 0;

		this.control_state = this.CONTROL_STATES.pattern1;
		this.pattern_duration = this.pattern1times[this.pattern1tally];
		SDS.dlgMgr.open("Paola_c2_pattern1_"+this.pattern1tally,function(index,retval){
			if (retval!=null){
				
			}
		},true);


		this.sprite.collision_flags = 
			//DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
			//DEFINE_SPRITE_COLLISION_FLAGS.AIR |
			DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE;
		this.interactions = 0;
			//DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
			//DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;

		this.leftward_move_water = this.p1_leftward_move_water;
		this.rightward_move_water = this.p1_rightward_move_water;
		this.upward_move_water = this.p1_upward_move_water;
		this.downward_move_water = this.p1_downward_move_water;

		this.last_pattern = this.control_state;
	}
	// ghost accel pattern, to give time to react
	GO_Paola.prototype.p1_leftward_move_water = [0,
		-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,
		-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,
		-1,-1,-1,-1,-1,-1,-1,
		-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,
		-2,-2,-2,-2,-2,-2,-2,
		-3,-2,-3,-2,-3,-2,-3,-2,-3,-2,
		-3];
	GO_Paola.prototype.p1_rightward_move_water = [0,
		1,0,0,1,0,0,1,0,0,1,0,0,
		1,0,1,0,1,0,1,0,1,0,1,0,
		1,1,1,1,1,1,1,
		2,1,2,1,2,1,2,1,2,1,
		2,2,2,2,2,2,2,
		3,2,3,2,3,2,3,2,3,2,
		3];
	GO_Paola.prototype.p1_upward_move_water = [0,
		-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,
		-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,
		-1,-1,-1,-1,-1,-1,-1,
		-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,
		-2,-2,-2,-2,-2,-2,-2,
		-3,-2,-3,-2,-3,-2,-3,-2,-3,-2,
		-3];
	GO_Paola.prototype.p1_downward_move_water = [0,
		1,0,0,1,0,0,1,0,0,1,0,0,
		1,0,1,0,1,0,1,0,1,0,1,0,
		1,1,1,1,1,1,1,
		2,1,2,1,2,1,2,1,2,1,
		2,2,2,2,2,2,2,
		3,2,3,2,3,2,3,2,3,2,
		3];

	// watcher in the weeds
	//GO_Paola.prototype.pattern1time = 320; //460
	GO_Paola.prototype.pattern1times = [320, 200, 80];
	GO_Paola.prototype.pattern1 = function(){
		if (!this.target) return;
		++this.control_timer;
		this.pattern_time=this.control_timer;
		if (this.control_timer<=this.pattern_duration){
			for (this._heap.i=0; this._heap.i<this.clones.length; ++this._heap.i){
				this._heap.clone=this.clones[this._heap.i];
				this._heap.angle = ((this.control_timer<<1) + (this._heap.i<<6))&255;
				// calculations assume Paola is the same size as target
				//this._heap.clone.direction = this.target.sprite.x+(SIN[this._heap.angle]>>3) > this._heap.x ? 1 : 0;
				this._heap.clone.direction = COS[this._heap.angle]>0 ? 1 : -1;
				this._heap.clone.x = this.target.sprite.x+(SIN[this._heap.angle]>>2);
				this._heap.clone.y = this.target.sprite.y+(COS[this._heap.angle]>>2);
			}
			this._heap.clone=null;

			this.clone_index = (this.clone_index+1)&3;


			this.anim_state=this.ANIM_STATES.swim;
			this.handleCloneSprite();
			
			if (this.control_timer==this.pattern_duration){
				// fix our default x/y to that of the clone x-furthest behind the target
				this.clone_index=0;
				this._heap.dx1 = this.target.sprite.x - this.clones[this.clone_index].x;
				this._heap.dx1 *= this.target.direction;
				for (this._heap.i=1; this._heap.i<this.clones.length; ++this._heap.i){
					this._heap.dx2 = this.target.sprite.x - this.clones[this._heap.i].x;
					this._heap.dx2 *= this.target.direction;

					if (this._heap.dx2 > this._heap.dx1){
						this.clone_index=this._heap.i;
						this._heap.dx1 = this._heap.dx2;
					}
				}

				this.sprite.x = this.clones[this.clone_index].x;
				this.sprite.y = this.clones[this.clone_index].y;
				this.direction = this.target.direction;

				this.interactions |= 
					DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
					DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;

				if (this.pattern1tally<this.pattern1times.length-1) ++this.pattern1tally;
			}
		}
		else{
			this.controls.held.left = this.target.sprite.x < this.sprite.x;
			this.controls.held.right = this.target.sprite.x > this.sprite.x;
			if (this.controls.held.left) this.horizontal_move_index = Math.min(0,this.horizontal_move_index);
			if (this.controls.held.right) this.horizontal_move_index = Math.max(0,this.horizontal_move_index);
			this.controls.held.up = this.target.sprite.y < this.sprite.y;
			this.controls.held.down = this.target.sprite.y > this.sprite.y;
			if (this.controls.held.up) this.vertical_move_index = Math.min(0,this.vertical_move_index);
			if (this.controls.held.down) this.vertical_move_index = Math.max(0,this.vertical_move_index);

			this.controlled();

			// test for hit
			this.sprite.testCollision(this.target.sprite, 0,0, this._heap.penetration);
			if (this._heap.penetration.x!=0 && this._heap.penetration.y!=0){
				this.switchSplit();
				this.tagGracie();
			}
		}
	}


	GO_Paola.prototype.switchPattern2 = function(){
		this.control_timer = 0;

		this.clone_index = 0;

		this.horizontal_move_index = 0;
		this.vertical_move_index = 0;

		for (this._heap.i=0; this._heap.i<this.clones.length; ++this._heap.i){
			this.clones[this._heap.i].y = 64;//(4<<4);
		}

		this.control_state = this.CONTROL_STATES.pattern2;
		this.pattern_duration = this.pattern2times[this.pattern2tally];
		SDS.dlgMgr.open("Paola_c2_pattern2_"+this.pattern2tally,function(index,retval){
			if (retval!=null){
				
			}
		},true);


		this.sprite.collision_flags = 
			//DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
			//DEFINE_SPRITE_COLLISION_FLAGS.AIR |
			DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE;
		this.interactions = 0;
			//DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
			//DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;

		this.leftward_move_water = this.p2_leftward_move_water;
		this.rightward_move_water = this.p2_rightward_move_water;
		this.upward_move_water = this.p2_upward_move_water;
		this.downward_move_water = this.p2_downward_move_water;

		this.last_pattern = this.control_state;
	}
	// falling accel pattern, to give chance of non-insta-kill
	GO_Paola.prototype.p2_leftward_move_water = [0,-1];
	GO_Paola.prototype.p2_rightward_move_water = [0,1];
	GO_Paola.prototype.p2_upward_move_water = [0,
		-1, 0, 0,
		-1, 0,
		-1,
		-2,
		-3];
	GO_Paola.prototype.p2_downward_move_water = [0,
		1,0,0,
		1,0,
		1,
		2,
		3];

	// ring around the gracie
	//GO_Paola.prototype.pattern2time = 250;//345
	GO_Paola.prototype.pattern2times = [250, 220, 120];
	GO_Paola.prototype.pattern2 = function(){
		if (!this.target) return;
		++this.control_timer;
		this.pattern_time=this.control_timer;
		if (this.control_timer<=this.pattern_duration){
			for (this._heap.i=0; this._heap.i<this.clones.length; ++this._heap.i){
				this._heap.clone=this.clones[this._heap.i];
				this._heap.angle = ((this.control_timer<<1) + (this._heap.i<<6))&255;
				// calculations assume Paola is the same size as target
				//this._heap.clone.direction = this.target.sprite.x+(SIN[this._heap.angle]>>3) > this._heap.x ? 1 : 0;
				this._heap.clone.direction = COS[this._heap.angle]>0 ? 1 : -1;
				this._heap.clone.x = 216+(SIN[this._heap.angle]);
				//this._heap.clone.y = 64+(COS[this._heap.angle]>>4);
				this._heap.clone.y = 180 - (this.control_timer>>1) + (COS[this._heap.angle]>>4);//236-
			}
			this._heap.clone=null;

			this.clone_index = (this.clone_index+1)&3;


			this.anim_state=this.ANIM_STATES.swim;
			this.handleCloneSprite();
			
			if (this.control_timer==this.pattern_duration){
				// fix our default x/y to that of the clone furthest from directly overhead.
				// was nearest-to, but that resulted in some insta-kills
				this.clone_index=0;
				this._heap.dx1 = Math.abs(this.target.sprite.x - this.clones[this.clone_index].x);
				
				for (this._heap.i=1; this._heap.i<this.clones.length; ++this._heap.i){
					this._heap.dx2 = Math.abs(this.target.sprite.x - this.clones[this._heap.i].x);

					if (this._heap.dx2 > this._heap.dx1){
						this.clone_index=this._heap.i;
						this._heap.dx1 = this._heap.dx2;
					}
				}

				this.sprite.x = this.clones[this.clone_index].x;
				this.sprite.y = this.clones[this.clone_index].y;
				this.direction = this.target.direction;

				this.interactions |= 
					DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
					DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;

				if (this.pattern2tally<this.pattern2times.length-1) ++this.pattern2tally;
			}
		}
		else{
			this.controls.held.left = this.target.sprite.x < this.sprite.x;
			this.controls.held.right = this.target.sprite.x > this.sprite.x;
			if (this.controls.held.left) this.horizontal_move_index = Math.min(0,this.horizontal_move_index);
			if (this.controls.held.right) this.horizontal_move_index = Math.max(0,this.horizontal_move_index);
			
			this.controls.held.down = true;
			this.controls.held.up = false;

			this.controlled();

			// test for hit
			this.sprite.testCollision(this.target.sprite, 0,0, this._heap.penetration);
			if (this._heap.penetration.x!=0 && this._heap.penetration.y!=0){
				this.switchSplit();
				this.tagGracie();
			}
			else{
				if (this.sprite.y>(17<<4)) this.sprite.y-=(16<<4)
			}
		}
	}

	GO_Paola.prototype.switchPattern3 = function(){
		this.control_timer = 0;

		this.clone_index = 0;

		this.horizontal_move_index = 0;
		this.vertical_move_index = 0;

		this.control_state = this.CONTROL_STATES.pattern3;
		this.pattern_duration = this.pattern3times[this.pattern3tally];
		SDS.dlgMgr.open("Paola_c2_pattern3_"+this.pattern3tally,function(index,retval){
			if (retval!=null){
				
			}
		},true);

		this.clones[0].x = (4<<4);
		this.clones[0].y = (4<<4);
		this.clones[0].direction=1;
		this.clones[1].x = (23<<4);
		this.clones[1].y = (4<<4);
		this.clones[1].direction=-1;
		this.clones[2].x = (23<<4);
		this.clones[2].y = (14<<4);
		this.clones[2].direction=-1;
		this.clones[3].x = (4<<4);
		this.clones[3].y = (14<<4);
		this.clones[3].direction=1;


		this.sprite.collision_flags = 
			//DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
			//DEFINE_SPRITE_COLLISION_FLAGS.AIR |
			DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE;
		this.interactions = 0;
			//DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
			//DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;

		this.leftward_move_water = this.p3_leftward_move_water;
		this.rightward_move_water = this.p3_rightward_move_water;
		this.upward_move_water = this.p3_upward_move_water;
		this.downward_move_water = this.p3_downward_move_water;

		this.last_pattern = this.control_state;
	}
	// ghost accel pattern, to give time to react
	GO_Paola.prototype.p3_leftward_move_water = [0,
		-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,
		-1,-1,-1,-1,-1,-1,-1,
		-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,
		-2,-2,-2,-2,-2,-2,-2,
		-3,-2,-3,-2,-3,-2,-3,-2,-3,-2,
		-3];
	GO_Paola.prototype.p3_rightward_move_water = [0,
		1,0,1,0,1,0,1,0,1,0,1,0,
		1,1,1,1,1,1,1,
		2,1,2,1,2,1,2,1,2,1,
		2,2,2,2,2,2,2,
		3,2,3,2,3,2,3,2,3,2,
		3];
	GO_Paola.prototype.p3_upward_move_water = [0,
		-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,-1, 0,
		-1,-1,-1,-1,-1,-1,-1,
		-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,
		-2,-2,-2,-2,-2,-2,-2,
		-3,-2,-3,-2,-3,-2,-3,-2,-3,-2,
		-3];
	GO_Paola.prototype.p3_downward_move_water = [0,
		1,0,1,0,1,0,1,0,1,0,1,0,
		1,1,1,1,1,1,1,
		2,1,2,1,2,1,2,1,2,1,
		2,2,2,2,2,2,2,
		3,2,3,2,3,2,3,2,3,2,
		3];

	// lazy crab
	//GO_Paola.prototype.pattern3time = 220;//360
	GO_Paola.prototype.pattern3times = [220, 110, 60];
	GO_Paola.prototype.pattern3 = function(){
		if (!this.target) return;
		++this.control_timer;
		this.pattern_time=this.control_timer;
		if (this.control_timer<=this.pattern_duration){
			
			if (!(this.control_timer & 1)){
				++this.clones[0].x;
				++this.clones[0].y;
				--this.clones[1].x;
				++this.clones[1].y;
				--this.clones[2].x;
				--this.clones[2].y;
				++this.clones[3].x;
				--this.clones[3].y;
			}

			this.clone_index = (this.clone_index+1)&3;


			this.anim_state=this.ANIM_STATES.swim;
			this.handleCloneSprite();
			
			if (this.control_timer==this.pattern_duration){
				// fix our default x/y to that of the clone furthest from the target
				this.clone_index=0;
				this._heap.dx1 = Math.abs(this.target.sprite.x - this.clones[this.clone_index].x) + Math.abs(this.target.sprite.y - this.clones[this.clone_index].y);
				for (this._heap.i=1; this._heap.i<this.clones.length; ++this._heap.i){
					this._heap.dx2 = Math.abs(this.target.sprite.x - this.clones[this._heap.i].x) + Math.abs(this.target.sprite.y - this.clones[this._heap.i].y);

					if (this._heap.dx2 > this._heap.dx1){
						this.clone_index=this._heap.i;
						this._heap.dx1 = this._heap.dx2;
					}
				}

				this.sprite.x = this.clones[this.clone_index].x;
				this.sprite.y = this.clones[this.clone_index].y;
				//this.direction = this.target.direction;
				this.controls.held.left = this.target.controls.held.left;
				this.controls.held.right = !this.controls.held.left;
				this.controls.held.up = this.target.controls.held.up;
				this.controls.held.down = !this.controls.held.up;

				this.interactions |= 
					DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
					DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;
				this.sprite.collision_flags = 
					DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
					//DEFINE_SPRITE_COLLISION_FLAGS.AIR |
					DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE;

				if (this.pattern3tally<this.pattern3times.length-1) ++this.pattern3tally;
			}
		}
		else{
			this.controlled();

			if (this._heap.spriteMoveRes.flags & DEFINE_SPRITE_MOVE_RESULT_EJECTED_H){
				this.controls.held.left = !this.controls.held.left;
				this.controls.held.right = !this.controls.held.right;
				if (this.control_timer>510){
					this.controls.held.up = this.target.sprite.y < this.sprite.y;
					this.controls.held.down = !this.controls.held.up;
				}
			}
			if (this._heap.spriteMoveRes.flags & DEFINE_SPRITE_MOVE_RESULT_EJECTED_V){
				this.controls.held.up = !this.controls.held.up;
				this.controls.held.down = !this.controls.held.down;

				if (this.control_timer>510){
					this.controls.held.left = this.target.sprite.x < this.sprite.x;
					this.controls.held.right = !this.controls.held.left;
				}
			}

			// test for hit
			this.sprite.testCollision(this.target.sprite, 0,0, this._heap.penetration);
			if (this._heap.penetration.x!=0 && this._heap.penetration.y!=0){
				this.switchSplit();
				this.tagGracie();
			}
		}
	}

	GO_Paola.prototype.switchPattern4 = function(){
		this.control_timer = 0;
		
		this.clone_index = 0;

		this.horizontal_move_index = 0;
		this.vertical_move_index = 0;
		this.gravity_index = 0;
		this.fragile = false;

		this.alreadyHit.length=0; // things we hit while falling; don't process them again

		this.push_counter = 0;
		this.seen_push = 0;

		this.held=false;

		this.control_state = this.CONTROL_STATES.pattern4;
		this.pattern_duration = this.pattern4time;
		SDS.dlgMgr.open("Paola_c2_pattern4",function(index,retval){
			if (retval!=null){
				
			}
		},true);

//		this.clones[0].x = (9<<4);
//		this.clones[0].y = (9<<4)+8;
//		this.clones[0].direction=1;
//		this.clones[2].x = (9<<4);
//		this.clones[2].y = (9<<4)+8;
//		this.clones[2].direction=1;
//		this.clones[1].x = (18<<4);
//		this.clones[1].y = (9<<4)+8;
//		this.clones[1].direction=-1;
//		this.clones[3].x = (18<<4);
//		this.clones[3].y = (9<<4)+8;
//		this.clones[3].direction=-1;
		for (this._heap.i=0; this._heap.i<this.clones.length; ++this._heap.i){
			this.clones[this._heap.i].x = this.target.sprite.x;
			this.clones[this._heap.i].y = this.target.sprite.y;
			this.clones[this._heap.i].direction=this.target.direction;
		}


		this.sprite.collision_flags = 
			//DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
			//DEFINE_SPRITE_COLLISION_FLAGS.AIR |
			DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE;
		this.interactions = 0;
			//DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
			//DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;

		this.last_pattern = this.control_state;
	}

	GO_Paola.prototype.gravity_water = [ 
		1, 
		1, 1, 1, 
		2, 2, 2, 
		3, 3, 3, 3, 3, 3,
		4, 4, 4, 4, 4, 4, 
		5, 5, 5, 5, 5, 5,
		6, 6, 6, 6, 6, 6, 
		7];

	GO_Paola.prototype.weight = DEFINE_PROJECTILE_WEIGHT.MEDIUM;
	GO_Paola.prototype.hoistpoint = [
		{'x':13, 'y':8}, // grab point when moving direction -1
		{'x':3, 'y':8} // grab point when moving direction 1
	];
	GO_Paola.prototype.grab = function(){
		this.gravity_index=0;
		this.interactions &= ~DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;
		this.sprite.collision_flags |= DEFINE_SPRITE_COLLISION_FLAGS.SOLID;

		if (this.sfx && this.sfx.name=="FX_grind"){
			this.sfx.stop();
		}

		this.held=true;
	};
	GO_Paola.prototype.drop = function(){
		this.gravity_index=0;
		this.fragile=true;
		this.held=false;
	};
	GO_Paola.prototype.IndisposedUpdate = function(){
		
	};
	GO_Paola.prototype.Unindispose = function(dx, dy, moveRes){
		if (moveRes.flags & (DEFINE_SPRITE_MOVE_RESULT_EJECTED_H | DEFINE_SPRITE_MOVE_RESULT_EJECTED_V)){
			if (moveRes.flags & DEFINE_SPRITE_MOVE_RESULT_EJECTED_S){
				if (this.sfx) this.sfx.stop();
				this.anim_state=this.ANIM_STATES.bob;
				// thrown into the barriers counts as a hit
				this.damage(null,0);
			}
			else if (Math.abs(dx)+Math.abs(dy) > 1){
				if (this.sfx) this.sfx.stop();
				this.sfx = new Chiptune("FX_fallcrash",SDS.sfxchip);
				this.sfx.play(false);
				
				if (Math.abs(dx)+Math.abs(dy) > 3){
					if (this.sfx){
						this.sfx.stop();
					}

					// TODO: maybe counts as a hit
					this.anim_state=this.ANIM_STATES.tickle;
					this.switchSplit();
				}
			}
		}
	};
	GO_Paola.prototype.push = function(dx){
		if (dx>=0){
			this.push_counter++;
		}
		else{
			this.push_counter--;
		}
		if (this.push_counter>=this.resistance){
			this.sprite.move(1,0);
			this.push_counter-=this.resistance;
		}
		else if (this.push_counter<=-this.resistance){
			this.sprite.move(-1,0);
			this.push_counter+=this.resistance;
		}

		if (this.gravity_index<2) this.seen_push = 5; // 1 frame to catch up if it moves, 1 to account for update ordering, 3 to actually wait
		if (!this.sfx || this.sfx.name!="FX_grind"){
			this.sfx = new Chiptune("FX_grind",SDS.sfxchip);
		}
		if (!this.sfx.is_playing && !this.held){
			this.sfx.play(true);
		}
	};

	// mary had a little clam
	GO_Paola.prototype.pattern4time = 320;//360
	GO_Paola.prototype.pattern4 = function(){
		++this.control_timer;
		this.pattern_time=this.control_timer;
		if (this.control_timer<=this.pattern_duration){

			if (!(this.control_timer & 3)){
				for (this._heap.i=this.clones.length-1; this._heap.i>0; --this._heap.i){
					this.clones[this._heap.i].x = this.clones[this._heap.i-1].x;
					this.clones[this._heap.i].y = this.clones[this._heap.i-1].y;
					this.clones[this._heap.i].direction = this.clones[this._heap.i-1].direction;
				}
			}
			this.clones[0].x = this.target.sprite.x;
			this.clones[0].y = this.target.sprite.y;
			this.clones[0].direction=this.target.direction;

			this.clone_index = (this.clone_index+1)&3;
			this.handleCloneSprite();
			//if (this.clone_index & 2) this.anim_state=this.ANIM_STATES.freeze;
			//else this.anim_state=this.ANIM_STATES.swim;

//			if (this.control_timer<=this.pattern4time>>1) this.anim_state=this.ANIM_STATES.swim;
//			else this.anim_state=this.ANIM_STATES.freeze;
			
			if (this.control_timer==this.pattern_duration){
				// fix our default x/y to that of the clone furthest from the target
//				this.clone_index=0;
//				this._heap.dx1 = Math.abs(this.target.sprite.x - this.clones[this.clone_index].x) + Math.abs(this.target.sprite.y - this.clones[this.clone_index].y);
//				for (this._heap.i=1; this._heap.i<this.clones.length; ++this._heap.i){
//					this._heap.dx2 = Math.abs(this.target.sprite.x - this.clones[this._heap.i].x) + Math.abs(this.target.sprite.y - this.clones[this._heap.i].y);
//
//					if (this._heap.dx2 > this._heap.dx1){
//						this.clone_index=this._heap.i;
//						this._heap.dx1 = this._heap.dx2;
//					}
//				}

				this.clone_index = 3;//furthest tail

				this.sprite.x = this.clones[this.clone_index].x;
				this.sprite.y = this.clones[this.clone_index].y;
				this.direction = this.clones[this.clone_index].direction;

				this.interactions = 
					DEFINE_GAMEOBJECT_INTERACTIONS.GRAB |
					DEFINE_GAMEOBJECT_INTERACTIONS.PUSH;
				this.sprite.collision_flags = 
					DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
					DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_ACTIVE |
					DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE |
					DEFINE_SPRITE_COLLISION_FLAGS.SOLID;
				this.anim_state=this.ANIM_STATES.freeze;
				this._heap.aniFrame=0;

				this.sprite.frame = this.anim_frames[this.anim_state][this._heap.aniFrame];

				this.sprite.frame = this.sprite.frame & 7;
				if (this.direction<0) this.sprite.frame+=8;

				this.sprite.visible=true;
			}
		}
		else{
			// typical projectile code
			this._heap.gravityArray = this.gravity_water;

			if (this._heap.gravityArray[this.gravity_index] > 3){
				this.interactions |= DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;
				this.sprite.collision_flags &= ~DEFINE_SPRITE_COLLISION_FLAGS.SOLID;
			}
			else{
				this.interactions &= ~DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;
				this.sprite.collision_flags |= DEFINE_SPRITE_COLLISION_FLAGS.SOLID;
			}

			this.sprite.move(0,this._heap.gravityArray[this.gravity_index],  this._heap.spriteMoveRes);
			this._heap.broken = false;
			if (this._heap.spriteMoveRes.flags & DEFINE_SPRITE_MOVE_RESULT_EJECTED_V){
				if (this.gravity_index>4){
					if (this.sfx) this.sfx.stop();
					this.sfx = new Chiptune("FX_fallcrash",SDS.sfxchip);
					this.sfx.play(false);
				}

				this.alreadyHit.length=0;
				this._heap.broken = this._heap.broken || (this.fragile && this.gravity_index>12);
				this.gravity_index=0;
			}
			else{
				this.gravity_index = Math.min(this.gravity_index+1,this._heap.gravityArray.length-1);
			}

			//if (this._heap.spriteMoveRes.flags & DEFINE_SPRITE_MOVE_RESULT_EJECTED_H){
			//	this._heap.broken = this._heap.broken || this.fragile;
			//}

			this.seen_push--;
			if (this.seen_push<=0){
				this.seen_push=0;
				if (this.sfx && this.sfx.name=="FX_grind"){
					this.sfx.stop();
				}
			}
			

			if (this._heap.broken){
				if (this.sfx){
					this.sfx.stop();
				}

				// TODO: maybe counts as a hit
				this.anim_state=this.ANIM_STATES.tickle;
				this.switchSplit();
			}	
		}
	}


	GO_Paola.prototype.switchSplit = function(){
		this.playSound("FX_ouch");

		this.control_timer = 0;
		
		this.control_state = this.CONTROL_STATES.split;

		for (this._heap.i=0; this._heap.i<this.clones.length; ++this._heap.i){
			this.clones[this._heap.i].x = this.sprite.x;
			this.clones[this._heap.i].y = this.sprite.y;
		}
		this.clones[0].direction = -1;
		this.clones[1].direction = 1;
		this.clones[2].direction = 1;
		this.clones[3].direction = -1;
		this._heap.clone=null;
		this.clone_index=0;

		this.sprite.collision_flags = 
			//DEFINE_SPRITE_COLLISION_FLAGS.GROUND | 
			//DEFINE_SPRITE_COLLISION_FLAGS.AIR |
			DEFINE_SPRITE_COLLISION_FLAGS.SPRITES_PASSIVE;
		this.interactions = 0;
			//DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
			//DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;
	}
	GO_Paola.prototype.split = function(){
		if (this.control_timer<60){
			--this.clones[0].x;
			--this.clones[0].y;
			++this.clones[1].x;
			--this.clones[1].y;
			++this.clones[2].x;
			++this.clones[2].y;
			--this.clones[3].x;
			++this.clones[3].y;

			++this.control_timer;
			this.clone_index = (this.clone_index+1)&3;


			this.anim_state=this.ANIM_STATES.swim;
			this.handleCloneSprite();
		}
		else{
			switch (this.last_pattern){
				case this.CONTROL_STATES.pattern1:
					if (this.pattern_time < this.pattern_duration+30) this.switchPattern4();
					else if (this.target.direction>0) this.switchPattern2();
					else this.switchPattern3();
				break;
				case this.CONTROL_STATES.pattern2:
					if (this.pattern_time < this.pattern_duration+30) this.switchPattern4();
					else if (this.target.direction>0) this.switchPattern3();
					else this.switchPattern1();
				break;
				case this.CONTROL_STATES.pattern3:
					if (this.pattern_time < this.pattern_duration+30) this.switchPattern4();
					else if (this.target.direction>0) this.switchPattern1();
					else this.switchPattern2();
				break;
				case this.CONTROL_STATES.pattern4:
					if (this.target.direction>0) this.switchPattern1();
					else this.switchPattern2();
				break;
				default:
					this.switchPattern1();
				break;
			}
		}
	}

	GO_Paola.prototype.handleCloneSprite = function(){
		this.frame_timer++;
		this._heap.aniFrame = (this.frame_timer>>2);
		if (this.anim_state==this.ANIM_STATES.swim || this.anim_state==this.ANIM_STATES.bob){
			this._heap.aniFrame = this._heap.aniFrame% this.anim_frames[this.anim_state].length;
		}
		else{
			this._heap.aniFrame = Math.min(this._heap.aniFrame,this.anim_frames[this.anim_state].length-1);
		}

		this._heap.clone = this.clones[this.clone_index];
		this.sprite.x = this._heap.clone.x;
		this.sprite.y = this._heap.clone.y;

		this.sprite.frame = this.anim_frames[this.anim_state][this._heap.aniFrame];

		this.sprite.frame = this.sprite.frame & 7;
		if (this._heap.clone.direction<0) this.sprite.frame+=8;

		this.sprite.visible=true;

		this._heap.clone=null;
	}

	GO_Paola.prototype.Update = function(){
		// peaceful mob style target lookup
		if (!this.target && !this.targetFind){
			this.target = this.manager.getNamedObject("Grace");
			this.grace = this.target;
			
			// yeah, this used to be part of the design
			//if (this.target.hp<=0) this.target = this.manager.getNamedObject("Meli");
			//this.targetFind = true;
		}
		//if (this.meli){
		//	this.direction = (this.meli.sprite.x>this.sprite.x) ? 1 : -1;
		//}

		this.aiControl();

		

		// Enemy-style check HP and destroy
		// TODO: instead, throw an event
		if (this.hp<=0 && this.control_state!=this.CONTROL_STATES.postfight){

			while (this.smoke.length>0){
				//var s = this.smoke.pop();
				//if (s.state!="dissipate"){
				//	s.state="dissipate";
				//	s.state_timer = 0;
				//	s.frame_timer = 0;
				//	s.interactions = 0;
				//}
				if (this.smoke[0].state!="dissipate"){
					this.smoke[0].state="dissipate";
					this.smoke[0].state_timer = 0;
					this.smoke[0].frame_timer = 0;
					this.smoke[0].interactions = 0;
				}
				this.smoke.shift();
			}

			this.endFight();
		}
	};
	// does the basic make-dangerous-iff-infected check.
	// some enemies may want to be dangerous even when uninfected,
	// so let individual AIs handle the call.
	GO_Paola.prototype.toggleInteractionsStd = function(){
		if (this.infection>0){
			this.interactions |= 
				DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE |
				DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;
		}
		else{
			this.interactions &=
				~DEFINE_GAMEOBJECT_INTERACTIONS.DAMAGE &
				~DEFINE_GAMEOBJECT_INTERACTIONS.INFLICT;
		}
	};

