Keiko.lua

From Pocket Rumble Wiki
Jump to: navigation, search

keiko.lua[edit]

local catWidth = 12 * gameLogicMult;
local catXOffset = 4 * gameLogicMult;
Keiko = {
	moves = {
		standA = {
			attackbox = {pushback=189 * gameLogicMult, hitStun=12, width=17 * gameLogicMult, height=11 * gameLogicMult, dmg=1, relativeY=8 * gameLogicMult, explosionX = 3 * gameLogicMult, priority = 4};
			{
				frames = {1,2,2,1,3,1};
				custom = function(self)
					self:executeSound('lightWhiff', {"sfx", "whiff"})
				end
			};
			{
				type = "active";
				frames = {4,2,5,2};
				custom = function(self)
					self:executeEffect("standAEffect")
				end
			};
			{
				type = "recovery";
				frames = {6,2,7,1};
			};
		};
		lowA = {
			special=true;
			attackbox = {pushback=133 * gameLogicMult, hitStun=16, width=24 * gameLogicMult, height=11 * gameLogicMult, dmg=1, relativeY=25 * gameLogicMult, explosionX = -6, explosionY = 2, priority = 4};
			{
				frames = {1,2,2,2,3,1};
				custom = function(self)
					self:executeSound('mediumWhiff', {"sfx", "whiff"})
				end
			};
			{
				type = "active";
				frames = {4,2,5,2,6,2,7,3};
				custom = function(self)
					self:executeEffect("lowAEffect")
				end
			};
			{
				type = "recovery";
				frames = {9,2,10,2};
			};
		};
		standB = {
			special=true;
			attackbox = {pushback=220 * gameLogicMult, hitStun=18, width=25 * gameLogicMult, height=14 * gameLogicMult, relativeY = 12 * gameLogicMult, dmg=1, explosionX = -4 * gameLogicMult, explosionY = -1 * gameLogicMult,  priority = 3};
			{ --hitStun=16 pushback=220
				frames = {1,2,2,2,3,2,4,1}; --1,4,2,2,3,2  1,3,2,2,3,2
				custom = function(self)
					self:executeSound('mediumWhiff', {"sfx", "whiff"})
				end
			};
			{
				type = "active";
				frames = {6,2,7,2,6,2,7,2,8,2,9,2}; --12
				custom = function(self)
					self:executeEffect("standBEffect")
				end
			};
			{
				type = "recovery";
				frames = {10,2,12,2}; --5,1,6,2,7,2,8,2,9,1,10,1,11,3
			};
		};
		lowB = {
			special=true;
			attackbox = {pushUp = 130*gameLogicMult,pushback=60 * gameLogicMult, hitStun=17, width=30 * gameLogicMult, height=12 * gameLogicMult, dmg=1, relativeY=26 * gameLogicMult, explosionX = -8 - (4 * gameLogicMult), explosionY = 2, priority = 3};
			{
				frames = {1,1,2,2,3,2,4,1}; --6
				custom = function(self)
					self:executeSound('heavyWhiff', {"sfx", "whiff"})
				end
			};
			{
				type = "active";
				frames = {5,2,6,2,7,2,8,2,9,2,10,2,11,2,12,2}; --18
				custom = function(self)
					self:executeEffect("lowBEffect")
				end
			};
			{
				type = "recovery";
				frames = {13,2,14,4,15,4}; --8,3,9,3,10,3,11,3,12,3,13,3,14,3,15,3
			};
		};
		jumpA = {
			attackbox = {pushback=145 * gameLogicMult, hitStun=14, width=22 * gameLogicMult, height=11 * gameLogicMult, dmg=1, relativeY=22 * gameLogicMult,
			explosionX = -10 + (5 * gameLogicMult), priority = 4, ignoreCornerPush=true}; --hitstun=16,pushback=145
			{
				frames = {2,1,3,2,4,2,5,2}; --7
				custom = function(self)
					self.ABTimer = 0
					self:executeSound('mediumWhiff', {"sfx", "whiff"})
				end
			};
			{
				type = "active";
				frames = {6,2,7,2,8,2,9,2,6,2,7,1}; --11
				custom = function(self)
					self:executeEffect("jumpAEffect")
				end
			};
			{
				type = "recovery";
				frames = {10,2,11,3,12,2}; --7
			};
			endWith = function(self)
				self:executeAnimation("jumpA", {
				  frames={1,15};
				});
			end
		};
		jumpB = {
			attackbox = {pushback=44 * gameLogicMult, hitStun=20, width=11 * gameLogicMult, height=20 * gameLogicMult, dmg=1, relativeX= (-16 * gameLogicMult),
				relativeY=22 * gameLogicMult, explosionX = -4 * gameLogicMult,explosionY = 20, priority = 3, ignoreCornerPush=true}; --pushback=66 * gameLogicMult hitstun=23
			{ --hitstun=22
				frames = {2,2,4,3,5,2,6,2};--9
				custom = function(self)
					self.ABTimer = 0
					self:executeSound('mediumWhiff', {"sfx", "whiff"})
				end
			};
			{
				type = "active";
				frames = {7,2,8,2,9,2,10,2,11,2,12,2,13,1}; --4,5,5,5,4,5,5,5,4,5
				custom = function(self)
					self:executeEffect("jumpBEffect")
				end
			};
			{
				type = "recovery";
				frames = {19,3,20,2,21,2};
			};
			endWith = function(self)
				self:executeAnimation("jumpUp", {
				  frames={5,4,6,4,7,4,8,4,9,10};
				});
			end
		};
		-- neutralAB = {
		-- 	attackbox = {pushUp=200*gameLogicMult,pushback=44 * gameLogicMult, hitStun=20, width=70 * gameLogicMult, height=80 * gameLogicMult, dmg=0, relativeX= (-45 * gameLogicMult),
		-- 		relativeY=-20 * gameLogicMult, explosionX = -4 * gameLogicMult,explosionY = 20, priority = 3, ignoreCornerPush=true, resetY=false};
		-- 	{
		-- 		frames = {5,4};
		-- 		custom = function(self)
		-- 			self.ySpeed = -1000;
		-- 		end
		-- 	};
		-- 	{
		-- 		type = "active";
		-- 		frames = {5,5};
		-- 		custom = function(self)
		-- 			self.ignoreGravity = true
		-- 			self.ySpeed = 0
		-- 		end
		-- 	};
		-- 	{
		-- 		type = "recovery";
		-- 		frames = {5,20,5,10};
		-- 		custom = function(self)
		-- 			self.ignoreGravity = false
		-- 			-- self.ySpeed = 100
		-- 		end
		-- 	};
		-- };
	};
	animations = {
		idle = {
			--frames = {1,4,2,4,3,4,4,4,5,4,6,4,7,4,8,4,9,4,10,4,11,4,12,4,13,4,14,4,15,4,16,4,17,4,18,4,19,4,20,4,21,4,22,4,23,4,24,4,25,4,26,4,27,4,28,4,29,4,30,4,31,4,32,4};
			frames = {1,4,2,3,3,4,4,4,5,4,6,4,7,4,8,4,9,4,10,3,11,4,12,4,13,4,14,4,15,4,16,4};
		};
		crouch = {
			frames = {1,3,2,3,3,3,4,3,5,3,6,3,7,3,8,3,9,3,10,3,11,6,12,6,13,3,14,3,15,3,16,3,17,6,18,3,19,3};
		};
		turn = {
			frames = {1,4};
		};
		crouchTurn = {
			frames = {1,4};
		};
		walkBack = {
			frames = {2,4,3,3,4,4,5,3,6,4,7,3,8,4,9,3,10,4,11,3,12,4,13,3,14,4,15,3,16,4,1,3};
		};
		walkForward = {
			frames = {1,3,2,3,3,3,4,4,5,4,6,3,7,3,8,3,9,3,10,3,11,3,12,4,13,4,14,3,15,3,16,3};
		};
		jumpUp = {
			endWith = "nothing";
			frames={2,4,3,4,4,4,5,4,6,4,7,4,8,4,9,10};
		};
		jumpForward = {
			endWith = "nothing";
			spriteName = "jumpUp";
			frames={2,4,3,4,4,4,5,4,6,4,7,4,8,4,9,10};
		};
		jumpBack = {
			endWith = "nothing";
			spriteName = "jumpUp";
			frames={2,4,3,4,4,4,5,4,6,4,7,4,8,4,9,10};
		};
		land = {
			spriteName = "jumpUp";
			frames = {10,2,11,4,12,2};
		};
		standTransition = {
			frames={1,2,2,2};
		};
		crouchTransition = {
			frames={1,2,2,2};
		};
		airHurt = {
			endWith = "nothing";
			{
				frames = {1,1,2,3,3,3};
			};
			{
				spriteName = "jumpUp";
				frames = {5,4,6,4,7,4,8,4,9,10};
			};
		};
		knockdown = {
			endWith = "nothing";
			frames = {1,2,2,3,3,3,4,3,5,2};
		};
		impact = {
			spriteName = "knockdown";
			frames = {6,1,7,2}
		};
		startGroundBounce = {
			spriteName = "knockdown";
			frames = {8,2,9,2,10,2,11,7}
		};
		stopGroundBounce = {
			spriteName = "knockdown";
			frames = {12,2,13,10}
		};
		wakeup = {
			spriteName = "knockdown";
			frames = {14,3,15,3,16,4}
		};
		death = {
			spriteName = "knockdown";
			endWith = "nothing";
			frames = {13,1}
		};
		preBlock={
			spriteName="blockStand";
			endWith = "nothing";
			frames = {1,1,2,1,3,1};
		};
		preBlockReverse={
			spriteName="blockStand";
			frames = {2,1,1,2};
		};
		preBlockCrouch={
			endWith = "nothing";
			spriteName="blockCrouch";
			frames={1,2,2,1};
		};
		preBlockCrouchReverse={
			spriteName="blockCrouch";
			frames={1,2};
		};
		chipDeath = {
			endWith = "nothing";
			{
				frames={1,3,2,3};
				custom=function(self)
					self.enemy:drawFirst()
				end
			};
			{
				frames={3,3,4,3,5,3,6,3};
				custom = function(self)
					self:executeSound("chipDeath", {"sfx"})
				end
			};
			{
				frames={7,3};
				custom = function(self)
					self:executeSound("chipDeath", {"sfx"})
				end
			};
			{
				frames={8,1};
				custom = function(self)
					koFinish = true
				end
			};
		};
		yay = {
			frames = {1,16,2,3,3,3,4,3,5,3,6,3,7,3,8,3,9,3,10,4,11,4,12,5,13,5,14,5,15,5,16,5,17,5,18,5,19,5,20,5,};
			endWith = function(self)
				self:executeAnimation("yayLoop")
			end
		};
		yayLoop = {
			spriteName = "yay";
			frames = {21,5,22,5,23,5,24,10,25,10,26,5,27,5,28,5,29,5,30,5,31,5,32,5,33,5};
		};
		boo = {
			frames = {1,16,2,3,3,3,4,3,5,3,6,3,7,3,8,3,9,3,10,3,11,3,12,3,13,3,14,3,15,15};
			endWith = function(self)
				self:executeAnimation("booLoop")
			end
		};
		booLoop = {
			spriteName = "boo";
			frames = {16,6,17,30,18,6,19,30,20,6,21,3,22,3,23,3,24,6,25,3,26,3,27,3,28,6,16,6,15,30};
			custom = function(self)
				self:executeEffect("rain")
			end
		};
		win = {
			frames = {1,4,2,4,3,4,4,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4, 5,5,6,4,7,5,8,4};
		};
	};
	throw = {
		enemyFrames = {
			{5,27,-5}, --f1
			{6,20,-5}, --f2
			{7,19,-5}, --f3
			{8,20,-5}, --f4
			{10,20,-8}, --f5
			{9,21,-7}, --f6
			{8,21,-5}, --f7
			{10,27,-8}, --f8
			{0,0,0}, --f9
			{0,0,0}, --f10
			{0,0,0}, --f11
			{0,0,0}, --f12
			{0,0,0}, --f13
			{0,0,0}, --f14
			{0,0,0}, --f15
			{8,21,-5}, --f16
			{8,24,-5}, --f17
			{8,25,-5}, --f18
			{8,25,-6}, --f19
			{9,22,-7}, --f20
			{9,20,-7}, --f21
			{9,16,-7}, --f22
			{1,9,-12}, --f23
			{4,-13,-11}, --f24
			{0,0,0}, --f25
			{0,0,0}, --f26
			{0,0,0}, --f27
			{0,0,0}, --f28
			{0,0,0}, --f29
			{0,0,0}, --f30
			{0,0,0}, --f31
			{0,0,0}, --f32
			{0,0,0}, --f33
			{0,0,0}, --f34
			{0,0,0}, --f35
		};
		start = {
			{frames = {1,3,2,3,3,3,4,3}}; --5,2,6,4 --1,4,2,4,3,4,4,2,5,1,6,1
		};
		forward = {
			{
				frames = {5,3,6,3}; --8,4,9,4,10,4,11,4
				custom = function(self)
					self:executeEffect("throwEffect1")
					self:throwHitstop(6, 24, 14)
					cameraJitterX = 2
					self.combo = self.combo + 1
					self.enemy:changeHealth(1)
					self:executeSound(self.hitSpecialSFX, "sfx")
				end
			};
			{
				frames = {7,20,8,2}; --11,4,13,2,14,2,15,2
				-- data = {dmg = 1, hitstop = 9, explosionX= 101, explosionY = 101, changeLocation = 90, changeSpeed = 350, changeYSpeed = -600};
			};
			{
				frames = {9,3,10,3,11,3,12,10,13,3,14,3};
				custom = function(self)
					self:executeEffect("throwEffect2")
					self.combo = self.combo + 1
					self.enemy:changeHealth(1)
					self:executeSound(self.hitSpecialSFX, "sfx")
					self:throwHitstop(8, 30, 20)
					cameraJitterX = 2
					self.enemy:changeLocation(30)
					self.enemy:changeSpeed(300)
					self.enemy.ySpeed = -250
					self.enemy.y = self.enemy.y + 20
					self.enemy.ignoreGravity = false
					self.enemy:knockFall()
					self.ignoreFloor = false
					self.enemy.ignoreFloor = false
				end
			};
		};
		backward = {
			{
				frames = {5,3,6,3}; --8,4,9,4,10,4,11,4
				custom = function(self)
					self:executeEffect("throwEffect1")
					self:throwHitstop(6, 24, 14)
					cameraJitterX = 2
					self.combo = self.combo + 1
					self.enemy:changeHealth(1)
					self:executeSound(self.hitSpecialSFX, "sfx")
				end
			};
			{
				frames = {16,2,17,2,18,2,19,2,20,2,21,2,22,2}; --21,4,22,4,23,4
				data = {dmg = 1, changeLocation = 10, changeSpeed = 500, changeYSpeed = -600};
			};
			{
				frames = {23,2,24,2}; --21,4,22,4,23,4
				custom = function(self)
					self:reverseDrawOrder()
				end
			};
			{
				frames = {25,3,26,3,27,3,28,3,29,3,30,3,31,3,32,2,33,2,34,2};
				custom = function(self)
					self.combo = self.combo + 1
					self.enemy:changeHealth(1)
					self:executeSound('grab', "sfx")
					self.enemy:changeSpeed(-400)
					self.enemy.ySpeed = -200
					self.enemy.y = self.enemy.y + 20
					self.enemy.ignoreGravity = false
					self.ignoreCollision = false
					self.enemy:knockFall()
					self.enemy.animation:gotoFrame(5)
					self.faceRight = not self.faceRight
					self.ignoreFloor = false
					self.enemy.ignoreFloor = false
				end
			};
			{
				custom = function(self)
					self:changeLocation(-4)
				end
			};
		};
	};
	effects = {
		hitEffect = {
			frames = {1,2,2,2,3,2,4,1,5,1,6,1,7,2,8,2,9,2,10,1,11,2,12,1,13,1,0,1,13,1};
		};
		standAEffect = {
			frames = {1,3,2,3,3,3,4,3};
			relativeX = 16 * gameLogicMult;
			relativeY = -11 * gameLogicMult;
			followPlayer = true;
			ignoreParry = true;
			destroyWhenPlayerHurt = true;
		};
		standBEffect = {
			frames = {3,2,4,2,1,2,2,2,3,2,4,2,5,3,6,3};
			relativeX = 24 * gameLogicMult;
			relativeY = -2 * gameLogicMult;
			followPlayer = true;
			ignoreParry = true;
			destroyWhenPlayerHurt = true;
		};
		lowAEffect = {
			frames = {1,3,2,3,3,3,4,3,5,3};
			relativeX = 16 * gameLogicMult;
			relativeY = 13 * gameLogicMult;
			followPlayer = true;
			ignoreParry = true;
			destroyWhenPlayerHurt = true;
		};
		lowBEffect = {
			frames = {1,3,2,3,3,3,4,3,5,3,6,3,8,3,9,3};
			relativeX = 18 * gameLogicMult;
			relativeY = 15 * gameLogicMult;
			followPlayer = true;
			ignoreParry = true;
			destroyWhenPlayerHurt = true;
		};
		jumpAEffect = {
			frames = {1,2,2,2,3,2,4,2,1,2,2,2,5,2};
			relativeX = 21 * gameLogicMult;
			relativeY = 20 * gameLogicMult;
			followPlayer = true;
			ignoreParry = true;
			destroyWhenPlayerHurt = true;
			destroyWhenPlayerLand = true;
		};
		jumpBEffect = {
			spriteName = "standBEffect";
			frames = {3,2,4,2,1,2,2,2,3,2,4,2,1,1,5,3,6,3};
			relativeX = -6 * gameLogicMult;
			relativeY = 18 * gameLogicMult;
			followPlayer = true;
			ignoreParry = true;
			destroyWhenPlayerHurt = true;
			destroyWhenPlayerLand = true;
		};
		catDownBackB = {
			layer = "bottom";
			relativeY = -36 * gameLogicMult;
			relativeX = (-36 + 17) * gameLogicMult;
			{
				frames = {4,2,5,2,6,2,7,2,8,2,9,2,10,3,11,3,12,3,13,3,14,3,15,3,16,2,17,2,18,2,19,2,20,2,21,2,22,2,23,2,24,2}
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catDownForwardB = {
			--layer = "bottom";
			relativeY = -16 * gameLogicMult;
			relativeX = (-36 + 17) * gameLogicMult;
			{
				frames = {1,2,2,2,3,2,4,2,5,2,6,2,7,2,8,2,9,2,10,2,11,2,12,2,13,2,14,2,15,2,16,2,17,2,18,2,19,2,20,2,21,2,22,2,23,2,24,2,25,2,26,2,27,2,28,2,29,2,30,2,31,2,32,2,33,2};
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catDownForwardA = {
			relativeY = -30 *gameLogicMult;
			relativeX = -25 * gameLogicMult;
			{
				frames = {1,2,2,2,3,2,4,2,5,2,6,2,7,2,8,2,9,2,10,2,11,2,12,2,13,2,14,2,15,2};
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catIdle = {
			frames = {1,4,2,4,3,3,4,3,5,3,6,3,7,6,8,3,9,3,10,3,11,3,12,3,13,3,14,12};
			relativeX = -20;
			relativeY = -6;
			layer = "bottom";
		};
		catTurn = {
			frames = {1,3};
			relativeX = -20;
			relativeY = -6;
			layer = "bottom";
		};
		catHurt = {
			relativeX = -28;
			relativeY = -18;
			layer = "bottom";
			{
				frames = {1,2,2,2,3,2,4,2};
			};
			{
				frames = {5,2,6,2,7,2,8,2}; --Cat is spinning in a ball in this part, can loop if necessary to fill out arc of flying through the air
			};
			{
				frames = {9,2,10,2,11,2,12,2}; --16 --Frame 9 is impact with the ground, frame 13 is death/laying there frame
			};
			-- {
			-- 	frames = {14,2,15,2};
			-- };
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catWakeup = {
			spriteName = "catHurt";
			relativeX = -28;
			relativeY = -18 - 8*gameLogicMult;
			layer = "bottom";
			{
				frames = {13,56}; --This whole thing is a wakeup animation where the cat like shakes off a bit, we can maybe recycle most of this for the special move recovery
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catWakeupTwo = {
			spriteName = "catHurt";
			relativeX = -28;
			relativeY = -18;
			layer = "bottom";
			{
				frames = {14,2,15,2,16,2,17,2,18,2,19,2,20,2,21,2,22,2,23,2,24,2,25,2}; --This whole thing is a wakeup animation where the cat like shakes off a bit, we can maybe recycle most of this for the special move recovery
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catDeath = {
			endWith = "nothing";
			spriteName = "catHurt";
			relativeX = -28;
			relativeY = -18;
			layer = "bottom";
			{
				frames = {1,2,2,2,3,2,4,2};
			};
			{
				frames = {5,2,6,2,7,2,8,2}; --Cat is spinning in a ball in this part, can loop if necessary to fill out arc of flying through the air
			};
			{
				frames = {13,2,26,2,27,2,28,1}; --Frame 9 is impact with the ground, frame 13 is death/laying there frame
			};
		};
		catStartup = {
			relativeX = -20;
			relativeY = -6;
			frames = {1,4,2,4,3,4,5,4,6,4,7,4};
		};
		catRecovery = {
			{
				frames = {1,1,2,1,3,2,4,3,5,3,6,3,7,3,8,3,9,3,10,3,11,3,12,3,13,3,14,2,15,2,16,2,17,2,18,1,19,2}; --354
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
			relativeX = -20;
			relativeY = -12;
			layer = "bottom";
		};
		hitEffectCat = {
			layer = "hit";
			frames = {1,3,2,3,3,2,4,2,2,1};
		};
		catDash = {
			relativeY = -8*gameLogicMult;
			relativeX = -9*gameLogicMult;
			{
				frames = {1,2,2,2,3,2,4,2,5,6,6,2,7,2,8,2,9,2,10,2,11,2,12,2,13,2}; --26
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catDashStart = {
			spriteName = "catDash";
			relativeY = -8*gameLogicMult;
			relativeX = -9*gameLogicMult;
			{
				frames = {1,10,2,2,3,2,4,2,5,6,6,2,7,2,8,2,9,2,10,2,11,2,12,2,13,2}; --26
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catDashBack = {
			relativeY = -8*gameLogicMult;
			relativeX = -4*gameLogicMult;
			{
				frames = {1,2,2,2,3,2,4,2,5,2,6,2,7,6,8,2,9,2,10,2,11,2,12,2,13,2}; --26
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catNeutralAB = {
			relativeY = -28 *gameLogicMult;
			relativeX = -19 * gameLogicMult;
			{
				frames = {1,2,2,2,3,2,4,2,5,2,6,2,7,2,8,3,9,3,10,3,11,3,12,3,13,3};
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		catDownBackA = {
			layer = "bottom";
			relativeX = -12*gameLogicMult;
			relativeY = -15*gameLogicMult;
			{
				frames = {1,2,2,2,3,2,4,2,5,2,6,2,7,2,8,2,9,2,10,2,11,2,12,2,13,2,14,2,15,2,16,2,17,2,18,2,19,2,20,2};
			};
			{
				custom = function(self)
					self.exists = false
				end
			};
		};
		throwEffect1 = {
			spriteName = "throwEffects";
			relativeX = -30*gameLogicMult;
			frames = {1,2,2,2,3,2,4,2,5,2};
		};
		throwEffect2 = {
			spriteName = "throwEffects";
			relativeX = -30*gameLogicMult;
			frames = {6,2,7,2,8,2,9,2,10,2,11,2,12,2,13,2,14,2};
		};
		rain = {
			frames = {1,2,2,2,3,2,4,2};
			relativeX = -11 * gameLogicMult;
			relativeY = -11 * gameLogicMult;
			endWith = "loop";
			flicker = true;
		};
	};
	nameplate = {
		frames = {1,5,2,2,3,2,4,2,5,2,6,2,7,2,8,2,9,2,10,2,11,2,12,2,13,2,14,2,15,2,16,2,17,2,18,2,19,2,20,2,21,2,22,2,23,2,24,2,25,2,26,2,27,2,28,2,29,2,30,2,31,2,32,2,33,2,34,2,35,2,36,2,37,2,38,2,39,2,40,2,41,2,42,2,43,2,44,2,45,2,46,2};
		custom = function(self, host)
				if host.player1 == true then
					host:executeSound("nameplate", {"sfx", "nameplate1"}, -1)
				else
					host:executeSound("nameplate", {"sfx", "nameplate2"}, 1)
				end
			end;
	};
	projectiles = {
		catDownBackBStartup = {
			sfx = "launch";
			effect = "catStartup";
			lifetime = 10;
			noAttackbox = false;
			stayOnScreen = true;
			width = catWidth;
			height = 6 * gameLogicMult;
			relativeX = 0 * gameLogicMult;
			relativeY = 0 * gameLogicMult;
			ignoreProjectileCollision = true;
			priority = 4;
			onDestroy = function(self, host)
				if self.exists then
					if self.lifetime == 0 then
						self.liveEffect.exists = false
						self.exists = false
						host:newCatProjectile(self, "catDownBackB")
					end
				end
			end
		};
		catDownBackAStartup = {
			sfx = "launch";
			effect = "catStartup";
			lifetime = 10;
			noAttackbox = false;
			stayOnScreen = true;
			width = catWidth;
			height = 6 * gameLogicMult;
			relativeX = 0 * gameLogicMult;
			relativeY = 0 * gameLogicMult;
			ignoreProjectileCollision = true;
			priority = 4;
			onDestroy = function(self, host)
				if self.exists then
					if self.lifetime == 0 then
						self.liveEffect.exists = false
						self.exists = false
						host:newCatProjectile(self, "catDownBackA")
					end
				end
			end
		};
		catDownForwardBStartup = {
			sfx = "launch";
			effect = "catStartup";
			lifetime = 10;
			noAttackbox = false;
			stayOnScreen = true;
			width = catWidth;
			height = 6 * gameLogicMult;
			relativeX = 0 * gameLogicMult;
			relativeY = 0 * gameLogicMult;
			ignoreProjectileCollision = true;
			priority = 4;
			onDestroy = function(self, host)
				if self.exists then
					if self.lifetime == 0 then
						self.liveEffect.exists = false
						self.exists = false
						host:newCatProjectile(self, "catDownForwardB")
					end
				end
			end
		};
		catDownForwardAStartup = {
			sfx = "launch";
			effect = "catStartup";
			lifetime = 10;
			noAttackbox = false;
			stayOnScreen = true;
			width = catWidth;
			height = 6 * gameLogicMult;
			relativeX = 0 * gameLogicMult;
			relativeY = 0 * gameLogicMult;
			ignoreProjectileCollision = true;
			priority = 4;
			onDestroy = function(self, host)
				if self.exists then
					if self.lifetime == 0 then
						self.liveEffect.exists = false
						self.exists = false
						host:newCatProjectile(self, "catDownForwardA")
					end
				end
			end
		};
		catIdle = {
			xSpeed = 0; --default 350
			relativeX = -100 *gameLogicMult; --29*gameLogicMult
			relativeY = 30 *gameLogicMult;
			width = catWidth;
			height = 14 * gameLogicMult;
			noAttackbox = true;
			updateDuringHitstop = true;
			stayOnScreen = true;
			onSpawn = function(self, host)
				if (self.host.enemy.x + self.host.enemy.width/2) < (self.x + self.width/2) then
					if self.flip ~= -1 then
						if self.host.enemy.x >= stageWidth - self.host.enemy.width - (12 * gameLogicMult) then return end
						self.flip = -1
						self.liveEffect.flip = -1
						self:placeProjectileEffect("catIdle")
					end
				else
					if self.flip ~= 1 then
						if self.host.enemy.x <= (12 * gameLogicMult) then return end
						self.flip = 1
						self.liveEffect.flip = 1
						self:placeProjectileEffect("catIdle")
					end
				end
			end;
			onUpdate =  function(self)
				if (self.host.enemy.x + self.host.enemy.width/2) < (self.x + self.width/2) then
					if self.flip ~= -1 then
						if self.host.enemy.x >= stageWidth - self.host.enemy.width - (12 * gameLogicMult) then return end
						self.flip = -1
						self.liveEffect.flip = -1
						self:placeProjectileEffect("catIdle")
					end
				else
					if self.flip ~= 1 then
						if self.host.enemy.x <= (12 * gameLogicMult) then return end
						self.flip = 1
						self.liveEffect.flip = 1
						self:placeProjectileEffect("catIdle")
					end
				end
			end;
			onEnemyAttackboxCollide = function(self, host, enemyFlip)
				host:changeMeter(-1)
				self.exists = false
				if host.meterAmount > 0 then
					host:newCatProjectile(self, "catHurt", nil, nil,-enemyFlip)
				else
					host:newCatProjectile(self, "catDeath",nil, nil, -enemyFlip)
				end
			end;
		};
		catDeath = {
			relativeX = 0;
			relativeY = 0;
			noAttackbox = true;
			width = catWidth;
			height = 6 * gameLogicMult;
			xSpeed = -400;
			decay = 25;
			stayOnScreen = true;
			updateDuringHitstop = true;
		};
		catHurt = {
			sfx = "lightAttack";
			xSpeed = -400; --default 350
			-- ySpeed = -200;
			decay = 25;
			relativeX = 0;
			relativeY = 0;
			lifetime = 65 - 24 + 4 + 30 - 50;
			width = catWidth;
			height = 6 * gameLogicMult;
			noAttackbox = true;
			updateDuringHitstop = true;
			stayOnScreen = true;
			onDestroy = function(self, host)
				if self.exists and self.lifetime == 0 then
					self.exists = false
					host:newCatProjectile(self, "catWakeup", self.x, self.y  + 8*gameLogicMult)
				end
			end;
		};
		catWakeup = {
			-- xSpeed = -400; --default 350
			-- ySpeed = -200;
			-- decay = 25;
			relativeX = 0;
			relativeY = 0;
			lifetime = 56; --20+50
			width = catWidth;
			height = 6 * gameLogicMult;
			noAttackbox = true;
			updateDuringHitstop = true;
			stayOnScreen = true;
			onDestroy = function(self, host)
				if self.exists and self.lifetime == 0 then
					self.exists = false
					host:newCatProjectile(self, "catWakeupTwo", self.x, self.y - 8*gameLogicMult)
				end
			end;
			onEnemyAttackboxCollide = function(self, host, enemyFlip)
				host:changeMeter(-1)
				self.exists = false
				self.liveEffect.exists = false
				if host.meterAmount > 0 then
					host:newCatProjectile(self, "catHurt", nil, self.y - 8*gameLogicMult,-enemyFlip)
				else
					host:newCatProjectile(self, "catDeath",nil, self.y - 8*gameLogicMult, -enemyFlip)
				end
			end;
		};
		catWakeupTwo = {
			relativeX = 0;
			relativeY = 0;
			lifetime = 20+50-46;
			width = catWidth;
			height = 14 * gameLogicMult;
			noAttackbox = true;
			updateDuringHitstop = true;
			stayOnScreen = true;
			onDestroy = function(self, host)
				if self.exists and self.lifetime == 0 then
					self.exists = false
					host:newCatProjectile(self, "catIdle", self.x, self.y)
				end
			end;
			onEnemyAttackboxCollide = function(self, host, enemyFlip)
				host:changeMeter(-1)
				self.exists = false
				self.liveEffect.exists = false
				if host.meterAmount > 0 then
					host:newCatProjectile(self, "catHurt", nil, self.y,-enemyFlip)
				else
					host:newCatProjectile(self, "catDeath",nil, nil, -enemyFlip)
				end
			end;
		};
		catRecovery = {
			sfx = "jump";
			lifetime = 45;
			relativeX = 0;
			relativeY = 0;
			width = catWidth;
			height = 14 * gameLogicMult;
			noAttackbox = true;
			stayOnScreen  = true;
			onDestroy = function(self, host)
				if self.exists then
					self.exists = false
					self.host:newCatProjectile(self, "catIdle", self.x, self.y)
				end
			end;
			onEnemyAttackboxCollide = function(self, host, enemyFlip)
				host:changeMeter(-1)
				self.exists = false
				self.liveEffect.exists = false
				if host.meterAmount > 0 then
					host:newCatProjectile(self, "catHurt", nil, nil,-enemyFlip)
				else
					host:newCatProjectile(self, "catDeath",nil, nil, -enemyFlip)
				end
			end;
		};
		catDash = {
			sfx = "jump";
			xSpeed = 800; --default 350
			decay = 50;
			relativeX = 0;
			relativeY = 0;
			lifetime = 30;
			width = catWidth;
			height = 14 * gameLogicMult;
			noAttackbox = true;
			updateDuringHitstop = true;
			stayOnScreen = true;
			onDestroy = function(self, host)
				if self.exists and self.lifetime == 0 then
					self.exists = false
					host:newCatProjectile(self, "catIdle", self.x, self.y)
				end
			end;
			onEnemyAttackboxCollide = function(self, host, enemyFlip)
				host:changeMeter(-1)
				self.exists = false
				self.liveEffect.exists = false
				if host.meterAmount > 0 then
					host:newCatProjectile(self, "catHurt", nil, nil,-enemyFlip)
				else
					host:newCatProjectile(self, "catDeath",nil, nil, -enemyFlip)
				end
			end;
		};
		catDashStart = {
			effect = "catDashStart";
			xSpeed = 1200; --default 350
			decay = 50;
			relativeX = 0;
			relativeY = 0;
			lifetime = 38;
			width = catWidth;
			height = 6 * gameLogicMult;
			noAttackbox = true;
			updateDuringHitstop = true;
			-- stayOnScreen = true;
			onDestroy = function(self, host)
				if self.exists and self.lifetime == 0 then
					self.exists = false
					host:newCatProjectile(self, "catIdle", self.x, self.y)
				end
			end;
			onLeaveScreen = function(self)
				--nothing
			end
		};
		catDownBackB = {
			sfx = "heavyRush";
			lifetime = 48;
			dontKillEffect = true;
			xSpeed = 0;
			relativeX = -12 *gameLogicMult; --doesn't matter
			relativeY = -54 *gameLogicMult;
			pushUp = 280 * gameLogicMult;
			width = 40 * gameLogicMult; --32
			height = 60 * gameLogicMult;
			updateDuringHitstop = true;
			ignoreProjectileCollision = true;
			priority = 4;
			customEffect = "hitEffectCat";
			-- noAttackbox = true;
			onUpdate = function(self)
				if self.lifetime == 48 then
					self.hitStun = 16; --this activates the projectile as an attack
				elseif self.lifetime == 10 then
					self.hitStun = nil;
				end
			end;
			onDestroy = function(self, host)
				if self.exists then
					self.noAttackbox = true
					if self.lifetime == 0 then
						self.exists = false
						if self.flip == -1 then
							host:newCatProjectile(self, "catRecovery", self.x + self.width/2 - catXOffset, self.y + 54 * gameLogicMult)
						else
							host:newCatProjectile(self, "catRecovery", self.x + self.width/2 - catWidth + catXOffset, self.y + 54 * gameLogicMult)
						end
					end
				end
			end;
			onLeaveScreen = function(self)
				--don't do anything (if this didn't exist, the projectile would die)
			end
		};
		catNeutralAB = {
			sfx = "naomiDP";
			dontKillSFX = true;
			lifetime = 25;
			relativeX = -31 * gameLogicMult;
			relativeY = -40 * gameLogicMult;
			width = 80 * gameLogicMult;
			height = 60 * gameLogicMult;
			pushUp = 300 * gameLogicMult;
			hitStun = 8;
			customEffect = "hitEffectCat";
			dontKillEffect = true;
			onUpdate = function(self, host)
				if self.lifetime == 25 then
					self.host:changeMeter(-8)
				end
			end;
		};
		catDownBackA = {
			sfx = "downBackA";
			lifetime = 30;
			dontKillEffect = true;
			-- xSpeed = 250;
			relativeX = -50 *gameLogicMult; --doesn't matter
			relativeY = 8 *gameLogicMult;
			pushUp = 140 * gameLogicMult;
			explosionX = -50 * gameLogicMult;
			width = 100 * gameLogicMult;
			height = 6 * gameLogicMult;

			attacktype = attackTypes.low;
			updateDuringHitstop = true;
			ignoreProjectileCollision = true;
			priority = 4;
			customEffect = "hitEffectCat";
			onUpdate = function(self)
				if self.lifetime == 16 then --10
					self.hitStun = 16;
				end
			end;
			onDestroy = function(self, host)
				if self.exists then
					self.noAttackbox = true
					if self.lifetime == 0 then
						self.exists = false
						if self.flip == -1 then
							host:newCatProjectile(self, "catRecovery", self.x + self.width/2 - 16 - catXOffset, self.y - 8*gameLogicMult)
						else
							host:newCatProjectile(self, "catRecovery", self.x + self.width/2 - catWidth + 16 + catXOffset, self.y - 8*gameLogicMult)
						end
					end
				end
			end;
			onLeaveScreen = function(self)
				--don't do anything (if this didn't exist, the projectile would die)
			end
		};
		catDownForwardA = {
			sfx = "rush";
			lifetime = 30;
			dontKillEffect = true;
			xSpeed = 250;
			relativeX = -30 *gameLogicMult; --doesn't matter
			relativeY = -17 *gameLogicMult; -- -54
			pushUp = 200 * gameLogicMult;
			pushback = 250;
			width = (8+42) * gameLogicMult;
			height = 30 * gameLogicMult;
			hitStun = 16;
			updateDuringHitstop = true;
			forceProjectileForward = true;
			-- noAttackbox = true;
			stayOnScreen = true;
			ignoreProjectileCollision = true;
			priority = 4;
			customEffect = "hitEffectCat";
			onUpdate = function(self)
				if self.lifetime == 8 then
					self.hitStun = nil;
					-- self.noAttackbox = false
				end
			end;
			onDestroy = function(self, host)
				if self.exists then
					self.noAttackbox = true
					if self.lifetime == 0 then
						self.exists = false
						if self.flip == -1 then
							host:newCatProjectile(self, "catRecovery", self.x + self.width/2 - catXOffset, self.y + 17 * gameLogicMult)
						else
							host:newCatProjectile(self, "catRecovery", self.x + self.width/2 - catWidth + catXOffset, self.y + 17 * gameLogicMult)
						end
					end
				end
			end;
		};
		catDownForwardB = {
			sfx = "downForwardB";
			lifetime = 60;
			dontKillEffect = true;
			-- xSpeed = 20;
			noAttackbox = true;
			attacktype = attackTypes.high;
			relativeX = -44 *gameLogicMult; --doesn't matter
			relativeY = -40 *gameLogicMult;
			pushUp = -300 * gameLogicMult;
			width = 105 * gameLogicMult;
			height = 54 * gameLogicMult;
			-- hitStun = 16;
			updateDuringHitstop = true;
			-- noAttackbox = true;
			-- stayOnScreen = true;
			-- forceForward = true;
			forceProjectileForward = true;
			-- ySpeed = -700;
			-- decay = 10 * gameLogicMult;
			ignoreProjectileCollision = true;
			priority = 4;
			customEffect = "hitEffectCat";
			onUpdate = function(self)
				-- if self.lifetime == 20 then
				-- 	self.noAttackbox = false
				-- 	self.ySpeed = 400;
				-- 	self.decay = 0;
				-- end
				if self.lifetime == 26 then
					self.noAttackbox = false
				elseif self.lifetime == 13 then
					self.hitStun = 16; --this activates the projectile as an attack
				elseif self.lifetime == 6 then
					self.hitStun = nil;
				end
			end;
			onDestroy = function(self, host)
				if self.exists then
					self.noAttackbox = true
					if self.lifetime == 0 then
						self.exists = false
						if self.flip == -1 then
							host:newCatProjectile(self, "catRecovery", self.x + self.width/2 - catXOffset, 122 + 30 *gameLogicMult)
						else
							host:newCatProjectile(self, "catRecovery", self.x + self.width/2 - catWidth + catXOffset, 122 + 30 *gameLogicMult)
						end
					end
				end
			end;
			onLeaveScreen = function(self)
				--don't do anything (if this didn't exist, the projectile would die)
			end
		};
		catRunLeft = {
			xSpeed = -200; --default 350
			relativeX = 0 *gameLogicMult; --29*gameLogicMult
			relativeY = 0 *gameLogicMult;
			width = catWidth;
			height = 6 * gameLogicMult;
			noAttackbox = true;
			updateDuringHitstop = true;
			-- stayOnScreen = true;
			onUpdate = function(self)
				if math.floor(self.host.x - self.x) >= 30 then
					self.host:newCatProjectile(self, "catIdle", self.x, self.y)
				end
			end;
			onLeaveScreen = function(self)
				--don't do anything (if this didn't exist, the projectile would die)
			end
		};
		catRunRight = {
			xSpeed = 200; --default 350
			relativeX = 0 *gameLogicMult; --29*gameLogicMult
			relativeY = 0 *gameLogicMult;
			width = catWidth;
			height = 6 * gameLogicMult;
			noAttackbox = true;
			updateDuringHitstop = true;
			-- stayOnScreen = true;
			onUpdate = function(self)
				if math.floor(self.host.x - self.x) <= 30 then
					self.host:newCatProjectile(self, "catIdle", self.x, self.y)
				end
			end;
			onLeaveScreen = function(self)
				--don't do anything (if this didn't exist, the projectile would die)
			end
		};
	};
	colors = {
		default = {
			sprite = {
				{255,201,255}; --DRESS and sparkle lighter
				{255,169,183}; --sparkle darker

				{248,245,248}; --cat fur
				{255,192,255}; --cat shading
				{0,221,155}; --cat eyes

				{0,53,70}; --normal tentacle shadow
				{0,84,100}; -- normal tentacle
				{0,33,38}; -- down back B darkest

				{29,159,165}; -- sucker rim
				{7,193,138}; -- sucker inside
				{4,116,83}; -- sucker inside shadow

			};
			effects = {
				{255,169,183}; --sparkle darker
				{255,201,255}; --sparkle lighter

				{248,245,248}; --cat fur
				{255,192,255}; --cat shading
				{0,221,155}; --cat eyes

				{0,53,70}; --normal tentacle shadow
				{0,84,100}; -- normal tentacle
				{0,33,38}; -- down back B darkest

				{29,159,165}; -- sucker rim
				{7,193,138}; -- sucker inside
				{4,116,83}; -- sucker inside shadow
			};


			hit = {
				{255,43,106}; --hot pink
				{255,119,180}; --medium pink
				{255,169,183}; --lightest pink

				{0,220,161}; --cat
			};
			meterIcon = {
				{0,221,155}; -- eyes
				{169,255,173}; --shadow

				{0,103,83}; -- health background
			};
			meterChunk = {
					{0,255,178}; --drain color
				};
			--generalAssets
				dust = {255,100,146};
				block = {255,100,146};

				mainUI = {149,0,52};
				health = {255,100,146};
		};
		alt1 = {
			sprite = {
				{255,76,76}; --DRESS and sparkle lighter
				{255,121,126}; --sparkle darker

				{255,198,198}; --cat fur
				{255,150,150}; --cat shading
				{25,124,255}; --cat eyes

				{20,38,88}; --normal tentacle shadow
				{0,80,116}; -- normal tentacle
				{3,16,42}; -- down back B darkest

				{5,117,255}; -- sucker rim
				{56,162,255}; -- sucker inside
				{34,83,143}; -- sucker inside shadow

			};
			effects = {
				{255,121,126}; --sparkle darker
				{255,76,76}; --sparkle lighter

				{255,198,198}; --cat fur
				{255,150,150}; --cat shading
				{25,124,255}; --cat eyes

				{20,38,88}; --normal tentacle shadow
				{0,80,116}; -- normal tentacle
				{3,16,42}; -- down back B darkest

				{5,117,255}; -- sucker rim
				{56,162,255}; -- sucker inside
				{34,83,143}; -- sucker inside shadow
			};


			hit = {
				{255,34,30}; --hot pink
				{255,0,0}; --medium pink
				{255,121,126}; --lightest pink

				{0,99,231}; --cat
			};
			meterIcon = {
				{25,124,255}; -- eyes
				{169,223,255}; --shadow

				{0,55,102}; -- health background
			};
			meterChunk = {
					{0,99,231}; --drain color
				};
			--generalAssets
				dust = {255,64,64};
				block = {255,0,0};

				mainUI = {113, 0, 0};
				health = {255,0,0};
		};
		alt2 = {
			sprite = {
				{255,177,107}; --DRESS and sparkle lighter
				{255,119,84}; --sparkle darker

				{255,247,243}; --cat fur
				{255,207,148}; --cat shading
				{229,230,0}; --cat eyes

				{118,98,0}; --normal tentacle shadow
				{184,165,0}; -- normal tentacle
				{67,61,19}; -- down back B darkest

				{235,230,35}; -- sucker rim
				{255,218,19}; -- sucker inside
				{202,151,46}; -- sucker inside shadow

			};
			effects = {
				{255,119,84}; --sparkle darker
				{255,177,107}; --sparkle lighter

				{255,247,243}; --cat fur
				{255,207,148}; --cat shading
				{229,230,0}; --cat eyes

				{118,98,0}; --normal tentacle shadow
				{184,165,0}; -- normal tentacle
				{67,61,19}; -- down back B darkest

				{235,230,35}; -- sucker rim
				{255,218,19}; -- sucker inside
				{202,151,46}; -- sucker inside shadow
			};


			hit = {
				{255,74,0}; --hot pink
				{255,106,46}; --medium pink
				{255,119,84}; --lightest pink

				{255,255,0}; --cat
			};
			meterIcon = {
				{229,230,0}; -- eyes
				{255,255,73}; --shadow

				{102,87,0}; -- health background
			};
			meterChunk = {
					{229,230,0}; --drain color
				};
			--generalAssets
				dust = {255,164,42};
				mainUI = {187,72,0};
				health = {255,102,7};
		};
		alt3 = {
			sprite = {
				{248,244,64}; --DRESS and sparkle lighter
				{255,239,169}; --sparkle darker

				{255,255,192}; --cat fur
				{255,248,76}; --cat shading
				{255,30,106}; --cat eyes

				{70,0,32}; --normal tentacle shadow
				{100,0,62}; -- normal tentacle
				{57,0,37}; -- down back B darkest

				{194,0,60}; -- sucker rim
				{204,51,136}; -- sucker inside
				{132,34,71}; -- sucker inside shadow

			};
			effects = {
				{255,239,169}; --sparkle darker
				{248,244,64}; --sparkle lighter

				{255,255,192}; --cat fur
				{255,248,76}; --cat shading
				{255,30,106}; --cat eyes

				{70,0,32}; --normal tentacle shadow
				{100,0,62}; -- normal tentacle
				{57,0,37}; -- down back B darkest

				{194,0,60}; -- sucker rim
				{204,51,136}; -- sucker inside
				{132,34,71}; -- sucker inside shadow
			};


			hit = {
				{255,255,0}; --hot pink
				{255,221,90}; --medium pink
				{255,239,169}; --lightest pink

				{255,30,106}; --cat
			};
			meterIcon = {
				{255,30,106}; -- eyes
				{255,169,186}; --shadow

				{102,0,47}; -- health background
			};
			meterChunk = {
					{255,30,106}; --drain color
				};
			--generalAssets
				dust = {255,255,0};
				block = {255,255,0};

				mainUI = {113, 113, 0};
				health = {215,215,0};
		};
		alt4 = {
			sprite = {
				{172,226,68}; --DRESS and sparkle lighter
				{103,210,57}; --sparkle darker

				{226,255,226}; --cat fur
				{179,220,99}; --cat shading
				{169,23,255}; --cat eyes

				{65,0,70}; --normal tentacle shadow
				{114,0,135}; -- normal tentacle
				{47,0,57}; -- down back B darkest

				{195,0,255}; -- sucker rim
				{255,0,255}; -- sucker inside
				{168,9,123}; -- sucker inside shadow

			};
			effects = {
				{103,210,57}; --sparkle darker
				{172,226,68}; --sparkle lighter

				{226,255,226}; --cat fur
				{179,220,99}; --cat shading
				{169,23,255}; --cat eyes

				{65,0,70}; --normal tentacle shadow
				{114,0,135}; -- normal tentacle
				{47,0,57}; -- down back B darkest

				{195,0,255}; -- sucker rim
				{255,0,255}; -- sucker inside
				{168,9,123}; -- sucker inside shadow
			};


			hit = {
				{0,255,0}; --hot pink
				{65,193,67}; --medium pink
				{103,210,57}; --lightest pink

				{153,85,193}; --cat
			};
			meterIcon = {
				{169,23,255}; -- eyes
				{208,122,255}; --shadow

				{70,0,102}; -- health background
			};
			meterChunk = {
					{169,23,255}; --drain color
				};
			--generalAssets
				dust = {0,255,0};
				mainUI = {0, 113, 0};
				health = {0,255,0}
		};
		alt5 = {
			sprite = {
				{128,183,192}; --DRESS and sparkle lighter
				{126,218,233}; --sparkle darker

				{202,214,255}; --cat fur
				{137,171,255}; --cat shading
				{247,0,0}; --cat eyes

				{87,0,0}; --normal tentacle shadow
				{117,27,34}; -- normal tentacle
				{64,0,4}; -- down back B darkest

				{194,11,0}; -- sucker rim
				{246,0,43}; -- sucker inside
				{154,11,0}; -- sucker inside shadow

			};
			effects = {
				{126,218,233}; --sparkle darker
				{128,183,192}; --sparkle lighter

				{202,214,255}; --cat fur
				{137,171,255}; --cat shading
				{247,0,0}; --cat eyes

				{87,0,0}; --normal tentacle shadow
				{117,27,34}; -- normal tentacle
				{64,0,4}; -- down back B darkest

				{194,11,0}; -- sucker rim
				{246,0,43}; -- sucker inside
				{154,11,0}; -- sucker inside shadow
			};


			hit = {
				{0,216,255}; --hot pink
				{101,196,255}; --medium pink
				{126,218,233}; --lightest pink

				{255,0,0}; --cat
			};
			meterIcon = {
				{247,0,0}; -- eyes
				{255,145,145}; --shadow

				{102,0,0}; -- health background
			};
			meterChunk = {
					{255,0,0}; --drain color
				};
			--generalAssets
				dust = {128,183,192};
				mainUI = {0,75,88}; --UIcolor
				health = {0,216,255};
		};
		alt6 = {
			sprite = {
				{202,202,208}; --DRESS and sparkle lighter
				{155,155,167}; --sparkle darker

				{227,227,227}; --cat fur
				{179,179,179}; --cat shading
				{235,138,167}; --cat eyes

				{144,0,153}; --normal tentacle shadow
				{209,30,182}; -- normal tentacle
				{101,0,111}; -- down back B darkest

				{243,56,255}; -- sucker rim
				{251,15,219}; -- sucker inside
				{220,9,181}; -- sucker inside shadow

			};
			effects = {
				{155,155,167}; --sparkle darker
				{202,202,208}; --sparkle lighter

				{227,227,227}; --cat fur
				{179,179,179}; --cat shading
				{235,138,167}; --cat eyes

				{144,0,153}; --normal tentacle shadow
				{209,30,182}; -- normal tentacle
				{101,0,111}; -- down back B darkest

				{243,56,255}; -- sucker rim
				{251,15,219}; -- sucker inside
				{220,9,181}; -- sucker inside shadow
			};


			hit = {
				{113,117,125}; --hot pink
				{120,126,138}; --medium pink
				{155,155,167}; --lightest pink

				{240,128,240}; --cat
			};
			meterIcon = {
				{235,138,167}; -- eyes
				{236,169,255}; --shadow

				{98,0,86}; -- health background
			};
			meterChunk = {
					{235,138,167}; --drain color
				};
			--generalAssets
				dust = {155,155,167};
				mainUI = {64,64,64}; --UIcolor
				health = {155,155,167};
		};
		alt7 = {
			sprite = {
				{213,134,208}; --DRESS and sparkle lighter
				{127,79,139}; --sparkle darker

				{210,167,255}; --cat fur
				{202,98,255}; --cat shading
				{0,197,0}; --cat eyes

				{0,99,67}; --normal tentacle shadow
				{31,161,0}; -- normal tentacle
				{0,57,47}; -- down back B darkest

				{0,255,0}; -- sucker rim
				{149,255,32}; -- sucker inside
				{107,224,0}; -- sucker inside shadow

			};
			effects = {
				{127,79,139}; --sparkle darker
				{213,134,208}; --sparkle lighter

				{210,167,255}; --cat fur
				{202,98,255}; --cat shading
				{0,197,0}; --cat eyes

				{0,99,67}; --normal tentacle shadow
				{31,161,0}; -- normal tentacle
				{0,57,47}; -- down back B darkest

				{0,255,0}; -- sucker rim
				{149,255,32}; -- sucker inside
				{107,224,0}; -- sucker inside shadow
			};


			hit = {
				{136,17,149}; --hot pink
				{184,15,255}; --medium pink
				{127,79,139}; --lightest pink

				{0,255,0}; --cat
			};
			meterIcon = {
				{0,197,0}; -- eyes
				{193,255,84}; --shadow

				{0,103,12}; -- health background
			};
			meterChunk = {
					{0,255,0}; --drain color
				};
			--generalAssets
				dust = {171,43,200};
				block = {171,43,200};
				mainUI = {71,42,69};
				health = {171,43,200};
		};
	};
};

function Keiko:newCatProjectile(currentProjectile, newProjectileString, overloadX, overloadY, overloadFlip)
	print("newCatProjectile Incoming:" .. newProjectileString)
	local relativeY = currentProjectile.y + self.projectiles[newProjectileString].relativeY
	if overloadY then relativeY = overloadY end
	local relativeX = self.projectiles[newProjectileString].relativeX
	if currentProjectile.flip == 1 then
		relativeX = currentProjectile.x + relativeX
	else
		relativeX = currentProjectile.x + currentProjectile.width - relativeX - self.projectiles[newProjectileString].width
	end
	if overloadX then relativeX = overloadX end
	if overloadFlip then currentProjectile.flip = overloadFlip end
	self:executeProjectile(newProjectileString, relativeX, relativeY, currentProjectile.flip)
	currentProjectile.liveEffect.exists = false
	currentProjectile.exists = false
	currentProjectile:destroy()
	if newProjectileString == "catDownBackAStartup" then
		self:setFDB({{type="startup", frameCount=9+14}, {type="active", frameCount=16}, {type="recovery", frameCount=41-5+10}})
	elseif newProjectileString == "catDownBackBStartup" then
		self:setFDB({{type="startup", frameCount=9+8}, {type="active", frameCount=30}, {type="recovery", frameCount=41+10-5+10}})
	elseif newProjectileString == "catDownForwardAStartup" then
		self:setFDB({{type="startup", frameCount=9}, {type="active", frameCount=22}, {type="recovery", frameCount=41+6-5+10+2}})
	elseif newProjectileString == "catDownForwardBStartup" then
		self:setFDB({{type="startup", frameCount=9+47}, {type="active", frameCount=13-6}, {type="recovery", frameCount=41-5+10+6}})
	elseif newProjectileString == "catHurt" then
		self:setFDB({{type="knockdown", frameCount=45+30-50+10}, {type="recovery", frameCount=20+50}})
	elseif newProjectileString == "catDash" then
		self:setFDB(Template:Type="recovery", frameCount=30)
	end
end

function Keiko:dashOverride(left, right)
	local catIdle = self:getProjectile("catIdle")
	if catIdle and not p.superStop and not q.superStop and not roundIntro then
		if left then
			self:newCatProjectile(catIdle, "catDash", nil, nil, -1)
		elseif right then
			self:newCatProjectile(catIdle, "catDash", nil, nil, 1)
		end
		self.dashInputLeft = 0
    self.dashInputRight = 0
    self.flagDashRight = false
    self.flagDashLeft = false
	end
end

function Keiko:controlUpdate(left, right, up, down, buttonA, buttonB, tapA, tapB, specialA, specialB)
	if not p.superStop and not q.superStop and not roundIntro then
		local catAnimation = self:getProjectile("catHurt")
		if not catAnimation then
			catAnimation = self:getProjectile("catWakeup")
			if not catAnimation then
				catAnimation = self:getProjectile("catRecovery")
				if not catAnimation then
					catAnimation = self:getProjectile("catDash")
					if not catAnimation then
						catAnimation = self:getProjectile("catWakeupTwo")
					end
				end
			end
		end
		if catAnimation then
			if self.ABTimer <= 1 and buttonA and buttonB then
				if not self:onFloor() then
					self:executeAnimation("jumpUp")
				else
					if not (down and right) and not (down and left) then
						self:executeAnimation("idle")
					end
				end
				self.noInput = false
				self.ABTimer = 2
				self.repeatA = true
				self.repeatB = true
				self:flushBar()
				if catAnimation == self:getProjectile("catWakeup") then
					self:newCatProjectile(catAnimation, "catNeutralAB", nil, catAnimation.y-48*gameLogicMult)
				else
					self:newCatProjectile(catAnimation, "catNeutralAB")
				end
			elseif buttonA and buttonB and not self.repeatA and not self.repeatB then
				self.repeatA = true
				self.repeatB = true
				if catAnimation == self:getProjectile("catWakeup") then
					self:newCatProjectile(catAnimation, "catNeutralAB", nil, catAnimation.y-48*gameLogicMult)
				else
					self:newCatProjectile(catAnimation, "catNeutralAB")
				end
			end
		end
		local catIdle = self:getProjectile("catIdle")
		if catIdle then
			-- if left and not self.lastFrameLeft then
			-- 	if self.dashInputLeft > 0 then
			-- 		self:newCatProjectile(catIdle, "catDash", nil, nil, -1)
			-- 	end
			-- elseif right and not self.lastFrameRight then
			--   if self.dashInputRight > 0 then
			--   	self:newCatProjectile(catIdle, "catDash", nil, nil, 1)
			--   end
			if self.ABTimer <= 1 and buttonA and buttonB then
				if not self:onFloor() then
					self:executeAnimation("jumpUp")
				else
					if not (down and right) and not (down and left) then
						self:executeAnimation("idle")
					end
				end
				self.noInput = false
				self.ABTimer = 2
				self.repeatA = true
				self.repeatB = true
				self:flushBar()
				self:newCatProjectile(catIdle, "catNeutralAB")
			elseif buttonA and buttonB and not self.repeatA and not self.repeatB then
				self.repeatA = true
				self.repeatB = true
				self:newCatProjectile(catIdle, "catNeutralAB")
			elseif buttonA and self.inputFrame >= 6 then
				if down and right and not left then
					-- if catIdle.flip == 1 then
					if (self.flip == 1 and self.move ~= "getThrown") or (self.move == "getThrown" and self.flip == -1) then
						self:newCatProjectile(catIdle, "catDownForwardAStartup")
					else
						self:newCatProjectile(catIdle, "catDownBackAStartup")
					end
					self.repeatA = true
					self.inputFrame = 0
				elseif down and left and not right then
					-- if catIdle.flip == 1 then
					if (self.flip == 1 and self.move ~= "getThrown") or (self.move == "getThrown" and self.flip == -1) then
						self:newCatProjectile(catIdle, "catDownBackAStartup")
					else
						self:newCatProjectile(catIdle, "catDownForwardAStartup")
					end
					self.repeatA = true
					self.inputFrame = 0
				end
			elseif buttonB and self.inputFrame >= 6 then
				if down and right and not left then
					-- if catIdle.flip == 1 then
					if (self.flip == 1 and self.move ~= "getThrown") or (self.move == "getThrown" and self.flip == -1) then
						self:newCatProjectile(catIdle, "catDownForwardBStartup")
					else
						self:newCatProjectile(catIdle, "catDownBackBStartup")
					end
					self.repeatB = true
					self.inputFrame = 0
				elseif down and left and not right then
					-- if catIdle.flip == 1 then
					if (self.flip == 1 and self.move ~= "getThrown") or (self.move == "getThrown" and self.flip == -1) then
						self:newCatProjectile(catIdle, "catDownBackBStartup")
					else
						self:newCatProjectile(catIdle, "catDownForwardBStartup")
					end
					self.repeatB = true
					self.inputFrame = 0
				end
			end
		end
	end
	self:_controlUpdate(left, right, up, down, buttonA, buttonB, tapA, tapB, specialA, specialB)
end

function Keiko:reset()
	self:_reset()
	self.catFDB = {}
	self.catFDBPhantom = {}
	for i=1, 200 do
		self.catFDB[i] = 0
		self.catFDBPhantom[i] = 0
	end
	self.meterAmount = 8
	if not selecting then
		if self.flip == 1 then
			self:executeProjectile("catDashStart", self.x - 300, self.y + 30 * gameLogicMult)
		else
			self:executeProjectile("catDashStart", self.x + self.width + 300 - (catWidth), self.y + 30 * gameLogicMult)
		end
	end
end

function Keiko:changeMeter(amount)
	self.meterAmount = self.meterAmount + amount
	if amount > 0 then
		if self.meterAmount == 1 then
			if self.playerNum == 1 then
				self:executeSound('fullMeter', "sfx", -1)
			else
				self:executeSound('fullMeter', "sfx", 1)
			end
		end
		if self.meterAmount >= 8 then
			self.meterJitter = 5
			self.meterAmount = 8
		else
			self.meterJitter = 2
		end
		self.meterAnimate = anim8.newAnimation(self.sprites.meter.grid(repeatNum(1,1)), frameTime, 'pauseAtEnd')
		for i=1, 8 do
			self.meterChunkArray[i] = anim8.newAnimation(self.sprites.meterChunk.grid(repeatNum(1,1,7,2,2,1,3,1,7,2,4,2,7,2,5,2,7,3,6,3,-1,1)), frameTime, 'pauseAtEnd') --6,1,1,2,2,2,3,2,4,2,5,1
		end
	else
		if self.meterAmount < 0 then self.meterAmount = 0 end
		if self.meterAmount == 0 then
			self.meterAnimate = anim8.newAnimation(self.sprites.meter.grid(repeatNum(4,2,5,1)), frameTime, 'pauseAtEnd')
			if self.meterAmount < 0 then self.meterAmount = 0 end
			-- self.neutralABRequirement = false
		end
			-- for i=1,8 do
  	-- 		self.meterChunkArray[i] = anim8.newAnimation(self.sprites.meterChunk.grid(repeatNum(1,1,2,3,3,3,4,3,5,3,6,3,7,3,8,1)), frameTime, 'pauseAtEnd')
			-- end
			self.meterJitter = 5
	end
end

function Keiko:initiate()
	self:_initiate()
	self.hitLightSFX = "lightAttack"
	self.hitHeavySFX = "heavyAttack"
	self.hitLowSFX = "lowAttack"
	self.hitSpecialSFX = "special"
end

function Keiko:resetMeter()
	self.meterChunkArray = {}
	for i=1, 8 do
		self.meterChunkArray[i] = anim8.newAnimation(self.sprites.meterChunk.grid(repeatNum(1,1,7,2,2,1,3,1,7,2,4,2,7,2,5,2,7,3,6,3,-1,1)), frameTime, 'pauseAtEnd') --6,1,1,2,2,2,3,2,4,2,5,1
	end
	self:_resetMeter()
end

function Keiko:meterAnimation()
	love.graphics.setShader()
	-- self:catFDBDraw(true)
	self:meterBackDraw()
	self:catFDBDraw()
	love.graphics.setShader(self.shaders.meterIcon)
	if self.player1 then
		self.meterAnimate:draw(self.sprites.meter.sheet, self.meterX, self.meterY + self.meterJitter, 0, gameLogicMult, gameLogicMult, 0, 0)
		love.graphics.setShader(self.shaders.meterChunk)
		for i=1, 8 do
			local d = i-1
			self.meterChunkArray[i]:draw(self.sprites.meterChunk.sheet, (self.meterX + 126) - (d * 12), self.meterY + 10 + self.meterJitter, 0, gameLogicMult, gameLogicMult, 0, 0)
		end
	else
		self.meterAnimate:draw(self.sprites.meter.sheet, self.meterX, self.meterY + self.meterJitter, 0, -gameLogicMult, gameLogicMult, 0, 0)
		love.graphics.setShader(self.shaders.meterChunk)
		for i=1, 8 do
			local d = i-1
			self.meterChunkArray[i]:draw(self.sprites.meterChunk.sheet, (self.meterX - 126) + (d * 12), self.meterY + 10 + self.meterJitter, 0, -gameLogicMult, gameLogicMult, 0, 0)
		end
	end
	love.graphics.setShader()
end

function Keiko:meterOverload()
	if self.meterChunkArray then
		for i=8, self.meterAmount+1,-1 do
			self.meterChunkArray[i]:update(frameTime)
		end
	end
end

function Keiko:setFDB(frameDataTable)
	if not frameDataTable then return end

	local tableSize = 0
	local frameData = {}
  tableSize = #frameDataTable
  frameData = frameDataTable
	if tableSize <= 0 then return end
	local frameType = 0
	local frameCount = 0
	local currentLocation = 0
	self:catFlushBar()
	for i=tableSize, 1, -1 do
	  frameCount = frameData[i].frameCount
	  frameType = frameData[i].type
	  for j=0, frameCount-1 do
	    self.catFDB[currentLocation + j] = frameType
	  end
	  -- self.catFDB[frameType] = self.catFDB[frameType] + frameCount
	  currentLocation = currentLocation + frameCount
	end
	self.catFDBPhantom = deepcopy(self.catFDB)
end

function Keiko:alwaysUpdate(dt)
	self:_alwaysUpdate(dt)
	self:catFDBUpdate()
end

function Keiko:catFlushBar()
  self.framePosition = 0
  local ending = 0
  while ending <= 79 and self.catFDB[ending] ~= 0 do
    self.catFDB[ending] = 0
    ending = ending + 1
  end
  -- self.catFDB.startup = 0
  -- self.catFDB.active = 0
  -- self.catFDB.recovery = 0

  -- self.catFDB.blockstun = 0
  -- self.catFDB.hitstun = 0
  -- self.catFDB.cancel = 0

  if not ignorePhantom then
    self.catFDBPhantom = deepcopy(self.catFDB)
  end
end

function Keiko:catFDBUpdate()
  local ending = 0
  while self.catFDB[ending] ~= 0 do
    ending = ending + 1
  end
  self.catFDB[ending - 1] = 0
end

function Keiko:catFDBDraw(phantom)
	local ending = 0
	local frameBar = self.catFDB
	local alpha = 255
	if phantom then frameBar = self.catFDBPhantom alpha = 255 end
	while ending <= 47 do
	  if frameBar[ending] == "recovery" then
	    love.graphics.setColor(100, 255, 100, alpha)
	    if phantom then love.graphics.setColor(35, 75, 35, alpha) end
	  elseif frameBar[ending] == "active" then
	    love.graphics.setColor(255,46,46, alpha)
	    if phantom then love.graphics.setColor(74, 20, 20, alpha) end
	  elseif frameBar[ending] == "startup" then
	    love.graphics.setColor(255,255,100, alpha)
	    if phantom then love.graphics.setColor(75, 75, 35, alpha) end
	  elseif frameBar[ending] == "blockstun" then
	    love.graphics.setColor(66,214,247, alpha)
	    if phantom then love.graphics.setColor(26, 64, 72, alpha) end
	  elseif frameBar[ending] == "hitstun" then
	    love.graphics.setColor(255,169,0, alpha)
	    if phantom then love.graphics.setColor(73, 51, 7, alpha) end
	  elseif frameBar[ending] == "cancel" then
	    love.graphics.setColor(255,255,255, alpha)
	  elseif frameBar[ending] == "knockdown" then
	    love.graphics.setColor(255,118,192, alpha)
	    if phantom then love.graphics.setColor(76, 41, 60, alpha) end
	  else
	    love.graphics.setColor(0,0,0,0)
	  end
	  if self.playerNum == 1 then
	    love.graphics.rectangle("fill", 52 + (2 * ending) + (7 * gameLogicMult), 234 + self.meterJitter, gameLogicMult,gameLogicMult)
	    love.graphics.rectangle("fill", 50 + (2 * ending) + (7 * gameLogicMult), 232 + self.meterJitter, gameLogicMult,gameLogicMult)
	  else
	    love.graphics.rectangle("fill", screenWidth - 52 - (2 * ending) - (7 * gameLogicMult), 234 + self.meterJitter, gameLogicMult,gameLogicMult)
	    love.graphics.rectangle("fill", screenWidth - 50 - (2 * ending) - (7 * gameLogicMult), 232 + self.meterJitter, gameLogicMult,gameLogicMult)
	  end
	  ending = ending + 1
	end
	love.graphics.setColor(255,255,255)
end

function Keiko:meterBackDraw()
	if self.colorNum == 8 then
		love.graphics.setColor(0,103,83)
	elseif self.colorNum == 1 then
		love.graphics.setColor(0,55,102)
	elseif self.colorNum == 2 then
		love.graphics.setColor(102,87,0)
	elseif self.colorNum == 3 then
		love.graphics.setColor(102,0,47)
	elseif self.colorNum == 4 then
		love.graphics.setColor(70,0,102)
	elseif self.colorNum == 5 then
		love.graphics.setColor(102,0,0)
	elseif self.colorNum == 6 then
		love.graphics.setColor(98,0,86)
	else
		love.graphics.setColor(0,103,12)
	end
	if self.playerNum == 1 then
		love.graphics.rectangle("fill", 50 + (7 * gameLogicMult), 232 + self.meterJitter, gameLogicMult*50,gameLogicMult*2)
	else
		love.graphics.rectangle("fill", screenWidth - 150 - (7 * gameLogicMult), 232 + self.meterJitter, gameLogicMult*50,gameLogicMult*2)
	end
	love.graphics.setColor(255,255,255)
end

function Keiko:fullMeter()
	if self.meterAmount < 8 then
		self.meterAmount = 0
		self:changeMeter(8)
	end
	if self:noProjectiles() and self.move.name == "idle" and self.height == standHeight and ((rootState.training and trainingOptions.infiniteMeter) or (rootState.mode == "lesson" and rootState.eventQueue[rootState.currentEvent.stage].infiniteMeter)) then
		if self.flip == 1 then
			self:executeProjectile("catDashStart", self.x - 300, self.y + 30 * gameLogicMult)
		else
			self:executeProjectile("catDashStart", self.x + self.width + 300 - (catWidth), self.y + 30 * gameLogicMult)
		end
	elseif self.projectileTable[1].name == "catDeath" then
		self.projectileTable[1].exists = false
		if self.flip == 1 then
			self:executeProjectile("catDashStart", self.x - 300, self.y + 30 * gameLogicMult)
		else
			self:executeProjectile("catDashStart", self.x + self.width + 300 - (catWidth), self.y + 30 * gameLogicMult)
		end
	end
end